psocket.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. """Packet read and write routines using network sockets."""
  2. from pypacker import pypacker
  3. from pypacker.layer12 import ethernet
  4. import socket
  5. import logging
  6. logger = logging.getLogger("pypacker")
  7. class SocketHndl(object):
  8. """
  9. Simple socket handler for layer 2 and 3 reading/writing.
  10. """
  11. ETH_P_ALL = 0x0003
  12. MODE_LAYER_2 = 0
  13. MODE_LAYER_3 = 1
  14. def __init__(self, iface_name="lo", mode=MODE_LAYER_2, timeout=3, buffersize_recv=2 ** 26, buffersize_send=2 ** 26):
  15. """
  16. iface_name -- bind to the given interface, mainly for MODE_LAYER_2
  17. mode -- set socket-mode for sending data (used by send() and sr()). The following modes are supported:
  18. MODE_LAYER_2: layer 2 packets have to be provided (Ethernet etc)
  19. MODE_LAYER_3: layer 3 packets have to be provided (IP, ARP etc), mac is auto-resolved
  20. timeout -- read timeout in seconds
  21. bufferspace -- amount of buffer used for receiving and sending
  22. """
  23. self.iface_name = iface_name
  24. self._socket_send = None
  25. self._socket_recv = None
  26. self.__mode = mode
  27. logger.info("creating socket on interface: %s" % iface_name)
  28. # use raw socket for receiving in all modes
  29. self._socket_recv = socket.socket(socket.AF_PACKET,
  30. socket.SOCK_RAW,
  31. socket.htons(SocketHndl.ETH_P_ALL))
  32. self._socket_recv.settimeout(timeout)
  33. if iface_name is not None:
  34. self._socket_recv.bind((iface_name, SocketHndl.ETH_P_ALL))
  35. # same socket for sending
  36. if mode == SocketHndl.MODE_LAYER_2:
  37. self._socket_send = self._socket_recv
  38. # different socket for sending
  39. elif mode == SocketHndl.MODE_LAYER_3:
  40. self._socket_send = socket.socket(socket.AF_INET,
  41. socket.SOCK_RAW,
  42. socket.IPPROTO_RAW)
  43. self._socket_send.setsockopt(socket.SOL_IP, socket.IP_HDRINCL, 1)
  44. self._socket_recv.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, buffersize_recv)
  45. self._socket_send.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, buffersize_send)
  46. def send(self, bts, dst=None):
  47. """
  48. Send the given bytes to network.
  49. bts -- the bytes to be sent
  50. dst -- destination for Layer 3 if mode is MODE_LAYER_3
  51. """
  52. if self.__mode == SocketHndl.MODE_LAYER_2:
  53. self._socket_send.send(bts)
  54. elif self.__mode == SocketHndl.MODE_LAYER_3:
  55. self._socket_send.sendto(bts, (dst, 0))
  56. def recv(self):
  57. """
  58. return -- bytes received from network
  59. """
  60. return self._socket_recv.recv(65536)
  61. def __iter__(self):
  62. """
  63. Call recv() until socket.timeout
  64. """
  65. try:
  66. while True:
  67. yield self.recv()
  68. except socket.timeout:
  69. raise StopIteration
  70. def recvp(self, filter_match_recv=None, lowest_layer=ethernet.Ethernet, max_amount=1):
  71. """
  72. Receive packets from network. This does the same as calling recv() but using a receive
  73. filter and received bytes will be converted to packets using class given by lowest_layer.
  74. Raises socket.timeout on timeout
  75. filter_match_recv -- filter as callback function to match packets to be retrieved.
  76. Callback-structure: fct(packet), Return True to accept a specific packet.
  77. Raise StopIteration to stop receiving packets, max_amount will match after all.
  78. lowest_layer -- packet class to be used to create new packets
  79. max_amount -- maximum amount of packets to be fetched
  80. return -- packets received from network as list
  81. """
  82. received = []
  83. # logger.debug("listening for packets")
  84. while len(received) < max_amount:
  85. bts = self.recv()
  86. packet_recv = lowest_layer(bts)
  87. # logger.debug("got packet: %s" % packet_recv)
  88. try:
  89. if filter_match_recv(packet_recv):
  90. received.append(packet_recv)
  91. except TypeError:
  92. # no filter set
  93. received.append(packet_recv)
  94. except StopIteration:
  95. break
  96. return received
  97. def sr(self, packet_send, max_packets_recv=1, filter=None, lowest_layer=ethernet.Ethernet):
  98. """
  99. Send a packet and receive answer packets. This will use information retrieved
  100. from direction() to retrieve answer packets. Raises socket.timeout on timeout
  101. packet_send -- pypacker packet to be sent
  102. max_packets_recv -- max packets to be received
  103. filter -- filter as lambda function to match packets to be retrieved,
  104. return True to accept a specific packet.
  105. Set to None to accept everything.
  106. lowest_layer -- packet class to be used to create new packets
  107. return -- packets receives
  108. """
  109. received = []
  110. packet_send_clz = packet_send.__class__
  111. if self.__mode == SocketHndl.MODE_LAYER_2:
  112. self.send(packet_send.bin())
  113. elif self.__mode == SocketHndl.MODE_LAYER_3:
  114. # logger.debug("sr with layer 3: %s" % packet_send.dst_s)
  115. self.send(packet_send.bin(), dst=packet_send.dst_s)
  116. while len(received) < max_packets_recv:
  117. bts = self.recv()
  118. packet_recv = lowest_layer(bts)
  119. # logger.debug("got packet: %s" % packet_recv)
  120. try:
  121. if not filter(packet_recv):
  122. # filter didn't match
  123. continue
  124. except TypeError:
  125. # no filter set
  126. pass
  127. # packet_send_clz can be IP on MODE_LAYER_3, start to compare on corresponding receive-layer
  128. if packet_send.is_direction(packet_recv[packet_send_clz], pypacker.Packet.DIR_REV):
  129. # logger.debug("direction matched: %s" % packet_recv)
  130. received.append(packet_recv)
  131. return received
  132. def close(self):
  133. try:
  134. self._socket_send.close()
  135. except:
  136. pass
  137. try:
  138. self._socket_recv.close()
  139. except:
  140. pass