Contents[hide] |
[edit] Software required
Any recent Linux distribution should be able to be used for these scripts. The example shown here uses Debian.The following packages need to be installed:
- conntrack
- sudo
- psmisc
- PHP
- squid (if you want web caching)
There are also other custom scripts, all of which are described below
[edit] Principle of operation
This page assumes that a single server is used on a network of clients to act as a router to the internet. The server should be setup as normal to share a single internet connection (the scripts below include the required firewall rules). On the server a number of iptables firewall rules are used to block a client accessing the internet until they have registered. Registration is carried out by a user browsing to any website, after which they are redirected to a signup webpage (served using Apache and PHP on the server). Once the user has completed the signup form, the client is allowed unrestricted access to the internet.Firewall rules are configured to:
- MARK any traffic from an unrecognised client with the number 99
- DROP any traffic marked 99
- Redirect to the localhost any traffic for port 80 that is MARKed 99
[edit] The users files
In this example a flat file is used to store all the details of users already registered (/var/lib/users). It is in the following format:Name <tab> Email <tab> Client IP <tab> Client MAC <tab> Date
[edit] Firewall rules required
By andy@andybev.com (Oct 2010) - I have just updated these rules based on various items feedback. I have not tested them yet though; please let me know if there are any problems.The following iptables rules are needed in your firewall. Add them to your system's firewall scripts, or alternatively put them in their own file, make it executable, and force it to run at system startup.
IPTABLES=/sbin/iptables # Create internet chain # This is used to authenticate users who have already signed up $IPTABLES -N internet -t nat # First send all traffic via newly created internet chain # At the prerouting NAT stage this will DNAT them to the local # webserver for them to signup if they aren't authorised # Packets for unauthorised users are marked for dropping later $IPTABLES -t nat -A PREROUTING -j internet ###### INTERNET CHAIN ########## # Allow authorised clients in, redirect all others to login webserver # Add known users to the NAT table to stop their dest being rewritten # Ignore MAC address with a * - these users are blocked # This awk script goes through the /var/lib/users flat file line by line awk 'BEGIN { FS="\t"; } { system("$IPTABLES -t nat -A internet -m mac --mac-source "$4" -j RETURN"); }' /var/lib/users # MAC address not found. Mark the packet 99 $IPTABLES -t nat -A internet -j MARK --set-mark 99 # Redirects web requests from Unauthorised users to logon Web Page $IPTABLES -t nat -A internet -m mark --mark 99 -p tcp --dport 80 -j DNAT --to-destination 10.0.0.1 ################################ # Now that we've got to the forward filter, drop all packets # marked 99 - these are unknown users. We can't drop them earlier # as there's no filter table $IPTABLES -t filter -A FORWARD -m mark --mark 99 -j DROP # Do the same for the INPUT chain to stop people accessing the web through Squid $IPTABLES -t filter -A INPUT -p tcp --dport 80 -j ACCEPT $IPTABLES -t filter -A INPUT -p udp --dport 53 -j ACCEPT $IPTABLES -t filter -A INPUT -m mark --mark 99 -j DROP # Enable Internet connection sharing $IPTABLES -A FORWARD -i ppp0 -o eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT $IPTABLES -A FORWARD -i eth0 -o ppp0 -j ACCEPT $IPTABLES -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
[edit] Setting up rmtrack
rmtrack is a one line script to remove connection track information about a client. If this script is not present then when the redirect is done on the completion of a user signing up, they may still not be able to access the page they were looking for. For example, if they go to www.google.com, they will first be redirected to the signup page on the local webserver. When the signup page redirects them back to Google, if the tracking information has not been cleared then they may end up back at the signup page, even though they've already signed up.Create the file /usr/bin/rmtrack and make it executable with the following contents:
/usr/sbin/conntrack -L \ |grep $1 \ |grep ESTAB \ |grep 'dport=80' \ |awk \ "{ system(\"conntrack -D --orig-src $1 --orig-dst \" \ substr(\$6,5) \" -p tcp --orig-port-src \" substr(\$7,7) \" \ --orig-port-dst 80\"); }"Note: the single command has been split over several lines
[edit] Configuring sudo
Sudo needs to be configured to allow the apache web server to issue certain iptables commands in order to allow clients to access the internet after they have signed up. Use visudo to add the following commands to the sudoers file:
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 www-data ALL = NOPASSWD: /usr/bin/rmtrack [0-9]*.[0-9]*.[0-9]*.[0-9]*Note: Sudo does not use regular expressions, so the final rule is not as preferable as it should be.
[edit] PHP script
One PHP script is described here. This is the main index.php script that the user sees when they initially try and access the internet and are redirected. This example script just asks for a user's name and email address, saves them to a file for future reference, and alters iptables rules to allow them access to the internet. The scripts can be edited as required. The example set of scripts at the following link force the user to accept an Acceptable User Policy and also have a facility to block users. http://files.andybev.com/web-portal/web-portal.tar.gzFor an example of how to retain a user's URL, have a look at the discussion page |
<?php $server_name = "hostname"; $domain_name = "example.com"; $site_name = "Betty's Wireless Network"; // Path to the arp command on the local server $arp = "/usr/sbin/arp"; // The following file is used to keep track of users $users = "/var/lib/users"; // Check if we've been redirected by firewall to here. // If so redirect to registration address if ($_SERVER['SERVER_NAME']!="$server_name.$domain_name") { header("location:http://$server_name.$domain_name/index.php?add=" .urlencode($_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'])); exit; } // Attempt to get the client's mac address $mac = shell_exec("$arp -a ".$_SERVER['REMOTE_ADDR']); preg_match('/..:..:..:..:..:../',$mac , $matches); @$mac = $matches[0]; if (!isset($mac)) { exit; } if (!isset($_POST['email']) || !isset($_POST['name'])) { // Name or email address not entered therefore display form ?> <h1>Welcome to <?php echo $site_name;?></h1> To access the Internet you must first enter your details:<br><br> <form method='POST'> <table border=0 cellpadding=5 cellspacing=0> <tr><td>Your full name:</td><td><input type='text' name='name'></td></tr> <tr><td>Your email address:</td><td><input type='text' name='email'></td></tr> <tr><td></td><td><input type='submit' name='submit' value='Submit'></td></tr> </table> </form> <?php } else { enable_address(); } // This function enables the PC on the system by calling iptables, and also saving the // details in the users file for next time the firewall is reset function enable_address() { global $name; global $email; global $mac; global $users; file_put_contents($users,$_POST['name']."\t".$_POST['email']."\t" .$_SERVER['REMOTE_ADDR']."\t$mac\t".date("d.m.Y")."\n",FILE_APPEND + LOCK_EX); // Add PC to the firewall exec("sudo iptables -I internet 1 -t nat -m mac --mac-source $mac -j RETURN"); // The following line removes connection tracking for the PC // This clears any previous (incorrect) route info for the redirection exec("sudo rmtrack ".$_SERVER['REMOTE_ADDR']); sleep(1); header("location:http://".$_GET['add']); exit; } // Function to print page header function print_header() { ?> <html> <head><title>Welcome to <?php echo $site_name;?></title> <META HTTP-EQUIV="CACHE-CONTROL" CONTENT="NO-CACHE"> <LINK rel="stylesheet" type="text/css" href="./style.css"> </head> <body bgcolor=#FFFFFF text=000000> <?php } // Function to print page footer function print_footer() { echo "</body>"; echo "</html>"; } ?>
[edit] In use
Once the firewall has been enabled on the server and the rest of the scripts setup, any client trying to browse to the internet will be presented with a web page to signup. Once they have entered their details, an additional iptables rule will be created which will allow them full access to the internet.Courtesy : http://www.andybev.com/index.php/Using_iptables_and_PHP_to_create_a_captive_portal