udp.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. """
  2. User Datagram Protocol (UDP)
  3. RFC 768 - User Datagram Protocol
  4. RFC 2460 - Internet Protocol, Version 6 (IPv6) Specification
  5. RFC 2675 - IPv6 Jumbograms
  6. RFC 4113 - Management Information Base for the UDP
  7. RFC 5405 - Unicast UDP Usage Guidelines for Application Designers
  8. """
  9. from pypacker import pypacker, checksum
  10. import struct
  11. import logging
  12. # avoid unneeded references for performance reasons
  13. pack = struct.pack
  14. unpack = struct.unpack
  15. logger = logging.getLogger("pypacker")
  16. UDP_PORT_MAX = 65535
  17. class UDP(pypacker.Packet):
  18. __hdr__ = (
  19. ("sport", "H", 0xdead),
  20. ("dport", "H", 0),
  21. ("ulen", "H", 8),
  22. ("sum", "H", 0)
  23. )
  24. def bin(self, update_auto_fields=True):
  25. if update_auto_fields:
  26. """
  27. UDP-checksum needs to be updated on one of the following:
  28. - this layer itself or any upper layer changed
  29. - changes to the IP-pseudoheader
  30. There is no update on user-set checksums.
  31. """
  32. changed = self._changed()
  33. update = True
  34. if changed:
  35. self.ulen = len(self)
  36. try:
  37. # changes to IP-layer, don't mind if this isn't IP
  38. if not self._lower_layer._header_changed:
  39. # lower layer doesn't need update, check for changes in present and upper layer
  40. # logger.debug("lower layer did NOT change!")
  41. update = changed
  42. except AttributeError:
  43. # assume not an IP packet: we can't calculate the checksum
  44. update = False
  45. if update:
  46. self._calc_sum()
  47. return pypacker.Packet.bin(self, update_auto_fields=update_auto_fields)
  48. def _dissect(self, buf):
  49. ports = [unpack(">H", buf[0:2])[0], unpack(">H", buf[2:4])[0]]
  50. try:
  51. # source or destination port should match
  52. htype = [x for x in ports if x in pypacker.Packet._handler[UDP.__name__]][0]
  53. self._init_handler(htype, buf[8:])
  54. except:
  55. # no type found
  56. # logger.debug("could not parse type: %d because: %s" % (type, e))
  57. pass
  58. return 8
  59. def _calc_sum(self):
  60. """Recalculate the UDP-checksum."""
  61. # TCP and underwriting are freaky bitches: we need the IP pseudoheader to calculate their checksum
  62. # logger.debug("UDP sum recalc: %s/%s/%s" % (src, dst, changed))
  63. try:
  64. # we need src/dst for checksum-calculation
  65. src, dst = self._lower_layer.src, self._lower_layer.dst
  66. # logger.debug(src + b" / "+ dst)
  67. self.sum = 0
  68. udp_bin = self.header_bytes + self.body_bytes
  69. # IP-pseudoheader: IP src, dst, \x00, UDP upper proto, length
  70. # check if version 4 or 6
  71. if len(src) == 4:
  72. s = pack(">4s4sBBH", src, dst, 0, 17, len(udp_bin)) # 17 = UDP
  73. else:
  74. s = pack(">16s16sxBH", src, dst, 17, len(udp_bin)) # 17 = UDP
  75. csum = checksum.in_cksum(s + udp_bin)
  76. if csum == 0:
  77. csum = 0xffff # RFC 768, p2
  78. # get the checksum of concatenated pseudoheader+TCP packet
  79. # assign via non-shadowed variable to trigger re-packing
  80. self.sum = csum
  81. except (AttributeError, struct.error):
  82. # not an IP packet as lower layer (src, dst not present) or invalid src/dst
  83. pass
  84. def direction(self, other):
  85. # logger.debug("checking direction: %s<->%s" % (self, other))
  86. if self.sport == other.sport and self.dport == other.dport:
  87. # consider packet to itself: can be DIR_REV
  88. return pypacker.Packet.DIR_SAME | pypacker.Packet.DIR_REV
  89. elif self.sport == other.dport and self.dport == other.sport:
  90. return pypacker.Packet.DIR_REV
  91. else:
  92. return pypacker.Packet.DIR_UNKNOWN
  93. def reverse_address(self):
  94. self.sport, self.dport = self.dport, self.sport
  95. UDP_PROTO_TELNET = 23
  96. UDP_PROTO_DNS = (53, 5353)
  97. UDP_PROTO_DHCP = (67, 68)
  98. UDP_PROTO_PMAP = 111
  99. UDP_PROTO_NTP = 123
  100. UDP_PROTO_RADIUS = (1812, 1813, 1645, 1646)
  101. UDP_PROTO_RTP = (5004, 5005)
  102. UDP_PROTO_SIP = (5060, 5061)
  103. # load handler
  104. from pypacker.layer567 import telnet, dns, dhcp, ntp, rtp, sip, pmap, radius
  105. pypacker.Packet.load_handler(UDP,
  106. {
  107. UDP_PROTO_TELNET: telnet.Telnet,
  108. UDP_PROTO_DNS: dns.DNS,
  109. UDP_PROTO_DHCP: dhcp.DHCP,
  110. UDP_PROTO_PMAP: pmap.Pmap,
  111. UDP_PROTO_NTP: ntp.NTP,
  112. UDP_PROTO_RADIUS: radius.Radius,
  113. UDP_PROTO_RTP: rtp.RTP,
  114. UDP_PROTO_SIP: sip.SIP
  115. }
  116. )