I am attempting to create a subnet scanner in python. The first part of the code takes input from a user and finds the subnet based on the input. The second part takes the subnet and goes through all 255 hosts.
The problem is, the code freezes when it tries to scan a host that is down.
main.py
import os
import socket
def spread():
ip_list = []
lst = []
new_ip = []
ip = input("Enter any ip on your network: ")
for ch in range(0, len(ip)):
new_ip = ip[ch]
if ip[ch] == ".":
print(ip[ch])
lst.append(ch)
t = True
while t == True:
try:
new_ip.pop(lst[2] 1)
except:
t = False
print(new_ip)
break
else:
pass
target = ""
for char in new_ip:
target = char
print(target)
#print(f"{ip} == {new_ip}")
for i in range(1,255):
print("socket initialized")
from portscanner import scanner as scan
for port in range(1,1025):
try:
scan(target str(i))
#HERE IS WHERE THE CODE FREEZES
except:
continue
else:
pass
portscanner.py
def scanner(ip):
for port in range(2, 1025):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.setdefaulttimeout(0.002)
# returns an error indicator
try:
result = s.connect_ex((ip, port))
#More specifically, here is where the code freezes
except:
continue
else:
pass
if result == 0:
print("Port {} is open".format(port))
else:
print("Port {} is CLOSED on ".format(port) ip)
continue
#print(port)
s.close()
My theory is that the code freezes because the host I am trying to connect to is down. How can I work around this and/or check to see if a host is up?
CodePudding user response:
First of all, no one would answer you in 2 ms (0.002 seconds). The correct way would be to use asyncio / multithreading / nonblocking select, and spread over the ports concurrently while waiting a little longer.
Second of all, as scanner
doesn't receive a port number, for every port between 1 and 1024 you scan every port between 2 and 1024. See the issue here?
Third of all, you set the default timeout for all sockets in every port scan. Why?
Fourth of all, you can use ipaddress.ip_address
to find a network or at least use str.rindex
to find the last byte and strip it off instead of the for
and while
loops.
Last of all, except: continue
means you just ignore all exceptions, some of them might be relevant. I'd suggest printing such errors so you will be able to further debug the problem, or at least change the result to -1 so it'll show it's closed. It also prevents you from using ctrl c
to stop the program.
I've refactored your code a little, and it works:
from ipaddress import ip_network
import socket
def main():
socket.setdefaulttimeout(0.4)
network = ip_network(input("Enter an IPv4 network: "))
for ip in network.hosts():
scan_ip(ip)
def scan_ip(ip):
for port in range(1, 1025):
with socket.socket() as s:
try:
result = s.connect_ex((str(ip), port))
except Exception as e:
print(f"Error on {ip=!s}, {port=}: {e}")
else:
if result == 0:
print(f"Port {port} is open on {ip}")
else:
print(f"Port {port} is CLOSED on {ip}")
Usage:
>>> main()
Enter an IPv4 network: 1.2.3.0/24
...
I leave the multithreading/asyncio for you to implement.
CodePudding user response:
This fix was extremely simple. All I had to do was set the timeout of the socket. What this does is it waits a certain amount of seconds for a response. If that response is not received, the socket closes.
ip = 192.168.1.1
port = 80
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Waits for 5 seconds
s.settimeout(5)
# Waits for 10 seconds
s.settimeout(10)
try:
s.connect(ip)
#If it freezes here for more than 10 seconds,
except Exception as e:
print(e)
else:
print(f"{ip}:{port} is open!")
s.close()