Skip to content
Snippets Groups Projects
Commit 3185c101 authored by gpotter2's avatar gpotter2 Committed by Guillaume Valadon
Browse files

Add GTP next_extension headers support

parent fbfd6348
No related branches found
No related tags found
No related merge requests found
...@@ -41,7 +41,7 @@ GTPmessageType = { 1: "echo_request", ...@@ -41,7 +41,7 @@ GTPmessageType = { 1: "echo_request",
21: "delete_pdp_context_res", 21: "delete_pdp_context_res",
26: "error_indication", 26: "error_indication",
27: "pdu_notification_req", 27: "pdu_notification_req",
255: "gtp_u_header" } 255: "g_pdu" }
IEType = { 1: "Cause", IEType = { 1: "Cause",
2: "IMSI", 2: "IMSI",
...@@ -131,6 +131,17 @@ Selection_Mode = { 11111100: "MS or APN", ...@@ -131,6 +131,17 @@ Selection_Mode = { 11111100: "MS or APN",
TrueFalse_value = {254: "False", TrueFalse_value = {254: "False",
255: "True"} 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): class TBCDByteField(StrFixedLenField):
...@@ -166,6 +177,16 @@ class TBCDByteField(StrFixedLenField): ...@@ -166,6 +177,16 @@ class TBCDByteField(StrFixedLenField):
TBCD_TO_ASCII = "0123456789*#abc" 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): class GTPHeader(Packet):
# 3GPP TS 29.060 V9.1.0 (2009-12) # 3GPP TS 29.060 V9.1.0 (2009-12)
...@@ -174,11 +195,14 @@ class GTPHeader(Packet): ...@@ -174,11 +195,14 @@ class GTPHeader(Packet):
BitField("PT", 1, 1), BitField("PT", 1, 1),
BitField("reserved", 0, 1), BitField("reserved", 0, 1),
BitField("E", 0, 1), BitField("E", 0, 1),
BitField("S", 1, 1), BitField("S", 0, 1),
BitField("PN", 0, 1), BitField("PN", 0, 1),
ByteEnumField("gtp_type", None, GTPmessageType), ByteEnumField("gtp_type", None, GTPmessageType),
ShortField("length", None), 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): def post_build(self, p, pay):
p += pay p += pay
...@@ -197,19 +221,17 @@ class GTPHeader(Packet): ...@@ -197,19 +221,17 @@ class GTPHeader(Packet):
@classmethod @classmethod
def dispatch_hook(cls, _pkt=None, *args, **kargs): def dispatch_hook(cls, _pkt=None, *args, **kargs):
if _pkt and len(_pkt) >= 1: if _pkt and len(_pkt) >= 8:
if (struct.unpack("B", _pkt[0])[0] >> 5) & 0x7 == 2: if struct.unpack("!B", _pkt[1:2])[0] == 255:
from . import gtp_v2 return GTP_U_Header
return gtp_v2.GTPHeader return cls
return GTPHeader
class GTPEchoRequest(Packet): class GTPEchoRequest(Packet):
# 3GPP TS 29.060 V9.1.0 (2009-12) # 3GPP TS 29.060 V9.1.0 (2009-12)
name = "GTP Echo Request" name = "GTP Echo Request"
fields_desc = [ XBitField("seq", 0, 16), fields_desc = [ XBitField("seq", 0, 16),
ByteField("npdu", 0), ByteField("npdu", 0),
ByteField("next_ex", 0),] ByteEnumField("next_ex", 0, ExtensionHeadersTypes),]
def hashret(self): def hashret(self):
return struct.pack("H", self.seq) return struct.pack("H", self.seq)
...@@ -681,27 +703,24 @@ ietypecls = {1: IE_Cause, ...@@ -681,27 +703,24 @@ ietypecls = {1: IE_Cause,
def IE_Dispatcher(s): def IE_Dispatcher(s):
"""Choose the correct Information Element class.""" """Choose the correct Information Element class."""
if len(s) < 1:
if len(s) < 1: return Raw(s)
return Raw(s) # Get the IE type
ietype = ord(s[0])
# Get the IE type cls = ietypecls.get(ietype, Raw)
ietype = ord(s[0])
cls = ietypecls.get(ietype, Raw) # if ietype greater than 128 are TLVs
if cls == Raw and ietype & 128 == 128:
# if ietype greater than 128 are TLVs cls = IE_NotImplementedTLV
if cls == Raw and ietype & 128 == 128: return cls(s)
cls = IE_NotImplementedTLV
return cls(s)
class GTPEchoResponse(Packet): class GTPEchoResponse(Packet):
# 3GPP TS 29.060 V9.1.0 (2009-12) # 3GPP TS 29.060 V9.1.0 (2009-12)
name = "GTP Echo Response" name = "GTP Echo Response"
fields_desc = [ XBitField("seq", 0, 16), fields_desc = [ XBitField("seq", 0, 16),
ByteField("npdu", 0), ByteField("npdu", 0),
ByteField("next_ex", 0), ByteEnumField("next_ex", 0, ExtensionHeadersTypes),
PacketListField("IE_list", [], IE_Dispatcher) ] PacketListField("IE_list", [], IE_Dispatcher) ]
def hashret(self): def hashret(self):
...@@ -716,7 +735,7 @@ class GTPCreatePDPContextRequest(Packet): ...@@ -716,7 +735,7 @@ class GTPCreatePDPContextRequest(Packet):
name = "GTP Create PDP Context Request" name = "GTP Create PDP Context Request"
fields_desc = [ ShortField("seq", RandShort()), fields_desc = [ ShortField("seq", RandShort()),
ByteField("npdu", 0), ByteField("npdu", 0),
ByteField("next_ex", 0), ByteEnumField("next_ex", 0, ExtensionHeadersTypes),
PacketListField("IE_list", [ IE_TEIDI(), IE_NSAPI(), IE_GSNAddress(), PacketListField("IE_list", [ IE_TEIDI(), IE_NSAPI(), IE_GSNAddress(),
IE_GSNAddress(), IE_GSNAddress(),
IE_NotImplementedTLV(ietype=135, length=15,data=RandString(15)) ], IE_NotImplementedTLV(ietype=135, length=15,data=RandString(15)) ],
...@@ -729,7 +748,7 @@ class GTPCreatePDPContextResponse(Packet): ...@@ -729,7 +748,7 @@ class GTPCreatePDPContextResponse(Packet):
name = "GTP Create PDP Context Response" name = "GTP Create PDP Context Response"
fields_desc = [ ShortField("seq", RandShort()), fields_desc = [ ShortField("seq", RandShort()),
ByteField("npdu", 0), ByteField("npdu", 0),
ByteField("next_ex", 0), ByteEnumField("next_ex", 0, ExtensionHeadersTypes),
PacketListField("IE_list", [], IE_Dispatcher) ] PacketListField("IE_list", [], IE_Dispatcher) ]
def hashret(self): def hashret(self):
...@@ -744,7 +763,7 @@ class GTPUpdatePDPContextRequest(Packet): ...@@ -744,7 +763,7 @@ class GTPUpdatePDPContextRequest(Packet):
name = "GTP Update PDP Context Request" name = "GTP Update PDP Context Request"
fields_desc = [ShortField("seq", RandShort()), fields_desc = [ShortField("seq", RandShort()),
ByteField("npdu", 0), ByteField("npdu", 0),
ByteField("next_ex", 0), ByteEnumField("next_ex", 0, ExtensionHeadersTypes),
PacketListField("IE_list", [ PacketListField("IE_list", [
IE_Cause(), IE_Cause(),
IE_Recovery(), IE_Recovery(),
...@@ -776,7 +795,7 @@ class GTPUpdatePDPContextResponse(Packet): ...@@ -776,7 +795,7 @@ class GTPUpdatePDPContextResponse(Packet):
name = "GTP Update PDP Context Response" name = "GTP Update PDP Context Response"
fields_desc = [ShortField("seq", RandShort()), fields_desc = [ShortField("seq", RandShort()),
ByteField("npdu", 0), ByteField("npdu", 0),
ByteField("next_ex", 0), ByteEnumField("next_ex", 0, ExtensionHeadersTypes),
PacketListField("IE_list", None, IE_Dispatcher)] PacketListField("IE_list", None, IE_Dispatcher)]
def hashret(self): def hashret(self):
...@@ -796,7 +815,7 @@ class GTPDeletePDPContextRequest(Packet): ...@@ -796,7 +815,7 @@ class GTPDeletePDPContextRequest(Packet):
name = "GTP Delete PDP Context Request" name = "GTP Delete PDP Context Request"
fields_desc = [ XBitField("seq", 0, 16), fields_desc = [ XBitField("seq", 0, 16),
ByteField("npdu", 0), ByteField("npdu", 0),
ByteField("next_ex", 0), ByteEnumField("next_ex", 0, ExtensionHeadersTypes),
PacketListField("IE_list", [], IE_Dispatcher) ] PacketListField("IE_list", [], IE_Dispatcher) ]
class GTPDeletePDPContextResponse(Packet): class GTPDeletePDPContextResponse(Packet):
...@@ -812,40 +831,22 @@ class GTPPDUNotificationRequest(Packet): ...@@ -812,40 +831,22 @@ class GTPPDUNotificationRequest(Packet):
name = "GTP PDU Notification Request" name = "GTP PDU Notification Request"
fields_desc = [ XBitField("seq", 0, 16), fields_desc = [ XBitField("seq", 0, 16),
ByteField("npdu", 0), ByteField("npdu", 0),
ByteField("next_ex", 0), ByteEnumField("next_ex", 0, ExtensionHeadersTypes),
PacketListField("IE_list", [ IE_IMSI(), PacketListField("IE_list", [ IE_IMSI(),
IE_TEICP(TEICI=RandInt()), IE_TEICP(TEICI=RandInt()),
IE_EndUserAddress(PDPTypeNumber=0x21), IE_EndUserAddress(PDPTypeNumber=0x21),
IE_AccessPointName(), IE_AccessPointName(),
IE_GSNAddress(address="127.0.0.1"), IE_GSNAddress(address="127.0.0.1"),
], IE_Dispatcher) ] ], IE_Dispatcher) ]
class GTP_U_Header(Packet): class GTP_U_Header(GTPHeader):
# 3GPP TS 29.060 V9.1.0 (2009-12) # 3GPP TS 29.060 V9.1.0 (2009-12)
name = "GTP-U Header" 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), # 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 # 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. # 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), pass
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
class GTPmorethan1500(Packet): class GTPmorethan1500(Packet):
# 3GPP TS 29.060 V9.1.0 (2009-12) # 3GPP TS 29.060 V9.1.0 (2009-12)
...@@ -865,6 +866,8 @@ bind_layers(GTPHeader, GTPUpdatePDPContextResponse, gtp_type=19) ...@@ -865,6 +866,8 @@ bind_layers(GTPHeader, GTPUpdatePDPContextResponse, gtp_type=19)
bind_layers(GTPHeader, GTPDeletePDPContextRequest, gtp_type=20) bind_layers(GTPHeader, GTPDeletePDPContextRequest, gtp_type=20)
bind_layers(GTPHeader, GTPDeletePDPContextResponse, gtp_type=21) bind_layers(GTPHeader, GTPDeletePDPContextResponse, gtp_type=21)
bind_layers(GTPHeader, GTPPDUNotificationRequest, gtp_type=27) 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 GTP-U
bind_layers(UDP, GTP_U_Header, dport = 2152) bind_layers(UDP, GTP_U_Header, dport = 2152)
......
...@@ -5,18 +5,26 @@ ...@@ -5,18 +5,26 @@
+ GTPv1 + GTPv1
= GTPHeader, basic instanciation
a = GTPHeader()
assert a.version == 1
assert a.E == a.S == a.PN == 0
= GTPCreatePDPContextRequest(), basic instanciation = GTPCreatePDPContextRequest(), basic instanciation
gtp = IP()/UDP(dport=2123)/GTPHeader(teid=2807)/GTPCreatePDPContextRequest() gtp = IP()/UDP(dport=2123)/GTPHeader(teid=2807)/GTPCreatePDPContextRequest()
gtp.dport == 2123 and gtp.teid == 2807 and len(gtp.IE_list) == 5 gtp.dport == 2123 and gtp.teid == 2807 and len(gtp.IE_list) == 5
= GTPCreatePDPContextRequest(), basic dissection = GTPCreatePDPContextRequest(), basic dissection
random.seed(0x2807) 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 = GTPV1UpdatePDPContextRequest(), dissect
h = "3333333333332222222222228100a38408004588006800000000fd1134820a2a00010a2a00024aa5084b005408bb32120044ed99aea9386f0000100000530514058500040a2a00018500040a2a000187000c0213921f739680fe74f2ffff94000130970001019800080112f41004d204d29900024000b6000101" h = "3333333333332222222222228100a38408004588006800000000fd1134820a2a00010a2a00024aa5084b005408bb32120044ed99aea9386f0000100000530514058500040a2a00018500040a2a000187000c0213921f739680fe74f2ffff94000130970001019800080112f41004d204d29900024000b6000101"
gtp = Ether(h.decode('hex')) gtp = Ether(h.decode('hex'))
gtp.gtp_type == 18 assert gtp.gtp_type == 18
assert gtp.next_ex == 0
= GTPV1UpdatePDPContextResponse(), dissect = GTPV1UpdatePDPContextResponse(), dissect
h = "3333333333332222222222228100838408004588005400000000fd1182850a2a00010a2a0002084b084b00406b46321300305843da17f07300000180100000032c7f4a0f58108500040a2a00018500040a2a000187000f0213921f7396d1fe7482ffff004a00f7a71e0a" h = "3333333333332222222222228100838408004588005400000000fd1182850a2a00010a2a0002084b084b00406b46321300305843da17f07300000180100000032c7f4a0f58108500040a2a00018500040a2a000187000f0213921f7396d1fe7482ffff004a00f7a71e0a"
...@@ -286,4 +294,4 @@ ie.ietype == 251 and ie.ipv4_address == '127.0.0.1' and ie.ipv6_address == '::1' ...@@ -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_PrivateExtension(), basic instantiation
ie = IE_PrivateExtension(extention_value='hello') 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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment