Help Isolating VLANs on 1.5-rolling

I’m still trying to learn my way around vyos and I’ve been enjoying the process. I’m still trying to wrap my brain around how to read the firewall rulesets so I can actually manipulate them in a predictable manner that actually gives me confidence it’s doing what I think it should do. I’m slowly piecing together all the things opnsense used to do for me automagically. I am currently stumped on what obvious thing I’m missing to isolate my LAN-UNTRUSTED from my LAN-TRUSTED. Essentially I’m treating LAN-UNTRUSTED like an IoT network where I want LAN-TRUSTED to uni-directionally be able to access LAN-UNTRUSTED, but not the reverse, while letting both still access the internet. I’m 99% it’s the forward chain I need to be manipulating and I tried to mirror the example OUTSIDE-IN rules.

As it’s currently written an IP in LAN-UNTRUSTED (17.16.95.50) can access an IP in LAN-TRUSTED (192.168.95.50) so obviously I’ve missed the mark somewhere.

eth4 is WAN. eth5* are all LAN.

An extra pair of eyes would be greatly appreciated to let me know what I’m doing wrong here. Thanks!

 group {
     interface-group LAN {
         interface "eth5*"
     }
     interface-group WAN {
         interface eth4
     }
     network-group LAN-TRUSTED {
         network 192.168.5.0/24
         network 192.168.10.0/24
         network 192.168.65.0/24
         network 192.168.95.0/24
     }
     network-group LAN-UNTRUSTED {
         network 172.16.5.0/24
         network 172.16.95.0/24
     }
     network-group NET-INSIDE-v4 {
         include LAN-TRUSTED
         include LAN-UNTRUSTED
     }
     port-group HAPROXY_PORTS {
         port 80
         port 443
     }
 }
 ipv4 {
     forward {
         filter {
             rule 10 {
                 action jump
                 jump-target CONN_FILTER
             }
             rule 100 {
                 action jump
                 destination {
                     group {
                         network-group NET-INSIDE-v4
                     }
                 }
                 inbound-interface {
                     interface-group WAN
                 }
                 jump-target OUTSIDE-IN-v4
             }
             rule 110 {
                 action jump
                 destination {
                     group {
                         network-group NET-INSIDE-v4
                     }
                 }
                 inbound-interface {
                     interface-group LAN
                 }
                 jump-target LAN-IN
             }
         }
     }
     input {
         filter {
             default-action drop
             rule 10 {
                 action jump
                 jump-target CONN_FILTER
             }
             rule 20 {
                 action jump
                 destination {
                     port 22
                 }
                 jump-target MGMT
                 protocol tcp
             }
             rule 30 {
                 action accept
                 icmp {
                     type-name echo-request
                 }
                 protocol icmp
                 state {
                     new enable
                 }
             }
             rule 40 {
                 action accept
                 destination {
                     port 53
                 }
                 protocol tcp_udp
                 source {
                     group {
                         network-group LAN-TRUSTED
                     }
                 }
             }
             rule 50 {
                 action accept
                 source {
                     address 127.0.0.0/8
                 }
             }
         }
     }
     name CONN_FILTER {
         default-action accept
         rule 10 {
             action accept
             state {
                 established enable
                 related enable
             }
         }
         rule 20 {
             action drop
             state {
                 invalid enable
             }
         }
     }
     name LAN-IN {
         default-action drop
         rule 100 {
             action accept
             destination {
                 group {
                     network-group LAN-UNTRUSTED
                 }
             }
             source {
                 group {
                     network-group LAN-TRUSTED
                 }
             }
             state {
                 new enable
             }
         }
     }
     name MGMT {
         default-action return
         rule 15 {
             action accept
             inbound-interface {
                 interface-group LAN
             }
             source {
                 group {
                     network-group LAN-TRUSTED
                 }
             }
         }
         rule 20 {
             action drop
             inbound-interface {
                 interface-group WAN
             }
             recent {
                 count 4
                 time minute
             }
             state {
                 new enable
             }
         }
     }
     name OUTSIDE-IN-v4 {
         default-action drop
     }
 }
 ethernet eth0 {
     hw-id 0c:c4:7a:d9:e5:18
 }
 ethernet eth1 {
     hw-id 0c:c4:7a:d9:e5:19
 }
 ethernet eth2 {
     hw-id 0c:c4:7a:d9:e5:1a
 }
 ethernet eth3 {
     hw-id 0c:c4:7a:d9:e5:1b
 }
 ethernet eth4 {
     address dhcp
     hw-id e4:1d:2d:49:d1:00
 }
 ethernet eth5 {
     address 192.168.5.5/24
     hw-id e4:1d:2d:49:d1:01
     vif 95 {
         address 192.168.95.5/24
     }
     vif 96 {
         address 172.16.95.5/24
     }
 }
 loopback lo {
 }

