LAN IP Scanner
LAN IP Scanner
This Python script scans a local network for active IP addresses. It uses the ping
command to check if a host is reachable and employs multithreading to speed up the scanning process. A semaphore limits the number of concurrent threads to avoid overwhelming the system. The script takes a network address (e.g., “192.168.1.0/24”) as input and prints whether each IP address in the network is up or down.
This script helps identify devices on the network, such as a TP-LINK mesh router operating in wired bridge mode, by scanning for active IP addresses.
import subprocess
import ipaddress
import threading
import os
import socket
import argparse
MAX_THREADS = 50 # Maximum number of threads to use
def is_host_up(host, port=None):
"""
Checks if a host is up using ping or telnet.
If port is specified, uses telnet to check if the port is open.
Otherwise, uses ping.
Returns True if the host is up, False otherwise.
"""
if port:
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(1)
result = sock.connect_ex((host, port))
if result == 0:
return True
else:
return False
except socket.error as e:
return False
finally:
sock.close()
else:
try:
# -c 1: Send only 1 packet
# -W 1: Wait 1 second for a response
subprocess.check_output(["ping", "-c", "1", "-W", "1", host], timeout=1)
return True
except subprocess.CalledProcessError:
return False
except subprocess.TimeoutExpired:
return False
def scan_ip(ip_str, up_ips, port=None):
"""
Scans a single IP address and prints its status.
"""
if is_host_up(ip_str, port):
print(f"{ip_str} is up")
up_ips.append(ip_str)
else:
print(f"{ip_str} is down")
def scan_network(network, port=None):
"""
Scans a network for live hosts using threads, limiting the number of concurrent threads.
"""
print(f"Scanning network: {network}")
threads = []
semaphore = threading.Semaphore(MAX_THREADS) # Limit the number of concurrent threads
up_ips = []
def scan_ip_with_semaphore(ip_str):
semaphore.acquire()
try:
scan_ip(ip_str, up_ips, port)
finally:
semaphore.release()
for ip in ipaddress.IPv4Network(network):
ip_str = str(ip)
thread = threading.Thread(target=scan_ip_with_semaphore, args=(ip_str,))
threads.append(thread)
thread.start()
for thread in threads:
thread.join()
return up_ips
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Scan a network for live hosts.")
parser.add_argument("network", nargs='?', default="192.168.1.0/24", help="The network to scan (e.g., 192.168.1.0/24)")
parser.add_argument("-p", "--port", type=int, help="The port to check (optional)")
args = parser.parse_args()
network_to_scan = args.network
port_to_scan = args.port
up_ips = scan_network(network_to_scan, port_to_scan)
print("\nLive IPs:")
for ip in up_ips:
print(ip)
Bypassing Local IPs
The script identifies active IP addresses. To ensure proper network communication, verify that proxy settings are configured to bypass these local IPs.
192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,127.0.0.1,localhost,*.local,timestamp.apple.com,sequoia.apple.com,seed-sequoia.siri.apple.com, 192.168.1.0/16
Subnet Masks
My second machine is usually at 192.168.1.16.
So it works using the command below.
python scripts/ip_scan.py 192.168.1.0/27 -p 22
because 32 - 27 = 5, 2^5 = 32, so it will try 192.168.1.0
to 192.168.1.31
.
But it doesn’t work when using 192.168.1.0/28
, because 2^4 = 16, so it will try 192.168.1.0
to 192.168.1.15
, which doesn’t cover 192.168.1.16
.