Skip to content

Port Scan Detection Coverage

NRGLine4Sec edited this page Oct 17, 2026 · 1 revision

Port scan detection: coverage

Back to Port Scan Detection.

Generated by daemon/portscan/testdata/coverage. Do not edit by hand: the table below is produced by replaying the capture corpus through the detection engine, so it says what the code does rather than what it is meant to do.

Status codes

Code Meaning
D_FULL Reliably visible to this sensor.
D_PARTIAL Visible, with a documented blind spot.
D_INDIRECT The scan itself is not visible; only a side effect is.
U_UNREACHABLE Structurally invisible from the target host. The reason is stated.
U_OUT_OF_SCOPE Detectable in principle, deliberately not covered. The reason is stated.

Scan is whether the activity can be seen. Attribution is whether the address in the packets can be believed to be its origin's. The two differ for every indirection technique, and that difference is why blocking is gated by policy rather than automatic.

Techniques

Technique Option Scan Attribution Exercised by Observed
TCP SYN scan -sS D_FULL D_FULL tcp-syn.pcap tcp-syn, 9 ports, score 108
TCP connect scan -sT D_FULL D_FULL tcp-connect.pcap tcp-syn, 9 ports, score 108
TCP FIN scan -sF D_FULL D_FULL tcp-fin.pcap tcp-fin, 7 ports, score 112
TCP NULL scan -sN D_FULL D_FULL tcp-null.pcap tcp-null, 7 ports, score 112
TCP Xmas scan -sX D_FULL D_FULL tcp-xmas.pcap tcp-xmas, 7 ports, score 112
TCP Maimon scan -sM D_PARTIAL D_FULL tcp-maimon.pcap tcp-maimon, 25 ports, score 100
TCP ACK scan -sA D_PARTIAL D_FULL tcp-ack.pcap tcp-ack, 25 ports, score 100
TCP window scan -sW U_UNREACHABLE D_FULL tcp-window.pcap tcp-ack, 25 ports, score 100
Custom flag combinations --scanflags D_FULL D_FULL tcp-custom-flags.pcap tcp-custom-flags, 7 ports, score 112
SYN|FIN scan --scanflags SYNFIN D_FULL D_FULL tcp-synfin.pcap tcp-syn-fin, 7 ports, score 112
UDP scan -sU D_PARTIAL U_UNREACHABLE udp.pcap udp, 25 ports, score 100
IP protocol scan -sO D_FULL D_FULL ip-protocol.pcap protocol scan, 260 probes
Decoy scan -D D_FULL U_UNREACHABLE tcp-syn-decoy.pcap tcp-syn, 9 ports, score 108
OS fingerprinting -O D_FULL D_FULL tcp-os-fingerprint.pcap tcp-syn, 9 ports, score 108
Fragmented probes -f / --mtu D_PARTIAL D_FULL tcp-syn-fragmented.pcap tcp-fragmented, 9 ports, score 108
Slow scan -T0 / -T1 D_PARTIAL D_FULL tcp-syn-slow.pcap tcp-syn, 10 ports, score 107
Idle (zombie) scan -sI D_FULL U_UNREACHABLE - not exercised here
FTP bounce scan -b D_FULL U_UNREACHABLE - not exercised here
Spoofed source -S D_FULL U_UNREACHABLE - not exercised here
SCTP INIT / COOKIE ECHO scan -sY / -sZ U_OUT_OF_SCOPE D_FULL - not exercised here
Horizontal scan of the network - U_UNREACHABLE U_UNREACHABLE - not exercised here
Single-port brute force - U_OUT_OF_SCOPE D_FULL benign-single-port.pcap not reported (2 probes)
IPv6 port scan -6 D_FULL D_FULL tcp-syn-v6.pcap tcp-syn, 9 ports, score 108
IPv6 FIN scan -6 -sF D_FULL D_FULL tcp-fin-v6.pcap tcp-fin, 7 ports, score 112
IPv6 Xmas scan -6 -sX D_FULL D_FULL tcp-xmas-v6.pcap tcp-xmas, 7 ports, score 112
IPv6 UDP scan -6 -sU D_PARTIAL U_UNREACHABLE udp-v6.pcap udp, 25 ports, score 100
Extension-header evasion Topera D_FULL D_FULL - not exercised here
Out-of-band enumeration DNS / rDNS / certificate logs U_UNREACHABLE U_UNREACHABLE - not exercised here

Why, in each case

TCP SYN scan (-sS): scan D_FULL, attribution D_FULL. a bare SYN to a port where nothing listens is the nominal case.

TCP connect scan (-sT): scan D_FULL, attribution D_FULL. connect(2) puts the same bare SYN on the wire; the difference is in the scanner, not in the packets.

TCP FIN scan (-sF): scan D_FULL, attribution D_FULL. a FIN outside an established connection cannot be legitimate.

TCP NULL scan (-sN): scan D_FULL, attribution D_FULL. no control bits at all is not something a stack emits.

TCP Xmas scan (-sX): scan D_FULL, attribution D_FULL. FIN, PSH and URG together cannot open or continue a connection.

TCP Maimon scan (-sM): scan D_PARTIAL, attribution D_FULL. FIN|ACK carries ACK, the shape of a connection's teardown, so it is treated as an ACK scan is: counted at the lowest weight, not counted in the ephemeral range, and not enough on its own to block.

TCP ACK scan (-sA): scan D_PARTIAL, attribution D_FULL. a lone ACK is also what a straggler from a just-closed socket looks like, so it is counted at the lowest weight; the connection table removes most of the ambiguity, which a network sensor cannot do at all.

