Might be useful if you’re doing this on windows
import socket
import subprocess
from Queue import Queue
from threading import Thread
"""
module lan
this namespace is for utility functions deailing with simple questions about the
local network. It's not for serious networking code - just for inspecting the
LAN (eg, looking to see what other machines are around
"""
def _ip_format(item):
"""
Convert an ip string into a tuple (N.N.N.N)
"""
return tuple(map(int, item.split(".")))
def _ip_to_str(ip):
"""
Converts an ip tuple (N.N.N.N) to a string
"""
if hasattr(ip, '__iter__'):
return (".".join(map(str, ip)))
else:
return ip
def ip_info():
"""
Returns a dictionary with the hostname, ip address, and subnet mask of the local machine
Note this uses the windows ipconfig command, and it will return the first
set of info it finds -- if there are multiple adapters it will return the
first one it sees
If the command can't be parsed, raises a RuntimeError
"""
po = subprocess.Popen("ipconfig", stdout=subprocess.PIPE)
subnet, ip, gateway = None, None, None
retcode = po.communicate()
for eachLine in retcode[0].splitlines():
if eachLine:
if eachLine.count("Subnet Mask"):
subnet = _ip_format(eachLine.partition(":")[-1].strip())
if eachLine.count('IPv4 Address'):
ip = _ip_format(eachLine.partition(":")[-1].strip())
if eachLine.count('Default Gateway'):
gateway = _ip_format(eachLine.partition(":")[-1].strip())
if subnet and ip and gateway:
return {
"subnet": subnet,
"ip": ip,
"gateway": gateway
}
raise RuntimeError, "unable to determine IP info"
def ping(ip):
"""
Pings the supplied ip ( a string or a tuple). Returns -1 if the hose cannot be found and 1 if it can.
@todo: parse out the actual ping time
"""
po = subprocess.Popen("ping -n 1 " + _ip_to_str(ip), stdout=subprocess.PIPE)
result = po.communicate()[0]
if result.count("unreachable"):
return -1
else:
return 1
def scan_local_network(threads=4):
"""
Scans the local network and returns a list of all visible machines. This
process takes several seconds of real time. User can supply an number of
threads to use in the scan, which speeds up the query ( default nubmer of
threads is 4)
The entries in the result are in the same format as socket.gethostbyaddr
"""
ip_queue = Queue()
results = []
subnet = ip_info()['ip']
for suffix in range(0, 255):
newIp = subnet[0], subnet[1], subnet[2], suffix
ip_queue.put(newIp)
# inner proc
def _test_ip(in_q, out_q):
while in_q.not_empty:
ip = _ip_to_str(in_q.get())
p = ping(ip)
if p > -1:
try:
machine = socket.gethostbyaddr(_ip_to_str(ip))
out_q.append(machine)
except:
pass
in_q.task_done()
# spin up as many threads as requested. Numbers > 4 don't help too much
for i in range(threads):
worker = Thread(target=_test_ip, args=(ip_queue, results))
worker.setDaemon(True)
worker.start()
# block until scan is complete
ip_queue.join()
return results
__all__ = ['ping', 'scan_local_network', 'ip_info']