UDP state table doesn't respect DSCP/TOS
I've been testing pfsense's DSCP/TOS handling here locally. The pfsense has a minimal firewall rule set under the LAN interface:
block return in quick on vr0 inet all dscp 0x28 label "USER_RULE"
pass in quick on vr0 inet all flags S/SA keep state label "USER_RULE"
Essentially this should work like this:
1. Any packet with a TOS of 0x28 will be rejected with an icmp unreachable.
2. All other packets will pass no problem.
If the states table is empty, these rules work exactly as expected. tos 0x28 is rejected.
However, it doesn't work if this sequence of events occurs:
1. A UDP packet, with tos of 0x0, is sent to a destination. For this example, let's say UDP port 53 (for a DNS lookup).
2. Now, a packet with tos of 0x28 is sent to the same destination, with the same source port. The only thing different is the tos is now 0x28 instead of 0x0. This packet is allowed when it should be rejected.
To simulate this I'm using netcat on Linux:
To send a UDP packet with tos 0x0, I'm using this command:
nc -u -p 17210 172.28.1.1 53
Then, to send the same UDP packet, to the same destination, but with tos 0x28, I'm using this command:
nc -u -T 0x28 -p 17210 172.28.1.1 53
As long as the first netcat command is executed first, the second command is successful as well. It would seem the UDP lookup for existing sessions is a five tuple lookup only? source IP, dest IP, source port, dest port, protocol? If the pass/block/reject rules allow a "tos/dscp" setting ideally it would be considered when matching a particular flow.
Is this intended behavior?
The state is created from the first packet in the session, from there DSCP/TOS aren't checked when it matches the state. That's by design, just how pf works.