TCP window scan (-sW): scan U_UNREACHABLE, attribution D_FULL. byte-identical to -sA on the wire: the two differ only in how the scanner reads the window field of the reply. Reporting anything more specific would be a fabrication, so it is reported as an ACK scan.

Custom flag combinations (--scanflags): scan D_FULL, attribution D_FULL. anything that is not a legitimate combination is caught as 'not matched above' rather than by a list of known ones, so a novel combination is still caught.

SYN|FIN scan (--scanflags SYNFIN): scan D_FULL, attribution D_FULL. a classic filter-evasion combination, named explicitly.

UDP scan (-sU): scan D_PARTIAL, attribution U_UNREACHABLE. legitimate multi-port UDP traffic is common (mDNS, SSDP, games, P2P) so the weight is low; and a UDP source address costs nothing to forge, so RequireTCPEvidence refuses to block on UDP-only evidence.

IP protocol scan (-sO): scan D_FULL, attribution D_FULL. counting distinct IP protocol numbers is cheap and unambiguous; the method is legitimately mixed because -sO also emits real TCP and UDP headers.

Decoy scan (-D): scan D_FULL, attribution U_UNREACHABLE. the scan is fully visible but the forged sources are indistinguishable from the real one. This is the reason the default block policy asks rather than acts.

OS fingerprinting (-O): scan D_FULL, attribution D_FULL. mixes a port scan with fingerprinting probes, so several probe families arrive from one source.

Fragmented probes (-f / --mtu): scan D_PARTIAL, attribution D_FULL. the first fragment ends after the eighth byte of the TCP header, so the ports are readable and the flags are not. The scan is detected; the technique behind it is reported as indeterminate rather than guessed, because an unread flag octet reads as zero and would otherwise be reported as a NULL scan.

Slow scan (-T0 / -T1): scan D_PARTIAL, attribution D_FULL. a leaky bucket detects a scan whose probes arrive faster than it leaks, but how fast is not the whole answer: as the interval approaches the point where gain equals leak, the time to reach the threshold diverges. Config.SlowestDetectableScan reports the slowest scan the running configuration reports WITHIN AN HOUR, which is the figure worth quoting; slower scans are either invisible or detected long after the scanner has gone.

Idle (zombie) scan (-sI): scan D_FULL, attribution U_UNREACHABLE. every probe reaches us from the zombie, so the scan is plainly visible; the attacker never sends us a packet, so their address is not in anything we can observe.

FTP bounce scan (-b): scan D_FULL, attribution U_UNREACHABLE. the connections arrive from the FTP server. Largely obsolete, but the attribution limit is the same as the idle scan's.

Spoofed source (-S): scan D_FULL, attribution U_UNREACHABLE. the source address is chosen by the sender; nothing in the packets contradicts it.

SCTP INIT / COOKIE ECHO scan (-sY / -sZ): scan U_OUT_OF_SCOPE, attribution D_FULL. IP protocol 132 is counted towards the protocol-scan total, but SCTP chunk parsing is not implemented: it would add a third transport parser to the kernel program for a technique that is vanishingly rare on desktops.

Horizontal scan of the network: scan U_UNREACHABLE, attribution U_UNREACHABLE. a sweep of one port across many hosts is, from any single host, one packet. There is nothing to count. This is a property of the vantage point, not a gap in the implementation.

Single-port brute force: scan U_OUT_OF_SCOPE, attribution D_FULL. repeated attempts on one port are a credential attack or an application failing to reach a stopped service, not reconnaissance. Counting them is the mistake PortSentry and flowhawk make.

IPv6 port scan (-6): scan D_FULL, attribution D_FULL. identical to the IPv4 techniques once the target address is known; address-space size protects the network, not the host.

IPv6 FIN scan (-6 -sF): scan D_FULL, attribution D_FULL. the flag analysis is address-family independent.

IPv6 Xmas scan (-6 -sX): scan D_FULL, attribution D_FULL. the flag analysis is address-family independent.

IPv6 UDP scan (-6 -sU): scan D_PARTIAL, attribution U_UNREACHABLE. same weighting and same refusal to block on UDP-only evidence as IPv4.

Extension-header evasion (Topera): scan D_FULL, attribution D_FULL. hiding the TCP header behind more IPv6 extension headers than the parser walks (eight, and 1024 bytes) is itself the signature: the host answers such a probe, ordinary traffic never sends one, so each packet that exhausts the walk scores like a SYN to a system port and the scan is reported as ipv6-extension-evasion. The ports themselves are not readable, and the probes are not evidence for blocking.

Out-of-band enumeration (DNS / rDNS / certificate logs): scan U_UNREACHABLE, attribution U_UNREACHABLE. no packet reaches the host at all. Detecting it is not a network-sensor problem.

What the running configuration implies

These are derived from the configuration, not asserted: the slowest scan a leaky bucket can detect is a function of its threshold, its decay rate and the weight of one probe. As a scan slows towards the rate at which the bucket leaks, the time it takes to be reported grows without bound, so each figure below is the slowest scan reported within an hour of its first probe.

Score threshold 100, decay one point per 10s.

Probe Weight Slowest detectable interval
SYN to a closed system port (< 1024) 12 1m36s
SYN to a closed registered port 6 47s
SYN to a closed dynamic port 3 23s
anomalous flags, system port 16 2m9s
UDP to a closed dynamic port 1 7s

For reference, nmap -T1 waits 15s between probes and nmap -T0 waits 5 minutes. A scan slower than the figures above is reported late or not at all. A lower threshold or a slower decay moves the figures, at the price of reporting ordinary traffic; no setting makes a leaky bucket see a scan that is slower than its leak.

Clone this wiki locally