Captive Portal


This guide is to help you along in creating a captive portal. A captive portal is a linux router / gateway control system to allow and disallow wired or wireless access via your internet connection, similar to the many hotspots located in numerous businesses around the world. There are some great systems such as pfsense and untangle that are very good routing packages and I recommend them. However, for my needs, I wanted something simpler and very customizable. There are other projects out there to do this but I found the documentation lacking and the projects in various states of decay. What I have compiled here uses pretty much any flavor of Linux and some simple scripts.


Some assumptions

While this guide and accompanied files are not rocket science or a reinvention of the wheel, I will assume you know a little about managing and using Linux. You do not need to be a Sys Admin, but some basic understanding would go well. The scripts are all in bash and php, so nothing crazy there, either; just some basic understanding. The code does have some comments to help you along.


Hardware requirements

Really any commodity PC with two ethernet interfaces will work. I'm partial to using these great SuperMicro mini-servers for Linux routers, Asterisk VoIP servers or pretty much anything else. Low power, and they can fit into wall-mounted network brackets.
SuperMicro Atom-based Servers.


Zip file with the scripts are here.


Packages required

  • A recent Linux kernel with iptables support (most updated distributions these days would be good to go).
  • iptables
  • conntrack
  • sudo
  • dhcpd
  • Some kind of MTA. This can be Sendmail, Postix, Qmail, even ssmtp. Required to send notifications or lists of the registered users.
  • bind (completely optional)
  • sshd
  • Apache (or another web server that can parse PHP)
  • PHP (command line and apache / webserver connector)


Server setup

Some steps here are outside of the scope of this tutorial. Google is your friend.

  1. 1. Get a base installation of your chosen Linux distribution installed and ready to go. Get the previously-mentioned packages via your system's package management. Limit other services unless needed.
  2. 2. Download these scripts to your server and unzip them. I suggest putting all of the scripts (except index.php) in /root/scripts/, but that is up to you.
  3. 3. Configure dhcpd to supply ip's for your private nat network. Nothing crazy here, just make sure the Linux router is listed as the default gw for any connected users.
  4. 4. Configure ssh for remote access. The iptables.rules file has port 2022 open as a rule, so change either your default port for ssh to match or change the iptables.rules file to match the port you specify.
  5. 5. Configure sudo to allow the web server user (specified in the web server's configuration file, i.e. httpd.conf or apache.conf) to access these scripts and commands without needing a password. A sample entry would be :
    www-data ALL = NOPASSWD: /sbin/iptables -I internet 1 -t nat -m mac --mac-source ??\:??\:??\:??\:??\:?? -j RETURN
    www-data ALL = NOPASSWD: /sbin/iptables -D internet -t nat -m mac --mac-source ??\:??\:??\:??\:??\:?? -j RETURN
    This will allow access to iptables but limit it to the rules we specify. You will also need to add entries for the scripts in /root/scripts/. Don't forget to use 'visudo' to add these entries, do not edit the /etc/sudoers file directly!
  6. 6. Configure your system to allow ip forwarding by editing the /etc/sysctl.conf file. This will make sure ip forwarding remains enabled after a restart.
  7. 7. Configure iptables by editing the ip's in the iptables.rules file to match your network set up then using 'iptables-restore < /path_to_file/iptables.rules'. Then do an iptables-save so the rules will persist.
  8. 8. Put a call in to the 'preload.sh' script upon system startup. This can be done via rc.local or any other means of specifying a startup script.
  9. 9. Put the index.php page in your web server's root directory, such as /srv/http or something similar. Again, this is specified in the configuration file for your web server.
  10. 10. Install bind to act as a dns server, if needed. I use these scripts without having dns, instead just using some internet-bound dns servers such as 4.2.2.2


That is most of the heavy lifting. The rest is tweaking of the paths to the different commands (arp,iptables, etc.) and making changes that are specific to your needs. Read through each file and you will see I specified full paths for most system commands. Please go through these and make sure the paths are correct by using the 'which' command, i.e. 'which arp'.


How it works

Basically, any traffic not from specified mac addresses that is destined to the internet is redirected to the index page. Users put in their name, phone number and email address. The email is checked to make sure it is valid, i.e. no one can just put in garbage for their email and get allowed access. If things look good, the 'allow_access.sh' script is called to add the client mac address to the table that is exempt from the redirected traffic and remove the redirected connection so new connections pass through to the internet. If the client selects to store their information, their mac is recorded as an emply file in a location of your choosing, and the 'preload.sh' script adds these mac addresses at boot time. The filled-in information is stored in a tabbed delimited file named after the email address. I've included a script that, when called by cron, will email this info to someone. I also included a script to revoke access and require the specified mac address to be redirected.


This can be expanded like crazy, to include mysql database storage of credentials (including passwords) to traffic shaping and rate limiting of clients. That is again beyond the scope here, but this information can be found via Google or your local Linux Systems Administrator, namely, me. Contact info is at the top right. :)