PF Allow ICMP on local network, but not outside the network

The handbook says:
One solution is to let all ICMP traffic from the local network through while stopping all probes from outside the network:
pass inet proto icmp from $localnet to any keep state
pass inet proto icmp from any to $ext_if keep state
But, this reads to me (uniformed, I'm sure) as if it allows icmp on 192.168.1.0/24 (localnet for me), but also from any (the second line). What am I missing?
 
Well if your localnet is an RFC1918 network, and you're presumably blocking all those networks on your external interface, there's no way for packets to match both $localnet and $ext_if. Personally, I prefer this rule:
Code:
pass in quick inet proto icmp all icmp-type { echoreq, unreach }

"keep state" is the default as was pointed out to me on this forum. They really need to update the Handbook to remove all those redundant declarations.
 
Hmm. I’m getting it, so the idea is that $ext_if is a separate nic going out to other nets (external interface in a 2 nic system :). My system is strictly a one nic system. So, that being the case, If I want to allow ICMP for local traffic only, what’s the procedure? If I allow traffic coming in from local net, will that allow traffic from other nets too? Those packets would still traverse the local net and the one nic, right?
 
The "localnet" concept doesn't make sense for a single-interface system (unless you're bridging). There's only one net.
 
If I want to allow ICMP for local traffic only, what’s the procedure?
Code:
pass in on $ext_if proto icmp from $ext_if:network to ($ext_if) icmp-type echorep
pass out on $ext_if proto icmp from ($ext_if) to $ext_if:network icmp-type echoreq

pf.conf(5):
Code:
           :network      Translates to the network(s) attached to the
                         interface.

This is really strict though, if you have other subnets (i.e. not directly connected networks) connected in your LAN through a router then those ICMP requests will get ignored. You could add unreach but running traceroute(8) on a single subnet network makes very little sense.
 
I guess I really don't understand what you're trying to accomplish here. If your machine is not a firewall, and is behind NAT, it can't be pinged from the Internet anyway. If it is directly connected to the Internet, you want it to allow ICMP echoreq and unreachable messages for path MTU discovery.
 
You want to allow unreach behind NAT as well, for the very same reason. It seems to be implicit with pf, when it can be attributed to a tracked connection (?) – Allowing echoreq would be nice, but can't work without a public address…

edit, side note: as unbelievable as it might sound, it's even possible to mess up the implementation of something as simple as a ping. There was a time when it was possible to crash Windows (and, IIRC, Linux as well, maybe even other systems) from remote, just using a malformed icmp echoreq packet. 🤦‍♂️ So, historically, there was a "sane" reason for wanting to block icmp echoreq. I sincerely hope such idiotic bugs are a thing from the past.
 
Allowing echoreq would be nice, but can't work without a public address…
Yep, I allow it both ways so that machines on the internal side can ping out thanks to the implicit "keep state", but yeah, inbound path MTU discovery stops at your public IP.
 
inbound path MTU discovery stops at your public IP.
Actually, it shouldn't. Your application chosing "don't fragment" must know when the packets it sent are too large. A sane NAT implementation should rewrite the corresponding unreach messages as well… but it seems, in practice, this is an issue sometimes, see for example https://github.com/opnsense/core/issues/4094

On a second thought, "sane" and "NAT" shouldn't be used in the same sentence 😈
 
Actually, it shouldn't. Your application chosing "don't fragment" must know when the packets it sent are too large. A sane NAT implementation should rewrite the corresponding unreach messages as well… but it seems, in practice, this is an issue sometimes, see for example https://github.com/opnsense/core/issues/4094

On a second thought, "sane" and "NAT" shouldn't be used in the same sentence 😈
This is why quality firewalls have options for fragment reassembly.
 
Yet another poor workaround (which often spoils the very reason for not allowing fragmentation) only necessary because of this horrible hack called NAT. Although, in this case, correct handling of icmp unreach messages should be possible, even with NAT…
 
Packet fragmentation itself is the awful workaround for the lack of path MTU discovery. Allow the latter and you won't have any troubles with NAT or with anything else.
 
The point is that properly supporting PMTUD (making use of ICMP messages from routers on the way) seems to be non-trivial with NAT, at least, there seem to be many implementations that don't get it correct. The point is not supporting fragmentation, after all, that's what you want to avoid.
 
Back
Top