Jump to content
Not connected, Your IP: 3.145.7.187
theradgrad

Prevent leaks with *BSD & pf

Recommended Posts

Posted ... (edited)

Greetings! In this guide I'll help walk you through configuring pf to prevent leaks when your OpenVPN connection drops. I'm using OpenBSD 7.6, so all steps should work as-is under that, but other OSes that also use pf, like FreeBSD and macOS, should still be compatible with a few changes in commands to achieve the same result.

 

Setting up the OpenVPN daemon


Before you do anything, I strongly suggest you make a backup of your current /etc/pf.conf and /etc/rc.conf.local like so, in case something doesn't work right for you and you want to revert back to how it was before (you will need [to be careful with your] root privileges to do nearly all of the tasks I discuss):

$ su -
Password:
# cp -p /etc/pf.conf /etc/pf.conf.bak
# cp -p /etc/rc.conf.local /etc/rc.conf.local.bak
# exit
$


Okay!
 

I will assume you already have doas (or sudo) configured (I recommend you do) and will prefix it to the below commands, but if you really don't want to do that, you should be able to su -, as above, for essentially the same result.

From here you should download the OpenVPN command line client and configure it to run in the background (i.e. a "daemon") automatically on startup. On OpenBSD we use pkg_add to add new software:

# pkg_add -U openvpn

If prompted to choose between openvpn-x.x.xx and openvpn-x.x.xx-mbedtls, choose the former unless you face issues.

Create an OpenVPN config file here, and then move it to a typical place:

# mkdir -p /etc/openvpn
# mv -iv /path/to/downloaded/AirVPN-Config.ovpn /etc/openvpn


Enable, configure, and start the openvpn daemon. On OpenBSD we use rcctl for daemon manipulation:

# rcctl enable openvpn
# rcctl set openvpn flags --config /etc/openvpn/AirVPN-Config.ovpn
# rcctl start openvpn

Be sure to use the same OpenVPN config filename as the one you moved in the previous step.

Now that we have OpenVPN's client daemon set up, it's time to create a "kill switch" for it!

 

Configuring a "kill switch" to prevent leaks during OpenVPN disconnects


Edit your /etc/pf.conf (using something like vi) to look similar to mine (I omitted some unrelated/sensitive details):

# Define macros:
ext_if = "bge0" # 1Gb Ethernet interface (physical)
vpn_if = "tun0" # OpenVPN interface (virtual)

# Don't filter on loopback interfaces:
set skip on lo

# Block everything by default (we'll whitelist the VPN exclusively further
# down):
block

# Enforce antispoofing measures:
block in quick from urpf-failed

# From https://dylanharris.org/blog/2017/b28.shtml:

#     I had to turn "pf.conf's" urpf check off. This is a protection to ensure
#     that naughty routing isn't being attempted. When a packet is received,
#     "urpf-check" verifies that, if the sender can be reached by the default
#     route, then any packets returned would use the default route's network
#     interface.
#
#     Unfortunately, this check is defeated by the standard configuration of
#     OpenVPN under OpenBSD. When OpenVPN starts up, it does not change the
#     default route; rather it adds a couple of specialised routes to use the
#     VPN tunnel, routes that happen to cover the entire IPv4 address space. In
#     consequence, any packets that come in on the old interface will fail the
#     urpf check.
#
#     If this is what you want to happen, that all data leaves on the VPN
#     interface, and all other external communication is blocked, then that's
#     good. That, however, is not what I want. I want to maintain contact with
#     my ISP. So I disable the check [by commenting out that line.]
# We most definitely want all data leaving on the VPN interface, and never
# outside it, so it should be enabled in our case.

# Whitelist incoming/outgoing protocol/port connections over LAN:
pass $ext_if proto {tcp udp} from $ext_if:network to $ext_if port 22
# * 22 : SSH
pass in on $ext_if proto icmp from $ext_if:network to any # Ping to this computer from another over LAN.
pass out on $ext_if proto icmp from any to $ext_if:network # Ping from this computer to another over LAN.

# Allow DNS (for server IP lookup):
pass quick proto {tcp udp} from any to any port 53 keep state
# From https://daemonforums.org/showthread.php?t=11666.

# Whitelist VPN IP addresses:
include "/etc/pf.conf.d/vpn_server_ips.conf"
pass on $vpn_if all


To go with our pf.conf, as you might've seen on the second-to-last line of it, I have a file, /etc/pf.conf.d/vpn_server_ips.conf, that stores all of AirVPN's server IPs. You can create one yourself with these commands:

