ip.py 2.5 KB

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