| 775 | |
| 776 | |
| 777 | def scan_services(host_ips, ports, timing="T4", verbose=False, max_hostgroup=None): |
| 778 | import nmap |
| 779 | |
| 780 | if not host_ips: |
| 781 | return {} |
| 782 | |
| 783 | nm = nmap.PortScanner() |
| 784 | port_str = ",".join(str(port) for port in sorted(set(ports))) |
| 785 | targets = " ".join(host_ips) |
| 786 | args = f"-sT -sV --version-light --open -Pn -n -{timing} -p {port_str}" |
| 787 | if verbose: |
| 788 | args += " -v" |
| 789 | if max_hostgroup: |
| 790 | args += f" --max-hostgroup {max_hostgroup}" |
| 791 | args += " --host-timeout 15s" |
| 792 | |
| 793 | nm.scan(hosts=targets, arguments=args) |
| 794 | data = {} |
| 795 | for host in nm.all_hosts(): |
| 796 | host_data = {"ports": [], "service_info": ""} |
| 797 | service_parts = [] |
| 798 | if "addresses" in nm[host] and nm[host]["addresses"].get("mac"): |
| 799 | host_data["mac"] = nm[host]["addresses"].get("mac", "") |
| 800 | if "vendor" in nm[host] and host_data.get("mac"): |
| 801 | vendor_map = nm[host].get("vendor", {}) |
| 802 | host_data["vendor"] = vendor_map.get(host_data["mac"], "") |
| 803 | tcp = nm[host].get("tcp", {}) |
| 804 | for port, port_data in sorted(tcp.items()): |
| 805 | if port_data.get("state") != "open": |
| 806 | continue |
| 807 | host_data["ports"].append(port) |
| 808 | pieces = [ |
| 809 | port_data.get("name", ""), |
| 810 | port_data.get("product", ""), |
| 811 | port_data.get("version", ""), |
| 812 | port_data.get("extrainfo", ""), |
| 813 | ] |
| 814 | script_map = port_data.get("script", {}) or {} |
| 815 | for script_name, script_output in script_map.items(): |
| 816 | pieces.append(f"{script_name}: {script_output}") |
| 817 | joined = " ".join(piece for piece in pieces if piece).strip() |
| 818 | if joined: |
| 819 | service_parts.append(f"port {port}: {joined}") |
| 820 | host_data["service_info"] = " | ".join(service_parts) |
| 821 | data[host] = host_data |
| 822 | return data |
| 823 | |
| 824 | |
| 825 | # ───────────────────────────────────────────── |