The Ping Rule Counted as Every Port
I cut my network’s access policy from every port down to twenty-six. The next morning the scanner that had spent weeks telling me to do exactly that reported no change: 65,536 ports admitted, same as the day before, still not narrow.
The policy was fine. The scanner was counting a rule that has no ports.
A field that has to be filled in anyway
ICMP is the protocol behind ping. It has no port numbers. There is nowhere in the packet to put one, because the idea does not apply.
The compiled filter my machines actually enforce has no optional fields. Every rule carries a destination port range, so the rule that lets my own devices ping each other has to carry one too, and the compiler writes the only value available: 0 through 65535, which is how that format spells “not applicable here” rather than a claim about what is reachable.
My reader summed port ranges and never looked at the protocol column. So one ping rule counted as a rule admitting every port that exists, and it outvoted the twenty-six real ones by arithmetic. A quieter version of the same mistake sat next to it: a UDP service could be graded reachable because a TCP rule happened to allow that port number. The protocol was in the data both times. Nothing read it.
The repair is dull. The parser carries the protocol now, the port arithmetic skips rules with no TCP or UDP protocol, and the reachability check matches the listener’s protocol and reports which range actually matched. The report header went from 65,536 to 26.
The direction of a wrong number decides how long it lives
That reader had been wrong since the day I wrote it, and it had exactly one symptom: I had stopped believing one line of my own morning report.
A monitor that says you are more exposed than you are will never be caught out. Nothing contradicts it. There is no morning where the number is wrong in a way that costs you anything, because it errs toward alarm, and alarm is the direction you are permitted to be wrong in. So it does not get fixed. It gets discounted. I had been mentally subtracting that line for weeks. That is what a discounted instrument feels like from the inside: not doubt, nothing as deliberate as doubt, just a small daily correction you stop noticing you apply.
The same morning, the other way round
Somewhere else in the same tool, a different check grades how exposed each background service is. It read the bind address. A service listening on loopback accepts connections from its own machine and nothing else, which is true, and it was graded accordingly: not network-facing, the safest thing on the report, sorted to the bottom of the list.
Eight of them were published to my entire private network by a proxy sitting in front.
They were on loopback because my own hardening rule says to be. The rule reads: anything a browser opens binds loopback only, behind a front that terminates TLS. Obeying that rule exactly is what made those eight services invisible to the tool whose job is checking that rule. The most compliant services I run were the ones the inventory could not see.
This error had no symptom at all. Nothing to be annoyed by, nothing to subtract. It agreed with what I already believed, and filed eight services under the heading of things that are fine.
Attention was never going to find either one
So: one tool, one morning, one question, wrong in both directions. Wrong by 65,510 in the direction of alarm and wrong by eight services in the direction of comfort.
I had looked at one of them every day for weeks and never once looked at the other, and I had fixed neither. The one I noticed, I noticed the way you notice a door that squeaks: often enough to be annoying, never enough to be an event. The one I did not notice was unnoticeable by construction, because it produced good news, and good news does not earn a second look.
Errors toward alarm get discounted. Errors toward comfort get believed. Both survive, for opposite reasons, and neither is found by paying closer attention, because paying attention is the filter both of them were already shaped to pass.
Two lines in the repair matter more than the repair itself. The port arithmetic now counts rules whose protocol data is missing or empty, so a stored report from before that field existed can never make a blanket rule vanish by failing to describe it. And when the proxy’s map of published services cannot be read, the report says the map is unreadable, rather than that nothing is published.
Those are one rule, which I did not have written down until this week. A gap in what you can see must never render as good news. Missing information has to come out of the pipeline still shaped like a question.
The check that finally settled any of it produced nothing at all. From another machine I opened a connection to a port I had dropped from the policy an hour earlier, and watched it hang there, unrefused and unanswered, until it gave up on its own. Thirty seconds of silence, from software I did not write and cannot talk into agreeing with me.