--- /dev/null
+<?php
+/*
+
+$Id$
+
+ radius_accounting.inc
+ part of m0n0wall (http://m0n0.ch/wall)
+
+ Copyright (C) 2004 Dinesh Nair <dinesh@alphaque.com>
+ 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 radius_accounting.inc has been modified by
+ // Rob Parker <rob.parker@keycom.co.uk>. Changes made include:
+ // * now sends Framed-IP-Address (client IP)
+ // * now sends Called-Station-ID (NAS IP)
+ // * now sends Calling-Station-ID (client IP)
+
+ // This version of radius_accounting.inc has been modified by
+ // Jonathan De Graeve <jonathan@imelda.be>. Changes made include:
+ // - RFC2869 (Radius Extensions)
+ // * now sends Acct-Input-Gigawords
+ // * now sends Acct-Output-Gigawords
+ // * full implementation of nas-ip/nas_mac and called/calling-station ids
+
+*/
+
+function RADIUS_ACCOUNTING_START($ruleno,$username,$sessionid,$radiusip,$radiusport,$radiuskey,$clientip,$clientmac) {
+ # $debug = 1 ;
+ global $config;
+
+ exec("/bin/hostname", $nasHostname) ;
+ if(!$nasHostname[0])
+ $nasHostname[0] = "m0n0wall" ;
+
+ $fd = @fsockopen("udp://$radiusip",$radiusport,$errno,$errstr,3) ;
+ if(!$fd)
+ return 1 ; /* error return */
+
+ /* set 5 second timeout on socket i/o */
+ stream_set_timeout($fd, 5) ;
+
+ $nas_ip = get_nas_ip();
+ $nas_ip_exp = explode(".",$nas_ip);
+ $nas_mac = get_interface_mac($config['interfaces']['wan']['if']); // This function is defined in radius_authentication.inc
+ $nas_port = $ruleno - 10000;
+ $ip_exp=explode(".",$clientip);
+ $radiusvendor = $config['captiveportal']['radiusvendor'] ? $config['captiveportal']['radiusvendor'] : null;
+
+ switch($radiusvendor) {
+
+ case 'cisco':
+ $calledstationid = $clientmac;
+ $callingstationid = $clientip;
+ break;
+
+ default:
+ $calledstationid = $nas_mac;
+ $callingstationid = $clientmac;
+ break;
+ }
+
+ if ($debug)
+ echo "<br>radius-port: $radiusport<br>radius-host: $radiusip<br>username: $username<hr>\n";
+
+ /* Initialise rand function, make it more random */
+ srand((double)microtime() * 1000000);
+
+ $thisidentifier=rand()%256;
+
+ $length=4+ // header
+ 16+ // auth code
+ 6+ // service type
+ 2+strlen($username)+ // username
+ 2+strlen($nasHostname[0])+ // nasIdentifier
+ 6+ // nasPort
+ 6+ // nasPortType
+ 6+ // Acct Status Type
+ 6+ // Acct RADIUS Authenticated
+ 2+strlen($sessionid)+ // Acct SessionID
+ 2+strlen($calledstationid)+ //Called-Station-ID
+ 2+strlen($callingstationid)+ //Calling-Station-ID
+ 6+ // nas-IP-Address
+ 6; // Framed-IP-Address
+
+ // v v v v v v v v v 1 v
+ // Line # 1 2 3 4 5 6 7 8 9 0 E
+ $data=pack("CCCCNNNNCCCCCCCCa*CCa*CCCCCCCCCCCCCCCCCCCCCCCCCCa*CCa*CCa*CCCCCCCCCCCC",
+ 4,$thisidentifier,$length/256,$length%256, // header
+ 0,0,0,0, // authcode
+ 6,6,0,0,0,1, // service type
+ 1,2+strlen($username),$username, // username
+ 32,2+strlen($nasHostname[0]),$nasHostname[0], // nasIdentifier
+ 5,6,0,0,0,$nas_port, // nasPort
+ 61,6,0,0,0,15, // nasPortType = Ethernet
+ 40,6,0,0,0,1, // Acct Status Type = Start
+ 45,6,0,0,0,1, // Acct RADIUS Authenticated
+ 44,2+strlen($sessionid),$sessionid, // Acct Session ID
+ 30,2+strlen($calledstationid),$calledstationid, //Called-Station-ID
+ 31,2+strlen($callingstationid),$callingstationid, //Calling-Station-ID
+ 4,6,$nas_ip_exp[0],$nas_ip_exp[1],$nas_ip_exp[2],$nas_ip_exp[3], //nas-IP-Address
+ 8,6,$ip_exp[0],$ip_exp[1],$ip_exp[2],$ip_exp[3] //Framed-IP-Address
+ );
+
+ /* Generate Accounting Request Authenticator */
+ $RA = md5($data.$radiuskey) ;
+
+ // v v v v v v v v v 1 v
+ // Line # 1 2 3 4 5 6 7 8 9 0 E
+ $data=pack("CCCCH*CCCCCCCCa*CCa*CCCCCCCCCCCCCCCCCCCCCCCCCCa*CCa*CCa*CCCCCCCCCCCC",
+ 4,$thisidentifier,$length/256,$length%256, // header
+ $RA, // authcode
+ 6,6,0,0,0,1, // service type
+ 1,2+strlen($username),$username, // username
+ 32,2+strlen($nasHostname[0]),$nasHostname[0], // nasIdentifier
+ 5,6,0,0,0,$nas_port, // nasPort
+ 61,6,0,0,0,15, // nasPortType = Ethernet
+ 40,6,0,0,0,1, // Acct Status Type = Start
+ 45,6,0,0,0,1, // Acct RADIUS Authenticated
+ 44,2+strlen($sessionid),$sessionid, // Acct Session ID
+ 30,2+strlen($calledstationid),$calledstationid, //Called-Station-ID
+ 31,2+strlen($callingstationid),$callingstationid, //Calling-Station-ID
+ 4,6,$nas_ip_exp[0],$nas_ip_exp[1],$nas_ip_exp[2],$nas_ip_exp[3], //nas-IP-Address
+ 8,6,$ip_exp[0],$ip_exp[1],$ip_exp[2],$ip_exp[3] //Framed-IP-Address
+ );
+
+ if($debug) {
+ echo "username is $username with len " . strlen($username) ."\n" ;
+ echo "nasHostname is {$nasHostname[0]} with len " . strlen($nasHostname[0]) ."\n" ;
+ }
+
+ $ret = fwrite($fd,$data) ;
+ if( !$ret || ($ret != $length) )
+ return 1; /* error return */
+
+ if ($debug)
+ echo "<br>writing $length bytes<hr>\n";
+
+ $readdata = fgets($fd,2) ; /* read 1 byte */
+ $status = socket_get_status($fd) ;
+ fclose($fd) ;
+
+ if($status['timed_out'])
+ $retvalue = 1 ;
+ else
+ $retvalue = ord($readdata) ;
+
+ return $retvalue ;
+ // 5 -> Accounting-Response
+ // See RFC2866 for this.
+}
+
+function RADIUS_ACCOUNTING_STOP($ruleno,$username,$sessionid,$start_time,$radiusip,$radiusport,$radiuskey,$clientip,$clientmac,$interimupdate=false, $radius_term_cause = 1) {
+ # $debug = 1 ;
+ global $config;
+
+ exec("/bin/hostname", $nasHostname) ;
+ if(!$nasHostname[0])
+ $nasHostname[0] = "quewall" ;
+
+ $input_pkts = $input_bytes = $input_gigawords = $output_pkts = $output_bytes = $output_gigawords = 0 ;
+
+ exec("/sbin/ipfw show {$ruleno}", $ipfw) ;
+ preg_match("/(\d+)\s+(\d+)\s+(\d+)\s+skipto/", $ipfw[0], $matches) ;
+ $input_pkts = $matches[2] ;
+ $input_bytes = remainder($matches[3]) ;
+ $input_gigawords = gigawords($matches[3]) ;
+
+ unset($matches) ;
+ preg_match("/(\d+)\s+(\d+)\s+(\d+)\s+skipto/", $ipfw[1], $matches) ;
+ $output_pkts = $matches[2] ;
+ $output_bytes = remainder($matches[3]) ;
+ $output_gigawords = gigawords($matches[3]) ;
+
+ $fd = @fsockopen("udp://$radiusip",$radiusport,$errno,$errstr,3) ;
+ if(!$fd)
+ return 1 ; /* error return */
+
+ /* set 5 second timeout on socket i/o */
+ stream_set_timeout($fd, 5) ;
+
+ $nas_ip = get_nas_ip();
+ $nas_ip_exp = explode(".",$nas_ip);
+ $nas_port = $ruleno - 10000;
+ $nas_mac = get_interface_mac($config['interfaces']['wan']['if']);
+ $ip_exp=explode(".",$clientip);
+ $radiusvendor = $config['captiveportal']['radiusvendor'] ? $config['captiveportal']['radiusvendor'] : null;
+
+ switch($radiusvendor) {
+
+ case 'cisco':
+ $calledstationid = $clientmac;
+ $callingstationid = $clientip;
+ break;
+
+ default:
+ $calledstationid = $nas_mac;
+ $callingstationid = $clientmac;
+ break;
+ }
+
+ if ($debug)
+ echo "<br>radius-port: $radiusport<br>radius-host: $radiusip<br>username: $username<hr>\n";
+
+ /* Initialise rand function, make it more random */
+ srand((double)microtime() * 1000000);
+
+ $thisidentifier=rand()%256;
+
+ $length=4+ // header
+ 16+ // auth code
+ 6+ // service type
+ 2+strlen($username)+ // username
+ 2+strlen($nasHostname[0])+ // nasIdentifier
+ 6+ // nasPort
+ 6+ // nasPortType
+ 6+ // Acct Status Type
+ 6+ // Acct RADIUS Authenticated
+ 2+strlen($sessionid)+ // Acct SessionID
+ 6+ // Acct terminate
+ 6+ // Session time
+ 6+ // input bytes
+ 6+ // input packets
+ 6+ // input gigawords
+ 6+ // output bytes
+ 6+ // output packets
+ 6+ // output gigawords
+ 2+strlen($calledstationid)+ //Called-Station-ID
+ 2+strlen($callingstationid)+ //Calling-Station-ID
+ 6+ //nas-IP-Address
+ 6; //Framed-IP-Address
+
+ if ($interimupdate)
+ $acctstatustype = 3;
+ else
+ $acctstatustype = 2;
+
+ // v v v v v v v v v 1 1 1 1 1 1 1 1 1 v
+ // Line # 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 E
+ $data=pack("CCCCNNNNCCCCCCCCa*CCa*CCCCCCCCCCCCCCCCCCCCCCCCCCa*CCNCCNCCNCCNCCNCCNCCNCCNCCa*CCa*CCCCCCCCCCCC",
+ 4,$thisidentifier,$length/256,$length%256, // header
+ 0,0,0,0, // authcode
+ 6,6,0,0,0,1, // service type
+ 1,2+strlen($username),$username, // username
+ 32,2+strlen($nasHostname[0]),$nasHostname[0], // nasIdentifier
+ 5,6,0,0,0,$nas_port, // nasPort
+ 61,6,0,0,0,15, // nasPortType = Ethernet
+ 40,6,0,0,0,$acctstatustype, // Acct Status Type
+ 45,6,0,0,0,1, // Acct RADIUS Authenticated
+ 44,2+strlen($sessionid),$sessionid, // Acct Session ID
+ 49,6,$radius_term_cause, // Acct Terminate = User Request
+ 46,6,time() - $start_time, // Session Time
+ 42,6,$input_bytes, // Input Octets
+ 47,6,$input_pkts, // Input Packets
+ 52,6,$input_gigawords, // Input Gigawords
+ 43,6,$output_bytes, // Output Octets
+ 48,6,$output_pkts, // Output Packets
+ 53,6,$output_gigawords, // Output Gigawords
+ 30,2+strlen($calledstationid),$calledstationid, //Called-Station-ID
+ 31,2+strlen($callingstationid),$callingstationid, //Calling-Station-ID
+ 4,6,$nas_ip_exp[0],$nas_ip_exp[1],$nas_ip_exp[2],$nas_ip_exp[3], //nas-IP-Address
+ 8,6,$ip_exp[0],$ip_exp[1],$ip_exp[2],$ip_exp[3] //Framed-IP-Address
+ );
+
+ /* Generate Accounting Request Authenticator */
+ $RA = md5($data.$radiuskey) ;
+
+ // v v v v v v v v v 1 1 1 1 1 1 1 1 1 v
+ // Line # 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 E
+ $data=pack("CCCCH*CCCCCCCCa*CCa*CCCCCCCCCCCCCCCCCCCCCCCCCCa*CCNCCNCCNCCNCCNCCNCCNCCNCCa*CCa*CCCCCCCCCCCC",
+ 4,$thisidentifier,$length/256,$length%256, // header
+ $RA, // authcode
+ 6,6,0,0,0,1, // service type
+ 1,2+strlen($username),$username, // username
+ 32,2+strlen($nasHostname[0]),$nasHostname[0], // nasIdentifier
+ 5,6,0,0,0,$nas_port, // nasPort
+ 61,6,0,0,0,15, // nasPortType = Ethernet
+ 40,6,0,0,0,$acctstatustype, // Acct Status Type
+ 45,6,0,0,0,1, // Acct RADIUS Authenticated
+ 44,2+strlen($sessionid),$sessionid, // Acct Session ID
+ 49,6,$radius_term_cause, // Acct Terminate = User Request
+ 46,6,time() - $start_time, // Session Time
+ 42,6,$input_bytes, // Input Octets
+ 47,6,$input_pkts, // Input Packets
+ 52,6,$input_gigawords, // Input Gigawords
+ 43,6,$output_bytes, // Output Octets
+ 48,6,$output_pkts, // Output Packets
+ 53,6,$output_gigawords, // Output Gigawords
+ 30,2+strlen($calledstationid),$calledstationid, //Called-Station-ID
+ 31,2+strlen($callingstationid),$callingstationid, //Calling-Station-ID
+ 4,6,$nas_ip_exp[0],$nas_ip_exp[1],$nas_ip_exp[2],$nas_ip_exp[3], //nas-IP-Address
+ 8,6,$ip_exp[0],$ip_exp[1],$ip_exp[2],$ip_exp[3] //Framed-IP-Address
+ );
+
+ if($debug) {
+ echo "username is $username with len " . strlen($username) ."\n" ;
+ echo "nasHostname is {$nasHostname[0]} with len " . strlen($nasHostname[0]) ."\n" ;
+ }
+
+ $ret = fwrite($fd,$data) ;
+ if( !$ret || ($ret != $length) )
+ return 1; /* error return */
+
+ if ($debug)
+ echo "<br>writing $length bytes<hr>\n";
+
+ $readdata = fgets($fd,2) ; /* read 1 byte */
+ $status = socket_get_status($fd) ;
+ fclose($fd) ;
+
+ if($status['timed_out'])
+ $retvalue = 1 ;
+ else
+ $retvalue = ord($readdata) ;
+
+ return $retvalue ;
+ // 5 -> Accounting-Response
+ // See RFC2866 for this.
+}
+
+function gigawords($bytes) {
+
+ /* We use BCMath functions since normal integers don't work with so large numbers */
+ $gigawords = bcdiv( bcsub( $bytes, remainder($bytes) ) , 2147483647) ;
+
+ return $gigawords;
+}
+
+function remainder($bytes) {
+
+ /* Calculate the bytes we are going to send to the radius. */
+ $bytes = bcmod($bytes, 2147483647);
+
+ return $bytes;
+}
+
+
+?>
--- /dev/null
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+/*
+
+$Id$
+
+Copyright (c) 2006, Jonathan De Graeve <jonathan.de.graeve@imelda.be>
+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 <michael@bretterklieber.com>
+ 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
+ * TODO implementation of different Acct-Terminate-Cause (Disconnect reason) (should be changed in index.php)
+
+*/
+
+/*
+RADIUS ACCOUNTING START
+-----------------------
+*/
+
+function RADIUS_ACCOUNTING_START($username,$sessionid,$radiusip,$radiusport,$radiuskey,$clientip) {
+ global $debug;
+
+ exec("/bin/hostname", $nasHostname) ;
+ if(!$nasHostname[0])
+ $nasHostname[0] = "m0n0wall" ;
+
+ $nas_ip_address = get_nas_ip();
+
+ if(!isset($clientip)) {
+ //if there's no client ip, we'll need to use the NAS ip
+ $clientip=$nas_ip_address;
+ }
+
+
+$racct = new Auth_RADIUS_Acct_Start;
+$racct->addServer($radiusip, $radiusport, $radiuskey);
+/* Different Authentication options
+ RADIUS_AUTH_RADIUS => authenticated via Radius
+ RADIUS_AUTH_LOCAL => authenicated local
+ RADIUS_AUTH_REMOTE => authenticated remote
+*/
+
+$racct->authentic = RADIUS_AUTH_RADIUS;
+$racct->username = $username;
+$status = $racct->start();
+if(PEAR::isError($status)) {
+ if ($debug)
+ printf("Radius start: %s<br>\n", $status->getMessage());
+ exit;
+}
+
+/*
+NAS_PORT_TYPE, int => RADIUS_ETHERNET (15), RADIUS_WIRELESS_OTHER (18), RADIUS_WIRELESS_IEEE_802_11 (19)
+NAS_IDENTIFIER, int => should be int but nasHostname[0] returns string
+*/
+
+$racct->putAttribute(RADIUS_SERVICE_TYPE, RADIUS_LOGIN);
+$racct->putAttribute(RADIUS_NAS_PORT, 0);
+$racct->putAttribute(RADIUS_NAS_PORT_TYPE, RADIUS_ETHERNET);
+//$racct->putAttribute(RADIUS_NAS_IDENTIFIER, $nasHostname[0]);
+$racct->putAttribute(RADIUS_NAS_IP_ADDRESS, $nas_ip_address);
+$racct->putAttribute(RADIUS_ACCT_SESSION_ID, $sessionid);
+$racct->putAttribute(RADIUS_FRAMED_IP_ADDRESS, $clientip);
+$result = $racct->send();
+if (PEAR::isError($result)) {
+ $retvalue = 1;
+if ($debug)
+ printf("Radius send failed: %s<br>\n", $result->getMessage());
+} else if ($result === true) {
+ $retvalue = 5 ;
+ if ($debug)
+ printf("Radius Accounting succeeded<br>\n") ;
+} else {
+ $retvalue = 1 ;
+ if ($debug)
+ printf("Radius Accounting rejected<br>\n") ;
+}
+
+$racct->close();
+
+return $retvalue ;
+
+}
+
+/*
+RADIUS ACCOUNTING STOP/UPDATE
+-----------------------------
+*/
+
+p
+function RADIUS_ACCOUNTING_STOP($ruleno,$username,$sessionid,$start_time,$radiusip,$radiusport,$radiuskey,$clientip,$interimupdate=false,$radius_term_cause = "RADIUS_TERM_IDLE_TIMEOUT") {
+ global $debug;
+
+ exec("/bin/hostname", $nasHostname) ;
+ if(!$nasHostname[0])
+ $nasHostname[0] = "quewall" ;
+
+ $input_pkts = $input_bytes = $input_gigawords = $output_pkts = $output_bytes = $output_gigawords = 0 ;
+
+ exec("/sbin/ipfw show {$ruleno}", $ipfw) ;
+ preg_match("/(\d+)\s+(\d+)\s+(\d+)\s+skipto/", $ipfw[0], $matches) ;
+ $input_pkts = $matches[2] ;
+ $input_bytes = remainder($matches[3]);
+ $input_gigawords = gigawords($matches[3]);
+
+ unset($matches) ;
+ preg_match("/(\d+)\s+(\d+)\s+(\d+)\s+skipto/", $ipfw[1], $matches) ;
+ $output_pkts = $matches[2] ;
+ $output_bytes = remainder($matches[3]);
+ $output_gigawords = gigawords($matches[3]);
+
+ $nas_ip_address = get_nas_ip();
+
+ if(!isset($clientip)) {
+ //if there's no client ip, we'll need to use the NAS ip
+ $clientip=$nas_ip_address;
+ }
+
+ if ($debug)
+ echo "<br>radius-port: $radiusport<br>radius-host: $radiusip<br>username: $username<hr>\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;
+
+// Construct data package
+$racct->addServer($radiusip, $radiusport, $radiuskey);
+$racct->username = $username;
+$racct->session_time = time() - $start_time;
+$status = $racct->start();
+if(PEAR::isError($status)) {
+ if ($debug)
+ printf("Radius start: %s<br>\n", $status->getMessage());
+ exit;
+}
+// you can put any additional attributes here
+//$racct->putAttribute(RADIUS_SERVICE_TYPE, RADIUS_LOGIN);
+//$racct->putAttribute(RADIUS_NAS_IDENTIFIER, $nasHostname[0]);
+$racct->putAttribute(RADIUS_NAS_IP_ADDRESS, $nas_ip_address);
+$racct->putAttribute(RADIUS_ACCT_SESSION_ID, $sessionid);
+$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);
+if (!$interimupdate)
+$racct->putAttribute(RADIUS_ACCT_TERMINATE_CAUSE, $radius_term_cause);
+
+$result = $racct->send();
+if (PEAR::isError($result)) {
+ $retvalue = 1;
+ if ($debug)
+ printf("Radius send failed: %s<br>\n", $result->getMessage());
+} else if ($result === true) {
+ $retvalue = 5 ;
+ if ($debug)
+ printf("Radius Accounting succeeded<br>\n");
+} else {
+ $retvalue = 1 ;
+ if ($debug)
+ printf("Radius Accounting rejected<br>\n");
+}
+
+$racct->close();
+
+return $retvalue ;
+// 5 -> Accounting-Response
+// See RFC2866 for this.
+
+}
+
+function get_nas_ip() {
+ global $config;
+
+ /* static WAN IP address */
+ return $config['interfaces']['wan']['ipaddr'];
+}
+
+function gigawords($bytes) {
+ /* We use BCMath functions since normal integers don't work */
+ $gigawords = bcdiv( bcsub( $bytes, remainder($bytes) ) , 4294967295);
+
+ return $gigawords;
+}
+
+function remainder($bytes) {
+ /* Calculate the remainder */
+ $bytes = bcmod($bytes, 4294967295);
+
+ return $bytes;
+}
+
+
+
+?>
--- /dev/null
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+/*
+$Id$
+
+Copyright (c) 2005, Jonathan De Graeve <jonathan.de.graeve@imelda.be>
+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 <michael@bretterklieber.com>
+ author of the PHP PECL Radius package
+
+ $Id_jdg: 2005/11/08 20:42
+
+ Changes made include:
+ * Support for multiple radius servers
+ * Error Message and Reply Message
+ * Called-Station-Id,Calling-Station-Id,NAS-Port,NAS-Port-Type,NAS-Ip-Address
+ * Different Authentication Methods
+
+*/
+
+require_once("radius.inc");
+
+/*
+RADIUS AUTHENTICATION
+---------------------
+*/
+
+function RADIUS_AUTHENTICATION($username,$password,$radiusservers,$clientip,$clientmac,$ruleno,$auth_type = "PAP") {
+ global $config, $debug;
+
+ /* Initialisation of variables */
+ $retvalue = array();
+ $retvalue['error'] = $retvalue['reply_message'] = $retvalue['url_redirection'] = null;
+ $retvalue['session_timeout'] = 0;
+ $nas_ip = get_nas_ip();
+ $nas_mac = get_interface_mac($config['interfaces']['wan']['if']);
+ $nas_port = $ruleno - 10000;
+ $radiusvendor = $config['captiveportal']['radiusvendor'] ? $config['captiveportal']['radiusvendor'] : null;
+
+/*
+Possible Authentication methods
+$auth_type = 'PAP';
+$auth_type = 'CHAP_MD5';
+$auth_type = 'MSCHAPv1';
+$auth_type = 'MSCHAPv2';
+*/
+
+ exec("/bin/hostname", $nasHostname) ;
+ if(!$nasHostname[0])
+ $nasHostname[0] = "m0n0wall" ;
+
+$classname = 'Auth_RADIUS_' . $auth_type;
+$rauth = new $classname($username, $password);
+
+/*
+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) {
+
+ // Add a new server to our instance
+ $rauth->addServer($radsrv['ipaddr'], $radsrv['port'], $radsrv['key']);
+
+}
+
+$rauth->username = $username;
+
+switch($auth_type) {
+case 'CHAP_MD5':
+case 'MSCHAPv1':
+ $classname = $auth_type == 'MSCHAPv1' ? 'Crypt_CHAP_MSv1' : 'Crypt_CHAP_MD5';
+ $crpt = new $classname;
+ $crpt->password = $password;
+ $rauth->challenge = $crpt->challenge;
+ $rauth->chapid = $crpt->chapid;
+ $rauth->response = $crpt->challengeResponse();
+ $rauth->flags = 1;
+ break;
+
+case 'MSCHAPv2':
+ $crpt = new Crypt_CHAP_MSv2;
+ $crpt->username = $username;
+ $crpt->password = $password;
+ $rauth->challenge = $crpt->authChallenge;
+ $rauth->peerChallenge = $crpt->peerChallenge;
+ $rauth->chapid = $crpt->chapid;
+ $rauth->response = $crpt->challengeResponse();
+ break;
+
+default:
+ $rauth->password = $password;
+ break;
+}
+
+
+if (!$rauth->start()) {
+ $retvalue['auth_val'] = 1;
+ $retvalue['error'] = $rauth->getError();
+ if ($debug)
+ printf("Radius start: %s<br>\n", $retvalue['error']);
+}
+else {
+
+ // 1 -> Access-Request => We will use this value as an error indicator since we can't get a 1 back from the radius
+ // 2 -> Access-Accept
+ // 3 -> Access-Reject
+ // See RFC2865 for this.
+
+ /*
+ * We put our attributes in here
+ */
+
+ 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);
+ break;
+ }
+
+ // Default attributes
+ $rauth->putAttribute(RADIUS_NAS_IP_ADDRESS, $nas_ip, "addr");
+ $rauth->putAttribute(RADIUS_NAS_PORT, $nas_port);
+
+ // Send request
+
+ $result = $rauth->send();
+ if (PEAR::isError($result)) {
+ $retvalue['auth_val'] = 1;
+ $retvalue['error'] = $result->getMessage();
+ if ($debug)
+ printf("Radius send failed: %s<br>\n", $retvalue['error']);
+ } else if ($result === true) {
+ $retvalue['auth_val'] = 2;
+ if ($debug)
+ printf("Radius Auth succeeded<br>\n");
+ } else {
+ $retvalue['auth_val'] = 3;
+ if ($debug)
+ printf("Radius Auth rejected<br>\n");
+ }
+
+ // Get attributes, even if auth failed.
+ // We will push the results in the retvalue array
+ if (!$rauth->getAttributes()) {
+ $retvalue['error'] = $rauth->getError();
+ if ($debug)
+ printf("Radius getAttributes: No attributes<br>\n", $retvalue['error']);
+ } else {
+ $retvalue = array_merge($retvalue,$rauth->listAttributes());
+ if ($debug) {
+ if (!$rauth->listAttributes())
+ printf("No Attributes<br>\n");
+ else
+ print_r($rauth->listAttributes());
+ }
+ }
+ }
+
+ // close OO RADIUS_AUTHENTICATION
+ $rauth->close();
+
+ return $retvalue;
+
+}
+
+function get_nas_ip() {
+ global $config;
+
+ /* static WAN IP address */
+ return $config['interfaces']['wan']['ipaddr'];
+}
+
+function get_interface_mac($interface) {
+
+ /* build interface list with netstat */
+ exec("/usr/bin/netstat -I $interface -nW -f link", $linkinfo);
+ array_shift($linkinfo);
+ $alink = preg_split("/\s+/", $linkinfo[0]);
+ $mac = chop($alink[3]);
+ return $mac;
+}
+
+
+?>