I’ve modified a few things so I’m posting an updated config. The more I read about nftables, I’m convinced I’m correct I need to be manipulating the forward chain but I don’t understand why my jump rule isn’t working. I don’t think the CONN_FILTER is causing the problem, but maybe?

Things I’ve changed:

  • Modified the LAN interface-group just to include a new LAN-UNTRUSTED and LAN-TRUSTED. I’m still using the network-group though as I’d prefer to use subnets vs interfaces.
  • Added default-action drop to the forward chain
  • Got rid of destination group on forward chain rule 110 just to broaden the scope to see if my rule was too specific
 interface-group LAN {
     include LAN-TRUSTED
     include LAN-UNTRUSTED
 }
 interface-group LAN-TRUSTED {
     interface eth5
     interface eth5.95
 }
 interface-group LAN-UNTRUSTED {
     interface eth5.96
 }
 interface-group WAN {
     interface eth4
 }
 network-group LAN-TRUSTED {
     network 192.168.5.0/24
     network 192.168.10.0/24
     network 192.168.65.0/24
     network 192.168.95.0/24
 }
 network-group LAN-UNTRUSTED {
     network 172.16.5.0/24
     network 172.16.95.0/24
 }
 network-group NET-INSIDE-v4 {
     include LAN-TRUSTED
     include LAN-UNTRUSTED
 }
 port-group HAPROXY_PORTS {
     port 80
     port 443
 }
 forward {
     filter {
         default-action drop
         rule 10 {
             action jump
             jump-target CONN_FILTER
         }
         rule 100 {
             action jump
             destination {
                 group {
                     network-group NET-INSIDE-v4
                 }
             }
             inbound-interface {
                 interface-group WAN
             }
             jump-target OUTSIDE-IN-v4
         }
         rule 110 {
             action jump
             inbound-interface {
                 interface-group LAN
             }
             jump-target LAN-IN
         }
     }
 }
 input {
     filter {
         default-action drop
         rule 10 {
             action jump
             jump-target CONN_FILTER
         }
         rule 20 {
             action jump
             destination {
                 port 22
             }
             jump-target MGMT
             protocol tcp
         }
         rule 30 {
             action accept
             icmp {
                 type-name echo-request
             }
             protocol icmp
             state {
                 new enable
             }
         }
         rule 40 {
             action accept
             destination {
                 port 53
             }
             protocol tcp_udp
             source {
                 group {
                     network-group LAN-TRUSTED
                 }
             }
         }
         rule 50 {
             action accept
             source {
                 address 127.0.0.0/8
             }
         }
     }
 }
 name CONN_FILTER {
     default-action accept
     rule 10 {
         action accept
         state {
             established enable
             related enable
         }
     }
     rule 20 {
         action drop
         state {
             invalid enable
         }
     }
 }
 name LAN-IN {
     default-action drop
     rule 100 {
         action accept
         destination {
             group {
                 network-group LAN-UNTRUSTED
             }
         }
         source {
             group {
                 network-group LAN-TRUSTED
             }
         }
         state {
             new enable
         }
     }
 }
 name MGMT {
     default-action return
     rule 15 {
         action accept
         inbound-interface {
             interface-group LAN
         }
         source {
             group {
                 network-group LAN-TRUSTED
             }
         }
     }
     rule 20 {
         action drop
         inbound-interface {
             interface-group WAN
         }
         recent {
             count 4
             time minute
         }
         state {
             new enable
         }
     }
 }
 name OUTSIDE-IN-v4 {
     default-action drop
 }
1 Like

