Skip to content

Instantly share code, notes, and snippets.

@thomasbhatia
Created December 5, 2012 11:33
Show Gist options
  • Save thomasbhatia/4214901 to your computer and use it in GitHub Desktop.
Save thomasbhatia/4214901 to your computer and use it in GitHub Desktop.
Scapy layer: GTP
## This file is not now part of Scapy
## Look iniqua.com for more informations
## ffranz <[email protected]>
## This program is published under a GPLv2 license
import time
import logging
from scapy.packet import *
from scapy.fields import *
from scapy.layers.inet import UDP
from scapy.all import *
# ToDo:
# GTPv0/1
#
# GTP-C
# ---------------------------
#
# GTPHeader()
#
#
# GTP-U
# ---------------------------
#
# GTP_U_Header()
GTPmessageType = { 1 : "echo_request",
2 : "echo_response",
16 : "create_pdp_context_req",
20 : "delete_pdp_context_req",
21 : "delete_pdp_context_res",
26 : "error_indication",
255: "gtp_u_header" }
IEType = { 1 : "Cause",
2 : "IMSI",
3 : "RAI",
4 : "TLLI",
5 : "P_TMSI",
14 : "Recovery",
15 : "SelectionMode",
16 : "TEIDI",
17 : "TEICP",
19 : "TeardownInd",
20 : "NSAPI",
26 : "ChargingChrt",
27 : "TraceReference",
28 : "TraceType",
128: "EndUserAddress",
131: "AccessPointName",
133: "GSNAddress" }
CauseValues = { 0 : "Request IMSI",
1 : "Request IMEI",
2 : "Request IMSI and IMEI",
3 : "No identity needed",
4 : "MS Refuses",
5 : "MS is not GPRS Responding",
128 : "Request accepted",
129 : "New PDP type due to network prefernce",
130 : "New PDP type due to single address bearer only",
192 : "Non-exitent",
193 : "Invalid message format",
194 : "IMSI not known",
195 : "MS is GPRS Detached",
196 : "MS is not GPRS Responding",
197 : "MS Refuses",
198 : "Version not supported",
199 : "No resources available",
200 : "Service not supported",
201 : "Mandatory IE incorrect",
202 : "Mandatory IE missing",
203 : "Optional IE incorrect",
204 : "System failure",
205 : "Roaming restriction",
206 : "P-TMSI Signature mismatch",
207 : "GRPS connection suspended",
208 : "Authentication failure",
209 : "User authentication failed",
210 : "Context not found",
211 : "All dynamic PDP addresses are occupied",
212 : "No memory is available",
213 : "Realocation failure",
214 : "Unknown mandatory extension header",
215 : "Semantic error in the TFT operation",
216 : "Syntactic error in TFT operation",
217 : "Semantc errors in packet filter(s)",
218 : "Syntactic errors in packet filter(s)",
219 : "Missing or unknown APN",
220 : "Unknown PDP address or PDP type",
221 : "PDP context without TFT already activated",
222 : "APN access denied : no subscription",
223 : "APN Restriction type incompatibility with currently active PDP Contexts",
224 : "MS MBMS Capabilities Insufficient",
225 : "Invalid Correlation : ID",
226 : "MBMS Bearer Context Superseded",
227 : "Bearer Control Mode violation",
228 : "Collision with network initiated request" }
Selection_Mode = { 11111100:"MSorAPN",
11111101:"MS",
11111110:"NET",
11111111:"FutureUse" }
TeardownInd_value = { 254 : "False",
255 : "True" }
class GTPHeader(Packet):
# 3GPP TS 29.060 V9.1.0 (2009-12)
name = "GTP Header"
fields_desc = [ BitField("version", 1, 3),
BitField("PT", 1, 1),
BitField("Reserved", 0, 1),
BitField("E", 0, 1),
BitField("S", 1, 1),
BitField("PN", 0, 1),
ByteEnumField("type", None, GTPmessageType),
BitField("length", None, 16),
XBitField("TEID", 0, 32),]
def post_build(self, p, pay):
p +=pay
warning("Packet length: " + str(len(p)-8))
if self.length is None:
l = len(p)-8
p = p[:1] + struct.pack("!i",l)+ p[4:]
if self.type is None:
if isinstance(self.payload, GTPEchoRequest):
t = 1
elif isinstance(self.payload, GTPEchoResponse):
t = 2
elif isinstance(self.payload, GTPCreatePDPContextRequest):
t = 16
elif isinstance(self.payload, GTPDeletePDPContextRequest):
t = 20
elif isinstance(self.payload, GTPDeletePDPContextResponse):
t = 21
elif isinstance(self.payload, GTPErrorIndication):
t = 26
else:
warning("GTPHeader: cannot GPT type! Set type 1 (Echo Request).")
t = 1
p = p[:1] + struct.pack("!B",t) + p[3:]
#if self.payload.seq is not None:
# warning("TODO: Set S bit '1' because seq number is present.")
#else:
# warning("TODO: Set S bit '0' because seq number is not present.")
return p
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),]
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("IE_Recovery", "Recovery", IEType),
ByteField("res-counter",24), ]
class GTPCreatePDPContextRequest(Packet):
# 3GPP TS 29.060 V9.1.0 (2009-12)
name = "GTP Create PDP Context Request"
fields_desc = [ XBitField("seq", 0, 16),
ByteField("npdu", 0),
ByteField("next_ex", 0),
# IMSI: Conditional - Suscariber identity of de MS
ByteEnumField("IE_IMSI", "IMSI", IEType),
BitField("IMSI", 0, 64),
# RAI: Optional - Routeing Area Identity
ByteEnumField("IE_RAI", "RAI", IEType),
BitField("MCC", None, 12),
# MNC: If only have 2 digits, then third digit (1byte) is 0xf
BitField("MNC", None, 12),
BitField("LAC", None, 16),
ByteField("RAC", None),
# Selection Mode: Conditional - Indicates the origin of the APN in the message
ByteEnumField("IE_SelectionMode", "SelectionMode", IEType),
# First 6 bits are "1". Use only first 2 bits.
BitEnumField("SelectionMode", "MSorAPN", 8, Selection_Mode),
# TEIDI: Mandatory - Tunnel Endpoint Identifier Data I
ByteEnumField("IE_TEIDI", "TEIDI", IEType),
XBitField("TEIDI", 0, 32),
# TEICP: Conditional - Tunnel Endpoint Identifier Control Plane
ByteEnumField("IE_TEICP", "TEICP", IEType),
XBitField("TEICP", 0, 32),
# NSAPI: Mandatory - identifying a PDP context in a mobility management context specified by TEICP
ByteEnumField("IE_NASPI", "NSAPI", IEType),
XBitField("SpareNSAPI", 0x0000, 4),
XBitField("NSAPI", 0x0000, 4),
# Charging Characteristics: Conditional - way of informing both the SGSN and GGSN of the rules for
# producing charging informarion based on opetaror configured triggers.
# 0000 .... .... .... : spare
# .... 1... .... .... : normal charging
# .... .0.. .... .... : prepaid charging
# .... ..0. .... .... : flat rate charging
# .... ...0 .... .... : hot billing charging
# .... .... 0000 0000 : reserved
ByteEnumField("IE_ChargingChrt", "ChargingChrt", IEType),
XBitField("Ch_ChSpare", None, 4),
XBitField("normal_charging", None, 1),
XBitField("prepaid_charging", None, 1),
XBitField("flat_rate_charging", None, 1),
XBitField("hot_billing_charging", None, 1),
XBitField("Ch_ChReserved", 0, 8),
# Trace Reference: Optional - Identifies a record or a collection of records for a particular trace.
ByteEnumField("IE_TraceReference", "TraceReference", IEType),
XBitField("Trace_reference", None, 16),
# Trace Type: Optional - Indicate the type of the trace
ByteEnumField("IE_TraceType", "TraceType", IEType),
XBitField("Trace_type", None, 16),
# End User Address: Conditional - to supply protocol specific information of the external packet
# data network accessed by the GGPRS suscribers.
# - Request
# 1 Type (1byte)
# 2-3 Length (2bytes) - value 2
# 4 Spare + PDP Type Organization
# 5 PDP Type Number
# - Response
# 6-n PDP Address
ByteEnumField("IE_EndUserAddress", "EndUserAddress", IEType),
BitField("EndUserAddressLength", 2, 16),
BitField("EndUserAddress", 1111, 4),
BitField("PDPTypeOrganization", 1, 4),
XByteField("PDPTypeNumber", None),
# Access Point Name: Conditional - Sent by SGSN or by GGSN as defined in 3GPP TS 23.060
ByteEnumField("IE_AccessPointName", "AccessPointName", IEType),
ByteField("APNLength", None),
#, length_from=lambda pkt:len(pkt.APNUrl)),
StrField("APNUrl", "apn.es"),
# Protocol Configuration:
# GSN Address:
ByteEnumField("IE_GSNAddress1", "GSNAddress", IEType),
LongField("GSNAddressLength", 4),
IPField("IPGSN1", "0.0.0.0"), ]
# GSN Address:
class GTPErrorIndication(Packet):
# 3GPP TS 29.060 V9.1.0 (2009-12)
name = "GTP Error Indication"
fields_desc = [ XBitField("seq", 0, 16),
ByteField("npdu", 0),
ByteField("next_ex", 0),
# TEIDI: Mandatory - Tunnel Endpoint Identifier Data I
ByteEnumField("IE_TEIDI", "TEIDI", IEType),
XBitField("TEIDI", 0, 32),
# GSN Address:
ByteEnumField("IE_GSNAddress1", "GSNAddress", IEType),
BitField("GSNAddressLength", 4, 16),
IPField("IPGSN1", "252.253.254.255"), ]
class GTPDeletePDPContextRequest(Packet):
# 3GPP TS 29.060 V9.1.0 (2009-12)
name = "GTP Delete PDP Context Request"
fields_desc = [ XBitField("seq", 0, 16),
ByteField("npdu", 0),
ByteField("next_ex", 0),
# Teardown Ind: conditional - If this element is set to "1", all PDP Contexts thatt share the same PDP
# address or two IP addresses with the PDP context indentified by the
# NSAPI included in the Delete PDP Context Request Message shall be torn down.
ByteEnumField("IE_TeardownInd", "TeardownInd", IEType),
ByteEnumField("TeardownInd", "True", TeardownInd_value),
# NSAPI: Mandatory - identifying a PDP context in a mobility management context specified by TEICP
ByteEnumField("IE_NSAPI", "NSAPI", IEType),
XBitField("SpareNSAPI", 0x0000, 4),
XBitField("NSAPI", 0x0000, 4), ]
# Protocol Configuration Options: Optional - TODO
# Private Extansions: Optional - Contains vendor specific information. TODO
class GTPDeletePDPContextResponse(Packet):
# 3GPP TS 29.060 V9.1.0 (2009-12)
name = "GTP Delete PDP Context Response"
fields_desc = [ XBitField("seq", 0, 16),
ByteField("npdu", 0),
ByteField("next_ex", 0),
# Cause: Mandatory -
ByteEnumField("IE_Cause", "Cause", IEType),
BitField("Response", None, 1),
BitField("Rejection", None, 1),
BitEnumField("CauseValue", None, 6, CauseValues), ]
# Protocol Configuration Options: Optional - TODO
# User Location Information: Optional - TODO
# MS Time Zone: Optional - TODO
# Private Extension: Optional - TODO
class GTP_U_Header(Packet):
# 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("type", None, GTPmessageType),
BitField("length", None, 16),
XBitField("TEID", 0, 32),
# Conditional fields:
# XBitField("seq", 0, 16),
ByteField("npdu", 0),
ByteField("next_ex", 0),
ConditionalField(XBitField("seq", 0, 16), lambda pkt:pkt.S == 1),
# ConditionalField(ByteField("npdu", 0), lambda pkt:pkt.PT == 1),
# ConditionalField(ByteField("next_ex", 0), lambda pkt:pkt.E == 1),
]
def post_build(self, p, pay):
p += pay
warning("Packet length: " + str(len(p)-8))
if self.length is None:
l = len(p)-8
p = p[:1] + struct.pack("!i",l)+ p[4:]
if self.type is None:
if isinstance(self.payload, IP):
t = 255
else:
warning("GTP-U Header: Not PDU detected.")
t = 255
p = p[:1] + struct.pack("!B",t) + p[3:]
return p
class GTPmorethan1500(Packet):
# 3GPP TS 29.060 V9.1.0 (2009-12)
name = "GTP More than 1500"
# 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 = [ ByteEnumField("IE_Cause", "Cause", IEType),
BitField("IE", 1, 12000),]
# Bind GTP-C
bind_layers( UDP, GTPHeader)
bind_layers( GTPHeader, GTPEchoRequest)
bind_layers( GTPHeader, GTPEchoResponse)
bind_layers( GTPHeader, GTPCreatePDPContextRequest)
bind_layers( GTPHeader, GTPDeletePDPContextRequest)
bind_layers( GTPHeader, GTPDeletePDPContextResponse)
#Bind GTP-U
bind_layers( UDP, GTP_U_Header)
bind_layers( GTP_U_Header, IP)
if __name__ == "__main__":
interact(mydict=globals(), mybanner="Test GTP add-on v0.1")
@palVikram
Copy link

I have to capture GTP-c packet. What command should I use?, I am totally new to this field.

Thanks & Regards
Vikram Pal

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment