From f4de164945b8bad2fa8889e8d103e2a99da63590 Mon Sep 17 00:00:00 2001 From: jdegraeve Date: Thu, 9 Feb 2006 13:51:46 +0000 Subject: [PATCH] Updating files, needed for second commit (name change) git-svn-id: https://svn.m0n0.ch/wall/trunk@66 e36fee2c-cc09-0410-a7cc-ebac5c6737de --- ...p.inc => radius_accounting_nas_ip_old.inc} | 2 +- ...counting.inc => radius_accounting_old.inc} | 0 captiveportal/radius_accounting_v2.inc | 342 ++--- captiveportal/radius_authentication.inc | 74 +- phpconf/inc/captiveportal.inc | 1356 +++++++++-------- 5 files changed, 886 insertions(+), 888 deletions(-) rename captiveportal/{radius_accounting_nas_ip.inc => radius_accounting_nas_ip_old.inc} (99%) rename captiveportal/{radius_accounting.inc => radius_accounting_old.inc} (100%) diff --git a/captiveportal/radius_accounting_nas_ip.inc b/captiveportal/radius_accounting_nas_ip_old.inc similarity index 99% rename from captiveportal/radius_accounting_nas_ip.inc rename to captiveportal/radius_accounting_nas_ip_old.inc index bb876a6..54c6706 100644 --- a/captiveportal/radius_accounting_nas_ip.inc +++ b/captiveportal/radius_accounting_nas_ip_old.inc @@ -49,7 +49,7 @@ function RADIUS_ACCOUNTING_START($ruleno,$username,$sessionid,$radiusip,$radiusp $nas_ip = get_current_wan_address(); $nas_ip_exp = explode(".",$nas_ip); - $nas_mac = get_interface_mac($config['interfaces']['wan']['if']); // This function is defined in radius_authentication.inc + $nas_mac = get_interface_mac($config['interfaces']['wan']['if']); // This function is defined in interfaces.inc $nas_port = $ruleno - 10000; $ip_exp=explode(".",$clientip); $radiusvendor = $config['captiveportal']['radiusvendor'] ? $config['captiveportal']['radiusvendor'] : null; diff --git a/captiveportal/radius_accounting.inc b/captiveportal/radius_accounting_old.inc similarity index 100% rename from captiveportal/radius_accounting.inc rename to captiveportal/radius_accounting_old.inc diff --git a/captiveportal/radius_accounting_v2.inc b/captiveportal/radius_accounting_v2.inc index c663ada..6c492b5 100644 --- a/captiveportal/radius_accounting_v2.inc +++ b/captiveportal/radius_accounting_v2.inc @@ -2,47 +2,39 @@ /* vim: set expandtab tabstop=4 shiftwidth=4: */ /* -$Id$ - -Copyright (c) 2006, Jonathan De Graeve -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. -3. The names of the authors may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -This code cannot simply be copied and put under the GNU Public License or -any other GPL-like (LGPL, GPL2) License. - - This code is made possible thx to samples made by Michael Bretterklieber - author of the PHP PECL Radius package - - Changes made include: - * Porting to M0n0wall environment - * Sends NAS-IP-Address AND Nas-Identifier (first word of hostname) in Accounting request - * Sending of Framed-IP-Address (client IP) - * Sending of Called-Station-ID (NAS IP) - * Sending of Calling-Station-ID (client IP) - * RADIUS Extensions (RFC2869) => Acct-(Input|Output)-Gigawords + $Id$ + + Copyright (c) 2006, Jonathan De Graeve + 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. + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + This code cannot simply be copied and put under the GNU Public License or + any other GPL-like (LGPL, GPL2) License. + + This code is made possible thx to samples made by Michael Bretterklieber + author of the PHP PECL Radius package */ @@ -55,9 +47,8 @@ function RADIUS_ACCOUNTING_START($ruleno,$username,$sessionid,$radiusip,$radiusp global $config; - $nas_mac = get_interface_mac($config['interfaces']['wan']['if']); // This function is defined in radius_authentication.inc + $nas_mac = get_interface_mac($config['interfaces']['wan']['if']); $nas_port = $ruleno - 10000; - $ip_exp=explode(".",$clientip); $radiusvendor = $config['captiveportal']['radiusvendor'] ? $config['captiveportal']['radiusvendor'] : null; switch($radiusvendor) { @@ -75,54 +66,56 @@ function RADIUS_ACCOUNTING_START($ruleno,$username,$sessionid,$radiusip,$radiusp if ($debug) echo "
radius-port: $radiusport
radius-host: $radiusip
username: $username
\n"; -// Create our instance -$racct = new Auth_RADIUS_Acct_Start; - -/* Different Authentication options - * - * Its possible todo other authentication methods but still do radius accounting - - RADIUS_AUTH_RADIUS => authenticated via Radius - RADIUS_AUTH_LOCAL => authenicated local - RADIUS_AUTH_REMOTE => authenticated remote - - */ + // Create our instance + $racct = new Auth_RADIUS_Acct_Start; + + /* Different Authentication options + * + * Its possible todo other authentication methods but still do radius accounting + * + * RADIUS_AUTH_RADIUS => authenticated via Radius + * RADIUS_AUTH_LOCAL => authenticated local + * RADIUS_AUTH_REMOTE => authenticated remote + * + */ -$racct->authentic = RADIUS_AUTH_RADIUS; + $racct->authentic = RADIUS_AUTH_RADIUS; -// Construct data package -$racct->addServer($radiusip, $radiusport, $radiuskey); -$racct->username = $username; + // Construct data package + $racct->addServer($radiusip, $radiusport, $radiuskey); + $racct->username = $username; + if (PEAR::isError($racct->start())) { + $retvalue['acct_val'] = 1; + $retvalue['error'] = $racct->getMessage(); + if ($debug) + printf("Radius start: %s
\n", $retvalue['error']); + + /* Old code: + * $status = $racct->start(); + * if(PEAR::isError($status)) { + * if ($debug) + * printf("Radius start: %s
\n", $status->getMessage()); + * exit; + * } + */ + } -if (PEAR::isError($racct->start())) { - $retvalue['acct_val'] = 1; - $retvalue['error'] = $rauth->getMessage(); - if ($debug) - printf("Radius start: %s
\n", $retvalue['error']); - - /* Old code: - $status = $racct->start(); - if(PEAR::isError($status)) { - if ($debug) - printf("Radius start: %s
\n", $status->getMessage()); - exit; - } + /* + * NAS_PORT_TYPE, int => RADIUS_ETHERNET (15), RADIUS_WIRELESS_OTHER (18), RADIUS_WIRELESS_IEEE_802_11 (19) */ -} -/* -NAS_PORT_TYPE, int => RADIUS_ETHERNET (15), RADIUS_WIRELESS_OTHER (18), RADIUS_WIRELESS_IEEE_802_11 (19) -*/ + // Default attributes + $racct->putAttribute(RADIUS_NAS_PORT_TYPE, RADIUS_ETHERNET); + $racct->putAttribute(RADIUS_NAS_PORT, $nas_port); + $racct->putAttribute(RADIUS_ACCT_SESSION_ID, $sessionid); + $racct->putAttribute(RADIUS_SERVICE_TYPE, RADIUS_OUTBOUND); + // Extra data to identify the client and nas + $racct->putAttribute(RADIUS_FRAMED_IP_ADDRESS, $clientip); + $racct->putAttribute(RADIUS_CALLING_STATION_ID, $callingstationid); + $racct->putAttribute(RADIUS_CALLED_STATION_ID, $calledstationid); -// Other options -$racct->putAttribute(RADIUS_SERVICE_TYPE, RADIUS_LOGIN); -$racct->putAttribute(RADIUS_NAS_PORT, 0); -$racct->putAttribute(RADIUS_NAS_PORT_TYPE, RADIUS_ETHERNET); -$racct->putAttribute(RADIUS_ACCT_SESSION_ID, $sessionid); -$racct->putAttribute(RADIUS_FRAMED_IP_ADDRESS, $clientip); // Send request - $result = $racct->send(); if (PEAR::isError($result)) { $retvalue['acct_val'] = 1; @@ -154,94 +147,99 @@ RADIUS ACCOUNTING STOP/UPDATE */ function RADIUS_ACCOUNTING_STOP($ruleno,$username,$sessionid,$start_time,$radiusip,$radiusport,$radiuskey,$clientip,$clientmac, $term_cause = 1, $interimupdate=false,$stop_time = null) { - global $config; - $stop_time = (empty($stop_time)) ? time() : $stop_time; + global $config; - $nas_port = $ruleno - 10000; $nas_mac = get_interface_mac($config['interfaces']['wan']['if']); + $nas_port = $ruleno - 10000; + $radiusvendor = $config['captiveportal']['radiusvendor'] ? $config['captiveportal']['radiusvendor'] : null; + $stop_time = (empty($stop_time)) ? time() : $stop_time; $session_time = $stop_time - $start_time; - $radiusvendor = $config['captiveportal']['radiusvendor'] ? $config['captiveportal']['radiusvendor'] : null + $volume = getVolume($ruleno); + $volume['input_bytes_radius'] = remainder($volume['input_bytes']); + $volume['input_gigawords'] = gigawords($volume['input_bytes']); + $volume['output_bytes_radius'] = remainder($volume['output_bytes']); + $volume['output_gigawords'] = gigawords($volume['output_bytes']); + + switch($radiusvendor) { + + case 'cisco': + $calledstationid = $clientmac; + $callingstationid = $clientip; + break; + + default: + $calledstationid = $nas_mac; + $callingstationid = $clientmac; + } if ($debug) echo "
radius-port: $radiusport
radius-host: $radiusip
username: $username
\n"; - // See if we should use Accounting Interim Updates or Accounting STOP messages if ($interimupdate) $racct = new_Auth_RADIUS_Acct_Update; else $racct = new_Auth_RADIUS_Acct_Stop; -/* - * Currently disabled -Add support for more then one radiusserver. -At most 10 servers may be specified. -When multiple servers are given, they are tried in round-robin fashion until a valid response is received - -foreach ($radiusservers as $radsrv) { + /* + * Currently disabled + Add support for more then one radiusserver. + At most 10 servers may be specified. + When multiple servers are given, they are tried in round-robin fashion until a valid response is received - // Add a new server to our instance - $rauth->addServer($radsrv['ipaddr'], $radsrv['port'], $radsrv['key']); + foreach ($radiusservers as $radsrv) { -} -*/ + // Add a new server to our instance + $racct->addServer($radsrv['ipaddr'], $radsrv['port'], $radsrv['key']); -$racct->authentic = RADIUS_AUTH_RADIUS; - -// Construct data package -$racct->addServer($radiusip, $radiusport, $radiuskey); -$racct->username = $username; - -if (PEAR::isError($racct->start())) { - $retvalue['acct_val'] = 1; - $retvalue['error'] = $rauth->getMessage(); - if ($debug) - printf("Radius start: %s
\n", $retvalue['error']); -} - -// you can put any additional attributes here -//$racct->putAttribute(RADIUS_SERVICE_TYPE, RADIUS_LOGIN); - - // Do the accounting style as configured in GUI - switch($radiusvendor) { - - case 'cisco': - $rauth->putAttribute(RADIUS_CALLED_STATION_ID, $clientmac); - $rauth->putAttribute(RADIUS_CALLING_STATION_ID, $clientip); - break; - - default: - $rauth->putAttribute(RADIUS_CALLED_STATION_ID, $nas_mac); - $rauth->putAttribute(RADIUS_CALLING_STATION_ID, $clientmac); } + */ - // Default attributes - $rauth->putAttribute(RADIUS_NAS_PORT, $nas_port) - -$session_time = $stop_time - $start_time; -// We have 2 ways to set the session-time, we will see which one to use in a later version -$racct->session_time = $session_time; -$racct->putAttribute(RADIUS_ACCT_SESSION_TIME, $session_time); + // See RADIUS_ACCOUNTING_START for info + $racct->authentic = RADIUS_AUTH_RADIUS; -// Set the session_id here since we removed it into the radius.inc removing the possibility to overwrite it by $racct->session_id -$racct->putAttribute(RADIUS_ACCT_SESSION_ID, $sessionid); + // Construct data package + $racct->addServer($radiusip, $radiusport, $radiuskey); + $racct->username = $username; + if (PEAR::isError($racct->start())) { + $retvalue['acct_val'] = 1; + $retvalue['error'] = $racct->getMessage(); + if ($debug) + printf("Radius start: %s
\n", $retvalue['error']); + } -$racct->putAttribute(RADIUS_FRAMED_IP_ADDRESS, $clientip); -$racct->putAttribute(RADIUS_CALLING_STATION_ID, $clientip); -$racct->putAttribute(RADIUS_CALLED_STATION_ID, $nas_ip_address); -$racct->putAttribute(RADIUS_ACCT_INPUT_PACKETS, $input_pkts); -$racct->putAttribute(RADIUS_ACCT_INPUT_OCTETS, $input_bytes); -$racct->putAttribute(RADIUS_ACCT_INPUT_GIGAWORDS, $input_gigawords); -$racct->putAttribute(RADIUS_ACCT_OUTPUT_PACKETS, $output_pkts); -$racct->putAttribute(RADIUS_ACCT_OUTPUT_OCTETS, $output_bytes); -$racct->putAttribute(RADIUS_ACCT_OUTPUT_GIGAWORDS, $output_gigawords); + // you can put any additional attributes here + //$racct->putAttribute(RADIUS_SERVICE_TYPE, RADIUS_LOGIN); -if (!$interimupdate) -$racct->putAttribute(RADIUS_ACCT_TERMINATE_CAUSE, $radius_term_cause); + // Default attributes + $racct->putAttribute(RADIUS_NAS_PORT_TYPE, RADIUS_ETHERNET); + $racct->putAttribute(RADIUS_NAS_PORT, $nas_port); + $racct->putAttribute(RADIUS_ACCT_SESSION_ID, $sessionid); + $racct->putAttribute(RADIUS_SERVICE_TYPE, RADIUS_OUTBOUND); + + // We have 2 ways to set the session-time, we will see which one to use in a later version + // $racct->session_time = $session_time; + $racct->putAttribute(RADIUS_ACCT_SESSION_TIME, $session_time); + + // Extra data to identify the client and nas + $racct->putAttribute(RADIUS_FRAMED_IP_ADDRESS, $clientip); + $racct->putAttribute(RADIUS_CALLING_STATION_ID, $callingstationid); + $racct->putAttribute(RADIUS_CALLED_STATION_ID, $calledstationid); + + // Volume stuff: Ingress + $racct->putAttribute(RADIUS_ACCT_INPUT_PACKETS, $volume['input_pkts']); + $racct->putAttribute(RADIUS_ACCT_INPUT_OCTETS, $volume['input_bytes_radius']); + $racct->putAttribute(RADIUS_ACCT_INPUT_GIGAWORDS, $volume['input_gigawords']); + // Volume stuff: Outgress + $racct->putAttribute(RADIUS_ACCT_OUTPUT_PACKETS, $volume['output_pkts']); + $racct->putAttribute(RADIUS_ACCT_OUTPUT_OCTETS, $volume['output_bytes_radius']); + $racct->putAttribute(RADIUS_ACCT_OUTPUT_GIGAWORDS, $volume['output_gigawords']); + + if (!$interimupdate) + $racct->putAttribute(RADIUS_ACCT_TERMINATE_CAUSE, $radius_term_cause); // Send request - $result = $racct->send(); if (PEAR::isError($result)) { $retvalue['acct_val'] = 1; @@ -267,53 +265,19 @@ $racct->putAttribute(RADIUS_ACCT_TERMINATE_CAUSE, $radius_term_cause); } -function get_nas_ip() { - global $config; - - /* static WAN IP address */ - return $config['interfaces']['wan']['ipaddr']; -} - /** - * This function will calculate the traffic produced by a host - * based on its firewall rule - * - * Will be moved to in captiveportal.inc - * so that we can implement user volume limits - * - * Point of view: Client + * Deprecated function that shouldn't be used anymore if get_current_wan_address() works * */ -function volumeCalculation($ruleno) { - - $volume = array(); - - /* Ingress */ - exec("/sbin/ipfw show {$ruleno}", $ipfw); - preg_match("/(\d+)\s+(\d+)\s+(\d+)\s+skipto/", $ipfw[0], $matches); - $volume['input_pkts'] = $matches[2]; - $volume['input_bytes'] = $matches[3]; - /* These functions will be moved to the accounting part - $volume['input_bytes_radius'] = remainder($matches[3]); - $volume['input_gigawords'] = gigawords($matches[3]); - */ - - /* Flush internal buffer */ - unset($matches); - - /* Outgress */ - preg_match("/(\d+)\s+(\d+)\s+(\d+)\s+skipto/", $ipfw[1], $matches); - $volume['output_pkts'] = $matches[2]; - $volume['output_bytes'] = $matches[3]; - /* These functions will be moved to the accounting part - $volume['output_bytes_radius'] = remainder($matches[3]); - $volume['output_gigawords'] = gigawords($matches[3]); - */ +function get_nas_ip() { + global $config; - return $volume; + /* static WAN IP address */ + return $config['interfaces']['wan']['ipaddr']; } + /** * Radius Volume Helpers * @@ -321,7 +285,7 @@ function volumeCalculation($ruleno) { function gigawords($bytes) { - /* We use BCMath functions since normal integers don't work with so large numbers */ + // We use BCMath functions since normal integers don't work with so large numbers $gigawords = bcdiv( bcsub( $bytes, remainder($bytes) ) , 2147483647) ; return $gigawords; @@ -329,7 +293,7 @@ function gigawords($bytes) { function remainder($bytes) { - /* Calculate the bytes we are going to send to the radius. */ + // Calculate the bytes we are going to send to the radius $bytes = bcmod($bytes, 2147483647); return $bytes; diff --git a/captiveportal/radius_authentication.inc b/captiveportal/radius_authentication.inc index a732bbb..14f8664 100644 --- a/captiveportal/radius_authentication.inc +++ b/captiveportal/radius_authentication.inc @@ -1,50 +1,42 @@ -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. -3. The names of the authors may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -This code cannot simply be copied and put under the GNU Public License or -any other GPL-like (LGPL, GPL2) License. - - This code is made possible thx to samples made by Michael Bretterklieber - author of the PHP PECL Radius package - - Changes made include: - * Support for multiple radius servers - * Error Message and Reply Message - * Called-Station-Id,Calling-Station-Id,NAS-Port,NAS-Port-Type - * Different Authentication Methods + $Id$ + + Copyright (c) 2006, Jonathan De Graeve + 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. + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + This code cannot simply be copied and put under the GNU Public License or + any other GPL-like (LGPL, GPL2) License. + + This code is made possible thx to samples made by Michael Bretterklieber + author of the PHP PECL Radius package */ -require_once("radius.inc"); - /* RADIUS AUTHENTICATION --------------------- diff --git a/phpconf/inc/captiveportal.inc b/phpconf/inc/captiveportal.inc index 3afb89e..376a362 100644 --- a/phpconf/inc/captiveportal.inc +++ b/phpconf/inc/captiveportal.inc @@ -1,91 +1,92 @@ . - 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 - AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. - - This version of captiveportal.inc has been modified by Rob Parker - to include changes for per-user bandwidth management - via returned RADIUS attributes. This page has been modified to delete any - added rules which may have been created by other per-user code (index.php, etc). - These changes are (c) 2004 Keycom PLC. + $Id$ + part of m0n0wall (http://m0n0.ch/wall) + + Copyright (C) 2003-2006 Manuel Kasper . + 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 + AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + This version of captiveportal.inc has been modified by Rob Parker + to include changes for per-user bandwidth management + via returned RADIUS attributes. This page has been modified to delete any + 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.inc"); require_once("radius_authentication.inc"); require_once("radius_accounting.inc"); $lockfile = "{$g['varrun_path']}/captiveportal.lock"; function captiveportal_configure() { - global $config, $g; - - 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(); - - /* initialize minicron interval value */ - $croninterval = $config['captiveportal']['croninterval'] ? $config['captiveportal']['croninterval'] : 60; - - /* double check if the $croninterval is numeric and at least 10 seconds. If not we set it to 60 to avoid problems */ - if ((!is_numeric($croninterval)) || ($croninterval < 10)) { $croninterval = 60; } - - /* remove old information */ - unlink_if_exists("{$g['vardb_path']}/captiveportal.nextrule"); - unlink_if_exists("{$g['vardb_path']}/captiveportal.db"); - 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']); - else { - /* example/template page */ - $htmltext = << m0n0wall captive portal @@ -101,20 +102,20 @@ function captiveportal_configure() { EOD; - } - - $fd = @fopen("{$g['varetc_path']}/captiveportal.html", "w"); - if ($fd) { - fwrite($fd, $htmltext); - fclose($fd); - } - - /* write error page */ - if ($config['captiveportal']['page']['errtext']) - $errtext = base64_decode($config['captiveportal']['page']['errtext']); - else { - /* example page */ - $errtext = << Authentication error @@ -130,183 +131,183 @@ Username and/or password invalid. EOD; - } - - $fd = @fopen("{$g['varetc_path']}/captiveportal-error.html", "w"); - if ($fd) { - fwrite($fd, $errtext); - fclose($fd); - } - - /* write elements */ - captiveportal_write_elements(); - - /* 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']); - - if ($config['captiveportal']['maxproc']) - $maxproc = $config['captiveportal']['maxproc']; - else - $maxproc = 16; - - if (isset($config['captiveportal']['maxprocperip']) && - $config['captiveportal']['maxprocperip'] !== "") { - if ($config['captiveportal']['maxprocperip'] == 0) - $maxperiparg = ""; - else - $maxperiparg = "-maxperip " . $config['captiveportal']['maxprocperip']; - } else - $maxperiparg = "-maxperip 4"; - - /* start web server */ - $cpip = $config['interfaces'][$config['captiveportal']['interface']]['ipaddr']; - mwexec("/usr/local/sbin/mini_httpd -a -M 0 -u root -maxproc $maxproc $maxperiparg" . - " -p 8000 -i {$g['varrun_path']}/mini_httpd.cp.pid" . - " -cpelement {$g['captiveportal_element_path']} $cpip:8000"); - - /* 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"); - return 1; - } - chmod("{$g['varetc_path']}/cert-portal.pem", 0600); - fwrite($fd, $cert); - fwrite($fd, "\n"); - fwrite($fd, $key); - fclose($fd); - - $httpsname = ($config['captiveportal']['httpsname']) ? $config['captiveportal']['httpsname'] : $cpip; - - mwexec("/usr/local/sbin/mini_httpd -S -a -M 0 -E {$g['varetc_path']}/cert-portal.pem" . - " -u root -maxproc $maxproc $maxperiparg -p 8001" . - " -i {$g['varrun_path']}/mini_httpd.cps.pid" . - " -cpelement {$g['captiveportal_element_path']} $httpsname:8001"); - } - - /* start pruning process (interval defaults to 60 seconds) */ - mwexec("/usr/local/bin/minicron $croninterval {$g['varrun_path']}/minicron.pid " . - "/etc/rc.prunecaptiveportal"); - - /* generate passthru mac database */ - 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'] && (!isset($config['captiveportal']['auth_method']) || - ($config['captiveportal']['auth_method'] == "radius"))) { - $radiusip = $config['captiveportal']['radiusip']; - $radiusip2 = ($config['captiveportal']['radiusip2']) ? $config['captiveportal']['radiusip2'] : null; - - if ($config['captiveportal']['radiusport']) - $radiusport = $config['captiveportal']['radiusport']; - else - $radiusport = 1812; - - if ($config['captiveportal']['radiusacctport']) - $radiusacctport = $config['captiveportal']['radiusacctport']; - else - $radiusacctport = 1813; - - if ($config['captiveportal']['radiusport2']) - $radiusport2 = $config['captiveportal']['radiusport2']; - else - $radiusport2 = 1812; - - $radiuskey = $config['captiveportal']['radiuskey']; - $radiuskey2 = ($config['captiveportal']['radiuskey2']) ? $config['captiveportal']['radiuskey2'] : null; - - $fd = @fopen("{$g['vardb_path']}/captiveportal_radius.db", "w"); - if (!$fd) { - printf("Error: cannot open radius DB file in captiveportal_configure().\n"); - return 1; - } else if (isset($radiusip2, $radiuskey2)) { - fwrite($fd,$radiusip . "," . $radiusport . "," . $radiusacctport . "," . $radiuskey . "\n" - . $radiusip2 . "," . $radiusport2 . "," . $radiusacctport . "," . $radiuskey2); - } else { - fwrite($fd,$radiusip . "," . $radiusport . "," . $radiusacctport . "," . $radiuskey); - } - fclose($fd); - } - - 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(); - - 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; + } + + $fd = @fopen("{$g['varetc_path']}/captiveportal-error.html", "w"); + if ($fd) { + fwrite($fd, $errtext); + fclose($fd); + } + + /* write elements */ + captiveportal_write_elements(); + + /* 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']); + + if ($config['captiveportal']['maxproc']) + $maxproc = $config['captiveportal']['maxproc']; + else + $maxproc = 16; + + if (isset($config['captiveportal']['maxprocperip']) && + $config['captiveportal']['maxprocperip'] !== "") { + if ($config['captiveportal']['maxprocperip'] == 0) + $maxperiparg = ""; + else + $maxperiparg = "-maxperip " . $config['captiveportal']['maxprocperip']; + } else + $maxperiparg = "-maxperip 4"; + + /* start web server */ + $cpip = $config['interfaces'][$config['captiveportal']['interface']]['ipaddr']; + mwexec("/usr/local/sbin/mini_httpd -a -M 0 -u root -maxproc $maxproc $maxperiparg" . + " -p 8000 -i {$g['varrun_path']}/mini_httpd.cp.pid" . + " -cpelement {$g['captiveportal_element_path']} $cpip:8000"); + + /* 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"); + return 1; + } + chmod("{$g['varetc_path']}/cert-portal.pem", 0600); + fwrite($fd, $cert); + fwrite($fd, "\n"); + fwrite($fd, $key); + fclose($fd); + + $httpsname = ($config['captiveportal']['httpsname']) ? $config['captiveportal']['httpsname'] : $cpip; + + mwexec("/usr/local/sbin/mini_httpd -S -a -M 0 -E {$g['varetc_path']}/cert-portal.pem" . + " -u root -maxproc $maxproc $maxperiparg -p 8001" . + " -i {$g['varrun_path']}/mini_httpd.cps.pid" . + " -cpelement {$g['captiveportal_element_path']} $httpsname:8001"); + } + + /* start pruning process (interval defaults to 60 seconds) */ + mwexec("/usr/local/bin/minicron $croninterval {$g['varrun_path']}/minicron.pid " . + "/etc/rc.prunecaptiveportal"); + + /* generate passthru mac database */ + 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'] && (!isset($config['captiveportal']['auth_method']) || + ($config['captiveportal']['auth_method'] == "radius"))) { + $radiusip = $config['captiveportal']['radiusip']; + $radiusip2 = ($config['captiveportal']['radiusip2']) ? $config['captiveportal']['radiusip2'] : null; + + if ($config['captiveportal']['radiusport']) + $radiusport = $config['captiveportal']['radiusport']; + else + $radiusport = 1812; + + if ($config['captiveportal']['radiusacctport']) + $radiusacctport = $config['captiveportal']['radiusacctport']; + else + $radiusacctport = 1813; + + if ($config['captiveportal']['radiusport2']) + $radiusport2 = $config['captiveportal']['radiusport2']; + else + $radiusport2 = 1812; + + $radiuskey = $config['captiveportal']['radiuskey']; + $radiuskey2 = ($config['captiveportal']['radiuskey2']) ? $config['captiveportal']['radiuskey2'] : null; + + $fd = @fopen("{$g['vardb_path']}/captiveportal_radius.db", "w"); + if (!$fd) { + printf("Error: cannot open radius DB file in captiveportal_configure().\n"); + return 1; + } else if (isset($radiusip2, $radiuskey2)) { + fwrite($fd,$radiusip . "," . $radiusport . "," . $radiusacctport . "," . $radiuskey . "\n" + . $radiusip2 . "," . $radiusport2 . "," . $radiusacctport . "," . $radiuskey2); + } else { + fwrite($fd,$radiusip . "," . $radiusport . "," . $radiusacctport . "," . $radiuskey); + } + fclose($fd); + } + + 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(); + + 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 .= <<= $timeout) { - $timedout = true; - $term_cause = 5; // Session-Timeout - } - } - - /* Session-Terminate-Time */ - if (!$timedout && !empty($cpdb[$i][9])) { - if (time() >= $cpdb[$i][9]) { - $timedout = true; - $term_cause = 5; // Session-Timeout - } - } - - /* check if the radius idle_timeout attribute has been set and if its set change the idletimeout to this value */ - $idletimeout = (is_numeric($cpdb[$i][8])) ? $cpdb[$i][8] : $idletimeout; - /* 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; - $term_cause = 4; // Idle-Timeout - $stop_time = $lastact; // Entry added to comply with WISPr - } - } - - /* if radius session_timeout is enabled and the session_timeout is not null, then check if the user should be logged out */ - if (!$timedout && isset($config['captiveportal']['radiussession_timeout']) && !empty($cpdb[$i][7])) { - if (time() >= ($cpdb[$i][0] + $cpdb[$i][7])) { - $timedout = true; - $term_cause = 5; // Session-Timeout - } - } - - if ($timedout) { - captiveportal_disconnect($cpdb[$i], $radiusservers,$term_cause,$stop_time); - 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 - $cpdb[$i][3], // clientmac - 10); // NAS Request - exec("/sbin/ipfw zero {$cpdb[$i][1]}"); - RADIUS_ACCOUNTING_START($cpdb[$i][1], // ruleno - $cpdb[$i][4], // username - $cpdb[$i][5], // sessionid - $radiusservers[0]['ipaddr'], - $radiusservers[0]['acctport'], - $radiusservers[0]['key'], - $cpdb[$i][2], // clientip - $cpdb[$i][3]); // clientmac - } 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 - $cpdb[$i][3], // clientmac - 10, // NAS Request - true); // Interim Updates - } - } - - /* check this user against RADIUS again */ - $auth_list = RADIUS_AUTHENTICATION($cpdb[$i][4], // username - base64_decode($cpdb[$i][6]), // password - $radiusservers, - $cpdb[$i][2], // clientip - $cpdb[$i][3], // clientmac - $cpdb[$i][1]); // ruleno - - if ($auth_list['auth_val'] == 3) { - captiveportal_disconnect($cpdb[$i], $radiusservers, 17); - captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "RADIUS_DISCONNECT", $auth_list['reply_message']); - unset($cpdb[$i]); - } - } - } - - /* write database */ - captiveportal_write_db($cpdb); - - captiveportal_unlock(); + + 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 && !isset($config['captiveportal']['reauthenticate']) && !isset($config['captiveportal']['radiussession_timeout'])) + return; + + captiveportal_lock(); + + /* read database */ + $cpdb = captiveportal_read_db(); + + $radiusservers = captiveportal_get_radius_servers(); + + for ($i = 0; $i < count($cpdb); $i++) { + + $timedout = false; + $term_cause = 1; + + /* hard timeout? */ + if ($timeout) { + if ((time() - $cpdb[$i][0]) >= $timeout) { + $timedout = true; + $term_cause = 5; // Session-Timeout + } + } + + /* Session-Terminate-Time */ + if (!$timedout && !empty($cpdb[$i][9])) { + if (time() >= $cpdb[$i][9]) { + $timedout = true; + $term_cause = 5; // Session-Timeout + } + } + + /* check if the radius idle_timeout attribute has been set and if its set change the idletimeout to this value */ + $idletimeout = (is_numeric($cpdb[$i][8])) ? $cpdb[$i][8] : $idletimeout; + /* 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; + $term_cause = 4; // Idle-Timeout + $stop_time = $lastact; // Entry added to comply with WISPr + } + } + + /* if radius session_timeout is enabled and the session_timeout is not null, then check if the user should be logged out */ + if (!$timedout && isset($config['captiveportal']['radiussession_timeout']) && !empty($cpdb[$i][7])) { + if (time() >= ($cpdb[$i][0] + $cpdb[$i][7])) { + $timedout = true; + $term_cause = 5; // Session-Timeout + } + } + + if ($timedout) { + captiveportal_disconnect($cpdb[$i], $radiusservers,$term_cause,$stop_time); + 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 + $cpdb[$i][3], // clientmac + 10); // NAS Request + exec("/sbin/ipfw zero {$cpdb[$i][1]}"); + RADIUS_ACCOUNTING_START($cpdb[$i][1], // ruleno + $cpdb[$i][4], // username + $cpdb[$i][5], // sessionid + $radiusservers[0]['ipaddr'], + $radiusservers[0]['acctport'], + $radiusservers[0]['key'], + $cpdb[$i][2], // clientip + $cpdb[$i][3]); // clientmac + } 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 + $cpdb[$i][3], // clientmac + 10, // NAS Request + true); // Interim Updates + } + } + + /* check this user against RADIUS again */ + $auth_list = RADIUS_AUTHENTICATION($cpdb[$i][4], // username + base64_decode($cpdb[$i][6]), // password + $radiusservers, + $cpdb[$i][2], // clientip + $cpdb[$i][3], // clientmac + $cpdb[$i][1]); // ruleno + + if ($auth_list['auth_val'] == 3) { + captiveportal_disconnect($cpdb[$i], $radiusservers, 17); + captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "RADIUS_DISCONNECT", $auth_list['reply_message']); + unset($cpdb[$i]); + } + } + } + + /* write database */ + captiveportal_write_db($cpdb); + + captiveportal_unlock(); } /* remove a single client according to the DB entry */ function captiveportal_disconnect($dbent, $radiusservers,$term_cause = 1,$stop_time = null) { - - global $g, $config; - - $stop_time = (empty($stop_time)) ? time() : $stop_time; - - /* 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 - $dbent[3], // clientmac - $term_cause, // Acct-Terminate-Cause - false, - $stop_time); - } - - 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)); - } + + global $g, $config; + + $stop_time = (empty($stop_time)) ? time() : $stop_time; + + /* 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 + $dbent[3], // clientmac + $term_cause, // Acct-Terminate-Cause + false, + $stop_time); + } + + 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,$term_cause = 1) { - - global $g, $config; - - captiveportal_lock(); - - /* read database */ - $cpdb = captiveportal_read_db(); - $radiusservers = captiveportal_get_radius_servers(); - - /* find entry */ - for ($i = 0; $i < count($cpdb); $i++) { - if ($cpdb[$i][1] == $id) { - captiveportal_disconnect($cpdb[$i], $radiusservers, $term_cause); - captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "DISCONNECT"); - unset($cpdb[$i]); - break; - } - } - - /* write database */ - captiveportal_write_db($cpdb); - - captiveportal_unlock(); + + global $g, $config; + + captiveportal_lock(); + + /* read database */ + $cpdb = captiveportal_read_db(); + $radiusservers = captiveportal_get_radius_servers(); + + /* find entry */ + for ($i = 0; $i < count($cpdb); $i++) { + if ($cpdb[$i][1] == $id) { + captiveportal_disconnect($cpdb[$i], $radiusservers, $term_cause); + captiveportal_logportalauth($cpdb[$i][4], $cpdb[$i][3], $cpdb[$i][2], "DISCONNECT"); + unset($cpdb[$i]); + break; + } + } + + /* write database */ + captiveportal_write_db($cpdb); + + captiveportal_unlock(); } /* send RADIUS acct stop for all current clients */ function captiveportal_radius_stop_all() { - global $g, $config; - - if (!isset($config['captiveportal']['radacct_enable'])) - return; - - 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 - $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 - $cpdb[$i][3], // clientmac - 7); // Admin Reboot - } - } - captiveportal_unlock(); + global $g, $config; + + if (!isset($config['captiveportal']['radacct_enable'])) + return; + + 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 + $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 + $cpdb[$i][3], // clientmac + 7); // Admin Reboot + } + } + captiveportal_unlock(); } function captiveportal_passthrumac_configure() { - global $config, $g; - - captiveportal_lock(); - - /* clear out passthru macs, if necessary */ - 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"); - 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); - } - - captiveportal_unlock(); - - return 0; + global $config, $g; + + captiveportal_lock(); + + /* clear out passthru macs, if necessary */ + 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"); + 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); + } + + captiveportal_unlock(); + + return 0; } function captiveportal_allowedip_configure() { - global $config, $g; - - captiveportal_lock(); - - /* clear out existing allowed ips, if necessary */ - if (file_exists("{$g['vardb_path']}/captiveportal_ip.db")) { - $fd = @fopen("{$g['vardb_path']}/captiveportal_ip.db", "r"); - if ($fd) { - while (!feof($fd)) { - $line = trim(fgets($fd)); - if ($line) { - list($ip,$rule) = explode(",",$line); - mwexec("/sbin/ipfw delete $rule"); - } - } - } - 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; - } - - foreach ($config['captiveportal']['allowedip'] as $ipent) { - - /* record allowed ip so it can be recognized and removed later */ - 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); - - /* write next rule number */ - $fd = @fopen("{$g['vardb_path']}/captiveportal.nextrule", "w"); - if ($fd) { - fwrite($fd, $ruleno); - fclose($fd); - } - } - - captiveportal_unlock(); - return 0; + global $config, $g; + + captiveportal_lock(); + + /* clear out existing allowed ips, if necessary */ + if (file_exists("{$g['vardb_path']}/captiveportal_ip.db")) { + $fd = @fopen("{$g['vardb_path']}/captiveportal_ip.db", "r"); + if ($fd) { + while (!feof($fd)) { + $line = trim(fgets($fd)); + if ($line) { + list($ip,$rule) = explode(",",$line); + mwexec("/sbin/ipfw delete $rule"); + } + } + } + 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; + } + + foreach ($config['captiveportal']['allowedip'] as $ipent) { + + /* record allowed ip so it can be recognized and removed later */ + 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); + + /* write next rule number */ + $fd = @fopen("{$g['vardb_path']}/captiveportal.nextrule", "w"); + if ($fd) { + fwrite($fd, $ruleno); + fclose($fd); + } + } + + captiveportal_unlock(); + return 0; } /* 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; + + 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 RADIUS servers into array */ @@ -768,57 +769,57 @@ function captiveportal_unlock() { /* log successful captive portal authentication to syslog */ /* part of this code from php.net */ function captiveportal_logportalauth($user,$mac,$ip,$status, $message = null) { - define_syslog_variables(); - $message = trim($message); - openlog("logportalauth", LOG_PID, LOG_LOCAL4); - // Log it - if (!$message) - syslog(LOG_INFO, "$status: $user, $mac, $ip"); - else - syslog(LOG_INFO, "$status: $user, $mac, $ip, $message"); - closelog(); + define_syslog_variables(); + $message = trim($message); + openlog("logportalauth", LOG_PID, LOG_LOCAL4); + // Log it + if (!$message) + syslog(LOG_INFO, "$status: $user, $mac, $ip"); + else + syslog(LOG_INFO, "$status: $user, $mac, $ip, $message"); + closelog(); } function radius($username,$password,$clientip,$clientmac,$type) { - global $g, $config; - - $next_ruleno = get_next_ipfw_ruleno(); - $radiusservers = captiveportal_get_radius_servers(); - $radacct_enable = isset($config['captiveportal']['radacct_enable']); - - $auth_list = RADIUS_AUTHENTICATION($username, - $password, - $radiusservers, - $clientip, - $clientmac, - $next_ruleno); - - if ($auth_list['auth_val'] == 2) { - captiveportal_logportalauth($username,$clientmac,$clientip,$type); - $sessionid = portal_allow($clientip, - $clientmac, - $username, - $password, - $auth_list['session_timeout'], - $auth_list['idle_timeout'], - $auth_list['url_redirection'], - $auth_list['session_terminate_time']); - - if ($radacct_enable) { - $auth_list['acct_val'] = RADIUS_ACCOUNTING_START($next_ruleno, - $username, - $sessionid, - $radiusservers[0]['ipaddr'], - $radiusservers[0]['acctport'], - $radiusservers[0]['key'], - $clientip, - $clientmac); - if ($auth_list['acct_val'] == 1) - captiveportal_logportalauth($username,$clientmac,$clientip,$type,"RADIUS ACCOUNTING FAILED"); - } - } - - return $auth_list; + global $g, $config; + + $next_ruleno = get_next_ipfw_ruleno(); + $radiusservers = captiveportal_get_radius_servers(); + $radacct_enable = isset($config['captiveportal']['radacct_enable']); + + $auth_list = RADIUS_AUTHENTICATION($username, + $password, + $radiusservers, + $clientip, + $clientmac, + $next_ruleno); + + if ($auth_list['auth_val'] == 2) { + captiveportal_logportalauth($username,$clientmac,$clientip,$type); + $sessionid = portal_allow($clientip, + $clientmac, + $username, + $password, + $auth_list['session_timeout'], + $auth_list['idle_timeout'], + $auth_list['url_redirection'], + $auth_list['session_terminate_time']); + + if ($radacct_enable) { + $auth_list['acct_val'] = RADIUS_ACCOUNTING_START($next_ruleno, + $username, + $sessionid, + $radiusservers[0]['ipaddr'], + $radiusservers[0]['acctport'], + $radiusservers[0]['key'], + $clientip, + $clientmac); + if ($auth_list['acct_val'] == 1) + captiveportal_logportalauth($username,$clientmac,$clientip,$type,"RADIUS ACCOUNTING FAILED"); + } + } + + return $auth_list; } @@ -856,35 +857,76 @@ function captiveportal_write_db($cpdb) { } function captiveportal_write_elements() { - global $g, $config; - - /* delete any existing elements */ - if (is_dir($g['captiveportal_element_path'])) { - $dh = opendir($g['captiveportal_element_path']); - while (($file = readdir($dh)) !== false) { - if ($file != "." && $file != "..") - unlink($g['captiveportal_element_path'] . "/" . $file); - } - closedir($dh); - } else { - mkdir($g['captiveportal_element_path']); - } - - if (is_array($config['captiveportal']['element'])) { - - foreach ($config['captiveportal']['element'] as $data) { - $fd = @fopen($g['captiveportal_element_path'] . '/' . $data['name'], "wb"); - if (!$fd) { - printf("Error: cannot open '{$data['name']}' in captiveportal_write_elements().\n"); - return 1; - } - $decoded = base64_decode($data['content']); - fwrite($fd,$decoded); - fclose($fd); - } - } - - return 0; + global $g, $config; + + /* delete any existing elements */ + if (is_dir($g['captiveportal_element_path'])) { + $dh = opendir($g['captiveportal_element_path']); + while (($file = readdir($dh)) !== false) { + if ($file != "." && $file != "..") + unlink($g['captiveportal_element_path'] . "/" . $file); + } + closedir($dh); + } else { + mkdir($g['captiveportal_element_path']); + } + + if (is_array($config['captiveportal']['element'])) { + + foreach ($config['captiveportal']['element'] as $data) { + $fd = @fopen($g['captiveportal_element_path'] . '/' . $data['name'], "wb"); + if (!$fd) { + printf("Error: cannot open '{$data['name']}' in captiveportal_write_elements().\n"); + return 1; + } + $decoded = base64_decode($data['content']); + fwrite($fd,$decoded); + fclose($fd); + } + } + + return 0; } +/** + * This function will calculate the traffic produced by a client + * based on its firewall rule + * + * Point of view: Client + * + * Input on the FW will be viewed as Output for the Client + * Output on the FW will be viewed as Input for the Client + * + */ + +function getVolume($ruleno) { + + $volume = array(); + + // Ingress + exec("/sbin/ipfw show {$ruleno}", $ipfw); + preg_match("/(\d+)\s+(\d+)\s+(\d+)\s+skipto/", $ipfw[0], $matches); + $volume['input_pkts'] = $matches[2]; + $volume['input_bytes'] = $matches[3]; + /* These functions are moved to the accounting part + $volume['input_bytes_radius'] = remainder($matches[3]); + $volume['input_gigawords'] = gigawords($matches[3]); + */ + + // Flush internal buffer + unset($matches); + + // Outgress + preg_match("/(\d+)\s+(\d+)\s+(\d+)\s+skipto/", $ipfw[1], $matches); + $volume['output_pkts'] = $matches[2]; + $volume['output_bytes'] = $matches[3]; + /* These functions are moved to the accounting part + $volume['output_bytes_radius'] = remainder($matches[3]); + $volume['output_gigawords'] = gigawords($matches[3]); + */ + + return $volume; +} + + ?> -- 2.25.1