I think I solved my issue. I got default-action accept happy when writing out (not copy/pasting) the rules from the Quick Start guide. Below are the changes I had to make for those that might need to do the same as me:

  • CONN_FILTER default-action was set errantly to accept and must be return. As I suspected, the traffic was never able to even hit the other jump chains because CONN_FILTER wasn’t literally returning back to continue processing. Once doing this, I should see the additional packets hit the other forward filter rules.
  • I had to expand on my LAN-IN. As it was written originally, it was preventing LAN-TRUSTED from reaching the internet, but could hit LAN-UNTRUSTED. And subsequently, LAN-UNTRUSTED couldn’t do anything outside their individual subnets, which is also not the behavior I wanted.
  • One small after the fact edit, I also changed the LAN-IN default-action from accept to return as well.

I didn’t need to change anything in my firewall groups. This is what I ended up with for my firewall ipv4 to let all subnets reach the internet, let LAN-TRUSTED reach LAN-UNTRUSTED, but LAN-UNTRUSTED not reach LAN-TRUSTED. I assume this is the best way to approach this, but I’m definitely open to criticism and feedback from anyone that spots any glaring issues or better practice.

 forward {
     filter {
         default-action drop
         rule 10 {
             action jump
             jump-target CONN_FILTER
         }
         rule 100 {
             action jump
             destination {
                 group {
                     network-group NET-INSIDE-v4
                 }
             }
             inbound-interface {
                 interface-group WAN
             }
             jump-target OUTSIDE-IN-v4
         }
         rule 110 {
             action jump
             inbound-interface {
                 interface-group LAN
             }
             jump-target LAN-IN
             log enable
         }
     }
 }
 input {
     filter {
         default-action drop
         rule 10 {
             action jump
             jump-target CONN_FILTER
         }
         rule 20 {
             action jump
             destination {
                 port 22
             }
             jump-target MGMT
             protocol tcp
         }
         rule 30 {
             action accept
             icmp {
                 type-name echo-request
             }
             protocol icmp
             state {
                 new enable
             }
         }
         rule 40 {
             action accept
             destination {
                 port 53
             }
             protocol tcp_udp
             source {
                 group {
                     network-group LAN-TRUSTED
                 }
             }
         }
         rule 50 {
             action accept
             source {
                 address 127.0.0.0/8
             }
         }
     }
 }
 name CONN_FILTER {
     default-action return
     rule 10 {
         action accept
         state {
             established enable
             related enable
         }
     }
     rule 20 {
         action drop
         state {
             invalid enable
         }
     }
 }
 name LAN-IN {
     default-action return
     rule 100 {
         action accept
         source {
             group {
                 network-group LAN-TRUSTED
             }
         }
         state {
             new enable
         }
     }
     rule 110 {
         action accept
         destination {
             group {
                 network-group !LAN-TRUSTED
             }
         }
         source {
             group {
                 network-group LAN-UNTRUSTED
             }
         }
         state {
             new enable
         }
     }
 }
 name MGMT {
     default-action return
     rule 15 {
         action accept
         inbound-interface {
             interface-group LAN
         }
         source {
             group {
                 network-group LAN-TRUSTED
             }
         }
     }
     rule 20 {
         action drop
         inbound-interface {
             interface-group WAN
         }
         recent {
             count 4
             time minute
         }
         state {
             new enable
         }
     }
 }
 name OUTSIDE-IN-v4 {
     default-action drop
 }
1 Like

Yes, thats part of the optimizations regarding nftables (and older iptables) if other rules should be inspected or not (along with that nftables and iptables are first-match firewalls rather than best-match as with the ones in *bsd products).

I have put up an example of zonebased firewalling with the new firewall syntax (who arrived early august for 1.4-rolling and newer) where I simply filter out the destination interfacegroup and then have a default-action of deny or accept set for that.

That is its not necessary for the nftables to evaluate other destination interfacegroups if the traffic is egressing WAN group and have already processed the rules related to egressing WAN group.

Here is the example Im talking about:

2 Likes

Ah this is excellent! I really appreciate you crafting this, let alone pointing me to it. The documentation on the website has been great but I’ve found myself frustrated at my timing to jump into vyos to try and find relevant examples since the change.

Note that I just updated the example with following:

