summaryrefslogtreecommitdiffstats
path: root/etc/inc/captiveportal.inc
diff options
context:
space:
mode:
authorScott Ullrich <sullrich@pfsense.org>2005-09-12 18:56:37 +0000
committerScott Ullrich <sullrich@pfsense.org>2005-09-12 18:56:37 +0000
commit3db19cf1b0d5950d2980692c849b8ebc608c3aea (patch)
tree90e87880cc953d09034848b1513ba4203f0ed988 /etc/inc/captiveportal.inc
parentd460bfdc56d5d907368e22cd5e637a5c16c2da41 (diff)
downloadpfsense-3db19cf1b0d5950d2980692c849b8ebc608c3aea.zip
pfsense-3db19cf1b0d5950d2980692c849b8ebc608c3aea.tar.gz
Sync with m0n0wall 1.2b9's captiveportal.
Diffstat (limited to 'etc/inc/captiveportal.inc')
-rw-r--r--etc/inc/captiveportal.inc592
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();
+}
+
?>
OpenPOWER on IntegriCloud