INTRODUCTION :
___________________________________________________________
___________________________________________________________
Updated 2015 January 04 : see the changelog
After the Snowden whistleblower revelations, we learned that what we could have though of as paranoïa or conspiration, is in fact very true. There is a worlwide automated mass surveillance of citizens, it is not targeted investigations but rather full blown automated privacy violation. We may have guessed it, but until now there wasn't proofs or facts to support it. Oh and by the way it is not "just" the USA/NSA surveillance, there is great probabilities that the country you live on is also spying on you. Being a french citizen, I learned that my country is well known for its leading Deep Packet Inspection (DPI) products that it sells to foreign dictators, and that it also spies on its citizens and already provided the NSA enormous ammount of intercepted data. Same goes for the UK, who already accessed part of the NSA's tools for their own purpose, such as spying on Belgium Telecom. I can even mention Sweden who is providing information to the NSA too. Chances are, unfortunately, that no matter where you live, anything you do online is automatically recorded : web surfing, orders, emails, search requests, downloads, and even phone calls and text messages ( including Blackberry). From these last links, it seems that even Germany has its hands on NSA's tool and cooperate with them. So USA, UK, France, Sweden, Germany, who else ?
We may think that well, we will do something about that, but what ? One of the direct answer to automated recording and surveillance is using a Virtual Private Network (VPN). That way, everything going out of your network is encrypted and cannot directly be used to spy on you. Sounds easy, so let's buy a router from a known brand to do it, right ? Unfortunately, NSA can be here too by having probably a backdoor in it allowing them unfeterred access to the router. The last solution is to build your router yourself, based on one of the most secure Operating System (OS) around : OpenBSD.
The search for privacy is not a criminal act, it is a fundamental human right.
DESCRIPTION :
___________________________________________________________
___________________________________________________________
The OpenBSD VPN gateway we'll see soon, brings on the following features :
- DHCP server to distribute network parameters to your LAN
- DNS cache/server to speed up DNS requests
- DNS encryption so that every outgoing request cannot be spied on by your ISP
- VPN gateway to your VPN provider (AirVPN is used on this article)
- Watchdog script to check that your connection is secure (VPN and DNS encryption are alive)
- Windows software client displaying in the taskbar information sent by the Watchdog script (optional)
- Prevents any direct Internet access from the LAN (prevents VPN bypass)
- Intercept DNS leaks from the LAN to the Internet, and redirect them to the local DNSCypt.
It could be sume up as an encrypted DNS and VPN gateway, with a monitoring script to warn you and self repair itself in case of something is down, to always stay fully encrypted and to ensure that nothing goes out in clear.
- DHCP server to distribute network parameters to your LAN
- DNS cache/server to speed up DNS requests
- DNS encryption so that every outgoing request cannot be spied on by your ISP
- VPN gateway to your VPN provider (AirVPN is used on this article)
- Watchdog script to check that your connection is secure (VPN and DNS encryption are alive)
- Windows software client displaying in the taskbar information sent by the Watchdog script (optional)
- Prevents any direct Internet access from the LAN (prevents VPN bypass)
- Intercept DNS leaks from the LAN to the Internet, and redirect them to the local DNSCypt.
It could be sume up as an encrypted DNS and VPN gateway, with a monitoring script to warn you and self repair itself in case of something is down, to always stay fully encrypted and to ensure that nothing goes out in clear.
PREREQUISITES :
___________________________________________________________
___________________________________________________________
To make an OpenBSD VPN gateway you will need the following :
- A computer with two network cards
- Two Ethernet cables
- An OpenBSD ISO
- A VPN provider subscription, providing raw OpenVPN configuration file
The network map is a typical home network with one or two computers, and one DSL router from the ISP :
I personally bought as computer a Shuttle DS437, which is a fanless and noiseless small case (SSD required), to build a low energy router (10W idle, equivalent to two Raspberry Pi). OpenBSD 5.6-release natively supports RTL8111G (5.5-release did not).
Beforehand, I would like to thanks people from the forum DaemonForums.org as their help was invaluable to sort my network card driver issue, thanks again guys :-) I would like also to thanks the website BSDNow which provides many useful up to date tutorials, such as The ultimate OpenBSD router.
- A computer with two network cards
- Two Ethernet cables
- An OpenBSD ISO
- A VPN provider subscription, providing raw OpenVPN configuration file
The network map is a typical home network with one or two computers, and one DSL router from the ISP :
I personally bought as computer a Shuttle DS437, which is a fanless and noiseless small case (SSD required), to build a low energy router (10W idle, equivalent to two Raspberry Pi). OpenBSD 5.6-release natively supports RTL8111G (5.5-release did not).
Beforehand, I would like to thanks people from the forum DaemonForums.org as their help was invaluable to sort my network card driver issue, thanks again guys :-) I would like also to thanks the website BSDNow which provides many useful up to date tutorials, such as The ultimate OpenBSD router.
SUMMARY :
___________________________________________________________
___________________________________________________________
-
INTRODUCTION
- FIRST START
- FSTAB
- NETWORK CONFIGURATION
- NTP
- DHCP
- FIREWALL
- BUILDING PACKAGES FROM PORTS
- DNS
- VPN
- WATCHDOG SCRIPT(optional)
- WINDOWS CLIENT(optional)
- BEYOND VPN TUNNEL
DESCRIPTION
PREREQUISITES
CONCLUSION
CHANGELOG
LINKS
1. FIRST START
___________________________________________________________
___________________________________________________________
Before using your downloaded ISO, check its SHA256 checksum with a "sha256sum.exe" (Windows) for instance you can find
on the net, or the sha256 file command on OpenBSD.
Once you have booted on the ISO for your architecture, for instance amd64, you just have to answer simple questions to get started, see below.
Please note that supporting the OpenBSD project is very welcome, you can do so by just buying a 3 CDs set, it will help to keep the project kicking.
Below is just an example, you have to enter values according to your country, network card detected name, your ISP DNS, etc... :
Below the sets to choose are in function of the OpenBSD flavor you install. If it is OpenBSD 5.5-release (from the official website or from CD set), you don't need any X packages that you can remove with "-x*" and "enter". If however you either use OpenBSD 5.5-current (from an online snapshot for instance) or that you use a release flavor, but expect to build packages from ports instead of from the "pkg" command line, you will need at least the xbase55.tgz :
Installation should proceed, then at the end :
Install done, you can now log in :
Login with the root account, and modify the sudoer file to allow your user account to use "sudo" :
From now on, you can login with your unprivileged account from SSH and continue the configuration.
If you installed OpenBSD 5.5-release, please apply all available security updates from http://www.openbsd.org/errata55.html. It contains a security fix for the Heartbleed vulnerability.
Once you have booted on the ISO for your architecture, for instance amd64, you just have to answer simple questions to get started, see below.
Please note that supporting the OpenBSD project is very welcome, you can do so by just buying a 3 CDs set, it will help to keep the project kicking.
Below is just an example, you have to enter values according to your country, network card detected name, your ISP DNS, etc... :
(I)nstall, (U)pgrade, (A)utoinstall or (S)hell ? I
Choose your keyboard layout ('?' or 'L' for list) [default] fr
System hostname? (short form, e.g. 'foo') OpenBSD
Which network interface do you wish to configure? (or 'done') [re0] enter
IPv4 address for re0? (or 'dhcp' or 'none') [dhcp] 10.0.0.1
Netmask? [255.255.255.0] enter
IPv6 address for re0? (or 'rtsol' or 'none') [none] enter
Which network interface do you wish to configure? (or 'done') [done] enter
Default IPv4 route? (IPv4 address, 'dhcp' or 'none') 192.168.1.1
DNS domain name? (e.g. 'bar.com') [my.domain] enter
DNS nameservers? (IP address list or 'none') [none] 208.67.222.222
Password for root account? (will not echo) your password !
Start sshd(8) by default? [yes] enter
Start ntpd(8) by default? [no] yes
NTP server? (hostname or 'default') [default] enter
Do you expect to run the X Window System [yes] no
Setup a user? (enter a lower-case loginname, or 'no') [no] guillaume
Full name for user guillaume? [guillaume] enter
Password for user guillaume? (will not echo) your password !
Since you set up a user, disable sshd(8) logins to root? [yes] yes
What timezone are you in? ('?' for list) [Europe/Paris] enter
Which disk is the root disk? ('?' for details) [wd0] enter
Use DUIDs rather than device names in fstab? [yes] enter
Use (W)hole disk ? W
Use (A)uto layout, (E)dit auto layout, or create (C)ustom layout? [a] enter
Location of sets? (cd disk ftp http or 'done') [cd] enter
Which CD-ROM contains the install media? (or 'done') [cd0] enter
Pathname to the sets? (or 'done') [5.5/amd64] enter
Choose your keyboard layout ('?' or 'L' for list) [default] fr
System hostname? (short form, e.g. 'foo') OpenBSD
Which network interface do you wish to configure? (or 'done') [re0] enter
IPv4 address for re0? (or 'dhcp' or 'none') [dhcp] 10.0.0.1
Netmask? [255.255.255.0] enter
IPv6 address for re0? (or 'rtsol' or 'none') [none] enter
Which network interface do you wish to configure? (or 'done') [done] enter
Default IPv4 route? (IPv4 address, 'dhcp' or 'none') 192.168.1.1
DNS domain name? (e.g. 'bar.com') [my.domain] enter
DNS nameservers? (IP address list or 'none') [none] 208.67.222.222
Password for root account? (will not echo) your password !
Start sshd(8) by default? [yes] enter
Start ntpd(8) by default? [no] yes
NTP server? (hostname or 'default') [default] enter
Do you expect to run the X Window System [yes] no
Setup a user? (enter a lower-case loginname, or 'no') [no] guillaume
Full name for user guillaume? [guillaume] enter
Password for user guillaume? (will not echo) your password !
Since you set up a user, disable sshd(8) logins to root? [yes] yes
What timezone are you in? ('?' for list) [Europe/Paris] enter
Which disk is the root disk? ('?' for details) [wd0] enter
Use DUIDs rather than device names in fstab? [yes] enter
Use (W)hole disk ? W
Use (A)uto layout, (E)dit auto layout, or create (C)ustom layout? [a] enter
Location of sets? (cd disk ftp http or 'done') [cd] enter
Which CD-ROM contains the install media? (or 'done') [cd0] enter
Pathname to the sets? (or 'done') [5.5/amd64] enter
Below the sets to choose are in function of the OpenBSD flavor you install. If it is OpenBSD 5.5-release (from the official website or from CD set), you don't need any X packages that you can remove with "-x*" and "enter". If however you either use OpenBSD 5.5-current (from an online snapshot for instance) or that you use a release flavor, but expect to build packages from ports instead of from the "pkg" command line, you will need at least the xbase55.tgz :
Set name(s)? (or 'abort' or 'done') [done] -game55.tgz
Set name(s)? (or 'abort' or 'done') [done] enter
Directory does not contain SHA256.sig. Continue without verification? [no] yes
Set name(s)? (or 'abort' or 'done') [done] enter
Directory does not contain SHA256.sig. Continue without verification? [no] yes
Installation should proceed, then at the end :
Location of sets? (cd disk ftp http or 'done') [done] enter
Time appears wrong. Set to 'xxx xxx x xx:xx:xx xxxx 2014'? [yes] enter
# reboot
Time appears wrong. Set to 'xxx xxx x xx:xx:xx xxxx 2014'? [yes] enter
# reboot
Install done, you can now log in :
Login with the root account, and modify the sudoer file to allow your user account to use "sudo" :
# visudo
# Uncomment to allow people in group wheel to run all commands
# and set environment variables.
%wheel ALL=(ALL) SETENV: ALL
# and set environment variables.
%wheel ALL=(ALL) SETENV: ALL
From now on, you can login with your unprivileged account from SSH and continue the configuration.
If you installed OpenBSD 5.5-release, please apply all available security updates from http://www.openbsd.org/errata55.html. It contains a security fix for the Heartbleed vulnerability.
2. FSTAB
___________________________________________________________
___________________________________________________________
It is a good idea to add in the fstab file the mount options "softdep" and "noatime". The first one increase disk performances,
while the second will prevent the "last access time" file properties to be written. While it also allows to increase disk speed, it is above all interesting for SSD drives to avoid writing
too often to them (which reduces their lifetime).
$ sudo vi /etc/fstab
YourDiskDUID.b none swap sw
YourDiskDUID.a / ffs rw,noatime,softdep 1 1
YourDiskDUID.k /home ffs rw,nodev,nosuid,noatime,softdep 1 2
YourDiskDUID.d /tmp ffs rw,nodev,nosuid,noatime,softdep 1 2
YourDiskDUID.f /usr ffs rw,nodev,noatime,softdep 1 2
YourDiskDUID.g /usr/X11R6 ffs rw,nodev,noatime,softdep 1 2
YourDiskDUID.h /usr/local ffs rw,nodev,noatime,softdep 1 2
YourDiskDUID.j /usr/obj ffs rw,nodev,nosuid,noatime,softdep 1 2
YourDiskDUID.i /usr/src ffs rw,nodev,nosuid,noatime,softdep 1 2
YourDiskDUID.e /var ffs rw,nodev,nosuid,noatime,softdep 1 2
YourDiskDUID.a / ffs rw,noatime,softdep 1 1
YourDiskDUID.k /home ffs rw,nodev,nosuid,noatime,softdep 1 2
YourDiskDUID.d /tmp ffs rw,nodev,nosuid,noatime,softdep 1 2
YourDiskDUID.f /usr ffs rw,nodev,noatime,softdep 1 2
YourDiskDUID.g /usr/X11R6 ffs rw,nodev,noatime,softdep 1 2
YourDiskDUID.h /usr/local ffs rw,nodev,noatime,softdep 1 2
YourDiskDUID.j /usr/obj ffs rw,nodev,nosuid,noatime,softdep 1 2
YourDiskDUID.i /usr/src ffs rw,nodev,nosuid,noatime,softdep 1 2
YourDiskDUID.e /var ffs rw,nodev,nosuid,noatime,softdep 1 2
3. NETWORK CONFIGURATION
___________________________________________________________
___________________________________________________________
We now need to check or modify our network card IP addresses, and enable forwarding. Please adapt the following to your network card names, and your network class.
In my example, there is the LAN network 10.0.0.0/24 with OpenBSD being 10.0.0.1, and the other side with the ISP router is 192.168.1.0/24 with OpenBSD being 192.168.1.2.
Check your gateway is correct :
Enable forwarding to allow your LAN traffic to pass trough your new OpenBSD router :
$ sudo vi /etc/hostname.re0
inet 10.0.0.1 255.255.255.0
$ sudo vi /etc/hostname.re1
inet 192.168.1.2 255.255.255.0
Check your gateway is correct :
$ cat /etc/mygate
192.168.1.1
192.168.1.1
Enable forwarding to allow your LAN traffic to pass trough your new OpenBSD router :
$ sudo vi /etc/sysctl.conf
net.inet.ip.forwarding=1
4. NTP
___________________________________________________________
___________________________________________________________
NTP should have been enabled at setup, if you followed the setup example. Having a router with a correct time and date is always handy when you need to check your logs to see what happened.
Here we just need to quickly check that the ntp client is enabled.
Create ntpd.conf
If NTP was not started at boot, enable it now :
That's it !
$ sudo vi /etc/rc.conf.local
# Starting NTP client
ntpd_flags=""
ntpd_flags=""
Create ntpd.conf
$ sudo vi /etc/ntpd.conf
servers pool.ntp.org
If NTP was not started at boot, enable it now :
$ sudo ntpd -s
That's it !
5. DHCP
___________________________________________________________
___________________________________________________________
We want to provide network configuration to make use of our VPN gateway to our LAN network, as well as pointing to our DNS cache. Advertising ourself on the network will allow
VPN-incapable devices to make use of the VPN like any computer. It is also a seamless way to provide traffic encryption to your LAN computers without modifying their configuration.
First, make sure DHCP will run at startup :
Modify DHCP configuration :
First, make sure DHCP will run at startup :
$ sudo vi /etc/rc.conf.local
# Start DHCP server
dhcpd_flags="re0"
dhcpd_flags="re0"
Modify DHCP configuration :
$ sudo mv /etc/dhcpd.conf /etc/dhcpd.conf.orig
$ sudo vi /etc/dhcpd.conf
$ sudo vi /etc/dhcpd.conf
option domain-name-servers 10.0.0.1;
subnet 10.0.0.0 netmask 255.255.255.0 {
option routers 10.0.0.1;
range 10.0.0.10 10.0.0.20;
}
subnet 10.0.0.0 netmask 255.255.255.0 {
option routers 10.0.0.1;
range 10.0.0.10 10.0.0.20;
}
6. FIREWALL
___________________________________________________________
___________________________________________________________
Here is the main part of our router. We will decide which traffic to forward, normalize the traffic, randomize IP or TCP ID fields, catch DNS leaks, prevent VPN bypass, and so one. I propose
below three different PF configuration. The first one should be used as a temporary one, to check your setup and ensure forwarding is working correctly, and eventually check your VPN. The
configurations 2 and 3 are more advanced and are the real pf rules. They both do the same things, but one is rule based, while the other one is policy based.
First PF simple configuration rules, to first check your connectivity to the Internet:
This second PF configuration is more complete, it does more and and covers more cases. This one is still a "rule based" configuration :
This third PF configuration is the same as above, but "policy based". It means we are in a first time applying internal "tags" to packets, basing then in a second time our filtering on them. The tags help creating policies, and when correctly used, enable us to create trust between two interfaces. For instance, if a packet comes to the LAN side, and is aimed at a remote address, we can tag it as "LAN_FORWARD". Then, when an outbound packet wants to go out of the egress interface, we can check if it has the tag or not, ensuring it belongs to the "LAN_FORWARD" trusted flow. Policy based filtering is not necessarily better, in fact it's easy to misapply tags, and have a packet tagged more than once (thus losing its first tag) and being blocked involuntarily. It's just a matter of taste I guess, and personally I prefer this version.
Also this more advanced version allows you to tag traffic you do not want to go into your VPN interface. Indeed the VPN tunnel being the default route, if you want to connect to your ISP router HTTP interface for instance, it won't connect because you traffic will be routed inside the tunnel. With this ruleset, you can mark any traffic you like with the NO_VPN tag, which will automatically be routed to your egress interface instead of tun0. Finally, we tweak the priority of outgoing UDP 443 traffic (VPN and dnscrypt) to have a greater priority (6) than default traffic (3). With just this tiny modification, I gained an avereage of 20KB/s in my download speed on a 10Mbps connection (1200KB/s max download):
The "label" added in this third pf ruleset allows for a statistical view, to check which rule has been matched, and how many times. First number is only the number of time the rule has been evaluated:
The LAN_FORWARD and RDR_LAN_DNS_LEAK could have been triggered when I was terminating the VPN to check I was effectively cut off the Internet. When VPN is down, the default route becomes the ISP router again, not the virtual TUN adapter, and traffic tries naturally to go out.
You can make your own ruleset, it has not to be only rule based or policy base, you can start on a rule based ruleset, add one or two relevant tags, and just one label on a rule you want to keep an eye on. Feel free to be creative :-)
First PF simple configuration rules, to first check your connectivity to the Internet:
$ sudo vi /etc/pf.conf
# VERSION 1 : basic NAT #
lan_if="re0"
set skip on lo
set loginterface egress
match in all scrub (no-df max-mss 1440)
match out on egress from !(egress:network) to any nat-to (egress:0)
match out on tun0 from !(tun0:network) to any nat-to (tun0:0)
pass out quick on egress keep state
pass out quick on tun0 keep state
pass in quick on $lan_if inet
block # block everything else
lan_if="re0"
set skip on lo
set loginterface egress
match in all scrub (no-df max-mss 1440)
match out on egress from !(egress:network) to any nat-to (egress:0)
match out on tun0 from !(tun0:network) to any nat-to (tun0:0)
pass out quick on egress keep state
pass out quick on tun0 keep state
pass in quick on $lan_if inet
block # block everything else
This second PF configuration is more complete, it does more and and covers more cases. This one is still a "rule based" configuration :
$ sudo vi /etc/pf.conf
# VERSION 2 : more advanced firewall, VPN out only, no tags #
# Variables, Macro, and Tables
lan="re0"
lan_ip="10.0.0.1"
egress_ip="192.168.1.2"
vpn="tun0"
# Global Policy
block log all
set block-policy drop
set loginterface egress
set skip on lo
match in all scrub (no-df max-mss 1440 random-id reassemble tcp)
# NAT rules
match out on $vpn from $lan:network to any nat-to ($vpn:0)
# Antispoof
antispoof log quick for (egress)
block in quick log on egress from { no-route urpf-failed } to any
block out quick log on egress from any to no-route
# Block IPV6
block quick inet6 all
# Prevent VPN bypass
block out quick log on egress from $lan:network to any
# Drop outbound DNS requests (53), as we use DNSCrypt
block out quick log on egress proto { tcp udp } from any to any port 53
# Redirect DNS leaks from the LAN, to ourself
pass in quick log on $lan proto { tcp udp } from $lan:network to ! $lan_ip port 53 rdr-to $lan_ip
# Modify IP Type Of Service to speed up DNS and VPN traffic
match out on egress proto udp from $egress_ip to any port 443 set tos lowdelay set prio 6
# Standard rules
pass out quick inet modulate state
pass in quick on $lan
# Variables, Macro, and Tables
lan="re0"
lan_ip="10.0.0.1"
egress_ip="192.168.1.2"
vpn="tun0"
# Global Policy
block log all
set block-policy drop
set loginterface egress
set skip on lo
match in all scrub (no-df max-mss 1440 random-id reassemble tcp)
# NAT rules
match out on $vpn from $lan:network to any nat-to ($vpn:0)
# Antispoof
antispoof log quick for (egress)
block in quick log on egress from { no-route urpf-failed } to any
block out quick log on egress from any to no-route
# Block IPV6
block quick inet6 all
# Prevent VPN bypass
block out quick log on egress from $lan:network to any
# Drop outbound DNS requests (53), as we use DNSCrypt
block out quick log on egress proto { tcp udp } from any to any port 53
# Redirect DNS leaks from the LAN, to ourself
pass in quick log on $lan proto { tcp udp } from $lan:network to ! $lan_ip port 53 rdr-to $lan_ip
# Modify IP Type Of Service to speed up DNS and VPN traffic
match out on egress proto udp from $egress_ip to any port 443 set tos lowdelay set prio 6
# Standard rules
pass out quick inet modulate state
pass in quick on $lan
This third PF configuration is the same as above, but "policy based". It means we are in a first time applying internal "tags" to packets, basing then in a second time our filtering on them. The tags help creating policies, and when correctly used, enable us to create trust between two interfaces. For instance, if a packet comes to the LAN side, and is aimed at a remote address, we can tag it as "LAN_FORWARD". Then, when an outbound packet wants to go out of the egress interface, we can check if it has the tag or not, ensuring it belongs to the "LAN_FORWARD" trusted flow. Policy based filtering is not necessarily better, in fact it's easy to misapply tags, and have a packet tagged more than once (thus losing its first tag) and being blocked involuntarily. It's just a matter of taste I guess, and personally I prefer this version.
Also this more advanced version allows you to tag traffic you do not want to go into your VPN interface. Indeed the VPN tunnel being the default route, if you want to connect to your ISP router HTTP interface for instance, it won't connect because you traffic will be routed inside the tunnel. With this ruleset, you can mark any traffic you like with the NO_VPN tag, which will automatically be routed to your egress interface instead of tun0. Finally, we tweak the priority of outgoing UDP 443 traffic (VPN and dnscrypt) to have a greater priority (6) than default traffic (3). With just this tiny modification, I gained an avereage of 20KB/s in my download speed on a 10Mbps connection (1200KB/s max download):
$ sudo vi /etc/pf.conf
# VARIABLES, MACRO, AND TABLES
# ---------------------------------------------------------------------------------------
egress="re1"
lan="re0"
vpn="tun0"
lan_ip="10.0.0.1"
egress_ip="192.168.1.2"
gateway="192.168.1.1"
all_networks="0.0.0.0/0"
table <internet> const { $all_networks, !self, !$lan:network, !egress:network }
table <lan> const { $lan:network, !self }
table <myself> const { self }
# GLOBAL POLICY
# ---------------------------------------------------------------------------------------
block log all
set block-policy drop
set loginterface egress
set skip on lo
match in all scrub (no-df max-mss 1440 random-id reassemble tcp)
# TRAFFIC TAG
# ---------------------------------------------------------------------------------------
# POLICY ENFORCEMENT
# ---------------------------------------------------------------------------------------
# NAT & Type of Service & Traffic Priority
match out tagged VPN_OUT nat-to ($vpn)
match out tagged NO_VPN_OUT nat-to egress
match out tagged DNSVPN_OUT set tos lowdelay set prio 6
# Blocking spoofed or malformed packets, and IPv6
antispoof log quick for egress label "block_spoofing"
block quick log tagged BAD_PACKET label "block_bad_packet"
block quick log tagged IPV6 label "block_ipv6"
# Prevent lan VPN bypass
block out quick log on egress tagged LAN_FORWARD label "block_lan_forward"
# Redirect DNS leaks from the LAN, and drop outbound DNS requests (53) as we use dnscrypt (443)
pass in quick tagged LAN_DNS_LEAK rdr-to $lan_ip label "rdr_lan_dns_leak"
block out quick log tagged GW_DNS_LEAK label "block_gw_dns_leak"
# Standard rules
pass out quick modulate state
pass in quick tagged LAN_IN
pass in quick tagged LAN_FORWARD
# This rule avoid the VPN tunnel and route traffic to the egress interface
pass in quick tagged NO_VPN route-to ($egress $gateway)
# Do not Log network noise
block in quick proto udp to port { netbios-ns netbios-dgm }
# ---------------------------------------------------------------------------------------
egress="re1"
lan="re0"
vpn="tun0"
lan_ip="10.0.0.1"
egress_ip="192.168.1.2"
gateway="192.168.1.1"
all_networks="0.0.0.0/0"
table <internet> const { $all_networks, !self, !$lan:network, !egress:network }
table <lan> const { $lan:network, !self }
table <myself> const { self }
# GLOBAL POLICY
# ---------------------------------------------------------------------------------------
block log all
set block-policy drop
set loginterface egress
set skip on lo
match in all scrub (no-df max-mss 1440 random-id reassemble tcp)
# TRAFFIC TAG
# ---------------------------------------------------------------------------------------
match in on $lan from <lan> to $lan_ip match in on $lan from <lan> to <internet> match in on $lan proto tcp from <lan> to $gateway port http match in on $lan proto { tcp udp } from <lan> to ! $lan_ip port domain match out on egress proto { tcp udp } from <myself> to <internet> port domain match out on egress tagged NO_VPN match out on egress proto udp from $egress_ip to <internet> port https match out on $vpn from <myself> to <internet> match out on $vpn tagged LAN_FORWARD match in on egress from { no-route urpf-failed } to any match out on egress from any to no-route match inet6 all |
   tag LAN_IN    tag LAN_FORWARD    tag NO_VPN    tag LAN_DNS_LEAK    tag GW_DNS_LEAK    tag NO_VPN_OUT    tag DNSVPN_OUT    tag VPN_OUT    tag VPN_OUT    tag BAD_PACKET    tag BAD_PACKET    tag IPV6 |
