Stopping DNS leakage with pfSense

I’ve recently changed my core router over from OpenWRT to pfSense.  I was pretty happy with OpenWRT, but I wanted something more powerful since it was running in a VM anyway.

A few days ago, CloudFlare announced their new service.  This is a public DNS service very much like Google’s DNS service, with a notable difference.  It supports TLS.

Why should you care?  Because DNS requests are normally not encrypted, and therefore visible to your ISP to record, use for research / marketing purposes, or even (in the case of some nefarious actors) manipulate or change.  Running DNS over TLS prevents that, by encrypting your DNS traffic so that it can’t be manipulated or collected.

In this post, we’ll be configuring pfSense to do three things – provide a local standard unencrypted port 53 DNS resolver which uses CloudFlare’s encrypted service on the WAN end, and then set up a NAT redirect so any attempts on the internal network to use port 53 DNS servers outside the network instead are intercepted and resolved by the internal resolver.  Lastly, it will also make sure that it blocks any outbound requests to port 53 just to be sure.

NOTE:  There’s one piece here I haven’t figured out yet.  How to pin a cert for the DNS endpoints listed here, so it’s not perfect.  When I figure that out, I’ll edit this post.

Let’s get started.

Configuring the pfSense Local Resolver

In pfSense, go to Services -> DNS Resolver, then put the following block into Custom Options:

ssl-upstream: yes
do-tcp: yes
    name: "." 
    forward-addr: 2606:4700:4700::1111@853
    forward-addr: 2606:4700:4700::1001@853

You will also need to make sure that the DNS Query Forwarding option is NOT selected, otherwise the above settings will conflict.  It’s OK to set the resolver to listen on all interfaces, since the firewall rules on the WAN will prevent Internet hosts from using your resolver anyway.  Follow the prompts, then test it with something like;

dig @yourrouter.local

You should see a resolve against your router’s local DNS resolver that works.  If you really want, use Diagnostics -> Packet Capture, and capture port 853 to verify that requests are being triggered.

Redirect all DNS requests to outside DNS servers to pfSense

Follow the article you can find here.  You will need to do this once for each of your interfaces (in my case, LAN, DMZ, and VPN).  Obviously don’t configure this for the WAN interface.  This then causes any requests to addresses that are not on your internal network to be resolved through the local pfSense resolver (which goes out to port 853 anyway).

To test this, try and dig something against an IP that you know is not internal and is not a DNS server.  It should work, since the request will be NATted.  Something like;

dig @

Assuming that’s all fine, you should now be able to configure a broad block rule to bar all outbound port 53.

Block all outbound non-encrypted DNS

This shouldn’t really be required if the NAT rule is working, but we’ll do it anyway to be sure we’re stopping any DNS leaks.

In pfSense, go to Firewall -> Rules, and for the WAN interface, define a new rule at the top of the list.  This rule should use these settings;

Action: Block
Interface: WAN
Address Family: IPv4+IPv6
Protocol: TCP/UDP
Source: any
Destination: any
Destination Port: DNS (53)
Description: Block outbound insecure DNS