Edit 230930: Turns out that state established and related can be defined in the same rule nowadays so the above example is now updated for that.

I went ahead and adapted the template you provided and initially it didn’t work 100% for me. I had to change this:

set firewall ipv4 forward filter rule 30 action 'jump'
set firewall ipv4 forward filter rule 30 jump-target 'V4_TO_WAN'
set firewall ipv4 forward filter rule 30 outbound-interface interface-group 'WAN'
set firewall ipv4 forward filter rule 40 action 'jump'
set firewall ipv4 forward filter rule 40 jump-target 'V4_TO_DMZ'
set firewall ipv4 forward filter rule 40 outbound-interface interface-group 'DMZ'
set firewall ipv4 forward filter rule 50 action 'jump'
set firewall ipv4 forward filter rule 50 jump-target 'V4_TO_LAN'
set firewall ipv4 forward filter rule 50 outbound-interface interface-group 'LAN'

All of the outbound-interface to inbound-interface and I got the correct expected behavior. Just figured I’d share. I was going to reply back to the initial thread where you have those rules but I wasn’t sure if that would split that topic too broadly or not.

Hmm…

The idea with “my” template is that you will protect whatever is going into a specific zone (aka interface-group).

This means whatever is egressing to that interface-group.

For example stuff sent from LAN to WAN (dstip 192.0.2.1) would first be catched by:

set firewall ipv4 forward filter rule 30 jump-target 'V4_TO_WAN'
set firewall ipv4 forward filter rule 30 outbound-interface interface-group 'WAN'

followed by:

set firewall ipv4 name V4_TO_WAN default-action 'drop'
set firewall ipv4 name V4_TO_WAN rule 10 action 'accept'
set firewall ipv4 name V4_TO_WAN rule 10 inbound-interface interface-group 'LAN'
set firewall ipv4 name V4_TO_WAN rule 10 destination address '192.0.2.1'

That is since we already concluded the outbound interface-group in forward filter we will then only act on inbound interface-group within the V4_TO_WAN.

The combo will be packet who arrived in interface-group LAN going to interface-group WAN dstip 192.0.2.1 will be accepted. Any other packet going to interface-group WAN will by default be dropped.

That is the details for which source interface-group along with srcip/dstip/srcport/dstport are written in V4_TO_WAN.

Can you please verify the above in your config (or did I get the directions wrong)?

Yea, this is what I have currently. This version I can ping between vlans and out to 1.1.1.1.

