1 # This file is part of Scapy 2 # Scapy is free software: you can redistribute it and/or modify 3 # it under the terms of the GNU General Public License as published by 4 # the Free Software Foundation, either version 2 of the License, or 5 # any later version. 6 # 7 # Scapy is distributed in the hope that it will be useful, 8 # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 # GNU General Public License for more details. 11 # 12 # You should have received a copy of the GNU General Public License 13 # along with Scapy. If not, see <http://www.gnu.org/licenses/>. 14 15 # author: <jellch (at] harris.com> 16 17 # scapy.contrib.description = PPI GEOLOCATION 18 # scapy.contrib.status = loads 19 20 21 """ 22 PPI-GEOLOCATION tags 23 """ 24 from __future__ import absolute_import 25 import struct, time 26 from scapy.packet import * 27 from scapy.fields import * 28 from scapy.contrib.ppi import PPIGenericFldHdr,addPPIType 29 from scapy.error import warning 30 import scapy.modules.six as six 31 from scapy.modules.six.moves import range 32 33 CURR_GEOTAG_VER = 2 #Major revision of specification 34 35 PPI_GPS = 30002 36 PPI_VECTOR = 30003 37 PPI_SENSOR = 30004 38 PPI_ANTENNA = 30005 39 #The FixedX_Y Fields are used to store fixed point numbers in a variety of fields in the GEOLOCATION-TAGS specification 40 class Fixed3_6Field(LEIntField): 41 def i2h(self, pkt, x): 42 if x is not None: 43 if (x < 0): 44 warning("Fixed3_6: Internal value too negative: %d", x) 45 x = 0 46 elif (x > 999999999): 47 warning("Fixed3_6: Internal value too positive: %d", x) 48 x = 999999999 49 x = x * 1e-6 50 return x 51 def h2i(self, pkt, x): 52 if x is not None: 53 if (x <= -0.5e-6): 54 warning("Fixed3_6: Input value too negative: %.7f", x) 55 x = 0 56 elif (x >= 999.9999995): 57 warning("Fixed3_6: Input value too positive: %.7f", x) 58 x = 999.999999 59 x = int(round(x * 1e6)) 60 return x 61 def i2m(self, pkt, x): 62 """Convert internal value to machine value""" 63 if x is None: 64 #Try to return zero if undefined 65 x = self.h2i(pkt, 0) 66 return x 67 68 def i2repr(self,pkt,x): 69 if x is None: 70 y=0 71 else: 72 y=self.i2h(pkt,x) 73 return "%3.6f"%(y) 74 class Fixed3_7Field(LEIntField): 75 def i2h(self, pkt, x): 76 if x is not None: 77 if (x < 0): 78 warning("Fixed3_7: Internal value too negative: %d", x) 79 x = 0 80 elif (x > 3600000000): 81 warning("Fixed3_7: Internal value too positive: %d", x) 82 x = 3600000000 83 x = (x - 1800000000) * 1e-7 84 return x 85 def h2i(self, pkt, x): 86 if x is not None: 87 if (x <= -180.00000005): 88 warning("Fixed3_7: Input value too negative: %.8f", x) 89 x = -180.0 90 elif (x >= 180.00000005): 91 warning("Fixed3_7: Input value too positive: %.8f", x) 92 x = 180.0 93 x = int(round((x + 180.0) * 1e7)) 94 return x 95 def i2m(self, pkt, x): 96 """Convert internal value to machine value""" 97 if x is None: 98 #Try to return zero if undefined 99 x = self.h2i(pkt, 0) 100 return x 101 def i2repr(self,pkt,x): 102 if x is None: 103 y=0 104 else: 105 y=self.i2h(pkt,x) 106 return "%3.7f"%(y) 107 108 class Fixed6_4Field(LEIntField): 109 def i2h(self, pkt, x): 110 if x is not None: 111 if (x < 0): 112 warning("Fixed6_4: Internal value too negative: %d", x) 113 x = 0 114 elif (x > 3600000000): 115 warning("Fixed6_4: Internal value too positive: %d", x) 116 x = 3600000000 117 x = (x - 1800000000) * 1e-4 118 return x 119 def h2i(self, pkt, x): 120 if x is not None: 121 if (x <= -180000.00005): 122 warning("Fixed6_4: Input value too negative: %.5f", x) 123 x = -180000.0 124 elif (x >= 180000.00005): 125 warning("Fixed6_4: Input value too positive: %.5f", x) 126 x = 180000.0 127 x = int(round((x + 180000.0) * 1e4)) 128 return x 129 def i2m(self, pkt, x): 130 """Convert internal value to machine value""" 131 if x is None: 132 #Try to return zero if undefined 133 x = self.h2i(pkt, 0) 134 return x 135 def i2repr(self,pkt,x): 136 if x is None: 137 y=0 138 else: 139 y=self.i2h(pkt,x) 140 return "%6.4f"%(y) 141 #The GPS timestamps fractional time counter is stored in a 32-bit unsigned ns counter. 142 #The ept field is as well, 143 class NSCounter_Field(LEIntField): 144 def i2h(self, pkt, x): #converts nano-seconds to seconds for output 145 if x is not None: 146 if (x < 0): 147 warning("NSCounter_Field: Internal value too negative: %d", x) 148 x = 0 149 elif (x >= 2**32): 150 warning("NSCounter_Field: Internal value too positive: %d", x) 151 x = 2**32-1 152 x = (x / 1e9) 153 return x 154 def h2i(self, pkt, x): #converts input in seconds into nano-seconds for storage 155 if x is not None: 156 if (x < 0): 157 warning("NSCounter_Field: Input value too negative: %.10f", x) 158 x = 0 159 elif (x >= (2**32) / 1e9): 160 warning("NSCounter_Field: Input value too positive: %.10f", x) 161 x = (2**32-1) / 1e9 162 x = int(round((x * 1e9))) 163 return x 164 def i2repr(self,pkt,x): 165 if x is None: 166 y=0 167 else: 168 y=self.i2h(pkt,x) 169 return "%1.9f"%(y) 170 171 class LETimeField(UTCTimeField,LEIntField): 172 __slots__ = ["epoch", "delta", "strf"] 173 def __init__(self, name, default, epoch=None, strf="%a, %d %b %Y %H:%M:%S +0000"): 174 LEIntField.__init__(self, name, default) 175 UTCTimeField.__init__(self, name, default, epoch=epoch, strf=strf) 176 177 class SignedByteField(Field): 178 def __init__(self, name, default): 179 Field.__init__(self, name, default, "b") 180 def randval(self): 181 return RandSByte() 182 183 class XLEShortField(LEShortField,XShortField): 184 def i2repr(self, pkt, x): 185 return XShortField.i2repr(self, pkt, x) 186 187 class XLEIntField(LEIntField,XIntField): 188 def i2repr(self, pkt, x): 189 return XIntField.i2repr(self, pkt, x) 190 191 class GPSTime_Field(LETimeField): 192 def __init__(self, name, default): 193 return LETimeField.__init__(self, name, default, strf="%a, %d %b %Y %H:%M:%S UTC") 194 195 class VectorFlags_Field(XLEIntField): 196 """Represents te VectorFlags field. Handles the RelativeTo:sub-field""" 197 _fwdstr = "DefinesForward" 198 _resmask = 0xfffffff8 199 _relmask = 0x6 200 _relnames = ["RelativeToForward", "RelativeToEarth", "RelativeToCurrent", "RelativeToReserved"] 201 _relvals = [0x00, 0x02, 0x04, 0x06] 202 def i2repr(self, pkt, x): 203 if x is None: 204 return str(x) 205 r = [] 206 if (x & 0x1): 207 r.append(self._fwdstr) 208 i = (x & self._relmask) >> 1 209 r.append(self._relnames[i]) 210 i = x & self._resmask 211 if (i): 212 r.append("ReservedBits:%08X" % i) 213 sout = "+".join(r) 214 return sout 215 def any2i(self, pkt, x): 216 if isinstance(x, str): 217 r = x.split("+") 218 y = 0 219 for value in r: 220 if (value == self._fwdstr): 221 y |= 0x1 222 elif (value in self._relnames): 223 i = self._relnames.index(value) 224 y &= (~self._relmask) 225 y |= self._relvals[i] 226 else: 227 #logging.warning("Unknown VectorFlags Argument: %s", value) 228 pass 229 else: 230 y = x 231 #print "any2i: %s --> %s" % (str(x), str(y)) 232 return y 233 234 class HCSIFlagsField(FlagsField): 235 """ A FlagsField where each bit/flag turns a conditional field on or off. 236 If the value is None when building a packet, i2m() will check the value of 237 every field in self.names. If the field's value is not None, the corresponding 238 flag will be set. """ 239 def i2m(self, pkt, val): 240 if val is None: 241 val = 0 242 if (pkt): 243 for i, name in enumerate(self.names): 244 value = pkt.getfieldval(name) 245 if value is not None: 246 val |= 1 << i 247 return val 248 249 class HCSINullField(StrFixedLenField): 250 def __init__(self, name, default): 251 return StrFixedLenField.__init__(self, name, default, length=0) 252 253 class HCSIDescField(StrFixedLenField): 254 def __init__(self, name, default): 255 return StrFixedLenField.__init__(self, name, default, length=32) 256 257 class HCSIAppField(StrFixedLenField): 258 def __init__(self, name, default): 259 return StrFixedLenField.__init__(self, name, default, length=60) 260 261 def _FlagsList(myfields): 262 flags = ["Reserved%02d" % i for i in range(32)] 263 for i, value in six.iteritems(myfields): 264 flags[i] = value 265 return flags 266 267 # Define all geolocation-tag flags lists 268 _hcsi_gps_flags = _FlagsList({0:"No Fix Available", 1:"GPS", 2:"Differential GPS", 269 3:"Pulse Per Second", 4:"Real Time Kinematic", 270 5:"Float Real Time Kinematic", 6:"Estimated (Dead Reckoning)", 271 7:"Manual Input", 8:"Simulation"}) 272 273 #_hcsi_vector_flags = _FlagsList({0:"ForwardFrame", 1:"RotationsAbsoluteXYZ", 5:"OffsetFromGPS_XYZ"}) 274 #This has been replaced with the VectorFlags_Field class, in order to handle the RelativeTo:subfield 275 276 _hcsi_vector_char_flags = _FlagsList({0:"Antenna", 1:"Direction of Travel", 277 2:"Front of Vehicle", 3:"Angle of Arrival", 4:"Transmitter Position", 278 8:"GPS Derived", 9:"INS Derived", 10:"Compass Derived", 279 11:"Acclerometer Derived", 12:"Human Derived"}) 280 281 _hcsi_antenna_flags = _FlagsList({ 1:"Horizontal Polarization", 2:"Vertical Polarization", 282 3:"Circular Polarization Left", 4:"Circular Polarization Right", 283 16:"Electronically Steerable", 17:"Mechanically Steerable"}) 284 285 """ HCSI PPI Fields are similar to RadioTap. A mask field called "present" specifies if each field 286 is present. All other fields are conditional. When dissecting a packet, each field is present if 287 "present" has the corresponding bit set. When building a packet, if "present" is None, the mask is 288 set to include every field that does not have a value of None. Otherwise, if the mask field is 289 not None, only the fields specified by "present" will be added to the packet. 290 291 To build each Packet type, build a list of the fields normally, excluding the present bitmask field. 292 The code will then construct conditional versions of each field and add the present field. 293 See GPS_Fields as an example. """ 294 295 # Conditional test for all HCSI Fields 296 def _HCSITest(pkt, ibit, name): 297 if pkt.present is None: 298 return (pkt.getfieldval(name) is not None) 299 return pkt.present & ibit 300 301 # Wrap optional fields in ConditionalField, add HCSIFlagsField 302 def _HCSIBuildFields(fields): 303 names = [f.name for f in fields] 304 cond_fields = [HCSIFlagsField('present', None, -len(names), names)] 305 for i, name in enumerate(names): 306 ibit = 1 << i 307 seval = "lambda pkt:_HCSITest(pkt,%s,'%s')" % (ibit, name) 308 test = eval(seval) 309 cond_fields.append(ConditionalField(fields[i], test)) 310 return cond_fields 311 312 class HCSIPacket(Packet): 313 name = "PPI HCSI" 314 fields_desc = [ LEShortField('pfh_type', None), 315 LEShortField('pfh_length', None), 316 ByteField('geotag_ver', CURR_GEOTAG_VER), 317 ByteField('geotag_pad', 0), 318 LEShortField('geotag_len', None)] 319 def post_build(self, p, pay): 320 if self.pfh_length is None: 321 l = len(p) - 4 322 sl = struct.pack('<H',l) 323 p = p[:2] + sl + p[4:] 324 if self.geotag_len is None: 325 l_g = len(p) - 4 326 sl_g = struct.pack('<H',l_g) 327 p = p[:6] + sl_g + p[8:] 328 p += pay 329 return p 330 def extract_padding(self, p): 331 return b"", p 332 333 #GPS Fields 334 GPS_Fields = [FlagsField("GPSFlags", None, -32, _hcsi_gps_flags), 335 Fixed3_7Field("Latitude", None), 336 Fixed3_7Field("Longitude", None), Fixed6_4Field("Altitude", None), 337 Fixed6_4Field("Altitude_g", None), GPSTime_Field("GPSTime", None), 338 NSCounter_Field("FractionalTime", None), Fixed3_6Field("eph", None), 339 Fixed3_6Field("epv", None), NSCounter_Field("ept", None), 340 HCSINullField("Reserved10", None), HCSINullField("Reserved11", None), 341 HCSINullField("Reserved12", None), HCSINullField("Reserved13", None), 342 HCSINullField("Reserved14", None), HCSINullField("Reserved15", None), 343 HCSINullField("Reserved16", None), HCSINullField("Reserved17", None), 344 HCSINullField("Reserved18", None), HCSINullField("Reserved19", None), 345 HCSINullField("Reserved20", None), HCSINullField("Reserved21", None), 346 HCSINullField("Reserved22", None), HCSINullField("Reserved23", None), 347 HCSINullField("Reserved24", None), HCSINullField("Reserved25", None), 348 HCSINullField("Reserved26", None), HCSINullField("Reserved27", None), 349 HCSIDescField("DescString", None), XLEIntField("AppId", None), 350 HCSIAppField("AppData", None), HCSINullField("Extended", None)] 351 352 class GPS(HCSIPacket): 353 name = "PPI GPS" 354 fields_desc = [ LEShortField('pfh_type', PPI_GPS), #pfh_type 355 LEShortField('pfh_length', None), #pfh_len 356 ByteField('geotag_ver', CURR_GEOTAG_VER), #base_geotag_header.ver 357 ByteField('geotag_pad', 0), #base_geotag_header.pad 358 LEShortField('geotag_len', None)] + _HCSIBuildFields(GPS_Fields) 359 360 361 #Vector Fields 362 VEC_Fields = [VectorFlags_Field("VectorFlags", None), 363 FlagsField("VectorChars", None, -32, _hcsi_vector_char_flags), 364 Fixed3_6Field("Pitch", None), Fixed3_6Field("Roll", None), 365 Fixed3_6Field("Heading", None), Fixed6_4Field("Off_X", None), 366 Fixed6_4Field("Off_Y", None), Fixed6_4Field("Off_Z", None), 367 HCSINullField("Reserved08", None), HCSINullField("Reserved09", None), 368 HCSINullField("Reserved10", None), HCSINullField("Reserved11", None), 369 HCSINullField("Reserved12", None), HCSINullField("Reserved13", None), 370 HCSINullField("Reserved14", None), HCSINullField("Reserved15", None), 371 Fixed3_6Field("Err_Rot", None), Fixed6_4Field("Err_Off", None), 372 HCSINullField("Reserved18", None), HCSINullField("Reserved19", None), 373 HCSINullField("Reserved20", None), HCSINullField("Reserved21", None), 374 HCSINullField("Reserved22", None), HCSINullField("Reserved23", None), 375 HCSINullField("Reserved24", None), HCSINullField("Reserved25", None), 376 HCSINullField("Reserved26", None), HCSINullField("Reserved27", None), 377 HCSIDescField("DescString", None), XLEIntField("AppId", None), 378 HCSIAppField("AppData", None), HCSINullField("Extended", None)] 379 380 class Vector(HCSIPacket): 381 name = "PPI Vector" 382 fields_desc = [ LEShortField('pfh_type', PPI_VECTOR), #pfh_type 383 LEShortField('pfh_length', None), #pfh_len 384 ByteField('geotag_ver', CURR_GEOTAG_VER), #base_geotag_header.ver 385 ByteField('geotag_pad', 0), #base_geotag_header.pad 386 LEShortField('geotag_len', None)] + _HCSIBuildFields(VEC_Fields) 387 388 #Sensor Fields 389 # http://www.iana.org/assignments/icmp-parameters 390 sensor_types= { 1 : "Velocity", 391 2 : "Acceleration", 392 3 : "Jerk", 393 100 : "Rotation", 394 101 : "Magnetic", 395 1000: "Temperature", 396 1001: "Barometer", 397 1002: "Humidity", 398 2000: "TDOA_Clock", 399 2001: "Phase" 400 } 401 SENS_Fields = [ LEShortEnumField('SensorType', None, sensor_types), 402 SignedByteField('ScaleFactor', None), 403 Fixed6_4Field('Val_X', None), 404 Fixed6_4Field('Val_Y', None), 405 Fixed6_4Field('Val_Z', None), 406 Fixed6_4Field('Val_T', None), 407 Fixed6_4Field('Val_E', None), 408 HCSINullField("Reserved07", None), HCSINullField("Reserved08", None), 409 HCSINullField("Reserved09", None), HCSINullField("Reserved10", None), 410 HCSINullField("Reserved11", None), HCSINullField("Reserved12", None), 411 HCSINullField("Reserved13", None), HCSINullField("Reserved14", None), 412 HCSINullField("Reserved15", None), HCSINullField("Reserved16", None), 413 HCSINullField("Reserved17", None), HCSINullField("Reserved18", None), 414 HCSINullField("Reserved19", None), HCSINullField("Reserved20", None), 415 HCSINullField("Reserved21", None), HCSINullField("Reserved22", None), 416 HCSINullField("Reserved23", None), HCSINullField("Reserved24", None), 417 HCSINullField("Reserved25", None), HCSINullField("Reserved26", None), 418 HCSINullField("Reserved27", None), 419 HCSIDescField("DescString", None), XLEIntField("AppId", None), 420 HCSIAppField("AppData", None), HCSINullField("Extended", None)] 421 422 423 424 class Sensor(HCSIPacket): 425 name = "PPI Sensor" 426 fields_desc = [ LEShortField('pfh_type', PPI_SENSOR), #pfh_type 427 LEShortField('pfh_length', None), #pfh_len 428 ByteField('geotag_ver', CURR_GEOTAG_VER ), #base_geotag_header.ver 429 ByteField('geotag_pad', 0), #base_geotag_header.pad 430 LEShortField('geotag_len', None)] + _HCSIBuildFields(SENS_Fields) 431 432 # HCSIAntenna Fields 433 ANT_Fields = [FlagsField("AntennaFlags", None, -32, _hcsi_antenna_flags), 434 ByteField("Gain", None), 435 Fixed3_6Field("HorizBw", None), Fixed3_6Field("VertBw", None), 436 Fixed3_6Field("PrecisionGain",None), XLEShortField("BeamID", None), 437 HCSINullField("Reserved06", None), HCSINullField("Reserved07", None), 438 HCSINullField("Reserved08", None), HCSINullField("Reserved09", None), 439 HCSINullField("Reserved10", None), HCSINullField("Reserved11", None), 440 HCSINullField("Reserved12", None), HCSINullField("Reserved13", None), 441 HCSINullField("Reserved14", None), HCSINullField("Reserved15", None), 442 HCSINullField("Reserved16", None), HCSINullField("Reserved17", None), 443 HCSINullField("Reserved18", None), HCSINullField("Reserved19", None), 444 HCSINullField("Reserved20", None), HCSINullField("Reserved21", None), 445 HCSINullField("Reserved22", None), HCSINullField("Reserved23", None), 446 HCSINullField("Reserved24", None), HCSINullField("Reserved25", None), 447 HCSIDescField("SerialNumber", None), HCSIDescField("ModelName", None), 448 HCSIDescField("DescString", None), XLEIntField("AppId", None), 449 HCSIAppField("AppData", None), HCSINullField("Extended", None)] 450 451 class Antenna(HCSIPacket): 452 name = "PPI Antenna" 453 fields_desc = [ LEShortField('pfh_type', PPI_ANTENNA), #pfh_type 454 LEShortField('pfh_length', None), #pfh_len 455 ByteField('geotag_ver', CURR_GEOTAG_VER), #base_geotag_header.ver 456 ByteField('geotag_pad', 0), #base_geotag_header.pad 457 LEShortField('geotag_len', None)] + _HCSIBuildFields(ANT_Fields) 458 459 addPPIType(PPI_GPS, GPS) 460 addPPIType(PPI_VECTOR, Vector) 461 addPPIType(PPI_SENSOR, Sensor) 462 addPPIType(PPI_ANTENNA,Antenna) 463