views:

201

answers:

2

I've written a small script in Python that pings all subnets of my school's wireless network and prints out the IP addresses and hostnames of computers that are connected to each subnet of the network. My current setup is that I'm relying on creating threads to handle each of the ping requests.

from threading import Thread
import subprocess
from Queue import Queue
import time
import socket

#wraps system ping command
def ping(i, q):
    """Pings address"""
    while True:
        ip = q.get()
        #print "Thread %s: Pinging %s" % (i, ip)
        result = subprocess.call("ping -n 1 %s" % ip, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        #Avoid flooding the network with ping requests
        time.sleep(3)
        if result == 0:

            try:
                hostname=socket.gethostbyaddr(ip)
                print "%s (%s): alive" % (ip,hostname[0])
            except:
                print "%s: alive"%ip
        q.task_done()

num_threads = 100
queue = Queue()
addresses=[]
#Append all possible IP addresses from all subnets on wireless network
for i in range(1,255):
    for j in range(1,254):
        addresses.append('128.119.%s.%s'%(str(i),str(j)))
#Spawn thread pool
for i in range(num_threads):
    worker = Thread(target=ping, args=(i, queue))
    worker.setDaemon(True)
    worker.start()
#Place work in queue
for ip in addresses:
    queue.put(ip)
#Wait until worker threads are done to exit    
queue.join()

However, I want to modify my script so that it only seeks out the first available host in the subnet. What that means is that suppose I have the following subnet (128.119.177.0/24) and the first available host is 128.119.177.20. I want my script to stop pinging the remaining hosts in the 128.119.177.0/24 after I successfully contact 128.119.177.20. I want to repeat that for every subnet on my network (128.119.0.1 - 128.119.255.254). Given my current setup, what would be the best course of action to make this change? I was thinking of doing something like a list of Queues (where each Queue holds 255 IP addresses for one of the subnets) and having one thread process each queue (unless there is a limitation on how many threads I can spawn in Python on Windows).

EDIT: I have played around with nmap (and Angry IP scanner) for this task, but I was interested in pursuing writing my own script.

+1  A: 

Simplest thing would be to have a thread work through a whole subnet and exit when it finds a host.

UNTESTED

from Queue import Queue
import time
import socket

#wraps system ping command
def ping(i, q):
    """Pings address"""
    while True:
        subnet = q.get()
        # each IP addresse in subnet 
        for ip in (subnet=str(x) for x in range(1,254)):
            #print "Thread %s: Pinging %s" % (i, ip)
            result = subprocess.call("ping -n 1 %s" % ip, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
            #Avoid flooding the network with ping requests
            time.sleep(3)
            if result == 0:

                try:
                    hostname=socket.gethostbyaddr(ip)
                    print "%s (%s): alive" % (ip,hostname[0]  
                except:
                    print "%s: alive"%ip
                break
        q.task_done()

num_threads = 100
queue = Queue()

#Put all possible subnets on wireless network into a queue
for i in range(1,255):
    queue.put('128.119.%s.'%i)

#Spawn thread pool
for i in range(num_threads):
    worker = Thread(target=ping, args=(i, queue))
    worker.setDaemon(True)
    worker.start()

#Wait until worker threads are done to exit    
queue.join()
gnibbler
A: 

Since you know how many threads you got in the beginning of the run, you could periodically check the current number of threads running to see if nowThreadCount < startThreadCount. If it's true terminate the current thread.

PS: Easiest way would be to just clear the queue object too, but I can't find that in the docs.

EightyEight