diff options
-rw-r--r-- | etc/inc/captiveportal.inc | 289 | ||||
-rwxr-xr-x | usr/local/captiveportal/index.php | 78 | ||||
-rwxr-xr-x | usr/local/www/services_captiveportal.php | 13 | ||||
-rwxr-xr-x | usr/local/www/services_captiveportal_ip.php | 5 | ||||
-rwxr-xr-x | usr/local/www/services_captiveportal_ip_edit.php | 38 | ||||
-rwxr-xr-x | usr/local/www/services_captiveportal_mac.php | 14 | ||||
-rwxr-xr-x | usr/local/www/services_captiveportal_mac_edit.php | 27 |
7 files changed, 312 insertions, 152 deletions
diff --git a/etc/inc/captiveportal.inc b/etc/inc/captiveportal.inc index 33d1b75..c7095d6 100644 --- a/etc/inc/captiveportal.inc +++ b/etc/inc/captiveportal.inc @@ -102,6 +102,16 @@ function captiveportal_configure() { killbypid("{$g['varrun_path']}/lighty-CaptivePortal.pid"); killbypid("{$g['varrun_path']}/lighty-CaptivePortal-SSL.pid"); + /* remove old information */ + 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"); + mwexec("/sbin/ipfw table all flush"); + + /* setup new database in case someone tries to access the status -> captive portal page */ + touch("{$g['vardb_path']}/captiveportal.db"); + /* kill any running minicron */ killbypid("{$g['varrun_path']}/minicron.pid"); @@ -112,7 +122,14 @@ function captiveportal_configure() { mwexec("/sbin/kldload dummynet"); /* generate ipfw rules */ + captiveportal_init_ipfw_ruleno(); $cprules = captiveportal_rules_generate($cpinterface, $cpips); + $cprules .= "\n"; + /* generate passthru mac database */ + $cprules .= captiveportal_passthrumac_configure(true); + $cprules .= "\n"; + /* allowed ipfw rules to make allowed ip work */ + $cprules .= captiveportal_allowedip_configure(); /* stop accounting on all clients */ captiveportal_radius_stop_all(true); @@ -123,17 +140,6 @@ function captiveportal_configure() { /* 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"); - mwexec("/sbin/ipfw table all flush"); - - /* setup new database in case someone tries to access the status -> captive portal page */ - touch("{$g['vardb_path']}/captiveportal.db"); - /* write portal page */ if ($config['captiveportal']['page']['htmltext']) $htmltext = base64_decode($config['captiveportal']['page']['htmltext']); @@ -210,7 +216,7 @@ EOD; captiveportal_write_elements(); /* load rules */ - mwexec("/sbin/ipfw -f delete set 1"); + mwexec("/sbin/ipfw -q flush"); /* ipfw cannot accept rules directly on stdin, so we have to write them to a temporary file first */ @@ -225,7 +231,7 @@ EOD; mwexec("/sbin/ipfw {$g['tmp_path']}/ipfw.cp.rules"); - unlink("{$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"); @@ -268,11 +274,6 @@ EOD; mwexec("/usr/local/bin/minicron $croninterval {$g['varrun_path']}/minicron.pid " . "/etc/rc.prunecaptiveportal"); - /* generate passthru mac database */ - captiveportal_passthrumac_configure(true); - /* allowed ipfw rules to make allowed ip work */ - captiveportal_allowedip_configure(); - /* generate radius server database */ if ($config['captiveportal']['radiusip'] && (!isset($config['captiveportal']['auth_method']) || ($config['captiveportal']['auth_method'] == "radius"))) { @@ -346,36 +347,30 @@ EOD; function captiveportal_rules_generate($cpif, &$cpiparray) { global $config, $g; - $cpifn = $config['captiveportal']['interface']; - $lanip = get_interface_ip("lan"); - - /* note: the captive portal daemon inserts all pass rules for authenticated - clients as skipto 50000 rules to make traffic shaping work */ - - $cprules = "add 500 set 1 allow pfsync from any to any\n"; - $cprules .= "add 500 set 1 allow carp from any to any\n"; + $cprules = "add 65301 set 1 allow pfsync from any to any\n"; + $cprules .= "add 65302 set 1 allow carp from any to any\n"; $cprules .= <<<EOD -add 1000 set 1 skipto 1150 all from any to any not layer2 +# add 65305 set 1 skipto 65534 all from any to any not layer2 # layer 2: pass ARP -add 1100 set 1 pass layer2 mac-type arp +add 65310 set 1 pass layer2 mac-type arp # pfsense requires for WPA -add 1100 set 1 pass layer2 mac-type 0x888e -add 1100 set 1 pass layer2 mac-type 0x88c7 +add 65311 set 1 pass layer2 mac-type 0x888e +add 65312 set 1 pass layer2 mac-type 0x88c7 # PPP Over Ethernet Discovery Stage -add 1100 set 1 pass layer2 mac-type 0x8863 +add 65313 set 1 pass layer2 mac-type 0x8863 # PPP Over Ethernet Session Stage -add 1100 set 1 pass layer2 mac-type 0x8864 +add 65314 set 1 pass layer2 mac-type 0x8864 # Allow WPA -add 1100 set 1 pass layer2 mac-type 0x888e +add 65315 set 1 pass layer2 mac-type 0x888e # layer 2: block anything else non-IP -add 1101 set 1 deny layer2 not mac-type ip +add 65316 set 1 deny layer2 not mac-type ip EOD; - $rulenum = 1150; + $rulenum = 65320; $ips = "255.255.255.255 "; foreach ($cpiparray as $cpip) $ips .= "or {$cpip} "; @@ -420,30 +415,27 @@ EOD; $rulenum++; if (isset($config['captiveportal']['peruserbw'])) { - $cprules .= "add {$rulenum} set 1 pipe tablearg ip from table(3) to any in\n"; + $cprules .= "add {$rulenum} set 1 pipe tablearg ip from table(1) to any in\n"; $rulenum++; - $cprules .= "add {$rulenum} set 1 pipe tablearg ip from any to table(4) out\n"; + $cprules .= "add {$rulenum} set 1 pipe tablearg ip from any to table(2) out\n"; $rulenum++; } else { - $cprules .= "add {$rulenum} set 1 skipto 50000 ip from table(3) to any in\n"; + $cprules .= "add {$rulenum} set 1 allow ip from table(1) to any in\n"; $rulenum++; - $cprules .= "add {$rulenum} set 1 skipto 50000 ip from any to table(4) out\n"; + $cprules .= "add {$rulenum} set 1 allow ip from any to table(2) out\n"; $rulenum++; } $cprules .= <<<EOD # redirect non-authenticated clients to captive portal -add 1990 set 1 fwd 127.0.0.1,8000 tcp from any to any in +add 65531 set 1 fwd 127.0.0.1,8000 tcp from any to any in # let the responses from the captive portal web server back out -add 1991 set 1 pass tcp from any to any out +add 65532 set 1 pass tcp from any to any out # block everything else -add 1992 set 1 deny all from any to any - -# ... 2000-49899: layer2 block rules per authenticated client go here... - +add 65533 set 1 deny all from any to any # pass everything else on layer2 -add 49900 set 1 pass all from any to any layer2 +add 65534 set 1 pass all from any to any layer2 EOD; @@ -566,8 +558,8 @@ function captiveportal_prune_old() { $cpdb[$i][2], // clientip $cpdb[$i][3], // clientmac 10); // NAS Request - exec("/sbin/ipfw table 3 entryzerostats {$cpdb[$i][2]}"); - exec("/sbin/ipfw table 4 entryzerostats {$cpdb[$i][2]}"); + exec("/sbin/ipfw table 1 entryzerostats {$cpdb[$i][2]}"); + exec("/sbin/ipfw table 2 entryzerostats {$cpdb[$i][2]}"); RADIUS_ACCOUNTING_START($cpdb[$i][1], // ruleno $cpdb[$i][4], // username $cpdb[$i][5], // sessionid @@ -633,8 +625,10 @@ function captiveportal_disconnect($dbent, $radiusservers,$term_cause = 1,$stop_t $stop_time); } /* Delete client's ip entry from tables 3 and 4. */ - mwexec("/sbin/ipfw table 3 delete {$dbent[2]}"); - mwexec("/sbin/ipfw table 4 delete {$dbent[2]}"); + mwexec("/sbin/ipfw table 1 delete {$dbent[2]}"); + mwexec("/sbin/ipfw table 2 delete {$dbent[2]}"); + /* Release the ruleno so it can be reallocated to new clients. */ + captiveportal_free_ipfw_ruleno($dbent[1]); /* * These are the pipe numbers we use to control traffic shaping for each logged in user via captive portal @@ -645,7 +639,7 @@ function captiveportal_disconnect($dbent, $radiusservers,$term_cause = 1,$stop_t mwexec("/sbin/ipfw pipe " . ($dbent[1]+20001) . " delete"); } - /* Ensure all pf(4) states are killed. */ + /* XXX: Redundant?! Ensure all pf(4) states are killed. */ mwexec("pfctl -k {$dbent[2]}"); mwexec("pfctl -K {$dbent[2]}"); @@ -664,7 +658,8 @@ function captiveportal_disconnect_client($id,$term_cause = 1) { /* find entry */ $tmpindex = 0; - for ($i = 0; $i < count($cpdb); $i++) { + $cpdbcount = count($cpdb); + for ($i = 0; $i < $cpdbcount; $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"); @@ -717,6 +712,7 @@ function captiveportal_passthrumac_configure($lock = false) { /* clear out passthru macs, if necessary */ unlink_if_exists("{$g['vardb_path']}/captiveportal_mac.db"); + $rules = ""; if (is_array($config['captiveportal']['passthrumac'])) { $fd = @fopen("{$g['vardb_path']}/captiveportal_mac.db", "w"); @@ -726,69 +722,85 @@ function captiveportal_passthrumac_configure($lock = false) { return 1; } + $peruserbw = isset($config['captiveportal']['peruserbw']); + $macdb = ""; foreach ($config['captiveportal']['passthrumac'] as $macent) { - /* record passthru mac so it can be recognized and let thru */ - fwrite($fd, $macent['mac'] . "\n"); + $ruleno = captiveportal_get_next_ipfw_ruleno(); + + $macdb .= $macent['mac'] . "\n"; + + /* pfSense: + * pass through mac entries should always exist. the reason + * for this is because we do not have native mac address filtering + * mechanisms. this allows us to filter by mac address easily + * and get around this limitation. I consider this a bug in + * m0n0wall and pfSense as m0n0wall does not have native mac + * filtering mechanisms as well. -Scott Ullrich + * + * Add rules for traffic shaping. + * This assumes that net.inet.ip.fw.one_pass: 1 is set. + */ + + $actionup = "allow"; + $actiondown = "allow"; + if ($peruserbw) { + $bw_up = isset($macent['bw_up']) ? trim($macent['bw_up']) : $config['captiveportal']['bwdefaultup']; + $bw_down = isset($macent['bw_down']) ? trim($macent['bw_down']) : $config['captiveportal']['bwdefaultdn']; + if (!empty($bw_up) && is_numeric($bw_up)) { + $bw_up_pipeno = $ruleno + 20000; + $rules .= "pipe {$bw_up_pipeno} config bw {$bw_up}Kbit/s queue 100\n"; + $actionup = "pipe {$bw_up_pipeno}"; + } + if (!empty($bw_down) && is_numeric($bw_down)) { + $bw_down_pipeno = $ruleno + 20001; + $rules .= "pipe {$bw_down_pipeno} config bw {$bw_down}Kbit/s queue 100\n"; + $actiondown = "pipe {$bw_down_pipeno}"; + } + } + $rules .= "add {$ruleno} {$actionup} ip from any to any MAC {$macent['mac']} any\n"; + $ruleno++; + $rules .= "add {$ruleno} {$actiondown} ip from any to any MAC any {$macent['mac']}\n"; } - + /* record passthru MACs so can be recognized and let thru */ + fwrite($fd, $macdb); fclose($fd); } - /* pfSense: - * pass through mac entries should always exist. the reason - * for this is because we do not have native mac address filtering - * mechanisms. this allows us to filter by mac address easily - * and get around this limitation. I consider this a bug in - * m0n0wall and pfSense as m0n0wall does not have native mac - * filtering mechanisms as well. -Scott Ullrich - */ - if (is_array($config['captiveportal']['passthrumac'])) { - mwexec("/sbin/ipfw delete 50"); - foreach($config['captiveportal']['passthrumac'] as $ptm) { - /* create the pass through mac entry */ - //system("echo /sbin/ipfw add 50 skipto 65535 ip from any to any MAC {$ptm['mac']} any > /tmp/cp"); - mwexec("/sbin/ipfw add 50 skipto 49900 ip from any to any MAC {$ptm['mac']} any keep-state"); - mwexec("/sbin/ipfw add 50 skipto 49900 ip from any to any MAC any {$ptm['mac']} keep-state"); - } - } - if (!$lock) unlock($captiveportallck); - return 0; + return $rules; } function captiveportal_allowedip_configure() { global $config, $g; - /* clear out existing allowed ips, if necessary */ - mwexec("/sbin/ipfw table 1 flush"); - mwexec("/sbin/ipfw table 2 flush"); - + $rules = ""; if (is_array($config['captiveportal']['allowedip'])) { - $tableone = false; - $tabletwo = false; + $peruserbw = isset($config['captiveportal']['peruserbw']); foreach ($config['captiveportal']['allowedip'] as $ipent) { + $ruleno = captiveportal_get_next_ipfw_ruleno(); + $bw_up = ""; + $bw_down = ""; + if ($peruserbw) { + $bwup = isset($ipent['bw_up']) ? trim($ipent['bw_up']) : $config['captiveportal']['bwdefaultup']; + $bwdown = isset($ipent['bw_down']) ? trim($ipent['bw_down']) : $config['captiveportal']['bwdefaultdn']; + if (!empty($bwup) && is_numeric($bwup)) { + $bw_up = $ruleno + 20000; + $rules .= "pipe {$bw_up} config bw {$bw_up}Kbit/s queue 100\n"; + } + if (!empty($bwdown) && is_numeric($bwdown)) { + $bw_down = $ruleno + 20001; + $rules .= "pipe {$bw_down} config bw {$bw_down}Kbit/s queue 100\n"; + } + } /* insert address in ipfw table */ - if ($ipent['dir'] == "from") { - mwexec("/sbin/ipfw table 1 add {$ipent['ip']}"); - $tableone = true; - } else { - mwexec("/sbin/ipfw table 2 add {$ipent['ip']}"); - $tabletwo = true; - } - } - if ($tableone == true) { - mwexec("/sbin/ipfw add 1890 set 1 skipto 50000 ip from table\(1\) to any in"); - mwexec("/sbin/ipfw add 1891 set 1 skipto 50000 ip from any to table\(1\) out"); - } - if ($tabletwo == true) { - mwexec("/sbin/ipfw add 1892 set 1 skipto 50000 ip from any to table\(2\) in"); - mwexec("/sbin/ipfw add 1893 set 1 skipto 50000 ip from table\(2\) to any out"); + $rules .= "table 1 add {$ipent['ip']} ${bw_up}\n"; + $rules .= "table 2 add {$ipent['ip']} ${bw_down}\n"; } } - return 0; + return $rules; } /* get last activity timestamp given client IP address */ @@ -796,7 +808,7 @@ function captiveportal_get_last_activity($ip) { $ipfwoutput = ""; - exec("/sbin/ipfw table 3 entrystats {$ip} 2>/dev/null", $ipfwoutput); + exec("/sbin/ipfw table 1 entrystats {$ip} 2>/dev/null", $ipfwoutput); /* Reading only from one of the tables is enough of approximation. */ if ($ipfwoutput[0]) { $ri = explode(" ", $ipfwoutput[0]); @@ -974,6 +986,14 @@ function captiveportal_write_elements() { return 0; } +function captiveportal_init_ipfw_ruleno($rulenos_start = 2000, $rulenos_range_max = 49899) { + global $g; + + @unlink("{$g['vardb_path']}/captiveportal.rules"); + $rules = array_pad(array(), $rulenos_range_max - $rulenos_start, false); + file_put_contents("{$g['vardb_path']}/captiveportal.rules", serialize($rules)); +} + /* * This function will calculate the lowest free firewall ruleno * within the range specified based on the actual logged on users @@ -981,26 +1001,67 @@ function captiveportal_write_elements() { */ function captiveportal_get_next_ipfw_ruleno($rulenos_start = 2000, $rulenos_range_max = 49899) { global $config, $g; + if(!isset($config['captiveportal']['enable'])) return NULL; + $ruleno = 0; - if (file_exists("{$g['vardb_path']}/captiveportal.nextrule")) - $ruleno = intval(file_get_contents("{$g['vardb_path']}/captiveportal.nextrule")); - else - $ruleno = 1; - if ($ruleno > 0 && (($rulenos_start + $ruleno) < $rulenos_range_max)) { - /* - * This allows our traffic shaping pipes to be the in pipe the same as ruleno - * and the out pipe ruleno + 1. This removes limitation that where present in - * previous version of the peruserbw. - */ + if (file_exists("{$g['vardb_path']}/captiveportal.rules")) { + $rules = unserialize(file_get_contents("{$g['vardb_path']}/captiveportal.rules")); + for ($ridx = 2; $ridx < ($rulenos_range_max - $rulenos_start); $ridx++) { + if ($rules[$ridx]) { + /* + * This allows our traffic shaping pipes to be the in pipe the same as ruleno + * and the out pipe ruleno + 1. This removes limitation that where present in + * previous version of the peruserbw. + */ + if (isset($config['captiveportal']['peruserbw'])) + $ridx++; + continue; + } + $ruleno = $ridx; + $rules[$ridx] = "used"; + if (isset($config['captiveportal']['peruserbw'])) + $rules[++$ridx] = "used"; + break; + } + } else { + $rules = array_pad(array(), $rulenos_range_max - $rulenos_start, false); + $rules[2] = "used"; + $ruleno = 2; + } + file_put_contents("{$g['vardb_path']}/captiveportal.rules", serialize($rules)); + return $ruleno; +} + +function captiveportal_free_ipfw_ruleno($ruleno) { + global $config, $g; + + if(!isset($config['captiveportal']['enable'])) + return NULL; + + if (file_exists("{$g['vardb_path']}/captiveportal.rules")) { + $rules = unserialize(file_get_contents("{$g['vardb_path']}/captiveportal.rules")); + $rules[$ruleno] = false; if (isset($config['captiveportal']['peruserbw'])) - $ruleno += 2; - else - $ruleno++; - file_put_contents("{$g['vardb_path']}/captiveportal.nextrule", $ruleno); - return $rulenos_start + $ruleno; + $rules[++$ruleno] = false; + file_put_contents("{$g['vardb_path']}/captiveportal.rules", serialize($rules)); } +} + +function captiveportal_get_ipfw_ruleno_byvalue($value) { + global $config, $g; + + if(!isset($config['captiveportal']['enable'])) + return NULL; + + if (file_exists("{$g['vardb_path']}/captiveportal.rules")) { + $rules = unserialize(file_get_contents("{$g['vardb_path']}/captiveportal.rules")); + $ruleno = intval(`/sbin/ipfw show | /usr/bin/grep 00:0c:29:88:77:80 | /usr/bin/grep -v grep | /usr/bin/cut -d " " -f 1 | /usr/bin/head -n 1`); + if ($rules[$ruleno]) + return $ruleno; + } + return NULL; } @@ -1027,14 +1088,14 @@ function getVolume($ip) { $ipfwout = ""; $matchesin = ""; $matchesout = ""; - exec("/sbin/ipfw table 3 entrystats {$ip}", $ipfwin); + exec("/sbin/ipfw table 1 entrystats {$ip}", $ipfwin); if ($ipfwin[0]) { $ipfwin = split(" ", $ipfwin[0]); $volume['input_pkts'] = $ipfwin[2]; $volume['input_bytes'] = $ipfwin[3]; } - exec("/sbin/ipfw table 4 entrystats {$ip}", $ipfwout); + exec("/sbin/ipfw table 2 entrystats {$ip}", $ipfwout); if ($ipfwout[0]) { $ipfwout = split(" ", $ipfwout[0]); $volume['output_pkts'] = $ipfwout[2]; diff --git a/usr/local/captiveportal/index.php b/usr/local/captiveportal/index.php index 0011f0b..c2f886c 100755 --- a/usr/local/captiveportal/index.php +++ b/usr/local/captiveportal/index.php @@ -117,11 +117,13 @@ setTimeout('window.close();',5000) ; </HTML> EOD; -/* The $macfilter can be removed safely since we first check if the $clientmac is present, if not we fail */ +/* NOTE: This is not needed now that CP works only at layer2. + * The $macfilter can be removed safely since we first check if the $clientmac is present, if not we fail } else if ($clientmac && portal_mac_fixed($clientmac)) { - /* punch hole in ipfw for pass thru mac addresses */ + // punch hole in ipfw for pass thru mac addresses portal_allow($clientip, $clientmac, "unauthenticated"); exit; +*/ } else if ($clientmac && $radmac_enable && portal_mac_radius($clientmac,$clientip)) { /* radius functions handle everything so we exit here since we're done */ @@ -307,6 +309,7 @@ function portal_allow($clientip,$clientmac,$username,$password = null, $attribut return 0; // voucher already used and no time left } + $writecfg = false; if (!isset($sessionid)) { /* generate unique session ID */ @@ -314,40 +317,69 @@ function portal_allow($clientip,$clientmac,$username,$password = null, $attribut $sessionid = substr(md5(mt_rand() . $tod['sec'] . $tod['usec'] . $clientip . $clientmac), 0, 16); /* Add rules for traffic shaping - * We don't need to add extra l3 allow rules since traffic will pass due to the following kernel option + * We don't need to add extra rules since traffic will pass due to the following kernel option * net.inet.ip.fw.one_pass: 1 */ $peruserbw = isset($config['captiveportal']['peruserbw']); - + $passthrumacadd = isset($config['captiveportal']['passthrumacadd']); + $bw_up = isset($attributes['bw_up']) ? trim($attributes['bw_up']) : $config['captiveportal']['bwdefaultup']; $bw_down = isset($attributes['bw_down']) ? trim($attributes['bw_down']) : $config['captiveportal']['bwdefaultdn']; + if ($passthrumacadd) { + $mac = array(); + $mac['mac'] = $clientmac; + if (!empty($bw_up)) + $mac['bw_up'] = $bw_up; + if (!empty($bw_down)) + $mac['bw_down'] = $bw_down; + if (!is_array($config['captiveportal']['passthrumac'])) + $config['captiveportal']['passthrumac'] = array(); + $config['captiveportal']['passthrumac'][] = $mac; + $writecfg = true; + } + if ($peruserbw && !empty($bw_up) && is_numeric($bw_up)) { $bw_up_pipeno = $ruleno + 20000; - mwexec("/sbin/ipfw pipe $bw_up_pipeno config bw {$bw_up}Kbit/s queue 100"); - - if (!isset($config['captiveportal']['nomacfilter'])) - mwexec("/sbin/ipfw table 3 add {$clientip} mac {$clientmac} {$bw_up_pipeno}"); + //$bw_up /= 1000; // Scale to Kbit/s + mwexec("/sbin/ipfw pipe {$bw_up_pipeno} config bw {$bw_up}Kbit/s queue 100"); + mwexec("echo 'pipe {$bw_up_pipeno} config bw {$bw_up}Kbit/s queue 100' > /tmp/testing"); + + if ($passthrumacadd) { + mwexec("/sbin/ipfw add {$ruleno} pipe {$bw_up_pipeno} ip from any to any MAC {$clientmac} any"); + } else if (!isset($config['captiveportal']['nomacfilter'])) + mwexec("/sbin/ipfw table 1 add {$clientip} mac {$clientmac} {$bw_up_pipeno}"); else - mwexec("/sbin/ipfw table 3 add {$clientip} {$bw_up_pipeno}"); + mwexec("/sbin/ipfw table 1 add {$clientip} {$bw_up_pipeno}"); } else { - if (!isset($config['captiveportal']['nomacfilter'])) - mwexec("/sbin/ipfw table 3 add {$clientip} mac {$clientmac}"); + if ($passthrumacadd) { + mwexec("/sbin/ipfw add {$ruleno} allow ip from any to any MAC {$clientmac} any"); + } else if (!isset($config['captiveportal']['nomacfilter'])) + mwexec("/sbin/ipfw table 1 add {$clientip} mac {$clientmac}"); else - mwexec("/sbin/ipfw table 3 add {$clientip}"); + mwexec("/sbin/ipfw table 1 add {$clientip}"); } if ($peruserbw && !empty($bw_down) && is_numeric($bw_down)) { $bw_down_pipeno = $ruleno + 20001; - mwexec("/sbin/ipfw pipe $bw_down_pipeno config bw {$bw_down}Kbit/s queue 100"); - if (!isset($config['captiveportal']['nomacfilter'])) - mwexec("/sbin/ipfw table 4 add {$clientip} mac {$clientmac} {$bw_down_pipeno}"); + //$bw_down /= 1000; // Scale to Kbit/s + mwexec("/sbin/ipfw pipe {$bw_down_pipeno} config bw {$bw_down}Kbit/s queue 100"); + mwexec("echo 'pipe {$bw_down_pipeno} config bw {$bw_down}Kbit/s queue 100' > /tmp/testing"); + + if ($passthrumacadd) { + $ruledown = $ruleno + 1; + mwexec("/sbin/ipfw add {$ruledown} pipe {$bw_down_pipeno} ip from any to any MAC any {$clientmac}"); + } else if (!isset($config['captiveportal']['nomacfilter'])) + mwexec("/sbin/ipfw table 2 add {$clientip} mac {$clientmac} {$bw_down_pipeno}"); else - mwexec("/sbin/ipfw table 4 add {$clientip} {$bw_down_pipeno}"); + mwexec("/sbin/ipfw table 2 add {$clientip} {$bw_down_pipeno}"); } else { - if (!isset($config['captiveportal']['nomacfilter'])) - mwexec("/sbin/ipfw table 4 add {$clientip} mac {$clientmac}"); + if ($passthrumacadd) { + $ruledown = $ruleno + 1; + mwexec("/sbin/ipfw add {$ruleno} allow ip from any to any MAC {$clientmac} any"); + } else if (!isset($config['captiveportal']['nomacfilter'])) + mwexec("/sbin/ipfw table 2 add {$clientip} mac {$clientmac}"); else - mwexec("/sbin/ipfw table 4 add {$clientip}"); + mwexec("/sbin/ipfw table 2 add {$clientip}"); } if ($attributes['voucher']) @@ -379,6 +411,9 @@ function portal_allow($clientip,$clientmac,$username,$password = null, $attribut if ($captiveshouldunlock == true) unlock($cplock); + if ($writecfg == true) + write_config(); + /* redirect user to desired destination */ if ($url_redirection) $my_redirurl = $url_redirection; @@ -387,7 +422,7 @@ function portal_allow($clientip,$clientmac,$username,$password = null, $attribut else $my_redirurl = $redirurl; - if(isset($config['captiveportal']['logoutwin_enable'])) { + if(isset($config['captiveportal']['logoutwin_enable']) && !isset($config['captiveportal']['passthrumacadd'])) { if (isset($config['captiveportal']['httpslogin'])) $logouturl = "https://{$config['captiveportal']['httpsname']}:8001/"; @@ -456,7 +491,8 @@ function disconnect_client($sessionid, $logoutReason = "LOGOUT", $term_cause = 1 $radiusservers = captiveportal_get_radius_servers(); /* find entry */ - for ($i = 0; $i < count($cpdb); $i++) { + $dbcount = count($cpdb); + for ($i = 0; $i < $dbcount; $i++) { if ($cpdb[$i][5] == $sessionid) { captiveportal_disconnect($cpdb[$i],$radiusservers, $term_cause); captiveportal_logportalauth($cpdb[$i][4],$cpdb[$i][3],$cpdb[$i][2],$logoutReason); diff --git a/usr/local/www/services_captiveportal.php b/usr/local/www/services_captiveportal.php index b79a5ac..99a943f 100755 --- a/usr/local/www/services_captiveportal.php +++ b/usr/local/www/services_captiveportal.php @@ -92,6 +92,7 @@ $pconfig['radiuskey'] = $config['captiveportal']['radiuskey']; $pconfig['radiuskey2'] = $config['captiveportal']['radiuskey2']; $pconfig['radiusvendor'] = $config['captiveportal']['radiusvendor']; $pconfig['radiussession_timeout'] = isset($config['captiveportal']['radiussession_timeout']); +$pconfig['passthrumacadd'] = isset($config['captiveportal']['passthrumacadd']); $pconfig['radmac_format'] = $config['captiveportal']['radmac_format']; if ($_POST) { @@ -192,7 +193,8 @@ if ($_POST) { $config['captiveportal']['radiuskey2'] = $_POST['radiuskey2']; $config['captiveportal']['radiusvendor'] = $_POST['radiusvendor'] ? $_POST['radiusvendor'] : false; $config['captiveportal']['radiussession_timeout'] = $_POST['radiussession_timeout'] ? true : false; - $config['captiveportal']['radmac_format'] = $_POST['radmac_format'] ? $_POST['radmac_format'] : false; + $config['captiveportal']['passthrumacadd'] = $_POST['passthrumacadd'] ? true : false; + $config['captiveportal']['radmac_format'] = $_POST['radmac_format'] ? $_POST['radmac_format'] : false; /* file upload? */ if (is_uploaded_file($_FILES['htmlfile']['tmp_name'])) @@ -362,6 +364,15 @@ to access after they've authenticated.</td> If this is enabled, RADIUS MAC authentication cannot be used.</td> </tr> <tr> + <td valign="top" class="vncell">MAC passthrough</td> + <td class="vtable"> + <input name="passthrumacadd" type="checkbox" class="formfld" id="passthrumacadd" value="yes" <?php if ($pconfig['passthrumacadd']) echo "checked"; ?>> + <strong>MAC passthrough authentication</strong><br> + If this option is set, after a user is authenticated a mac passthrough entry will be added. + To remove the passthrough MAC entry you either have to log in and remove it manually from the MAC passthrough tab or send a POST to remove it from some other system. + If this is enabled, RADIUS MAC authentication cannot be used. Also, the logout window will not be shown.</td> + </tr> + <tr> <td valign="top" class="vncell">Per-user bandwidth restriction</td> <td class="vtable"> <input name="peruserbw" type="checkbox" class="formfld" id="peruserbw" value="yes" <?php if ($pconfig['peruserbw']) echo "checked"; ?>> diff --git a/usr/local/www/services_captiveportal_ip.php b/usr/local/www/services_captiveportal_ip.php index 60d2792..1da30a1 100755 --- a/usr/local/www/services_captiveportal_ip.php +++ b/usr/local/www/services_captiveportal_ip.php @@ -54,10 +54,11 @@ $a_allowedips = &$config['captiveportal']['allowedip'] ; if ($_GET['act'] == "del") { if ($a_allowedips[$_GET['id']]) { $ipent = $a_allowedips[$_GET['id']]; - if ($ipent['dir'] == "from") + + if (isset($config['captiveportal']['enable'])) { mwexec("/sbin/ipfw table 1 delete " . $ipent['ip']); - else mwexec("/sbin/ipfw table 2 delete " . $ipent['ip']); + } unset($a_allowedips[$_GET['id']]); write_config(); diff --git a/usr/local/www/services_captiveportal_ip_edit.php b/usr/local/www/services_captiveportal_ip_edit.php index 93628ba..4e1b661 100755 --- a/usr/local/www/services_captiveportal_ip_edit.php +++ b/usr/local/www/services_captiveportal_ip_edit.php @@ -67,8 +67,9 @@ if (isset($_POST['id'])) if (isset($id) && $a_allowedips[$id]) { $pconfig['ip'] = $a_allowedips[$id]['ip']; + $pconfig['bw_up'] = $a_allowedips[$id]['bw_up']; + $pconfig['bw_down'] = $a_allowedips[$id]['bw_down']; $pconfig['descr'] = $a_allowedips[$id]['descr']; - $pconfig['dir'] = $a_allowedips[$id]['dir']; } if ($_POST) { @@ -85,6 +86,10 @@ if ($_POST) { if (($_POST['ip'] && !is_ipaddr($_POST['ip']))) { $input_errors[] = "A valid IP address must be specified. [".$_POST['ip']."]"; } + if ($_POST['bw_up'] && !is_numeric($_POST['bw_up'])) + $input_errors[] = "Upload speed needs to be an integer"; + if ($_POST['bw_down'] && !is_numeric($_POST['bw_down'])) + $input_errors[] = "Download speed needs to be an integer"; foreach ($a_allowedips as $ipent) { if (isset($id) && ($a_allowedips[$id]) && ($a_allowedips[$id] === $ipent)) @@ -100,8 +105,10 @@ if ($_POST) { $ip = array(); $ip['ip'] = $_POST['ip']; $ip['descr'] = $_POST['descr']; - $ip['dir'] = $_POST['dir']; - + if ($_POST['bw_up']) + $ip['bw_up'] = $_POST['bw_up']; + if ($_POST['bw_down']) + $ip['bw_down'] = $_POST['bw_down']; if (isset($id) && $a_allowedips[$id]) $a_allowedips[$id] = $ip; else @@ -111,10 +118,7 @@ if ($_POST) { write_config(); if (isset($config['captiveportal']['enable'])) { - if ($ip['dir'] == "from") - mwexec("/sbin/ipfw table 1 add " . $ip['ip']); - else - mwexec("/sbin/ipfw table 2 add " . $ip['ip']); + mwexec("/sbin/ipfw table 1 add " . $ip['ip']); } header("Location: services_captiveportal_ip.php"); @@ -130,7 +134,8 @@ include("head.inc"); <?php if ($input_errors) print_input_errors($input_errors); ?> <form action="services_captiveportal_ip_edit.php" method="post" name="iform" id="iform"> <table width="100%" border="0" cellpadding="6" cellspacing="0"> - <tr> +<?php if (false): ?> + <tr> <td width="22%" valign="top" class="vncellreq">Direction</td> <td width="78%" class="vtable"> <select name="dir" class="formselect"> @@ -146,20 +151,33 @@ include("head.inc"); <span class="vexpl">Use <em>From</em> to always allow an IP address through the captive portal (without authentication). Use <em>To</em> to allow access from all clients (even non-authenticated ones) behind the portal to this IP address.</span></td> </tr> - <tr> +<?php endif; ?> + <tr> <td width="22%" valign="top" class="vncellreq">IP address</td> <td width="78%" class="vtable"> <?=$mandfldhtml;?><input name="ip" type="text" class="formfld unknown" id="ip" size="17" value="<?=htmlspecialchars($pconfig['ip']);?>"> <br> <span class="vexpl">IP address</span></td> </tr> - <tr> + <tr> <td width="22%" valign="top" class="vncell">Description</td> <td width="78%" class="vtable"> <input name="descr" type="text" class="formfld unknown" id="descr" size="40" value="<?=htmlspecialchars($pconfig['descr']);?>"> <br> <span class="vexpl">You may enter a description here for your reference (not parsed).</span></td> </tr> + <tr> + <td width="22%" valign="top" class="vncell">Bandwidth up</td> + <td width="78%" class="vtable"> + <input name="bw_up" type="text" class="formfld unknown" id="bw_up" size="10" value="<?=htmlspecialchars($pconfig['bw_up']);?>"> + <br> <span class="vexpl">Enter a upload limit to be enforced on this mac-address in Kbit/s</span></td> + </tr> + <tr> + <td width="22%" valign="top" class="vncell">Bandwidth down</td> + <td width="78%" class="vtable"> + <input name="bw_down" type="text" class="formfld unknown" id="bw_down" size="10" value="<?=htmlspecialchars($pconfig['bw_down']);?>"> + <br> <span class="vexpl">Enter a download limit to be enforced on this mac-address in Kbit/s</span></td> + </tr> <tr> <td width="22%" valign="top"> </td> <td width="78%"> diff --git a/usr/local/www/services_captiveportal_mac.php b/usr/local/www/services_captiveportal_mac.php index 5080c0c..ca900bf 100755 --- a/usr/local/www/services_captiveportal_mac.php +++ b/usr/local/www/services_captiveportal_mac.php @@ -50,6 +50,7 @@ if (!is_array($config['captiveportal']['passthrumac'])) $a_passthrumacs = &$config['captiveportal']['passthrumac'] ; + if ($_POST) { $pconfig = $_POST; @@ -57,7 +58,9 @@ if ($_POST) { if ($_POST['apply']) { $retval = 0; - $retval = captiveportal_passthrumac_configure(); + $rules = captiveportal_passthrumac_configure(); + file_put_contents("{$g['tmp_path']}/passthru.mac", $rules); + mwexec("/sbin/ipfw {$g['tmp_path']}/passthru.mac"); $savemsg = get_std_save_message($retval); if ($retval == 0) @@ -67,10 +70,17 @@ if ($_POST) { if ($_GET['act'] == "del") { if ($a_passthrumacs[$_GET['id']]) { + $ruleno = captiveportal_get_ipfw_ruleno_byvalue($a_passthrumacs[$_GET['id']]['mac']); + if ($ruleno) { + mwexec("/sbin/ipfw delete {$ruleno}"); + captiveportal_free_ipfw_ruleno($ruleno); + $ruleno++; + mwexec("/sbin/ipfw delete {$ruleno}"); + } unset($a_passthrumacs[$_GET['id']]); write_config(); - mark_subsystem_dirty('passthrumac'); header("Location: services_captiveportal_mac.php"); + //mark_subsystem_dirty('passthrumac'); exit; } } diff --git a/usr/local/www/services_captiveportal_mac_edit.php b/usr/local/www/services_captiveportal_mac_edit.php index 9123303..f618d47 100755 --- a/usr/local/www/services_captiveportal_mac_edit.php +++ b/usr/local/www/services_captiveportal_mac_edit.php @@ -66,6 +66,8 @@ if (isset($_POST['id'])) if (isset($id) && $a_passthrumacs[$id]) { $pconfig['mac'] = $a_passthrumacs[$id]['mac']; + $pconfig['bw_up'] = $a_passthrumacs[$id]['bw_up']; + $pconfig['bw_down'] = $a_passthrumacs[$id]['bw_down']; $pconfig['descr'] = $a_passthrumacs[$id]['descr']; } @@ -85,6 +87,10 @@ if ($_POST) { if (($_POST['mac'] && !is_macaddr($_POST['mac']))) { $input_errors[] = "A valid MAC address must be specified. [".$_POST['mac']."]"; } + if ($_POST['bw_up'] && !is_numeric($_POST['bw_up'])) + $input_errors[] = "Upload speed needs to be an integer"; + if ($_POST['bw_down'] && !is_numeric($_POST['bw_down'])) + $input_errors[] = "Download speed needs to be an integer"; foreach ($a_passthrumacs as $macent) { if (isset($id) && ($a_passthrumacs[$id]) && ($a_passthrumacs[$id] === $macent)) @@ -99,6 +105,11 @@ if ($_POST) { if (!$input_errors) { $mac = array(); $mac['mac'] = $_POST['mac']; + if ($_POST['bw_up']) + $mac['bw_up'] = $_POST['bw_up']; + if ($_POST['bw_down']) + $mac['bw_down'] = $_POST['bw_down']; + $mac['descr'] = $_POST['descr']; if (isset($id) && $a_passthrumacs[$id]) @@ -109,7 +120,7 @@ if ($_POST) { write_config(); - mark_subsystem_dirty('passthrumac'); + //mark_subsystem_dirty('passthrumac'); header("Location: services_captiveportal_mac.php"); exit; @@ -129,13 +140,25 @@ include("head.inc"); <br> <span class="vexpl">MAC address (6 hex octets separated by colons)</span></td> </tr> - <tr> + <tr> <td width="22%" valign="top" class="vncell">Description</td> <td width="78%" class="vtable"> <input name="descr" type="text" class="formfld unknown" id="descr" size="40" value="<?=htmlspecialchars($pconfig['descr']);?>"> <br> <span class="vexpl">You may enter a description here for your reference (not parsed).</span></td> </tr> + <tr> + <td width="22%" valign="top" class="vncell">Bandwidth up</td> + <td width="78%" class="vtable"> + <input name="bw_up" type="text" class="formfld unknown" id="bw_up" size="10" value="<?=htmlspecialchars($pconfig['bw_up']);?>"> + <br> <span class="vexpl">Enter a upload limit to be enforced on this mac-address in Kbit/s</span></td> + </tr> + <tr> + <td width="22%" valign="top" class="vncell">Bandwidth down</td> + <td width="78%" class="vtable"> + <input name="bw_down" type="text" class="formfld unknown" id="bw_down" size="10" value="<?=htmlspecialchars($pconfig['bw_down']);?>"> + <br> <span class="vexpl">Enter a download limit to be enforced on this mac-address in Kbit/s</span></td> + </tr> <tr> <td width="22%" valign="top"> </td> <td width="78%"> |