Created
December 5, 2012 11:33
-
-
Save thomasbhatia/4214901 to your computer and use it in GitHub Desktop.
Scapy layer: GTP
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
## 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") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I have to capture GTP-c packet. What command should I use?, I am totally new to this field.
Thanks & Regards
Vikram Pal