diff options
author | Scott Ullrich <sullrich@pfsense.org> | 2005-09-12 18:56:37 +0000 |
---|---|---|
committer | Scott Ullrich <sullrich@pfsense.org> | 2005-09-12 18:56:37 +0000 |
commit | 3db19cf1b0d5950d2980692c849b8ebc608c3aea (patch) | |
tree | 90e87880cc953d09034848b1513ba4203f0ed988 | |
parent | d460bfdc56d5d907368e22cd5e637a5c16c2da41 (diff) | |
download | pfsense-3db19cf1b0d5950d2980692c849b8ebc608c3aea.zip pfsense-3db19cf1b0d5950d2980692c849b8ebc608c3aea.tar.gz |
Sync with m0n0wall 1.2b9's captiveportal.
-rw-r--r-- | etc/inc/captiveportal.inc | 592 |
1 files changed, 386 insertions, 206 deletions
diff --git a/etc/inc/captiveportal.inc b/etc/inc/captiveportal.inc index 2cdc63b..52e878d 100644 --- a/etc/inc/captiveportal.inc +++ b/etc/inc/captiveportal.inc @@ -1,26 +1,21 @@ <?php -/* $Id$ */ /* captiveportal.inc - part of pfSense (http://www.pfSense.com) - - Copyright (C) 2005 Scott Ullrich <sullrich@gmail.com> - All rights reserved. - - originally part of m0n0wall (http://m0n0.ch/wall) + part of m0n0wall (http://m0n0.ch/wall) + Copyright (C) 2003-2005 Manuel Kasper <mk@neon1.net>. All rights reserved. - + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE @@ -38,27 +33,37 @@ added rules which may have been created by other per-user code (index.php, etc). These changes are (c) 2004 Keycom PLC. */ - + /* include all configuration functions */ require_once("functions.inc"); +require_once("radius_authentication.inc"); require_once("radius_accounting.inc") ; function captiveportal_configure() { global $config, $g; - - if (isset($config['captiveportal']['enable'])) { - - if($g['booting']) echo "Starting captive portal... "; - + + if (isset($config['captiveportal']['enable']) && + (($config['captiveportal']['interface'] == "lan") || + isset($config['interfaces'][$config['captiveportal']['interface']]['enable']))) { + + if ($g['booting']) + echo "Starting captive portal... "; + /* kill any running mini_httpd */ killbypid("{$g['varrun_path']}/mini_httpd.cp.pid"); killbypid("{$g['varrun_path']}/mini_httpd.cps.pid"); - + /* kill any running minicron */ killbypid("{$g['varrun_path']}/minicron.pid"); - + + /* generate ipfw rules */ + $cprules = captiveportal_rules_generate(); + + /* make sure ipfw is loaded */ + mwexec("/sbin/kldload ipfw"); + /* stop accounting on all clients */ - captiveportal_radius_stop_all() ; + captiveportal_radius_stop_all(); /* remove old information */ unlink_if_exists("{$g['vardb_path']}/captiveportal.nextrule"); @@ -66,7 +71,7 @@ function captiveportal_configure() { unlink_if_exists("{$g['vardb_path']}/captiveportal_mac.db"); unlink_if_exists("{$g['vardb_path']}/captiveportal_ip.db"); unlink_if_exists("{$g['vardb_path']}/captiveportal_radius.db"); - + /* write portal page */ if ($config['captiveportal']['page']['htmltext']) $htmltext = base64_decode($config['captiveportal']['page']['htmltext']); @@ -74,37 +79,16 @@ function captiveportal_configure() { /* example/template page */ $htmltext = <<<EOD <html> -<title>pfSense's captive portal</title> <head> - <STYLE type="text/css"> -.listhdrr { - background-color: #BBBBBB; - padding-right: 16px; - padding-left: 6px; - font-weight: bold; - border-right: 1px solid #999999; - border-bottom: 1px solid #999999; - font-size: 11px; - padding-top: 5px; - padding-bottom: 5px; -} - - </STYLE> +<title>m0n0wall captive portal</title> </head> -<body bgcolor="#990000"> -<center> -<font color="white" face="arial" size="+1">Welcome to pfSense's captive portal!</font> -<p> +<body> +<h2>m0n0wall captive portal</h2> +<p>This is the default captive portal page. Please upload your own custom HTML file on the <em>Services: Captive portal</em> screen in the m0n0wall webGUI.</p> <form method="post" action="\$PORTAL_ACTION\$"> -<table border="0" cellpadding="6" cellspacing="0"> -<tr><td align="right" class="listhdrr"><font color="white">Username:</td><td class="listhdrr"><input name="auth_user" type="text"></td></tr> -<tr><td align="right" class="listhdrr"><font color="white">Password:</td><td class="listhdrr"><input name="auth_pass" type="password"></td></tr> -<input name="redirurl" type="hidden" value="\$PORTAL_REDIRURL\$"> -</table> -<p> -<center><input name="accept" type="submit" value="Continue"> + <input name="accept" type="submit" value="Continue"> + <input name="redirurl" type="hidden" value="\$PORTAL_REDIRURL\$"> </form> -</center> </body> </html> @@ -114,9 +98,9 @@ EOD; $fd = @fopen("{$g['varetc_path']}/captiveportal.html", "w"); if ($fd) { fwrite($fd, $htmltext); - fclose($fd); + fclose($fd); } - + /* write error page */ if ($config['captiveportal']['page']['errtext']) $errtext = base64_decode($config['captiveportal']['page']['errtext']); @@ -143,26 +127,45 @@ EOD; $fd = @fopen("{$g['varetc_path']}/captiveportal-error.html", "w"); if ($fd) { fwrite($fd, $errtext); - fclose($fd); + fclose($fd); } + /* load rules */ + mwexec("/sbin/ipfw -f delete set 1"); + mwexec("/sbin/ipfw -f delete set 2"); + mwexec("/sbin/ipfw -f delete set 3"); + + /* XXX - seems like ipfw cannot accept rules directly on stdin, + so we have to write them to a temporary file first */ + $fd = @fopen("{$g['tmp_path']}/ipfw.cp.rules", "w"); + if (!$fd) { + printf("Cannot open ipfw.cp.rules in captiveportal_configure()\n"); + return 1; + } + + fwrite($fd, $cprules); + fclose($fd); + + mwexec("/sbin/ipfw {$g['tmp_path']}/ipfw.cp.rules"); + + unlink("{$g['tmp_path']}/ipfw.cp.rules"); + + /* filter on layer2 as well so we can check MAC addresses */ + mwexec("/sbin/sysctl net.link.ether.ipfw=1"); + chdir($g['captiveportal_path']); - + /* start web server */ mwexec("/usr/local/sbin/mini_httpd -a -M 0 -u root -maxproc 16" . " -p 8000 -i {$g['varrun_path']}/mini_httpd.cp.pid"); - - $fd = fopen("/tmp/captiveportal.txt", "w"); - fwrite($fd, "/usr/local/sbin/mini_httpd -a -M 0 -u root -maxproc 16 -p 8000 -i {$g['varrun_path']}/mini_httpd.cp.pid"); - fclose($fd); - + /* fire up another one for HTTPS if requested */ if (isset($config['captiveportal']['httpslogin']) && $config['captiveportal']['certificate'] && $config['captiveportal']['private-key']) { - + $cert = base64_decode($config['captiveportal']['certificate']); $key = base64_decode($config['captiveportal']['private-key']); - + $fd = fopen("{$g['varetc_path']}/cert-portal.pem", "w"); if (!$fd) { printf("Error: cannot open cert-portal.pem in system_webgui_start().\n"); @@ -173,32 +176,33 @@ EOD; fwrite($fd, "\n"); fwrite($fd, $key); fclose($fd); - + mwexec("/usr/local/sbin/mini_httpd -S -a -M 0 -E {$g['varetc_path']}/cert-portal.pem" . " -u root -maxproc 16 -p 8001" . " -i {$g['varrun_path']}/mini_httpd.cps.pid"); } - + /* start pruning process (interval = 60 seconds) */ - //mwexec("/usr/local/bin/minicron 60 {$g['varrun_path']}/minicron.pid " . - // "/etc/rc.prunecaptiveportal"); - + mwexec("/usr/local/bin/minicron 60 {$g['varrun_path']}/minicron.pid " . + "/etc/rc.prunecaptiveportal"); + /* generate passthru mac database */ - captiveportal_passthrumac_configure() ; - /* create allowed ip database and insert pf tables to make it so */ - captiveportal_allowedip_configure() ; + captiveportal_passthrumac_configure(); + /* create allowed ip database and insert ipfw rules to make it so */ + captiveportal_allowedip_configure(); /* generate radius server database */ - if($config['captiveportal']['radiusip'] && $config['captiveportal']['auth_method']=="radius") { - $radiusip = $config['captiveportal']['radiusip'] ; + if ($config['captiveportal']['radiusip'] && (!isset($config['captiveportal']['auth_method']) || + ($config['captiveportal']['auth_method'] == "radius"))) { + $radiusip = $config['captiveportal']['radiusip']; - if($config['captiveportal']['radiusport']) - $radiusport = $config['captiveportal']['radiusport'] ; + if ($config['captiveportal']['radiusport']) + $radiusport = $config['captiveportal']['radiusport']; else $radiusport = 1812; - if($config['captiveportal']['radiusacctport']) - $radiusacctport = $config['captiveportal']['radiusacctport'] ; + if ($config['captiveportal']['radiusacctport']) + $radiusacctport = $config['captiveportal']['radiusacctport']; else $radiusacctport = 1813; @@ -209,134 +213,277 @@ EOD; printf("Error: cannot open radius DB file in captiveportal_configure().\n"); return 1; } else { - fwrite($fd,$radiusip . "," . $radiusport . "," . $radiusacctport . "," . $radiuskey) ; + fwrite($fd,$radiusip . "," . $radiusport . "," . $radiusacctport . "," . $radiuskey); } - fclose($fd) ; + fclose($fd); } - if($g['booting']) print "done.\n"; - + if ($g['booting']) + echo "done\n"; + } else { killbypid("{$g['varrun_path']}/mini_httpd.cp.pid"); + killbypid("{$g['varrun_path']}/mini_httpd.cps.pid"); killbypid("{$g['varrun_path']}/minicron.pid"); - captiveportal_radius_stop_all() ; - } + captiveportal_radius_stop_all(); + + mwexec("/sbin/sysctl net.link.ether.ipfw=0"); + + if (!isset($config['shaper']['enable'])) { + /* unload ipfw */ + mwexec("/sbin/kldunload ipfw"); + } else { + /* shaper is on - just remove our rules */ + mwexec("/sbin/ipfw -f delete set 1"); + mwexec("/sbin/ipfw -f delete set 2"); + mwexec("/sbin/ipfw -f delete set 3"); + } + } + return 0; } +function captiveportal_rules_generate() { + global $config, $g; + + $cpifn = $config['captiveportal']['interface']; + $cpif = $config['interfaces'][$cpifn]['if']; + $cpip = $config['interfaces'][$cpifn]['ipaddr']; + + /* note: the captive portal daemon inserts all pass rules for authenticated + clients as skipto 50000 rules to make traffic shaping work */ + + $cprules = ""; + + /* captive portal on LAN interface? */ + if ($cpifn == "lan") { + /* add anti-lockout rules */ + $cprules .= <<<EOD +add 500 set 1 pass all from $cpip to any out via $cpif +add 501 set 1 pass all from any to $cpip in via $cpif + +EOD; + } + + $cprules .= <<<EOD +# skip to traffic shaper if not on captive portal interface +add 1000 set 1 skipto 50000 all from any to any not layer2 not via $cpif +# pass all layer2 traffic on other interfaces +add 1001 set 1 pass layer2 not via $cpif + +# layer 2: pass ARP +add 1100 set 1 pass layer2 mac-type arp +# layer 2: block anything else non-IP +add 1101 set 1 deny layer2 not mac-type ip +# layer 2: check if MAC addresses of authenticated clients are correct +add 1102 set 1 skipto 20000 layer2 + +# allow access to our DHCP server (which needs to be able to ping clients as well) +add 1200 set 1 pass udp from any 68 to 255.255.255.255 67 in +add 1201 set 1 pass udp from any 68 to $cpip 67 in +add 1202 set 1 pass udp from $cpip 67 to any 68 out +add 1203 set 1 pass icmp from $cpip to any out icmptype 8 +add 1204 set 1 pass icmp from any to $cpip in icmptype 0 + +# allow access to our DNS forwarder +add 1300 set 1 pass udp from any to $cpip 53 in +add 1301 set 1 pass udp from $cpip 53 to any out + +# allow access to our web server +add 1302 set 1 pass tcp from any to $cpip 8000 in +add 1303 set 1 pass tcp from $cpip 8000 to any out + +EOD; + + if (isset($config['captiveportal']['httpslogin'])) { + $cprules .= <<<EOD +add 1304 set 1 pass tcp from any to $cpip 8001 in +add 1305 set 1 pass tcp from $cpip 8001 to any out + +EOD; + } + + $cprules .= <<<EOD + +# ... 10000-19899: rules per authenticated client go here... + +# redirect non-authenticated clients to captive portal +add 19900 set 1 fwd 127.0.0.1,8000 tcp from any to any 80 in +# let the responses from the captive portal web server back out +add 19901 set 1 pass tcp from any 80 to any out +# block everything else +add 19902 set 1 deny all from any to any + +# ... 20000-29899: layer2 block rules per authenticated client go here... + +# pass everything else on layer2 +add 29900 set 1 pass all from any to any layer2 + +EOD; + + return $cprules; +} + /* remove clients that have been around for longer than the specified amount of time */ -/* db file structure: timestamp,clientip,clientmac,username,sessionid */ +/* db file structure: timestamp,ipfw_rule_no,clientip,clientmac,username,sessionid,password */ +/* (password is in Base64 and only saved when reauthentication is enabled) */ function captiveportal_prune_old() { - + global $g, $config; - + /* check for expired entries */ if ($config['captiveportal']['timeout']) $timeout = $config['captiveportal']['timeout'] * 60; else $timeout = 0; - + if ($config['captiveportal']['idletimeout']) $idletimeout = $config['captiveportal']['idletimeout'] * 60; else $idletimeout = 0; - - if (!$timeout && !$idletimeout) + + if (!$timeout && !$idletimeout && !isset($config['captiveportal']['reauthenticate'])) return; - + captiveportal_lock(); - + /* read database */ $cpdb = captiveportal_read_db(); - + $radiusservers = captiveportal_get_radius_servers(); - - if($idletimeout <> 0) { - /* launch expire table and remove entries older than $timeout */ - mwexec("/usr/bin/nice -n20 /usr/local/sbin/expiretable -v -t {$idletimeout} captiveportal"); - } - - $after_prune = `/sbin/pfctl -t captiveportal -T show`; - - /* - * loop back through and determine if expiretable removed a client. - * if we detect a client removal then update the internal db accordingly - */ + for ($i = 0; $i < count($cpdb); $i++) { - + $timedout = false; - - /* hard timeout? */ - if ((time() - $cpdb[$i][0]) >= $timeout) - $timedout = true; - if(stristr($after_prune, $cpdb[$i][2]) == false) - $timedout= true; - + /* hard timeout? */ + if ($timeout) { + if ((time() - $cpdb[$i][0]) >= $timeout) + $timedout = true; + } + + /* if an idle timeout is specified, get last activity timestamp from ipfw */ + if (!$timedout && $idletimeout) { + $lastact = captiveportal_get_last_activity($cpdb[$i][1]); + if ($lastact && ((time() - $lastact) >= $idletimeout)) + $timedout = true; + } + if ($timedout) { - /* this client needs to be deleted - remove pf table item */ - if (isset($config['captiveportal']['radacct_enable']) && isset($radiusservers[0])) { - RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno - $cpdb[$i][4], // username - $cpdb[$i][5], // sessionid - $cpdb[$i][0], // start time - $radiusservers[0]['ipaddr'], - $radiusservers[0]['acctport'], - $radiusservers[0]['key'], - $cpdb[$i][2]); //clientip - syslog(LOG_INFO,"Authenticated user $cpdb[$i][4] timed out"); - } - + captiveportal_disconnect($cpdb[$i], $radiusservers); + captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "TIMEOUT"); unset($cpdb[$i]); } + + /* do periodic RADIUS reauthentication? */ + if (!$timedout && isset($config['captiveportal']['reauthenticate']) && + ($radiusservers !== false)) { + + if (isset($config['captiveportal']['radacct_enable'])) { + if ($config['captiveportal']['reauthenticateacct'] == "stopstart") { + /* stop and restart accounting */ + RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno + $cpdb[$i][4], // username + $cpdb[$i][5], // sessionid + $cpdb[$i][0], // start time + $radiusservers[0]['ipaddr'], + $radiusservers[0]['acctport'], + $radiusservers[0]['key'], + $cpdb[$i][2]); //clientip + exec("/sbin/ipfw zero {$cpdb[$i][1]}"); + RADIUS_ACCOUNTING_START($cpdb[$i][4], + $cpdb[$i][5], + $radiusservers[0]['ipaddr'], + $radiusservers[0]['acctport'], + $radiusservers[0]['key'], + $cpdb[$i][2]); + } else if ($config['captiveportal']['reauthenticateacct'] == "interimupdate") { + RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno + $cpdb[$i][4], // username + $cpdb[$i][5], // sessionid + $cpdb[$i][0], // start time + $radiusservers[0]['ipaddr'], + $radiusservers[0]['acctport'], + $radiusservers[0]['key'], + $cpdb[$i][2], //clientip + true); + } + } + + /* check this user against RADIUS again */ + $auth_val = RADIUS_AUTHENTICATION($cpdb[$i][4], + base64_decode($cpdb[$i][6]), + $radiusservers[0]['ipaddr'], + $radiusservers[0]['port'], + $radiusservers[0]['key']); + + if ($auth_val == 3) { + captiveportal_disconnect($cpdb[$i], $radiusservers); + captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "RADIUS_DISCONNECT"); + unset($cpdb[$i]); + } + } } - + /* write database */ captiveportal_write_db($cpdb); - + captiveportal_unlock(); } -/* remove a single client */ -function captiveportal_disconnect_client($id) { - +/* remove a single client according to the DB entry */ +function captiveportal_disconnect($dbent, $radiusservers) { + global $g, $config; + + /* this client needs to be deleted - remove ipfw rules */ + if (isset($config['captiveportal']['radacct_enable']) && isset($radiusservers[0])) { + RADIUS_ACCOUNTING_STOP($dbent[1], // ruleno + $dbent[4], // username + $dbent[5], // sessionid + $dbent[0], // start time + $radiusservers[0]['ipaddr'], + $radiusservers[0]['acctport'], + $radiusservers[0]['key'], + $dbent[2]); //clientip + } + + mwexec("/sbin/ipfw delete " . $dbent[1] . " " . ($dbent[1]+10000)); + + //KEYCOM: we need to delete +40500 and +45500 as well... + //these are the rule numbers we use to control traffic shaping for each logged in user via captive portal + //we only need to remove our rules if peruserbw is turned on. + if (isset($config['captiveportal']['peruserbw'])) { + mwexec("/sbin/ipfw delete " . ($dbent[1]+40500)); + mwexec("/sbin/ipfw delete " . ($dbent[1]+45500)); + } +} +/* remove a single client by ipfw rule number */ +function captiveportal_disconnect_client($id) { + + global $g, $config; + captiveportal_lock(); - + /* read database */ $cpdb = captiveportal_read_db(); $radiusservers = captiveportal_get_radius_servers(); - - /* find entry */ + + /* find entry */ for ($i = 0; $i < count($cpdb); $i++) { if ($cpdb[$i][1] == $id) { - /* this client needs to be deleted - remove pf table item */ - if (isset($config['captiveportal']['radacct_enable']) && isset($radiusservers[0])) { - RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno - $cpdb[$i][4], // username - $cpdb[$i][5], // sessionid - $cpdb[$i][0], // start time - $radiusservers[0]['ipaddr'], - $radiusservers[0]['acctport'], - $radiusservers[0]['key'], - $cpdb[$i][2]); //clientip - syslog(LOG_INFO,"Authenticated user $cpdb[$i][4] disconnected"); - } - - mwexec("/sbin/pfctl -t captiveportal -T delete {$cpdb[$i][2]}"); - + captiveportal_disconnect($cpdb[$i], $radiusservers); + captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "DISCONNECT"); unset($cpdb[$i]); - break; } } - - + /* write database */ captiveportal_write_db($cpdb); - + captiveportal_unlock(); } @@ -344,11 +491,11 @@ function captiveportal_disconnect_client($id) { function captiveportal_radius_stop_all() { global $g, $config; - captiveportal_lock() ; - $cpdb = captiveportal_read_db() ; - + captiveportal_lock(); + $cpdb = captiveportal_read_db(); + $radiusservers = captiveportal_get_radius_servers(); - + if (isset($radiusservers[0])) { for ($i = 0; $i < count($cpdb); $i++) { RADIUS_ACCOUNTING_STOP($cpdb[$i][1], // ruleno @@ -361,40 +508,43 @@ function captiveportal_radius_stop_all() { $cpdb[$i][2]); //clientip } } - captiveportal_unlock() ; + captiveportal_unlock(); } function captiveportal_passthrumac_configure() { global $config, $g; - + + captiveportal_lock(); + /* clear out passthru macs, if necessary */ - if (file_exists("{$g['vardb_path']}/captiveportal_mac.db")) { - unlink("{$g['vardb_path']}/captiveportal_mac.db"); - } - + unlink_if_exists("{$g['vardb_path']}/captiveportal_mac.db"); + if (is_array($config['captiveportal']['passthrumac'])) { - + $fd = @fopen("{$g['vardb_path']}/captiveportal_mac.db", "w"); if (!$fd) { printf("Error: cannot open passthru mac DB file in captiveportal_passthrumac_configure().\n"); - return 1; + captiveportal_unlock(); + return 1; } - + foreach ($config['captiveportal']['passthrumac'] as $macent) { /* record passthru mac so it can be recognized and let thru */ fwrite($fd, $macent['mac'] . "\n"); } - - fclose($fd); + + fclose($fd); } - + + captiveportal_unlock(); + return 0; } function captiveportal_allowedip_configure() { global $config, $g; - - captiveportal_lock() ; + + captiveportal_lock(); /* clear out existing allowed ips, if necessary */ if (file_exists("{$g['vardb_path']}/captiveportal_ip.db")) { @@ -402,36 +552,51 @@ function captiveportal_allowedip_configure() { if ($fd) { while (!feof($fd)) { $line = trim(fgets($fd)); - if($line) { + if ($line) { list($ip,$rule) = explode(",",$line); - mwexec("/sbin/pfctl -t captiveportal -T delete {$ip}"); - } + mwexec("/sbin/ipfw delete $rule"); + } } } - fclose($fd) ; + fclose($fd); unlink("{$g['vardb_path']}/captiveportal_ip.db"); } + /* get next ipfw rule number */ + if (file_exists("{$g['vardb_path']}/captiveportal.nextrule")) + $ruleno = trim(file_get_contents("{$g['vardb_path']}/captiveportal.nextrule")); + if (!$ruleno) + $ruleno = 10000; /* first rule number */ + if (is_array($config['captiveportal']['allowedip'])) { - + $fd = @fopen("{$g['vardb_path']}/captiveportal_ip.db", "w"); if (!$fd) { printf("Error: cannot open allowed ip DB file in captiveportal_allowedip_configure().\n"); - captiveportal_unlock() ; - return 1; + captiveportal_unlock(); + return 1; } - + foreach ($config['captiveportal']['allowedip'] as $ipent) { + /* record allowed ip so it can be recognized and removed later */ - fwrite($fd, $ipent['ip'] . "," . $ipent['ip'] ."\n"); - /* insert pf table item to allow traffic */ - mwexec("echo \"pfctl -t captiveportal -T add {$ipent['ip']} \"> /tmp/tmp"); - mwexec("/sbin/pfctl -t captiveportal -T add {$ipent['ip']}"); - - $ruleno = $ip; + fwrite($fd, $ipent['ip'] . "," . $ruleno ."\n"); + + /* insert ipfw rule to allow ip thru */ + if ($ipent['dir'] == "from") { + mwexec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from " . $ipent['ip'] . " to any in"); + mwexec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from any to " . $ipent['ip'] . " out"); + } else { + mwexec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from any to " . $ipent['ip'] . " in"); + mwexec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from " . $ipent['ip'] . " to any out"); + } + + $ruleno++; + if ($ruleno > 19899) + $ruleno = 10000; } - - fclose($fd); + + fclose($fd); /* write next rule number */ $fd = @fopen("{$g['vardb_path']}/captiveportal.nextrule", "w"); @@ -440,26 +605,31 @@ function captiveportal_allowedip_configure() { fclose($fd); } } - - captiveportal_unlock() ; + + captiveportal_unlock(); return 0; } -/* get last activity timestamp given pf table item */ -function captiveportal_get_last_activity($ip) { - - $info = `/usr/sbin/arp -an | /usr/bin/grep $ip`; - - if($info <> "") return 1; - +/* get last activity timestamp given ipfw rule number */ +function captiveportal_get_last_activity($ruleno) { + + exec("/sbin/ipfw -T list {$ruleno} 2>/dev/null", $ipfwoutput); + + /* in */ + if ($ipfwoutput[0]) { + $ri = explode(" ", $ipfwoutput[0]); + if ($ri[1]) + return $ri[1]; + } + return 0; } /* read captive portal DB into array */ function captiveportal_read_db() { - + global $g; - + $cpdb = array(); $fd = @fopen("{$g['vardb_path']}/captiveportal.db", "r"); if ($fd) { @@ -467,7 +637,7 @@ function captiveportal_read_db() { $line = trim(fgets($fd)); if ($line) { $cpdb[] = explode(",", $line); - } + } } fclose($fd); } @@ -476,9 +646,9 @@ function captiveportal_read_db() { /* write captive portal DB */ function captiveportal_write_db($cpdb) { - + global $g; - + $fd = @fopen("{$g['vardb_path']}/captiveportal.db", "w"); if ($fd) { foreach ($cpdb as $cpent) { @@ -490,9 +660,9 @@ function captiveportal_write_db($cpdb) { /* read RADIUS servers into array */ function captiveportal_get_radius_servers() { - + global $g; - + if (file_exists("{$g['vardb_path']}/captiveportal_radius.db")) { $fd = @fopen("{$g['vardb_path']}/captiveportal_radius.db","r"); if ($fd) { @@ -506,22 +676,22 @@ function captiveportal_get_radius_servers() { } } fclose($fd); - + return $radiusservers; } } - + return false; } /* lock captive portal information, decide that the lock file is stale after 10 seconds */ function captiveportal_lock() { - + global $g; - + $lockfile = "{$g['varrun_path']}/captiveportal.lock"; - + $n = 0; while ($n < 10) { /* open the lock file in append mode to avoid race condition */ @@ -539,13 +709,23 @@ function captiveportal_lock() { /* unlock configuration file */ function captiveportal_unlock() { - + global $g; - + $lockfile = "{$g['varrun_path']}/captiveportal.lock"; - + if (file_exists($lockfile)) unlink($lockfile); } +/* log successful captive portal authentication to syslog */ +/* part of this code from php.net */ +function captiveportal_logportalauth($user,$mac,$ip,$status) { + define_syslog_variables(); + openlog("logportalauth", LOG_PID, LOG_LOCAL4); + // Log it + syslog(LOG_INFO, "$status: $user, $mac, $ip"); + closelog(); +} + ?> |