I'm having an odd issue with an AF_PACKET
socket and I was wondering if it was due to possible misuse of trio
on my behalf, or something else.
I'm writing a TCP SYN port scanner with the goal of making it highly performant. Suppose that I want to scan 64K ports; the program will split this interval into eight 8K intervals, and for each interval, spawn a multiprocessing.Process
, with trio.run
as argument. Within the process, everything is asynchronous due to the use of async sockets. Speaking of sockets, I'm doing my own filtering with BPF
- it's a simple filter that allows only packets originating at the target and destined to the listening port to pass through.
However, the issue is that I would recv()
seemingly random packets more than once, and I can't figure out why is that. I've inspected the traffic using Wireshark and I'm not seeing duplicate packets, so I reckon the issue must be somewhere within the program.
I'm looking for insight as for why this might be happening, as well as for suggestions on how to overcome the issue.
I'm also uncertain if this design where n multiprocessing.Process
run n trio
event loops is considered advisable.
I'm attaching the code if anyone wants to look:
import multiprocessing as mp
import trio
from trio import socket
async def jumboworker(target, interval):
start, end = interval
ipv4_packet = build_ipv4_packet(target)
send_sock, recv_sock = create_sock_pair(target)
await recv_sock.bind(('enp5s0', 0x0800))
for port in range(start, end):
await microworker(send_sock, recv_sock, target, ipv4_packet, port)
async def microworker(send_sock, recv_sock, target, ipv4_packet, port):
tcp_packet = build_tcp_packet(target, port)
for _ in range(3):
await send_sock.sendto(ipv4_packet + tcp_packet, (target, port))
data, addr = await recv_sock.recvfrom(1024)
src, dest, flags = unpack(data)
if flags == 18:
print('port %d: open' % src)
break
elif flags == 20:
print('port %d: closed' % src)
break
else:
break
async def main(target: str, ports: t.Union[t.Tuple, t.List]) -> None:
async with trio.open_nursery() as nursery:
if isinstance(ports, tuple):
nursery.start_soon(jumboworker, target, ports)
if __name__ == '__main__':
# Parse args and separate individual ports from
# intervals; slice big intervals to 8K
for interval in intervals:
mp.Process(target=trio.run, args=(main, target, i)).start()
if ports:
mp.Process(target=trio.run, args=(main, target, ports)).start()
Thanks.