diff --git a/.gitattributes b/.gitattributes index 0c210b4e705aeff54e3aa3c9e0b15242cd3549b5..7ddf3f340cb8f3f7a271fcd58dd810779045149e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,3 @@ scapy/__init__.py export-subst +* text=auto +*.bat text eol=crlf diff --git a/bin/UTscapy.bat b/bin/UTscapy.bat index 3bccb69a072dd0c8ce5861b2b37f343325f84031..d9c277f26424c712fb9bed8eac26be2d4530a484 100755 --- a/bin/UTscapy.bat +++ b/bin/UTscapy.bat @@ -1,4 +1,4 @@ -@echo off -REM Use Python to run the UTscapy script from the current directory, passing all parameters -title UTscapy -python "%~dp0\UTscapy" %* +@echo off +REM Use Python to run the UTscapy script from the current directory, passing all parameters +title UTscapy +python "%~dp0\UTscapy" %* diff --git a/bin/scapy.bat b/bin/scapy.bat index cbb17445abb0577f3eceb4541ea332855265b80e..23e43cba51c72900b636898326358df46e6805af 100755 --- a/bin/scapy.bat +++ b/bin/scapy.bat @@ -1,4 +1,4 @@ -@echo off -REM Use Python to run the Scapy script from the current directory, passing all parameters -title scapy -python "%~dp0\scapy" %* +@echo off +REM Use Python to run the Scapy script from the current directory, passing all parameters +title scapy +python "%~dp0\scapy" %* diff --git a/run_scapy.bat b/run_scapy.bat index ef1273f7c58128568606cd743d7cc4fc87589eec..ba0774288ea073cc391ad8f84414562b7f61f757 100644 --- a/run_scapy.bat +++ b/run_scapy.bat @@ -1,6 +1,6 @@ -@echo off -set PYTHONPATH=%cd% -python -m scapy.__init__ -if errorlevel 1 ( - PAUSE -) +@echo off +set PYTHONPATH=%cd% +python -m scapy.__init__ +if errorlevel 1 ( + PAUSE +) diff --git a/scapy/contrib/gtp.py b/scapy/contrib/gtp.py index 4fef6c023c24a371a745665c7785cdfa3d70204f..8e40b17be71341e4bd8fc934a9e8412df83a7411 100644 --- a/scapy/contrib/gtp.py +++ b/scapy/contrib/gtp.py @@ -1,198 +1,198 @@ -#! /usr/bin/env python - -## Copyright (C) 2017 Alexis Sultan <alexis.sultan@sfr.com> -## 2017 Alessio Deiana <adeiana@gmail.com> -## 2014 Guillaume Valadon <guillaume.valadon@ssi.gouv.fr> -## 2012 ffranz <ffranz@iniqua.com> -## -## This program is published under a GPLv2 license - -# scapy.contrib.description = GTP -# scapy.contrib.status = loads - -import time -import logging - -from scapy.packet import * -from scapy.fields import * -from scapy.layers.inet import IP, UDP -from scapy.layers.inet6 import IP6Field -from scapy.error import warning - -# GTP Data types - -RATType = { - 1: "UTRAN", - 2: "GETRAN", - 3: "WLAN", - 4: "GAN", - 5: "HSPA" -} - -GTPmessageType = { 1: "echo_request", - 2: "echo_response", - 16: "create_pdp_context_req", - 17: "create_pdp_context_res", - 18: "update_pdp_context_req", - 19: "update_pdp_context_resp", - 20: "delete_pdp_context_req", - 21: "delete_pdp_context_res", - 26: "error_indication", - 27: "pdu_notification_req", - 255: "gtp_u_header" } - -IEType = { 1: "Cause", - 2: "IMSI", - 3: "RAI", - 4: "TLLI", - 5: "P_TMSI", - 8: "IE_ReorderingRequired", - 14: "Recovery", - 15: "SelectionMode", - 16: "TEIDI", - 17: "TEICP", - 19: "TeardownInd", - 20: "NSAPI", - 26: "ChargingChrt", - 27: "TraceReference", - 28: "TraceType", - 127: "ChargingId", - 128: "EndUserAddress", - 131: "AccessPointName", - 132: "ProtocolConfigurationOptions", - 133: "GSNAddress", - 134: "MSInternationalNumber", - 135: "QoS", - 148: "CommonFlags", - 149: "APNRestriction", - 151: "RatType", - 152: "UserLocationInformation", - 153: "MSTimeZone", - 154: "IMEI", - 181: "MSInfoChangeReportingAction", - 184: "BearerControlMode", - 191: "EvolvedAllocationRetentionPriority", - 255: "PrivateExtention"} - -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 preference", - 130: "New PDP type due to single address bearer only", - 192: "Non-existent", - 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: "GPRS 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: "Reallocation failure", - 214: "Unknown mandatory extension header", - 215: "Semantic error in the TFT operation", - 216: "Syntactic error in TFT operation", - 217: "Semantic 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: "MS or APN", - 11111101: "MS", - 11111110: "NET", - 11111111: "FutureUse" } - -TrueFalse_value = {254: "False", - 255: "True"} - - -class TBCDByteField(StrFixedLenField): - - def i2h(self, pkt, val): - return val - - def i2repr(self, pkt, x): - return repr(self.i2h(pkt,x)) - - def m2i(self, pkt, val): - ret = [] - for v in val: - byte = ord(v) - left = byte >> 4 - right = byte & 0xf - if left == 0xf: - ret += [TBCD_TO_ASCII[right]] - else: - ret += [TBCD_TO_ASCII[right], TBCD_TO_ASCII[left]] - return "".join(ret) - - def i2m(self, pkt, val): - val = str(val) - ret_string = "" - for i in xrange(0, len(val), 2): - tmp = val[i:i+2] - if len(tmp) == 2: - ret_string += chr(int(tmp[1] + tmp[0], 16)) - else: - ret_string += chr(int("F" + tmp[0], 16)) - return ret_string - - -TBCD_TO_ASCII = "0123456789*#abc" - - -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("gtp_type", None, GTPmessageType), - ShortField("length", None), - IntField("teid", 0) ] - - 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 - - def hashret(self): - return struct.pack("B", self.version) + self.payload.hashret() - - def answers(self, other): - return (isinstance(other, GTPHeader) and - self.version == other.version and - self.payload.answers(other.payload)) - +#! /usr/bin/env python + +## Copyright (C) 2017 Alexis Sultan <alexis.sultan@sfr.com> +## 2017 Alessio Deiana <adeiana@gmail.com> +## 2014 Guillaume Valadon <guillaume.valadon@ssi.gouv.fr> +## 2012 ffranz <ffranz@iniqua.com> +## +## This program is published under a GPLv2 license + +# scapy.contrib.description = GTP +# scapy.contrib.status = loads + +import time +import logging + +from scapy.packet import * +from scapy.fields import * +from scapy.layers.inet import IP, UDP +from scapy.layers.inet6 import IP6Field +from scapy.error import warning + +# GTP Data types + +RATType = { + 1: "UTRAN", + 2: "GETRAN", + 3: "WLAN", + 4: "GAN", + 5: "HSPA" +} + +GTPmessageType = { 1: "echo_request", + 2: "echo_response", + 16: "create_pdp_context_req", + 17: "create_pdp_context_res", + 18: "update_pdp_context_req", + 19: "update_pdp_context_resp", + 20: "delete_pdp_context_req", + 21: "delete_pdp_context_res", + 26: "error_indication", + 27: "pdu_notification_req", + 255: "gtp_u_header" } + +IEType = { 1: "Cause", + 2: "IMSI", + 3: "RAI", + 4: "TLLI", + 5: "P_TMSI", + 8: "IE_ReorderingRequired", + 14: "Recovery", + 15: "SelectionMode", + 16: "TEIDI", + 17: "TEICP", + 19: "TeardownInd", + 20: "NSAPI", + 26: "ChargingChrt", + 27: "TraceReference", + 28: "TraceType", + 127: "ChargingId", + 128: "EndUserAddress", + 131: "AccessPointName", + 132: "ProtocolConfigurationOptions", + 133: "GSNAddress", + 134: "MSInternationalNumber", + 135: "QoS", + 148: "CommonFlags", + 149: "APNRestriction", + 151: "RatType", + 152: "UserLocationInformation", + 153: "MSTimeZone", + 154: "IMEI", + 181: "MSInfoChangeReportingAction", + 184: "BearerControlMode", + 191: "EvolvedAllocationRetentionPriority", + 255: "PrivateExtention"} + +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 preference", + 130: "New PDP type due to single address bearer only", + 192: "Non-existent", + 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: "GPRS 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: "Reallocation failure", + 214: "Unknown mandatory extension header", + 215: "Semantic error in the TFT operation", + 216: "Syntactic error in TFT operation", + 217: "Semantic 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: "MS or APN", + 11111101: "MS", + 11111110: "NET", + 11111111: "FutureUse" } + +TrueFalse_value = {254: "False", + 255: "True"} + + +class TBCDByteField(StrFixedLenField): + + def i2h(self, pkt, val): + return val + + def i2repr(self, pkt, x): + return repr(self.i2h(pkt,x)) + + def m2i(self, pkt, val): + ret = [] + for v in val: + byte = ord(v) + left = byte >> 4 + right = byte & 0xf + if left == 0xf: + ret += [TBCD_TO_ASCII[right]] + else: + ret += [TBCD_TO_ASCII[right], TBCD_TO_ASCII[left]] + return "".join(ret) + + def i2m(self, pkt, val): + val = str(val) + ret_string = "" + for i in xrange(0, len(val), 2): + tmp = val[i:i+2] + if len(tmp) == 2: + ret_string += chr(int(tmp[1] + tmp[0], 16)) + else: + ret_string += chr(int("F" + tmp[0], 16)) + return ret_string + + +TBCD_TO_ASCII = "0123456789*#abc" + + +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("gtp_type", None, GTPmessageType), + ShortField("length", None), + IntField("teid", 0) ] + + 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 + + def hashret(self): + return struct.pack("B", self.version) + self.payload.hashret() + + def answers(self, other): + return (isinstance(other, GTPHeader) and + self.version == other.version and + self.payload.answers(other.payload)) + @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt and len(_pkt) >= 1: @@ -200,675 +200,675 @@ class GTPHeader(Packet): import gtp_v2 return gtp_v2.GTPHeader return GTPHeader - - -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),] - - def hashret(self): - return struct.pack("H", self.seq) - - -class IE_Base(Packet): - - def extract_padding(self, pkt): - return "", pkt - - -class IE_Cause(IE_Base): - name = "Cause" - fields_desc = [ByteEnumField("ietype", 1, IEType), - ByteEnumField("CauseValue", None, CauseValues)] - - -class IE_IMSI(IE_Base): - name = "IMSI - Subscriber identity of the MS" - fields_desc = [ByteEnumField("ietype", 2, IEType), - TBCDByteField("imsi", str(RandNum(0, 999999999999999)), 8)] - - -class IE_Routing(IE_Base): - name = "Routing Area Identity" - fields_desc = [ ByteEnumField("ietype", 3, IEType), - TBCDByteField("MCC", "", 2), - # MNC: if the third digit of MCC is 0xf, - # then the length of MNC is 1 byte - TBCDByteField("MNC", "", 1), - ShortField("LAC", None), - ByteField("RAC", None) ] - - -class IE_ReorderingRequired(IE_Base): - name = "Recovery" - fields_desc = [ByteEnumField("ietype", 8, IEType), - ByteEnumField("reordering_required", 254, TrueFalse_value)] - - -class IE_Recovery(IE_Base): - name = "Recovery" - fields_desc = [ ByteEnumField("ietype", 14, IEType), - ByteField("restart_counter", 24) ] - - -class IE_SelectionMode(IE_Base): - # Indicates the origin of the APN in the message - name = "Selection Mode" - fields_desc = [ ByteEnumField("ietype", 15, IEType), - BitEnumField("SelectionMode", "MS or APN", - 8, Selection_Mode) ] - - -class IE_TEIDI(IE_Base): - name = "Tunnel Endpoint Identifier Data" - fields_desc = [ ByteEnumField("ietype", 16, IEType), - XIntField("TEIDI", RandInt()) ] - - -class IE_TEICP(IE_Base): - name = "Tunnel Endpoint Identifier Control Plane" - fields_desc = [ ByteEnumField("ietype", 17, IEType), - XIntField("TEICI", RandInt())] - - -class IE_Teardown(IE_Base): - name = "Teardown Indicator" - fields_desc = [ ByteEnumField("ietype", 19, IEType), - ByteEnumField("indicator", "True", TrueFalse_value) ] - - -class IE_NSAPI(IE_Base): - # Identifies a PDP context in a mobility management context specified by TEICP - name = "NSAPI" - fields_desc = [ ByteEnumField("ietype", 20, IEType), - XBitField("sparebits", 0x0000, 4), - XBitField("NSAPI", RandNum(0, 15), 4) ] - - -class IE_ChargingCharacteristics(IE_Base): - # Way of informing both the SGSN and GGSN of the rules for - name = "Charging Characteristics" - fields_desc = [ ByteEnumField("ietype", 26, IEType), - # producing charging information based on operator configured triggers. - # 0000 .... .... .... : spare - # .... 1... .... .... : normal charging - # .... .0.. .... .... : prepaid charging - # .... ..0. .... .... : flat rate charging - # .... ...0 .... .... : hot billing charging - # .... .... 0000 0000 : reserved - 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) ] - -class IE_TraceReference(IE_Base): - # Identifies a record or a collection of records for a particular trace. - name = "Trace Reference" - fields_desc = [ ByteEnumField("ietype", 27, IEType), - XBitField("Trace_reference", None, 16) ] - - -class IE_TraceType(IE_Base): - # Indicates the type of the trace - name = "Trace Type" - fields_desc = [ ByteEnumField("ietype", 28, IEType), - XBitField("Trace_type", None, 16) ] - - -class IE_ChargingId(IE_Base): - name = "Charging ID" - fields_desc = [ByteEnumField("ietype", 127, IEType), - XIntField("Charging_id", RandInt())] - - -class IE_EndUserAddress(IE_Base): - # Supply protocol specific information of the external packet - name = "End User Addresss" - fields_desc = [ ByteEnumField("ietype", 128, IEType), - # data network accessed by the GGPRS subscribers. - # - Request - # 1 Type (1byte) - # 2-3 Length (2bytes) - value 2 - # 4 Spare + PDP Type Organization - # 5 PDP Type Number - # - Response - # 6-n PDP Address - ShortField("length", 2), - BitField("SPARE", 15, 4), - BitField("PDPTypeOrganization", 1, 4), - XByteField("PDPTypeNumber", None), - ConditionalField(IPField("PDPAddress", RandIP()), - lambda pkt: pkt.length > 2)] - - -class APNStrLenField(StrLenField): - # Inspired by DNSStrField - def m2i(self, pkt, s): - ret_s = "" - tmp_s = s - while tmp_s: - tmp_len = struct.unpack("!B", tmp_s[0])[0] + 1 - if tmp_len > len(tmp_s): - warning("APN prematured end of character-string (size=%i, remaining bytes=%i)" % (tmp_len, len(tmp_s))) - ret_s += tmp_s[1:tmp_len] - tmp_s = tmp_s[tmp_len:] - if len(tmp_s) : - ret_s += "." - s = ret_s - return s - def i2m(self, pkt, s): - s = "".join(map(lambda x: chr(len(x))+x, s.split("."))) - return s - - -class IE_AccessPointName(IE_Base): - # Sent by SGSN or by GGSN as defined in 3GPP TS 23.060 - name = "Access Point Name" - fields_desc = [ ByteEnumField("ietype", 131, IEType), - ShortField("length", None), - APNStrLenField("APN", "nternet", length_from=lambda x: x.length) ] - - def post_build(self, p, pay): - if self.length is None: - l = len(p)-3 - p = p[:2] + struct.pack("!B", l)+ p[3:] - return p - - -class IE_ProtocolConfigurationOptions(IE_Base): - name = "Protocol Configuration Options" - fields_desc = [ ByteEnumField("ietype", 132, IEType), - ShortField("length", 4), - StrLenField("Protocol_Configuration", "", - length_from=lambda x: x.length) ] - - -class IE_GSNAddress(IE_Base): - name = "GSN Address" - fields_desc = [ ByteEnumField("ietype", 133, IEType), - ShortField("length", 4), - IPField("address", RandIP()) ] - - -class IE_MSInternationalNumber(IE_Base): - name = "MS International Number" - fields_desc = [ ByteEnumField("ietype", 134, IEType), - ShortField("length", None), - FlagsField("flags", 0x91, 8, ["Extension","","","International Number","","","","ISDN numbering"]), - TBCDByteField("digits", "33607080910", length_from=lambda x: x.length-1) ] - - -class QoS_Profile(IE_Base): - name = "QoS profile" - fields_desc = [ByteField("qos_ei", 0), - ByteField("length", None), - XBitField("spare", 0x00, 2), - XBitField("delay_class", 0x000, 3), - XBitField("reliability_class", 0x000, 3), - XBitField("peak_troughput", 0x0000, 4), - BitField("spare", 0, 1), - XBitField("precedence_class", 0x000, 3), - XBitField("spare", 0x000, 3), - XBitField("mean_troughput", 0x00000, 5), - XBitField("traffic_class", 0x000, 3), - XBitField("delivery_order", 0x00, 2), - XBitField("delivery_of_err_sdu", 0x000, 3), - ByteField("max_sdu_size", None), - ByteField("max_bitrate_up", None), - ByteField("max_bitrate_down", None), - XBitField("redidual_ber", 0x0000, 4), - XBitField("sdu_err_ratio", 0x0000, 4), - XBitField("transfer_delay", 0x00000, 5), - XBitField("traffic_handling_prio", 0x000, 3), - ByteField("guaranteed_bit_rate_up", None), - ByteField("guaranteed_bit_rate_down", None)] - - -class IE_QoS(IE_Base): - name = "QoS" - fields_desc = [ByteEnumField("ietype", 135, IEType), - ShortField("length", None), - ByteField("allocation_retention_prioiry", 1), - - ConditionalField(XBitField("spare", 0x00, 2), - lambda pkt: pkt.length > 1), - ConditionalField(XBitField("delay_class", 0x000, 3), - lambda pkt: pkt.length > 1), - ConditionalField(XBitField("reliability_class", 0x000, 3), - lambda pkt: pkt.length > 1), - - ConditionalField(XBitField("peak_troughput", 0x0000, 4), - lambda pkt: pkt.length > 2), - ConditionalField(BitField("spare", 0, 1), - lambda pkt: pkt.length > 2), - ConditionalField(XBitField("precedence_class", 0x000, 3), - lambda pkt: pkt.length > 2), - - ConditionalField(XBitField("spare", 0x000, 3), - lambda pkt: pkt.length > 3), - ConditionalField(XBitField("mean_troughput", 0x00000, 5), - lambda pkt: pkt.length > 3), - - ConditionalField(XBitField("traffic_class", 0x000, 3), - lambda pkt: pkt.length > 4), - ConditionalField(XBitField("delivery_order", 0x00, 2), - lambda pkt: pkt.length > 4), - ConditionalField(XBitField("delivery_of_err_sdu", 0x000, 3), - lambda pkt: pkt.length > 4), - - ConditionalField(ByteField("max_sdu_size", None), - lambda pkt: pkt.length > 5), - ConditionalField(ByteField("max_bitrate_up", None), - lambda pkt: pkt.length > 6), - ConditionalField(ByteField("max_bitrate_down", None), - lambda pkt: pkt.length > 7), - - ConditionalField(XBitField("redidual_ber", 0x0000, 4), - lambda pkt: pkt.length > 8), - ConditionalField(XBitField("sdu_err_ratio", 0x0000, 4), - lambda pkt: pkt.length > 8), - ConditionalField(XBitField("transfer_delay", 0x00000, 6), - lambda pkt: pkt.length > 9), - ConditionalField(XBitField("traffic_handling_prio", - 0x000, - 2), - lambda pkt: pkt.length > 9), - - ConditionalField(ByteField("guaranteed_bit_rate_up", None), - lambda pkt: pkt.length > 10), - ConditionalField(ByteField("guaranteed_bit_rate_down", - None), - lambda pkt: pkt.length > 11), - - ConditionalField(XBitField("spare", 0x000, 3), - lambda pkt: pkt.length > 12), - ConditionalField(BitField("signaling_indication", 0, 1), - lambda pkt: pkt.length > 12), - ConditionalField(XBitField("source_stats_desc", 0x0000, 4), - lambda pkt: pkt.length > 12), - - ConditionalField(ByteField("max_bitrate_down_ext", None), - lambda pkt: pkt.length > 13), - ConditionalField(ByteField("guaranteed_bitrate_down_ext", - None), - lambda pkt: pkt.length > 14), - ConditionalField(ByteField("max_bitrate_up_ext", None), - lambda pkt: pkt.length > 15), - ConditionalField(ByteField("guaranteed_bitrate_up_ext", - None), - lambda pkt: pkt.length > 16), - ConditionalField(ByteField("max_bitrate_down_ext2", None), - lambda pkt: pkt.length > 17), - ConditionalField(ByteField("guaranteed_bitrate_down_ext2", - None), - lambda pkt: pkt.length > 18), - ConditionalField(ByteField("max_bitrate_up_ext2", None), - lambda pkt: pkt.length > 19), - ConditionalField(ByteField("guaranteed_bitrate_up_ext2", - None), - lambda pkt: pkt.length > 20)] - - -class IE_CommonFlags(IE_Base): - name = "Common Flags" - fields_desc = [ByteEnumField("ietype", 148, IEType), - ShortField("length", None), - BitField("dual_addr_bearer_fl", 0, 1), - BitField("upgrade_qos_supported", 0, 1), - BitField("nrsn", 0, 1), - BitField("no_qos_nego", 0, 1), - BitField("mbms_cnting_info", 0, 1), - BitField("ran_procedure_ready", 0, 1), - BitField("mbms_service_type", 0, 1), - BitField("prohibit_payload_compression", 0, 1)] - - -class IE_APNRestriction(IE_Base): - name = "APN Restriction" - fields_desc = [ByteEnumField("ietype", 149, IEType), - ShortField("length", 1), - ByteField("restriction_type_value", 0)] - - -class IE_RATType(IE_Base): - name = "Rat Type" - fields_desc = [ByteEnumField("ietype", 151, IEType), - ShortField("length", 1), - ByteEnumField("RAT_Type", None, RATType)] - - -class IE_UserLocationInformation(IE_Base): - name = "User Location Information" - fields_desc = [ ByteEnumField("ietype", 152, IEType), - ShortField("length", None), - ByteField("type", 1), - # Only type 1 is currently supported - TBCDByteField("MCC", "", 2), - # MNC: if the third digit of MCC is 0xf, then the length of MNC is 1 byte - TBCDByteField("MNC", "", 1), - ShortField("LAC", None), - ShortField("SAC", None) ] - - -class IE_MSTimeZone(IE_Base): - name = "MS Time Zone" - fields_desc = [ByteEnumField("ietype", 153, IEType), - ShortField("length", None), - ByteField("timezone", 0), - BitField("Spare", 0, 1), - BitField("Spare", 0, 1), - BitField("Spare", 0, 1), - BitField("Spare", 0, 1), - BitField("Spare", 0, 1), - BitField("Spare", 0, 1), - XBitField("daylight_saving_time", 0x00, 2)] - - -class IE_IMEI(IE_Base): - name = "IMEI" - fields_desc = [ ByteEnumField("ietype", 154, IEType), - ShortField("length", None), - TBCDByteField("IMEI", "", length_from=lambda x: x.length) ] - - -class IE_MSInfoChangeReportingAction(IE_Base): - name = "MS Info Change Reporting Action" - fields_desc = [ByteEnumField("ietype", 181, IEType), - ShortField("length", 1), - ByteField("Action", 0)] - - -class IE_DirectTunnelFlags(IE_Base): - name = "Direct Tunnel Flags" - fields_desc = [ByteEnumField("ietype", 182, IEType), - ShortField("length", 1), - BitField("Spare", 0, 1), - BitField("Spare", 0, 1), - BitField("Spare", 0, 1), - BitField("Spare", 0, 1), - BitField("Spare", 0, 1), - BitField("EI", 0, 1), - BitField("GCSI", 0, 1), - BitField("DTI", 0, 1)] - - -class IE_BearerControlMode(IE_Base): - name = "Bearer Control Mode" - fields_desc = [ByteEnumField("ietype", 184, IEType), - ShortField("length", 1), - ByteField("bearer_control_mode", 0)] - - -class IE_EvolvedAllocationRetentionPriority(IE_Base): - name = "Evolved Allocation/Retention Priority" - fields_desc = [ByteEnumField("ietype", 191, IEType), - ShortField("length", 1), - BitField("Spare", 0, 1), - BitField("PCI", 0, 1), - XBitField("PL", 0x0000, 4), - BitField("Spare", 0, 1), - BitField("PVI", 0, 1)] - - -class IE_CharginGatewayAddress(IE_Base): - name = "Chargin Gateway Address" - fields_desc = [ByteEnumField("ietype", 251, IEType), - ShortField("length", 4), - ConditionalField(IPField("ipv4_address", "127.0.0.1"), - lambda - pkt: pkt.length == 4), - ConditionalField(IP6Field("ipv6_address", "::1"), lambda - pkt: pkt.length == 16)] - - -class IE_PrivateExtension(IE_Base): - name = "Private Extension" - fields_desc = [ByteEnumField("ietype", 255, IEType), - ShortField("length", 1), - ByteField("extension identifier", 0), - StrLenField("extention_value", "", - length_from=lambda x: x.length)] - - -class IE_NotImplementedTLV(Packet): - name = "IE not implemented" - fields_desc = [ ByteEnumField("ietype", 0, IEType), - ShortField("length", None), - StrLenField("data", "", length_from=lambda x: x.length) ] - def extract_padding(self, pkt): - return "",pkt - - -ietypecls = {1: IE_Cause, - 2: IE_IMSI, - 3: IE_Routing, - 8: IE_ReorderingRequired, - 14: IE_Recovery, - 15: IE_SelectionMode, - 16: IE_TEIDI, - 17: IE_TEICP, - 19: IE_Teardown, - 20: IE_NSAPI, - 26: IE_ChargingCharacteristics, - 27: IE_TraceReference, - 28: IE_TraceType, - 127: IE_ChargingId, - 128: IE_EndUserAddress, - 131: IE_AccessPointName, - 132: IE_ProtocolConfigurationOptions, - 133: IE_GSNAddress, - 134: IE_MSInternationalNumber, - 135: IE_QoS, - 148: IE_CommonFlags, - 149: IE_APNRestriction, - 151: IE_RATType, - 152: IE_UserLocationInformation, - 153: IE_MSTimeZone, - 154: IE_IMEI, - 181: IE_MSInfoChangeReportingAction, - 182: IE_DirectTunnelFlags, - 184: IE_BearerControlMode, - 191: IE_EvolvedAllocationRetentionPriority, - 251: IE_CharginGatewayAddress, - 255: IE_PrivateExtension} - - -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) - -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), - PacketListField("IE_list", [], IE_Dispatcher) ] - - def hashret(self): - return struct.pack("H", self.seq) - - def answers(self, other): - return self.seq == other.seq - - -class GTPCreatePDPContextRequest(Packet): - # 3GPP TS 29.060 V9.1.0 (2009-12) - name = "GTP Create PDP Context Request" - fields_desc = [ ShortField("seq", RandShort()), - ByteField("npdu", 0), - ByteField("next_ex", 0), - PacketListField("IE_list", [ IE_TEIDI(), IE_NSAPI(), IE_GSNAddress(), - IE_GSNAddress(), - IE_NotImplementedTLV(ietype=135, length=15,data=RandString(15)) ], - IE_Dispatcher) ] - def hashret(self): - return struct.pack("H", self.seq) - -class GTPCreatePDPContextResponse(Packet): - # 3GPP TS 29.060 V9.1.0 (2009-12) - name = "GTP Create PDP Context Response" - fields_desc = [ ShortField("seq", RandShort()), - ByteField("npdu", 0), - ByteField("next_ex", 0), - PacketListField("IE_list", [], IE_Dispatcher) ] - - def hashret(self): - return struct.pack("H", self.seq) - - def answers(self, other): - return self.seq == other.seq - - -class GTPUpdatePDPContextRequest(Packet): - # 3GPP TS 29.060 V9.1.0 (2009-12) - name = "GTP Update PDP Context Request" - fields_desc = [ShortField("seq", RandShort()), - ByteField("npdu", 0), - ByteField("next_ex", 0), - PacketListField("IE_list", [ - IE_Cause(), - IE_Recovery(), - IE_TEIDI(), - IE_TEICP(), - IE_ChargingId(), - IE_ProtocolConfigurationOptions(), - IE_GSNAddress(), - IE_GSNAddress(), - IE_GSNAddress(), - IE_GSNAddress(), - IE_QoS(), - IE_CharginGatewayAddress(), - IE_CharginGatewayAddress(), - IE_CommonFlags(), - IE_APNRestriction(), - IE_BearerControlMode(), - IE_MSInfoChangeReportingAction(), - IE_EvolvedAllocationRetentionPriority(), - IE_PrivateExtension()], - IE_Dispatcher)] - - def hashret(self): - return struct.pack("H", self.seq) - - -class GTPUpdatePDPContextResponse(Packet): - # 3GPP TS 29.060 V9.1.0 (2009-12) - name = "GTP Update PDP Context Response" - fields_desc = [ShortField("seq", RandShort()), - ByteField("npdu", 0), - ByteField("next_ex", 0), - PacketListField("IE_list", None, IE_Dispatcher)] - - def hashret(self): - return struct.pack("H", self.seq) - - -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), - PacketListField("IE_list", [], IE_Dispatcher) ] - -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), - PacketListField("IE_list", [], IE_Dispatcher) ] - -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), - PacketListField("IE_list", [], IE_Dispatcher) ] - -class GTPPDUNotificationRequest(Packet): - # 3GPP TS 29.060 V9.1.0 (2009-12) - name = "GTP PDU Notification Request" - fields_desc = [ XBitField("seq", 0, 16), - ByteField("npdu", 0), - ByteField("next_ex", 0), - 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): - # 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 - -class GTPmorethan1500(Packet): - # 3GPP TS 29.060 V9.1.0 (2009-12) - name = "GTP More than 1500" - fields_desc = [ ByteEnumField("IE_Cause", "Cause", IEType), - BitField("IE", 1, 12000),] - -# Bind GTP-C -bind_layers(UDP, GTPHeader, dport = 2123) -bind_layers(UDP, GTPHeader, sport = 2123) -bind_layers(GTPHeader, GTPEchoRequest, gtp_type=1) -bind_layers(GTPHeader, GTPEchoResponse, gtp_type=2) -bind_layers(GTPHeader, GTPCreatePDPContextRequest, gtp_type=16) -bind_layers(GTPHeader, GTPCreatePDPContextResponse, gtp_type=17) -bind_layers(GTPHeader, GTPUpdatePDPContextRequest, gtp_type=18) -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 GTP-U -bind_layers(UDP, GTP_U_Header, dport = 2152) -bind_layers(UDP, GTP_U_Header, sport = 2152) -bind_layers(GTP_U_Header, IP, gtp_type = 255) - -if __name__ == "__main__": - from scapy.all import * - interact(mydict=globals(), mybanner="GTPv1 add-on") + + +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),] + + def hashret(self): + return struct.pack("H", self.seq) + + +class IE_Base(Packet): + + def extract_padding(self, pkt): + return "", pkt + + +class IE_Cause(IE_Base): + name = "Cause" + fields_desc = [ByteEnumField("ietype", 1, IEType), + ByteEnumField("CauseValue", None, CauseValues)] + + +class IE_IMSI(IE_Base): + name = "IMSI - Subscriber identity of the MS" + fields_desc = [ByteEnumField("ietype", 2, IEType), + TBCDByteField("imsi", str(RandNum(0, 999999999999999)), 8)] + + +class IE_Routing(IE_Base): + name = "Routing Area Identity" + fields_desc = [ ByteEnumField("ietype", 3, IEType), + TBCDByteField("MCC", "", 2), + # MNC: if the third digit of MCC is 0xf, + # then the length of MNC is 1 byte + TBCDByteField("MNC", "", 1), + ShortField("LAC", None), + ByteField("RAC", None) ] + + +class IE_ReorderingRequired(IE_Base): + name = "Recovery" + fields_desc = [ByteEnumField("ietype", 8, IEType), + ByteEnumField("reordering_required", 254, TrueFalse_value)] + + +class IE_Recovery(IE_Base): + name = "Recovery" + fields_desc = [ ByteEnumField("ietype", 14, IEType), + ByteField("restart_counter", 24) ] + + +class IE_SelectionMode(IE_Base): + # Indicates the origin of the APN in the message + name = "Selection Mode" + fields_desc = [ ByteEnumField("ietype", 15, IEType), + BitEnumField("SelectionMode", "MS or APN", + 8, Selection_Mode) ] + + +class IE_TEIDI(IE_Base): + name = "Tunnel Endpoint Identifier Data" + fields_desc = [ ByteEnumField("ietype", 16, IEType), + XIntField("TEIDI", RandInt()) ] + + +class IE_TEICP(IE_Base): + name = "Tunnel Endpoint Identifier Control Plane" + fields_desc = [ ByteEnumField("ietype", 17, IEType), + XIntField("TEICI", RandInt())] + + +class IE_Teardown(IE_Base): + name = "Teardown Indicator" + fields_desc = [ ByteEnumField("ietype", 19, IEType), + ByteEnumField("indicator", "True", TrueFalse_value) ] + + +class IE_NSAPI(IE_Base): + # Identifies a PDP context in a mobility management context specified by TEICP + name = "NSAPI" + fields_desc = [ ByteEnumField("ietype", 20, IEType), + XBitField("sparebits", 0x0000, 4), + XBitField("NSAPI", RandNum(0, 15), 4) ] + + +class IE_ChargingCharacteristics(IE_Base): + # Way of informing both the SGSN and GGSN of the rules for + name = "Charging Characteristics" + fields_desc = [ ByteEnumField("ietype", 26, IEType), + # producing charging information based on operator configured triggers. + # 0000 .... .... .... : spare + # .... 1... .... .... : normal charging + # .... .0.. .... .... : prepaid charging + # .... ..0. .... .... : flat rate charging + # .... ...0 .... .... : hot billing charging + # .... .... 0000 0000 : reserved + 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) ] + +class IE_TraceReference(IE_Base): + # Identifies a record or a collection of records for a particular trace. + name = "Trace Reference" + fields_desc = [ ByteEnumField("ietype", 27, IEType), + XBitField("Trace_reference", None, 16) ] + + +class IE_TraceType(IE_Base): + # Indicates the type of the trace + name = "Trace Type" + fields_desc = [ ByteEnumField("ietype", 28, IEType), + XBitField("Trace_type", None, 16) ] + + +class IE_ChargingId(IE_Base): + name = "Charging ID" + fields_desc = [ByteEnumField("ietype", 127, IEType), + XIntField("Charging_id", RandInt())] + + +class IE_EndUserAddress(IE_Base): + # Supply protocol specific information of the external packet + name = "End User Addresss" + fields_desc = [ ByteEnumField("ietype", 128, IEType), + # data network accessed by the GGPRS subscribers. + # - Request + # 1 Type (1byte) + # 2-3 Length (2bytes) - value 2 + # 4 Spare + PDP Type Organization + # 5 PDP Type Number + # - Response + # 6-n PDP Address + ShortField("length", 2), + BitField("SPARE", 15, 4), + BitField("PDPTypeOrganization", 1, 4), + XByteField("PDPTypeNumber", None), + ConditionalField(IPField("PDPAddress", RandIP()), + lambda pkt: pkt.length > 2)] + + +class APNStrLenField(StrLenField): + # Inspired by DNSStrField + def m2i(self, pkt, s): + ret_s = "" + tmp_s = s + while tmp_s: + tmp_len = struct.unpack("!B", tmp_s[0])[0] + 1 + if tmp_len > len(tmp_s): + warning("APN prematured end of character-string (size=%i, remaining bytes=%i)" % (tmp_len, len(tmp_s))) + ret_s += tmp_s[1:tmp_len] + tmp_s = tmp_s[tmp_len:] + if len(tmp_s) : + ret_s += "." + s = ret_s + return s + def i2m(self, pkt, s): + s = "".join(map(lambda x: chr(len(x))+x, s.split("."))) + return s + + +class IE_AccessPointName(IE_Base): + # Sent by SGSN or by GGSN as defined in 3GPP TS 23.060 + name = "Access Point Name" + fields_desc = [ ByteEnumField("ietype", 131, IEType), + ShortField("length", None), + APNStrLenField("APN", "nternet", length_from=lambda x: x.length) ] + + def post_build(self, p, pay): + if self.length is None: + l = len(p)-3 + p = p[:2] + struct.pack("!B", l)+ p[3:] + return p + + +class IE_ProtocolConfigurationOptions(IE_Base): + name = "Protocol Configuration Options" + fields_desc = [ ByteEnumField("ietype", 132, IEType), + ShortField("length", 4), + StrLenField("Protocol_Configuration", "", + length_from=lambda x: x.length) ] + + +class IE_GSNAddress(IE_Base): + name = "GSN Address" + fields_desc = [ ByteEnumField("ietype", 133, IEType), + ShortField("length", 4), + IPField("address", RandIP()) ] + + +class IE_MSInternationalNumber(IE_Base): + name = "MS International Number" + fields_desc = [ ByteEnumField("ietype", 134, IEType), + ShortField("length", None), + FlagsField("flags", 0x91, 8, ["Extension","","","International Number","","","","ISDN numbering"]), + TBCDByteField("digits", "33607080910", length_from=lambda x: x.length-1) ] + + +class QoS_Profile(IE_Base): + name = "QoS profile" + fields_desc = [ByteField("qos_ei", 0), + ByteField("length", None), + XBitField("spare", 0x00, 2), + XBitField("delay_class", 0x000, 3), + XBitField("reliability_class", 0x000, 3), + XBitField("peak_troughput", 0x0000, 4), + BitField("spare", 0, 1), + XBitField("precedence_class", 0x000, 3), + XBitField("spare", 0x000, 3), + XBitField("mean_troughput", 0x00000, 5), + XBitField("traffic_class", 0x000, 3), + XBitField("delivery_order", 0x00, 2), + XBitField("delivery_of_err_sdu", 0x000, 3), + ByteField("max_sdu_size", None), + ByteField("max_bitrate_up", None), + ByteField("max_bitrate_down", None), + XBitField("redidual_ber", 0x0000, 4), + XBitField("sdu_err_ratio", 0x0000, 4), + XBitField("transfer_delay", 0x00000, 5), + XBitField("traffic_handling_prio", 0x000, 3), + ByteField("guaranteed_bit_rate_up", None), + ByteField("guaranteed_bit_rate_down", None)] + + +class IE_QoS(IE_Base): + name = "QoS" + fields_desc = [ByteEnumField("ietype", 135, IEType), + ShortField("length", None), + ByteField("allocation_retention_prioiry", 1), + + ConditionalField(XBitField("spare", 0x00, 2), + lambda pkt: pkt.length > 1), + ConditionalField(XBitField("delay_class", 0x000, 3), + lambda pkt: pkt.length > 1), + ConditionalField(XBitField("reliability_class", 0x000, 3), + lambda pkt: pkt.length > 1), + + ConditionalField(XBitField("peak_troughput", 0x0000, 4), + lambda pkt: pkt.length > 2), + ConditionalField(BitField("spare", 0, 1), + lambda pkt: pkt.length > 2), + ConditionalField(XBitField("precedence_class", 0x000, 3), + lambda pkt: pkt.length > 2), + + ConditionalField(XBitField("spare", 0x000, 3), + lambda pkt: pkt.length > 3), + ConditionalField(XBitField("mean_troughput", 0x00000, 5), + lambda pkt: pkt.length > 3), + + ConditionalField(XBitField("traffic_class", 0x000, 3), + lambda pkt: pkt.length > 4), + ConditionalField(XBitField("delivery_order", 0x00, 2), + lambda pkt: pkt.length > 4), + ConditionalField(XBitField("delivery_of_err_sdu", 0x000, 3), + lambda pkt: pkt.length > 4), + + ConditionalField(ByteField("max_sdu_size", None), + lambda pkt: pkt.length > 5), + ConditionalField(ByteField("max_bitrate_up", None), + lambda pkt: pkt.length > 6), + ConditionalField(ByteField("max_bitrate_down", None), + lambda pkt: pkt.length > 7), + + ConditionalField(XBitField("redidual_ber", 0x0000, 4), + lambda pkt: pkt.length > 8), + ConditionalField(XBitField("sdu_err_ratio", 0x0000, 4), + lambda pkt: pkt.length > 8), + ConditionalField(XBitField("transfer_delay", 0x00000, 6), + lambda pkt: pkt.length > 9), + ConditionalField(XBitField("traffic_handling_prio", + 0x000, + 2), + lambda pkt: pkt.length > 9), + + ConditionalField(ByteField("guaranteed_bit_rate_up", None), + lambda pkt: pkt.length > 10), + ConditionalField(ByteField("guaranteed_bit_rate_down", + None), + lambda pkt: pkt.length > 11), + + ConditionalField(XBitField("spare", 0x000, 3), + lambda pkt: pkt.length > 12), + ConditionalField(BitField("signaling_indication", 0, 1), + lambda pkt: pkt.length > 12), + ConditionalField(XBitField("source_stats_desc", 0x0000, 4), + lambda pkt: pkt.length > 12), + + ConditionalField(ByteField("max_bitrate_down_ext", None), + lambda pkt: pkt.length > 13), + ConditionalField(ByteField("guaranteed_bitrate_down_ext", + None), + lambda pkt: pkt.length > 14), + ConditionalField(ByteField("max_bitrate_up_ext", None), + lambda pkt: pkt.length > 15), + ConditionalField(ByteField("guaranteed_bitrate_up_ext", + None), + lambda pkt: pkt.length > 16), + ConditionalField(ByteField("max_bitrate_down_ext2", None), + lambda pkt: pkt.length > 17), + ConditionalField(ByteField("guaranteed_bitrate_down_ext2", + None), + lambda pkt: pkt.length > 18), + ConditionalField(ByteField("max_bitrate_up_ext2", None), + lambda pkt: pkt.length > 19), + ConditionalField(ByteField("guaranteed_bitrate_up_ext2", + None), + lambda pkt: pkt.length > 20)] + + +class IE_CommonFlags(IE_Base): + name = "Common Flags" + fields_desc = [ByteEnumField("ietype", 148, IEType), + ShortField("length", None), + BitField("dual_addr_bearer_fl", 0, 1), + BitField("upgrade_qos_supported", 0, 1), + BitField("nrsn", 0, 1), + BitField("no_qos_nego", 0, 1), + BitField("mbms_cnting_info", 0, 1), + BitField("ran_procedure_ready", 0, 1), + BitField("mbms_service_type", 0, 1), + BitField("prohibit_payload_compression", 0, 1)] + + +class IE_APNRestriction(IE_Base): + name = "APN Restriction" + fields_desc = [ByteEnumField("ietype", 149, IEType), + ShortField("length", 1), + ByteField("restriction_type_value", 0)] + + +class IE_RATType(IE_Base): + name = "Rat Type" + fields_desc = [ByteEnumField("ietype", 151, IEType), + ShortField("length", 1), + ByteEnumField("RAT_Type", None, RATType)] + + +class IE_UserLocationInformation(IE_Base): + name = "User Location Information" + fields_desc = [ ByteEnumField("ietype", 152, IEType), + ShortField("length", None), + ByteField("type", 1), + # Only type 1 is currently supported + TBCDByteField("MCC", "", 2), + # MNC: if the third digit of MCC is 0xf, then the length of MNC is 1 byte + TBCDByteField("MNC", "", 1), + ShortField("LAC", None), + ShortField("SAC", None) ] + + +class IE_MSTimeZone(IE_Base): + name = "MS Time Zone" + fields_desc = [ByteEnumField("ietype", 153, IEType), + ShortField("length", None), + ByteField("timezone", 0), + BitField("Spare", 0, 1), + BitField("Spare", 0, 1), + BitField("Spare", 0, 1), + BitField("Spare", 0, 1), + BitField("Spare", 0, 1), + BitField("Spare", 0, 1), + XBitField("daylight_saving_time", 0x00, 2)] + + +class IE_IMEI(IE_Base): + name = "IMEI" + fields_desc = [ ByteEnumField("ietype", 154, IEType), + ShortField("length", None), + TBCDByteField("IMEI", "", length_from=lambda x: x.length) ] + + +class IE_MSInfoChangeReportingAction(IE_Base): + name = "MS Info Change Reporting Action" + fields_desc = [ByteEnumField("ietype", 181, IEType), + ShortField("length", 1), + ByteField("Action", 0)] + + +class IE_DirectTunnelFlags(IE_Base): + name = "Direct Tunnel Flags" + fields_desc = [ByteEnumField("ietype", 182, IEType), + ShortField("length", 1), + BitField("Spare", 0, 1), + BitField("Spare", 0, 1), + BitField("Spare", 0, 1), + BitField("Spare", 0, 1), + BitField("Spare", 0, 1), + BitField("EI", 0, 1), + BitField("GCSI", 0, 1), + BitField("DTI", 0, 1)] + + +class IE_BearerControlMode(IE_Base): + name = "Bearer Control Mode" + fields_desc = [ByteEnumField("ietype", 184, IEType), + ShortField("length", 1), + ByteField("bearer_control_mode", 0)] + + +class IE_EvolvedAllocationRetentionPriority(IE_Base): + name = "Evolved Allocation/Retention Priority" + fields_desc = [ByteEnumField("ietype", 191, IEType), + ShortField("length", 1), + BitField("Spare", 0, 1), + BitField("PCI", 0, 1), + XBitField("PL", 0x0000, 4), + BitField("Spare", 0, 1), + BitField("PVI", 0, 1)] + + +class IE_CharginGatewayAddress(IE_Base): + name = "Chargin Gateway Address" + fields_desc = [ByteEnumField("ietype", 251, IEType), + ShortField("length", 4), + ConditionalField(IPField("ipv4_address", "127.0.0.1"), + lambda + pkt: pkt.length == 4), + ConditionalField(IP6Field("ipv6_address", "::1"), lambda + pkt: pkt.length == 16)] + + +class IE_PrivateExtension(IE_Base): + name = "Private Extension" + fields_desc = [ByteEnumField("ietype", 255, IEType), + ShortField("length", 1), + ByteField("extension identifier", 0), + StrLenField("extention_value", "", + length_from=lambda x: x.length)] + + +class IE_NotImplementedTLV(Packet): + name = "IE not implemented" + fields_desc = [ ByteEnumField("ietype", 0, IEType), + ShortField("length", None), + StrLenField("data", "", length_from=lambda x: x.length) ] + def extract_padding(self, pkt): + return "",pkt + + +ietypecls = {1: IE_Cause, + 2: IE_IMSI, + 3: IE_Routing, + 8: IE_ReorderingRequired, + 14: IE_Recovery, + 15: IE_SelectionMode, + 16: IE_TEIDI, + 17: IE_TEICP, + 19: IE_Teardown, + 20: IE_NSAPI, + 26: IE_ChargingCharacteristics, + 27: IE_TraceReference, + 28: IE_TraceType, + 127: IE_ChargingId, + 128: IE_EndUserAddress, + 131: IE_AccessPointName, + 132: IE_ProtocolConfigurationOptions, + 133: IE_GSNAddress, + 134: IE_MSInternationalNumber, + 135: IE_QoS, + 148: IE_CommonFlags, + 149: IE_APNRestriction, + 151: IE_RATType, + 152: IE_UserLocationInformation, + 153: IE_MSTimeZone, + 154: IE_IMEI, + 181: IE_MSInfoChangeReportingAction, + 182: IE_DirectTunnelFlags, + 184: IE_BearerControlMode, + 191: IE_EvolvedAllocationRetentionPriority, + 251: IE_CharginGatewayAddress, + 255: IE_PrivateExtension} + + +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) + +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), + PacketListField("IE_list", [], IE_Dispatcher) ] + + def hashret(self): + return struct.pack("H", self.seq) + + def answers(self, other): + return self.seq == other.seq + + +class GTPCreatePDPContextRequest(Packet): + # 3GPP TS 29.060 V9.1.0 (2009-12) + name = "GTP Create PDP Context Request" + fields_desc = [ ShortField("seq", RandShort()), + ByteField("npdu", 0), + ByteField("next_ex", 0), + PacketListField("IE_list", [ IE_TEIDI(), IE_NSAPI(), IE_GSNAddress(), + IE_GSNAddress(), + IE_NotImplementedTLV(ietype=135, length=15,data=RandString(15)) ], + IE_Dispatcher) ] + def hashret(self): + return struct.pack("H", self.seq) + +class GTPCreatePDPContextResponse(Packet): + # 3GPP TS 29.060 V9.1.0 (2009-12) + name = "GTP Create PDP Context Response" + fields_desc = [ ShortField("seq", RandShort()), + ByteField("npdu", 0), + ByteField("next_ex", 0), + PacketListField("IE_list", [], IE_Dispatcher) ] + + def hashret(self): + return struct.pack("H", self.seq) + + def answers(self, other): + return self.seq == other.seq + + +class GTPUpdatePDPContextRequest(Packet): + # 3GPP TS 29.060 V9.1.0 (2009-12) + name = "GTP Update PDP Context Request" + fields_desc = [ShortField("seq", RandShort()), + ByteField("npdu", 0), + ByteField("next_ex", 0), + PacketListField("IE_list", [ + IE_Cause(), + IE_Recovery(), + IE_TEIDI(), + IE_TEICP(), + IE_ChargingId(), + IE_ProtocolConfigurationOptions(), + IE_GSNAddress(), + IE_GSNAddress(), + IE_GSNAddress(), + IE_GSNAddress(), + IE_QoS(), + IE_CharginGatewayAddress(), + IE_CharginGatewayAddress(), + IE_CommonFlags(), + IE_APNRestriction(), + IE_BearerControlMode(), + IE_MSInfoChangeReportingAction(), + IE_EvolvedAllocationRetentionPriority(), + IE_PrivateExtension()], + IE_Dispatcher)] + + def hashret(self): + return struct.pack("H", self.seq) + + +class GTPUpdatePDPContextResponse(Packet): + # 3GPP TS 29.060 V9.1.0 (2009-12) + name = "GTP Update PDP Context Response" + fields_desc = [ShortField("seq", RandShort()), + ByteField("npdu", 0), + ByteField("next_ex", 0), + PacketListField("IE_list", None, IE_Dispatcher)] + + def hashret(self): + return struct.pack("H", self.seq) + + +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), + PacketListField("IE_list", [], IE_Dispatcher) ] + +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), + PacketListField("IE_list", [], IE_Dispatcher) ] + +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), + PacketListField("IE_list", [], IE_Dispatcher) ] + +class GTPPDUNotificationRequest(Packet): + # 3GPP TS 29.060 V9.1.0 (2009-12) + name = "GTP PDU Notification Request" + fields_desc = [ XBitField("seq", 0, 16), + ByteField("npdu", 0), + ByteField("next_ex", 0), + 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): + # 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 + +class GTPmorethan1500(Packet): + # 3GPP TS 29.060 V9.1.0 (2009-12) + name = "GTP More than 1500" + fields_desc = [ ByteEnumField("IE_Cause", "Cause", IEType), + BitField("IE", 1, 12000),] + +# Bind GTP-C +bind_layers(UDP, GTPHeader, dport = 2123) +bind_layers(UDP, GTPHeader, sport = 2123) +bind_layers(GTPHeader, GTPEchoRequest, gtp_type=1) +bind_layers(GTPHeader, GTPEchoResponse, gtp_type=2) +bind_layers(GTPHeader, GTPCreatePDPContextRequest, gtp_type=16) +bind_layers(GTPHeader, GTPCreatePDPContextResponse, gtp_type=17) +bind_layers(GTPHeader, GTPUpdatePDPContextRequest, gtp_type=18) +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 GTP-U +bind_layers(UDP, GTP_U_Header, dport = 2152) +bind_layers(UDP, GTP_U_Header, sport = 2152) +bind_layers(GTP_U_Header, IP, gtp_type = 255) + +if __name__ == "__main__": + from scapy.all import * + interact(mydict=globals(), mybanner="GTPv1 add-on") diff --git a/scapy/contrib/mqtt.uts b/scapy/contrib/mqtt.uts index 17d92c2d3b90095a2404ec15f8feb0d70306f0c0..0b3f456eede72c88dd0c3c6468d0aa219b194942 100644 --- a/scapy/contrib/mqtt.uts +++ b/scapy/contrib/mqtt.uts @@ -1,110 +1,110 @@ -# MQTT layer unit tests -# Copyright (C) Santiago Hernandez Ramos <shramos@protonmail.com> -# -# Type the following command to launch start the tests: -# $ test/run_tests -P "load_contrib('mqtt')" -t scapy/contrib/mqtt.uts - -+ Syntax check -= Import the MQTT layer -from scapy.contrib.mqtt import * - - -+ MQTT protocol test - -= MQTTPublish, packet instanciation -p = MQTT()/MQTTPublish(topic='test1',value='test2') -assert(p.type == 3) -assert(p.topic == 'test1') -assert(p.value == 'test2') -assert(p.len == None) -assert(p.length == None) - -= Fixed header and MQTTPublish, packet dissection -s = b'0\n\x00\x04testtest' -publish = MQTT(s) -assert(publish.type == 3) -assert(publish.QOS == 0) -assert(publish.DUP == 0) -assert(publish.RETAIN == 0) -assert(publish.len == 10) -assert(publish[MQTTPublish].length == 4) -assert(publish[MQTTPublish].topic == 'test') -assert(publish[MQTTPublish].value == 'test') - - -= MQTTConnect, packet instanciation -c = MQTT()/MQTTConnect(clientIdlen=5, clientId='newid') -assert(c.type == 1) -assert(c.clientId == 'newid') -assert(c.clientIdlen == 5) - -= MQTTConnect, packet dissection -s = b'\x10\x1f\x00\x06MQIsdp\x03\x02\x00<\x00\x11mosqpub/1440-kali' -connect = MQTT(s) -assert(connect.length == 6) -assert(connect.protoname == 'MQIsdp') -assert(connect.protolevel == 3) -assert(connect.usernameflag == 0) -assert(connect.passwordflag == 0) -assert(connect.willretainflag == 0) -assert(connect.willQOSflag == 0) -assert(connect.willflag == 0) -assert(connect.cleansess == 1) -assert(connect.reserved == 0) -assert(connect.klive == 60) -assert(connect.clientIdlen == 17) -assert(connect.clientId == 'mosqpub/1440-kali') - - -=MQTTConnack, packet instanciation -ck = MQTT()/MQTTConnack(sessPresentFlag=1,retcode=0) -assert(ck.type == 2) -assert(ck.sessPresentFlag == 1) -assert(ck.retcode == 0) - -= MQTTConnack, packet dissection -s = b' \x02\x00\x00' -connack = MQTT(s) -assert(connack.sessPresentFlag == 0) -assert(connack.retcode == 0) - - -= MQTTSubscribe, packet instanciation -sb = MQTT()/MQTTSubscribe(msgid=1,topic='newtopic',QOS=0,length=0) -assert(sb.type == 8) -assert(sb.msgid == 1) -assert(sb.topic == 'newtopic') -assert(sb.length == 0) -assert(sb[MQTTSubscribe].QOS == 0) - -= MQTTSubscribe, packet dissection -s = b'\x82\t\x00\x01\x00\x04test\x00' -subscribe = MQTT(s) -assert(subscribe.msgid == 1) -assert(subscribe.length == 4) -assert(subscribe.topic == 'test') -assert(subscribe.QOS == 1) - - -= MQTTSuback, packet instanciation -sk = MQTT()/MQTTSuback(msgid=1, retcode=0) -assert(sk.type == 9) -assert(sk.msgid == 1) -assert(sk.retcode == 0) - -= MQTTSuback, packet dissection -s = b'\x90\x03\x00\x01\x00' -suback = MQTT(s) -assert(suback.msgid == 1) -assert(suback.retcode == 0) - - -= MQTTPubrec, packet instanciation -pc = MQTT()/MQTTPubrec(msgid=1) -assert(pc.type == 5) -assert(pc.msgid == 1) - -= MQTTPubrec packet dissection -s = b'P\x02\x00\x01' -pubrec = MQTT(s) -assert(pubrec.msgid == 1) +# MQTT layer unit tests +# Copyright (C) Santiago Hernandez Ramos <shramos@protonmail.com> +# +# Type the following command to launch start the tests: +# $ test/run_tests -P "load_contrib('mqtt')" -t scapy/contrib/mqtt.uts + ++ Syntax check += Import the MQTT layer +from scapy.contrib.mqtt import * + + ++ MQTT protocol test + += MQTTPublish, packet instanciation +p = MQTT()/MQTTPublish(topic='test1',value='test2') +assert(p.type == 3) +assert(p.topic == 'test1') +assert(p.value == 'test2') +assert(p.len == None) +assert(p.length == None) + += Fixed header and MQTTPublish, packet dissection +s = b'0\n\x00\x04testtest' +publish = MQTT(s) +assert(publish.type == 3) +assert(publish.QOS == 0) +assert(publish.DUP == 0) +assert(publish.RETAIN == 0) +assert(publish.len == 10) +assert(publish[MQTTPublish].length == 4) +assert(publish[MQTTPublish].topic == 'test') +assert(publish[MQTTPublish].value == 'test') + + += MQTTConnect, packet instanciation +c = MQTT()/MQTTConnect(clientIdlen=5, clientId='newid') +assert(c.type == 1) +assert(c.clientId == 'newid') +assert(c.clientIdlen == 5) + += MQTTConnect, packet dissection +s = b'\x10\x1f\x00\x06MQIsdp\x03\x02\x00<\x00\x11mosqpub/1440-kali' +connect = MQTT(s) +assert(connect.length == 6) +assert(connect.protoname == 'MQIsdp') +assert(connect.protolevel == 3) +assert(connect.usernameflag == 0) +assert(connect.passwordflag == 0) +assert(connect.willretainflag == 0) +assert(connect.willQOSflag == 0) +assert(connect.willflag == 0) +assert(connect.cleansess == 1) +assert(connect.reserved == 0) +assert(connect.klive == 60) +assert(connect.clientIdlen == 17) +assert(connect.clientId == 'mosqpub/1440-kali') + + +=MQTTConnack, packet instanciation +ck = MQTT()/MQTTConnack(sessPresentFlag=1,retcode=0) +assert(ck.type == 2) +assert(ck.sessPresentFlag == 1) +assert(ck.retcode == 0) + += MQTTConnack, packet dissection +s = b' \x02\x00\x00' +connack = MQTT(s) +assert(connack.sessPresentFlag == 0) +assert(connack.retcode == 0) + + += MQTTSubscribe, packet instanciation +sb = MQTT()/MQTTSubscribe(msgid=1,topic='newtopic',QOS=0,length=0) +assert(sb.type == 8) +assert(sb.msgid == 1) +assert(sb.topic == 'newtopic') +assert(sb.length == 0) +assert(sb[MQTTSubscribe].QOS == 0) + += MQTTSubscribe, packet dissection +s = b'\x82\t\x00\x01\x00\x04test\x00' +subscribe = MQTT(s) +assert(subscribe.msgid == 1) +assert(subscribe.length == 4) +assert(subscribe.topic == 'test') +assert(subscribe.QOS == 1) + + += MQTTSuback, packet instanciation +sk = MQTT()/MQTTSuback(msgid=1, retcode=0) +assert(sk.type == 9) +assert(sk.msgid == 1) +assert(sk.retcode == 0) + += MQTTSuback, packet dissection +s = b'\x90\x03\x00\x01\x00' +suback = MQTT(s) +assert(suback.msgid == 1) +assert(suback.retcode == 0) + + += MQTTPubrec, packet instanciation +pc = MQTT()/MQTTPubrec(msgid=1) +assert(pc.type == 5) +assert(pc.msgid == 1) + += MQTTPubrec packet dissection +s = b'P\x02\x00\x01' +pubrec = MQTT(s) +assert(pubrec.msgid == 1) diff --git a/scapy/contrib/ppi.py b/scapy/contrib/ppi.py index 95d39ed454f820016bbcda9fbb2451f8fd61c050..13945a33faec1247a1b997e51e182611fb5abf5a 100644 --- a/scapy/contrib/ppi.py +++ b/scapy/contrib/ppi.py @@ -1,97 +1,97 @@ -# This file is part of Scapy -# Scapy is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# any later version. -# -# Scapy is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Scapy. If not, see <http://www.gnu.org/licenses/>. - -# author: <jellch@harris.com> - -# scapy.contrib.description = PPI -# scapy.contrib.status = loads - - -""" -PPI (Per-Packet Information). -""" -import logging,struct -from scapy.config import conf -from scapy.packet import * -from scapy.fields import * -from scapy.layers.l2 import Ether -from scapy.layers.dot11 import Dot11 - -# Dictionary to map the TLV type to the class name of a sub-packet -_ppi_types = {} -def addPPIType(id, value): - _ppi_types[id] = value -def getPPIType(id, default="default"): - return _ppi_types.get(id, _ppi_types.get(default, None)) - - -# Default PPI Field Header -class PPIGenericFldHdr(Packet): - name = "PPI Field Header" - fields_desc = [ LEShortField('pfh_type', 0), - FieldLenField('pfh_length', None, length_of="value", fmt='<H', adjust=lambda p,x:x+4), - StrLenField("value", "", length_from=lambda p:p.pfh_length) ] - - def extract_padding(self, p): - return "",p - -def _PPIGuessPayloadClass(p, **kargs): - """ This function tells the PacketListField how it should extract the - TLVs from the payload. We pass cls only the length string - pfh_len says it needs. If a payload is returned, that means - part of the sting was unused. This converts to a Raw layer, and - the remainder of p is added as Raw's payload. If there is no - payload, the remainder of p is added as out's payload. - """ - if len(p) >= 4: - t,pfh_len = struct.unpack("<HH", p[:4]) - # Find out if the value t is in the dict _ppi_types. - # If not, return the default TLV class - cls = getPPIType(t, "default") - pfh_len += 4 - out = cls(p[:pfh_len], **kargs) - if (out.payload): - out.payload = conf.raw_layer(out.payload.load) - if (len(p) > pfh_len): - out.payload.payload = conf.padding_layer(p[pfh_len:]) - elif (len(p) > pfh_len): - out.payload = conf.padding_layer(p[pfh_len:]) - - else: - out = conf.raw_layer(p, **kargs) - return out - - - - -class PPI(Packet): - name = "PPI Packet Header" - fields_desc = [ ByteField('pph_version', 0), - ByteField('pph_flags', 0), - FieldLenField('pph_len', None, length_of="PPIFieldHeaders", fmt="<H", adjust=lambda p,x:x+8 ), - LEIntField('dlt', None), - PacketListField("PPIFieldHeaders", [], _PPIGuessPayloadClass, length_from=lambda p:p.pph_len-8,) ] - def guess_payload_class(self,payload): - return conf.l2types.get(self.dlt, Packet.guess_payload_class(self, payload)) - -#Register PPI -addPPIType("default", PPIGenericFldHdr) - -conf.l2types.register(192, PPI) -conf.l2types.register_num2layer(192, PPI) - -bind_layers(PPI, Dot11, dlt=conf.l2types.get(Dot11)) -bind_layers(Dot11, PPI) -bind_layers(PPI, Ether, dlt=conf.l2types.get(Ether)) -bind_layers(Dot11, Ether) +# This file is part of Scapy +# Scapy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# any later version. +# +# Scapy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Scapy. If not, see <http://www.gnu.org/licenses/>. + +# author: <jellch@harris.com> + +# scapy.contrib.description = PPI +# scapy.contrib.status = loads + + +""" +PPI (Per-Packet Information). +""" +import logging,struct +from scapy.config import conf +from scapy.packet import * +from scapy.fields import * +from scapy.layers.l2 import Ether +from scapy.layers.dot11 import Dot11 + +# Dictionary to map the TLV type to the class name of a sub-packet +_ppi_types = {} +def addPPIType(id, value): + _ppi_types[id] = value +def getPPIType(id, default="default"): + return _ppi_types.get(id, _ppi_types.get(default, None)) + + +# Default PPI Field Header +class PPIGenericFldHdr(Packet): + name = "PPI Field Header" + fields_desc = [ LEShortField('pfh_type', 0), + FieldLenField('pfh_length', None, length_of="value", fmt='<H', adjust=lambda p,x:x+4), + StrLenField("value", "", length_from=lambda p:p.pfh_length) ] + + def extract_padding(self, p): + return "",p + +def _PPIGuessPayloadClass(p, **kargs): + """ This function tells the PacketListField how it should extract the + TLVs from the payload. We pass cls only the length string + pfh_len says it needs. If a payload is returned, that means + part of the sting was unused. This converts to a Raw layer, and + the remainder of p is added as Raw's payload. If there is no + payload, the remainder of p is added as out's payload. + """ + if len(p) >= 4: + t,pfh_len = struct.unpack("<HH", p[:4]) + # Find out if the value t is in the dict _ppi_types. + # If not, return the default TLV class + cls = getPPIType(t, "default") + pfh_len += 4 + out = cls(p[:pfh_len], **kargs) + if (out.payload): + out.payload = conf.raw_layer(out.payload.load) + if (len(p) > pfh_len): + out.payload.payload = conf.padding_layer(p[pfh_len:]) + elif (len(p) > pfh_len): + out.payload = conf.padding_layer(p[pfh_len:]) + + else: + out = conf.raw_layer(p, **kargs) + return out + + + + +class PPI(Packet): + name = "PPI Packet Header" + fields_desc = [ ByteField('pph_version', 0), + ByteField('pph_flags', 0), + FieldLenField('pph_len', None, length_of="PPIFieldHeaders", fmt="<H", adjust=lambda p,x:x+8 ), + LEIntField('dlt', None), + PacketListField("PPIFieldHeaders", [], _PPIGuessPayloadClass, length_from=lambda p:p.pph_len-8,) ] + def guess_payload_class(self,payload): + return conf.l2types.get(self.dlt, Packet.guess_payload_class(self, payload)) + +#Register PPI +addPPIType("default", PPIGenericFldHdr) + +conf.l2types.register(192, PPI) +conf.l2types.register_num2layer(192, PPI) + +bind_layers(PPI, Dot11, dlt=conf.l2types.get(Dot11)) +bind_layers(Dot11, PPI) +bind_layers(PPI, Ether, dlt=conf.l2types.get(Ether)) +bind_layers(Dot11, Ether) diff --git a/scapy/contrib/ppi_cace.py b/scapy/contrib/ppi_cace.py index 9fc63d25b8d27617f698e327d4b8d6d7c73a72a6..b1896be21e6f209be331f5a84b1ee25278972223 100644 --- a/scapy/contrib/ppi_cace.py +++ b/scapy/contrib/ppi_cace.py @@ -1,98 +1,98 @@ -# This file is part of Scapy -# Scapy is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# any later version. -# -# Scapy is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Scapy. If not, see <http://www.gnu.org/licenses/>. - -# author: <jellch@harris.com> - -# scapy.contrib.description = PPI CACE -# scapy.contrib.status = loads - -""" -CACE PPI types -""" -import logging,struct -from scapy.config import conf -from scapy.packet import * -from scapy.fields import * -from scapy.layers.l2 import Ether -from scapy.layers.dot11 import Dot11 -from scapy.contrib.ppi import * - -PPI_DOT11COMMON = 2 -PPI_DOT11NMAC = 3 -PPI_DOT11NMACPHY = 4 -PPI_SPECTRUMMAP = 5 -PPI_PROCESSINFO = 6 -PPI_CAPTUREINFO = 7 -PPI_AGGREGATION = 8 -PPI_DOT3 = 9 - -# PPI 802.11 Common Field Header Fields -class dBmByteField(Field): - def __init__(self, name, default): - Field.__init__(self, name, default, "b") - def i2repr(self, pkt, val): - if (val != None): - val = "%4d dBm" % val - return val - -class PPITSFTField(LELongField): - def i2h(self, pkt, val): - flags = 0 - if (pkt): - flags = pkt.getfieldval("Pkt_Flags") - if not flags: - flags = 0 - if (flags & 0x02): - scale = 1e-3 - else: - scale = 1e-6 - tout = scale * float(val) - return tout - def h2i(self, pkt, val): - scale = 1e6 - if pkt: - flags = pkt.getfieldval("Pkt_Flags") - if flags: - if (flags & 0x02): - scale = 1e3 - tout = int((scale * val) + 0.5) - return tout - -_PPIDot11CommonChFlags = ['','','','','Turbo','CCK','OFDM','2GHz','5GHz', - 'PassiveOnly','Dynamic CCK-OFDM','GSFK'] - -_PPIDot11CommonPktFlags = ['FCS','TSFT_ms','FCS_Invalid','PHY_Error'] - -# PPI 802.11 Common Field Header -class Dot11Common(Packet): - name = "PPI 802.11-Common" - fields_desc = [ LEShortField('pfh_type',PPI_DOT11COMMON), - LEShortField('pfh_length', 20), - PPITSFTField('TSF_Timer', 0), - FlagsField('Pkt_Flags',0, -16, _PPIDot11CommonPktFlags), - LEShortField('Rate',0), - LEShortField('Ch_Freq',0), - FlagsField('Ch_Flags', 0, -16, _PPIDot11CommonChFlags), - ByteField('FHSS_Hop',0), - ByteField('FHSS_Pat',0), - dBmByteField('Antsignal',-128), - dBmByteField('Antnoise',-128)] - - def extract_padding(self, p): - return "",p -#Hopefully other CACE defined types will be added here. - -#Add the dot11common layer to the PPI array -addPPIType(PPI_DOT11COMMON, Dot11Common) - +# This file is part of Scapy +# Scapy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# any later version. +# +# Scapy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Scapy. If not, see <http://www.gnu.org/licenses/>. + +# author: <jellch@harris.com> + +# scapy.contrib.description = PPI CACE +# scapy.contrib.status = loads + +""" +CACE PPI types +""" +import logging,struct +from scapy.config import conf +from scapy.packet import * +from scapy.fields import * +from scapy.layers.l2 import Ether +from scapy.layers.dot11 import Dot11 +from scapy.contrib.ppi import * + +PPI_DOT11COMMON = 2 +PPI_DOT11NMAC = 3 +PPI_DOT11NMACPHY = 4 +PPI_SPECTRUMMAP = 5 +PPI_PROCESSINFO = 6 +PPI_CAPTUREINFO = 7 +PPI_AGGREGATION = 8 +PPI_DOT3 = 9 + +# PPI 802.11 Common Field Header Fields +class dBmByteField(Field): + def __init__(self, name, default): + Field.__init__(self, name, default, "b") + def i2repr(self, pkt, val): + if (val != None): + val = "%4d dBm" % val + return val + +class PPITSFTField(LELongField): + def i2h(self, pkt, val): + flags = 0 + if (pkt): + flags = pkt.getfieldval("Pkt_Flags") + if not flags: + flags = 0 + if (flags & 0x02): + scale = 1e-3 + else: + scale = 1e-6 + tout = scale * float(val) + return tout + def h2i(self, pkt, val): + scale = 1e6 + if pkt: + flags = pkt.getfieldval("Pkt_Flags") + if flags: + if (flags & 0x02): + scale = 1e3 + tout = int((scale * val) + 0.5) + return tout + +_PPIDot11CommonChFlags = ['','','','','Turbo','CCK','OFDM','2GHz','5GHz', + 'PassiveOnly','Dynamic CCK-OFDM','GSFK'] + +_PPIDot11CommonPktFlags = ['FCS','TSFT_ms','FCS_Invalid','PHY_Error'] + +# PPI 802.11 Common Field Header +class Dot11Common(Packet): + name = "PPI 802.11-Common" + fields_desc = [ LEShortField('pfh_type',PPI_DOT11COMMON), + LEShortField('pfh_length', 20), + PPITSFTField('TSF_Timer', 0), + FlagsField('Pkt_Flags',0, -16, _PPIDot11CommonPktFlags), + LEShortField('Rate',0), + LEShortField('Ch_Freq',0), + FlagsField('Ch_Flags', 0, -16, _PPIDot11CommonChFlags), + ByteField('FHSS_Hop',0), + ByteField('FHSS_Pat',0), + dBmByteField('Antsignal',-128), + dBmByteField('Antnoise',-128)] + + def extract_padding(self, p): + return "",p +#Hopefully other CACE defined types will be added here. + +#Add the dot11common layer to the PPI array +addPPIType(PPI_DOT11COMMON, Dot11Common) + diff --git a/scapy/contrib/ppi_geotag.py b/scapy/contrib/ppi_geotag.py index 47b3d83f35526248e7da04ca37ac7a1893a1cdfb..23fe38b0cc84561ba48f5c8c9b1c4c6f92f7eaf8 100644 --- a/scapy/contrib/ppi_geotag.py +++ b/scapy/contrib/ppi_geotag.py @@ -1,459 +1,459 @@ -# This file is part of Scapy -# Scapy is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# any later version. -# -# Scapy is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Scapy. If not, see <http://www.gnu.org/licenses/>. - -# author: <jellch@harris.com> - -# scapy.contrib.description = PPI GEOLOCATION -# scapy.contrib.status = loads - - -""" -PPI-GEOLOCATION tags -""" -import struct, time -from scapy.packet import * -from scapy.fields import * -from scapy.contrib.ppi import PPIGenericFldHdr,addPPIType -from scapy.error import warning - -CURR_GEOTAG_VER = 2 #Major revision of specification - -PPI_GPS = 30002 -PPI_VECTOR = 30003 -PPI_SENSOR = 30004 -PPI_ANTENNA = 30005 -#The FixedX_Y Fields are used to store fixed point numbers in a variety of fields in the GEOLOCATION-TAGS specification -class Fixed3_6Field(LEIntField): - def i2h(self, pkt, x): - if x is not None: - if (x < 0): - warning("Fixed3_6: Internal value too negative: %d" % x) - x = 0 - elif (x > 999999999): - warning("Fixed3_6: Internal value too positive: %d" % x) - x = 999999999 - x = x * 1e-6 - return x - def h2i(self, pkt, x): - if x is not None: - if (x <= -0.5e-6): - warning("Fixed3_6: Input value too negative: %.7f" % x) - x = 0 - elif (x >= 999.9999995): - warning("Fixed3_6: Input value too positive: %.7f" % x) - x = 999.999999 - x = int(round(x * 1e6)) - return x - def i2m(self, pkt, x): - """Convert internal value to machine value""" - if x is None: - #Try to return zero if undefined - x = self.h2i(pkt, 0) - return x - - def i2repr(self,pkt,x): - if x is None: - y=0 - else: - y=self.i2h(pkt,x) - return "%3.6f"%(y) -class Fixed3_7Field(LEIntField): - def i2h(self, pkt, x): - if x is not None: - if (x < 0): - warning("Fixed3_7: Internal value too negative: %d" % x) - x = 0 - elif (x > 3600000000): - warning("Fixed3_7: Internal value too positive: %d" % x) - x = 3600000000 - x = (x - 1800000000) * 1e-7 - return x - def h2i(self, pkt, x): - if x is not None: - if (x <= -180.00000005): - warning("Fixed3_7: Input value too negative: %.8f" % x) - x = -180.0 - elif (x >= 180.00000005): - warning("Fixed3_7: Input value too positive: %.8f" % x) - x = 180.0 - x = int(round((x + 180.0) * 1e7)) - return x - def i2m(self, pkt, x): - """Convert internal value to machine value""" - if x is None: - #Try to return zero if undefined - x = self.h2i(pkt, 0) - return x - def i2repr(self,pkt,x): - if x is None: - y=0 - else: - y=self.i2h(pkt,x) - return "%3.7f"%(y) - -class Fixed6_4Field(LEIntField): - def i2h(self, pkt, x): - if x is not None: - if (x < 0): - warning("Fixed6_4: Internal value too negative: %d" % x) - x = 0 - elif (x > 3600000000): - warning("Fixed6_4: Internal value too positive: %d" % x) - x = 3600000000 - x = (x - 1800000000) * 1e-4 - return x - def h2i(self, pkt, x): - if x is not None: - if (x <= -180000.00005): - warning("Fixed6_4: Input value too negative: %.5f" % x) - x = -180000.0 - elif (x >= 180000.00005): - warning("Fixed6_4: Input value too positive: %.5f" % x) - x = 180000.0 - x = int(round((x + 180000.0) * 1e4)) - return x - def i2m(self, pkt, x): - """Convert internal value to machine value""" - if x is None: - #Try to return zero if undefined - x = self.h2i(pkt, 0) - return x - def i2repr(self,pkt,x): - if x is None: - y=0 - else: - y=self.i2h(pkt,x) - return "%6.4f"%(y) -#The GPS timestamps fractional time counter is stored in a 32-bit unsigned ns counter. -#The ept field is as well, -class NSCounter_Field(LEIntField): - def i2h(self, pkt, x): #converts nano-seconds to seconds for output - if x is not None: - if (x < 0): - warning("NSCounter_Field: Internal value too negative: %d" % x) - x = 0 - elif (x >= 2**32): - warning("NSCounter_Field: Internal value too positive: %d" % x) - x = 2**32-1 - x = (x / 1e9) - return x - def h2i(self, pkt, x): #converts input in seconds into nano-seconds for storage - if x is not None: - if (x < 0): - warning("NSCounter_Field: Input value too negative: %.10f" % x) - x = 0 - elif (x >= (2**32) / 1e9): - warning("NSCounter_Field: Input value too positive: %.10f" % x) - x = (2**32-1) / 1e9 - x = int(round((x * 1e9))) - return x - def i2repr(self,pkt,x): - if x is None: - y=0 - else: - y=self.i2h(pkt,x) - return "%1.9f"%(y) - -class LETimeField(UTCTimeField,LEIntField): - __slots__ = ["epoch", "delta", "strf"] - def __init__(self, name, default, epoch=None, strf="%a, %d %b %Y %H:%M:%S +0000"): - LEIntField.__init__(self, name, default) - UTCTimeField.__init__(self, name, default, epoch=epoch, strf=strf) - -class SignedByteField(Field): - def __init__(self, name, default): - Field.__init__(self, name, default, "b") - def randval(self): - return RandSByte() - -class XLEShortField(LEShortField,XShortField): - def i2repr(self, pkt, x): - return XShortField.i2repr(self, pkt, x) - -class XLEIntField(LEIntField,XIntField): - def i2repr(self, pkt, x): - return XIntField.i2repr(self, pkt, x) - -class GPSTime_Field(LETimeField): - def __init__(self, name, default): - return LETimeField.__init__(self, name, default, strf="%a, %d %b %Y %H:%M:%S UTC") - -class VectorFlags_Field(XLEIntField): - """Represents te VectorFlags field. Handles the RelativeTo:sub-field""" - _fwdstr = "DefinesForward" - _resmask = 0xfffffff8 - _relmask = 0x6 - _relnames = ["RelativeToForward", "RelativeToEarth", "RelativeToCurrent", "RelativeToReserved"] - _relvals = [0x00, 0x02, 0x04, 0x06] - def i2repr(self, pkt, x): - if x is None: - return str(x) - r = [] - if (x & 0x1): - r.append(self._fwdstr) - i = (x & self._relmask) >> 1 - r.append(self._relnames[i]) - i = x & self._resmask - if (i): - r.append("ReservedBits:%08X" % i) - sout = "+".join(r) - return sout - def any2i(self, pkt, x): - if isinstance(x, str): - r = x.split("+") - y = 0 - for value in r: - if (value == self._fwdstr): - y |= 0x1 - elif (value in self._relnames): - i = self._relnames.index(value) - y &= (~self._relmask) - y |= self._relvals[i] - else: - #logging.warning("Unknown VectorFlags Argument: %s" % value) - pass - else: - y = x - #print "any2i: %s --> %s" % (str(x), str(y)) - return y - -class HCSIFlagsField(FlagsField): - """ A FlagsField where each bit/flag turns a conditional field on or off. - If the value is None when building a packet, i2m() will check the value of - every field in self.names. If the field's value is not None, the corresponding - flag will be set. """ - def i2m(self, pkt, val): - if val is None: - val = 0 - if (pkt): - for i, name in enumerate(self.names): - value = pkt.getfieldval(name) - if value is not None: - val |= 1 << i - return val - -class HCSINullField(StrFixedLenField): - def __init__(self, name, default): - return StrFixedLenField.__init__(self, name, default, length=0) - -class HCSIDescField(StrFixedLenField): - def __init__(self, name, default): - return StrFixedLenField.__init__(self, name, default, length=32) - -class HCSIAppField(StrFixedLenField): - def __init__(self, name, default): - return StrFixedLenField.__init__(self, name, default, length=60) - -def _FlagsList(myfields): - flags = ["Reserved%02d" % i for i in xrange(32)] - for i, value in myfields.iteritems(): - flags[i] = value - return flags - -# Define all geolocation-tag flags lists -_hcsi_gps_flags = _FlagsList({0:"No Fix Available", 1:"GPS", 2:"Differential GPS", - 3:"Pulse Per Second", 4:"Real Time Kinematic", - 5:"Float Real Time Kinematic", 6:"Estimated (Dead Reckoning)", - 7:"Manual Input", 8:"Simulation"}) - -#_hcsi_vector_flags = _FlagsList({0:"ForwardFrame", 1:"RotationsAbsoluteXYZ", 5:"OffsetFromGPS_XYZ"}) -#This has been replaced with the VectorFlags_Field class, in order to handle the RelativeTo:subfield - -_hcsi_vector_char_flags = _FlagsList({0:"Antenna", 1:"Direction of Travel", - 2:"Front of Vehicle", 3:"Angle of Arrival", 4:"Transmitter Position", - 8:"GPS Derived", 9:"INS Derived", 10:"Compass Derived", - 11:"Acclerometer Derived", 12:"Human Derived"}) - -_hcsi_antenna_flags = _FlagsList({ 1:"Horizontal Polarization", 2:"Vertical Polarization", - 3:"Circular Polarization Left", 4:"Circular Polarization Right", - 16:"Electronically Steerable", 17:"Mechanically Steerable"}) - -""" HCSI PPI Fields are similar to RadioTap. A mask field called "present" specifies if each field -is present. All other fields are conditional. When dissecting a packet, each field is present if -"present" has the corresponding bit set. When building a packet, if "present" is None, the mask is -set to include every field that does not have a value of None. Otherwise, if the mask field is -not None, only the fields specified by "present" will be added to the packet. - -To build each Packet type, build a list of the fields normally, excluding the present bitmask field. -The code will then construct conditional versions of each field and add the present field. -See GPS_Fields as an example. """ - -# Conditional test for all HCSI Fields -def _HCSITest(pkt, ibit, name): - if pkt.present is None: - return (pkt.getfieldval(name) is not None) - return pkt.present & ibit - -# Wrap optional fields in ConditionalField, add HCSIFlagsField -def _HCSIBuildFields(fields): - names = [f.name for f in fields] - cond_fields = [HCSIFlagsField('present', None, -len(names), names)] - for i, name in enumerate(names): - ibit = 1 << i - seval = "lambda pkt:_HCSITest(pkt,%s,'%s')" % (ibit, name) - test = eval(seval) - cond_fields.append(ConditionalField(fields[i], test)) - return cond_fields - -class HCSIPacket(Packet): - name = "PPI HCSI" - fields_desc = [ LEShortField('pfh_type', None), - LEShortField('pfh_length', None), - ByteField('geotag_ver', CURR_GEOTAG_VER), - ByteField('geotag_pad', 0), - LEShortField('geotag_len', None)] - def post_build(self, p, pay): - if self.pfh_length is None: - l = len(p) - 4 - sl = struct.pack('<H',l) - p = p[:2] + sl + p[4:] - if self.geotag_len is None: - l_g = len(p) - 4 - sl_g = struct.pack('<H',l_g) - p = p[:6] + sl_g + p[8:] - p += pay - return p - def extract_padding(self, p): - return "",p - -#GPS Fields -GPS_Fields = [FlagsField("GPSFlags", None, -32, _hcsi_gps_flags), - Fixed3_7Field("Latitude", None), - Fixed3_7Field("Longitude", None), Fixed6_4Field("Altitude", None), - Fixed6_4Field("Altitude_g", None), GPSTime_Field("GPSTime", None), - NSCounter_Field("FractionalTime", None), Fixed3_6Field("eph", None), - Fixed3_6Field("epv", None), NSCounter_Field("ept", None), - HCSINullField("Reserved10", None), HCSINullField("Reserved11", None), - HCSINullField("Reserved12", None), HCSINullField("Reserved13", None), - HCSINullField("Reserved14", None), HCSINullField("Reserved15", None), - HCSINullField("Reserved16", None), HCSINullField("Reserved17", None), - HCSINullField("Reserved18", None), HCSINullField("Reserved19", None), - HCSINullField("Reserved20", None), HCSINullField("Reserved21", None), - HCSINullField("Reserved22", None), HCSINullField("Reserved23", None), - HCSINullField("Reserved24", None), HCSINullField("Reserved25", None), - HCSINullField("Reserved26", None), HCSINullField("Reserved27", None), - HCSIDescField("DescString", None), XLEIntField("AppId", None), - HCSIAppField("AppData", None), HCSINullField("Extended", None)] - -class GPS(HCSIPacket): - name = "PPI GPS" - fields_desc = [ LEShortField('pfh_type', PPI_GPS), #pfh_type - LEShortField('pfh_length', None), #pfh_len - ByteField('geotag_ver', CURR_GEOTAG_VER), #base_geotag_header.ver - ByteField('geotag_pad', 0), #base_geotag_header.pad - LEShortField('geotag_len', None)] + _HCSIBuildFields(GPS_Fields) - - -#Vector Fields -VEC_Fields = [VectorFlags_Field("VectorFlags", None), - FlagsField("VectorChars", None, -32, _hcsi_vector_char_flags), - Fixed3_6Field("Pitch", None), Fixed3_6Field("Roll", None), - Fixed3_6Field("Heading", None), Fixed6_4Field("Off_X", None), - Fixed6_4Field("Off_Y", None), Fixed6_4Field("Off_Z", None), - HCSINullField("Reserved08", None), HCSINullField("Reserved09", None), - HCSINullField("Reserved10", None), HCSINullField("Reserved11", None), - HCSINullField("Reserved12", None), HCSINullField("Reserved13", None), - HCSINullField("Reserved14", None), HCSINullField("Reserved15", None), - Fixed3_6Field("Err_Rot", None), Fixed6_4Field("Err_Off", None), - HCSINullField("Reserved18", None), HCSINullField("Reserved19", None), - HCSINullField("Reserved20", None), HCSINullField("Reserved21", None), - HCSINullField("Reserved22", None), HCSINullField("Reserved23", None), - HCSINullField("Reserved24", None), HCSINullField("Reserved25", None), - HCSINullField("Reserved26", None), HCSINullField("Reserved27", None), - HCSIDescField("DescString", None), XLEIntField("AppId", None), - HCSIAppField("AppData", None), HCSINullField("Extended", None)] - -class Vector(HCSIPacket): - name = "PPI Vector" - fields_desc = [ LEShortField('pfh_type', PPI_VECTOR), #pfh_type - LEShortField('pfh_length', None), #pfh_len - ByteField('geotag_ver', CURR_GEOTAG_VER), #base_geotag_header.ver - ByteField('geotag_pad', 0), #base_geotag_header.pad - LEShortField('geotag_len', None)] + _HCSIBuildFields(VEC_Fields) - -#Sensor Fields -# http://www.iana.org/assignments/icmp-parameters -sensor_types= { 1 : "Velocity", - 2 : "Acceleration", - 3 : "Jerk", - 100 : "Rotation", - 101 : "Magnetic", - 1000: "Temperature", - 1001: "Barometer", - 1002: "Humidity", - 2000: "TDOA_Clock", - 2001: "Phase" - } -SENS_Fields = [ LEShortEnumField('SensorType', None, sensor_types), - SignedByteField('ScaleFactor', None), - Fixed6_4Field('Val_X', None), - Fixed6_4Field('Val_Y', None), - Fixed6_4Field('Val_Z', None), - Fixed6_4Field('Val_T', None), - Fixed6_4Field('Val_E', None), - HCSINullField("Reserved07", None), HCSINullField("Reserved08", None), - HCSINullField("Reserved09", None), HCSINullField("Reserved10", None), - HCSINullField("Reserved11", None), HCSINullField("Reserved12", None), - HCSINullField("Reserved13", None), HCSINullField("Reserved14", None), - HCSINullField("Reserved15", None), HCSINullField("Reserved16", None), - HCSINullField("Reserved17", None), HCSINullField("Reserved18", None), - HCSINullField("Reserved19", None), HCSINullField("Reserved20", None), - HCSINullField("Reserved21", None), HCSINullField("Reserved22", None), - HCSINullField("Reserved23", None), HCSINullField("Reserved24", None), - HCSINullField("Reserved25", None), HCSINullField("Reserved26", None), - HCSINullField("Reserved27", None), - HCSIDescField("DescString", None), XLEIntField("AppId", None), - HCSIAppField("AppData", None), HCSINullField("Extended", None)] - - - -class Sensor(HCSIPacket): - name = "PPI Sensor" - fields_desc = [ LEShortField('pfh_type', PPI_SENSOR), #pfh_type - LEShortField('pfh_length', None), #pfh_len - ByteField('geotag_ver', CURR_GEOTAG_VER ), #base_geotag_header.ver - ByteField('geotag_pad', 0), #base_geotag_header.pad - LEShortField('geotag_len', None)] + _HCSIBuildFields(SENS_Fields) - -# HCSIAntenna Fields -ANT_Fields = [FlagsField("AntennaFlags", None, -32, _hcsi_antenna_flags), - ByteField("Gain", None), - Fixed3_6Field("HorizBw", None), Fixed3_6Field("VertBw", None), - Fixed3_6Field("PrecisionGain",None), XLEShortField("BeamID", None), - HCSINullField("Reserved06", None), HCSINullField("Reserved07", None), - HCSINullField("Reserved08", None), HCSINullField("Reserved09", None), - HCSINullField("Reserved10", None), HCSINullField("Reserved11", None), - HCSINullField("Reserved12", None), HCSINullField("Reserved13", None), - HCSINullField("Reserved14", None), HCSINullField("Reserved15", None), - HCSINullField("Reserved16", None), HCSINullField("Reserved17", None), - HCSINullField("Reserved18", None), HCSINullField("Reserved19", None), - HCSINullField("Reserved20", None), HCSINullField("Reserved21", None), - HCSINullField("Reserved22", None), HCSINullField("Reserved23", None), - HCSINullField("Reserved24", None), HCSINullField("Reserved25", None), - HCSIDescField("SerialNumber", None), HCSIDescField("ModelName", None), - HCSIDescField("DescString", None), XLEIntField("AppId", None), - HCSIAppField("AppData", None), HCSINullField("Extended", None)] - -class Antenna(HCSIPacket): - name = "PPI Antenna" - fields_desc = [ LEShortField('pfh_type', PPI_ANTENNA), #pfh_type - LEShortField('pfh_length', None), #pfh_len - ByteField('geotag_ver', CURR_GEOTAG_VER), #base_geotag_header.ver - ByteField('geotag_pad', 0), #base_geotag_header.pad - LEShortField('geotag_len', None)] + _HCSIBuildFields(ANT_Fields) - -addPPIType(PPI_GPS, GPS) -addPPIType(PPI_VECTOR, Vector) -addPPIType(PPI_SENSOR, Sensor) -addPPIType(PPI_ANTENNA,Antenna) +# This file is part of Scapy +# Scapy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# any later version. +# +# Scapy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Scapy. If not, see <http://www.gnu.org/licenses/>. + +# author: <jellch@harris.com> + +# scapy.contrib.description = PPI GEOLOCATION +# scapy.contrib.status = loads + + +""" +PPI-GEOLOCATION tags +""" +import struct, time +from scapy.packet import * +from scapy.fields import * +from scapy.contrib.ppi import PPIGenericFldHdr,addPPIType +from scapy.error import warning + +CURR_GEOTAG_VER = 2 #Major revision of specification + +PPI_GPS = 30002 +PPI_VECTOR = 30003 +PPI_SENSOR = 30004 +PPI_ANTENNA = 30005 +#The FixedX_Y Fields are used to store fixed point numbers in a variety of fields in the GEOLOCATION-TAGS specification +class Fixed3_6Field(LEIntField): + def i2h(self, pkt, x): + if x is not None: + if (x < 0): + warning("Fixed3_6: Internal value too negative: %d" % x) + x = 0 + elif (x > 999999999): + warning("Fixed3_6: Internal value too positive: %d" % x) + x = 999999999 + x = x * 1e-6 + return x + def h2i(self, pkt, x): + if x is not None: + if (x <= -0.5e-6): + warning("Fixed3_6: Input value too negative: %.7f" % x) + x = 0 + elif (x >= 999.9999995): + warning("Fixed3_6: Input value too positive: %.7f" % x) + x = 999.999999 + x = int(round(x * 1e6)) + return x + def i2m(self, pkt, x): + """Convert internal value to machine value""" + if x is None: + #Try to return zero if undefined + x = self.h2i(pkt, 0) + return x + + def i2repr(self,pkt,x): + if x is None: + y=0 + else: + y=self.i2h(pkt,x) + return "%3.6f"%(y) +class Fixed3_7Field(LEIntField): + def i2h(self, pkt, x): + if x is not None: + if (x < 0): + warning("Fixed3_7: Internal value too negative: %d" % x) + x = 0 + elif (x > 3600000000): + warning("Fixed3_7: Internal value too positive: %d" % x) + x = 3600000000 + x = (x - 1800000000) * 1e-7 + return x + def h2i(self, pkt, x): + if x is not None: + if (x <= -180.00000005): + warning("Fixed3_7: Input value too negative: %.8f" % x) + x = -180.0 + elif (x >= 180.00000005): + warning("Fixed3_7: Input value too positive: %.8f" % x) + x = 180.0 + x = int(round((x + 180.0) * 1e7)) + return x + def i2m(self, pkt, x): + """Convert internal value to machine value""" + if x is None: + #Try to return zero if undefined + x = self.h2i(pkt, 0) + return x + def i2repr(self,pkt,x): + if x is None: + y=0 + else: + y=self.i2h(pkt,x) + return "%3.7f"%(y) + +class Fixed6_4Field(LEIntField): + def i2h(self, pkt, x): + if x is not None: + if (x < 0): + warning("Fixed6_4: Internal value too negative: %d" % x) + x = 0 + elif (x > 3600000000): + warning("Fixed6_4: Internal value too positive: %d" % x) + x = 3600000000 + x = (x - 1800000000) * 1e-4 + return x + def h2i(self, pkt, x): + if x is not None: + if (x <= -180000.00005): + warning("Fixed6_4: Input value too negative: %.5f" % x) + x = -180000.0 + elif (x >= 180000.00005): + warning("Fixed6_4: Input value too positive: %.5f" % x) + x = 180000.0 + x = int(round((x + 180000.0) * 1e4)) + return x + def i2m(self, pkt, x): + """Convert internal value to machine value""" + if x is None: + #Try to return zero if undefined + x = self.h2i(pkt, 0) + return x + def i2repr(self,pkt,x): + if x is None: + y=0 + else: + y=self.i2h(pkt,x) + return "%6.4f"%(y) +#The GPS timestamps fractional time counter is stored in a 32-bit unsigned ns counter. +#The ept field is as well, +class NSCounter_Field(LEIntField): + def i2h(self, pkt, x): #converts nano-seconds to seconds for output + if x is not None: + if (x < 0): + warning("NSCounter_Field: Internal value too negative: %d" % x) + x = 0 + elif (x >= 2**32): + warning("NSCounter_Field: Internal value too positive: %d" % x) + x = 2**32-1 + x = (x / 1e9) + return x + def h2i(self, pkt, x): #converts input in seconds into nano-seconds for storage + if x is not None: + if (x < 0): + warning("NSCounter_Field: Input value too negative: %.10f" % x) + x = 0 + elif (x >= (2**32) / 1e9): + warning("NSCounter_Field: Input value too positive: %.10f" % x) + x = (2**32-1) / 1e9 + x = int(round((x * 1e9))) + return x + def i2repr(self,pkt,x): + if x is None: + y=0 + else: + y=self.i2h(pkt,x) + return "%1.9f"%(y) + +class LETimeField(UTCTimeField,LEIntField): + __slots__ = ["epoch", "delta", "strf"] + def __init__(self, name, default, epoch=None, strf="%a, %d %b %Y %H:%M:%S +0000"): + LEIntField.__init__(self, name, default) + UTCTimeField.__init__(self, name, default, epoch=epoch, strf=strf) + +class SignedByteField(Field): + def __init__(self, name, default): + Field.__init__(self, name, default, "b") + def randval(self): + return RandSByte() + +class XLEShortField(LEShortField,XShortField): + def i2repr(self, pkt, x): + return XShortField.i2repr(self, pkt, x) + +class XLEIntField(LEIntField,XIntField): + def i2repr(self, pkt, x): + return XIntField.i2repr(self, pkt, x) + +class GPSTime_Field(LETimeField): + def __init__(self, name, default): + return LETimeField.__init__(self, name, default, strf="%a, %d %b %Y %H:%M:%S UTC") + +class VectorFlags_Field(XLEIntField): + """Represents te VectorFlags field. Handles the RelativeTo:sub-field""" + _fwdstr = "DefinesForward" + _resmask = 0xfffffff8 + _relmask = 0x6 + _relnames = ["RelativeToForward", "RelativeToEarth", "RelativeToCurrent", "RelativeToReserved"] + _relvals = [0x00, 0x02, 0x04, 0x06] + def i2repr(self, pkt, x): + if x is None: + return str(x) + r = [] + if (x & 0x1): + r.append(self._fwdstr) + i = (x & self._relmask) >> 1 + r.append(self._relnames[i]) + i = x & self._resmask + if (i): + r.append("ReservedBits:%08X" % i) + sout = "+".join(r) + return sout + def any2i(self, pkt, x): + if isinstance(x, str): + r = x.split("+") + y = 0 + for value in r: + if (value == self._fwdstr): + y |= 0x1 + elif (value in self._relnames): + i = self._relnames.index(value) + y &= (~self._relmask) + y |= self._relvals[i] + else: + #logging.warning("Unknown VectorFlags Argument: %s" % value) + pass + else: + y = x + #print "any2i: %s --> %s" % (str(x), str(y)) + return y + +class HCSIFlagsField(FlagsField): + """ A FlagsField where each bit/flag turns a conditional field on or off. + If the value is None when building a packet, i2m() will check the value of + every field in self.names. If the field's value is not None, the corresponding + flag will be set. """ + def i2m(self, pkt, val): + if val is None: + val = 0 + if (pkt): + for i, name in enumerate(self.names): + value = pkt.getfieldval(name) + if value is not None: + val |= 1 << i + return val + +class HCSINullField(StrFixedLenField): + def __init__(self, name, default): + return StrFixedLenField.__init__(self, name, default, length=0) + +class HCSIDescField(StrFixedLenField): + def __init__(self, name, default): + return StrFixedLenField.__init__(self, name, default, length=32) + +class HCSIAppField(StrFixedLenField): + def __init__(self, name, default): + return StrFixedLenField.__init__(self, name, default, length=60) + +def _FlagsList(myfields): + flags = ["Reserved%02d" % i for i in xrange(32)] + for i, value in myfields.iteritems(): + flags[i] = value + return flags + +# Define all geolocation-tag flags lists +_hcsi_gps_flags = _FlagsList({0:"No Fix Available", 1:"GPS", 2:"Differential GPS", + 3:"Pulse Per Second", 4:"Real Time Kinematic", + 5:"Float Real Time Kinematic", 6:"Estimated (Dead Reckoning)", + 7:"Manual Input", 8:"Simulation"}) + +#_hcsi_vector_flags = _FlagsList({0:"ForwardFrame", 1:"RotationsAbsoluteXYZ", 5:"OffsetFromGPS_XYZ"}) +#This has been replaced with the VectorFlags_Field class, in order to handle the RelativeTo:subfield + +_hcsi_vector_char_flags = _FlagsList({0:"Antenna", 1:"Direction of Travel", + 2:"Front of Vehicle", 3:"Angle of Arrival", 4:"Transmitter Position", + 8:"GPS Derived", 9:"INS Derived", 10:"Compass Derived", + 11:"Acclerometer Derived", 12:"Human Derived"}) + +_hcsi_antenna_flags = _FlagsList({ 1:"Horizontal Polarization", 2:"Vertical Polarization", + 3:"Circular Polarization Left", 4:"Circular Polarization Right", + 16:"Electronically Steerable", 17:"Mechanically Steerable"}) + +""" HCSI PPI Fields are similar to RadioTap. A mask field called "present" specifies if each field +is present. All other fields are conditional. When dissecting a packet, each field is present if +"present" has the corresponding bit set. When building a packet, if "present" is None, the mask is +set to include every field that does not have a value of None. Otherwise, if the mask field is +not None, only the fields specified by "present" will be added to the packet. + +To build each Packet type, build a list of the fields normally, excluding the present bitmask field. +The code will then construct conditional versions of each field and add the present field. +See GPS_Fields as an example. """ + +# Conditional test for all HCSI Fields +def _HCSITest(pkt, ibit, name): + if pkt.present is None: + return (pkt.getfieldval(name) is not None) + return pkt.present & ibit + +# Wrap optional fields in ConditionalField, add HCSIFlagsField +def _HCSIBuildFields(fields): + names = [f.name for f in fields] + cond_fields = [HCSIFlagsField('present', None, -len(names), names)] + for i, name in enumerate(names): + ibit = 1 << i + seval = "lambda pkt:_HCSITest(pkt,%s,'%s')" % (ibit, name) + test = eval(seval) + cond_fields.append(ConditionalField(fields[i], test)) + return cond_fields + +class HCSIPacket(Packet): + name = "PPI HCSI" + fields_desc = [ LEShortField('pfh_type', None), + LEShortField('pfh_length', None), + ByteField('geotag_ver', CURR_GEOTAG_VER), + ByteField('geotag_pad', 0), + LEShortField('geotag_len', None)] + def post_build(self, p, pay): + if self.pfh_length is None: + l = len(p) - 4 + sl = struct.pack('<H',l) + p = p[:2] + sl + p[4:] + if self.geotag_len is None: + l_g = len(p) - 4 + sl_g = struct.pack('<H',l_g) + p = p[:6] + sl_g + p[8:] + p += pay + return p + def extract_padding(self, p): + return "",p + +#GPS Fields +GPS_Fields = [FlagsField("GPSFlags", None, -32, _hcsi_gps_flags), + Fixed3_7Field("Latitude", None), + Fixed3_7Field("Longitude", None), Fixed6_4Field("Altitude", None), + Fixed6_4Field("Altitude_g", None), GPSTime_Field("GPSTime", None), + NSCounter_Field("FractionalTime", None), Fixed3_6Field("eph", None), + Fixed3_6Field("epv", None), NSCounter_Field("ept", None), + HCSINullField("Reserved10", None), HCSINullField("Reserved11", None), + HCSINullField("Reserved12", None), HCSINullField("Reserved13", None), + HCSINullField("Reserved14", None), HCSINullField("Reserved15", None), + HCSINullField("Reserved16", None), HCSINullField("Reserved17", None), + HCSINullField("Reserved18", None), HCSINullField("Reserved19", None), + HCSINullField("Reserved20", None), HCSINullField("Reserved21", None), + HCSINullField("Reserved22", None), HCSINullField("Reserved23", None), + HCSINullField("Reserved24", None), HCSINullField("Reserved25", None), + HCSINullField("Reserved26", None), HCSINullField("Reserved27", None), + HCSIDescField("DescString", None), XLEIntField("AppId", None), + HCSIAppField("AppData", None), HCSINullField("Extended", None)] + +class GPS(HCSIPacket): + name = "PPI GPS" + fields_desc = [ LEShortField('pfh_type', PPI_GPS), #pfh_type + LEShortField('pfh_length', None), #pfh_len + ByteField('geotag_ver', CURR_GEOTAG_VER), #base_geotag_header.ver + ByteField('geotag_pad', 0), #base_geotag_header.pad + LEShortField('geotag_len', None)] + _HCSIBuildFields(GPS_Fields) + + +#Vector Fields +VEC_Fields = [VectorFlags_Field("VectorFlags", None), + FlagsField("VectorChars", None, -32, _hcsi_vector_char_flags), + Fixed3_6Field("Pitch", None), Fixed3_6Field("Roll", None), + Fixed3_6Field("Heading", None), Fixed6_4Field("Off_X", None), + Fixed6_4Field("Off_Y", None), Fixed6_4Field("Off_Z", None), + HCSINullField("Reserved08", None), HCSINullField("Reserved09", None), + HCSINullField("Reserved10", None), HCSINullField("Reserved11", None), + HCSINullField("Reserved12", None), HCSINullField("Reserved13", None), + HCSINullField("Reserved14", None), HCSINullField("Reserved15", None), + Fixed3_6Field("Err_Rot", None), Fixed6_4Field("Err_Off", None), + HCSINullField("Reserved18", None), HCSINullField("Reserved19", None), + HCSINullField("Reserved20", None), HCSINullField("Reserved21", None), + HCSINullField("Reserved22", None), HCSINullField("Reserved23", None), + HCSINullField("Reserved24", None), HCSINullField("Reserved25", None), + HCSINullField("Reserved26", None), HCSINullField("Reserved27", None), + HCSIDescField("DescString", None), XLEIntField("AppId", None), + HCSIAppField("AppData", None), HCSINullField("Extended", None)] + +class Vector(HCSIPacket): + name = "PPI Vector" + fields_desc = [ LEShortField('pfh_type', PPI_VECTOR), #pfh_type + LEShortField('pfh_length', None), #pfh_len + ByteField('geotag_ver', CURR_GEOTAG_VER), #base_geotag_header.ver + ByteField('geotag_pad', 0), #base_geotag_header.pad + LEShortField('geotag_len', None)] + _HCSIBuildFields(VEC_Fields) + +#Sensor Fields +# http://www.iana.org/assignments/icmp-parameters +sensor_types= { 1 : "Velocity", + 2 : "Acceleration", + 3 : "Jerk", + 100 : "Rotation", + 101 : "Magnetic", + 1000: "Temperature", + 1001: "Barometer", + 1002: "Humidity", + 2000: "TDOA_Clock", + 2001: "Phase" + } +SENS_Fields = [ LEShortEnumField('SensorType', None, sensor_types), + SignedByteField('ScaleFactor', None), + Fixed6_4Field('Val_X', None), + Fixed6_4Field('Val_Y', None), + Fixed6_4Field('Val_Z', None), + Fixed6_4Field('Val_T', None), + Fixed6_4Field('Val_E', None), + HCSINullField("Reserved07", None), HCSINullField("Reserved08", None), + HCSINullField("Reserved09", None), HCSINullField("Reserved10", None), + HCSINullField("Reserved11", None), HCSINullField("Reserved12", None), + HCSINullField("Reserved13", None), HCSINullField("Reserved14", None), + HCSINullField("Reserved15", None), HCSINullField("Reserved16", None), + HCSINullField("Reserved17", None), HCSINullField("Reserved18", None), + HCSINullField("Reserved19", None), HCSINullField("Reserved20", None), + HCSINullField("Reserved21", None), HCSINullField("Reserved22", None), + HCSINullField("Reserved23", None), HCSINullField("Reserved24", None), + HCSINullField("Reserved25", None), HCSINullField("Reserved26", None), + HCSINullField("Reserved27", None), + HCSIDescField("DescString", None), XLEIntField("AppId", None), + HCSIAppField("AppData", None), HCSINullField("Extended", None)] + + + +class Sensor(HCSIPacket): + name = "PPI Sensor" + fields_desc = [ LEShortField('pfh_type', PPI_SENSOR), #pfh_type + LEShortField('pfh_length', None), #pfh_len + ByteField('geotag_ver', CURR_GEOTAG_VER ), #base_geotag_header.ver + ByteField('geotag_pad', 0), #base_geotag_header.pad + LEShortField('geotag_len', None)] + _HCSIBuildFields(SENS_Fields) + +# HCSIAntenna Fields +ANT_Fields = [FlagsField("AntennaFlags", None, -32, _hcsi_antenna_flags), + ByteField("Gain", None), + Fixed3_6Field("HorizBw", None), Fixed3_6Field("VertBw", None), + Fixed3_6Field("PrecisionGain",None), XLEShortField("BeamID", None), + HCSINullField("Reserved06", None), HCSINullField("Reserved07", None), + HCSINullField("Reserved08", None), HCSINullField("Reserved09", None), + HCSINullField("Reserved10", None), HCSINullField("Reserved11", None), + HCSINullField("Reserved12", None), HCSINullField("Reserved13", None), + HCSINullField("Reserved14", None), HCSINullField("Reserved15", None), + HCSINullField("Reserved16", None), HCSINullField("Reserved17", None), + HCSINullField("Reserved18", None), HCSINullField("Reserved19", None), + HCSINullField("Reserved20", None), HCSINullField("Reserved21", None), + HCSINullField("Reserved22", None), HCSINullField("Reserved23", None), + HCSINullField("Reserved24", None), HCSINullField("Reserved25", None), + HCSIDescField("SerialNumber", None), HCSIDescField("ModelName", None), + HCSIDescField("DescString", None), XLEIntField("AppId", None), + HCSIAppField("AppData", None), HCSINullField("Extended", None)] + +class Antenna(HCSIPacket): + name = "PPI Antenna" + fields_desc = [ LEShortField('pfh_type', PPI_ANTENNA), #pfh_type + LEShortField('pfh_length', None), #pfh_len + ByteField('geotag_ver', CURR_GEOTAG_VER), #base_geotag_header.ver + ByteField('geotag_pad', 0), #base_geotag_header.pad + LEShortField('geotag_len', None)] + _HCSIBuildFields(ANT_Fields) + +addPPIType(PPI_GPS, GPS) +addPPIType(PPI_VECTOR, Vector) +addPPIType(PPI_SENSOR, Sensor) +addPPIType(PPI_ANTENNA,Antenna) diff --git a/scapy/contrib/rsvp.py b/scapy/contrib/rsvp.py index b8d8d7f4fc629409bcef98f869cdc739c0b7330c..3908546c5b9459609152a875544eaae7aa7d8d57 100644 --- a/scapy/contrib/rsvp.py +++ b/scapy/contrib/rsvp.py @@ -1,200 +1,200 @@ -## RSVP layer - -# This file is part of Scapy -# Scapy is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# any later version. -# -# Scapy is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Scapy. If not, see <http://www.gnu.org/licenses/>. - -# scapy.contrib.description = RSVP -# scapy.contrib.status = loads - -from scapy.packet import * -from scapy.fields import * -from scapy.layers.inet import IP - -rsvpmsgtypes = { 0x01 : "Path", - 0x02 : "Reservation request", - 0x03 : "Path error", - 0x04 : "Reservation request error", - 0x05 : "Path teardown", - 0x06 : "Reservation teardown", - 0x07 : "Reservation request acknowledgment" -} - -class RSVP(Packet): - name = "RSVP" - fields_desc = [ BitField("Version",1,4), - BitField("Flags",1,4), - ByteEnumField("Class",0x01, rsvpmsgtypes), - XShortField("chksum", None), - ByteField("TTL",1), - XByteField("dataofs", 0), - ShortField("Length",None)] - def post_build(self, p, pay): - p += pay - if self.Length is None: - l = len(p) - p = p[:6]+chr((l>>8)&0xff)+chr(l&0xff)+p[8:] - if self.chksum is None: - ck = checksum(p) - p = p[:2]+chr(ck>>8)+chr(ck&0xff)+p[4:] - return p - -rsvptypes = { 0x01 : "Session", - 0x03 : "HOP", - 0x04 : "INTEGRITY", - 0x05 : "TIME_VALUES", - 0x06 : "ERROR_SPEC", - 0x07 : "SCOPE", - 0x08 : "STYLE", - 0x09 : "FLOWSPEC", - 0x0A : "FILTER_SPEC", - 0x0B : "SENDER_TEMPLATE", - 0x0C : "SENDER_TSPEC", - 0x0D : "ADSPEC", - 0x0E : "POLICY_DATA", - 0x0F : "RESV_CONFIRM", - 0x10 : "RSVP_LABEL", - 0x11 : "HOP_COUNT", - 0x12 : "STRICT_SOURCE_ROUTE", - 0x13 : "LABEL_REQUEST", - 0x14 : "EXPLICIT_ROUTE", - 0x15 : "ROUTE_RECORD", - 0x16 : "HELLO", - 0x17 : "MESSAGE_ID", - 0x18 : "MESSAGE_ID_ACK", - 0x19 : "MESSAGE_ID_LIST", - 0x1E : "DIAGNOSTIC", - 0x1F : "ROUTE", - 0x20 : "DIAG_RESPONSE", - 0x21 : "DIAG_SELECT", - 0x22 : "RECOVERY_LABEL", - 0x23 : "UPSTREAM_LABEL", - 0x24 : "LABEL_SET", - 0x25 : "PROTECTION", - 0x26 : "PRIMARY PATH ROUTE", - 0x2A : "DSBM IP ADDRESS", - 0x2B : "SBM_PRIORITY", - 0x2C : "DSBM TIMER INTERVALS", - 0x2D : "SBM_INFO", - 0x32 : "S2L_SUB_LSP", - 0x3F : "DETOUR", - 0x40 : "CHALLENGE", - 0x41 : "DIFF-SERV", - 0x42 : "CLASSTYPE", - 0x43 : "LSP_REQUIRED_ATTRIBUTES", - 0x80 : "NODE_CHAR", - 0x81 : "SUGGESTED_LABEL", - 0x82 : "ACCEPTABLE_LABEL_SET", - 0x83 : "RESTART_CA", - 0x84 : "SESSION-OF-INTEREST", - 0x85 : "LINK_CAPABILITY", - 0x86 : "Capability Object", - 0xA1 : "RSVP_HOP_L2", - 0xA2 : "LAN_NHOP_L2", - 0xA3 : "LAN_NHOP_L3", - 0xA4 : "LAN_LOOPBACK", - 0xA5 : "TCLASS", - 0xC0 : "TUNNEL", - 0xC1 : "LSP_TUNNEL_INTERFACE_ID", - 0xC2 : "USER_ERROR_SPEC", - 0xC3 : "NOTIFY_REQUEST", - 0xC4 : "ADMIN-STATUS", - 0xC5 : "LSP_ATTRIBUTES", - 0xC6 : "ALARM_SPEC", - 0xC7 : "ASSOCIATION", - 0xC8 : "SECONDARY_EXPLICIT_ROUTE", - 0xC9 : "SECONDARY_RECORD_ROUTE", - 0xCD : "FAST_REROUTE", - 0xCF : "SESSION_ATTRIBUTE", - 0xE1 : "DCLASS", - 0xE2 : "PACKETCABLE EXTENSIONS", - 0xE3 : "ATM_SERVICECLASS", - 0xE4 : "CALL_OPS (ASON)", - 0xE5 : "GENERALIZED_UNI", - 0xE6 : "CALL_ID", - 0xE7 : "3GPP2_Object", - 0xE8 : "EXCLUDE_ROUTE" -} - -class RSVP_Object(Packet): - name = "RSVP_Object" - fields_desc = [ ShortField("Length",4), - ByteEnumField("Class",0x01, rsvptypes), - ByteField("C-Type",1)] - def guess_payload_class(self, payload): - if self.Class == 0x03: - return RSVP_HOP - elif self.Class == 0x05: - return RSVP_Time - elif self.Class == 0x0c: - return RSVP_SenderTSPEC - elif self.Class == 0x13: - return RSVP_LabelReq - elif self.Class == 0xCF: - return RSVP_SessionAttrb - else: - return RSVP_Data - - - -class RSVP_Data(Packet): - name = "Data" - fields_desc = [StrLenField("Data","",length_from= lambda pkt:pkt.underlayer.Length - 4)] - def default_payload_class(self, payload): - return RSVP_Object - -class RSVP_HOP(Packet): - name = "HOP" - fields_desc = [ IPField("neighbor","0.0.0.0"), - BitField("inface",1,32)] - def default_payload_class(self, payload): - return RSVP_Object - -class RSVP_Time(Packet): - name = "Time Val" - fields_desc = [ BitField("refresh",1,32)] - def default_payload_class(self, payload): - return RSVP_Object - -class RSVP_SenderTSPEC(Packet): - name = "Sender_TSPEC" - fields_desc = [ ByteField("Msg_Format",0), - ByteField("reserve",0), - ShortField("Data_Length",4), - ByteField("Srv_hdr",1), - ByteField("reserve2",0), - ShortField("Srv_Length",4), - StrLenField("Tokens","",length_from= lambda pkt:pkt.underlayer.Length - 12) ] - def default_payload_class(self, payload): - return RSVP_Object - -class RSVP_LabelReq(Packet): - name = "Lable Req" - fields_desc = [ ShortField("reserve",1), - ShortField("L3PID",1)] - def default_payload_class(self, payload): - return RSVP_Object - -class RSVP_SessionAttrb(Packet): - name = "Session_Attribute" - fields_desc = [ ByteField("Setup_priority",1), - ByteField("Hold_priority",1), - ByteField("flags",1), - ByteField("Name_length",1), - StrLenField("Name","",length_from= lambda pkt:pkt.underlayer.Length - 8), - ] - def default_payload_class(self, payload): - return RSVP_Object - -bind_layers( IP, RSVP, { "proto" : 46} ) -bind_layers( RSVP, RSVP_Object, {}) +## RSVP layer + +# This file is part of Scapy +# Scapy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# any later version. +# +# Scapy is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Scapy. If not, see <http://www.gnu.org/licenses/>. + +# scapy.contrib.description = RSVP +# scapy.contrib.status = loads + +from scapy.packet import * +from scapy.fields import * +from scapy.layers.inet import IP + +rsvpmsgtypes = { 0x01 : "Path", + 0x02 : "Reservation request", + 0x03 : "Path error", + 0x04 : "Reservation request error", + 0x05 : "Path teardown", + 0x06 : "Reservation teardown", + 0x07 : "Reservation request acknowledgment" +} + +class RSVP(Packet): + name = "RSVP" + fields_desc = [ BitField("Version",1,4), + BitField("Flags",1,4), + ByteEnumField("Class",0x01, rsvpmsgtypes), + XShortField("chksum", None), + ByteField("TTL",1), + XByteField("dataofs", 0), + ShortField("Length",None)] + def post_build(self, p, pay): + p += pay + if self.Length is None: + l = len(p) + p = p[:6]+chr((l>>8)&0xff)+chr(l&0xff)+p[8:] + if self.chksum is None: + ck = checksum(p) + p = p[:2]+chr(ck>>8)+chr(ck&0xff)+p[4:] + return p + +rsvptypes = { 0x01 : "Session", + 0x03 : "HOP", + 0x04 : "INTEGRITY", + 0x05 : "TIME_VALUES", + 0x06 : "ERROR_SPEC", + 0x07 : "SCOPE", + 0x08 : "STYLE", + 0x09 : "FLOWSPEC", + 0x0A : "FILTER_SPEC", + 0x0B : "SENDER_TEMPLATE", + 0x0C : "SENDER_TSPEC", + 0x0D : "ADSPEC", + 0x0E : "POLICY_DATA", + 0x0F : "RESV_CONFIRM", + 0x10 : "RSVP_LABEL", + 0x11 : "HOP_COUNT", + 0x12 : "STRICT_SOURCE_ROUTE", + 0x13 : "LABEL_REQUEST", + 0x14 : "EXPLICIT_ROUTE", + 0x15 : "ROUTE_RECORD", + 0x16 : "HELLO", + 0x17 : "MESSAGE_ID", + 0x18 : "MESSAGE_ID_ACK", + 0x19 : "MESSAGE_ID_LIST", + 0x1E : "DIAGNOSTIC", + 0x1F : "ROUTE", + 0x20 : "DIAG_RESPONSE", + 0x21 : "DIAG_SELECT", + 0x22 : "RECOVERY_LABEL", + 0x23 : "UPSTREAM_LABEL", + 0x24 : "LABEL_SET", + 0x25 : "PROTECTION", + 0x26 : "PRIMARY PATH ROUTE", + 0x2A : "DSBM IP ADDRESS", + 0x2B : "SBM_PRIORITY", + 0x2C : "DSBM TIMER INTERVALS", + 0x2D : "SBM_INFO", + 0x32 : "S2L_SUB_LSP", + 0x3F : "DETOUR", + 0x40 : "CHALLENGE", + 0x41 : "DIFF-SERV", + 0x42 : "CLASSTYPE", + 0x43 : "LSP_REQUIRED_ATTRIBUTES", + 0x80 : "NODE_CHAR", + 0x81 : "SUGGESTED_LABEL", + 0x82 : "ACCEPTABLE_LABEL_SET", + 0x83 : "RESTART_CA", + 0x84 : "SESSION-OF-INTEREST", + 0x85 : "LINK_CAPABILITY", + 0x86 : "Capability Object", + 0xA1 : "RSVP_HOP_L2", + 0xA2 : "LAN_NHOP_L2", + 0xA3 : "LAN_NHOP_L3", + 0xA4 : "LAN_LOOPBACK", + 0xA5 : "TCLASS", + 0xC0 : "TUNNEL", + 0xC1 : "LSP_TUNNEL_INTERFACE_ID", + 0xC2 : "USER_ERROR_SPEC", + 0xC3 : "NOTIFY_REQUEST", + 0xC4 : "ADMIN-STATUS", + 0xC5 : "LSP_ATTRIBUTES", + 0xC6 : "ALARM_SPEC", + 0xC7 : "ASSOCIATION", + 0xC8 : "SECONDARY_EXPLICIT_ROUTE", + 0xC9 : "SECONDARY_RECORD_ROUTE", + 0xCD : "FAST_REROUTE", + 0xCF : "SESSION_ATTRIBUTE", + 0xE1 : "DCLASS", + 0xE2 : "PACKETCABLE EXTENSIONS", + 0xE3 : "ATM_SERVICECLASS", + 0xE4 : "CALL_OPS (ASON)", + 0xE5 : "GENERALIZED_UNI", + 0xE6 : "CALL_ID", + 0xE7 : "3GPP2_Object", + 0xE8 : "EXCLUDE_ROUTE" +} + +class RSVP_Object(Packet): + name = "RSVP_Object" + fields_desc = [ ShortField("Length",4), + ByteEnumField("Class",0x01, rsvptypes), + ByteField("C-Type",1)] + def guess_payload_class(self, payload): + if self.Class == 0x03: + return RSVP_HOP + elif self.Class == 0x05: + return RSVP_Time + elif self.Class == 0x0c: + return RSVP_SenderTSPEC + elif self.Class == 0x13: + return RSVP_LabelReq + elif self.Class == 0xCF: + return RSVP_SessionAttrb + else: + return RSVP_Data + + + +class RSVP_Data(Packet): + name = "Data" + fields_desc = [StrLenField("Data","",length_from= lambda pkt:pkt.underlayer.Length - 4)] + def default_payload_class(self, payload): + return RSVP_Object + +class RSVP_HOP(Packet): + name = "HOP" + fields_desc = [ IPField("neighbor","0.0.0.0"), + BitField("inface",1,32)] + def default_payload_class(self, payload): + return RSVP_Object + +class RSVP_Time(Packet): + name = "Time Val" + fields_desc = [ BitField("refresh",1,32)] + def default_payload_class(self, payload): + return RSVP_Object + +class RSVP_SenderTSPEC(Packet): + name = "Sender_TSPEC" + fields_desc = [ ByteField("Msg_Format",0), + ByteField("reserve",0), + ShortField("Data_Length",4), + ByteField("Srv_hdr",1), + ByteField("reserve2",0), + ShortField("Srv_Length",4), + StrLenField("Tokens","",length_from= lambda pkt:pkt.underlayer.Length - 12) ] + def default_payload_class(self, payload): + return RSVP_Object + +class RSVP_LabelReq(Packet): + name = "Lable Req" + fields_desc = [ ShortField("reserve",1), + ShortField("L3PID",1)] + def default_payload_class(self, payload): + return RSVP_Object + +class RSVP_SessionAttrb(Packet): + name = "Session_Attribute" + fields_desc = [ ByteField("Setup_priority",1), + ByteField("Hold_priority",1), + ByteField("flags",1), + ByteField("Name_length",1), + StrLenField("Name","",length_from= lambda pkt:pkt.underlayer.Length - 8), + ] + def default_payload_class(self, payload): + return RSVP_Object + +bind_layers( IP, RSVP, { "proto" : 46} ) +bind_layers( RSVP, RSVP_Object, {}) diff --git a/test/run_tests.bat b/test/run_tests.bat index 8c4200d867fe76d9df2814d942cdb145b18fee85..fce8e76ec211e621da2abb2352058932f50b4e77 100644 --- a/test/run_tests.bat +++ b/test/run_tests.bat @@ -1,10 +1,10 @@ -@echo off -title UTscapy - All tests -set MYDIR=%cd%\.. -set PYTHONPATH=%MYDIR% -if [%1]==[] ( - python "%MYDIR%\scapy\tools\UTscapy.py" -c configs\\windows2.utsc -T bpf.uts -o scapy_regression_test_%date:~6,4%_%date:~3,2%_%date:~0,2%.html -) else ( - python "%MYDIR%\scapy\tools\UTscapy.py" %@ -) -PAUSE +@echo off +title UTscapy - All tests +set MYDIR=%cd%\.. +set PYTHONPATH=%MYDIR% +if [%1]==[] ( + python "%MYDIR%\scapy\tools\UTscapy.py" -c configs\\windows2.utsc -T bpf.uts -o scapy_regression_test_%date:~6,4%_%date:~3,2%_%date:~0,2%.html +) else ( + python "%MYDIR%\scapy\tools\UTscapy.py" %@ +) +PAUSE