0

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.

adder
  • 3,512
  • 1
  • 16
  • 28
  • Unfortunately the code snippets you provide are pretty incomplete. One might make educated guesses what might be the problem but there is no way to understand or even reproduce what you are really doing. – Steffen Ullrich Sep 25 '21 at 16:55

1 Answers1

1

AF_PACKET defines a raw socket. In this case incoming packets are duplicated to all raw sockets on the same interface - because there is no clear identifier which socket the incoming packet would belong to. Since you are using multiple raw sockets you get the duplicated packets on these sockets.

Steffen Ullrich
  • 114,247
  • 10
  • 131
  • 172