-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathanalyze-ip
More file actions
executable file
·121 lines (103 loc) · 4.31 KB
/
analyze-ip
File metadata and controls
executable file
·121 lines (103 loc) · 4.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#!/usr/bin/env python3
import argparse
import ipaddress
import json
import subprocess
import sys
import requests
import xml.etree.ElementTree as ET
def run_nmap_scan(ip_str: str) -> dict:
scan_results = {}
command = ["sudo", "nmap", "-sV", "-O", "-oX", "-", ip_str]
try:
nmap_xml_output = subprocess.run(
command, capture_output=True, text=True, check=True, timeout=300
).stdout
root = ET.fromstring(nmap_xml_output)
host = root.find("host")
if host is not None:
status = host.find("status")
scan_results["status"] = {
"state": status.get("state"),
"reason": status.get("reason"),
}
ports = []
port_elements = host.find("ports")
if port_elements is not None:
for port_elem in port_elements.findall("port"):
state_elem = port_elem.find("state")
service_elem = port_elem.find("service")
port_info = {
"port_id": int(port_elem.get("portid")),
"protocol": port_elem.get("protocol"),
"state": state_elem.get("state"),
"reason": state_elem.get("reason"),
"service": (
{
"name": service_elem.get("name"),
"product": service_elem.get("product"),
"version": service_elem.get("version"),
"extrainfo": service_elem.get("extrainfo"),
"method": service_elem.get("method"),
"conf": (
int(service_elem.get("conf"))
if service_elem.get("conf")
else None
),
}
if service_elem is not None
else {}
),
}
ports.append(port_info)
scan_results["ports"] = ports
os_elem = host.find("os")
if os_elem is not None and os_elem.find("osmatch") is not None:
os_match = os_elem.find("osmatch")
scan_results["os"] = {
"name": os_match.get("name"),
"accuracy": int(os_match.get("accuracy")),
}
else:
scan_results["error"] = "Could not find host information in Nmap output."
except FileNotFoundError:
return {
"error": "Nmap command not found. Please install nmap and ensure it's in your PATH."
}
except subprocess.CalledProcessError as e:
# This catches errors from the nmap command itself, like an invalid IP.
return {"error": f"Nmap scan failed: {e.stderr}"}
except subprocess.TimeoutExpired:
return {"error": "Nmap scan timed out after 5 minutes."}
except ET.ParseError:
return {"error": "Failed to parse Nmap XML output."}
except Exception as e:
return {"error": f"An unexpected error occurred during the Nmap scan: {e}"}
return scan_results
def analyze(ip_str: str) -> dict:
analysis_results = {"valid": False, "analysis": {}}
try:
ip_obj = ipaddress.ip_address(ip_str)
analysis_results["valid"] = True
except ValueError:
return analysis_results
analysis_results["analysis"]["private_ip"] = ip_obj.is_private
analysis_results["analysis"]["local_ip"] = ip_obj.is_loopback
analysis_results["analysis"]["multicast_ip"] = ip_obj.is_multicast
analysis_results["analysis"]["global_ip"] = ip_obj.is_global
analysis_results["analysis"]["scan_results"] = {"nmap": run_nmap_scan(ip_str)}
return analysis_results
def main():
"""
Main function to parse command-line arguments and run the analysis.
"""
parser = argparse.ArgumentParser(
description="Analyze an IP address using Nmap.",
epilog="Example: analyze-ip 8.8.8.8",
)
parser.add_argument("ip", help="The IP address to analyze.")
args = parser.parse_args()
results = analyze(args.ip)
print(json.dumps(results, indent=4))
if __name__ == "__main__":
main()