set firewall ipv4 forward filter default-action 'drop'
set firewall ipv4 forward filter rule 10 action 'accept'
set firewall ipv4 forward filter rule 10 state established 'enable'
set firewall ipv4 forward filter rule 10 state related 'enable'
set firewall ipv4 forward filter rule 20 action 'drop'
set firewall ipv4 forward filter rule 20 state invalid 'enable'
set firewall ipv4 forward filter rule 30 action 'jump'
set firewall ipv4 forward filter rule 30 inbound-interface interface-group 'WAN'
set firewall ipv4 forward filter rule 30 jump-target 'V4_TO_WAN'
set firewall ipv4 forward filter rule 40 action 'jump'
set firewall ipv4 forward filter rule 40 inbound-interface interface-group 'LAN'
set firewall ipv4 forward filter rule 40 jump-target 'V4_TO_LAN'
set firewall ipv4 input filter default-action 'drop'
set firewall ipv4 input filter rule 10 action 'accept'
set firewall ipv4 input filter rule 10 state established 'enable'
set firewall ipv4 input filter rule 10 state related 'enable'
set firewall ipv4 input filter rule 20 action 'drop'
set firewall ipv4 input filter rule 20 state invalid 'enable'
set firewall ipv4 input filter rule 30 action 'accept'
set firewall ipv4 input filter rule 30 destination port '22'
set firewall ipv4 input filter rule 30 inbound-interface interface-group 'LAN'
set firewall ipv4 input filter rule 30 protocol 'tcp'
set firewall ipv4 input filter rule 30 source group network-group 'V4_LAN_TRUSTED'
set firewall ipv4 input filter rule 40 action 'accept'
set firewall ipv4 input filter rule 40 destination port '22'
set firewall ipv4 input filter rule 40 inbound-interface interface-group 'WAN'
set firewall ipv4 input filter rule 40 protocol 'tcp'
set firewall ipv4 input filter rule 40 source group address-group 'SAFE'
set firewall ipv4 input filter rule 50 action 'accept'
set firewall ipv4 input filter rule 50 inbound-interface interface-group 'LAN'
set firewall ipv4 input filter rule 50 protocol 'vrrp'
set firewall ipv4 input filter rule 50 source group network-group 'V4_LAN'
set firewall ipv4 input filter rule 60 action 'accept'
set firewall ipv4 input filter rule 60 icmp type-name 'echo-request'
set firewall ipv4 input filter rule 60 protocol 'icmp'
set firewall ipv4 input filter rule 60 state new 'enable'
set firewall ipv4 name V4_TO_LAN default-action 'drop'
set firewall ipv4 name V4_TO_LAN rule 100 action 'accept'
set firewall ipv4 name V4_TO_LAN rule 100 source group network-group 'V4_LAN_TRUSTED'
set firewall ipv4 name V4_TO_LAN rule 100 state new 'enable'
set firewall ipv4 name V4_TO_LAN rule 110 action 'accept'
set firewall ipv4 name V4_TO_LAN rule 110 destination group network-group '!V4_LAN_TRUSTED'
set firewall ipv4 name V4_TO_LAN rule 110 source group network-group 'V4_LAN_UNTRUSTED'
set firewall ipv4 name V4_TO_LAN rule 110 state new 'enable'
set firewall ipv4 name V4_TO_LAN rule 120 action 'accept'
set firewall ipv4 name V4_TO_LAN rule 120 destination group address-group 'LAN-DNS'
set firewall ipv4 name V4_TO_LAN rule 120 destination port '53'
set firewall ipv4 name V4_TO_LAN rule 120 protocol 'udp'
set firewall ipv4 name V4_TO_LAN rule 120 source group network-group 'V4_LAN'
set firewall ipv4 name V4_TO_WAN default-action 'drop'
set firewall ipv4 output filter default-action 'accept'
set firewall ipv4 output filter rule 10 action 'accept'
set firewall ipv4 output filter rule 10 state established 'enable'
set firewall ipv4 output filter rule 10 state related 'enable'
set firewall ipv4 output filter rule 20 action 'drop'
set firewall ipv4 output filter rule 20 state invalid 'enable'
set firewall ipv4 output filter rule 999999 action 'accept'
set firewall ipv4 output filter rule 999999 destination address '127.0.0.0/8'
set firewall ipv4 output filter rule 999999 outbound-interface interface-name 'lo'

If I flip flop them, I can still ping across vlans but not out to 1.1.1.1.