# POLICY ENFORCEMENT
# ---------------------------------------------------------------------------------------
# NAT & Type of Service & Traffic Priority
match out tagged VPN_OUT nat-to ($vpn)
match out tagged NO_VPN_OUT nat-to egress
match out tagged DNSVPN_OUT set tos lowdelay set prio 6
# Blocking spoofed or malformed packets, and IPv6
antispoof log quick for egress label "block_spoofing"
block quick log tagged BAD_PACKET label "block_bad_packet"
block quick log tagged IPV6 label "block_ipv6"
# Prevent lan VPN bypass
block out quick log on egress tagged LAN_FORWARD label "block_lan_forward"
# Redirect DNS leaks from the LAN, and drop outbound DNS requests (53) as we use dnscrypt (443)
pass in quick tagged LAN_DNS_LEAK rdr-to $lan_ip label "rdr_lan_dns_leak"
block out quick log tagged GW_DNS_LEAK label "block_gw_dns_leak"
# Standard rules
pass out quick modulate state
pass in quick tagged LAN_IN
pass in quick tagged LAN_FORWARD
# This rule avoid the VPN tunnel and route traffic to the egress interface
pass in quick tagged NO_VPN route-to ($egress $gateway)
# Do not Log network noise
block in quick proto udp to port { netbios-ns netbios-dgm }
The "label" added in this third pf ruleset allows for a statistical view, to check which rule has been matched, and how many times. First number is only the number of time the rule has been evaluated:
$ sudo pfctl -s label
BLOCK_SPOOFING 132827 0 0 0 0 0 0 0
BLOCK_SPOOFING 123423 0 0 0 0 0 0 0
BLOCK_BAD_PACKET 132827 2 616 2 616 0 0 0
BLOCK_IPV6 132825 0 0 0 0 0 0 0
BLOCK_LAN_FORWARD 132825 81 4140 0 0 81 4140 0
RDR_LAN_DNS_LEAK 132744 60 4429 30 2046 30 2383 30
BLOCK_DNS_OUT 1452 0 0 0 0 0 0 0
BLOCK_SPOOFING 132827 0 0 0 0 0 0 0
BLOCK_SPOOFING 123423 0 0 0 0 0 0 0
BLOCK_BAD_PACKET 132827 2 616 2 616 0 0 0
BLOCK_IPV6 132825 0 0 0 0 0 0 0
BLOCK_LAN_FORWARD 132825 81 4140 0 0 81 4140 0
RDR_LAN_DNS_LEAK 132744 60 4429 30 2046 30 2383 30
BLOCK_DNS_OUT 1452 0 0 0 0 0 0 0
The LAN_FORWARD and RDR_LAN_DNS_LEAK could have been triggered when I was terminating the VPN to check I was effectively cut off the Internet. When VPN is down, the default route becomes the ISP router again, not the virtual TUN adapter, and traffic tries naturally to go out.
You can make your own ruleset, it has not to be only rule based or policy base, you can start on a rule based ruleset, add one or two relevant tags, and just one label on a rule you want to keep an eye on. Feel free to be creative :-)
7. BUILDING PACKAGES FROM PORTS
___________________________________________________________
___________________________________________________________
If you installed the "release" flavor, which is recommended, then this step is much more simple. For instance, if you want to install any packages I will talk about, just do (first line once) :
Choose your own mirror at : http://www.openbsd.org/ftp.html, then you can skip this chapter.
Besides the fact that using packages is easy, you can in addition rely on M:Tier for security update notifications, and security binary packages. Usually, when you have a release version, third party packages (not in base system) updated with security fix are only available in stable and current version, not in release. That requires to download ports sources as below, and to build your packages just to have the packages security fixes. Thanks to M:Tier, you can keep your release version and only use the "pkg_add" command line, and download packages binary security fixes from them.
However if you had to install the "current" flavor, we have to pull the ports sources, and then build it. I'm not an expert in this area, downloading only "ports" sources may be enough, but in case a port needs librairies in other sources too (sys, X11) I download them all. Choose your CVS server first http://www.openbsd.org/anoncvs.html#CVSROOT
Later if you want to update your sources :
If you look for a particular port :
Now let's build our packages. It can take a while :
If your current system and ports sources are in sync, and that you installed the X11 librairies while first installing OpenBSD on your router, it shouldn't have any error here.
$ export PKG_PATH=ftp://ftp.openbsd.org/pub/OpenBSD/5.6/packages/amd64/
$ sudo pkg_add package1 package2 ...
# Example if you installed the RELEASE version
$ sudo pkg_add dnscrypt-proxy openvpn
$ sudo pkg_add package1 package2 ...
# Example if you installed the RELEASE version
$ sudo pkg_add dnscrypt-proxy openvpn
Choose your own mirror at : http://www.openbsd.org/ftp.html, then you can skip this chapter.
Besides the fact that using packages is easy, you can in addition rely on M:Tier for security update notifications, and security binary packages. Usually, when you have a release version, third party packages (not in base system) updated with security fix are only available in stable and current version, not in release. That requires to download ports sources as below, and to build your packages just to have the packages security fixes. Thanks to M:Tier, you can keep your release version and only use the "pkg_add" command line, and download packages binary security fixes from them.
However if you had to install the "current" flavor, we have to pull the ports sources, and then build it. I'm not an expert in this area, downloading only "ports" sources may be enough, but in case a port needs librairies in other sources too (sys, X11) I download them all. Choose your CVS server first http://www.openbsd.org/anoncvs.html#CVSROOT
$ cd /usr
$ export CVSROOT=anoncvs@anoncvs.comstyle.com:/cvs
$ sudo cvs -d$CVSROOT checkout -P src
$ sudo cvs -d$CVSROOT checkout -P ports
$ sudo cvs -d$CVSROOT checkout -P sys
$ sudo cvs -d$CVSROOT checkout -P xenocara
$ sudo cvs -d$CVSROOT checkout -P X11
$ export CVSROOT=anoncvs@anoncvs.comstyle.com:/cvs
$ sudo cvs -d$CVSROOT checkout -P src
$ sudo cvs -d$CVSROOT checkout -P ports
$ sudo cvs -d$CVSROOT checkout -P sys
$ sudo cvs -d$CVSROOT checkout -P xenocara
$ sudo cvs -d$CVSROOT checkout -P X11
Later if you want to update your sources :
$ cd /usr/src (OR ports,sys, X11, etc...)
$ sudo cvs -q up -Pd
$ sudo cvs -q up -Pd
If you look for a particular port :
$ cd /usr/ports
$ make search key=your_port
$ make search key=your_port
Now let's build our packages. It can take a while :
$ cd /usr/ports/net/dnscrypt-proxy
$ sudo make install
$ cd /usr/ports/net/openvpn
$ sudo make install
$ sudo make install
$ cd /usr/ports/net/openvpn
$ sudo make install
If your current system and ports sources are in sync, and that you installed the X11 librairies while first installing OpenBSD on your router, it shouldn't have any error here.
8. DNS
___________________________________________________________
___________________________________________________________
Now that DNSCrypt is installed, we can configure it to run at startup and to listen on localhost port 40, and use a dnscrypt server :
Please note that OpenDNS is a US company, and that their servers by default are logging. If for any reason you do not wish to trust OpenDNS, you may choose another logless dnscrypt-enabled DNS resolver at the following list. For instance, if you prefer using a logless EU based server, located in Denmark, you can modify the "-R opendns" parameter by "-R dnscrypt.eu-dk", like we just did. If you choose to do so, please modify this parameter accordingly in /etc/rc.conf.local and in the commands below. Also be informed that the watchdog script won't be able to check that dns requests are encrypted if you choose something else than "opendns", as the other dns resolvers do not provide (to my knowledge) an online dns check.
Start it now and check it is launched :
DNSCrypt won't be directly accessed by the LAN. Our local DNS cache/handler, Unbound, will. It will forward queries to DNSCrypt if it does not have the answer in its cache:
Do not forget to modify your /etc/resolv.conf and to replace the whole file by just one line :
Enable Unbound to launch at startup :
if Unbound is not started, start it and test that your DNS chain is working :
We can finally move on to the next step : VPN :-)
$ sudo vi /etc/rc.local
# DNSCrypt-proxy
/usr/local/sbin/dnscrypt-proxy -a 127.0.0.1:40 -u _dnscrypt-proxy -d -R dnscrypt.eu-dk
/usr/local/sbin/dnscrypt-proxy -a 127.0.0.1:40 -u _dnscrypt-proxy -d -R dnscrypt.eu-dk
Please note that OpenDNS is a US company, and that their servers by default are logging. If for any reason you do not wish to trust OpenDNS, you may choose another logless dnscrypt-enabled DNS resolver at the following list. For instance, if you prefer using a logless EU based server, located in Denmark, you can modify the "-R opendns" parameter by "-R dnscrypt.eu-dk", like we just did. If you choose to do so, please modify this parameter accordingly in /etc/rc.conf.local and in the commands below. Also be informed that the watchdog script won't be able to check that dns requests are encrypted if you choose something else than "opendns", as the other dns resolvers do not provide (to my knowledge) an online dns check.
Start it now and check it is launched :
$ sudo /usr/local/sbin/dnscrypt-proxy -a 127.0.0.1:40 -u _dnscrypt-proxy -d -R dnscrypt.eu-dk
$ netstat -an | grep 127.0.0.1.40
tcp 0 0 127.0.0.1.40 *.* LISTEN
udp 0 0 127.0.0.1.40 *.*
$ netstat -an | grep 127.0.0.1.40
tcp 0 0 127.0.0.1.40 *.* LISTEN
udp 0 0 127.0.0.1.40 *.*
DNSCrypt won't be directly accessed by the LAN. Our local DNS cache/handler, Unbound, will. It will forward queries to DNSCrypt if it does not have the answer in its cache:
$ sudo vi /var/unbound/etc/unbound.conf
server:
username: _unbound
directory: /var/unbound
chroot: /var/unbound
do-not-query-localhost: no
interface: 10.0.0.1
access-control: 0.0.0.0/0 refuse
access-control: 127.0.0.0/8 allow
access-control: 10.0.0.0/24 allow
hide-identity: yes
hide-version: yes
auto-trust-anchor-file: "/var/unbound/db/root.key"
forward-zone:
name: "." # use for ALL queries
forward-addr: 127.0.0.1@40 # dnscrypt-proxy
username: _unbound
directory: /var/unbound
chroot: /var/unbound
do-not-query-localhost: no
interface: 10.0.0.1
access-control: 0.0.0.0/0 refuse
access-control: 127.0.0.0/8 allow
access-control: 10.0.0.0/24 allow
hide-identity: yes
hide-version: yes
auto-trust-anchor-file: "/var/unbound/db/root.key"
forward-zone:
name: "." # use for ALL queries
forward-addr: 127.0.0.1@40 # dnscrypt-proxy
Do not forget to modify your /etc/resolv.conf and to replace the whole file by just one line :
$ sudo vi /etc/resolv.conf
nameserver 10.0.0.1
Enable Unbound to launch at startup :
$ sudo vi /etc/rc.conf.local
# Unbound
unbound_flags="-c /var/unbound/etc/unbound.conf"
unbound_flags="-c /var/unbound/etc/unbound.conf"
if Unbound is not started, start it and test that your DNS chain is working :
$ pgrep unbound
$ sudo /etc/rc.d/unbound start
$ nslookup openbsd.org
Server: 10.0.0.1
Address: 10.0.0.1#53
Non-authoritative answer:
Name: openbsd.org
Address: 129.128.5.194
$ sudo /etc/rc.d/unbound start
$ nslookup openbsd.org
Server: 10.0.0.1
Address: 10.0.0.1#53
Non-authoritative answer:
Name: openbsd.org
Address: 129.128.5.194
We can finally move on to the next step : VPN :-)
9. VPN
___________________________________________________________
___________________________________________________________
We arrive at the most crucial part : choosing a VPN provider. There is plenty of VPN providers, more than I wish to try. However, if we set criteria like the following, there is not many VPN
providers left:
- logless (do not keep logs !)
- OpenBSD compatible (should support OpenVPN configuration file)
- not based in the US (the NSA is there)
- provides an online OpenVPN config file generator
- displays its servers status in realtime
- accept payments in BitCoins
- provides censorship bypass options, by offering multiple ways to mount the VPN (80/443 UDP/TCP, SSH tunneling, etc...)
- should not drop the connection speed to a crawl ! (Internet experience should stay the same)
- allows trying for a few days cheaply
- should offer servers on various countries
- very secure : 4096 bit RSA, AES-256-CBC, 4096 bit Diffie-Hellman, HMAC SHA1, TLS 2048 bit additional key, Perfect Forward Secrecy (PFS)
I have found such a VPN provider : AirVPN
You are free to use any VPN provider of course, but the setup bellow is a working configuration with AirVPN only. There is many configurations possible, I could have chosen a single remote server, or a country, you can play with their online OpenVPN generator to suit your needs. I have chosen to select 3 servers, the first one is the main I will use, and the two others are backup servers.
Please note that the 3 remote VPN IP addresses I will write from now one are fake/random IP, you cannot copy/paste the configuration as is, you have to modify it accordingly to your remote VPN servers you have chosen.
Create your config directory, I created it on "/usr/local/etc/openvpn" :
Now copy via SSH/SFTP (WinSCP for Windows for instance) the files the AirVPN generator created, below is an example :
In case you did not yet do it :
Launch OpenVPN at startup :
Let's connect !
You can check in "/var/log/message" that your VPN connected without error, then check with "ifconfig" that the interface "tun0" is active, and finally with a "route -n show" check that the route was added.
You can browse with a client to a website such as http://whoer.net/ to check you are going trough your VPN. You can also go to the AirVPN homepage, where it will displays to which VPN server you are connected. You can also do a "traceroute openbsd.org" and see the VPN magic :-)
Now that our OpenVPN is running chrooted, in the event it would misbehave because of a vulnerability, it is a good idea to additionaly enforce a systrace profile on it. Systrace will allow us to define which system calls are allowed or not. While systrace and chroot alone are not considered secure enough, combining chroot, systrace, and privilege revocation, still makes exploitation harder.
To approach systrace, you have to know there is a learning mode in wich a profile/policy file is filled with explicit calls, and an enforce mode which denies any call not allowed in the policy. Once the learning mode has generated its file, you must edit it to make explicit calls more generic (i.e EXPLICIT_IP:53 -> *:53). You can run a systrace learning mode with $ sudo systrace -A /bin/foo which will store the application profile in /home/your_user/.systrace/bin_foo file. Once you edited the profile and moved it to /etc/systrace, you can run the program in enforce mode with $ sudo systrace -a -U /bin/foo (-U argument will use the file located in /etc/systrace).
Below is a working profile I generated. Although it is working on my system, you must test it in learning mode first.
Be aware that learning mode will generate a profile for programs called by openvpn, such as ifconfig and route. Below are the two automatically generated policies I did not modify. If you go trough a learning mode, these files will be created for you. Anyway, for your information:
It can probably be simplified and the calls grouped differently, and it may have to be modified regarding GUID and UID on your system for _openvpn user and group. To test the profile in learning mode:
If everything is working as expected, check your policy file. If nothing new, you can kill openvpn and restart it in enforce mode:
If you want to run it under a systrace policy from the startup, you have to modify the /etc/rc.local file like this:
Your VPN setup is now complete. When OpenVPN starts it drops its privileges from root to the _openvpn user, chroots itself, and runs under a systrace policy.
- logless (do not keep logs !)
- OpenBSD compatible (should support OpenVPN configuration file)
- not based in the US (the NSA is there)
- provides an online OpenVPN config file generator
- displays its servers status in realtime
- accept payments in BitCoins
- provides censorship bypass options, by offering multiple ways to mount the VPN (80/443 UDP/TCP, SSH tunneling, etc...)
- should not drop the connection speed to a crawl ! (Internet experience should stay the same)
- allows trying for a few days cheaply
- should offer servers on various countries
- very secure : 4096 bit RSA, AES-256-CBC, 4096 bit Diffie-Hellman, HMAC SHA1, TLS 2048 bit additional key, Perfect Forward Secrecy (PFS)
I have found such a VPN provider : AirVPN
You are free to use any VPN provider of course, but the setup bellow is a working configuration with AirVPN only. There is many configurations possible, I could have chosen a single remote server, or a country, you can play with their online OpenVPN generator to suit your needs. I have chosen to select 3 servers, the first one is the main I will use, and the two others are backup servers.
Please note that the 3 remote VPN IP addresses I will write from now one are fake/random IP, you cannot copy/paste the configuration as is, you have to modify it accordingly to your remote VPN servers you have chosen.
9.1 - OPENVPN
Create your config directory, I created it on "/usr/local/etc/openvpn" :
$ sudo mkdir -p /usr/local/etc/openvpn
$ sudo chown root:wheel /usr/local/etc/openvpn
$ sudo chown root:wheel /usr/local/etc/openvpn
Now copy via SSH/SFTP (WinSCP for Windows for instance) the files the AirVPN generator created, below is an example :
$ sudo ls /usr/local/etc/openvpn/
airvpn.ovpn ca.crt ta.key user.crt user.key
$ sudo vi /usr/local/etc/openvpn/airvpn.ovpn
airvpn.ovpn ca.crt ta.key user.crt user.key
$ sudo vi /usr/local/etc/openvpn/airvpn.ovpn
client
dev tun
# Depending on what you have chosen, TCP or UDP (not both !)
proto udp
# When there is multiple "remote" options, OpenVPN tries to connect
# in the order the servers are specified
# Country 1 : Server 1 (Main)
remote x.x.x.x 443
# Country 1 : Server 2 (Backup)
remote x.x.x.x 443
# Country 2 : Server 3 (Backup)
remote x.x.x.x 443
# Chroot OpenVPN and drop root privileges (don't forget to "mkdir /var/empty/tmp")
user _openvpn
group _openvpn
chroot /var/empty
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
cipher AES-256-CBC
comp-lzo no
verb 3
explicit-exit-notify 5
# do a chmod 600 on them
ca "/usr/local/etc/openvpn/ca.crt"
cert "/usr/local/etc/openvpn/user.crt"
key "/usr/local/etc/openvpn/user.key"
tls-auth "/usr/local/etc/openvpn/ta.key" 1
dev tun
# Depending on what you have chosen, TCP or UDP (not both !)
proto udp
# When there is multiple "remote" options, OpenVPN tries to connect
# in the order the servers are specified
# Country 1 : Server 1 (Main)
remote x.x.x.x 443
# Country 1 : Server 2 (Backup)
remote x.x.x.x 443
# Country 2 : Server 3 (Backup)
remote x.x.x.x 443
# Chroot OpenVPN and drop root privileges (don't forget to "mkdir /var/empty/tmp")
user _openvpn
group _openvpn
chroot /var/empty
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
cipher AES-256-CBC
comp-lzo no
verb 3
explicit-exit-notify 5
# do a chmod 600 on them
ca "/usr/local/etc/openvpn/ca.crt"
cert "/usr/local/etc/openvpn/user.crt"
key "/usr/local/etc/openvpn/user.key"
tls-auth "/usr/local/etc/openvpn/ta.key" 1
In case you did not yet do it :
$ sudo chmod 600 /usr/local/etc/openvpn/*.*
$ sudo mkdir /var/empty/tmp
$ sudo mkdir /var/empty/tmp
Launch OpenVPN at startup :
$ sudo vi /etc/rc.local
# OpenVPN
/usr/local/sbin/openvpn --config /usr/local/etc/openvpn/airvpn.ovpn --daemon
/usr/local/sbin/openvpn --config /usr/local/etc/openvpn/airvpn.ovpn --daemon
Let's connect !
$ sudo /usr/local/sbin/openvpn --config /usr/local/etc/openvpn/airvpn.ovpn --daemon
You can check in "/var/log/message" that your VPN connected without error, then check with "ifconfig" that the interface "tun0" is active, and finally with a "route -n show" check that the route was added.
You can browse with a client to a website such as http://whoer.net/ to check you are going trough your VPN. You can also go to the AirVPN homepage, where it will displays to which VPN server you are connected. You can also do a "traceroute openbsd.org" and see the VPN magic :-)
9.2 - SYSTRACE
Now that our OpenVPN is running chrooted, in the event it would misbehave because of a vulnerability, it is a good idea to additionaly enforce a systrace profile on it. Systrace will allow us to define which system calls are allowed or not. While systrace and chroot alone are not considered secure enough, combining chroot, systrace, and privilege revocation, still makes exploitation harder.
To approach systrace, you have to know there is a learning mode in wich a profile/policy file is filled with explicit calls, and an enforce mode which denies any call not allowed in the policy. Once the learning mode has generated its file, you must edit it to make explicit calls more generic (i.e EXPLICIT_IP:53 -> *:53). You can run a systrace learning mode with $ sudo systrace -A /bin/foo which will store the application profile in /home/your_user/.systrace/bin_foo file. Once you edited the profile and moved it to /etc/systrace, you can run the program in enforce mode with $ sudo systrace -a -U /bin/foo (-U argument will use the file located in /etc/systrace).
Below is a working profile I generated. Although it is working on my system, you must test it in learning mode first.
$ sudo vi /etc/systrace/usr_local_sbin_openvpn
Policy: /usr/local/sbin/openvpn, Emulation: native
# Global
native-fstat: permit
native-close: permit
native-read: permit
native-munmap: permit
native-sigprocmask: permit
native-__sysctl: permit
native-gettimeofday: permit
native-minherit: permit
native-mquery: permit
native-sigaction: permit
native-getpid: permit
native-sendsyslog: permit
native-issetugid: permit
native-getentropy: permit
native-pread: permit
native-fork: permit
native-exit: permit
native-setsid: permit
native-dup2: permit
native-poll: permit
native-recvfrom: permit
native-write: permit
native-ioctl: permit
native-wait4: permit
native-writev: permit
native-readv: permit
native-sigreturn: permit
native-clock_gettime: permit
# Memory
native-mprotect: prot eq "PROT_READ" then permit
native-mprotect: prot eq "PROT_NONE" then permit
native-mprotect: prot eq "PROT_READ|PROT_WRITE" then permit
native-mmap: prot eq "PROT_READ|PROT_WRITE" then permit
native-mmap: prot eq "PROT_READ" then permit
native-mmap: prot eq "PROT_NONE" then permit
native-mmap: prot eq "PROT_READ|PROT_EXEC" then permit
# File read
native-fsread: filename eq "/var/run/ld.so.hints" then permit
native-fsread: filename match "/usr/local/lib/liblzo2.so.*" then permit
native-fsread: filename match "/usr/lib/libc.so.*" then permit
native-fsread: filename match "/usr/lib/libcrypto.so.*" then permit
native-fsread: filename match "/usr/lib/libssl.so.*" then permit
native-fsread: filename match "/usr/local/etc/openvpn/*" then permit
native-fsread: filename match "/usr/share/zoneinfo/*" then permit
native-fsread: filename eq "/etc/malloc.conf" then permit
native-fsread: filename eq "/usr/share/nls/C/libc.cat" then permit
native-fsread: filename eq "/var/empty" then permit
native-fsread: filename eq "/var/empty/tmp" then permit
native-fsread: filename eq "/etc/resolv.conf" then permit
native-fsread: filename eq "/etc/group" then permit
native-fsread: filename eq "/etc/spwd.db" then permit
native-fsread: filename eq "/<non-existent filename>: /usr/share/nls/C/libc.cat" then permit
native-fsread: filename eq "/<non-existent filename>: /usr/share/nls/C./libc.cat" then permit
# File write
native-fswrite: filename eq "/dev/tun0" then permit
native-fswrite: filename eq "/dev/null" then permit
# Socket operations
native-socket: sockdom eq "AF_INET" and socktype eq "SOCK_DGRAM" then permit
native-socket: sockdom eq "AF_UNKNOWN(17)" and socktype eq "SOCK_RAW" then permit
native-getsockopt: permit
native-setsockopt: permit
native-sendto: sockaddr match "inet-*:443" then permit
# Chroot & Privilege revocation
native-setgroups: permit
native-chdir: filename eq "/" then permit
native-chroot: filename eq "/var/empty" then permit
native-setgid: gid eq "577" then permit
native-setuid: uid eq "577" and uname eq "_openvpn" then permit
# Exec
native-execve: filename eq "/sbin/ifconfig" and argv match "/sbin/ifconfig tun0 * mtu 1500 netmask 255.255.255.255 up -link0" then permit
native-execve: filename eq "/sbin/route" and argv match "/sbin/route add -net * -netmask *" then permit
native-execve: filename eq "/<non-existent filename>: /sbin/route" and argv match "/sbin/route delete -net * -netmask *" then permit
# Process
native-fcntl: cmd eq "F_SETFD" then permit
native-fcntl: cmd eq "F_SETFL" then permit
# Global
native-fstat: permit
native-close: permit
native-read: permit
native-munmap: permit
native-sigprocmask: permit
native-__sysctl: permit
native-gettimeofday: permit
native-minherit: permit
native-mquery: permit
native-sigaction: permit
native-getpid: permit
native-sendsyslog: permit
native-issetugid: permit
native-getentropy: permit
native-pread: permit
native-fork: permit
native-exit: permit
native-setsid: permit
native-dup2: permit
native-poll: permit
native-recvfrom: permit
native-write: permit
native-ioctl: permit
native-wait4: permit
native-writev: permit
native-readv: permit
native-sigreturn: permit
native-clock_gettime: permit
# Memory
native-mprotect: prot eq "PROT_READ" then permit
native-mprotect: prot eq "PROT_NONE" then permit
native-mprotect: prot eq "PROT_READ|PROT_WRITE" then permit
native-mmap: prot eq "PROT_READ|PROT_WRITE" then permit
native-mmap: prot eq "PROT_READ" then permit
native-mmap: prot eq "PROT_NONE" then permit
native-mmap: prot eq "PROT_READ|PROT_EXEC" then permit
# File read
native-fsread: filename eq "/var/run/ld.so.hints" then permit
native-fsread: filename match "/usr/local/lib/liblzo2.so.*" then permit
native-fsread: filename match "/usr/lib/libc.so.*" then permit
native-fsread: filename match "/usr/lib/libcrypto.so.*" then permit
native-fsread: filename match "/usr/lib/libssl.so.*" then permit
native-fsread: filename match "/usr/local/etc/openvpn/*" then permit
native-fsread: filename match "/usr/share/zoneinfo/*" then permit
native-fsread: filename eq "/etc/malloc.conf" then permit
native-fsread: filename eq "/usr/share/nls/C/libc.cat" then permit
native-fsread: filename eq "/var/empty" then permit
native-fsread: filename eq "/var/empty/tmp" then permit
native-fsread: filename eq "/etc/resolv.conf" then permit
native-fsread: filename eq "/etc/group" then permit
native-fsread: filename eq "/etc/spwd.db" then permit
native-fsread: filename eq "/<non-existent filename>: /usr/share/nls/C/libc.cat" then permit
native-fsread: filename eq "/<non-existent filename>: /usr/share/nls/C./libc.cat" then permit
# File write
native-fswrite: filename eq "/dev/tun0" then permit
native-fswrite: filename eq "/dev/null" then permit
# Socket operations
native-socket: sockdom eq "AF_INET" and socktype eq "SOCK_DGRAM" then permit
native-socket: sockdom eq "AF_UNKNOWN(17)" and socktype eq "SOCK_RAW" then permit
native-getsockopt: permit
native-setsockopt: permit
native-sendto: sockaddr match "inet-*:443" then permit
# Chroot & Privilege revocation
native-setgroups: permit
native-chdir: filename eq "/" then permit
native-chroot: filename eq "/var/empty" then permit
native-setgid: gid eq "577" then permit
native-setuid: uid eq "577" and uname eq "_openvpn" then permit
# Exec
native-execve: filename eq "/sbin/ifconfig" and argv match "/sbin/ifconfig tun0 * mtu 1500 netmask 255.255.255.255 up -link0" then permit
native-execve: filename eq "/sbin/route" and argv match "/sbin/route add -net * -netmask *" then permit
native-execve: filename eq "/<non-existent filename>: /sbin/route" and argv match "/sbin/route delete -net * -netmask *" then permit
# Process
native-fcntl: cmd eq "F_SETFD" then permit
native-fcntl: cmd eq "F_SETFL" then permit
Be aware that learning mode will generate a profile for programs called by openvpn, such as ifconfig and route. Below are the two automatically generated policies I did not modify. If you go trough a learning mode, these files will be created for you. Anyway, for your information:
$ sudo vi /etc/systrace/sbin_route
Policy: /sbin/route, Emulation: native
native-__sysctl: permit
native-mmap: prot eq "PROT_READ|PROT_WRITE" then permit
native-mprotect: prot eq "PROT_READ" then permit
native-getrtable: permit
native-getpid: permit
native-geteuid: permit
native-socket: sockdom eq "AF_UNKNOWN(17)" and socktype eq "SOCK_RAW" then permit
native-shutdown: permit
native-write: permit
native-mprotect: prot eq "PROT_READ|PROT_WRITE" then permit
native-fstat: permit
native-fsread: filename eq "/etc/malloc.conf" then permit
native-issetugid: permit
native-getentropy: permit
native-minherit: permit
native-mprotect: prot eq "PROT_NONE" then permit
native-ioctl: permit
native-munmap: permit
native-exit: permit
native-__sysctl: permit
native-mmap: prot eq "PROT_READ|PROT_WRITE" then permit
native-mprotect: prot eq "PROT_READ" then permit
native-getrtable: permit
native-getpid: permit
native-geteuid: permit
native-socket: sockdom eq "AF_UNKNOWN(17)" and socktype eq "SOCK_RAW" then permit
native-shutdown: permit
native-write: permit
native-mprotect: prot eq "PROT_READ|PROT_WRITE" then permit
native-fstat: permit
native-fsread: filename eq "/etc/malloc.conf" then permit
native-issetugid: permit
native-getentropy: permit
native-minherit: permit
native-mprotect: prot eq "PROT_NONE" then permit
native-ioctl: permit
native-munmap: permit
native-exit: permit
$ sudo vi /etc/systrace/sbin_ifconfig
Policy: /sbin/ifconfig, Emulation: native
native-__sysctl: permit
native-mmap: prot eq "PROT_READ|PROT_WRITE" then permit
native-mprotect: prot eq "PROT_READ" then permit
native-socket: sockdom eq "AF_INET" and socktype eq "SOCK_DGRAM" then permit
native-ioctl: permit
native-mprotect: prot eq "PROT_READ|PROT_WRITE" then permit
native-munmap: permit
native-exit: permit
native-__sysctl: permit
native-mmap: prot eq "PROT_READ|PROT_WRITE" then permit
native-mprotect: prot eq "PROT_READ" then permit
native-socket: sockdom eq "AF_INET" and socktype eq "SOCK_DGRAM" then permit
native-ioctl: permit
native-mprotect: prot eq "PROT_READ|PROT_WRITE" then permit
native-munmap: permit
native-exit: permit
It can probably be simplified and the calls grouped differently, and it may have to be modified regarding GUID and UID on your system for _openvpn user and group. To test the profile in learning mode:
$ sudo systrace -A -U /usr/local/etc/openvpn --config /usr/local/etc/openvpn/airvpn.ovpn --daemon
$ tail -f /var/log/messages
$ tail -f /var/log/messages
If everything is working as expected, check your policy file. If nothing new, you can kill openvpn and restart it in enforce mode:
$ sudo pkill openvpn
$ pgrep openvpn
$ sudo systrace -a -U /usr/local/etc/openvpn --config /usr/local/etc/openvpn/airvpn.ovpn --daemon
$ tail -f /var/log/messages
$ pgrep openvpn
$ sudo systrace -a -U /usr/local/etc/openvpn --config /usr/local/etc/openvpn/airvpn.ovpn --daemon
$ tail -f /var/log/messages
If you want to run it under a systrace policy from the startup, you have to modify the /etc/rc.local file like this:
$ sudo vi /etc/rc.local
# OpenVPN
systrace -a -U /usr/local/sbin/openvpn --config /usr/local/etc/openvpn/airvpn.ovpn --daemon
systrace -a -U /usr/local/sbin/openvpn --config /usr/local/etc/openvpn/airvpn.ovpn --daemon
Your VPN setup is now complete. When OpenVPN starts it drops its privileges from root to the _openvpn user, chroots itself, and runs under a systrace policy.
10. WATCHDOG SCRIPT
___________________________________________________________
___________________________________________________________
At this point, you should have a fully working OpenBSD gateway, providing DHCP, DNS cache/encryption, and VPN. However, it is critical to ensure that both DNS encryption and VPN are
constantly operational. If by any chance one is stopped, you should be cut off the internet, but that's not always the case. At first I wasn't preventing LAN to be forwarded and NATed
out on PF rules, it just happened that once the VPN was up, all traffic was going trough it (tun0 interface). One time, VPN disconnected because of tests I was doing, but I still had
internet access, and was sending out clear traffic without knowing it (should not happen with aforementioned PF rulesets). Also, your DNS queries work, fine, but how do you know the encryption
is working ? Once again the previous PF rulesets should ensure that regular DNS requests on TCP/UDP port 53 are blocked, but if anything goes wrong on the DNS queries to OpenDNS (port 443),
it's better to be warned. Finally, if OpenVPN or DNSCrypt-proxy processes crash for any reason, it's better to have a monitoring script to launch them back.
The following Watchdog script is not mandatory for the OpenBSD gateway to work, you could stop here and not going further, but this script is a kind of privacy insurance. You must edit the variables at the start of the script, to add your IP addresses, your network card names, and your three remote VPN servers you are using. This script basically checks that you have network connectivity, then checks OpenVPN is started, if so checks that you are in fact really connected to a VPN, identifies which remote server. Afterwards it goes on checking that dnscrypt-proxy is started, and verifies that DNS queries are really encrypted.
For every check, this script by default can send UDP packets to two Windows computers on the LAN, but it can be one, more, or none. Just edit the "RECEIVER" variables at the beginning, and edit the "send_notification()" function to specify to which computer send notifications, or to not send anything at all. If you choose to let LAN notifications enabled, the Windows client is covered on the next chapter.
I developped this little script to act as a "guardian" out of curiosity, but noticed that even without it the above configuration just works and is very stable. I no longer use this script, that I nonetheless keep in this article to let you an example you can eventually play with to fit your needs.
Now edit the crontab to run it every minute :
You can view the scrip working by checking its log file (example with imaginary VPN server names):
It is best to check the script is covering you in case of OpenVPN crash :
This script by itself, without LAN notifications, reaches its purpose : monitoring and acting automatically to recover a dead process, and keeping you secure. If you also want the LAN notifications, to know your DNS/VPN state from a Windows client, please proceed to the next chapter.
The following Watchdog script is not mandatory for the OpenBSD gateway to work, you could stop here and not going further, but this script is a kind of privacy insurance. You must edit the variables at the start of the script, to add your IP addresses, your network card names, and your three remote VPN servers you are using. This script basically checks that you have network connectivity, then checks OpenVPN is started, if so checks that you are in fact really connected to a VPN, identifies which remote server. Afterwards it goes on checking that dnscrypt-proxy is started, and verifies that DNS queries are really encrypted.
For every check, this script by default can send UDP packets to two Windows computers on the LAN, but it can be one, more, or none. Just edit the "RECEIVER" variables at the beginning, and edit the "send_notification()" function to specify to which computer send notifications, or to not send anything at all. If you choose to let LAN notifications enabled, the Windows client is covered on the next chapter.
I developped this little script to act as a "guardian" out of curiosity, but noticed that even without it the above configuration just works and is very stable. I no longer use this script, that I nonetheless keep in this article to let you an example you can eventually play with to fit your needs.
$ sudo vi /home/guillaume/watchdog.sh
#!/bin/sh
# Watchdog v1.0
# Variables
# -------------------------------------------------------------------------------------
# YOU MUST EDIT THESE VARIABLES BELOW !
LAN_INTERFACE="re0"
EXT_INTERFACE="re1"
VPN_INTERFACE="tun0"
VPN_SERVER_1="x.x.x.x" # Country 1 - Server 1
VPN_SERVER_2="x.x.x.x" # Country 1 - Server 2
VPN_SERVER_3="x.x.x.x" # Country 2 - Server 3
VPN_LABEL_1="Swiss - Server Tarzan"
VPN_LABEL_2="Swiss - Server John"
VPN_LABEL_3="Canada - Server Albert"
RECEIVER_1="10.0.0.15" # first LAN computer
RECEIVER_2="10.0.0.19" # second LAN computer
# YOU MUST EDIT THESE VARIABLES ABOVE !
GATEWAY=`cat /etc/mygate`
WEBSITE_IP_CHECKER="whatismy-ip.com"
WD_LOG=/var/log/watchdog.log
SYS_LOG=/var/log/messages
TIME=`date +"%b %e %H:%M:%S"`
UNAME=`uname`
LOG_TIME="$TIME $UNAME watchdog :"
NETWORK_CONNECTED=`ifconfig $EXT_INTERFACE | grep active`
VPN_CONNECTED=`ifconfig $VPN_INTERFACE | grep active`
VPN_ROUTE=`route -n show | grep 0/1 | grep $VPN_INTERFACE`
VPN_PID=`pgrep openvp`
VPN_IP=`ifconfig $VPN_INTERFACE | grep "inet " | cut -d'-' -f1 | cut -d' ' -f2`
DNSCRYPT_PID=`pgrep dnscrypt-proxy`
# Functions
# -------------------------------------------------------------------------------------
# SPECIFY HERE WHICH IP ON YOUR LAN HAVE THE WINDOWS CLIENT STARTED
# This function will send an UDP packet with netcat to inform of the connection status
send_notification() {
echo "$1" | nc -uw 0 $RECEIVER_1 7951
echo "$1" | nc -uw 0 $RECEIVER_2 7951
}
# Main
# -------------------------------------------------------------------------------------
# If network is disconnected, exit
if [ -z "$NETWORK_CONNECTED" ]; then
send_notification "DOWN_NETWORK (Interface $EXT_INTERFACE not active)"
exit
fi
# If gateway is unreachable, exit
GATEWAY_CHECK=`ping -c 2 -w 2 $GATEWAY | grep "100% packet loss"`
if [ ! -z "$GATEWAY_CHECK" ]; then
send_notification "DOWN_GATEWAY ($GATEWAY unreachable.)"
exit
fi
# Check if OpenVPN is started
if [ -z "$VPN_PID" ]; then
echo "$LOG_TIME OpenVPN process not found, starting it..." >> $SYS_LOG
echo "$LOG_TIME OpenVPN process not found, starting it..." >> $WD_LOG
/usr/local/sbin/openvpn --config /usr/local/etc/openvpn/airvpn.ovpn --daemon
send_notification "DOWN_VPN (OpenVPN process not found)"
exit
fi
# Check if interface tun0 is active
if [ -z "$VPN_CONNECTED" ]; then
echo "$LOG_TIME Interface $VPN_INTERFACE not connected" >> $SYS_LOG
echo "$LOG_TIME Interface $VPN_INTERFACE not connected" >> $WD_LOG
send_notification "DOWN_VPN (Interface $VPN_INTERFACE not connected)"
exit
fi
# Check if a route for interface tun0 exists
if [ -z "$VPN_ROUTE" ]; then
echo "$LOG_TIME Route for $VPN_INTERFACE not found." >> $SYS_LOG
echo "$LOG_TIME Route for $VPN_INTERFACE not found." >> $WD_LOG
send_notification "DOWN_VPN (Route for $VPN_INTERFACE not found)"
exit
fi
# Check if tun0 has an ip address
if [ -z "$VPN_IP" ]; then
echo "$LOG_TIME No IP for $VPN_INTERFACE." >> $SYS_LOG
echo "$LOG_TIME No IP for $VPN_INTERFACE." >> $WD_LOG
send_notification "DOWN_VPN (No IP for $VPN_INTERFACE.)"
exit
fi
# Check the connectivity of all our remote VPN servers
CHECK_VPNSERVER_1=`ping -c 3 -w 2 $VPN_SERVER_1 | grep "100.0% packet loss"`
CHECK_VPNSERVER_2=`ping -c 3 -w 2 $VPN_SERVER_2 | grep "100.0% packet loss"`
CHECK_VPNSERVER_3=`ping -c 3 -w 2 $VPN_SERVER_3 | grep "100.0% packet loss"`
# If all of the servers are unreachable
if ([[ ! -z "$CHECK_VPNSERVER_1" ]] && [[ ! -z "$CHECK_VPNSERVER_2" ]] && [[ ! -z "$CHECK_VPNSERVER_3" ]]); then
echo "$LOG_TIME All VPN servers are unavailable." >> $SYS_LOG
echo "$LOG_TIME All VPN servers are unavailable." >> $WD_LOG
send_notification "DOWN_VPN (All VPN servers are unavailable.)"
exit
fi
if [ -z "$CHECK_VPNSERVER_1" ]; then
echo "$LOG_TIME $VPN_LABEL_1 up." >> $WD_LOG
else
echo "$LOG_TIME $VPN_LABEL_1 down." >> $WD_LOG
fi
if [ -z "$CHECK_VPNSERVER_2" ]; then
echo "$LOG_TIME $VPN_LABEL_2 up." >> $WD_LOG
else
echo "$LOG_TIME $VPN_LABEL_2 down." >> $WD_LOG
fi
if [ -z "$CHECK_VPNSERVER_3" ]; then
echo "$LOG_TIME $VPN_LABEL_3 up." >> $WD_LOG
else
echo "$LOG_TIME $VPN_LABEL_3 down." >> $WD_LOG
fi
# Retrieve our VPN server IP, by reading the last successful connection (tail -n 1)
VPN_REMOTE_IP=`grep "Peer Connection Initiated with" /var/log/messages | tail -n 1 | cut -d'_' -f 2 | cut -d']' -f 2 | cut -d':' -f 1`
# Only do active online IP checking when local log does not have the answer
if [ -z $VPN_REMOTE_IP ]; then
ACTIVE_IP_CHECK=`echo "GET http://$WEBSITE_IP_CHECKER HTTP/1.0\n\n" | nc $WEBSITE_IP_CHECKER 80 | grep "Your IP address is" | cut -d' ' -f5 | cut -d'<' -f1`
VPN_REMOTE_IP=$ACTIVE_IP_CHECK
fi
VPN_REMOTE_DESCRIPTION="Public IP visible : "
if [ "$VPN_REMOTE_IP" = "$VPN_SERVER_1" ]; then
VPN_REMOTE_DESCRIPTION=$VPN_LABEL_1
elif [ "$VPN_REMOTE_IP" = "$VPN_SERVER_2" ]; then
VPN_REMOTE_DESCRIPTION=$VPN_LABEL_2
elif [ "$VPN_REMOTE_IP" = "$VPN_SERVER_3" ]; then
VPN_REMOTE_DESCRIPTION=$VPN_LABEL_3
fi
# All good our VPN is connected
echo "$LOG_TIME OpenVPN alive ($VPN_PID)." >> $WD_LOG
send_notification "UP_VPN ($VPN_REMOTE_DESCRIPTION $VPN_REMOTE_IP)"
# Check if DNSCrypt is started
if [ -z "$DNSCRYPT_PID" ]; then
echo "$LOG_TIME Dnscrypt-proxy process not found, starting it..." >> $SYS_LOG
echo "$LOG_TIME Dnscrypt-proxy process not found, starting it..." >> $WD_LOG
/usr/local/sbin/dnscrypt-proxy -a 127.0.0.1:40 -u _dnscrypt-proxy -d -R opendns
send_notification "DOWN_DNS (Dnscrypt-proxy process not found)"
exit
fi
# !! ONLY WORK WITH THE DNSCRYPT COMMAND LINE ARGUMENT "-d opendns"
# !! ONLY WORK WITH THE DNSCRYPT COMMAND LINE ARGUMENT "-d opendns"
# Check if our DNS requests are effectively encrypted
CHECK_DNS=`dig txt debug.opendns.com | grep "dnscrypt enabled"`
if [ -z "$CHECK_DNS" ]; then
# Dnscrypt started but dns requests not encrypted
echo "$LOG_TIME dnscrypt-proxy started but dns requests not encrypted ($DNSCRYPT_PID)." >> $SYS_LOG
echo "$LOG_TIME dnscrypt-proxy started but dns requests not encrypted ($DNSCRYPT_PID)." >> $WD_LOG
send_notification "DOWN_DNS (dns requests not encrypted)"
else
# All good, Dnscrypt started
echo "$LOG_TIME dnscrypt-proxy alive ($DNSCRYPT_PID)." >> $WD_LOG
send_notification "UP_DNS (pid : $DNSCRYPT_PID)"
fi
# Watchdog v1.0
# Variables
# -------------------------------------------------------------------------------------
# YOU MUST EDIT THESE VARIABLES BELOW !
LAN_INTERFACE="re0"
EXT_INTERFACE="re1"
VPN_INTERFACE="tun0"
VPN_SERVER_1="x.x.x.x" # Country 1 - Server 1
VPN_SERVER_2="x.x.x.x" # Country 1 - Server 2
VPN_SERVER_3="x.x.x.x" # Country 2 - Server 3
VPN_LABEL_1="Swiss - Server Tarzan"
VPN_LABEL_2="Swiss - Server John"
VPN_LABEL_3="Canada - Server Albert"
RECEIVER_1="10.0.0.15" # first LAN computer
RECEIVER_2="10.0.0.19" # second LAN computer
# YOU MUST EDIT THESE VARIABLES ABOVE !
GATEWAY=`cat /etc/mygate`
WEBSITE_IP_CHECKER="whatismy-ip.com"
WD_LOG=/var/log/watchdog.log
SYS_LOG=/var/log/messages
TIME=`date +"%b %e %H:%M:%S"`
UNAME=`uname`
LOG_TIME="$TIME $UNAME watchdog :"
NETWORK_CONNECTED=`ifconfig $EXT_INTERFACE | grep active`
VPN_CONNECTED=`ifconfig $VPN_INTERFACE | grep active`
VPN_ROUTE=`route -n show | grep 0/1 | grep $VPN_INTERFACE`
VPN_PID=`pgrep openvp`
VPN_IP=`ifconfig $VPN_INTERFACE | grep "inet " | cut -d'-' -f1 | cut -d' ' -f2`
DNSCRYPT_PID=`pgrep dnscrypt-proxy`
# Functions
# -------------------------------------------------------------------------------------
# SPECIFY HERE WHICH IP ON YOUR LAN HAVE THE WINDOWS CLIENT STARTED
# This function will send an UDP packet with netcat to inform of the connection status
send_notification() {
echo "$1" | nc -uw 0 $RECEIVER_1 7951
echo "$1" | nc -uw 0 $RECEIVER_2 7951
}
# Main
# -------------------------------------------------------------------------------------
# If network is disconnected, exit
if [ -z "$NETWORK_CONNECTED" ]; then
send_notification "DOWN_NETWORK (Interface $EXT_INTERFACE not active)"
exit
fi
# If gateway is unreachable, exit
GATEWAY_CHECK=`ping -c 2 -w 2 $GATEWAY | grep "100% packet loss"`
if [ ! -z "$GATEWAY_CHECK" ]; then
send_notification "DOWN_GATEWAY ($GATEWAY unreachable.)"
exit
fi
# Check if OpenVPN is started
if [ -z "$VPN_PID" ]; then
echo "$LOG_TIME OpenVPN process not found, starting it..." >> $SYS_LOG
echo "$LOG_TIME OpenVPN process not found, starting it..." >> $WD_LOG
/usr/local/sbin/openvpn --config /usr/local/etc/openvpn/airvpn.ovpn --daemon
send_notification "DOWN_VPN (OpenVPN process not found)"
exit
fi
# Check if interface tun0 is active
if [ -z "$VPN_CONNECTED" ]; then
echo "$LOG_TIME Interface $VPN_INTERFACE not connected" >> $SYS_LOG
echo "$LOG_TIME Interface $VPN_INTERFACE not connected" >> $WD_LOG
send_notification "DOWN_VPN (Interface $VPN_INTERFACE not connected)"
exit
fi
# Check if a route for interface tun0 exists
if [ -z "$VPN_ROUTE" ]; then
echo "$LOG_TIME Route for $VPN_INTERFACE not found." >> $SYS_LOG
echo "$LOG_TIME Route for $VPN_INTERFACE not found." >> $WD_LOG
send_notification "DOWN_VPN (Route for $VPN_INTERFACE not found)"
exit
fi
# Check if tun0 has an ip address
if [ -z "$VPN_IP" ]; then
echo "$LOG_TIME No IP for $VPN_INTERFACE." >> $SYS_LOG
echo "$LOG_TIME No IP for $VPN_INTERFACE." >> $WD_LOG
send_notification "DOWN_VPN (No IP for $VPN_INTERFACE.)"
exit
fi
# Check the connectivity of all our remote VPN servers
CHECK_VPNSERVER_1=`ping -c 3 -w 2 $VPN_SERVER_1 | grep "100.0% packet loss"`
CHECK_VPNSERVER_2=`ping -c 3 -w 2 $VPN_SERVER_2 | grep "100.0% packet loss"`
CHECK_VPNSERVER_3=`ping -c 3 -w 2 $VPN_SERVER_3 | grep "100.0% packet loss"`
# If all of the servers are unreachable
if ([[ ! -z "$CHECK_VPNSERVER_1" ]] && [[ ! -z "$CHECK_VPNSERVER_2" ]] && [[ ! -z "$CHECK_VPNSERVER_3" ]]); then
echo "$LOG_TIME All VPN servers are unavailable." >> $SYS_LOG
echo "$LOG_TIME All VPN servers are unavailable." >> $WD_LOG
send_notification "DOWN_VPN (All VPN servers are unavailable.)"
exit
fi
if [ -z "$CHECK_VPNSERVER_1" ]; then
echo "$LOG_TIME $VPN_LABEL_1 up." >> $WD_LOG
else
echo "$LOG_TIME $VPN_LABEL_1 down." >> $WD_LOG
fi
if [ -z "$CHECK_VPNSERVER_2" ]; then
echo "$LOG_TIME $VPN_LABEL_2 up." >> $WD_LOG
else
echo "$LOG_TIME $VPN_LABEL_2 down." >> $WD_LOG
fi
if [ -z "$CHECK_VPNSERVER_3" ]; then
echo "$LOG_TIME $VPN_LABEL_3 up." >> $WD_LOG
else
echo "$LOG_TIME $VPN_LABEL_3 down." >> $WD_LOG
fi
# Retrieve our VPN server IP, by reading the last successful connection (tail -n 1)
VPN_REMOTE_IP=`grep "Peer Connection Initiated with" /var/log/messages | tail -n 1 | cut -d'_' -f 2 | cut -d']' -f 2 | cut -d':' -f 1`
# Only do active online IP checking when local log does not have the answer
if [ -z $VPN_REMOTE_IP ]; then
ACTIVE_IP_CHECK=`echo "GET http://$WEBSITE_IP_CHECKER HTTP/1.0\n\n" | nc $WEBSITE_IP_CHECKER 80 | grep "Your IP address is" | cut -d' ' -f5 | cut -d'<' -f1`
VPN_REMOTE_IP=$ACTIVE_IP_CHECK
fi
VPN_REMOTE_DESCRIPTION="Public IP visible : "
if [ "$VPN_REMOTE_IP" = "$VPN_SERVER_1" ]; then
VPN_REMOTE_DESCRIPTION=$VPN_LABEL_1
elif [ "$VPN_REMOTE_IP" = "$VPN_SERVER_2" ]; then
VPN_REMOTE_DESCRIPTION=$VPN_LABEL_2
elif [ "$VPN_REMOTE_IP" = "$VPN_SERVER_3" ]; then
VPN_REMOTE_DESCRIPTION=$VPN_LABEL_3
fi
# All good our VPN is connected
echo "$LOG_TIME OpenVPN alive ($VPN_PID)." >> $WD_LOG
send_notification "UP_VPN ($VPN_REMOTE_DESCRIPTION $VPN_REMOTE_IP)"
# Check if DNSCrypt is started
if [ -z "$DNSCRYPT_PID" ]; then
echo "$LOG_TIME Dnscrypt-proxy process not found, starting it..." >> $SYS_LOG
echo "$LOG_TIME Dnscrypt-proxy process not found, starting it..." >> $WD_LOG
/usr/local/sbin/dnscrypt-proxy -a 127.0.0.1:40 -u _dnscrypt-proxy -d -R opendns
send_notification "DOWN_DNS (Dnscrypt-proxy process not found)"
exit
fi
# !! ONLY WORK WITH THE DNSCRYPT COMMAND LINE ARGUMENT "-d opendns"
# !! ONLY WORK WITH THE DNSCRYPT COMMAND LINE ARGUMENT "-d opendns"
# Check if our DNS requests are effectively encrypted
CHECK_DNS=`dig txt debug.opendns.com | grep "dnscrypt enabled"`
if [ -z "$CHECK_DNS" ]; then
# Dnscrypt started but dns requests not encrypted
echo "$LOG_TIME dnscrypt-proxy started but dns requests not encrypted ($DNSCRYPT_PID)." >> $SYS_LOG
echo "$LOG_TIME dnscrypt-proxy started but dns requests not encrypted ($DNSCRYPT_PID)." >> $WD_LOG
send_notification "DOWN_DNS (dns requests not encrypted)"
else
# All good, Dnscrypt started
echo "$LOG_TIME dnscrypt-proxy alive ($DNSCRYPT_PID)." >> $WD_LOG
send_notification "UP_DNS (pid : $DNSCRYPT_PID)"
fi
Now edit the crontab to run it every minute :
$ sudo crontab -e
# Watchdog
* * * * * /bin/sh /home/guillaume/watchdog.sh
* * * * * /bin/sh /home/guillaume/watchdog.sh
You can view the scrip working by checking its log file (example with imaginary VPN server names):
$ tail -f /var/log/watchdog.log
May 10 15:54:01 OpenBSD watchdog : Swiss Tarzan up.
May 10 15:54:01 OpenBSD watchdog : Swiss John up.
May 10 15:54:01 OpenBSD watchdog : Canada Albert up.
May 10 15:54:01 OpenBSD watchdog : OpenVPN alive (13279).
May 10 15:54:01 OpenBSD watchdog : dnscrypt-proxy alive (11395).
May 10 15:54:01 OpenBSD watchdog : Swiss Tarzan up.
May 10 15:54:01 OpenBSD watchdog : Swiss John up.
May 10 15:54:01 OpenBSD watchdog : Canada Albert up.
May 10 15:54:01 OpenBSD watchdog : OpenVPN alive (13279).
May 10 15:54:01 OpenBSD watchdog : dnscrypt-proxy alive (11395).
It is best to check the script is covering you in case of OpenVPN crash :
$ sudo pkill openvpn
Now check the "/var/log/watchdog.log" log file, and you should see that the script notices OpenVPN being stopped, and attempting to start it again.
You can check VPN connection steps in "/var/log/messages".This script by itself, without LAN notifications, reaches its purpose : monitoring and acting automatically to recover a dead process, and keeping you secure. If you also want the LAN notifications, to know your DNS/VPN state from a Windows client, please proceed to the next chapter.
11. WINDOWS CLIENT
___________________________________________________________
___________________________________________________________
The Windows client is just an icon in the taskbar, and a minimal right-click menu to show informations. The icons are the following :
Blue icon is when the program has started but did not receive any information yet.
Red icon is when a "DOWN" has been received, either for DNS or for VPN.
Green icon is when both DNS and VPN are "UP", and all checks passed successfully.
If the icon is green, the client tells you when was the last time it received an "UP" notification :
If you do a right click, a small popup menu appears, displays which VPN you are connected to if the information was available in the /var/log/messages of the router, or at last resort displays your visible public address. For both VPN IP and DNS entries, you can click them to open websites to check your online status :
You can download the archive containing both the source code (purebasic) and the built Windows binary : Download Here
If you want it to run at startup, you will have to do it manually, either a shortcut in the start menu, or a scheduled task triggered at session opening.
Blue icon is when the program has started but did not receive any information yet.
Red icon is when a "DOWN" has been received, either for DNS or for VPN.
Green icon is when both DNS and VPN are "UP", and all checks passed successfully.
If the icon is green, the client tells you when was the last time it received an "UP" notification :
If you do a right click, a small popup menu appears, displays which VPN you are connected to if the information was available in the /var/log/messages of the router, or at last resort displays your visible public address. For both VPN IP and DNS entries, you can click them to open websites to check your online status :
You can download the archive containing both the source code (purebasic) and the built Windows binary : Download Here
If you want it to run at startup, you will have to do it manually, either a shortcut in the start menu, or a scheduled task triggered at session opening.
12. BEYOND VPN
___________________________________________________________
___________________________________________________________
Even now, with all of our outgoing traffic encrypted, four main problems still exist :
1 - once our traffic goes out of the VPN tunnel, it becomes again visible (even if it cannot be linked to us)
2 - our browser can still be used against us to track what we done
3 - our emails can still be read by automated surveillance tools
4 - our searches on search engines like Google are read and stored
For the first point, it means that we should make our best efforts to connect mostly to HTTPS websites, so that the connection stays encrypted until its final destination. To achieve that, using a browser extension such as HTTPS Everywhere is a quick and easy way. It is available for Google Chrome, Firefox, and Opera. It contains a database of more than 1500 websites. If you connect to them in plain HTTP, this extension modifies the request to connect with HTTPS.
For the second point, even if you are connecting using different VPN servers each time, most websites are tracking you, voluntarily or not (often because of tracking ads displayed). To prevent your surf habits from being tracked, another browser extension is here to help : Ghostery. Ghostery knows about nearly 2000 trackers, and recognize more than 2000 tracking patterns. It can incidentally speed up your browsing too, and is available on many browsers : Google Chrome, Firefox, Opera, and Safari.
For the third point, even if we go through a VPN, and connect in HTTPS to our email provider, for instance Gmail, our emails are still stored in clear text and read automatically by Google, and by foreign agencies (I'm referring to Snowden's slides about NSA having access to Google, Facebook, Apple, etc...). Our emails contains mostly private information, credentials to most websites, and even our bank account. I'm keeping an eye on fully-encrypted zero-knowledge privacy email services such as Lavaboom which is in private Beta for now (the provider does not have the encryption/decryption keys to read your emails.
The fourth point can be easily overlooked, but every search we do on Google are sent and stored. Like Mikko Hypponen says (video), we are brutally honest with search engines. They can know more about us than our family or our best friends. The trick here is to move away from Google search engine and try something else like Duckduckgo. At the time of writing, they are developing their next version, available at https://next.duckduckgo.com. They do not track you, they do not store your searches, and they do not send your search to websites you visit (usually a website knows the search you did to fall on it). Their "next" version have an equivalent of Google image, and is customizable. Also, if there is any privacy risk they warn you :
Last but not least, be smart. Indeed, it is a moot point to want protecting its privacy and using a VPN, if the purpose is to upload your entire life on a public social service such as Facebook !
1 - once our traffic goes out of the VPN tunnel, it becomes again visible (even if it cannot be linked to us)
2 - our browser can still be used against us to track what we done
3 - our emails can still be read by automated surveillance tools
4 - our searches on search engines like Google are read and stored
For the first point, it means that we should make our best efforts to connect mostly to HTTPS websites, so that the connection stays encrypted until its final destination. To achieve that, using a browser extension such as HTTPS Everywhere is a quick and easy way. It is available for Google Chrome, Firefox, and Opera. It contains a database of more than 1500 websites. If you connect to them in plain HTTP, this extension modifies the request to connect with HTTPS.
For the second point, even if you are connecting using different VPN servers each time, most websites are tracking you, voluntarily or not (often because of tracking ads displayed). To prevent your surf habits from being tracked, another browser extension is here to help : Ghostery. Ghostery knows about nearly 2000 trackers, and recognize more than 2000 tracking patterns. It can incidentally speed up your browsing too, and is available on many browsers : Google Chrome, Firefox, Opera, and Safari.
For the third point, even if we go through a VPN, and connect in HTTPS to our email provider, for instance Gmail, our emails are still stored in clear text and read automatically by Google, and by foreign agencies (I'm referring to Snowden's slides about NSA having access to Google, Facebook, Apple, etc...). Our emails contains mostly private information, credentials to most websites, and even our bank account. I'm keeping an eye on fully-encrypted zero-knowledge privacy email services such as Lavaboom which is in private Beta for now (the provider does not have the encryption/decryption keys to read your emails.
The fourth point can be easily overlooked, but every search we do on Google are sent and stored. Like Mikko Hypponen says (video), we are brutally honest with search engines. They can know more about us than our family or our best friends. The trick here is to move away from Google search engine and try something else like Duckduckgo. At the time of writing, they are developing their next version, available at https://next.duckduckgo.com. They do not track you, they do not store your searches, and they do not send your search to websites you visit (usually a website knows the search you did to fall on it). Their "next" version have an equivalent of Google image, and is customizable. Also, if there is any privacy risk they warn you :
Last but not least, be smart. Indeed, it is a moot point to want protecting its privacy and using a VPN, if the purpose is to upload your entire life on a public social service such as Facebook !
CONCLUSION :
___________________________________________________________
___________________________________________________________
With this simple VPN gateway, you are starting to protect your privacy, bravo :
Having the VPN done externally, not on your computer, offers many advantages :
- it cannot be disabled by a malware on your computer
- it protects you at boot time and when opening your session
- it works for any Operating System
- it works for devices which are not VPN-capable
- it protects your whole LAN not just one computer
- if you format and install another OS on your client computer, you don't have to reinstall the VPN
- it is optimized, as a dedicated hardware fully works on that task
- it creates a DMZ, if you connect anything directly on your ISP router, behind the OpenBSD router
- if there is a backdoor on your ISP router, it cannot be used to reach your LAN.
However we should not forget to keep us informed on NSA's capabilities regarding VPN decryption, even if AirVPN provider seems not affected. I think the world has been shaken by the last revelations, and that new or improved security service will come to help us.
Anyway, using technical means to protect your privacy is just one part of the picture, it doesn't stop the automated mass surveillance. Beyond protecting your privacy, you can fight for it by registering to privacy associations and websites, and participate to bring awareness on privacy issues : "Fight for the future" website, or "Digital Freedom Manifesto" by F-Secure
As I said in the introduction :
Having the VPN done externally, not on your computer, offers many advantages :
- it cannot be disabled by a malware on your computer
- it protects you at boot time and when opening your session
- it works for any Operating System
- it works for devices which are not VPN-capable
- it protects your whole LAN not just one computer
- if you format and install another OS on your client computer, you don't have to reinstall the VPN
- it is optimized, as a dedicated hardware fully works on that task
- it creates a DMZ, if you connect anything directly on your ISP router, behind the OpenBSD router
- if there is a backdoor on your ISP router, it cannot be used to reach your LAN.
However we should not forget to keep us informed on NSA's capabilities regarding VPN decryption, even if AirVPN provider seems not affected. I think the world has been shaken by the last revelations, and that new or improved security service will come to help us.
Anyway, using technical means to protect your privacy is just one part of the picture, it doesn't stop the automated mass surveillance. Beyond protecting your privacy, you can fight for it by registering to privacy associations and websites, and participate to bring awareness on privacy issues : "Fight for the future" website, or "Digital Freedom Manifesto" by F-Secure
As I said in the introduction :
The search for privacy is not a criminal act, it is a fundamental human right.
CHANGELOG
___________________________________________________________
___________________________________________________________
Updated 2015 January 04 :
- OpenVPN : chroot added, login/password text file removed, systrace profile
- DNS : Bind removed, Unbound used instead (with chroot too).
- PF : advanced ruleset (third ruleset) improvements (set prio, route-to, tables, and few simplifications)
- Changelog section added
Updated 2014 November 30
- fixes mistakes, tested and working on OpenBSD 5.6
- OpenVPN : chroot added, login/password text file removed, systrace profile
- DNS : Bind removed, Unbound used instead (with chroot too).
- PF : advanced ruleset (third ruleset) improvements (set prio, route-to, tables, and few simplifications)
- Changelog section added
Updated 2014 November 30
- fixes mistakes, tested and working on OpenBSD 5.6
LINKS
___________________________________________________________
___________________________________________________________
http://reflets.info
https://firstlook.org/theintercept
http://www.thelocal.se
http://www.spiegel.de
http://www.openbsd.org/
http://daemonforums.org/
http://www.bsdnow.tv/
https://stable.mtier.org/
https://airvpn.org
http://whoer.net/
https://www.eff.org/https-everywhere
https://www.ghostery.com
http://www.lavaboom.com
https://duckduckgo.com/
https://next.duckduckgo.com
https://www.fightforthefuture.org/
http://campaigns.f-secure.com/digitalfreedom/
https://firstlook.org/theintercept
http://www.thelocal.se
http://www.spiegel.de
http://www.openbsd.org/
http://daemonforums.org/
http://www.bsdnow.tv/
https://stable.mtier.org/
https://airvpn.org
http://whoer.net/
https://www.eff.org/https-everywhere
https://www.ghostery.com
http://www.lavaboom.com
https://duckduckgo.com/
https://next.duckduckgo.com
https://www.fightforthefuture.org/
http://campaigns.f-secure.com/digitalfreedom/
Follow me @gkweb76