I'm writing a TCP SYN port scanner. I spin up 15 tasks that each send 64K / 15 packets to 64K ports, and I have a receiver that sits in a loop and prints the responses. However, some of the packets don't make their way back, making the receiver wait in the loop forever.
I'm looking for a way to reliably detect that no more packets are coming so that I can retry getting the missing ones.
async def recv_from(sock, target):
while True:
data, addr = await sock.recvfrom(1024)
if addr[0] == target:
yield data
async def receiver() -> None:
sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_TCP)
ports = list(range(PORTS))
async for packet in recv_from(sock, '192.168.1.1'):
if not ports:
break
src, dest, flags = unpack(packet)
if dest == 6969:
ports.remove(src)
if flags == 20:
print("port %d: closed" % src)
elif flags == 18:
print("port %d: open" % src)
sock.close()
async def sender(idx: int) -> None:
sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
for port in range(idx * int(PORTS / TASKS), (idx + 1) * int(PORTS / TASKS)):
tcp_packet = build_tcp_packet(port)
ipv4_packet = build_ipv4_packet()
await sock.sendto(ipv4_packet + tcp_packet, ('192.168.1.1', port))
sock.close()
async def main() -> None:
async with trio.open_nursery() as nursery:
nursery.start_soon(receiver)
for i in range(TASKS):
nursery.start_soon(sender, i)
await trio.sleep(0.5)
if __name__ == '__main__':
trio.run(main)