Solved PF Nat over OpenVPN Client

Hello. I have such a problem.

I have FreeBSD 12.1-RELEASE router (with 3 interfaces) - LAN HOME(192.168.22.), LAN WORK(192.168.11.), WAN(1.2.3.4)
My router connect to NordVPN over OpenVPN as a client (creates new TUN0 with address 10.8.0.3)

I want now to nat only one host from LAN_HOME ( 192.168.22.30) to internet over the NordVPN.

I try to setup this with PF and this rule :
Code:
nat on tun0 from 192.168.22.30/32 to any -> (tun0)
with no luck.
This works only if I add on FreeBSD router route : add route 8.8.8.8 10.8.0.1, then from 192.168.22.30 to 8.8.8.8 I go over NordVPN.
My idea is to route whole traffic over NordVPN from this LAN IP.

Thank you, for any advice.
 
I have FreeBSD 12.1-RELEASE
Upgrade your system, 12.1 is end-of-life and not supported any more.

This works only if I add on FreeBSD router route : add route 8.8.8.8 10.8.0.1, then from 192.168.22.30 to 8.8.8.8 I go over NordVPN.
A firewall is not a router. Routing is done by the OS, so if you want to route specific traffic through the VPN then you'll need to add routes for it. The NAT rule only tells the firewall "If this traffic passes my interface then I need to modify the source address". It doesn't "direct" that traffic to the VPN interface, that's what routes are for.
 
Upgrade your system, 12.1 is end-of-life and not supported any more.


A firewall is not a router. Routing is done by the OS, so if you want to route specific traffic through the VPN then you'll need to add routes for it. The NAT rule only tells the firewall "If this traffic passes my interface then I need to modify the source address". It doesn't "direct" that traffic to the VPN interface, that's what routes are for.
Thanks for reply.
Ok, then i need not nat it, only route traffic from 192.168.22.30 to GW of VPN?
How i can do with PF ?
Best.
 
How i can do with PF ?
A firewall is not a router. Routing is done by the OS, with the route(8) command you can add/remove/change routes.

This is probably more a networking question than a firewall question. You don't seem to understand how TCP/IP traffic flows from point A to point B. You should really read up on it.
 
A firewall is not a router. Routing is done by the OS, with the route(8) command you can add/remove/change routes.

This is probably more a networking question than a firewall question. You don't seem to understand how TCP/IP traffic flows from point A to point B. You should really read up on it.
Thanks for ansewer. I understand what you say. But with route i can set route for destination not for source address.
I can make route add 8.8.8.8 10.8.0.1 and all traffic to 8.8.8.8 will go over 10.8.0.1... and is ok.
Only i want to route only one IP from LAN over this GW. And i think, this i can't make with route, only with PF (route-to). Or im wrong ?
Thanks.
 
But with route i can set route for destination not for source address.
TCP/IP routing is done based on the destination address. What you're looking for is called source-based routing, often called policy based routing.

Only i want to route only one IP from LAN over this GW. And i think, this i can't make with route, only with PF (route-to). Or im wrong ?
I think you're in the right direction. You might need to combine it with reply-to though.
Code:
     route-to
           The route-to option routes the packet to the specified interface
           with an optional address for the next hop.  When a route-to rule
           creates state, only packets that pass in the same direction as the
           filter rule specifies will be routed in this way.  Packets passing
           in the opposite direction (replies) are not affected and are routed
           normally.

     reply-to
           The reply-to option is similar to route-to, but routes packets that
           pass in the opposite direction (replies) to the specified
           interface.  Opposite direction is only defined in the context of a
           state entry, and reply-to is useful only in rules that create
           state.  It can be used on systems with multiple external
           connections to route all outgoing packets of a connection through
           the interface the incoming connection arrived through (symmetric
           routing enforcement).
 
TCP/IP routing is done based on the destination address. What you're looking for is called source-based routing, often called policy based routing.


I think you're in the right direction. You might need to combine it with reply-to though.
Code:
     route-to
           The route-to option routes the packet to the specified interface
           with an optional address for the next hop.  When a route-to rule
           creates state, only packets that pass in the same direction as the
           filter rule specifies will be routed in this way.  Packets passing
           in the opposite direction (replies) are not affected and are routed
           normally.

     reply-to
           The reply-to option is similar to route-to, but routes packets that
           pass in the opposite direction (replies) to the specified
           interface.  Opposite direction is only defined in the context of a
           state entry, and reply-to is useful only in rules that create
           state.  It can be used on systems with multiple external
           connections to route all outgoing packets of a connection through
           the interface the incoming connection arrived through (symmetric
           routing enforcement).
Thanks. Im try to get it work... but for now with no luck.
I try add default router 10.8.0.1 on fib1 and change fib only for this ip with PF rtable 1 but this dont work eather ;/
If anyone have this done, please for info. Thanks.
 
Make sure to use tcpdump(1), it's an invaluable tool in situations like this because it really helps if you can look at the actual packets instead of having to guess if things work or not.
 
I do something similar in my setup, i.e. route traffic from a specific VLAN out over an OpenVPN client connection.
  • Add marcos in your pf.conf file for the LAN and VPN interfaces:
    • lan_home_if = "em0"
    • vpn_if = "tun0"
  • Add a macro for the VPN connection to be used as a gateway:
    • GW_VPN = "( tun0 10.8.0.1 )"
  • Add a PF rule to allow outbound traffic from the firewall device itself out to the Internet:
    • pass out route-to $GW_VPN from ($vpn_if) to ! $vpn_if:network keep state allow-opts
  • Add a PF rule to route all traffic originating on the em0 interface over the VPN connection:
    • pass in quick on $lan_home_if route-to $GW_VPN inet from 192.168.22.30/32 to any keep state
 
