Good evening everyone, I apologize in advance for what may be something simple, but it’s driving me up a wall. I’m working on a school project where I need to restrict access to an FTP server (192.168.20.4) from devices in another segment (192.168.30.x). I’ve tried creating access-lists for each device denying permission as well as for the entire subnet, but nothing seems to work. Do I need to somehow apply the access-list policy to get it to work? Thank you in advance for any and all help.
Please post the config you’ve tried that doesn’t work, tell us what version of VyOS you’re using etc.
Also note that you can also try to reboot your VyOS to make sure its not an already allowed entry in the conntrack table that bypasses your new ruleset.
There is probably a command aswell to drop all currently active conntracks to force your new attempt to be evaluated against the ruleset and not just get a hit as an already established/related session.
version 1.4
configure
set policy access-list 99 rule 10 destination host 192.168.20.4
set policy access-list 99 rule 10 source network 192.168.30.0/24
set policy access-list 99 rule 10 action deny
commit
save
I’ve tried altering the order these lines are placed, that does not seem to do anything. Also, Vyos tells me that 192.168.30.0/24 is not a valid ipv4 network. Alternatively, I’ve tried doing just one of the hosts I’m trying to restrict by using “source host 192.168.30.1”, but it still has access.
Access-lists in VyOS are used along FRR for filtering in the control plane (like route filtering for a routing protocol), and not filtering in the dataplane (like packet filtering).
In VyOS, to filter traffic between hosts, you need to configure the firewall. Since you’re trying to filter traffic between hosts, you’ll want to configure a rule in the Forward chain.
This only comes into play if you’re using Offload, doesn’t it? Offloaded packets don’t follow the standard path so you have clear conntrack for updated rules that might affect them to take effect, but this isn’t true for standard (non-offloaded) flows, is it?
Would you be able to provide an example of how that would be written? I’m a bit out of my element here and I’m really struggling to make sense of it all.
@Ninefive I would really, really recommend understanding firewall rules before trying to blindly apply examples from other people.
Still, here you go, an example that stops 192.168.0.11 and .12 from being able to access anything not in 192.168.0.0/16.
eth1 in this example is my “LAN” interface on my router.
set firewall ipv4 forward filter default-action 'accept'
set firewall ipv4 forward filter description 'Filter IPv4 packets being forwarded through the router'
set firewall ipv4 forward filter rule 10 action 'jump'
set firewall ipv4 forward filter rule 10 description 'Filter IPv4 Traffic Ingress via LAN Port'
set firewall ipv4 forward filter rule 10 inbound-interface name 'eth1'
set firewall ipv4 forward filter rule 10 jump-target 'v4-lan-in'
set firewall ipv4 name v4-lan-in default-action 'return'
set firewall ipv4 name v4-lan-in description 'Filter IPv4 Traffic Incoming From The LAN - eth1'
set firewall ipv4 name v4-lan-in rule 10 action 'drop'
set firewall ipv4 name v4-lan-in rule 10 description 'Stop Webcams Sending Direct To The Internet'
set firewall ipv4 name v4-lan-in rule 10 destination address '!192.168.0.0/16'
set firewall ipv4 name v4-lan-in rule 10 log
set firewall ipv4 name v4-lan-in rule 10 source address '192.168.0.11-192.168.0.12'
@tjh I appreciate the help. Like I said, this is for a school assignment and everything is being done in a sandbox. This instance of Vyos doesn’t seem to recognize the first line you provided, says it’s not valid. So I’m still kind of stumped here. But I’m curious how Vyos uses access-lists if they don’t allow you to restrict access to other hosts?
I understand it’s for a school assignment, hopefully I’m not doing your work for you. Surely part of the assignment would be understanding what you’re doing any why?
As already answered by @L0crian above, access lists are used to filter routes. You’re asking to filter traffic which is where firewall rules come into play.
You said you’re using Vyos 1.4 but my first line isn’t accepted, can you post a screenshot or similar showing the issue?
For the sake of simplicity, I’d avoid using any jump actions for this. The added logic won’t buy you anything if this is just for a simple function.
The VyOS firewall uses nftables on 1.4 and 1.5. There will be 3 chains that are used with nftables:
- Input - This is for traffic destined to an IP owned by VyOS
- Output - This is for traffic originated by VyOS itself
- Forward - This is for traffic that traverses VyOS (like what you’re trying to do).
You only need to configure the forward chain for what you’re trying to do. Mapping what you had before:
set policy access-list 99 rule 10 destination host 192.168.20.4
set policy access-list 99 rule 10 source network 192.168.30.0/24
set policy access-list 99 rule 10 action deny
Will translate to this (I further scoped the traffic by protocol and port for FTP):
set firewall ipv4 forward filter default-action drop
set firewall ipv4 forward filter rule 100 action 'accept'
set firewall ipv4 forward filter rule 100 destination address '192.168.20.4'
set firewall ipv4 forward filter rule 100 destination port '21'
set firewall ipv4 forward filter rule 100 protocol 'tcp'
set firewall ipv4 forward filter rule 100 source address '192.168.30.0/24'
This will allow that subnet to access the FTP server, but this won’t allow return traffic. You can explicitly allow the return by simply reversing the source and destination commands in rule 100 within another rule, but the better and more scalable way is to use state to allow the return traffic. You can do that with this:
set firewall ipv4 forward filter rule 10 action 'accept'
set firewall ipv4 forward filter rule 10 state 'established'
set firewall ipv4 forward filter rule 10 state 'related'
This will allow return traffic from the FTP server to that subnet, provided a host in the subnet attempted to initiate the conversation.
@L0crian Thanks for your help. This all makes sense to me as far as “why” it works, meaning I understand why this would do what I need it to. Unfortunately, it’s not working. I’m including screenshots for clarity. “ipv4” does not come up as a possible completion for “set firewall…”
Looks like you’re using a very old version of 1.4 (built in May of 2022). It was probably before the refactoring of the firewall from iptables to nftables.
You’ll want to modify what I wrote for the syntax found here:
https://docs.vyos.io/en/equuleus/configuration/firewall/index.html
The main difference is when using nftables, you don’t need to define an interface, but in older VyOS, you needed to apply a firewall config directly to the interfaces. You can see some examples throughout the page.
Is the sandbox provided by your school? If so, you may want to give them a heads up that VyOS has a program that may allow them to get access to current LTS images:
@L0crian You’re my hero! Finally got it to work how I need it to. Thank you so much for spending part of your day guiding me through this. In place of “ipv4” it uses “name” followed by a name of your choosing and leaves out “filter”. Then there was the matter of applying the rule to the interface, but that was simple enough to figure out.
Yes, the sandbox is provided by my school. I’m going to take your advice and see about recommending they update this. This is the first class I’ve had that used Vyos, so that didn’t help. But thank you once again for making the latter half of my Sunday a bit less stressful.
If so then it should be called route-fitlers or route-maps and not access-lists which are ACL aka “firewall” on a regular router/switch.
This comes into play as soon as you allow established/related which you normally would do as the first rule for performance reasons (on a SPI-based firewall (stateful packet inspection)).
Specially for iptables and nftables (VyOS uses the later since 1.4.x) who are “top-down” in its exeuction (similar to how ACL in Cisco, Arista etc works) rather than “best-match” which some BSD-based firewalls uses. That is for performance reasons you want each packet to be evaluated against as few lines as possible (which is for more advanced setups using jump as action is handy).
Normally you would setup the firewall something like this (as a bare minimum):
- Allow established/related.
- Drop invalid.
- Allow specific flows (for example host A to B using TCP22 etc).
- Default deny (+log if you want to log dropped packets).
With above the established/related is picked up from the conntrack table and as it currently seems when you change the current firewall (nftables) ruleset it wont be re-evaluated against flows that have already been allowed by the previous ruleset.
To do so you must either:
- Reboot the device (or if you use a pair with conntrack-sync you must reboot both at once).
- Clear the conntrack table either all together from the CLI (which will break connections for other sessions/flows where the ruleset didnt change) or manually hunt down sessions/flows and have them removed from the conntrack table one by one in the CLI (could of course be scripted but still).
For example you have allowed host A to host B using TCP22. But then with the new ruleset you realize that this was wrong so you change the ruleset into allowing host A to host C using TCP22.
Now the already existing session from host A to host B using TCP22 (assuming the client actually did try to connect) will remain valid until it timesout (default timeout in Linux world unless you change it is 2 weeks or so for established sessions/flows) or if the client disconnects from the server (or the server perform a disconnect using FIN/ACK or RST).
This can be somewhat confusing but also bad from a security point of view because you expect that your fix of host A to host C using TCP22 is now the only valid connection but looking at the conntrack you will find an ongoing session of host A to host B using TCP22 (which was valid with the old ruleset) and since it exists in the conntrack it will be allowed by that first “Allow established/related” rule. So now you got yourself a hole in your firewall which you might not be aware of.
This behaviour seems to be default for alot of firewall implementations. OPNsense also seem to NOT re-evaluate a new ruleset against whats already allowed according to the conntrack table (or whatever such is called in FreeBSD).
Im not aware of how PaloAlto Networks and the other commercial firewalls deals with this.
You dont have this issue on a regular router/switch using ACL’s since they normally cannot deal with connection tracking - they will just evaluate the packet against the current ACL as is.
Right you are - the way I have my rules setup this didn’t show up for me, but 100% in the testing I’ve just done I’ve seen it. Thanks for educating me - I thought this was a just a flow offload thing.
ACLs on a router/switch are general use objects that are used to match multiple things, including routes within a route-map. In route-maps, they’re typically used for discontiguous matching within a route-map (rather than the more typical prefix-list). Using an ACL to filter in the dataplane is just one of many places to call an ACL.
FRR follows this industry standard, but simply has a more limited use case since it is only for the control-plane. ACL is still the proper term for that object, and it is what will be generated in the FRR config when configuring them. No sense in reinventing the wheel and decades of a standard to rename it something different.
Yes but when you setup an ACL for an interface you expect it to be the equal when using VyOS and this thread shows that its a bad choice of a name to call something ACL which cannot be used as an access-list to filter packets on an interface.
The industry standard when you talk about ACL is to filter packets and route-filters (or route-maps) to filter routing entries.