ip.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. """
  2. Internet Protocol version 4.
  3. RFC 791
  4. """
  5. from pypacker import pypacker, triggerlist, checksum
  6. from pypacker.layer3.ip_shared import *
  7. import logging
  8. logger = logging.getLogger("pypacker")
  9. # avoid references for performance reasons
  10. in_cksum = checksum.in_cksum
  11. # IP options
  12. # http://www.iana.org/assignments/ip-parameters/ip-parameters.xml
  13. IP_OPT_EOOL = 0
  14. IP_OPT_NOP = 1
  15. IP_OPT_SEC = 2
  16. IP_OPT_LSR = 3
  17. IP_OPT_TS = 4
  18. IP_OPT_ESEC = 5
  19. IP_OPT_CIPSO = 6
  20. IP_OPT_RR = 7
  21. IP_OPT_SID = 8
  22. IP_OPT_SSR = 9
  23. IP_OPT_ZSU = 10
  24. IP_OPT_MTUP = 11
  25. IP_OPT_MTUR = 12
  26. IP_OPT_FINN = 13
  27. IP_OPT_VISA = 14
  28. IP_OPT_ENCODE = 15
  29. IP_OPT_IMITD = 16
  30. IP_OPT_EIP = 17
  31. IP_OPT_TR = 18
  32. IP_OPT_ADDEXT = 19
  33. IP_OPT_RTRALT = 20
  34. IP_OPT_SDB = 21
  35. IP_OPT_UNASSGNIED = 22
  36. IP_OPT_DPS = 23
  37. IP_OPT_UMP = 24
  38. IP_OPT_QS = 25
  39. IP_OPT_EXP = 30
  40. class IPOptSingle(pypacker.Packet):
  41. __hdr__ = (
  42. ("type", "B", 0),
  43. )
  44. class IPOptMulti(pypacker.Packet):
  45. """
  46. len = total length (header + data)
  47. """
  48. __hdr__ = (
  49. ("type", "B", 0),
  50. ("len", "B", 2),
  51. )
  52. def bin(self, update_auto_fields=True):
  53. if update_auto_fields:
  54. self.len = len(self)
  55. return pypacker.Packet.bin(self, update_auto_fields=update_auto_fields)
  56. class IP(pypacker.Packet):
  57. __hdr__ = (
  58. ("v_hl", "B", 69), # = 0x45
  59. ("tos", "B", 0),
  60. ("len", "H", 20),
  61. ("id", "H", 0),
  62. ("off", "H", 0),
  63. ("ttl", "B", 64),
  64. ("p", "B", IP_PROTO_TCP),
  65. ("sum", "H", 0),
  66. ("src", "4s", b"\x00" * 4),
  67. ("dst", "4s", b"\x00" * 4),
  68. ("opts", None, triggerlist.TriggerList)
  69. )
  70. def __get_v(self):
  71. return self.v_hl >> 4
  72. def __set_v(self, value):
  73. self.v_hl = (value << 4) | (self.v_hl & 0xf)
  74. v = property(__get_v, __set_v)
  75. def __get_hl(self):
  76. return self.v_hl & 0x0f
  77. def __set_hl(self, value):
  78. self.v_hl = (self.v_hl & 0xf0) | value
  79. hl = property(__get_hl, __set_hl)
  80. # Convenient access for: src[_s], dst[_s]
  81. src_s = pypacker.get_property_ip4("src")
  82. dst_s = pypacker.get_property_ip4("dst")
  83. def _dissect(self, buf):
  84. total_header_length = ((buf[0] & 0xf) << 2)
  85. options_length = total_header_length - 20 # total IHL - standard IP-len = options length
  86. if options_length < 0:
  87. # invalid header length: assume no options at all
  88. raise Exception("invalid header length: %d" % options_length)
  89. elif options_length > 0:
  90. # logger.debug("got some IP options: %s" % tl_opts)
  91. self._init_triggerlist("opts", buf[20: 20 + options_length], self.__parse_opts)
  92. self._init_handler(buf[9], buf[total_header_length:])
  93. return total_header_length
  94. __IP_OPT_SINGLE = set([IP_OPT_EOOL, IP_OPT_NOP])
  95. @staticmethod
  96. def __parse_opts(buf):
  97. """Parse IP options and return them as List."""
  98. optlist = []
  99. i = 0
  100. p = None
  101. while i < len(buf):
  102. # logger.debug("got IP-option type %s" % buf[i])
  103. if buf[i] in IP.__IP_OPT_SINGLE:
  104. p = IPOptSingle(type=buf[i])
  105. i += 1
  106. else:
  107. olen = buf[i + 1]
  108. # logger.debug("IPOptMulti")
  109. p = IPOptMulti(type=buf[i], len=olen, body_bytes=buf[i + 2: i + olen])
  110. # logger.debug("body bytes: %s" % buf[i + 2: i + olen])
  111. i += olen # typefield + lenfield + data-len
  112. # logger.debug("IPOptMulti 2")
  113. optlist.append(p)
  114. return optlist
  115. def bin(self, update_auto_fields=True):
  116. if update_auto_fields:
  117. if self._changed():
  118. self.len = len(self)
  119. # length changed so we have to recalculate checksum
  120. # logger.debug("updating checksum")
  121. # logger.debug(">>> IP: calculating sum")
  122. # reset checksum for recalculation, mark as changed / clear cache
  123. self.sum = 0
  124. # Update header length. NOTE: needs to be a multiple of 4 Bytes.
  125. # logger.debug("updating: %r" % self._packet)
  126. # options length need to be multiple of 4 Bytes
  127. self._hl = int(self.header_len / 4) & 0xf
  128. # logger.debug(">>> IP: bytes for sum: %s" % self.header_bytes)
  129. self.sum = in_cksum(self._pack_header())
  130. # logger.debug("IP: new hl: %d / %d" % (self._packet.hdr_len, hdr_len_off))
  131. # logger.debug("new sum: %0X" % self.sum)
  132. # logger.debug("new sum: %d" % self.sum)
  133. return pypacker.Packet.bin(self, update_auto_fields=update_auto_fields)
  134. def direction(self, other):
  135. # logger.debug("checking direction: %s<->%s" % (self, next))
  136. # TODO: handle broadcast
  137. if self.src == other.src and self.dst == other.dst:
  138. # consider packet to itself: can be DIR_REV
  139. return pypacker.Packet.DIR_SAME | pypacker.Packet.DIR_REV
  140. elif self.src == other.dst and self.dst == other.src:
  141. return pypacker.Packet.DIR_REV
  142. else:
  143. return pypacker.Packet.DIR_UNKNOWN
  144. def reverse_address(self):
  145. self.src, self.dst = self.dst, self.src
  146. # Type of service (ip_tos), RFC 1349 ("obsoleted by RFC 2474")
  147. IP_TOS_DEFAULT = 0x00 # default
  148. IP_TOS_LOWDELAY = 0x10 # low delay
  149. IP_TOS_THROUGHPUT = 0x08 # high throughput
  150. IP_TOS_RELIABILITY = 0x04 # high reliability
  151. IP_TOS_LOWCOST = 0x02 # low monetary cost - XXX
  152. IP_TOS_ECT = 0x02 # ECN-capable transport
  153. IP_TOS_CE = 0x01 # congestion experienced
  154. # IP precedence (high 3 bits of ip_tos), hopefully unused
  155. IP_TOS_PREC_ROUTINE = 0x00
  156. IP_TOS_PREC_PRIORITY = 0x20
  157. IP_TOS_PREC_IMMEDIATE = 0x40
  158. IP_TOS_PREC_FLASH = 0x60
  159. IP_TOS_PREC_FLASHOVERRIDE = 0x80
  160. IP_TOS_PREC_CRITIC_ECP = 0xa0
  161. IP_TOS_PREC_INTERNETCONTROL = 0xc0
  162. IP_TOS_PREC_NETCONTROL = 0xe0
  163. # Fragmentation flags (ip_off)
  164. IP_RF = 0x8000 # reserved
  165. IP_DF = 0x4000 # don't fragment
  166. IP_MF = 0x2000 # more fragments (not last frag)
  167. IP_OFFMASK = 0x1fff # mask for fragment offset
  168. # Time-to-live (ip_ttl), seconds
  169. IP_TTL_DEFAULT = 64 # default ttl, RFC 1122, RFC 1340
  170. IP_TTL_MAX = 255 # maximum ttl
  171. # load handler
  172. from pypacker.layer3 import esp, icmp, igmp, ip6, ipx, ospf, pim
  173. from pypacker.layer4 import tcp, udp, sctp
  174. pypacker.Packet.load_handler(IP,
  175. {
  176. IP_PROTO_IP: IP,
  177. IP_PROTO_ICMP: icmp.ICMP,
  178. IP_PROTO_IGMP: igmp.IGMP,
  179. IP_PROTO_TCP: tcp.TCP,
  180. IP_PROTO_UDP: udp.UDP,
  181. IP_PROTO_IP6: ip6.IP6,
  182. IP_PROTO_ESP: esp.ESP,
  183. IP_PROTO_PIM: pim.PIM,
  184. IP_PROTO_IPXIP: ipx.IPX,
  185. IP_PROTO_SCTP: sctp.SCTP,
  186. IP_PROTO_OSPF: ospf.OSPF
  187. }
  188. )