Python网络扫描器检测活跃主机时返回空列表的问题求助
我最近在做一个网络扫描器项目,遇到了个头疼的问题:我写了两个脚本,target_network_input.py负责让用户输入目标网段,输出可用主机列表和总地址数;active_networks.py接收这个主机列表,通过ICMP、TCP、UDP、ARP四种方式探测活跃主机,最后把活跃的主机收集起来输出。但不管怎么测试,结果总是返回空列表,完全达不到预期效果,有没有大佬能帮我看看哪里出问题了?
我的代码如下:
target_network_input.py
#!/usr/local/bin/python3 import ipaddress def process_network(): n = input('Enter the target network range (e.g., 192.168.1.0/24): ') try: net = ipaddress.IPv4Network(n, strict = False) net_list = list(net.hosts()) net_num = net.num_addresses print(f'Usable hosts: {net_list}\n') print(f'Total number of addresses (including network and broadcast): {net_num}') return net_list except ValueError: print('Invalid IP network range') if __name__ == '__main__': #Standalone execution logic(if needed) print('This script is used to process network ranges') process_network()
active_networks.py
#!/usr/local/bin/python3 from scapy.all import IP, ICMP, TCP, UDP, ARP, sr1, srp, Ether import target_network_input import logging logging.basicConfig(level = logging.DEBUG) net_list = target_network_input.process_network() #Main function to find active hosts def active_hosts(net_list): live_hosts = [] for ip in net_list: if icmp_ping(ip): live_hosts.append(ip) elif tcp_ping(ip): live_hosts.append(ip) elif udp_ping(ip): live_hosts.append(ip) elif arp_ping(ip): live_hosts.append(ip) else: continue print(live_hosts) return live_hosts #Identify networks through ICMP requests def icmp_ping(ip): try: packet = IP(dst = ip) / ICMP() response = sr1(packet, timeout = 1, verbose = 0) return response is not None except Exception as e: return False #Identify networks through TCP requests def tcp_ping(ip, port = 80): try: packet = IP(dst = ip) / TCP(dport = port, flags = 'S') response = sr1(packet, timeout = 1, verbose = 0) return response and response.haslayer(TCP) and response[TCP].flags == 'SA' except Exception as e: return False #Identify networks through UDP requests def udp_ping(ip, port = 53): try: packet = IP(dst = ip) / UDP(dport = port) response = sr1(packet, timeout = 1, verbose = 0) return response is not None except Exception as e: return False #Identify networks through ARP requests def arp_ping(ip): try: arp_request = ARP(pdst = ip) broadcast = Ether(dst = 'ff:ff:ff:ff:ff:ff') packet = broadcast / arp_request response = srp(packet, timeout = 1, verbose = 0)[0] return len(response) > 0 except Exception as e: return False active_hosts(net_list)
我本来的预期是:程序接收用户输入的网段,显示范围内的所有可用主机,然后逐个探测每个主机是否活跃,把活跃的主机添加到列表里最后输出,但现在每次运行都只返回[],完全找不到活跃主机。
可能的问题排查与解决建议
结合开发经验,给你列几个最可能的原因和对应的解决方法:
权限不足:Scapy发送ICMP、ARP这类数据包通常需要管理员/root权限,如果用普通用户运行脚本,很多探测会直接失败返回False。解决方法:Linux/macOS下用
sudo python3 active_networks.py运行,Windows右键以管理员身份打开命令提示符再执行脚本。IP对象格式不兼容:
ipaddress.IPv4Network.hosts()返回的是IPv4Address对象,而Scapy的IP(dst=ip)需要字符串格式的IP地址,直接传对象可能导致数据包发送失败。解决方法:在每个探测函数里把IP转成字符串,比如把ICMP ping里的packet = IP(dst = ip) / ICMP()改成packet = IP(dst = str(ip)) / ICMP(),其他三个探测函数同理修改。端口选择太局限:默认用TCP 80端口和UDP 53端口,但目标主机可能这些端口没开放,导致TCP/UDP探测失败。解决方法:要么换常用开放端口(比如TCP 22、443),要么改成多端口尝试,比如修改
tcp_ping函数:def tcp_ping(ip, ports=[22, 80, 443]): for port in ports: try: packet = IP(dst=str(ip)) / TCP(dport=port, flags='S') response = sr1(packet, timeout=2, verbose=0) if response and response.haslayer(TCP) and response[TCP].flags == 'SA': return True except Exception as e: print(f"TCP探测端口{port}时出错: {e}") return FalseARP探测的局限性:ARP协议只能在同一局域网内生效,如果目标网段不在本地局域网,ARP探测肯定会失败。解决方法:给
arp_ping函数加个判断,只有当目标IP在本地网段时才用ARP探测,否则直接跳过:def arp_ping(ip): # 先获取本地IP和网段 import socket def get_local_ip(): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: s.connect(('10.255.255.255', 1)) local_ip = s.getsockname()[0] except Exception: local_ip = '127.0.0.1' finally: s.close() return local_ip local_net = ipaddress.IPv4Network(f"{get_local_ip()}/24", strict=False) target_ip_obj = ipaddress.IPv4Address(str(ip)) if target_ip_obj not in local_net: return False # 非本地网段,ARP无效 try: arp_request = ARP(pdst=str(ip)) broadcast = Ether(dst='ff:ff:ff:ff:ff:ff') packet = broadcast / arp_request response = srp(packet, timeout=2, verbose=0)[0] return len(response) > 0 except Exception as e: print(f"ARP探测出错: {e}") return False超时时间太短:1秒的超时在网络延迟高的环境下可能不够,导致数据包还没收到响应就超时了。解决方法:把各个探测函数的
timeout改成2或3秒。异常捕获太隐蔽:每个探测函数都用
except Exception as e:捕获所有异常且直接返回False,看不到具体错误信息很难排查。解决方法:暂时去掉异常捕获,或者在异常里打印错误信息,比如:except Exception as e: print(f"ICMP探测{ip}时出错: {e}") return False
另外,可以在active_hosts函数里加一些打印日志,看看每个IP的探测情况,方便定位问题:
def active_hosts(net_list): live_hosts = [] for ip in net_list: print(f"正在探测主机: {ip}") if icmp_ping(ip): print(f"✅ {ip} 通过ICMP探测确认活跃") live_hosts.append(ip) elif tcp_ping(ip): print(f"✅ {ip} 通过TCP探测确认活跃") live_hosts.append(ip) elif udp_ping(ip): print(f"✅ {ip} 通过UDP探测确认活跃") live_hosts.append(ip) elif arp_ping(ip): print(f"✅ {ip} 通过ARP探测确认活跃") live_hosts.append(ip) else: print(f"❌ {ip} 未探测到活跃") continue print(f"\n最终活跃主机列表: {live_hosts}") return live_hosts
建议先从权限问题和IP格式转换这两个最基础的点入手排查,这两个是导致空列表最常见的原因,应该能解决大部分问题。
备注:内容来源于stack exchange,提问作者prince singh

