1# $Id: ip.py 87 2013-03-05 19:41:04Z andrewflnr@gmail.com $ 2# -*- coding: utf-8 -*- 3"""Internet Protocol.""" 4from __future__ import print_function 5from __future__ import absolute_import 6 7from . import dpkt 8from .compat import iteritems 9 10 11class IP(dpkt.Packet): 12 """Internet Protocol. 13 14 TODO: Longer class information.... 15 16 Attributes: 17 __hdr__: Header fields of IP. 18 TODO. 19 """ 20 21 __hdr__ = ( 22 ('_v_hl', 'B', (4 << 4) | (20 >> 2)), 23 ('tos', 'B', 0), 24 ('len', 'H', 20), 25 ('id', 'H', 0), 26 ('off', 'H', 0), 27 ('ttl', 'B', 64), 28 ('p', 'B', 0), 29 ('sum', 'H', 0), 30 ('src', '4s', b'\x00' * 4), 31 ('dst', '4s', b'\x00' * 4) 32 ) 33 _protosw = {} 34 opts = b'' 35 36 def __init__(self, *args, **kwargs): 37 super(IP, self).__init__(*args, **kwargs) 38 39 # If IP packet is not initialized by string and the len field has 40 # been rewritten. 41 if not args and 'len' not in kwargs: 42 self.len = self.__len__() 43 44 @property 45 def v(self): 46 return self._v_hl >> 4 47 48 @v.setter 49 def v(self, v): 50 self._v_hl = (v << 4) | (self._v_hl & 0xf) 51 52 @property 53 def hl(self): 54 return self._v_hl & 0xf 55 56 @hl.setter 57 def hl(self, hl): 58 self._v_hl = (self._v_hl & 0xf0) | hl 59 60 @property 61 def rf(self): 62 return (self.off >> 15) & 0x1 63 64 @rf.setter 65 def rf(self, rf): 66 self.off = (self.off & ~IP_RF) | (rf << 15) 67 68 @property 69 def df(self): 70 return (self.off >> 14) & 0x1 71 72 @df.setter 73 def df(self, df): 74 self.off = (self.off & ~IP_DF) | (df << 14) 75 76 @property 77 def mf(self): 78 return (self.off >> 13) & 0x1 79 80 @mf.setter 81 def mf(self, mf): 82 self.off = (self.off & ~IP_MF) | (mf << 13) 83 84 @property 85 def offset(self): 86 return (self.off & IP_OFFMASK) << 3 87 88 @offset.setter 89 def offset(self, offset): 90 self.off = (self.off & ~IP_OFFMASK) | (offset >> 3) 91 92 def __len__(self): 93 return self.__hdr_len__ + len(self.opts) + len(self.data) 94 95 def __bytes__(self): 96 self.len = self.__len__() 97 if self.sum == 0: 98 self.sum = dpkt.in_cksum(self.pack_hdr() + bytes(self.opts)) 99 if (self.p == 6 or self.p == 17) and (self.off & (IP_MF | IP_OFFMASK)) == 0 and \ 100 isinstance(self.data, dpkt.Packet) and self.data.sum == 0: 101 # Set zeroed TCP and UDP checksums for non-fragments. 102 p = bytes(self.data) 103 s = dpkt.struct.pack('>4s4sxBH', self.src, self.dst, 104 self.p, len(p)) 105 s = dpkt.in_cksum_add(0, s) 106 s = dpkt.in_cksum_add(s, p) 107 self.data.sum = dpkt.in_cksum_done(s) 108 109 # RFC 768 (Fields): 110 # If the computed checksum is zero, it is transmitted as all 111 # ones (the equivalent in one's complement arithmetic). An all 112 # zero transmitted checksum value means that the transmitter 113 # generated no checksum (for debugging or for higher level 114 # protocols that don't care). 115 if self.p == 17 and self.data.sum == 0: 116 self.data.sum = 0xffff 117 # XXX - skip transports which don't need the pseudoheader 118 return self.pack_hdr() + bytes(self.opts) + bytes(self.data) 119 120 def unpack(self, buf): 121 dpkt.Packet.unpack(self, buf) 122 ol = ((self._v_hl & 0xf) << 2) - self.__hdr_len__ 123 if ol < 0: 124 raise dpkt.UnpackError('invalid header length') 125 self.opts = buf[self.__hdr_len__:self.__hdr_len__ + ol] 126 if self.len: 127 buf = buf[self.__hdr_len__ + ol:self.len] 128 else: # very likely due to TCP segmentation offload 129 buf = buf[self.__hdr_len__ + ol:] 130 try: 131 self.data = self._protosw[self.p](buf) if self.offset == 0 else buf 132 setattr(self, self.data.__class__.__name__.lower(), self.data) 133 except (KeyError, dpkt.UnpackError): 134 self.data = buf 135 136 @classmethod 137 def set_proto(cls, p, pktclass): 138 cls._protosw[p] = pktclass 139 140 @classmethod 141 def get_proto(cls, p): 142 return cls._protosw[p] 143 144 145# IP Headers 146IP_ADDR_LEN = 0x04 147IP_ADDR_BITS = 0x20 148 149IP_HDR_LEN = 0x14 150IP_OPT_LEN = 0x02 151IP_OPT_LEN_MAX = 0x28 152IP_HDR_LEN_MAX = IP_HDR_LEN + IP_OPT_LEN_MAX 153 154IP_LEN_MAX = 0xffff 155IP_LEN_MIN = IP_HDR_LEN 156 157# Reserved Addresses 158IP_ADDR_ANY = "\x00\x00\x00\x00" # 0.0.0.0 159IP_ADDR_BROADCAST = "\xff\xff\xff\xff" # 255.255.255.255 160IP_ADDR_LOOPBACK = "\x7f\x00\x00\x01" # 127.0.0.1 161IP_ADDR_MCAST_ALL = "\xe0\x00\x00\x01" # 224.0.0.1 162IP_ADDR_MCAST_LOCAL = "\xe0\x00\x00\xff" # 224.0.0.255 163 164# Type of service (ip_tos), RFC 1349 ("obsoleted by RFC 2474") 165IP_TOS_DEFAULT = 0x00 # default 166IP_TOS_LOWDELAY = 0x10 # low delay 167IP_TOS_THROUGHPUT = 0x08 # high throughput 168IP_TOS_RELIABILITY = 0x04 # high reliability 169IP_TOS_LOWCOST = 0x02 # low monetary cost - XXX 170IP_TOS_ECT = 0x02 # ECN-capable transport 171IP_TOS_CE = 0x01 # congestion experienced 172 173# IP precedence (high 3 bits of ip_tos), hopefully unused 174IP_TOS_PREC_ROUTINE = 0x00 175IP_TOS_PREC_PRIORITY = 0x20 176IP_TOS_PREC_IMMEDIATE = 0x40 177IP_TOS_PREC_FLASH = 0x60 178IP_TOS_PREC_FLASHOVERRIDE = 0x80 179IP_TOS_PREC_CRITIC_ECP = 0xa0 180IP_TOS_PREC_INTERNETCONTROL = 0xc0 181IP_TOS_PREC_NETCONTROL = 0xe0 182 183# Fragmentation flags (ip_off) 184IP_RF = 0x8000 # reserved 185IP_DF = 0x4000 # don't fragment 186IP_MF = 0x2000 # more fragments (not last frag) 187IP_OFFMASK = 0x1fff # mask for fragment offset 188 189# Time-to-live (ip_ttl), seconds 190IP_TTL_DEFAULT = 64 # default ttl, RFC 1122, RFC 1340 191IP_TTL_MAX = 255 # maximum ttl 192 193# Protocol (ip_p) - http://www.iana.org/assignments/protocol-numbers 194IP_PROTO_IP = 0 # dummy for IP 195IP_PROTO_HOPOPTS = IP_PROTO_IP # IPv6 hop-by-hop options 196IP_PROTO_ICMP = 1 # ICMP 197IP_PROTO_IGMP = 2 # IGMP 198IP_PROTO_GGP = 3 # gateway-gateway protocol 199IP_PROTO_IPIP = 4 # IP in IP 200IP_PROTO_ST = 5 # ST datagram mode 201IP_PROTO_TCP = 6 # TCP 202IP_PROTO_CBT = 7 # CBT 203IP_PROTO_EGP = 8 # exterior gateway protocol 204IP_PROTO_IGP = 9 # interior gateway protocol 205IP_PROTO_BBNRCC = 10 # BBN RCC monitoring 206IP_PROTO_NVP = 11 # Network Voice Protocol 207IP_PROTO_PUP = 12 # PARC universal packet 208IP_PROTO_ARGUS = 13 # ARGUS 209IP_PROTO_EMCON = 14 # EMCON 210IP_PROTO_XNET = 15 # Cross Net Debugger 211IP_PROTO_CHAOS = 16 # Chaos 212IP_PROTO_UDP = 17 # UDP 213IP_PROTO_MUX = 18 # multiplexing 214IP_PROTO_DCNMEAS = 19 # DCN measurement 215IP_PROTO_HMP = 20 # Host Monitoring Protocol 216IP_PROTO_PRM = 21 # Packet Radio Measurement 217IP_PROTO_IDP = 22 # Xerox NS IDP 218IP_PROTO_TRUNK1 = 23 # Trunk-1 219IP_PROTO_TRUNK2 = 24 # Trunk-2 220IP_PROTO_LEAF1 = 25 # Leaf-1 221IP_PROTO_LEAF2 = 26 # Leaf-2 222IP_PROTO_RDP = 27 # "Reliable Datagram" proto 223IP_PROTO_IRTP = 28 # Inet Reliable Transaction 224IP_PROTO_TP = 29 # ISO TP class 4 225IP_PROTO_NETBLT = 30 # Bulk Data Transfer 226IP_PROTO_MFPNSP = 31 # MFE Network Services 227IP_PROTO_MERITINP = 32 # Merit Internodal Protocol 228IP_PROTO_SEP = 33 # Sequential Exchange proto 229IP_PROTO_3PC = 34 # Third Party Connect proto 230IP_PROTO_IDPR = 35 # Interdomain Policy Route 231IP_PROTO_XTP = 36 # Xpress Transfer Protocol 232IP_PROTO_DDP = 37 # Datagram Delivery Proto 233IP_PROTO_CMTP = 38 # IDPR Ctrl Message Trans 234IP_PROTO_TPPP = 39 # TP++ Transport Protocol 235IP_PROTO_IL = 40 # IL Transport Protocol 236IP_PROTO_IP6 = 41 # IPv6 237IP_PROTO_SDRP = 42 # Source Demand Routing 238IP_PROTO_ROUTING = 43 # IPv6 routing header 239IP_PROTO_FRAGMENT = 44 # IPv6 fragmentation header 240IP_PROTO_RSVP = 46 # Reservation protocol 241IP_PROTO_GRE = 47 # General Routing Encap 242IP_PROTO_MHRP = 48 # Mobile Host Routing 243IP_PROTO_ENA = 49 # ENA 244IP_PROTO_ESP = 50 # Encap Security Payload 245IP_PROTO_AH = 51 # Authentication Header 246IP_PROTO_INLSP = 52 # Integated Net Layer Sec 247IP_PROTO_SWIPE = 53 # SWIPE 248IP_PROTO_NARP = 54 # NBMA Address Resolution 249IP_PROTO_MOBILE = 55 # Mobile IP, RFC 2004 250IP_PROTO_TLSP = 56 # Transport Layer Security 251IP_PROTO_SKIP = 57 # SKIP 252IP_PROTO_ICMP6 = 58 # ICMP for IPv6 253IP_PROTO_NONE = 59 # IPv6 no next header 254IP_PROTO_DSTOPTS = 60 # IPv6 destination options 255IP_PROTO_ANYHOST = 61 # any host internal proto 256IP_PROTO_CFTP = 62 # CFTP 257IP_PROTO_ANYNET = 63 # any local network 258IP_PROTO_EXPAK = 64 # SATNET and Backroom EXPAK 259IP_PROTO_KRYPTOLAN = 65 # Kryptolan 260IP_PROTO_RVD = 66 # MIT Remote Virtual Disk 261IP_PROTO_IPPC = 67 # Inet Pluribus Packet Core 262IP_PROTO_DISTFS = 68 # any distributed fs 263IP_PROTO_SATMON = 69 # SATNET Monitoring 264IP_PROTO_VISA = 70 # VISA Protocol 265IP_PROTO_IPCV = 71 # Inet Packet Core Utility 266IP_PROTO_CPNX = 72 # Comp Proto Net Executive 267IP_PROTO_CPHB = 73 # Comp Protocol Heart Beat 268IP_PROTO_WSN = 74 # Wang Span Network 269IP_PROTO_PVP = 75 # Packet Video Protocol 270IP_PROTO_BRSATMON = 76 # Backroom SATNET Monitor 271IP_PROTO_SUNND = 77 # SUN ND Protocol 272IP_PROTO_WBMON = 78 # WIDEBAND Monitoring 273IP_PROTO_WBEXPAK = 79 # WIDEBAND EXPAK 274IP_PROTO_EON = 80 # ISO CNLP 275IP_PROTO_VMTP = 81 # Versatile Msg Transport 276IP_PROTO_SVMTP = 82 # Secure VMTP 277IP_PROTO_VINES = 83 # VINES 278IP_PROTO_TTP = 84 # TTP 279IP_PROTO_NSFIGP = 85 # NSFNET-IGP 280IP_PROTO_DGP = 86 # Dissimilar Gateway Proto 281IP_PROTO_TCF = 87 # TCF 282IP_PROTO_EIGRP = 88 # EIGRP 283IP_PROTO_OSPF = 89 # Open Shortest Path First 284IP_PROTO_SPRITERPC = 90 # Sprite RPC Protocol 285IP_PROTO_LARP = 91 # Locus Address Resolution 286IP_PROTO_MTP = 92 # Multicast Transport Proto 287IP_PROTO_AX25 = 93 # AX.25 Frames 288IP_PROTO_IPIPENCAP = 94 # yet-another IP encap 289IP_PROTO_MICP = 95 # Mobile Internet Ctrl 290IP_PROTO_SCCSP = 96 # Semaphore Comm Sec Proto 291IP_PROTO_ETHERIP = 97 # Ethernet in IPv4 292IP_PROTO_ENCAP = 98 # encapsulation header 293IP_PROTO_ANYENC = 99 # private encryption scheme 294IP_PROTO_GMTP = 100 # GMTP 295IP_PROTO_IFMP = 101 # Ipsilon Flow Mgmt Proto 296IP_PROTO_PNNI = 102 # PNNI over IP 297IP_PROTO_PIM = 103 # Protocol Indep Multicast 298IP_PROTO_ARIS = 104 # ARIS 299IP_PROTO_SCPS = 105 # SCPS 300IP_PROTO_QNX = 106 # QNX 301IP_PROTO_AN = 107 # Active Networks 302IP_PROTO_IPCOMP = 108 # IP Payload Compression 303IP_PROTO_SNP = 109 # Sitara Networks Protocol 304IP_PROTO_COMPAQPEER = 110 # Compaq Peer Protocol 305IP_PROTO_IPXIP = 111 # IPX in IP 306IP_PROTO_VRRP = 112 # Virtual Router Redundancy 307IP_PROTO_PGM = 113 # PGM Reliable Transport 308IP_PROTO_ANY0HOP = 114 # 0-hop protocol 309IP_PROTO_L2TP = 115 # Layer 2 Tunneling Proto 310IP_PROTO_DDX = 116 # D-II Data Exchange (DDX) 311IP_PROTO_IATP = 117 # Interactive Agent Xfer 312IP_PROTO_STP = 118 # Schedule Transfer Proto 313IP_PROTO_SRP = 119 # SpectraLink Radio Proto 314IP_PROTO_UTI = 120 # UTI 315IP_PROTO_SMP = 121 # Simple Message Protocol 316IP_PROTO_SM = 122 # SM 317IP_PROTO_PTP = 123 # Performance Transparency 318IP_PROTO_ISIS = 124 # ISIS over IPv4 319IP_PROTO_FIRE = 125 # FIRE 320IP_PROTO_CRTP = 126 # Combat Radio Transport 321IP_PROTO_CRUDP = 127 # Combat Radio UDP 322IP_PROTO_SSCOPMCE = 128 # SSCOPMCE 323IP_PROTO_IPLT = 129 # IPLT 324IP_PROTO_SPS = 130 # Secure Packet Shield 325IP_PROTO_PIPE = 131 # Private IP Encap in IP 326IP_PROTO_SCTP = 132 # Stream Ctrl Transmission 327IP_PROTO_FC = 133 # Fibre Channel 328IP_PROTO_RSVPIGN = 134 # RSVP-E2E-IGNORE 329IP_PROTO_RAW = 255 # Raw IP packets 330IP_PROTO_RESERVED = IP_PROTO_RAW # Reserved 331IP_PROTO_MAX = 255 332 333# XXX - auto-load IP dispatch table from IP_PROTO_* definitions 334 335 336def __load_protos(): 337 g = globals() 338 for k, v in iteritems(g): 339 if k.startswith('IP_PROTO_'): 340 name = k[9:].lower() 341 try: 342 mod = __import__(name, g, level=1) 343 IP.set_proto(v, getattr(mod, name.upper())) 344 except (ImportError, AttributeError): 345 continue 346 347 348def _mod_init(): 349 """Post-initialization called when all dpkt modules are fully loaded""" 350 if not IP._protosw: 351 __load_protos() 352 353 354def test_ip(): 355 from . import udp 356 357 s = b'E\x00\x00"\x00\x00\x00\x00@\x11r\xc0\x01\x02\x03\x04\x01\x02\x03\x04\x00o\x00\xde\x00\x0e\xbf5foobar' 358 ip = IP(id=0, src=b'\x01\x02\x03\x04', dst=b'\x01\x02\x03\x04', p=17) 359 u = udp.UDP(sport=111, dport=222) 360 u.data = b'foobar' 361 u.ulen += len(u.data) 362 ip.data = u 363 ip.len += len(u) 364 assert (bytes(ip) == s) 365 assert (ip.v == 4) 366 assert (ip.hl == 5) 367 368 ip = IP(s) 369 assert (bytes(ip) == s) 370 assert (ip.udp.sport == 111) 371 assert (ip.udp.data == b'foobar') 372 373 374def test_dict(): 375 ip = IP(id=0, src=b'\x01\x02\x03\x04', dst=b'\x01\x02\x03\x04', p=17) 376 d = dict(ip) 377 378 assert (d['src'] == b'\x01\x02\x03\x04') 379 assert (d['dst'] == b'\x01\x02\x03\x04') 380 assert (d['id'] == 0) 381 assert (d['p'] == 17) 382 383 384def test_hl(): # Todo chack this test method 385 s = (b'BB\x03\x00\x00\x00\x00\x00\x00\x00\xd0\x00\xec\xbc\xa5\x00\x00\x00\x03\x80\x00\x00\xd0' 386 b'\x01\xf2\xac\xa5"0\x01\x00\x14\x00\x02\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00') 387 try: 388 IP(s) 389 except dpkt.UnpackError: 390 pass 391 392 393def test_opt(): 394 s = (b'\x4f\x00\x00\x3c\xae\x08\x00\x00\x40\x06\x18\x10\xc0\xa8\x0a\x26\xc0\xa8\x0a\x01\x07\x27' 395 b'\x08\x01\x02\x03\x04\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' 396 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') 397 ip = IP(s) 398 ip.sum = 0 399 assert (bytes(ip) == s) 400 401 402def test_zerolen(): 403 from . import tcp 404 d = b'X' * 2048 405 s = (b'\x45\x00\x00\x00\x34\xce\x40\x00\x80\x06\x00\x00\x7f\x00\x00\x01\x7f\x00\x00\x01\xcc\x4e' 406 b'\x0c\x38\x60\xff\xc6\x4e\x5f\x8a\x12\x98\x50\x18\x40\x29\x3a\xa3\x00\x00') + d 407 ip = IP(s) 408 assert (isinstance(ip.data, tcp.TCP)) 409 assert (ip.tcp.data == d) 410 411 412def test_constuctor(): 413 ip1 = IP(data=b"Hello world!") 414 ip2 = IP(data=b"Hello world!", len=0) 415 ip3 = IP(bytes(ip1)) 416 ip4 = IP(bytes(ip2)) 417 assert (bytes(ip1) == bytes(ip3)) 418 assert (bytes(ip1) == b'E\x00\x00 \x00\x00\x00\x00@\x00z\xdf\x00\x00\x00\x00\x00\x00\x00\x00Hello world!') 419 assert (bytes(ip2) == bytes(ip4)) 420 assert (bytes(ip2) == b'E\x00\x00 \x00\x00\x00\x00@\x00z\xdf\x00\x00\x00\x00\x00\x00\x00\x00Hello world!') 421 422 423def test_frag(): 424 from . import ethernet 425 s = (b'\x00\x23\x20\xd4\x2a\x8c\x00\x23\x20\xd4\x2a\x8c\x08\x00\x45\x00\x00\x54\x00\x00\x40\x00' 426 b'\x40\x01\x25\x8d\x0a\x00\x00\x8f\x0a\x00\x00\x8e\x08\x00\x2e\xa0\x01\xff\x23\x73\x20\x48' 427 b'\x4a\x4d\x00\x00\x00\x00\x78\x85\x02\x00\x00\x00\x00\x00\x10\x11\x12\x13\x14\x15\x16\x17' 428 b'\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d' 429 b'\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37') 430 ip = ethernet.Ethernet(s).ip 431 assert (ip.rf == 0) 432 assert (ip.df == 1) 433 assert (ip.mf == 0) 434 assert (ip.offset == 0) 435 436 # test setters of fragmentation related attributes. 437 ip.rf = 1 438 ip.df = 0 439 ip.mf = 1 440 ip.offset = 1480 441 assert (ip.rf == 1) 442 assert (ip.df == 0) 443 assert (ip.mf == 1) 444 assert (ip.offset == 1480) 445 446 447def test_property_setters(): 448 ip = IP() 449 assert ip.v == 4 450 ip.v = 6 451 assert ip.v == 6 452 453 assert ip.hl == 5 454 ip.hl = 7 455 assert ip.hl == 7 456 457 458def test_default_udp_checksum(): 459 from dpkt.udp import UDP 460 461 udp = UDP(sport=1, dport=0xffdb) 462 ip = IP(src=b'\x00\x00\x00\x01', dst=b'\x00\x00\x00\x01', p=17, data=udp) 463 assert ip.p == 17 464 assert ip.data.sum == 0 465 466 # this forces recalculation of the data layer checksum 467 bytes(ip) 468 469 # during calculation the checksum was evaluated to 0x0000 470 # this was then conditionally set to 0xffff per RFC768 471 assert ip.data.sum == 0xffff 472