floating rules: why doesn't in+out = any? / how do constraints apply to in/out packets with "any" rules?
-
Question 1: Two adjacent floating rules, one with an "in" direction and one with an "out" direction on the same interface (the NATed WAN) and no other constraints do not behave the same as a single rule with an "any" direction. Why?
Question 2: In the scenario of visiting a simple website upstream of pfsense with a browser, permitting the browswer request "out" should be sufficient: the reply traffic should match state and pass without an explicit rule. But in my scenario which requires a floating rule on WAN (in order to precede another floating rule), I need an explicit "pass in" rule. Why?
Question 3: I cannot find any information as to how additional constraints in a floating "any" rule are matched against an "in" packet and an "out" packet. Testing shows that constraints such as "destination <ip-host>, TCP port 80, tagged with `MyTag'" and the like are matched in the "out" direction but not in the "in" direction (the incoming destination would be the pfsense machine itself or an inside host, the destination port would be random, and the packet would not have a mark). This suggests that in this case anyway the "in" direction is not actually being matched with this rule. But as said above, an "out"-only rule fails. The "in" direction is required, but the other constraints are ignored on the "in" direction. Help?
The destination host is also the gateway for the pfsense. I wonder but can't confirm whether that is a relevant complication. I haven't done the work (yet) of setting up a separate destination host to test.
pfsense 2.5.2
excerpts from /tmp/rules.debug are below with comments describing the scenario and results, including state tables and logging of rules.# NOTE This is excerpt from /tmp/rules.debug. # It starts here with relevant "boilerplate" reflecting general pfsense configuration before the "user rules" further down. # My comments begin with "NOTE". Other comments were directly in /tmp/rules.debug. #System aliases CABLE_IF = "{ igb0 }" MANAGEMENT_IF = "{ igb1.53 }" # User Aliases table <Cablemodem_Business> { 10.1.10.1 } Cablemodem_Business = "<Cablemodem_Business>" table <Private_and_Loopback_IPs> { 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 169.254.0.0/16 127.0.0.0/8 fc00::/7 } Private_and_Loopback_IPs = "<Private_and_Loopback_IPs>" # Gateways GWCABLE_IF_DHCP = " route-to ( igb0 10.1.10.1 ) " # Outbound NAT rules (automatic) # Subnets to NAT table <tonatsubnets> { 127.0.0.0/8 ::1/128 192.168.103.0/24 192.168.6.0/24 192.168.23.0/24 192.168.22.0/24 192.168.3.0/24 192.168.53.0/24 192.168.200.0/25 192.168.15.0/24 192.168.220.0/24 192.168.223.0/30 192.168.224.0/30 192.168.222.0/30 } nat on $CABLE_IF inet from <tonatsubnets> to any port 500 -> 10.1.10.2/32 static-port nat on $CABLE_IF inet from <tonatsubnets> to any -> 10.1.10.2/32 port 1024:65535 # block bogon networks (IPv4) # http://www.cymru.com/Documents/bogon-bn-nonagg.txt block in quick on $CABLE_IF from <bogons> to any tracker 11001 label "block bogon IPv4 networks from CABLE_IF" # let out anything from the firewall host itself and decrypted IPsec traffic pass out inet all keep state allow-opts tracker 1000015265 label "let out anything IPv4 from firewall host itself" pass out route-to ( igb0 10.1.10.1 ) from 10.1.10.2 to !10.1.10.0/24 tracker 1000015361 keep state allow-opts label "let out anything from firewall host itself" # User-defined rules follow # NOTE Scenario: # A host on MANAGEMENT_IF (192.168.53.8) attempts to visit the web interface on port 80 of the cable modem at 10.1.10.1 (http://10.1.10.1). # The cable modem is upstream of pfsense but has a private IP address, which are normally forbidden upstream, so I want rules which allow this special case. # Pfsense has 10.1.10.2 on igb0 and talks upstream to the only other host on the subnet, the cable modem at 10.1.10.1. # The cable modem is the default WAN gateway for pfsense; pfsense is configured as the DMZ host for the cable modem. # Everything about pfsense works fine and has worked for years, except for the special case I'm trying to permit. # Browser cache is disabled. # I ensure all pf state for 10.1.10.1 is cleared before testing (monitoring pftop). # IPv6 is turned off in pfsense. # I actually want to allow only tagged requests so that non-management hosts are blocked, but I am omitting tags to debug my other rules. # NOTE These are the floating rules. # # The first two rules allow all traffic out/in respectively to/from the cable modem. # Visits to http://10.1.10.1 fail with these "out" + "in" rules, however. # But replacing them with a single "any" rule succeeds. I don't understand the difference. # Order of the two rules doesn't matter (out-in and in-out both fail). # Either rule alone fails as well. # It's easy to see why an "in" rule alone fails (the request never goes out, and the block is logged). # But why doesn't the "out" rule alone work? Visiting a website in public internet space requires only an "out" rule, it does not require any explicit rule to allow the reply traffic. pass out log quick on { igb0 } reply-to ( igb0 10.1.10.1 ) inet from any to $Cablemodem_Business tracker 1644710647 keep state label "USER_RULE: Cablemodem webserver on private address <-- Cabl..." pass in log quick on { igb0 } reply-to ( igb0 10.1.10.1 ) inet from $Cablemodem_Business to any tracker 1644779982 keep state label "USER_RULE: Cablemodem webserver on private address --> Cabl..." # NOTE After the exception above, this rule blocks all outbound traffic to a private or loopback address. block return out log quick on { igb0 } reply-to ( igb0 10.1.10.1 ) inet from any to $Private_and_Loopback_IPs tracker 1644710485 label "USER_RULE: Private and Loopback Addreses (IPv4) <-- Cable_IF" # NOTE These additional floating rules, given for completeness, block some other stuff outbound which shouldn't ever get out. block return out quick on { igb0 } reply-to ( igb0 10.1.10.1 ) inet proto { tcp udp } from any port 136 >< 140 to any tracker 1606163252 label "USER_RULE: block NetBIOS on TCP/UDP outgoing on WAN" block return out quick on { igb0 } reply-to ( igb0 10.1.10.1 ) inet proto tcp from any to any port 135 tracker 1606163371 flags S/SA label "USER_RULE: block Microsoft RPC outgoing on WAN" block return out quick on { igb0 } reply-to ( igb0 10.1.10.1 ) inet proto { tcp udp } from any to any port 445 tracker 1606163497 label "USER_RULE: block SMB/CIFS outgoing on WAN" # NOTE Rules for CABLE_IF. I expect however that floating rules not these rules are handling all traffic for this scenario. pass in log quick on $CABLE_IF reply-to ( igb0 10.1.10.1 ) inet from $Cablemodem_Business to 10.1.10.2 tracker 1644783824 keep state label "USER_RULE: Cablemodem -> this firewall explicitly as destina..." block in log quick on $CABLE_IF reply-to ( igb0 10.1.10.1 ) inet from $Private_and_Loopback_IPs to any tracker 1644783728 label "USER_RULE: Private and Loopback IPs -> any" # NOTE Rules for MANAGEMENT_IF. pass in quick on $MANAGEMENT_IF inet from any to (self) tracker 1612646862 keep state label "USER_RULE: Management VLAN -> Pfsense anti-lockout" pass in log quick on $MANAGEMENT_IF inet from any to $Private_and_Loopback_IPs tracker 1613102475 keep state label "USER_RULE: Management VLAN -> Private and Loopback IPs" pass in quick on $MANAGEMENT_IF inet from any to any tracker 1607794050 keep state label "USER_RULE: Management VLAN -> any" ############################### state table on success: pfTop: Up State 1-3/3 (251), View: default, Order: dest. addr PR DIR SRC DEST STATE AGE EXP PKTS BYTES tcp In 192.168.53.8:56704 10.1.10.1:80 FIN_WAIT_2:FIN_WAIT_2 00:00:16 00:01:23 32 20700 tcp Out 10.1.10.2:61943 10.1.10.1:80 FIN_WAIT_2:FIN_WAIT_2 00:00:16 00:01:23 32 20700 # Log on success (logged rules above, plus default deny/pass/bogon/private rules) - note tracker for first entry is not above, which is the failing case # These are "pass" entries; no relevant blocks. [OUT symbol] CABLE_IF 10.1.10.2:61943 10.1.10.1:80 TCP:S Cablemodem webserver on private address <--> Cab... (1644787208) MANAGEMENT_IF 192.168.53.8:56704 10.1.10.1:80 TCP:S Management VLAN -> Private and Loopback IPs (1613102475) state table on fail (separate in + out rules): # The only differences I see are two pairs instead of one, and the different NATed source ports, and the STATE column contents, # which makes sense because the connection is failing. # Sometimes there are three pairs, sometimes two. pfTop: Up State 1-4/4 (346), View: default, Order: dest. addr PR DIR SRC DEST STATE AGE EXP PKTS BYTES tcp In 192.168.53.8:57160 10.1.10.1:80 SYN_SENT:ESTABLISHED 00:00:13 00:00:28 11 572 tcp Out 10.1.10.2:58244 10.1.10.1:80 ESTABLISHED:SYN_SENT 00:00:13 00:00:28 11 572 tcp In 192.168.53.8:57159 10.1.10.1:80 SYN_SENT:ESTABLISHED 00:00:13 00:00:28 11 572 tcp Out 10.1.10.2:32483 10.1.10.1:80 ESTABLISHED:SYN_SENT 00:00:13 00:00:28 11 572 # Log on fail. Likewise two pairs instead of one. These are "pass" logs; no relevant blocks. [OUT symbol] CABLE_IF 10.1.10.2:41303 10.1.10.1:80 TCP:S Cablemodem webserver on private address <-- Cabl... (1644710647) MANAGEMENT_IF 192.168.53.8:57779 10.1.10.1:80 TCP:S Management VLAN -> Private and Loopback IPs (1613102475) [OUT symbol] CABLE_IF 10.1.10.2:26164 10.1.10.1:80 TCP:S Cablemodem webserver on private address <-- Cabl... (1644710647) MANAGEMENT_IF 192.168.53.8:57778 10.1.10.1:80 TCP:S Management VLAN -> Private and Loopback IPs (1613102475)
-
@msswift I don't mess around with floating rules. I define them more explicitly on each interface. But here's some official documentation from Netgate on how they are applied:
https://docs.netgate.com/pfsense/en/latest/firewall/rule-methodology.html
Also note that floating rules marked as "Quick" act differently than non-quick floating rules.