123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171 |
- """Packet read and write routines using network sockets."""
- from pypacker import pypacker
- from pypacker.layer12 import ethernet
- import socket
- import logging
- logger = logging.getLogger("pypacker")
- class SocketHndl(object):
- """
- Simple socket handler for layer 2 and 3 reading/writing.
- """
- ETH_P_ALL = 0x0003
- MODE_LAYER_2 = 0
- MODE_LAYER_3 = 1
- def __init__(self, iface_name="lo", mode=MODE_LAYER_2, timeout=3, buffersize_recv=2 ** 26, buffersize_send=2 ** 26):
- """
- iface_name -- bind to the given interface, mainly for MODE_LAYER_2
- mode -- set socket-mode for sending data (used by send() and sr()). The following modes are supported:
- MODE_LAYER_2: layer 2 packets have to be provided (Ethernet etc)
- MODE_LAYER_3: layer 3 packets have to be provided (IP, ARP etc), mac is auto-resolved
- timeout -- read timeout in seconds
- bufferspace -- amount of buffer used for receiving and sending
- """
- self.iface_name = iface_name
- self._socket_send = None
- self._socket_recv = None
- self.__mode = mode
- logger.info("creating socket on interface: %s" % iface_name)
- # use raw socket for receiving in all modes
- self._socket_recv = socket.socket(socket.AF_PACKET,
- socket.SOCK_RAW,
- socket.htons(SocketHndl.ETH_P_ALL))
- self._socket_recv.settimeout(timeout)
- if iface_name is not None:
- self._socket_recv.bind((iface_name, SocketHndl.ETH_P_ALL))
- # same socket for sending
- if mode == SocketHndl.MODE_LAYER_2:
- self._socket_send = self._socket_recv
- # different socket for sending
- elif mode == SocketHndl.MODE_LAYER_3:
- self._socket_send = socket.socket(socket.AF_INET,
- socket.SOCK_RAW,
- socket.IPPROTO_RAW)
- self._socket_send.setsockopt(socket.SOL_IP, socket.IP_HDRINCL, 1)
- self._socket_recv.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, buffersize_recv)
- self._socket_send.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, buffersize_send)
- def send(self, bts, dst=None):
- """
- Send the given bytes to network.
- bts -- the bytes to be sent
- dst -- destination for Layer 3 if mode is MODE_LAYER_3
- """
- if self.__mode == SocketHndl.MODE_LAYER_2:
- self._socket_send.send(bts)
- elif self.__mode == SocketHndl.MODE_LAYER_3:
- self._socket_send.sendto(bts, (dst, 0))
- def recv(self):
- """
- return -- bytes received from network
- """
- return self._socket_recv.recv(65536)
- def __iter__(self):
- """
- Call recv() until socket.timeout
- """
- try:
- while True:
- yield self.recv()
- except socket.timeout:
- raise StopIteration
- def recvp(self, filter_match_recv=None, lowest_layer=ethernet.Ethernet, max_amount=1):
- """
- Receive packets from network. This does the same as calling recv() but using a receive
- filter and received bytes will be converted to packets using class given by lowest_layer.
- Raises socket.timeout on timeout
- filter_match_recv -- filter as callback function to match packets to be retrieved.
- Callback-structure: fct(packet), Return True to accept a specific packet.
- Raise StopIteration to stop receiving packets, max_amount will match after all.
- lowest_layer -- packet class to be used to create new packets
- max_amount -- maximum amount of packets to be fetched
- return -- packets received from network as list
- """
- received = []
- # logger.debug("listening for packets")
- while len(received) < max_amount:
- bts = self.recv()
- packet_recv = lowest_layer(bts)
- # logger.debug("got packet: %s" % packet_recv)
- try:
- if filter_match_recv(packet_recv):
- received.append(packet_recv)
- except TypeError:
- # no filter set
- received.append(packet_recv)
- except StopIteration:
- break
- return received
- def sr(self, packet_send, max_packets_recv=1, filter=None, lowest_layer=ethernet.Ethernet):
- """
- Send a packet and receive answer packets. This will use information retrieved
- from direction() to retrieve answer packets. Raises socket.timeout on timeout
- packet_send -- pypacker packet to be sent
- max_packets_recv -- max packets to be received
- filter -- filter as lambda function to match packets to be retrieved,
- return True to accept a specific packet.
- Set to None to accept everything.
- lowest_layer -- packet class to be used to create new packets
- return -- packets receives
- """
- received = []
- packet_send_clz = packet_send.__class__
- if self.__mode == SocketHndl.MODE_LAYER_2:
- self.send(packet_send.bin())
- elif self.__mode == SocketHndl.MODE_LAYER_3:
- # logger.debug("sr with layer 3: %s" % packet_send.dst_s)
- self.send(packet_send.bin(), dst=packet_send.dst_s)
- while len(received) < max_packets_recv:
- bts = self.recv()
- packet_recv = lowest_layer(bts)
- # logger.debug("got packet: %s" % packet_recv)
- try:
- if not filter(packet_recv):
- # filter didn't match
- continue
- except TypeError:
- # no filter set
- pass
- # packet_send_clz can be IP on MODE_LAYER_3, start to compare on corresponding receive-layer
- if packet_send.is_direction(packet_recv[packet_send_clz], pypacker.Packet.DIR_REV):
- # logger.debug("direction matched: %s" % packet_recv)
- received.append(packet_recv)
- return received
- def close(self):
- try:
- self._socket_send.close()
- except:
- pass
- try:
- self._socket_recv.close()
- except:
- pass
|