blob: e5e26959c69e153f70b9ee073d271758e55fbe40 [file] [log] [blame]
# $Id: ip.py 87 2013-03-05 19:41:04Z andrewflnr@gmail.com $
# -*- coding: utf-8 -*-
"""Internet Protocol."""
from __future__ import print_function
from __future__ import absolute_import
from . import dpkt
from .compat import iteritems
from .utils import inet_to_str, deprecation_warning
_ip_proto_names = {} # {1: 'ICMP', 6: 'TCP', 17: 'UDP', etc.}
def get_ip_proto_name(p):
return _ip_proto_names.get(p, None)
class IP(dpkt.Packet):
"""Internet Protocol.
TODO: Longer class information....
Attributes:
__hdr__: Header fields of IP.
TODO.
"""
__hdr__ = (
('_v_hl', 'B', (4 << 4) | (20 >> 2)),
('tos', 'B', 0),
('len', 'H', 20),
('id', 'H', 0),
('_flags_offset', 'H', 0), # XXX - previously ip.off
('ttl', 'B', 64),
('p', 'B', 0),
('sum', 'H', 0),
('src', '4s', b'\x00' * 4),
('dst', '4s', b'\x00' * 4)
)
__bit_fields__ = {
'_v_hl': (
('v', 4), # version, 4 bits
('hl', 4), # header len, 4 bits
),
'_flags_offset': (
('rf', 1), # reserved bit
('df', 1), # don't fragment
('mf', 1), # more fragments
('offset', 13), # fragment offset, 13 bits
)
}
__pprint_funcs__ = {
'dst': inet_to_str,
'src': inet_to_str,
'sum': hex, # display checksum in hex
'p': get_ip_proto_name
}
_protosw = {}
opts = b''
def __init__(self, *args, **kwargs):
super(IP, self).__init__(*args, **kwargs)
# If IP packet is not initialized by string and the len field has
# been rewritten.
if not args and 'len' not in kwargs:
self.len = self.__len__()
def __len__(self):
return self.__hdr_len__ + len(self.opts) + len(self.data)
def __bytes__(self):
self.len = self.__len__()
if self.sum == 0:
self.sum = dpkt.in_cksum(self.pack_hdr() + bytes(self.opts))
if (self.p == 6 or self.p == 17) and (self._flags_offset & (IP_MF | IP_OFFMASK)) == 0 and \
isinstance(self.data, dpkt.Packet) and self.data.sum == 0:
# Set zeroed TCP and UDP checksums for non-fragments.
p = bytes(self.data)
s = dpkt.struct.pack('>4s4sxBH', self.src, self.dst, self.p, len(p))
s = dpkt.in_cksum_add(0, s)
s = dpkt.in_cksum_add(s, p)
self.data.sum = dpkt.in_cksum_done(s)
# RFC 768 (Fields):
# If the computed checksum is zero, it is transmitted as all
# ones (the equivalent in one's complement arithmetic). An all
# zero transmitted checksum value means that the transmitter
# generated no checksum (for debugging or for higher level
# protocols that don't care).
if self.p == 17 and self.data.sum == 0:
self.data.sum = 0xffff
# XXX - skip transports which don't need the pseudoheader
return self.pack_hdr() + bytes(self.opts) + bytes(self.data)
def unpack(self, buf):
dpkt.Packet.unpack(self, buf)
ol = ((self._v_hl & 0xf) << 2) - self.__hdr_len__
if ol < 0:
raise dpkt.UnpackError('invalid header length')
self.opts = buf[self.__hdr_len__:self.__hdr_len__ + ol]
if self.len:
buf = buf[self.__hdr_len__ + ol:self.len]
else: # very likely due to TCP segmentation offload
buf = buf[self.__hdr_len__ + ol:]
try:
self.data = self._protosw[self.p](buf) if self.offset == 0 else buf
setattr(self, self.data.__class__.__name__.lower(), self.data)
except (KeyError, dpkt.UnpackError):
self.data = buf
@classmethod
def set_proto(cls, p, pktclass):
cls._protosw[p] = pktclass
@classmethod
def get_proto(cls, p):
return cls._protosw[p]
# XXX - compatibility; to be deprecated
@property
def off(self):
deprecation_warning("IP.off is deprecated")
return self._flags_offset
@off.setter
def off(self, val):
deprecation_warning("IP.off is deprecated")
self.offset = val
# IP Headers
IP_ADDR_LEN = 0x04
IP_ADDR_BITS = 0x20
IP_HDR_LEN = 0x14
IP_OPT_LEN = 0x02
IP_OPT_LEN_MAX = 0x28
IP_HDR_LEN_MAX = IP_HDR_LEN + IP_OPT_LEN_MAX
IP_LEN_MAX = 0xffff
IP_LEN_MIN = IP_HDR_LEN
# Reserved Addresses
IP_ADDR_ANY = "\x00\x00\x00\x00" # 0.0.0.0
IP_ADDR_BROADCAST = "\xff\xff\xff\xff" # 255.255.255.255
IP_ADDR_LOOPBACK = "\x7f\x00\x00\x01" # 127.0.0.1
IP_ADDR_MCAST_ALL = "\xe0\x00\x00\x01" # 224.0.0.1
IP_ADDR_MCAST_LOCAL = "\xe0\x00\x00\xff" # 224.0.0.255
# Type of service (ip_tos), RFC 1349 ("obsoleted by RFC 2474")
IP_TOS_DEFAULT = 0x00 # default
IP_TOS_LOWDELAY = 0x10 # low delay
IP_TOS_THROUGHPUT = 0x08 # high throughput
IP_TOS_RELIABILITY = 0x04 # high reliability
IP_TOS_LOWCOST = 0x02 # low monetary cost - XXX
IP_TOS_ECT = 0x02 # ECN-capable transport
IP_TOS_CE = 0x01 # congestion experienced
# IP precedence (high 3 bits of ip_tos), hopefully unused
IP_TOS_PREC_ROUTINE = 0x00
IP_TOS_PREC_PRIORITY = 0x20
IP_TOS_PREC_IMMEDIATE = 0x40
IP_TOS_PREC_FLASH = 0x60
IP_TOS_PREC_FLASHOVERRIDE = 0x80
IP_TOS_PREC_CRITIC_ECP = 0xa0
IP_TOS_PREC_INTERNETCONTROL = 0xc0
IP_TOS_PREC_NETCONTROL = 0xe0
# Fragmentation flags (ip_off)
IP_RF = 0x8000 # reserved
IP_DF = 0x4000 # don't fragment
IP_MF = 0x2000 # more fragments (not last frag)
IP_OFFMASK = 0x1fff # mask for fragment offset
# Time-to-live (ip_ttl), seconds
IP_TTL_DEFAULT = 64 # default ttl, RFC 1122, RFC 1340
IP_TTL_MAX = 255 # maximum ttl
# Protocol (ip_p) - http://www.iana.org/assignments/protocol-numbers
IP_PROTO_IP = 0 # dummy for IP
IP_PROTO_HOPOPTS = IP_PROTO_IP # IPv6 hop-by-hop options
IP_PROTO_ICMP = 1 # ICMP
IP_PROTO_IGMP = 2 # IGMP
IP_PROTO_GGP = 3 # gateway-gateway protocol
IP_PROTO_IPIP = 4 # IP in IP
IP_PROTO_ST = 5 # ST datagram mode
IP_PROTO_TCP = 6 # TCP
IP_PROTO_CBT = 7 # CBT
IP_PROTO_EGP = 8 # exterior gateway protocol
IP_PROTO_IGP = 9 # interior gateway protocol
IP_PROTO_BBNRCC = 10 # BBN RCC monitoring
IP_PROTO_NVP = 11 # Network Voice Protocol
IP_PROTO_PUP = 12 # PARC universal packet
IP_PROTO_ARGUS = 13 # ARGUS
IP_PROTO_EMCON = 14 # EMCON
IP_PROTO_XNET = 15 # Cross Net Debugger
IP_PROTO_CHAOS = 16 # Chaos
IP_PROTO_UDP = 17 # UDP
IP_PROTO_MUX = 18 # multiplexing
IP_PROTO_DCNMEAS = 19 # DCN measurement
IP_PROTO_HMP = 20 # Host Monitoring Protocol
IP_PROTO_PRM = 21 # Packet Radio Measurement
IP_PROTO_IDP = 22 # Xerox NS IDP
IP_PROTO_TRUNK1 = 23 # Trunk-1
IP_PROTO_TRUNK2 = 24 # Trunk-2
IP_PROTO_LEAF1 = 25 # Leaf-1
IP_PROTO_LEAF2 = 26 # Leaf-2
IP_PROTO_RDP = 27 # "Reliable Datagram" proto
IP_PROTO_IRTP = 28 # Inet Reliable Transaction
IP_PROTO_TP = 29 # ISO TP class 4
IP_PROTO_NETBLT = 30 # Bulk Data Transfer
IP_PROTO_MFPNSP = 31 # MFE Network Services
IP_PROTO_MERITINP = 32 # Merit Internodal Protocol
IP_PROTO_SEP = 33 # Sequential Exchange proto
IP_PROTO_3PC = 34 # Third Party Connect proto
IP_PROTO_IDPR = 35 # Interdomain Policy Route
IP_PROTO_XTP = 36 # Xpress Transfer Protocol
IP_PROTO_DDP = 37 # Datagram Delivery Proto
IP_PROTO_CMTP = 38 # IDPR Ctrl Message Trans
IP_PROTO_TPPP = 39 # TP++ Transport Protocol
IP_PROTO_IL = 40 # IL Transport Protocol
IP_PROTO_IP6 = 41 # IPv6
IP_PROTO_SDRP = 42 # Source Demand Routing
IP_PROTO_ROUTING = 43 # IPv6 routing header
IP_PROTO_FRAGMENT = 44 # IPv6 fragmentation header
IP_PROTO_RSVP = 46 # Reservation protocol
IP_PROTO_GRE = 47 # General Routing Encap
IP_PROTO_MHRP = 48 # Mobile Host Routing
IP_PROTO_ENA = 49 # ENA
IP_PROTO_ESP = 50 # Encap Security Payload
IP_PROTO_AH = 51 # Authentication Header
IP_PROTO_INLSP = 52 # Integated Net Layer Sec
IP_PROTO_SWIPE = 53 # SWIPE
IP_PROTO_NARP = 54 # NBMA Address Resolution
IP_PROTO_MOBILE = 55 # Mobile IP, RFC 2004
IP_PROTO_TLSP = 56 # Transport Layer Security
IP_PROTO_SKIP = 57 # SKIP
IP_PROTO_ICMP6 = 58 # ICMP for IPv6
IP_PROTO_NONE = 59 # IPv6 no next header
IP_PROTO_DSTOPTS = 60 # IPv6 destination options
IP_PROTO_ANYHOST = 61 # any host internal proto
IP_PROTO_CFTP = 62 # CFTP
IP_PROTO_ANYNET = 63 # any local network
IP_PROTO_EXPAK = 64 # SATNET and Backroom EXPAK
IP_PROTO_KRYPTOLAN = 65 # Kryptolan
IP_PROTO_RVD = 66 # MIT Remote Virtual Disk
IP_PROTO_IPPC = 67 # Inet Pluribus Packet Core
IP_PROTO_DISTFS = 68 # any distributed fs
IP_PROTO_SATMON = 69 # SATNET Monitoring
IP_PROTO_VISA = 70 # VISA Protocol
IP_PROTO_IPCV = 71 # Inet Packet Core Utility
IP_PROTO_CPNX = 72 # Comp Proto Net Executive
IP_PROTO_CPHB = 73 # Comp Protocol Heart Beat
IP_PROTO_WSN = 74 # Wang Span Network
IP_PROTO_PVP = 75 # Packet Video Protocol
IP_PROTO_BRSATMON = 76 # Backroom SATNET Monitor
IP_PROTO_SUNND = 77 # SUN ND Protocol
IP_PROTO_WBMON = 78 # WIDEBAND Monitoring
IP_PROTO_WBEXPAK = 79 # WIDEBAND EXPAK
IP_PROTO_EON = 80 # ISO CNLP
IP_PROTO_VMTP = 81 # Versatile Msg Transport
IP_PROTO_SVMTP = 82 # Secure VMTP
IP_PROTO_VINES = 83 # VINES
IP_PROTO_TTP = 84 # TTP
IP_PROTO_NSFIGP = 85 # NSFNET-IGP
IP_PROTO_DGP = 86 # Dissimilar Gateway Proto
IP_PROTO_TCF = 87 # TCF
IP_PROTO_EIGRP = 88 # EIGRP
IP_PROTO_OSPF = 89 # Open Shortest Path First
IP_PROTO_SPRITERPC = 90 # Sprite RPC Protocol
IP_PROTO_LARP = 91 # Locus Address Resolution
IP_PROTO_MTP = 92 # Multicast Transport Proto
IP_PROTO_AX25 = 93 # AX.25 Frames
IP_PROTO_IPIPENCAP = 94 # yet-another IP encap
IP_PROTO_MICP = 95 # Mobile Internet Ctrl
IP_PROTO_SCCSP = 96 # Semaphore Comm Sec Proto
IP_PROTO_ETHERIP = 97 # Ethernet in IPv4
IP_PROTO_ENCAP = 98 # encapsulation header
IP_PROTO_ANYENC = 99 # private encryption scheme
IP_PROTO_GMTP = 100 # GMTP
IP_PROTO_IFMP = 101 # Ipsilon Flow Mgmt Proto
IP_PROTO_PNNI = 102 # PNNI over IP
IP_PROTO_PIM = 103 # Protocol Indep Multicast
IP_PROTO_ARIS = 104 # ARIS
IP_PROTO_SCPS = 105 # SCPS
IP_PROTO_QNX = 106 # QNX
IP_PROTO_AN = 107 # Active Networks
IP_PROTO_IPCOMP = 108 # IP Payload Compression
IP_PROTO_SNP = 109 # Sitara Networks Protocol
IP_PROTO_COMPAQPEER = 110 # Compaq Peer Protocol
IP_PROTO_IPXIP = 111 # IPX in IP
IP_PROTO_VRRP = 112 # Virtual Router Redundancy
IP_PROTO_PGM = 113 # PGM Reliable Transport
IP_PROTO_ANY0HOP = 114 # 0-hop protocol
IP_PROTO_L2TP = 115 # Layer 2 Tunneling Proto
IP_PROTO_DDX = 116 # D-II Data Exchange (DDX)
IP_PROTO_IATP = 117 # Interactive Agent Xfer
IP_PROTO_STP = 118 # Schedule Transfer Proto
IP_PROTO_SRP = 119 # SpectraLink Radio Proto
IP_PROTO_UTI = 120 # UTI
IP_PROTO_SMP = 121 # Simple Message Protocol
IP_PROTO_SM = 122 # SM
IP_PROTO_PTP = 123 # Performance Transparency
IP_PROTO_ISIS = 124 # ISIS over IPv4
IP_PROTO_FIRE = 125 # FIRE
IP_PROTO_CRTP = 126 # Combat Radio Transport
IP_PROTO_CRUDP = 127 # Combat Radio UDP
IP_PROTO_SSCOPMCE = 128 # SSCOPMCE
IP_PROTO_IPLT = 129 # IPLT
IP_PROTO_SPS = 130 # Secure Packet Shield
IP_PROTO_PIPE = 131 # Private IP Encap in IP
IP_PROTO_SCTP = 132 # Stream Ctrl Transmission
IP_PROTO_FC = 133 # Fibre Channel
IP_PROTO_RSVPIGN = 134 # RSVP-E2E-IGNORE
IP_PROTO_RAW = 255 # Raw IP packets
IP_PROTO_RESERVED = IP_PROTO_RAW # Reserved
IP_PROTO_MAX = 255
# XXX - auto-load IP dispatch table from IP_PROTO_* definitions
def __load_protos():
g = globals()
for k, v in iteritems(g):
if k.startswith('IP_PROTO_'):
name = k[9:]
_ip_proto_names[v] = name
try:
mod = __import__(name.lower(), g, level=1)
IP.set_proto(v, getattr(mod, name))
except (ImportError, AttributeError):
continue
def _mod_init():
"""Post-initialization called when all dpkt modules are fully loaded"""
if not IP._protosw:
__load_protos()
def test_ip():
from . import udp
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'
ip = IP(id=0, src=b'\x01\x02\x03\x04', dst=b'\x01\x02\x03\x04', p=17)
u = udp.UDP(sport=111, dport=222)
u.data = b'foobar'
u.ulen += len(u.data)
ip.data = u
ip.len += len(u)
assert (bytes(ip) == s)
assert (ip.v == 4)
assert (ip.hl == 5)
ip = IP(s)
assert (bytes(ip) == s)
assert (ip.udp.sport == 111)
assert (ip.udp.data == b'foobar')
def test_dict():
ip = IP(id=0, src=b'\x01\x02\x03\x04', dst=b'\x01\x02\x03\x04', p=17)
d = dict(ip)
assert (d['src'] == b'\x01\x02\x03\x04')
assert (d['dst'] == b'\x01\x02\x03\x04')
assert (d['id'] == 0)
assert (d['p'] == 17)
def test_hl(): # Todo chack this test method
s = (b'BB\x03\x00\x00\x00\x00\x00\x00\x00\xd0\x00\xec\xbc\xa5\x00\x00\x00\x03\x80\x00\x00\xd0'
b'\x01\xf2\xac\xa5"0\x01\x00\x14\x00\x02\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00')
try:
IP(s)
except dpkt.UnpackError:
pass
def test_opt():
s = (b'\x4f\x00\x00\x3c\xae\x08\x00\x00\x40\x06\x18\x10\xc0\xa8\x0a\x26\xc0\xa8\x0a\x01\x07\x27'
b'\x08\x01\x02\x03\x04\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
ip = IP(s)
ip.sum = 0
assert (bytes(ip) == s)
def test_zerolen():
from . import tcp
d = b'X' * 2048
s = (b'\x45\x00\x00\x00\x34\xce\x40\x00\x80\x06\x00\x00\x7f\x00\x00\x01\x7f\x00\x00\x01\xcc\x4e'
b'\x0c\x38\x60\xff\xc6\x4e\x5f\x8a\x12\x98\x50\x18\x40\x29\x3a\xa3\x00\x00') + d
ip = IP(s)
assert (isinstance(ip.data, tcp.TCP))
assert (ip.tcp.data == d)
def test_constuctor():
ip1 = IP(data=b"Hello world!")
ip2 = IP(data=b"Hello world!", len=0)
ip3 = IP(bytes(ip1))
ip4 = IP(bytes(ip2))
assert (bytes(ip1) == bytes(ip3))
assert (bytes(ip1) == b'E\x00\x00 \x00\x00\x00\x00@\x00z\xdf\x00\x00\x00\x00\x00\x00\x00\x00Hello world!')
assert (bytes(ip2) == bytes(ip4))
assert (bytes(ip2) == b'E\x00\x00 \x00\x00\x00\x00@\x00z\xdf\x00\x00\x00\x00\x00\x00\x00\x00Hello world!')
def test_frag():
from . import ethernet
s = (b'\x00\x23\x20\xd4\x2a\x8c\x00\x23\x20\xd4\x2a\x8c\x08\x00\x45\x00\x00\x54\x00\x00\x40\x00'
b'\x40\x01\x25\x8d\x0a\x00\x00\x8f\x0a\x00\x00\x8e\x08\x00\x2e\xa0\x01\xff\x23\x73\x20\x48'
b'\x4a\x4d\x00\x00\x00\x00\x78\x85\x02\x00\x00\x00\x00\x00\x10\x11\x12\x13\x14\x15\x16\x17'
b'\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d'
b'\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37')
ip = ethernet.Ethernet(s).ip
assert (ip.rf == 0)
assert (ip.df == 1)
assert (ip.mf == 0)
assert (ip.offset == 0)
# test setters of fragmentation related attributes.
ip.rf = 1
ip.df = 0
ip.mf = 1
ip.offset = 1480
assert (ip.rf == 1)
assert (ip.df == 0)
assert (ip.mf == 1)
assert (ip.offset == 1480)
def test_property_setters():
ip = IP()
assert ip.v == 4
ip.v = 6
assert ip.v == 6
# test property delete
del ip.v
assert ip.v == 4 # back to default
assert ip.hl == 5
ip.hl = 7
assert ip.hl == 7
del ip.hl
assert ip.hl == 5
# coverage
ip.off = 10
assert ip.off == 10
def test_default_udp_checksum():
from dpkt.udp import UDP
udp = UDP(sport=1, dport=0xffdb)
ip = IP(src=b'\x00\x00\x00\x01', dst=b'\x00\x00\x00\x01', p=17, data=udp)
assert ip.p == 17
assert ip.data.sum == 0
# this forces recalculation of the data layer checksum
bytes(ip)
# during calculation the checksum was evaluated to 0x0000
# this was then conditionally set to 0xffff per RFC768
assert ip.data.sum == 0xffff
def test_get_proto_name():
assert get_ip_proto_name(6) == 'TCP'
assert get_ip_proto_name(999) is None