diff --git a/scapy/contrib/gtp.py b/scapy/contrib/gtp.py index bdcb28f05735d483b394096cdc29ffc0c029d06f..92f7d9f93d04146fe3cd8f4618107a8a4e21d394 100644 --- a/scapy/contrib/gtp.py +++ b/scapy/contrib/gtp.py @@ -41,7 +41,7 @@ GTPmessageType = { 1: "echo_request", 21: "delete_pdp_context_res", 26: "error_indication", 27: "pdu_notification_req", - 255: "gtp_u_header" } + 255: "g_pdu" } IEType = { 1: "Cause", 2: "IMSI", @@ -131,6 +131,17 @@ Selection_Mode = { 11111100: "MS or APN", TrueFalse_value = {254: "False", 255: "True"} +# http://www.arib.or.jp/IMT-2000/V720Mar09/5_Appendix/Rel8/29/29281-800.pdf +ExtensionHeadersTypes = { + 0: "No more extension headers", + 1: "Reserved", + 2: "Reserved", + 64: "UDP Port", + 192: "PDCP PDU Number", + 193: "Reserved", + 194: "Reserved" + } + class TBCDByteField(StrFixedLenField): @@ -166,6 +177,16 @@ class TBCDByteField(StrFixedLenField): TBCD_TO_ASCII = "0123456789*#abc" +class GTP_UDPPort_ExtensionHeader(Packet): + fields_desc=[ ShortField("length", 0x40), + BitField("udp_port", None, 48), + ByteEnumField("next_ex", 0, ExtensionHeadersTypes), ] + +class GTP_PDCP_PDU_ExtensionHeader(Packet): + fields_desc=[ ShortField("length", 0x01), + ByteField("pdcp_pdu", None), + ByteField("pdcp_pdu", None), + ByteEnumField("next_ex", 0, ExtensionHeadersTypes), ] class GTPHeader(Packet): # 3GPP TS 29.060 V9.1.0 (2009-12) @@ -174,11 +195,14 @@ class GTPHeader(Packet): BitField("PT", 1, 1), BitField("reserved", 0, 1), BitField("E", 0, 1), - BitField("S", 1, 1), + BitField("S", 0, 1), BitField("PN", 0, 1), ByteEnumField("gtp_type", None, GTPmessageType), ShortField("length", None), - IntField("teid", 0) ] + IntField("teid", 0), + ConditionalField(XBitField("seq", 0, 16), lambda pkt:pkt.E==1 or pkt.S==1 or pkt.PN==1), + ConditionalField(ByteField("npdu", 0), lambda pkt:pkt.E==1 or pkt.S==1 or pkt.PN==1), + ConditionalField(ByteEnumField("next_ex", 0, ExtensionHeadersTypes), lambda pkt:pkt.E==1 or pkt.S==1 or pkt.PN==1), ] def post_build(self, p, pay): p += pay @@ -197,19 +221,17 @@ class GTPHeader(Packet): @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): - if _pkt and len(_pkt) >= 1: - if (struct.unpack("B", _pkt[0])[0] >> 5) & 0x7 == 2: - from . import gtp_v2 - return gtp_v2.GTPHeader - return GTPHeader - + if _pkt and len(_pkt) >= 8: + if struct.unpack("!B", _pkt[1:2])[0] == 255: + return GTP_U_Header + return cls class GTPEchoRequest(Packet): # 3GPP TS 29.060 V9.1.0 (2009-12) name = "GTP Echo Request" fields_desc = [ XBitField("seq", 0, 16), ByteField("npdu", 0), - ByteField("next_ex", 0),] + ByteEnumField("next_ex", 0, ExtensionHeadersTypes),] def hashret(self): return struct.pack("H", self.seq) @@ -681,27 +703,24 @@ ietypecls = {1: IE_Cause, def IE_Dispatcher(s): - """Choose the correct Information Element class.""" - - if len(s) < 1: - return Raw(s) - - # Get the IE type - ietype = ord(s[0]) - cls = ietypecls.get(ietype, Raw) - - # if ietype greater than 128 are TLVs - if cls == Raw and ietype & 128 == 128: - cls = IE_NotImplementedTLV - - return cls(s) + """Choose the correct Information Element class.""" + if len(s) < 1: + return Raw(s) + # Get the IE type + ietype = ord(s[0]) + cls = ietypecls.get(ietype, Raw) + + # if ietype greater than 128 are TLVs + if cls == Raw and ietype & 128 == 128: + cls = IE_NotImplementedTLV + return cls(s) class GTPEchoResponse(Packet): # 3GPP TS 29.060 V9.1.0 (2009-12) name = "GTP Echo Response" fields_desc = [ XBitField("seq", 0, 16), ByteField("npdu", 0), - ByteField("next_ex", 0), + ByteEnumField("next_ex", 0, ExtensionHeadersTypes), PacketListField("IE_list", [], IE_Dispatcher) ] def hashret(self): @@ -716,7 +735,7 @@ class GTPCreatePDPContextRequest(Packet): name = "GTP Create PDP Context Request" fields_desc = [ ShortField("seq", RandShort()), ByteField("npdu", 0), - ByteField("next_ex", 0), + ByteEnumField("next_ex", 0, ExtensionHeadersTypes), PacketListField("IE_list", [ IE_TEIDI(), IE_NSAPI(), IE_GSNAddress(), IE_GSNAddress(), IE_NotImplementedTLV(ietype=135, length=15,data=RandString(15)) ], @@ -729,7 +748,7 @@ class GTPCreatePDPContextResponse(Packet): name = "GTP Create PDP Context Response" fields_desc = [ ShortField("seq", RandShort()), ByteField("npdu", 0), - ByteField("next_ex", 0), + ByteEnumField("next_ex", 0, ExtensionHeadersTypes), PacketListField("IE_list", [], IE_Dispatcher) ] def hashret(self): @@ -744,7 +763,7 @@ class GTPUpdatePDPContextRequest(Packet): name = "GTP Update PDP Context Request" fields_desc = [ShortField("seq", RandShort()), ByteField("npdu", 0), - ByteField("next_ex", 0), + ByteEnumField("next_ex", 0, ExtensionHeadersTypes), PacketListField("IE_list", [ IE_Cause(), IE_Recovery(), @@ -776,7 +795,7 @@ class GTPUpdatePDPContextResponse(Packet): name = "GTP Update PDP Context Response" fields_desc = [ShortField("seq", RandShort()), ByteField("npdu", 0), - ByteField("next_ex", 0), + ByteEnumField("next_ex", 0, ExtensionHeadersTypes), PacketListField("IE_list", None, IE_Dispatcher)] def hashret(self): @@ -796,7 +815,7 @@ class GTPDeletePDPContextRequest(Packet): name = "GTP Delete PDP Context Request" fields_desc = [ XBitField("seq", 0, 16), ByteField("npdu", 0), - ByteField("next_ex", 0), + ByteEnumField("next_ex", 0, ExtensionHeadersTypes), PacketListField("IE_list", [], IE_Dispatcher) ] class GTPDeletePDPContextResponse(Packet): @@ -812,40 +831,22 @@ class GTPPDUNotificationRequest(Packet): name = "GTP PDU Notification Request" fields_desc = [ XBitField("seq", 0, 16), ByteField("npdu", 0), - ByteField("next_ex", 0), + ByteEnumField("next_ex", 0, ExtensionHeadersTypes), PacketListField("IE_list", [ IE_IMSI(), IE_TEICP(TEICI=RandInt()), IE_EndUserAddress(PDPTypeNumber=0x21), IE_AccessPointName(), IE_GSNAddress(address="127.0.0.1"), ], IE_Dispatcher) ] + -class GTP_U_Header(Packet): +class GTP_U_Header(GTPHeader): # 3GPP TS 29.060 V9.1.0 (2009-12) name = "GTP-U Header" # GTP-U protocol is used to transmit T-PDUs between GSN pairs (or between an SGSN and an RNC in UMTS), # encapsulated in G-PDUs. A G-PDU is a packet including a GTP-U header and a T-PDU. The Path Protocol - # defines the path and the GTP-U header defines the tunnel. Several tunnels may be multiplexed on a single path. - fields_desc = [ BitField("version", 1,3), - BitField("PT", 1, 1), - BitField("Reserved", 0, 1), - BitField("E", 0,1), - BitField("S", 0, 1), - BitField("PN", 0, 1), - ByteEnumField("gtp_type", None, GTPmessageType), - BitField("length", None, 16), - XBitField("TEID", 0, 32), - ConditionalField(XBitField("seq", 0, 16), lambda pkt:pkt.E==1 or pkt.S==1 or pkt.PN==1), - ConditionalField(ByteField("npdu", 0), lambda pkt:pkt.E==1 or pkt.S==1 or pkt.PN==1), - ConditionalField(ByteField("next_ex", 0), lambda pkt:pkt.E==1 or pkt.S==1 or pkt.PN==1), - ] - - def post_build(self, p, pay): - p += pay - if self.length is None: - l = len(p)-8 - p = p[:2] + struct.pack("!H", l)+ p[4:] - return p + # defines the path and the GTP-U header defines the tunnel. Several tunnels may be multiplexed on a single path. + pass class GTPmorethan1500(Packet): # 3GPP TS 29.060 V9.1.0 (2009-12) @@ -865,6 +866,8 @@ bind_layers(GTPHeader, GTPUpdatePDPContextResponse, gtp_type=19) bind_layers(GTPHeader, GTPDeletePDPContextRequest, gtp_type=20) bind_layers(GTPHeader, GTPDeletePDPContextResponse, gtp_type=21) bind_layers(GTPHeader, GTPPDUNotificationRequest, gtp_type=27) +bind_layers(GTPHeader, GTP_UDPPort_ExtensionHeader, next_ex = 64, E = 1) +bind_layers(GTPHeader, GTP_PDCP_PDU_ExtensionHeader, next_ex = 192, E = 1) # Bind GTP-U bind_layers(UDP, GTP_U_Header, dport = 2152) diff --git a/scapy/contrib/gtp.uts b/scapy/contrib/gtp.uts index a23fd413c98b37a6a1105d8958ddefd586ad1e60..89f9411764151b0c62a7070fbc9006aabd69acdd 100644 --- a/scapy/contrib/gtp.uts +++ b/scapy/contrib/gtp.uts @@ -5,18 +5,26 @@ + GTPv1 += GTPHeader, basic instanciation + +a = GTPHeader() +assert a.version == 1 +assert a.E == a.S == a.PN == 0 + = GTPCreatePDPContextRequest(), basic instanciation gtp = IP()/UDP(dport=2123)/GTPHeader(teid=2807)/GTPCreatePDPContextRequest() gtp.dport == 2123 and gtp.teid == 2807 and len(gtp.IE_list) == 5 = GTPCreatePDPContextRequest(), basic dissection random.seed(0x2807) -str(gtp) == b"E\x00\x00O\x00\x01\x00\x00@\x11|\x9b\x7f\x00\x00\x01\x7f\x00\x00\x01\x08K\x08K\x00;{N2\x10\x00+\x00\x00\n\xf7\xd2y\x00\x00\x10\xf8>\x14\x05\x14\t\x85\x00\x04\xa6A\xd8+\x85\x00\x04z\xafnt\x87\x00\x0fxKbPaePK9oq0pb5" +str(gtp) +assert _ == b"E\x00\x00K\x00\x01\x00\x00@\x11|\x9f\x7f\x00\x00\x01\x7f\x00\x00\x01\x08K\x08K\x007\xa6\xa70\x10\x00'\x00\x00\n\xf7\x10\xd6\xd2\xf6\xd8\x14\x0f\x85\x00\x04\x98\xfaz\xab\x85\x00\x04\x02`0A\x87\x00\x0fu8h9lxKbPaePK9o" = GTPV1UpdatePDPContextRequest(), dissect h = "3333333333332222222222228100a38408004588006800000000fd1134820a2a00010a2a00024aa5084b005408bb32120044ed99aea9386f0000100000530514058500040a2a00018500040a2a000187000c0213921f739680fe74f2ffff94000130970001019800080112f41004d204d29900024000b6000101" gtp = Ether(h.decode('hex')) -gtp.gtp_type == 18 +assert gtp.gtp_type == 18 +assert gtp.next_ex == 0 = GTPV1UpdatePDPContextResponse(), dissect h = "3333333333332222222222228100838408004588005400000000fd1182850a2a00010a2a0002084b084b00406b46321300305843da17f07300000180100000032c7f4a0f58108500040a2a00018500040a2a000187000f0213921f7396d1fe7482ffff004a00f7a71e0a" @@ -286,4 +294,4 @@ ie.ietype == 251 and ie.ipv4_address == '127.0.0.1' and ie.ipv6_address == '::1' = IE_PrivateExtension(), basic instantiation ie = IE_PrivateExtension(extention_value='hello') -ie.ietype == 255 and ie.extention_value == 'hello' +ie.ietype == 255 and ie.extention_value == 'hello' \ No newline at end of file