masscan

A tool for when you absolutely, positively, must scan everything.

Basic scan of all TCP/UDP ports in a text file (saving to greppable format)

masscan -p1-65535,U:1-65535 --rate=1000 -iL subnets.txt -oG open-ports-report

Checking what ports "poked through"

Masscan's -oG isn't nmap grepable format — every line leads with Timestamp:, so the IP is field 4 and the port spec is field 7. Adjust your awk accordingly.

F=open-ports-report

# Did the scan actually finish? Look for the "# Masscan done at ..." footer.
tail -1 "$F"

# Total hits, and which hosts answered on anything
grep -c 'Host:' "$F"
grep 'Host:' "$F" | awk '{print $4}' | sort -uV | tee live-hosts.txt | wc -l

# Port frequency — the "what got through" summary
grep 'Host:' "$F" | awk '{split($7,a,"/"); print a[1]"/"a[3]}' \
  | sort | uniq -c | sort -rn

# Host → port list
grep 'Host:' "$F" | awk '{split($7,a,"/"); print $4, a[1]"/"a[3]}' \
  | sort -V -k1,1 -k2,2n \
  | awk '{if($1!=h){if(h)print h": "p; h=$1; p=$2}else p=p", "$2} END{print h": "p}'

# Which subnets were reachable at all
grep 'Host:' "$F" | awk '{split($4,o,"."); print o[1]"."o[2]"."o[3]".0/24"}' | sort -uV

Quick validation pass

Masscan is stateless, so treat every hit as a lead rather than a finding. Feed the discovered ports back into nmap for service detection and a second opinion:

ports=$(grep 'Host:' "$F" | awk '{split($7,a,"/"); if(a[3]=="tcp") print a[1]}' \
  | sort -un | paste -sd,)
nmap -Pn -n -sV -p "$ports" -iL live-hosts.txt --open -oA verify

Anything masscan found that nmap can't reproduce is almost certainly an artifact of scanning at rate — drop it.

Two things that will bite you

Gateway addresses. Hits on .1 addresses are usually the router's own management plane, not a host inside the target segment. A router answers on any of its interface IPs regardless of which interface the packet arrived on, so reaching 10.0.20.1 from a different VLAN doesn't mean your traffic entered that segment. Check the TTL — replies at 255 (undecremented) mean the device is one hop away and is likely your own gateway wearing a different address:

ping -c2 10.0.20.1 | grep ttl
traceroute -n -m5 10.0.20.1

Another tell: traceroute prints the first hop and then stops without ever naming the destination. That means the device replied but sourced the reply from a different interface — same box, different address.

That's still a real finding (management service exposed across segments), just a different one than "segmentation failed."

An empty result isn't proof of blocking. Masscan does no host discovery, so "no response" conflates host down, port filtered, and packet lost. Separate them before writing a negative finding:

nmap -sn -n -PE -PS443,80,22 -PA3389 -iL subnets.txt -oA alive
ping -c2 -W2 10.0.20.99    # pick an unused IP in the target subnet
                           # host-unreachable = sparse subnet
                           # silence        = actually filtered

Best practice: get the client to name one known-live host per target segment and scan it alongside the real targets. Its presence in the output proves the scan path was working, which is what turns "nothing answered" into a defensible result.

UDP caveat

The -oG header shows UDP as UDP(65535;65537-131071) — that's masscan's internal numbering (UDP offset by 65536), so U:1-65535 did what you wanted. But masscan only sends real protocol payloads for a handful of UDP ports (53, 123, 137, 161, 500, 1900, 5353, and a few others); everything else gets an empty datagram most services ignore. A blank UDP result is weak evidence. If UDP matters, follow up:

nmap -Pn -n -sU --top-ports 50 --open -iL live-hosts.txt -oA udp50