There aren’t (m)any lightweight captive portal solutions out there for us, except a few clumsy heavy or badly maintained projects together with heir professional counterparts in routers better than home-grade. Captive portals are cool and useful, read on how to build one, including video demo.
If you have read http://www.bsdguides.org/2012/a-wireless-access-point-hotspot-using-openbsd/ then you already know how to build a wireless access point. If not – also fine, because i will go trough the whole process once again, except this time we will configure our system to configure on boot, instead of via a script. Of course Wifi is not required to run a captive portal, you can use this method to have it run on a regular firewall router as well.
Have a look at the movie to see it working in action before doing your own thing:
Youtube movie coming asap…
You need a fresh install of OpenBSD 5.2 on a machine with two Network Cards. I used an older Asus EEEPC with wired + wireless NIC (alc0 & athn0).
You will also need to head over to GitHub and download the OpenBSD Captive Portal files – they contain the application and sample configuration files. They also contain a install.sh script, which helps you move everything into place – be sure to carefully understand what it does before running it though, as it will overwrite a bunch of configuration files such as /etc/pf.conf and /etc/dhcpd.conf to name a few.
The rest of this guide assumes you have extracted the Github files into a folder called /root/obsdcp
A quick overview of what a captive portal usually does and what this project wants to achieve: A user connects to a wireless access point, say in a Hotel. The access point will give an IP Address, but will not yet allow any traffic such as web or mail. When the user opens his browser, he is presented with a hotel login form of some sort. The user logs in using a password he is provided (by the front desk), and the access point informs the user that he now has internet access for a certain amount of time. The captive portal adds the Users IP address to a whitelist table that is allowed network access, and checks at regular intervals for addresses that need to be expired.
Lets get to it.
Setting up Apache
We need to configure and run our web server so we can intercept and serve web requests from non-authenticated clients. Open up your /var/www/conf/httpd.conf and make sure it has the following configuration directives:
Listen *:80 ServerName localhost # Set a sensible contact info ServerAdmin email@example.com # Uncomment rewrite_module and expires_module LoadModule rewrite_module ... LoadModule expires_module ... # Find
and set AllowOverride All # to allow .htaccess AllowOverride All
Because our httpd runs chrooted and our captive portal depends on Perl and CGI.pm, we need create a few folders and copy a bunch of files into our webserver directory.
mkdir /var/www/usr mkdir /var/www/usr/bin mkdir /var/www/usr/lib mkdir /var/www/usr/libdata mkdir /var/www/usr/libexec cd /var/www/usr/bin cp /usr/bin/perl . cd /var/www/usr/lib cp /usr/lib/libperl.so.* . cp /usr/lib/libm.so.* . cp /usr/lib/libutil.so.* . cp /usr/lib/libc.so.* . cd /var/www/usr/libexec cp /usr/libexec/ld.so . # Here i am copying a lot of possibly # unneeded modules for perls CGI.pm # But it got the job done and i can use # all of Perls base modules inside a # chrooted httpd cd /var/www/usr/libdata cp -r /usr/libdata/perl5 .
Add the following line to /etc/rc.conf.local so httpd starts on boot
httpd_flags = ""
Setting up the portal application
Move needed files into place – remember the downloaded GitHub Files are at /root/obsdcp
cd /root/obsdcp cp var/www/htdocs/* /var/www/htdocs/ cp var/www/conf/Obsdcp_config.pm /var/www/conf/ cp usr/local/bin/obsdcp /usr/local/bin/ cp etc/rc.d/obsdcp /etc/rc.d/obsdcp touch /var/www/conf/obsdcp_queue.txt touch /var/www/conf/obsdcp_allow.txt
obsdcp does the heavy lifting: It checks for new IPs to add to the whitelist, and existing IPs to expire after their time has run out. Add the following line to the end of /etc/rc.conf.local so obsdcp starts on boot
Now we need to adjust a few file permissions:
cd /var/www/conf/ chown www:daemon *.txt chmod 755 *.txt # Set permissions cd /var/www/htdocs/ chown www:daemon .htaccess chown www:daemon * chmod 755 .htaccess chmod 755 *
Lets setup our wired and wireless interfaces. Find out your interface names by running ifconfig. Mine are as follows:
wired: alc0 wireless: athn0
Create /etc/hostname.alc0 so your wired interface is configured automatically at each boot. We need to give it a fixed IP and add your LAN’s default Router so it can access the Internet.
inet 10.0.1.254 255.255.255.0 10.0.1.255
Adding the default Router to /etc/mygate
Now lets setup our wireless interface to be a wireless hotspot; create /etc/hostname.athn0. It will setup your open wireless hotspot using the SSID FreeWifi on channel 11. Note the below is all on one line.
inet 10.0.3.1 255.255.255.0 10.0.3.255 \ media autoselect mediaopt hostap \ nwid FreeWifi chan 11 up
Configuring your Firewall
Firstly, set the sysctl to allow passing of packets between interfaces by adjusting /etc/sysctl.conf:
Now copy the provided pf.conf to /etc/pf.conf
cd /root/obsdcp cp /etc/pf.conf /etc/pf.conf.bak cp etc/pf.conf /etc/pf.conf
I suggest you open up /etc/pf.conf and have a look at how it works; quote possible that you need to adjust the network interface names at the top to match your hardware.
Our pf.conf uses a table called whitelist to keep track of who is allowed internet access.
Add the following line to /etc/rc.conf.local so PF starts on boot
You will need to run dhcpd to provide network configuration to clients connecting to your access point. Copy the provided file, but adjust as you need. It’s not good to blindly copy stuff, always have a look inside and try to understand what it does.
cd ocbsdcp cp /etc/dhcpd.conf /etc/dhcpd.conf.bak cp etc/dhcpd.conf /etc/
Add the following line to /etc/rc.conf.local so dhcpd starts on boot
Yes, we want DNS as well; its not strictly needed but we can do a lot of nice things with it such as url filtering or ad blocking.
cd ocbsdcp cp -r /var/named /var/named-bak cp var/named/etc/named.conf /var/named/etc/ cp var/named/etc/rndc.conf /var/named/etc/ cp var/named/etc/rndc.key /var/named/etc/ cp etc/resolv.conf /etc/resolv.conf
Add the following line to /etc/rc.conf.local so named starts on boot
Check and reboot
Now its time to make sure everything works as expected. Reboot your access point and check that:
- You can ping your Router
- You can ping bsdguides.org
- Apache is running
- dhcpd is running for your wireless NIC
- named is running
- PF is enabled
- obsdcp is running
Check that relevant services are running by using ps -ax and netstat -an, also check your /var/log/messages and /var/log/daemon logfiles for any potential error messages. For any issues, troubleshoot, reboot, repeat.
Given that you followed the above guidelines and neither of us made any mistakes, you now have an access point with a captive portal. Connect to the “FreeWifi” access point by using your mobile or laptop, and try to browse the Internet. Are you asked to provide credentials before being allowed access? Great! Simple configuration and account management can be done inside /var/www/htdocs/Obsdcp_config.pm – you probably want to change those default username and passwords.
I chose to keep the index.cgi as simple as possible so everything is in base; though i am considering a more feature rich frontend as well. For the moment, this does the job just fine, and runs happily inside a coffee shop i frequently visit.
Let me know what can be improved, post your issues or suggestions in the comments.