写了一个程序,通过 ping 命令来查询地址段内的主机是否活动。
支持输入地址段格式(如 10.1.1.1-10.1.1.100)或 CIDR格式(如 10.1.1.0/28)。
CLI 版本
import subprocess
import ipaddress
import time
import platform
from typing import Optional, Callable, List, Tuple
def ping_host(ip: str, callback: Optional[Callable[[str], None]] = None) -> bool:
"""Ping a single host and return True if responsive."""
ping_cmd = ["ping", "-n", "1", ip] if platform.system() == "Windows" else ["ping", "-c", "1", ip]
try:
process = subprocess.Popen(
ping_cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
stdout, stderr = process.communicate(timeout=1)
return process.returncode == 0
except subprocess.TimeoutExpired:
output = f" Timeout pinging {ip}"
if callback:
callback(output)
else:
print(output)
return False
except Exception as e:
output = f" Error pinging {ip}: {e}"
if callback:
callback(output)
else:
print(output)
return False
def scan_ip_range(
start_ip: str,
end_ip: str,
callback: Optional[Callable[[str], None]] = None
) -> Tuple[List[str], bool]:
"""Scan a range of IP addresses and return live hosts and success status."""
live_hosts = []
try:
start = ipaddress.ip_address(start_ip)
end = ipaddress.ip_address(end_ip)
current_ip = start
while current_ip <= end:
ip_str = str(current_ip)
output = f"\nPinging {ip_str}..."
if callback:
callback(output)
else:
print(output, end="")
if ping_host(ip_str, callback):
live_hosts.append(ip_str)
output = " Live!"
if callback:
callback(output)
else:
print(output, end="")
current_ip += 1
time.sleep(0.1)
return live_hosts, True
except ValueError as e:
output = f"Invalid IP address: {e}\n"
if callback:
callback(output)
else:
print(output)
return [], False
def scan_cidr_network(
network: str,
callback: Optional[Callable[[str], None]] = None
) -> Tuple[List[str], bool]:
"""Scan a network in CIDR notation and return live hosts and success status."""
live_hosts = []
try:
net = ipaddress.ip_network(network, strict=False)
for ip in net.hosts():
ip_str = str(ip)
output = f"\nPinging {ip_str}..."
if callback:
callback(output)
else:
print(output, end="")
if ping_host(ip_str, callback):
live_hosts.append(ip_str)
output = " Live!"
if callback:
callback(output)
else:
print(output, end="")
time.sleep(0.1)
return live_hosts, True
except ValueError as e:
output = f"Invalid network address: {e}"
if callback:
callback(output)
else:
print(output)
return [], False
def parse_input(input_str: str) -> Tuple[str, Optional[str], Optional[str]]:
"""Parse input string and determine input type (range, cidr, or invalid)."""
input_str = input_str.strip()
if "-" in input_str:
try:
start_ip, end_ip = input_str.split("-")
ipaddress.ip_address(start_ip.strip())
ipaddress.ip_address(end_ip.strip())
return "range", start_ip.strip(), end_ip.strip()
except ValueError:
return "invalid", None, None
elif "/" in input_str:
try:
ipaddress.ip_network(input_str)
return "cidr", input_str, None
except ValueError:
return "invalid", None, None
return "invalid", None, None
def generate_report(live_hosts: List[str]) -> str:
"""Generate and save a report of live hosts."""
report = "\nLive Hosts:\n" + "\n".join(live_hosts)
with open("scan_report.txt", "w") as f:
f.write(report)
return "\nReport saved to scan_report.txt"
def main():
"""Main function to run the scanner."""
input_str = input(
"Enter IP range (e.g., 10.1.1.1-10.1.1.100) or CIDR (e.g., 10.1.1.0/28): "
)
input_type, value1, value2 = parse_input(input_str)
if input_type == "range":
live_hosts, success = scan_ip_range(value1, value2)
elif input_type == "cidr":
live_hosts, success = scan_cidr_network(value1)
else:
print("Invalid input format.")
live_hosts = []
success = False
if success:
if live_hosts:
print("\n\nLive Hosts Found:")
for host in live_hosts:
print(host)
else:
print("\nNo live hosts found.")
report = generate_report(live_hosts)
print(report)
if __name__ == "__main__":
main()
GUI 版本
import tkinter as tk
import tkinter.scrolledtext as st
from ping_scanner import parse_input, scan_ip_range, scan_cidr_network, generate_report
class PingScannerGUI:
def __init__(self, master):
self.master = master
master.title("Ping Scanner")
self.label = tk.Label(
master,
text="Enter the IP address range (e.g., 10.1.1.1-10.1.1.100)\n or CIDR notation (e.g., 10.1.1.0/28)",
)
self.label.pack()
self.entry = tk.Entry(master, width=50)
self.entry.pack()
self.scan_button = tk.Button(
master,
text="Scan",
command=self.scan,
activebackground="lightgray",
activeforeground="gray",
)
self.scan_button.pack()
self.result_area = st.ScrolledText(master, width=50, height=20)
self.result_area.pack()
self.result_area.config(state=tk.DISABLED)
def update_results(self, text):
self.result_area.config(state=tk.NORMAL)
self.result_area.insert(tk.END, text)
self.result_area.config(state=tk.DISABLED)
self.result_area.see(tk.END) # Scroll to the end
def scan(self):
self.scan_button.config(
state=tk.DISABLED
) # Disable the button and change color
self.result_area.config(state=tk.NORMAL)
self.result_area.delete(1.0, tk.END) # Clear previous results
self.result_area.config(state=tk.DISABLED)
input_str = self.entry.get()
input_type, value1, value2 = parse_input(input_str)
if input_type == "range":
live_hosts, success = scan_ip_range(value1, value2, callback=self.update_results)
elif input_type == "cidr":
live_hosts, success = scan_cidr_network(value1, callback=self.update_results)
else:
self.update_results("Invalid input format.\n")
self.scan_button.config(state=tk.NORMAL)
return
if success and live_hosts:
self.update_results("\n\nLive Hosts:\n")
for host in live_hosts:
self.update_results(host + "\n")
elif success:
self.update_results("No live hosts found in the specified range.\n")
else:
self.update_results("Error occurred during scanning.\n")
report = generate_report(live_hosts) # Still generate report
self.update_results(report)
self.scan_button.config(state=tk.NORMAL) # Re-enable the button
root = tk.Tk()
gui = PingScannerGUI(root)
root.mainloop()