I do something similar in my setup, i.e. route traffic from a specific VLAN out over an OpenVPN client connection.
  • Add marcos in your pf.conf file for the LAN and VPN interfaces:
    • lan_home_if = "em0"
    • vpn_if = "tun0"
  • Add a marco for the VPN connection to be used as a gateway:
    • GW_VPN = "( tun0 10.8.0.1 )"
  • Add a PF rule to allow outbound traffic from the firewall device itself out to the Internet:
    • pass out route-to $GW_VPN from ($vpn_if) to ! $vpn_if:network keep state allow-opts
  • Add a PF rule to route all traffic originating on the em0 interface over the VPN connection:
    • pass in quick on $lan_home_if route-to $GW_VPN inet from 192.168.22.30/32 to any keep state
Great, i test it today. Thanks!
Can i set GW_VPN = "(tun0)", this 10.8.0.1 is dynamic address, and not always will be 10.8.0.1
 
I do something similar in my setup, i.e. route traffic from a specific VLAN out over an OpenVPN client connection.
  • Add marcos in your pf.conf file for the LAN and VPN interfaces:
    • lan_home_if = "em0"
    • vpn_if = "tun0"
  • Add a macro for the VPN connection to be used as a gateway:
    • GW_VPN = "( tun0 10.8.0.1 )"
  • Add a PF rule to allow outbound traffic from the firewall device itself out to the Internet:
    • pass out route-to $GW_VPN from ($vpn_if) to ! $vpn_if:network keep state allow-opts
  • Add a PF rule to route all traffic originating on the em0 interface over the VPN connection:
    • pass in quick on $lan_home_if route-to $GW_VPN inet from 192.168.22.30/32 to any keep state
nordvpn_if="tun1"
gw_nordvpn="( tun1 10.8.0.1 )"

pass out route-to $gw_nordvpn from ($nordvpn_if) to !$nordvpn_if:network keep state allow-opts
pass in quick on $prv_if route-to $gw_nordvpn inet from 192.168.22.30/32 to any keep state

I have noticed two problems
1. 10.8.0.1 is dynamic, sometimes is 10.8.0.1, another time 10.8.4.1 etc. Is any macro to set this to pf.config ?
tun1: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> metric 0 mtu 1500
options=80000<LINKSTATE>
inet 10.8.0.6 --> 10.8.0.1 netmask 0xffffff00
groups: tun
nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
Opened by PID 8280

2. When i run this i see with tcpdump that all trafic from 22.30 is send over tun1 but nothing comes back. Internet stops working.
I solve this with add, but i dont know that is correct. After add this nat, internet on 22.30 works ok, over the nordVPN

nat on tun1 from 192.168.22.30/32 to any -> (tun1)

Thanks for help!
 
nordvpn_if="tun1"
gw_nordvpn="( tun1 10.8.0.1 )"

pass out route-to $gw_nordvpn from ($nordvpn_if) to !$nordvpn_if:network keep state allow-opts
pass in quick on $prv_if route-to $gw_nordvpn inet from 192.168.22.30/32 to any keep state

I have noticed two problems
1. 10.8.0.1 is dynamic, sometimes is 10.8.0.1, another time 10.8.4.1 etc. Is any macro to set this to pf.config ?


2. When i run this i see with tcpdump that all trafic from 22.30 is send over tun1 but nothing comes back. Internet stops working.
I solve this with add, but i dont know that is correct. After add this nat, internet on 22.30 works ok, over the nordVPN



Thanks for help!

Yes, your NAT rule looks correct.

nat on $nordvpn_if inet from 192.168.22.30 to any -> ($nordvpn_if)

In my configuration, I have root access to the VPN server and used a CCD rule to assign a static IP address to the client. In your case, I would probably write a script that updates the value in your pf.conf file. I haven't tested this pseudo code, but you could call something like this when your tunnel connects (via an OpenVPN "up" script) to automatically update your gateway address:

Code:
#!/usr/local/bin/bash
PFCONF='/path/to/pf.conf'
TUNIP=$(ifconfig tun1 | grep 'inet\ ' | cut -d' ' -f2)
sed -i "" "s|gw_nordvpn=\"( tun1.*|gw_nordvpn=\"( tun1 $TUNIP )\"|g" $PFCONF
pfctl -f $PFCONF
 
Yes, your NAT rule looks correct.

nat on $nordvpn_if inet from 192.168.22.30 to any -> ($nordvpn_if)

In my configuration, I have root access to the VPN server and used a CCD rule to assign a static IP address to the client. In your case, I would probably write a script that updates the value in your pf.conf file. I haven't tested this pseudo code, but you could call something like this when your tunnel connects (via an OpenVPN "up" script) to automatically update your gateway address:

Code:
#!/usr/local/bin/bash
PFCONF='/path/to/pf.conf'
TUNIP=$(ifconfig tun1 | grep 'inet\ ' | cut -d' ' -f2)
sed -i "" "s|gw_nordvpn=\"( tun1.*|gw_nordvpn=\"( tun1 $TUNIP )\"|g" $PFCONF
pfctl -f $PFCONF
Thanks. I think about it too, but first want to sure that isnt any macro in pf for this operation ;)
Thank you for help!
 
Hello,

Would you mind publishing a full solution : script and configuration files ? Can you toggle between vpn and no vpn ?
 
Back
Top