Reputation: 4681
I am new to Python3.5, and Async in general with the exception of minor use of Twisted in Python 2.7. I'm building this into a larger application and I need a small portion, as opposed to a monolithic framework, to perform TCP port scanning.
import asyncio
from random import SystemRandom
def run(task, *, loop=None):
if loop is None:
loop = asyncio.get_event_loop()
return loop.run_until_complete(asyncio.ensure_future(task, loop=loop))
async def scanner(ip, port, loop=None):
fut = asyncio.open_connection(ip, port, loop=loop)
try:
reader, writer = await asyncio.wait_for(fut, timeout=0.5) # This is where it is blocking?
print("{}:{} Connected".format(ip, port))
except asyncio.TimeoutError:
pass
def scan(ips, ports, randomize=False):
if randomize:
rdev = SystemRandom()
ips = rdev.shuffle(ips)
ports = rdev.shuffle(ports)
for port in ports:
for ips in ips:
run(scanner(ip, port))
ips = ["192.168.0.{}".format(i) for i in range(1, 255)]
ports = [22, 80, 443, 8080]
scan(ips, ports)
This is still taking as long as a single thread would take. How can I turn this into an async TCP scanner?
Upvotes: 2
Views: 2242
Reputation: 12587
run_until_complete
is blocking, the execution stops there and waits until the one scan ends, then the next one...
You should schedule all (or some part) of tasks and wait for all of them with wait
.
import asyncio
from random import SystemRandom
def run(tasks, *, loop=None):
if loop is None:
loop = asyncio.get_event_loop()
# waiting for all tasks
return loop.run_until_complete(asyncio.wait(tasks))
async def scanner(ip, port, loop=None):
fut = asyncio.open_connection(ip, port, loop=loop)
try:
reader, writer = await asyncio.wait_for(fut, timeout=0.5) # This is where it is blocking?
print("{}:{} Connected".format(ip, port))
except asyncio.TimeoutError:
pass
# handle connection refused and bunch of others
except Exception as exc:
print('Error {}:{} {}'.format(ip, port, exc))
def scan(ips, ports, randomize=False):
loop = asyncio.get_event_loop()
if randomize:
rdev = SystemRandom()
ips = rdev.shuffle(ips)
ports = rdev.shuffle(ports)
# let's pass list of task, not only one
run([scanner(ip, port) for port in ports for ip in ips])
ips = ["192.168.0.{}".format(i) for i in range(1, 255)]
ports = [22, 80, 443, 8080]
scan(ips, ports)
I've also added except
block to catch rest of exceptions, including most common connection refused.
Upvotes: 3