[PATCH 09/10] gtphub: add GTP header validation

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/OpenBSC@lists.osmocom.org/.

Neels Hofmeyr nhofmeyr at sysmocom.de
Wed Oct 7 14:18:27 UTC 2015


Sponsored-by: On-Waves ehi
---
 openbsc/src/gprs/gtphub.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 124 insertions(+)

diff --git a/openbsc/src/gprs/gtphub.c b/openbsc/src/gprs/gtphub.c
index 419b21f..c6ce4f6 100644
--- a/openbsc/src/gprs/gtphub.c
+++ b/openbsc/src/gprs/gtphub.c
@@ -24,6 +24,8 @@
 #include <inttypes.h>
 #include <netinet/in.h>
 
+#include <gtp.h>
+
 #include <openbsc/gtphub.h>
 #include <openbsc/debug.h>
 
@@ -46,6 +48,116 @@ typedef int (*osmo_fd_cb_t)(struct osmo_fd *fd, unsigned int what);
 #define __llist_first(head) (((head)->next == (head)) ? NULL : (head)->next)
 #define llist_first(head, type, entry) llist_entry(__llist_first(head), type, entry)
 
+/* TODO duplicated from openggsn/gtp/gtpie.h */
+#define ntoh16(x) ntohs(x)
+#define ntoh32(x) ntohl(x)
+
+/* TODO move GTP header stuff to openggsn/gtp/ ? See gtp_decaps*() */
+
+enum gtp_header_type {
+	GTPH_V0 = 0,
+	GTPH_V1 = 1,
+
+	GTPH_TOOSHORT = -1,
+	GTPH_UNSUPPORTED_VERSION = -2,
+	GTPH_LOWER_VERSION = -3, // when gtp0 is received by gtp1 socket
+};
+
+int validate_gtp0_header(const uint8_t *data, int data_len)
+{
+	struct gtp0_header *pheader;
+	pheader = (struct gtp0_header *)(data);
+
+	OSMO_ASSERT(data_len >= 1);
+
+	int version = (*data) >> 5;
+
+	/* Version should be gtp0 (or earlier) */
+	/* 09.60 is somewhat unclear on this issue. On gsn->fd0 we expect only */
+	/* GTP 0 messages. If other version message is received we reply that we */
+	/* only support version 0, implying that this is the only version */
+	/* supported on this port */
+	if (version != 0) {
+		LOGERR("Expecting GTP version 0, got: %d\n", version);
+		return GTPH_UNSUPPORTED_VERSION;
+	}
+
+	/* Check length of gtp0 packet */
+	if (data_len < GTP0_HEADER_SIZE) {
+		LOGERR("GTP0 packet too short: %d\n", data_len);
+		return GTPH_TOOSHORT;
+	}
+
+	/* Check packet length field versus length of packet */
+	if (data_len != (ntoh16(pheader->length) + GTP0_HEADER_SIZE)) {
+		LOGERR("GTP packet length field (%d + %d) does not match"
+		       " actual length (%d)\n",
+		       GTP0_HEADER_SIZE, (int)ntoh16(pheader->length),
+		       data_len);
+		return GTPH_TOOSHORT;
+	}
+
+	return GTPH_V0;
+}
+
+int validate_gtp1_header(const uint8_t *data, int data_len)
+{
+	struct gtp1_header_short *pheader;
+	pheader = (struct gtp1_header_short *)data;
+
+	OSMO_ASSERT(data_len >= 1);
+
+	int version = (*data) >> 5;
+
+	if (version != 1) {
+		LOGERR("Expecting GTP version 1, got: %d\n", version);
+		return (version < 1? GTPH_LOWER_VERSION : GTPH_UNSUPPORTED_VERSION);
+	}
+
+	/* Check length of packet */
+	if (data_len < GTP1_HEADER_SIZE_LONG) {
+		LOGERR("GTP packet too short: %d\n", data_len);
+		return GTPH_TOOSHORT;
+	}
+
+	/* Check packet length field versus length of packet */
+	if (data_len != (ntoh16(pheader->length) + GTP1_HEADER_SIZE_SHORT)) {
+		LOGERR("GTP packet length field (%d + %d) does not match"
+		       " actual length (%d)\n",
+		       GTP1_HEADER_SIZE_SHORT, (int)ntoh16(pheader->length),
+		       data_len);
+		return GTPH_TOOSHORT;
+	}
+
+	return GTPH_V1;
+}
+
+/* Examine whether given data of size data_len has a valid GTP header.
+ * Return the GTP version, or < 0 on error (see enum gtp_header_type).
+ */
+int validate_gtp_header(const uint8_t *data, int data_len)
+{
+	/* Need at least 1 byte in order to check version */
+	if (data_len < (1)) {
+		LOGERR("Discarding packet - too small\n");
+		return GTPH_TOOSHORT;
+	}
+
+	int version = (*data) >> 5;
+
+	switch (version) {
+	case 0:
+		return validate_gtp0_header(data, data_len);
+	case 1:
+		return validate_gtp1_header(data, data_len);
+	default:
+		break;
+	}
+
+	LOGERR("Unsupported GTP version: %d\n", version);
+	return GTPH_UNSUPPORTED_VERSION;
+}
+
 
 /* general */
 
@@ -55,6 +167,8 @@ const char* const gtphub_port_idx_names[GTPH_PORT_N] = {
 };
 
 
+/* tei_map, tei_pool */
+
 void tei_pool_init(struct tei_pool *pool)
 {
 	*pool = (struct tei_pool){};
@@ -215,6 +329,16 @@ static int gtp_relay(struct osmo_fd *from,
 
 	/* insert magic here */
 
+	int gtph = validate_gtp_header(buf, received);
+
+	if (gtph >= 0)
+		LOG("Valid GTP header (v%d)\n", gtph);
+#if 0
+	else
+		// error has been logged
+		return 0;
+#endif
+
 	errno = 0;
 	ssize_t sent = sendto(to->fd, buf, received, 0,
 			      (struct sockaddr*)to_addr, to_addr_len);
-- 
2.1.4




More information about the OpenBSC mailing list