# pkg_add -U curl jq
# mkdir -p /etc/pf.conf.d
# touch /etc/pf.conf.d/vpn_server_ips.conf
# chmod 0600 /etc/pf.conf.d/vpn_server_ips.conf
# chmod 0700 /etc/pf.conf.d


To fill/update it, just run this every-so-often (please DO NOT SPAM):

# curl -so- 'https://airvpn.org/api/status/' |
jq -r '
    .servers[] |
    .public_name as $server | .location as $city | .country_name as $country | .continent as $continent |
    to_entries |
    map(select(.key | test("^ip_v[46]_in[0-9]+$"))) |
    map(select(.value != null)) |
    map(select(.value |
        test("^(((25[0-5]|(2[0-4]|1[0-9]|[1-9]|)[0-9])\\.){3}(25[0-5]|(2[0-4]|1[0-9]|[1-9]|)[0-9])|([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$")
    )) |
    .[] |
    "pass out on $ext_if proto {tcp udp} from any to \(.value) # AirVPN (\($server)) - \($city), \($country), \($continent)"
')" > /etc/pf.conf.d/vpn_server_ips.conf

This step will require su - in particular so the shell can redirect output to the vpn_server_ips.conf file.

Finally, we use pfctl to apply all of the changes we made to pf.conf. I recommend doing a dry-run first:

# pfctl -nvvf /etc/pf.conf


Looking good? Reload pf with its modified config file (or reboot) if so:

# pfctl -vvf /etc/pf.conf


and if not, you can troubleshoot what went wrong, or simply restore your earlier backups:

# cp -p /etc/pf.conf.bak /etc/pf.conf && pfctl -vvf /etc/pf.conf
# cp -p /etc/rc.conf.local.bak /etc/rc.conf.local && rcctl stop openvpn && rcctl disable openvpn

 

Testing out the "kill switch"


Now it's time to give it a whirl! I have OpenVPN already running in the background via its daemon. Let's first try pinging AirVPN's web site in another terminal emulator window:

$ ping airvpn.org
PING airvpn.org (5.196.64.52): 56 data bytes
64 bytes from 5.196.64.52: icmp_seq=0 ttl=46 time=116.912 ms
64 bytes from 5.196.64.52: icmp_seq=1 ttl=46 time=119.857 ms
64 bytes from 5.196.64.52: icmp_seq=2 ttl=46 time=122.434 ms
...


With that running, let's find openvpn's PID (with pgrep), kill it (with kill), and see what happens:

# pgrep -x openvpn
91357
# kill 91357

 

...
64 bytes from 5.196.64.52: icmp_seq=13 ttl=46 time=118.249 ms
64 bytes from 5.196.64.52: icmp_seq=14 ttl=46 time=123.583 ms
64 bytes from 5.196.64.52: icmp_seq=15 ttl=46 time=121.109 ms
ping: sendmsg: Permission denied
ping: wrote airvpn.org 64 chars, ret=-1
ping: sendmsg: Permission denied
ping: wrote airvpn.org 64 chars, ret=-1
ping: sendmsg: Permission denied


Look at that beauty! Working exactly as expected. :good:

You can start the openvpn daemon again either via doas rcctl restart openvpn or doas openvpn --daemon /etc/openvpn/AirVPN-Config.ovpn.

 

Closing


Thank you to OpenSourcerer for helping steer me in the right direction, and everybody else in the blog posts, forum posts, and URLs I hotlinked in this guide & in my initial thread.

Hopefully this helps out anyone else in a similar situation. Cheers and happy net surfing! Edited ... by theradgrad
Replaced `pkg_add' manpage URL with section-specific one.

Share this post


Link to post
Posted ... (edited)

hello,

thanks for your contribution.

could you write a "How to" on how to cascade vpns (otherwise known as chaining two or more vpn configs) using a distro such as openbsd?

p.s. i tried to send you a pm but you disabled it.

Edited ... by paq4876

Share this post


Link to post

Highly unlikely you will see one. The poster did this guide out of personal interest for that one particular use case.. probably not up to invest time into something he/she doesn't need personally.
And also, don't try to push your wishes onto someone you think may be up to the task just because they demonstrate proficiency with the toolset, and because you want it easy. It comes across as slightly rude. Go out in the world, do your own research and write your own guide; I'm happy to support with pointers to resources across these forums or my own ideas.


NOT AN AIRVPN TEAM MEMBER. USE TICKETS FOR PROFESSIONAL SUPPORT.

LZ1's New User Guide to AirVPN « Plenty of stuff for advanced users, too!

Want to contact me directly? All relevant methods are on my About me page.

Share this post


Link to post

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Security Check
    Play CAPTCHA Audio
    Refresh Image

×
×
  • Create New...