Nmap does not always send the packet you think you asked for. When raw sockets are unavailable it substitutes a TCP connect scan for the default SYN scan, so a run as your normal user and a run under sudo can answer different questions about the same port. The results look like a privilege problem, and they are usually a method change. Making the method explicit is the only way to compare the two runs at all.

Two Probes, One Port, Different Code Paths

A SYN scan builds the TCP header itself, sends it from a raw socket, and reads the reply off the wire before the kernel's TCP stack ever records a completed connection. A connect scan asks the operating system to open an ordinary socket and reports whatever connect() returns. Both can label a port open, yet only one leaves a half-open attempt and only one is subject to socket-level policy attached to the sending process.

The raw path needs CAP_NET_RAW, which is why the default scan quietly degrades when that capability is missing. Nmap's own scan technique reference documents the substitution: connect scanning is the fallback because it needs no special privileges at all. The swap happens without a warning in most runs, which is what makes it so easy to misread. Once you know the fallback exists, "open as root, closed as a user" stops sounding like a permissions bug and starts sounding like two different measurements.

What sudo Actually Changes in the Scan

Raising privileges restores the raw-socket path, and that changes more than the verdict. Source port selection, packet timing, retransmission behaviour and the way a filtered response is classified all come from different code. A middlebox that rate-limits SYNs treats the two runs unequally even when the destination host is identical.

Target-side logging diverges as well. A completed handshake is visible to the service and to any socket accounting, while a reset half-open probe often is not. If you compare runs against a host whose logs you also read, part of the difference you observe is the observation itself.

Hold the Method Constant in Both Runs

Force the same technique in both invocations and the comparison starts to mean something. The flag -sT requests connect scanning explicitly, -Pn removes host discovery, -n removes name resolution, and a single -p removes port-list differences.

nmap -sT -Pn -n -p 8443 198.51.100.77
sudo nmap -sT -Pn -n -p 8443 198.51.100.77

Swap the address and port for a host you are authorised to test; the documentation range above is a placeholder, not a target. If the two runs now agree, the original difference came from the scan method. If they still disagree, something else is classifying the traffic, and the next section is where to look.

Account Context Is Not Only a Privilege Flag

A VPN deployment can classify packets by UID, by cgroup, or by a rule attached to the process that opened the socket. Root traffic and user traffic then leave through different routing tables or hit different rule sets, and no amount of scan-method discipline reconciles them.

Inspect the policy rather than the privilege. On Linux, nftables expresses this with meta skuid and iptables with the owner match, and either one can send a single UID down a tunnel while the other keeps using the physical default route.

sudo nft list ruleset | grep -n skuid
sudo iptables-save | grep -n uid-owner
ip rule show
ip route get 198.51.100.77

Confirm the Probe Before You Compare Results

Before drawing conclusions, prove which probe ran. Nmap names the technique in its own output, and --reason adds the evidence behind each state, which is the part that tells you whether a handshake actually completed.

nmap --reason -sT -Pn -n -p 8443 198.51.100.77
sudo nmap --reason -sS -Pn -n -p 8443 198.51.100.77
getcap "$(command -v nmap)"
capsh --print | grep -i net_raw

Two runs that report the same state for different reasons are not a contradiction, and two runs that report different states for the same reason point at routing or policy rather than at the scan. Keep destination, port, namespace and timing identical, then change one variable at a time. Running the service as root is not the repair for a policy mismatch; expressing the intended policy through the service's owner is.

Amanqephe ahlobene