theradgrad 1 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. 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. 1 OpenSourcerer reacted to this Quote Share this post Link to post
paq4876 0 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 Quote Share this post Link to post
OpenSourcerer 1435 Posted ... 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. Quote Hide OpenSourcerer's signature Hide all signatures 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