Sending packets with scapy
I’m currently doing some code based on scapy. This code reads data from a possibly huge file and send a packet for each line in the file using the contained information.
So the code contains a simple loop and uses sendp because the frame must be sent at layer 2.
def run(self): filedesc = open(self.filename, 'r') # loop on read line for line in filedesc: # Build and send packet sendp(pkt, iface = self.iface, verbose = verbose) # Inter packet treatment
Doing that the performance are a bit deceptive. For 18 packets, we’ve got:
real 0m2.437s user 0m0.056s sys 0m0.012s
If we strace the code, the explanation is quite obvious:
socket(PF_PACKET, SOCK_RAW, 768) = 4 setsockopt(4, SOL_SOCKET, SO_RCVBUF, [0], 4) = 0 select(5, [4], [], [], {0, 0}) = 0 (Timeout) ioctl(4, SIOCGIFINDEX, {ifr_name="lo", ifr_index=1}) = 0 bind(4, {sa_family=AF_PACKET, proto=0x03, if1, pkttype=PACKET_HOST, addr(0)={0, }, 20) = 0 setsockopt(4, SOL_SOCKET, SO_RCVBUF, [1073741824], 4) = 0 setsockopt(4, SOL_SOCKET, SO_SNDBUF, [1073741824], 4) = 0 getsockname(4, {sa_family=AF_PACKET, proto=0x03, if1, pkttype=PACKET_HOST, addr(6)={772, 000000000000}, [18]) = 0 ioctl(4, SIOCGIFNAME, {ifr_index=1, ifr_name="lo"}) = 0 sendto(4, "\377\377\377\377\377\377\0\0\0\0\0\0\10\0E\0\0S}0@\0*\6\265\373\307;\224\24\300\250"..., 97, 0, NULL, 0) = 97 select(0, NULL, NULL, NULL, {0, 0}) = 0 (Timeout) close(4) = 0 socket(PF_PACKET, SOCK_RAW, 768) = 4 setsockopt(4, SOL_SOCKET, SO_RCVBUF, [0], 4) = 0 select(5, [4], [], [], {0, 0}) = 0 (Timeout) ioctl(4, SIOCGIFINDEX, {ifr_name="lo", ifr_index=1}) = 0 bind(4, {sa_family=AF_PACKET, proto=0x03, if1, pkttype=PACKET_HOST, addr(0)={0, }, 20) = 0 setsockopt(4, SOL_SOCKET, SO_RCVBUF, [1073741824], 4) = 0 setsockopt(4, SOL_SOCKET, SO_SNDBUF, [1073741824], 4) = 0 getsockname(4, {sa_family=AF_PACKET, proto=0x03, if1, pkttype=PACKET_HOST, addr(6)={772, 000000000000}, [18]) = 0 ioctl(4, SIOCGIFNAME, {ifr_index=1, ifr_name="lo"}) = 0 sendto(4, "\377\377\377\377\377\377\0\0\0\0\0\0\10\0E\0\0004}1@\0*\6\266\31\307;\224\24\300\250"..., 66, 0, NULL, 0) = 66 select(0, NULL, NULL, NULL, {0, 0}) = 0 (Timeout) close(4) = 0
For each packet, a new socket is opened and this takes age.
Speeding up the sending
To speed up the sending, one solution is to build a list of packets and to send that list via a sendp() call.
def run(self): filedesc = open(self.filename, 'r') pkt_list = [] # loop on read line for line in filedesc: # Build and send packet pkt_list.append(pkt) sendp(pkt_list, iface = self.iface, verbose = verbose)
This is not possible in our case due to the inter packet treatment we have to do.
So the best way is to reuse the socket. This can be done easily when you’ve read the documentation^W code:
@@ -27,6 +27,7 @@ class replay: def run(self): # open filename filedesc = open(self.filename, 'r') + s = conf.L2socket(iface=self.iface) # loop on read line for line in filedesc: # Build and send packet - sendp(pkt, iface = self.iface, verbose = verbose) + s.send(pkt)
The idea is to create a socket via the function used in sendp() and to use the send() function of the object to send packets.
With that modification, the performance are far better:
real 0m0.108s user 0m0.064s sys 0m0.004s
I’m not a scapy expert so ping me if there is a better way to do this.