After doing this, verify that you can still resolve against the local resolver (your router’s IP), and that you can still resolve against what seems to be external resolvers (eg,  You should also check that when you do so that nothing passes on the WAN interface on port 53.

If that all passes, you’re done.   It’s up to you if you use the ‘Block’ target or the ‘Reject’ target.  Block causes a simple timeout if something hits 53 (which shouldn’t happen anyway), Reject causes an immediate fail.


Using ADB in Recovery Mode

I don’t have a specific use case for this, but I thought I’d experiment and see just how this can be done.  I’ve recently changed over to encryption on my smartphone, because it came to my attention that it’s possible to use the Android debugger to get access to an Android device’s flash even if you don’t have the unlock pin.  This of course requires physical access to the phone.

This procedure illustrates why it’s a damned good idea to encrypt your phone.

Step 1 – Install ADB

Go to this link and download the Android SDK and install it.  Install to the default location.  Since there’s a good chance you don’t have a 64-bit JDK installed too, go to this link and download the latest JDK for Windows x64.  Install that too.

You’ll probably also have to create a JAVA_HOME environment variable.  That’s described in the first link.

Step 2 – Install SDK Packages

Run Android Studio as Administrator.  Click Configure.  Click SDK Manager.  Click “Deselect All” then “Select Updates”.  Now, tick “Android SDK Platform-tools” under Tools, and “Google USB Driver” under Extras.  Click Install and follow the wizard.  Close the SDK Manager when done.

Close Android Studio.

Step 3 – Connect your device to ADB

Power off the phone, plug it into your computer and power it up in Recovery mode with (this is for a Samsung Galaxy S3) holding down the power button, volume up and menu at the same time.  Let go of the power button when the screen comes on.

If you don’t have a recovery installed, you’ll have to boot into the bootloader (same buttons as above just use volume down instead), and then use Fastboot to install a custom recovery (like CWM or TWRP).

Once in Recovery, go to Device Manager on your PC, and change the driver for the phone.  I used the SAMSUNG Android ADB Interface driver.

Then, fire up a command prompt in Administrator mode, go to “C:\Program Files (x86)\Android\android-studio\sdk\platform-tools” and run “adb shell”

You’re now in a basic recovery shell on the phone.  From here, you can now do pretty well whatever you want – read data, copy stuff off the phone, rewrite the recovery, change the unlock PIN, whatever.

Have fun.  Use your newfound powers for good, not evil.

A minimalist Google Authenticator – in Python!

So, after an argument with someone about how RFC6238 authenticators work (ie, the authenticator does not need to know any detail or be able to communicate with the service being authenticated to), I decided to cobble together a highly minimalist (and functional) Authenticator which spits out tokencodes that are compatible with Google Authenticator, in Python.

Just run this with the relevant secret key as a command-line parameter and you’ll get your tokencodes.

import time
import struct
import hmac
import hashlib
import base64
import sys

# derive components
secretkey = base64.b32decode(sys.argv[1])
tm = int(time.time() / 30)

# convert timestamp to raw bytes
b = struct.pack(">q", tm)

# generate HMAC-SHA1 from timestamp based on secret key
hm = hmac.HMAC(secretkey, b, hashlib.sha1).digest()

# extract 4 bytes from digest based on LSB
offset = ord(hm[-1]) & 0x0F
truncatedHash = hm[offset:offset+4]

# get the code from it
code = struct.unpack(">L", truncatedHash)[0]
code &= 0x7FFFFFFF;
code %= 1000000;

# print code
print "%06d" % code


Building a VPN with OpenVPN and OpenWRT

I wound out replacing my existing router (which had a buggy NAT issue) with a TP-Link TL-WR1043ND running OpenWRT.  It was pretty damned easy to get it all running and set it up as an in-place upgrade.  However, I wanted more out of it.

What I want to do is to establish a VPN tunnel such that my VPS has some (highly restricted) access to my local network, and my local network has (nearly) unrestricted access to the VPS.  I also want to have other devices (my phone) able to connect to my local network using VPN and have unrestricted access.  And lastly, I want to do this with certificates (and not shared secrets).  To do this, I used OpenVPN.

Desired Topology

  • – Internal LAN
  • – Trusted VPN
  • – Untrusted (DMZ) VPN

OpenWRT Configuration

Package Installation and TUN Configuration

First, run the following to install the required packages;

opkg update
opkg install openvpn-openssl
opkg install openvpn-easy-rsa

Once that’s done, edit /etc/config/network and add a declaration of a new TUN interface;

config interface 'vpn'
    option proto 'none'
    option ifname 'tun0'

Reboot your router, and you’ll find a new interface tun0 waiting.  Now you need to set up your PKI infrastructure and generate some certs.

Configure PKI

Follow the installation instructions for easy-rsa.  Once that’s done, you will have a functional self-signed CA.  Go and generate some certificates like this;

build-key-server server
build-key trustedclient
build-key dmzclient

Take server.crt and server.key and copy them into the OpenVPN configuration;

cp /etc/easy-rsa/server.* /etc/openvpn/
mkdir /etc/openvpn/clients/

You’ve now got a basic PKI setup, and two client certificates ready to go, along with the server certificate for OpenVPN.

Configure OpenVPN Server

Edit /etc/config/openvpn like this;

package openvpn

config openvpn trusted_vpn
        option enabled          1
        option port             1194
        option proto            udp
        option dev              tun
        option ca               /etc/easy-rsa/keys/ca.crt
        option cert             /etc/openvpn/server.crt
        option key              /etc/openvpn/server.key
        option dh               /etc/easy-rsa/keys/dh2048.pem
        option keepalive        '10 120'
        option comp_lzo         yes
        option persist_key      1
        option persist_tun      1
        option verb             3
        option status           /tmp/openvpn.status
        option log              /tmp/openvpn.log
        option ccd_exclusive    1
        option client_config_dir        /etc/openvpn/clients
        option server           ''
        option route            ''
        list push               "route"
        list push               "dhcp-option DOMAIN localdomain.local"
        list push               "dhcp-option DNS"

You should disable the log once you’ve got everything working.  What this does is the following;

  • Clients must have a matching client config entry in /etc/openvpn/clients to be able to connect
  • The server by default uses for connecting clients, but also has a route for down the TUN interface
  • The server pushes a route to the client for, along with a couple of settings that are used by Windows clients (setting local domain and DNS servers to use)

For your trusted client, create a file /etc/openvpn/clients/trustedclient which has this line in it;


This causes the trusted client to always get the IP address  Note, as per the OpenVPN documentation, in order for the ifconfig-push’ed addresses to work with WIndows clients properly, they must come from the set;

[  1,  2] [  5,  6] [  9, 10] [ 13, 14] [ 17, 18]
[ 21, 22] [ 25, 26] [ 29, 30] [ 33, 34] [ 37, 38]
[ 41, 42] [ 45, 46] [ 49, 50] [ 53, 54] [ 57, 58]
[ 61, 62] [ 65, 66] [ 69, 70] [ 73, 74] [ 77, 78]
[ 81, 82] [ 85, 86] [ 89, 90] [ 93, 94] [ 97, 98]
[101,102] [105,106] [109,110] [113,114] [117,118]
[121,122] [125,126] [129,130] [133,134] [137,138]
[141,142] [145,146] [149,150] [153,154] [157,158]
[161,162] [165,166] [169,170] [173,174] [177,178]
[181,182] [185,186] [189,190] [193,194] [197,198]
[201,202] [205,206] [209,210] [213,214] [217,218]
[221,222] [225,226] [229,230] [233,234] [237,238]
[241,242] [245,246] [249,250] [253,254]

Next, we repeat this with the DMZ client, but with a small change – we’ll also push the route for the trusted network.  This is required because otherwise the router itself cannot contact anything in the DMZ due to the router’s interface IP being in the range.

Create /etc/openvpn/clients/dmzclient as follows;

push route ""

That concludes the OpenVPN server config.  Now for the firewall.

Firewall Configuration

OpenVPN Access Port

Edit /etc/config/firewall .  Up fairly high, amongst any other port forwards, add the following;

config rule
    option name 'OpenVPN-Access'
    option src wan
    option proto udp
    option dest_port 1194
    option family ipv4
    option target ACCEPT

This allows your VPN to be accessible from the ‘net.

Full-Access VPN Zone

Next, we’ll create a new zone for the full-access VPN, but we’ll specify that it only applies to a specific subnet;

config zone
        option name             vpn
        option input            ACCEPT
        option forward          REJECT
        option output           ACCEPT
        list network            vpn
        list subnet             ''
        option masq             0
        option mtu_fix          1

config forwarding
        option dest             lan
        option src              vpn

config forwarding
        option dest             vpn
        option src              lan


And lastly we’ll define a new zone for the DMZ VPN along with allowed traffic.  Note that this does not specify a subnet, that way any traffic that comes in on the tun network that does not match the trusted VPN falls through to the DMZ zone.

config zone
        option name             dmz
        option input            REJECT
        option forward          REJECT
        option output           ACCEPT
        list network            vpn
        option masq             0
        option mtu_fix          1

config rule
        option name             'http-Linkage'
        option src              dmz
        option dest             lan
        option proto            tcp
        option src_ip 
        option dest_port        80
        option dest_ip
        option family           ipv4
        option target           ACCEPT

config rule
        option name             Allow-DMZ-Ping
        option src              dmz
        option dest             lan
        option proto            icmp
        option icmp_type        echo-request
        option family           ipv4
        option target           ACCEPT

config forwarding
        option dest             dmz
        option src              lan

Notably, there is only a forward here from lan to dmz, that way we have to specifically allow what traffic we want to be passed from dmz to lan.  Here, I allow the DMZ machine to ping into my local network, and to connect to on port tcp/80 only.

OpenVPN Server Summary

Essentially, what we’ve done is create two network zones which are pushed out by OpenVPN.  The firewall controls access between them.  Which user certificate lands in which zone is determined by the IP they’re assigned by OpenVPN on connect, which is defined by the configuration file in /etc/openvpn/clients.  All clients must have a config file waiting for them in this setup.

IMPORTANT – Don’t forget to add /etc/openvpn and /etc/easy-rsa to your /etc/sysupgrade.conf, otherwise you’ll lose all this on upgrading your router.  That would be unfortunate.

OpenVPN Client Setup (DMZ Client)

You will require the following components to configure your client;

  • /etc/easy-rsa/keys/ca.crt
  • /etc/easy-rsa/keys/dmzclient.crt
  • /etc/easy-rsa/keys/dmzclient.key

Download those off your router and store them somewhere.  Then, you’ll need to create a client.ovpn file in the same folder as follows;

dev tun
remote yourvpnserverhostname 1194
resolv-retry infinite
ns-cert-type server
ca /etc/openvpn/ca.crt
cert /etc/openvpn/dmzclient.crt
key /etc/openvpn/dmzclient.key

In my case, the files are in /etc/openvpn, as the config shows.  Notably, this config also does not pull route data from the OpenVPN server but instead sets it by itself.  Then, start your VPN with

openvpn --config client.ovpn

And it should all work!  If not, consult the logs, and good luck!

Password Reuse – Just Don’t.

Another XKCD to illustrate poignantly the evil that is password re-use;

Courtesy XKCD 792

Many people re-use the same password (or a simple permutation of a master password) in multiple locations.  Don’t do this!

The greatest threat to your passwords in modern times isn’t brute force guessing (assuming you haven’t picked something really terrible like your name and birthday).  It’s having an account sniffed/compromised/phished in one place, and then that same password being successfully used to compromise another service.

This sort of thing happens all the time.  If you don’t believe me, go search the Web for articles about companies losing cleartext password databases.

You also shouldn’t use passwords where the name of the service is bound up in the password, thus enabling an attacker to determine what your password may be for other services (eg, ‘facebookilovepuppies2012’ gives an attacker a pretty good indication your Paypal password may be ‘paypalilovepuppies2012’).  Each service should have its own, unique password.

But that’s a pig to remember!

Yes, it is.  However, there are various services around that can help out, such as LastPass, 1Password, among many others.  Make sure your master password you select to unlock the others is a good one, and you don’t use it anywhere else.

But, an important safety tip…

Don’t go locking yourself out of everything by forgetting your master password.  Make sure you provide yourself a way to get back into wherever you have stored all your passwords without requiring a password (which you might forget).  I’m going to say something now that flies in the face of what we’ve been told by the IT Industry for decades;

It’s OK to write passwords down on paper.

… as long as you store the paper somewhere safe.  Writing down your master password on a Post-It and sticking it on your monitor at work is a bad idea.  Putting it in a sealed envelope with your will being held by your attorney is a good idea.  Even putting your master password in your wallet is a reasonably safe idea, since anyone who steals your wallet is unlikely to know what to do with it before you go and change it (putting your ATM card’s PIN in your wallet is a bad idea however).

Also pay attention to any security unlock emails required for these services.  Don’t put in a security unlock email address which requires a password that you need the service to get into!  Using your ISP’s email address isn’t a bad idea, since you can walk up to your ISP’s head office with a driver’s license and get them to reset your password to get back into that even if you suffer from a blow to the head and forget everything at once.

So, in summary…

  • Use unique passwords for everything.
  • Make sure you always have a way to get back into your password databases.
  • It’s OK to write down passwords if you store them somewhere safe.

Password Selection

The following sums up about what this post will be regarding perfectly.

Courtesy XKCD 936

As it turns out, the IT Industry has spent an awful lot of time trying to convince people use horribly complicated passwords which are terribly difficult for a human to remember.  But they’re really easy for a computer to guess.  This leads to a number of security failures that people do to try and fit into the restrictions of their systems;

  • They use a password which is based on a single dictionary word and then tack on some symbols to fit into the requirements of whatever system they’re using.  Enter stuff like ‘Password2012!’.
  • They use the same base password, and then just increment some number at the end every time it expires.  So they wind up using ‘Password15’, ‘Password16’ and so on.
  • They use a decent password, but use it everywhere.  I’ll talk about password re-use later.
  • They use a decent password, but it’s derived from a formula where the name of the service or similar is bound into the password, making it easy to reverse engineer the password.  For example ‘Myhotmail1!’ or something like that.

Now, mathematically speaking, a long password is VERY MUCH harder to guess than a shorter, but more complex one.  The above cartoon illustrates this.  Selecting words in your native language, if you pick enough of them, is much much more secure than a nearly random bunch of punctuation and capital letters.

Why are random words easier to remember?

Interestingly, such a password is actually easier for a human to remember than a complex symbol-based password.  Why?  Because human memory works in symbols.  Your memory can store in correct order between 6-8 symbols with not too many transposition errors.  Four symbols is trivial to remember.  Your memory is able to store words in your native tongue as individual symbols, so a string of four random words is stored as only four symbols – easy to remember, easy to get in the right order.  However, the complex password above with punctuation symbols will be stored by your memory as several symbols – one will be the dictionary word you’ve based it on, then individual symbols for all the permutations you made to it.  Suddenly you’re trying to store 6 or more symbols in your memory at once.  This is near your upper limit, and transposition errors and other mistakes creep in.

So quotes and stuff are great, right?

Actually, no.  See, it turns out that humans are absolutely terrible at picking random strings of text.  Cracking dictionaries now contain the most common quotes that people tend to use, meaning their effective strength is greatly reduced.

You’re best off selecting a number of RANDOM words.

Ok, so REALLY random words.  What do we do?

Which brings us to the following resources;

The password generator I wrote uses the General Service List, a list of ~2k commonly-used English words.  The list used is very similar to the list that the XKCD Generator uses, with the notable exception that my generator uses a Mersenne Twister random number generator, which produces much better quality random numbers than the random() implementation in base JavaScript.  Both generators use client-side Javascript so they don’t record or otherwise log any of the passwords generated.

The beauty here is that it doesn’t matter if the word list is publically available.  It doesn’t matter that the algorithm used to generate the passwords is published.  The generated passwords are still strong.

Go forth and pick good passwords!


IPSec/L2TP VPN Server on CentOS 6 (PSK)

I’ve been using PopTop (a PPTP implementation) for quite some time now, but it appears that the PopTop Sourceforge site recently died and hasn’t come back.  In addition, PopTop hasn’t been updated in nearly five years.  Probably time to move on.

After a LOT of fighting (trying all sorts of things, including Racoon, OpenVPN, and finally OpenSWAN), I’ve got a working solution that runs fine with CentOS 6.3, and doesn’t require any funny repos or anything.

OpenSWAN + xl2tpd + PPP.  My understanding of how this stuff bolts together is a bit limited, but here goes…

Network Setup

I’m assuming the following network setup;

  • A client machine, off your network on the Internet somewhere.  You want that client to be able to get into your local network remotely and do ‘stuff’.
  • Your CentOS server has a single NIC, is running a DNS server locally, and has the IP address .
  • You have a NATting firewall (a router) on your network at which provides access to the Internet.
  • You have already configured port forwarding on your router to forward UDP ports 500, 4500 and 1701 to your CentOS server.
  • You want your VPN clients to appear in the IP range –, and this range is NOT in your dhcp scope.
  • You want to use a pre-shared key to get IPSEC working (certificates later!)


  • – Internal LAN
  • – Peer local IP to be used by VPN server for L2TP tunnels
  • through 10 – Local IP range to be used for L2TP tunnels, not in DHCP scope
  • – Private LAN interface of VPN server.
  • – DNS server to be used by VPN clients
  • – NATting border router

The Sequence

OpenSWAN provides the IPSEC component, encapsulating packets from the client to/from the server, providing basic network connectivity and authentication.  On connection, the client provides a pre-shared key to the server, and then OpenSWAN establishes the IPSEC tunnel and passes control to xl2tpd.

xl2tpd provides the component which connects the two disparate networks (the client’s and the server’s) together.  It talks to pppd to authenticate a user, and then makes that user appear on the local network as some IP in its defined range.

pppd provides authentication for users.  This way, there are TWO passwords required – one for the ipsec component provided by OpenSWAN, and one for the actual user account who is connecting to the VPN.

Setting it up

First, install the appropriate packages.

yum install openswan xl2tpd pppd
chkconfig ipsec on
chkconfig xl2tpd on

Then, edit /etc/sysctl.conf and set net.ipv4.ip_forward to 1.  Then, edit /etc/rc.local and add the following at the bottom;

# Correct ICMP Redirect issues with OpenSWAN
for each in /proc/sys/net/ipv4/conf/*; do
        echo 0 > $each/accept_redirects
        echo 0 > $each/send_redirects
        echo 0 > $each/rp_filter

This corrects some issues with OpenSWAN and ICMP redirect packets.  Now, edit /etc/ipsec.conf and make it look like the following;

config setup

conn L2TP-PSK

What’s happening here is that we define a new IPSEC connection where the right (the local side) is on the private network, and the left (the remote side, the client) is coming from the router and on port 1701.

Next up, we edit /etc/ipsec.secrets and define a PSK secret for this connection;   %any:   PSK yourpasswordhere

That does it for OpenSWAN.  Next we configure xl2tpd by editing /etc/xl2tpd/xl2tpd.conf and making it look like this;

listen-addr =

[lns default]
ip range =
local ip =
refuse pap = yes
require authentication = yes
name = YourServerNameHere
ppp debug = no
pppoptfile = /etc/ppp/options.xl2tpd
length bit = yes

There’s a few notable points here.  Firstly, the listen address is the local network address of the server.  Secondly, the ip range should be on the local network but not in your DHCP scope.  The local ip used should not be the same as the listen address AND should not be in the ip range.  Then we edit /etc/ppp/options.xl2tpd ;

idle 1800
mtu 1410
mru 1410
connect-delay 5000

You should set ms-dns to the DNS server you want your VPN clients to use.  And lastly, we edit /etc/ppp/chap-secrets and insert records for the accounts we want to be able to use VPN;

# Secrets for authentication using CHAP
# client        server  secret                  IP addresses
youruserhere    *       yourpasswordhere        *

With this done, you’re done with the xl2tpd component.  I’d advise you turn on the logging when you go to start all the services.  Start them up, and you should be able to connect!

Next up, requiring certificates.