Page MenuHomeVyOS Platform

OpenConnect route restriction via iptables is ignored
Open, WishlistPublicFEATURE REQUEST

Description

When using restrict-user-to-routes = true option in ocserv.conf, OpenConnect server inserts firewall rules into iptables using the shell script /usr/bin/ocserv-fwwhich will restrict the users traffic through the router explicitly to the routes they are assigned, e.g for the following config block, the ocserv-fw will insert an iptable chain that will only permit traffic to 10.0.95.42/32 and reject the rest

vyos@vyos# show vpn openconnect network-settings 
 client-ip-settings {
     subnet 10.0.95.20/30
 }
 push-route 10.0.95.42/32

Will result in the following iptables chain (after a user has connected)

Chain FORWARD-ocserv-fw-sslvpn0 (1 references)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             10.0.95.42           /* ocserv-fw */
REJECT     all  --  anywhere             anywhere             /* ocserv-fw */ reject-with icmp-port-unreachable

However these are ignored, i'm guessing this is due to other rules, a full iptables list is below which is taken while a single user is connected to the VPN. (These are default, no firewall rules have been added using the VyOS CLI)

root@vyos:/home/vyos# iptables --list
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
VYATTA_PRE_FW_IN_HOOK  all  --  anywhere             anywhere            
VYATTA_POST_FW_IN_HOOK  all  --  anywhere             anywhere            

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED /* ocserv-fw */
VYATTA_PRE_FW_FWD_HOOK  all  --  anywhere             anywhere            
VYATTA_POST_FW_FWD_HOOK  all  --  anywhere             anywhere            
ACCEPT     udp  --  anywhere             dns.google           udp dpt:domain /* ocserv-fw */
ACCEPT     tcp  --  anywhere             dns.google           tcp dpt:domain state NEW,ESTABLISHED /* ocserv-fw */
FORWARD-ocserv-fw-sslvpn0  all  --  anywhere             anywhere             /* ocserv-fw */

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
VYATTA_PRE_FW_OUT_HOOK  all  --  anywhere             anywhere            
VYATTA_POST_FW_OUT_HOOK  all  --  anywhere             anywhere            

Chain VYATTA_PRE_FW_IN_HOOK (1 references)
target     prot opt source               destination         
RETURN     all  --  anywhere             anywhere            

Chain VYATTA_PRE_FW_FWD_HOOK (1 references)
target     prot opt source               destination         
RETURN     all  --  anywhere             anywhere            

Chain VYATTA_PRE_FW_OUT_HOOK (1 references)
target     prot opt source               destination         
RETURN     all  --  anywhere             anywhere            

Chain VYATTA_POST_FW_IN_HOOK (1 references)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            

Chain VYATTA_POST_FW_FWD_HOOK (1 references)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            

Chain VYATTA_POST_FW_OUT_HOOK (1 references)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            

Chain FORWARD-ocserv-fw-sslvpn0 (1 references)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             10.0.95.42           /* ocserv-fw */
REJECT     all  --  anywhere             anywhere             /* ocserv-fw */ reject-with icmp-port-unreachable

In this example, when an openconnect client connects, despite the router not pushing the client other routes other than to 10.0.95.42/32 and vyos-fw adding iptables rules to reject traffic by default, the end user can route traffic to other routes through the VyOS router by manually adding routes.

Note that VyOS does not support configuring restrict-user-to-routes via the CLI and this has to be configured either by manually editing ocserv.conf or using per-group/per-user configuration such as in proposed PR https://github.com/vyos/vyos-1x/pull/1783

Steps to replicate (Verified on a fresh 1.3.2 VyOS instance):

  1. Configure OpenConnect Server as per https://docs.vyos.io/en/equuleus/configuration/vpn/openconnect.html#configuration and ensure you have a user you can connect with
  2. Add a single push route to OpenConnect server set vpn openconnect network-settings push-route x.x.x.x/x
  3. Commit and save changes

Steps to test with the OpenConnect client

  1. Connect to the VPN with the user setup in step 1
  2. Confirm you can route traffic through the route you setup to push in step 2 to confirm the VPN is working (I just pinged it)
  3. Manually add a route on your machine to another address that the VyOS router can access and then attempt to route traffic to it and you should have access to other routes despite the ocserv-fw firewall rules added