[firewall ipv4 forward filter rule 30]
- inbound-interface {
-     interface-group "WAN"
- }
+ outbound-interface {
+     interface-group "WAN"
+ }
[firewall ipv4 forward filter rule 40]
- inbound-interface {
-     interface-group "LAN"
- }
+ outbound-interface {
+     interface-group "LAN"
+ }
set firewall ipv4 forward filter default-action 'drop'
set firewall ipv4 forward filter rule 10 action 'accept'
set firewall ipv4 forward filter rule 10 state established 'enable'
set firewall ipv4 forward filter rule 10 state related 'enable'
set firewall ipv4 forward filter rule 20 action 'drop'
set firewall ipv4 forward filter rule 20 state invalid 'enable'
set firewall ipv4 forward filter rule 30 action 'jump'
set firewall ipv4 forward filter rule 30 jump-target 'V4_TO_WAN'
set firewall ipv4 forward filter rule 30 outbound-interface interface-group 'WAN'
set firewall ipv4 forward filter rule 40 action 'jump'
set firewall ipv4 forward filter rule 40 jump-target 'V4_TO_LAN'
set firewall ipv4 forward filter rule 40 outbound-interface interface-group 'LAN'
set firewall ipv4 input filter default-action 'drop'
set firewall ipv4 input filter rule 10 action 'accept'
set firewall ipv4 input filter rule 10 state established 'enable'
set firewall ipv4 input filter rule 10 state related 'enable'
set firewall ipv4 input filter rule 20 action 'drop'
set firewall ipv4 input filter rule 20 state invalid 'enable'
set firewall ipv4 input filter rule 30 action 'accept'
set firewall ipv4 input filter rule 30 destination port '22'
set firewall ipv4 input filter rule 30 inbound-interface interface-group 'LAN'
set firewall ipv4 input filter rule 30 protocol 'tcp'
set firewall ipv4 input filter rule 30 source group network-group 'V4_LAN_TRUSTED'
set firewall ipv4 input filter rule 40 action 'accept'
set firewall ipv4 input filter rule 40 destination port '22'
set firewall ipv4 input filter rule 40 inbound-interface interface-group 'WAN'
set firewall ipv4 input filter rule 40 protocol 'tcp'
set firewall ipv4 input filter rule 40 source group address-group 'SAFE'
set firewall ipv4 input filter rule 50 action 'accept'
set firewall ipv4 input filter rule 50 inbound-interface interface-group 'LAN'
set firewall ipv4 input filter rule 50 protocol 'vrrp'
set firewall ipv4 input filter rule 50 source group network-group 'V4_LAN'
set firewall ipv4 input filter rule 60 action 'accept'
set firewall ipv4 input filter rule 60 icmp type-name 'echo-request'
set firewall ipv4 input filter rule 60 protocol 'icmp'
set firewall ipv4 input filter rule 60 state new 'enable'
set firewall ipv4 name V4_TO_LAN default-action 'drop'
set firewall ipv4 name V4_TO_LAN rule 100 action 'accept'
set firewall ipv4 name V4_TO_LAN rule 100 source group network-group 'V4_LAN_TRUSTED'
set firewall ipv4 name V4_TO_LAN rule 100 state new 'enable'
set firewall ipv4 name V4_TO_LAN rule 110 action 'accept'
set firewall ipv4 name V4_TO_LAN rule 110 destination group network-group '!V4_LAN_TRUSTED'
set firewall ipv4 name V4_TO_LAN rule 110 source group network-group 'V4_LAN_UNTRUSTED'
set firewall ipv4 name V4_TO_LAN rule 110 state new 'enable'
set firewall ipv4 name V4_TO_LAN rule 120 action 'accept'
set firewall ipv4 name V4_TO_LAN rule 120 destination group address-group 'LAN-DNS'
set firewall ipv4 name V4_TO_LAN rule 120 destination port '53'
set firewall ipv4 name V4_TO_LAN rule 120 protocol 'udp'
set firewall ipv4 name V4_TO_LAN rule 120 source group network-group 'V4_LAN'
set firewall ipv4 name V4_TO_WAN default-action 'drop'
set firewall ipv4 output filter default-action 'accept'
set firewall ipv4 output filter rule 10 action 'accept'
set firewall ipv4 output filter rule 10 state established 'enable'
set firewall ipv4 output filter rule 10 state related 'enable'
set firewall ipv4 output filter rule 20 action 'drop'
set firewall ipv4 output filter rule 20 state invalid 'enable'
set firewall ipv4 output filter rule 999999 action 'accept'
set firewall ipv4 output filter rule 999999 destination address '127.0.0.0/8'
set firewall ipv4 output filter rule 999999 outbound-interface interface-name 'lo'

I was reading the forward chain as “jump to V4_TO_WAN rules when inbound traffic hits WAN interface”. This is where I’d basically be putting my future dNAT rules. And “jump to V4_TO_LAN rules when inbound traffic hits a LAN interface”. This is where I’d put my internal rules that traverse between vlans. Since I’m only filtering inbound traffic, and allowing all outbound traffic, it feels like those should be inbound-interface and not outbound-interface.

