ip.py 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. # -*- test-case-name: twisted.pair.test.test_ip -*-
  2. # Copyright (c) Twisted Matrix Laboratories.
  3. # See LICENSE for details.
  4. #
  5. """Support for working directly with IP packets"""
  6. import socket
  7. import struct
  8. from zope.interface import implementer
  9. from twisted.internet import protocol
  10. from twisted.pair import raw
  11. class IPHeader:
  12. def __init__(self, data):
  13. (
  14. ihlversion,
  15. self.tos,
  16. self.tot_len,
  17. self.fragment_id,
  18. frag_off,
  19. self.ttl,
  20. self.protocol,
  21. self.check,
  22. saddr,
  23. daddr,
  24. ) = struct.unpack("!BBHHHBBH4s4s", data[:20])
  25. self.saddr = socket.inet_ntoa(saddr)
  26. self.daddr = socket.inet_ntoa(daddr)
  27. self.version = ihlversion & 0x0F
  28. self.ihl = ((ihlversion & 0xF0) >> 4) << 2
  29. self.fragment_offset = frag_off & 0x1FFF
  30. self.dont_fragment = frag_off & 0x4000 != 0
  31. self.more_fragments = frag_off & 0x2000 != 0
  32. MAX_SIZE = 2**32
  33. @implementer(raw.IRawPacketProtocol)
  34. class IPProtocol(protocol.AbstractDatagramProtocol):
  35. def __init__(self):
  36. self.ipProtos = {}
  37. def addProto(self, num, proto):
  38. proto = raw.IRawDatagramProtocol(proto)
  39. if num < 0:
  40. raise TypeError("Added protocol must be positive or zero")
  41. if num >= MAX_SIZE:
  42. raise TypeError("Added protocol must fit in 32 bits")
  43. if num not in self.ipProtos:
  44. self.ipProtos[num] = []
  45. self.ipProtos[num].append(proto)
  46. def datagramReceived(self, data, partial, dest, source, protocol):
  47. header = IPHeader(data)
  48. for proto in self.ipProtos.get(header.protocol, ()):
  49. proto.datagramReceived(
  50. data=data[20:],
  51. partial=partial,
  52. source=header.saddr,
  53. dest=header.daddr,
  54. protocol=header.protocol,
  55. version=header.version,
  56. ihl=header.ihl,
  57. tos=header.tos,
  58. tot_len=header.tot_len,
  59. fragment_id=header.fragment_id,
  60. fragment_offset=header.fragment_offset,
  61. dont_fragment=header.dont_fragment,
  62. more_fragments=header.more_fragments,
  63. ttl=header.ttl,
  64. )