It would be great to get compatibility between VyOS and OpenConnect route restriction, particularly for the use case of per-user access control. I don't have a good understanding of iptables so I can't offer too much more apart from what I've outlined above. I'm happy to assist with providing more details on request

Thanks

Details

Difficulty level
Unknown (require assessment)
Version
-
Why the issue appeared?
Will be filled on close
Is it a breaking change?
Unspecified (possibly destroys the router)
Issue type
Unspecified (please specify)

Event Timeline

PeppyH created this object in space S1 VyOS Public.
Viacheslav changed the subtype of this task from "Task" to "Bug".
Viacheslav added a subscriber: Viacheslav.

Could you send sudo nft list ruleset ?

Could you send sudo nft list ruleset ?

Full table is below, i've also updated the original post to make it clear that the above iptables I posted were taken while a user was connected to the VPN. The below sudo nft list ruleset was also taken with a single user connected

table ip raw {
	chain PREROUTING {
		type filter hook prerouting priority raw; policy accept;
		counter packets 28007 bytes 3454160 jump VYATTA_CT_IGNORE
		counter packets 28007 bytes 3454160 jump VYATTA_CT_TIMEOUT
		counter packets 28007 bytes 3454160 jump VYATTA_CT_PREROUTING_HOOK
		counter packets 28007 bytes 3454160 # NOTRACK
	}

	chain OUTPUT {
		type filter hook output priority raw; policy accept;
		counter packets 13541 bytes 2149092 jump VYATTA_CT_IGNORE
		counter packets 13541 bytes 2149092 jump VYATTA_CT_TIMEOUT
		counter packets 13541 bytes 2149092 jump VYATTA_CT_OUTPUT_HOOK
		counter packets 13541 bytes 2149092 # NOTRACK
	}

	chain VYATTA_CT_IGNORE {
		counter packets 41548 bytes 5603252 return
	}

	chain VYATTA_CT_TIMEOUT {
		counter packets 41548 bytes 5603252 return
	}

	chain VYATTA_CT_HELPER {
		meta l4proto tcp tcp dport 1536 counter packets 0 bytes 0 # CT helper tns
		meta l4proto tcp tcp dport 1525 counter packets 0 bytes 0 # CT helper tns
		meta l4proto tcp tcp dport 1521 counter packets 0 bytes 0 # CT helper tns
		meta l4proto udp udp dport 111 counter packets 0 bytes 0 # CT helper rpc
		meta l4proto tcp tcp dport 111 counter packets 0 bytes 0 # CT helper rpc
		counter packets 0 bytes 0 return
	}

	chain VYATTA_CT_PREROUTING_HOOK {
		iifname "eth1" counter packets 23737 bytes 3140634 log snaplen 128 queue-threshold 100 group 2  comment "FLOW_ACCOUNTING_RULE"
		iifname "eth0" counter packets 0 bytes 0 log snaplen 128 queue-threshold 100 group 2  comment "FLOW_ACCOUNTING_RULE"
		counter packets 28007 bytes 3454160 return
	}

	chain VYATTA_CT_OUTPUT_HOOK {
		counter packets 13541 bytes 2149092 return
	}
}
table ip filter {
	chain INPUT {
		type filter hook input priority filter; policy accept;
		counter packets 14817 bytes 1431304 jump VYATTA_PRE_FW_IN_HOOK
		counter packets 14817 bytes 1431304 jump VYATTA_POST_FW_IN_HOOK
	}

	chain FORWARD {
		type filter hook forward priority filter; policy accept;
		oifname "sslvpn0" ct state related,established counter packets 0 bytes 0 accept comment "ocserv-fw"
		counter packets 4151 bytes 302298 jump VYATTA_PRE_FW_FWD_HOOK
		counter packets 4151 bytes 302298 jump VYATTA_POST_FW_FWD_HOOK
		iifname "sslvpn0" meta l4proto udp ip daddr 8.8.8.8 udp dport 53 counter packets 0 bytes 0 accept comment "ocserv-fw"
		iifname "sslvpn0" meta l4proto tcp ip daddr 8.8.8.8 tcp dport 53 ct state new,established counter packets 0 bytes 0 accept comment "ocserv-fw"
		iifname "sslvpn0" counter packets 0 bytes 0 jump FORWARD-ocserv-fw-sslvpn0 comment "ocserv-fw"
	}

	chain OUTPUT {
		type filter hook output priority filter; policy accept;
		counter packets 13541 bytes 2149092 jump VYATTA_PRE_FW_OUT_HOOK
		counter packets 13541 bytes 2149092 jump VYATTA_POST_FW_OUT_HOOK
	}

	chain VYATTA_PRE_FW_IN_HOOK {
		counter packets 14817 bytes 1431304 return
	}

	chain VYATTA_PRE_FW_FWD_HOOK {
		counter packets 4151 bytes 302298 return
	}

	chain VYATTA_PRE_FW_OUT_HOOK {
		counter packets 13541 bytes 2149092 return
	}

	chain VYATTA_POST_FW_IN_HOOK {
		counter packets 14817 bytes 1431304 accept
	}

	chain VYATTA_POST_FW_FWD_HOOK {
		counter packets 4151 bytes 302298 accept
	}

	chain VYATTA_POST_FW_OUT_HOOK {
		counter packets 13541 bytes 2149092 accept
	}

	chain FORWARD-ocserv-fw-sslvpn0 {
		iifname "sslvpn0" ip daddr 10.0.95.42 counter packets 0 bytes 0 accept comment "ocserv-fw"
		iifname "sslvpn0" counter packets 0 bytes 0 reject comment "ocserv-fw"
	}
}
table ip6 raw {
	chain PREROUTING {
		type filter hook prerouting priority raw; policy accept;
		counter packets 5005 bytes 240240 jump VYATTA_CT_PREROUTING_HOOK
		counter packets 5005 bytes 240240 # NOTRACK
	}

	chain OUTPUT {
		type filter hook output priority raw; policy accept;
		counter packets 15 bytes 1336 jump VYATTA_CT_OUTPUT_HOOK
		counter packets 15 bytes 1336 # NOTRACK
	}

	chain VYATTA_CT_PREROUTING_HOOK {
		iifname "eth1" counter packets 4986 bytes 239328 log snaplen 128 queue-threshold 100 group 2  comment "FLOW_ACCOUNTING_RULE"
		iifname "eth0" counter packets 0 bytes 0 log snaplen 128 queue-threshold 100 group 2  comment "FLOW_ACCOUNTING_RULE"
		counter packets 5005 bytes 240240 return
	}

	chain VYATTA_CT_OUTPUT_HOOK {
		counter packets 15 bytes 1336 return
	}
}
table ip6 filter {
	chain INPUT {
		type filter hook input priority filter; policy accept;
		counter packets 5005 bytes 240240 jump VYATTA_PRE_FW_IN_HOOK
		counter packets 5005 bytes 240240 jump VYATTA_POST_FW_IN_HOOK
	}

	chain FORWARD {
		type filter hook forward priority filter; policy accept;
		counter packets 0 bytes 0 jump VYATTA_PRE_FW_FWD_HOOK
		counter packets 0 bytes 0 jump VYATTA_POST_FW_FWD_HOOK
		iifname "sslvpn0" counter packets 0 bytes 0 jump FORWARD-ocserv-fw-sslvpn0 comment "ocserv-fw"
	}

	chain OUTPUT {
		type filter hook output priority filter; policy accept;
		counter packets 15 bytes 1336 jump VYATTA_PRE_FW_OUT_HOOK
		counter packets 15 bytes 1336 jump VYATTA_POST_FW_OUT_HOOK
	}

	chain VYATTA_PRE_FW_IN_HOOK {
		counter packets 5005 bytes 240240 return
	}

	chain VYATTA_PRE_FW_FWD_HOOK {
		counter packets 0 bytes 0 return
	}

	chain VYATTA_PRE_FW_OUT_HOOK {
		counter packets 15 bytes 1336 return
	}

	chain VYATTA_POST_FW_IN_HOOK {
		counter packets 5005 bytes 240240 accept
	}

	chain VYATTA_POST_FW_FWD_HOOK {
		counter packets 0 bytes 0 accept
	}

	chain VYATTA_POST_FW_OUT_HOOK {
		counter packets 15 bytes 1336 accept
	}

	chain FORWARD-ocserv-fw-sslvpn0 {
		iifname "sslvpn0" counter packets 0 bytes 0 reject comment "ocserv-fw"
	}
}
table ip6 mangle {
	chain PREROUTING {
		type filter hook prerouting priority mangle; policy accept;
		counter packets 5005 bytes 240240 jump VYOS_DNPT_HOOK
	}

	chain INPUT {
		type filter hook input priority mangle; policy accept;
	}

	chain FORWARD {
		type filter hook forward priority mangle; policy accept;
		oifname "eth1" counter packets 0 bytes 0 log snaplen 128 queue-threshold 100 group 2  comment "FLOW_ACCOUNTING_RULE"
		oifname "eth0" counter packets 0 bytes 0 log snaplen 128 queue-threshold 100 group 2  comment "FLOW_ACCOUNTING_RULE"
	}

	chain OUTPUT {
		type route hook output priority mangle; policy accept;
	}

	chain POSTROUTING {
		type filter hook postrouting priority mangle; policy accept;
		counter packets 15 bytes 1336 jump VYOS_SNPT_HOOK
	}

	chain VYOS_DNPT_HOOK {
		counter packets 5005 bytes 240240 return
	}

	chain VYOS_SNPT_HOOK {
		counter packets 15 bytes 1336 return
	}
}
table ip6 nat {
	chain PREROUTING {
		type nat hook prerouting priority dstnat; policy accept;
		counter packets 0 bytes 0 jump VYOS_DNPT_HOOK
	}

	chain INPUT {
		type nat hook input priority 100; policy accept;
	}

	chain POSTROUTING {
		type nat hook postrouting priority srcnat; policy accept;
		counter packets 0 bytes 0 jump VYOS_SNPT_HOOK
	}

	chain OUTPUT {
		type nat hook output priority -100; policy accept;
	}

	chain VYOS_DNPT_HOOK {
		counter packets 0 bytes 0 return
	}

	chain VYOS_SNPT_HOOK {
		counter packets 0 bytes 0 return
	}
}
table ip nat {
	chain PREROUTING {
		type nat hook prerouting priority dstnat; policy accept;
		counter packets 0 bytes 0 jump VYATTA_PRE_DNAT_HOOK
	}

	chain INPUT {
		type nat hook input priority 100; policy accept;
	}

	chain POSTROUTING {
		type nat hook postrouting priority srcnat; policy accept;
		counter packets 0 bytes 0 jump VYATTA_PRE_SNAT_HOOK
	}

	chain OUTPUT {
		type nat hook output priority -100; policy accept;
	}

	chain VYATTA_PRE_DNAT_HOOK {
		counter packets 0 bytes 0 return
	}

	chain VYATTA_PRE_SNAT_HOOK {
		counter packets 0 bytes 0 return
	}
}
table ip mangle {
	chain PREROUTING {
		type filter hook prerouting priority mangle; policy accept;
	}

	chain INPUT {
		type filter hook input priority mangle; policy accept;
	}

	chain FORWARD {
		type filter hook forward priority mangle; policy accept;
		oifname "eth1" counter packets 4151 bytes 302298 log snaplen 128 queue-threshold 100 group 2  comment "FLOW_ACCOUNTING_RULE"
		oifname "eth0" counter packets 0 bytes 0 log snaplen 128 queue-threshold 100 group 2  comment "FLOW_ACCOUNTING_RULE"
	}

	chain OUTPUT {
		type route hook output priority mangle; policy accept;
	}

	chain POSTROUTING {
		type filter hook postrouting priority mangle; policy accept;
	}
}
Viacheslav triaged this task as Wishlist priority.Jan 20 2024, 12:24 PM

Needs to find the solution for nftables/netfilter.

Viacheslav changed the subtype of this task from "Bug" to "Feature Request".

Output seems to be for VyOS 1.3, rather than 1.5
Can you show VyOS version @PeppyH ?

Output seems to be for VyOS 1.3, rather than 1.5
Can you show VyOS version @PeppyH ?

Yes this was for 1.3, I no longer have this environment setup but from my original post it looks like 1.3.2 which was LTS at the time of authoring

And do you have similar setup and situation in newer version?