I do seemingly keep my vlan filtering (V4_LAN_TRUSTED can ping V4_LAN_UNTRUSTED, but not the reverse as expected, so I feel like the V4_TO_LAN chain is being honored, but not V4_TO_WAN?

Here are my nat rules since pinging out WAN seems to be an issue:

set nat source rule 100 outbound-interface 'eth0'
set nat source rule 100 source group network-group 'V4_LAN'
set nat source rule 100 translation address 'masquerade'
set firewall group address-group SAFE address 'xx.xx.xx.xx'
set firewall group address-group SAFE address 'xx.xx.xx.xx'
set firewall group address-group SAFE address 'xx.xx.xx.xx'
set firewall group address-group LAN-DNS address '192.168.95.250'
set firewall group interface-group LAN include 'LAN-TRUSTED'
set firewall group interface-group LAN include 'LAN-UNTRUSTED'
set firewall group interface-group LAN-TRUSTED interface 'eth1'
set firewall group interface-group LAN-TRUSTED interface 'eth1.95'
set firewall group interface-group LAN-UNTRUSTED interface 'eth1.96'
set firewall group interface-group WAN interface 'eth0'
set firewall group ipv6-network-group V6_LAN_TRUSTED
set firewall group ipv6-network-group V6_LAN_UNTRUSTED
set firewall group ipv6-network-group V6_WAN network '::/0'
set firewall group network-group V4_LAN include 'V4_LAN_TRUSTED'
set firewall group network-group V4_LAN include 'V4_LAN_UNTRUSTED'
set firewall group network-group V4_LAN_TRUSTED network '192.168.5.0/24'
set firewall group network-group V4_LAN_TRUSTED network '192.168.10.0/24'
set firewall group network-group V4_LAN_TRUSTED network '192.168.95.0/24'
set firewall group network-group V4_LAN_UNTRUSTED network '172.16.5.0/24'
set firewall group network-group V4_LAN_UNTRUSTED network '172.16.95.0/24'
set firewall group network-group V4_LAN_UNTRUSTED network '192.168.65.0/24'
set firewall group network-group V4_RFC1918 network '10.0.0.0/8'
set firewall group network-group V4_RFC1918 network '172.16.0.0/12'
set firewall group network-group V4_RFC1918 network '192.168.0.0/16'
set firewall group network-group V4_WAN network '0.0.0.0/0'

I’m testing from 192.168.95.50 (V4_LAN_TRUSTED) and 172.168.95.50 (V4_LAN_UNTRUSTED). 192.168.95.50 can ping 172.168.95.50 but not the reverse. Both cannot ping 1.1.1.1. Watching tcpdump, I can see the ICMP requests go out, but not get returned. I haven’t figured out how to watch dropped traffic yet, but I assume that’s where I’d be seeing the returns hitting.

If I use my rules with outbound-interface, I still retain vlan filtering and I can ping out to the internet.

When you say “and out to 1.1.1.1”, is that from the VyOS itself or from a host connecting through the VyOS?

Also in both your examples the V4_TO_WAN is empty so the default action (which is drop) will trigger for anything thrown into this chain.

Which is what happens when you only change inbound to outbound in the forward filter.

If we ignore the actual syntax the zonebased approach I did was to protect hosts sitting in a particular zone.

That is a server connected to DMZ interface want the VyOS to filter traffic which have outbound-interface set to interface-group DMZ. That is packets which the VyOS will send to the server sitting at DMZ.

Thats why the syntax might seem backwards at first sight.

Because the first filtering will be to identify any packets which the nft firewall thinks will be sent out on the interface-group DMZ (remember that the rules are from the kernel point of view and the interfaces it have to choose from).

Once thats declared we jump to V4_TO_DMZ (for IPv4 traffic) and then apply the other rules which will look at inbound-interface as in from where the packet we are currently inspecting originated from (or if we dont care as in “any” then we just dont define “inbound-interface” in the rule within V4_TO_DMZ) along other parameters like protocol, portnumber etc.

Since we already taken care of established, related and invalid in the first rules of input, output and forward filters there is no need to look for “state new” when you are inside lets say V4_TO_DMZ.

There are only 5 states to choose from in nft:

https://wiki.nftables.org/wiki-nftables/index.php/Matching_connection_tracking_stateful_metainformation#ct_state_-_conntrack_state

  • new
  • established
  • related
  • invalid
  • untracked

When you say “and out to 1.1.1.1”, is that from the VyOS itself or from a host connecting through the VyOS?

VyOS itself can ping 1.1.1.1 using either of those rule sets. What changes is whether devices routing through VyOS can ping 1.1.1.1. What doesn’t change is filtering between TRUSTED and UNTRUSTED - it seems either ruleset accomplishes this.

I guess what is tripping me up is the perspective because when you say “V4_TO_WAN” I’m thinking inbound from the internet to my WAN (or OUTSIDE-IN from the docs config examples). Likewise with “V4_TO_LAN”, anything going TO one of my LAN interfaces.

My output chain already has a default action of accept and my nat allows 0.0.0.0/0, so by that logic I would expect any of my LAN devices (behind vyos) to ping the internet. I’d expect V4_TO_WAN to filter my dNAT (needing corresponding input chain rules to allow the dNAT to occur) and V4_TO_LAN to allow vlan filtering.

You obviously understand this very well and I apologize that I’m having a hard time wrapping my brain around this. I wish there was an easy way to follow a packet through a chain so I could easily see what it was passing through and where it was getting dropped. I think that would help me sort this out.

Imagine following setup:

HostA ↔ WAN-interface < VyOS > LAN-interface ↔ HostB

That is VyOS have 2 interfaces WAN and LAN.

HostA is connected to WAN-interface of the VyOS box and HostB is connected to the LAN-interface of the VyOS box.

In my case V4_TO_LAN would in the above example mean traffic going from HostA (at WAN) to HostB (at LAN).

Another way to see this would be:

ZONE:WAN VyOS ZONE:LAN

That is V4_TO_LAN would mean traffic sent through VyOS towards ZONE LAN.

Ah ok, so I was able to get internet back by allowing the V4_LAN network group onto the V4_TO_WAN chain by adding:

set firewall ipv4 name V4_TO_WAN rule 100 action accept
set firewall ipv4 name V4_TO_WAN rule 100 source group network-group V4_LAN

If I’m fine with allowing all outbound traffic, would I be better of by changing the default-action of V4_TO_WAN from drop to accept? And in doing so, wouldn’t need any rules within V4_TO_WAN?

Going a step further, I assume all inter-vlan filtering is still done in V4_TO_LAN as well as any dNAT rules destined for a LAN IP? Those dNAT rules though would need corresponding rules on the input chain, correct?

Generally speaking firewalls should always default to “default action drop + log” and then you explictly allow the traffic you want should be able to pass through. Even if that would be an “any any allow” rule.

Only time I would change the default action to allow would be during construction of the ruleset in a lab environment.

Because this way you will see at the hit counters if the rule is properly setup and when moving to production I would change all the default-actions to drop.

There is of course also the cornercase of where you want to allow everything but block a specific traffic (let say allow everything but block dstport TCP22).

Regarding where to put the NAT rules i would still put them at destination zone.

So if you want to source nat (aka masquarade) LAN going to WAN (lets say WAN is Internet) I would setup the NAT rule in V4_TO_WAN. But I might change my mind further down the road because I havent considered NAT yet in my template.

The thing is that DNAT occurs in prerouting while SNAT occurs in postrouting. And the decision of which egress interface to use is set between prerouting and postrouting.

That is a DNAT occurs before the forward filter is evaluated while a SNAT occurs after the forward filter.

You can see the flows here:

https://wiki.nftables.org/wiki-nftables/index.php/Netfilter_hooks

Generally speaking firewalls should always default to “default action drop + log” and then you explictly allow the traffic you want should be able to pass through. Even if that would be an “any any allow” rule.

Ok, so I want to keep V4_TO_WAN default-action to drop and either keep my V4_TO_WAN rule 100 as is, or change my source address to something like 0.0.0.0/0 (any).

For me personally, I’m using this at home, so my SNAT lines won’t ever really change especially since I’m allowing all traffic out. DNAT is where I will mostly need to edit to port forward to internal services. If I’m following along correctly, that would imply DNAT rules would go on V4_TO_LAN (and then open the corresponding ports on the input chain).

I’m inching my way closer. One last question for now. As I have things written now, I’m treating parts of my LAN as TRUSTED and UNTRUSTED (literally). In your example, I should adapt my UNTRUSTED segment as “DMZ” to keep those network only communicating in one direction as opposed to doing it all within the V4_TO_LAN chain. I suppose that would be the more appropriate naming convention and to keep things tidy.

For destination nat you could use connection-status

set firewall forward .... rule XX connection-status nat destination
set firewall forward .... rule XX state new enable
set firewall forward .... rule XX action accept

This will allow all new connections which had previously hit the destination NAT rules.

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.