Creating a DNS Black Hole for Captive Portal Clients - PFSenseDocs

Creating a DNS Black Hole for Captive Portal Clients – PFSenseDocs.

If you need to direct all of your portal clients to a single page, but the clients can fail to redirect due to flaky DNS resolution or missing DNS entries, you can setup a DNS “Black Hole” that will resolve all queries to a single IP address.

Setup BIND

On FreeBSD

If you are doing this on a FreeBSD box, BIND should be preinstalled. You do not need to install anything extra.

On pfSense

To setup the BIND service on a pfSense box, you must first disable the DNS forwarder, and then add the FreeBSD BIND package from the CLI:

pkg_add -r ftp://ftp.freebsd.org/pub/FreeBSD/ports/i386/packages-7-stable/Latest/bind97.tbz
rehash
mkdir -p /etc/namedb/

Create the configuration file

Edit /etc/namedb/named.conf (use vi, ee, or scp the file over). If you have an existing BIND config, you can alter it to work with this zone. A basic config is given here that will let it run, but it can be tweaked in various ways.

options {
	directory	"/etc/namedb";
	pid-file	"/var/run/named/pid";
	allow-query	{ any; };
	allow-recursion	{ any; };
};
zone "." {
	type master;
	file "/etc/namedb/db.catchall";
};

Create the zone file

Edit /etc/namedb/db.catchall – use the IP address of your web server in place of 192.168.1.5 in the blow example.

$TTL    604800
@       IN      SOA     . root.localhost. (
                              1         ; Serial
                         604800         ; Refresh
                          86400         ; Retry
                        2419200         ; Expire
                         604800 )       ; Negative Cache TTL

	IN	NS	.
.	IN	A	192.168.1.5
*.	IN	A	192.168.1.5

Start BIND

Start the bind service by hand for now (a startup script will be covered later):

# named -u bind

Initial Testing

Test a host that exists:

# host www.google.com 127.0.0.1
Using domain server:
Name: 127.0.0.1
Address: 127.0.0.1#53
Aliases: 

www.google.com has address 192.168.1.5

Test a host that does not exist:

# host www.rjksjklghhslkrgjhslhrgk.com 127.0.0.1
Using domain server:
Name: 127.0.0.1
Address: 127.0.0.1#53
Aliases: 

www.rjksjklghhslkrgjhslhrgk.com has address 192.168.1.5

Adjust your web server

If you point the *. record at your web server directly, ensure that your web server is configured to answer for all hostnames, and not just one virtual host.

It is probably also advisable to setup a forward for non-existing files to /, that way if someone requests a full URL, they won’t be greeted with a 404 error, but get the index page instead. That should only matter if they request a page after the initial portal redirect.

Configure a BIND startup script

You can place a simple startup script like this in /usr/local/etc/rc.d/named.sh :

#!/bin/sh

rc_start() {
	# start
	if [ "" = "`ps auxwww | grep 'named ' | awk '{print $2}'`" ]; then
		/usr/local/sbin/named -u bind
	fi
}

rc_stop() {
	killall -9 named 2>/dev/null
	wait
}

case $1 in
	start)
		rc_start
		;;
	stop)
		rc_stop
		;;
	restart)
		rc_stop
		rc_start
		;;
esac

Configure DHCP

Next, configure your DHCP service for the Captive Portal subnet to hand out your newly created DNS server to the clients.

Final Testing

The only step left is to try it on the clients. Fire up a browser, try a non-existant domain (www.kjrbnglakjrghlakrhgalkujerhghjralkrhgl.com for example) and you should be redirected to your web server no matter what domain was requested.