diff options
author | Ermal Luçi <eri@pfsense.org> | 2009-08-14 17:13:38 +0000 |
---|---|---|
committer | Ermal Luçi <eri@pfsense.org> | 2009-08-14 17:13:38 +0000 |
commit | f9f71ad37706cbe37ebc8af34aa55c029369c075 (patch) | |
tree | df22e56700dc3b90c6d0f6ed7ded3ecda3f6dd87 | |
parent | 74194bf7bb8c8c5783c7a48dfc5f81d4ba5feca7 (diff) | |
download | pfsense-f9f71ad37706cbe37ebc8af34aa55c029369c075.zip pfsense-f9f71ad37706cbe37ebc8af34aa55c029369c075.tar.gz |
* Convert captive portal rules to use tables. This reduces the number of rules ALOT.
* Make the peruserbw setting use tables also by taking advantage of the tablearg option.
* Convert statistics to use the new improvements of ipfw tables merged previously.
* Make the limit of users allowed around 25000 instead of 9999 of before.
NOTE: The only thing remaining for full optimization on ipfw(4) side is converting passthrumac and layer2 secure rules to tables aswell.
-rw-r--r-- | etc/inc/captiveportal.inc | 184 | ||||
-rwxr-xr-x | usr/local/captiveportal/index.php | 21 | ||||
-rw-r--r-- | usr/local/captiveportal/radius_accounting.inc | 4 | ||||
-rwxr-xr-x | usr/local/www/status_captiveportal.php | 2 | ||||
-rw-r--r-- | usr/local/www/widgets/widgets/captive_portal_status.widget.php | 2 |
5 files changed, 102 insertions, 111 deletions
diff --git a/etc/inc/captiveportal.inc b/etc/inc/captiveportal.inc index bfd3c01..9c70d33 100644 --- a/etc/inc/captiveportal.inc +++ b/etc/inc/captiveportal.inc @@ -333,7 +333,7 @@ EOD; } $cprules .= <<<EOD -add 1000 set 1 skipto 1200 all from any to any not layer2 +add 1000 set 1 skipto 1150 all from any to any not layer2 # layer 2: pass ARP add 1100 set 1 pass layer2 mac-type arp # pfsense requires for WPA @@ -350,11 +350,11 @@ add 1100 set 1 pass layer2 mac-type 0x888e # layer 2: block anything else non-IP add 1101 set 1 deny layer2 not mac-type ip # layer 2: check if MAC addresses of authenticated clients are correct -add 1102 set 1 skipto 20000 layer2 +add 1102 set 1 skipto 2000 layer2 EOD; - $rulenum = 1200; + $rulenum = 1150; foreach ($cpiparray as $cpip) { //# allow access to our DHCP server (which needs to be able to ping clients as well) $cprules .= "add {$rulenum} set 1 pass udp from any 68 to 255.255.255.255 67 in \n"; @@ -384,23 +384,33 @@ EOD; $cprules .= "add {$rulenum} set 1 pass tcp from {$cpip} 8001 to any out \n"; } } - $rulenum++; - $cprules .= <<<EOD -# ... 10000-19899: rules per authenticated client go here... + if (isset($config['captiveportal']['peruserbw'])) { + $cprules .= "add {$rulenum} set 2 pipe tablearg ip from table(3) to any in\n"; + $rulenum++; + $cprules .= "add {$rulenum} set 2 pipe tablearg ip from any to table(4) out\n"; + $rulenum++; + } else { + $cprules .= "add {$rulenum} set 2 skipto 50000 ip from table(3) to any in\n"; + $rulenum++; + $cprules .= "add {$rulenum} set 2 skipto 50000 ip from any to table(4) out\n"; + $rulenum++; + } + + $cprules .= <<<EOD # redirect non-authenticated clients to captive portal -add 19902 set 1 fwd 127.0.0.1,8000 tcp from any to any 80 in +add 1990 set 1 fwd 127.0.0.1,8000 tcp from any to any 80 in # let the responses from the captive portal web server back out -add 19903 set 1 pass tcp from any 80 to any out +add 1991 set 1 pass tcp from any 80 to any out # block everything else -add 19904 set 1 deny all from any to any +add 1992 set 1 deny all from any to any -# ... 20000-29899: layer2 block rules per authenticated client go here... +# ... 2000-49899: layer2 block rules per authenticated client go here... # pass everything else on layer2 -add 29900 set 1 pass all from any to any layer2 +add 49900 set 1 pass all from any to any layer2 EOD; @@ -473,7 +483,7 @@ function captiveportal_prune_old() { $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]); + $lastact = captiveportal_get_last_activity($cpdb[$i][2]); /* if the user has logged on but not sent any trafic they will never be logged out. * We "fix" this by setting lastact to the login timestamp */ @@ -524,7 +534,8 @@ function captiveportal_prune_old() { $cpdb[$i][2], // clientip $cpdb[$i][3], // clientmac 10); // NAS Request - exec("/sbin/ipfw zero {$cpdb[$i][1]}"); + exec("/sbin/ipfw table 3 entryzerostats {$cpdb[$i][2]}"); + exec("/sbin/ipfw table 4 entryzerostats {$cpdb[$i][2]}"); RADIUS_ACCOUNTING_START($cpdb[$i][1], // ruleno $cpdb[$i][4], // username $cpdb[$i][5], // sessionid @@ -596,18 +607,20 @@ function captiveportal_disconnect($dbent, $radiusservers,$term_cause = 1,$stop_t $stop_time); } - mwexec("/sbin/ipfw delete " . $dbent[1] . " " . ($dbent[1]+10000)); - - /* We need to delete +40500 and +45500 as well... - * these are the pipe numbers we use to control traffic shaping for each logged in user via captive portal - * We could get an error if the pipe doesn't exist but everything should still be fine - */ - if (isset($config['captiveportal']['peruserbw'])) { - mwexec("/sbin/ipfw pipe " . ($dbent[1]+40500) . " delete"); - mwexec("/sbin/ipfw pipe " . ($dbent[1]+45500) . " delete"); - } + mwexec("/sbin/ipfw table 4 delete {$dbent[2]}"); + mwexec("/sbin/ipfw table 4 delete {$dbent[2]}"); + mwexec("/sbin/ipfw delete {$dbent[1]}"); + + /* + * These are the pipe numbers we use to control traffic shaping for each logged in user via captive portal + * We could get an error if the pipe doesn't exist but everything should still be fine + */ + if (isset($config['captiveportal']['peruserbw'])) { + mwexec("/sbin/ipfw pipe " . ($dbent[1]+20000) . " delete"); + mwexec("/sbin/ipfw pipe " . ($dbent[1]+20001) . " delete"); + } - /* pfSense: ensure all pf states are killed (pfSense) */ + /* Ensure all pf(4) states are killed. */ mwexec("pfctl -k {$dbent[2]}"); mwexec("pfctl -K {$dbent[2]}"); @@ -713,8 +726,8 @@ function captiveportal_passthrumac_configure($lock = false) { 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 29900 ip from any to any MAC {$ptm['mac']} any keep-state"); - mwexec("/sbin/ipfw add 50 skipto 29900 ip from any to any MAC any {$ptm['mac']} keep-state"); + 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"); } } @@ -730,34 +743,8 @@ function captiveportal_allowedip_configure() { /* clear out existing allowed ips, if necessary */ mwexec("/sbin/ipfw table 1 flush"); mwexec("/sbin/ipfw table 2 flush"); - if (file_exists("{$g['vardb_path']}/captiveportal_ip.db")) { - $ruleno = intval(file_get_contents("{$g['vardb_path']}/captiveportal_ip.db")); - mwexec("/sbin/ipfw delete {$ruleno}"); - } 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"); - unlock($captiveportallck); - return 1; - } - /* get next ipfw rule number */ - $ruleno = captiveportal_get_next_ipfw_ruleno(); - - /* if the pool is empty, return apprioriate message and fail */ - if (is_null($ruleno)) { - printf("Error: system reached maximum login capacity, no free FW rulenos in captiveportal_allowedip_configure().\n"); - fclose($fd); - unlock($captiveportallck); - return 1; - } - /* Keep the rule number where this will be stored */ - fwrite($fd, $ruleno); - fclose($fd); - - $numberofallowedip = count($config['captiveportal']['allowedip']); $tableone = false; $tabletwo = false; foreach ($config['captiveportal']['allowedip'] as $ipent) { @@ -771,12 +758,12 @@ function captiveportal_allowedip_configure() { } } if ($tableone == true) { - mwexec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from table\(1\) to any in"); - mwexec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from any to table\(1\) out"); + mwexec("/sbin/ipfw add 1890 set 2 skipto 50000 ip from table\(1\) to any in"); + mwexec("/sbin/ipfw add 1891 set 2 skipto 50000 ip from any to table\(1\) out"); } if ($tabletwo == true) { - mwexec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from any to table\(2\) in"); - mwexec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from table\(2\) to any out"); + mwexec("/sbin/ipfw add 1892 set 2 skipto 50000 ip from any to table\(2\) in"); + mwexec("/sbin/ipfw add 1893 set 2 skipto 50000 ip from table\(2\) to any out"); } } @@ -784,17 +771,16 @@ function captiveportal_allowedip_configure() { } /* get last activity timestamp given ipfw rule number */ -function captiveportal_get_last_activity($ruleno) { +function captiveportal_get_last_activity($ip) { $ipfwoutput = ""; - exec("/sbin/ipfw -T list {$ruleno} 2>/dev/null", $ipfwoutput); - - /* in */ + exec("/sbin/ipfw table 3 entrystats {$ip} 2>/dev/null", $ipfwoutput); + /* Reading only from one of the tables is enough of approximation. */ if ($ipfwoutput[0]) { $ri = explode(" ", $ipfwoutput[0]); - if ($ri[1]) - return $ri[1]; + if ($ri[4]) + return $ri[4]; } return 0; @@ -969,28 +955,31 @@ function captiveportal_write_elements() { /* * This function will calculate the lowest free firewall ruleno - * within the range specified based on the actual installed rules + * within the range specified based on the actual logged on users * */ -function captiveportal_get_next_ipfw_ruleno($rulenos_start = 10000, $rulenos_range_max = 9899) { - - $fwrules = ""; - $matches = ""; - exec("/sbin/ipfw show", $fwrules); - foreach ($fwrules as $fwrule) { - preg_match("/^(\d+)\s+/", $fwrule, $matches); - $rulenos_used[] = $matches[1]; - } - $rulenos_used = array_unique($rulenos_used); - $rulenos_range = count($rulenos_used); - if ($rulenos_range > $rulenos_range_max) { - return NULL; - } - $rulenos_pool = range($rulenos_start, ($rulenos_start + $rulenos_range)); - $rulenos_free = array_diff($rulenos_pool, $rulenos_used); - $ruleno = array_shift($rulenos_free); +function captiveportal_get_next_ipfw_ruleno($rulenos_start = 2000, $rulenos_range_max = 29899) { + global $config, $g; - return $ruleno; + $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 (isset($config['captiveportal']['peruserbw'])) + $ruleno += 2; + else + $ruleno++; + file_put_contents("{$g['vardb_path']}/captiveportal.nextrule", $ruleno); + return $rulenos_start + $ruleno; + } + return NULL; } /** @@ -1004,7 +993,7 @@ function captiveportal_get_next_ipfw_ruleno($rulenos_start = 10000, $rulenos_ran * */ -function getVolume($ruleno) { +function getVolume($ip) { $volume = array(); @@ -1012,20 +1001,23 @@ function getVolume($ruleno) { $volume['input_pkts'] = $volume['input_bytes'] = $volume['output_pkts'] = $volume['output_bytes'] = 0 ; // Ingress - $ipfw = ""; - $matches = ""; - exec("/sbin/ipfw show {$ruleno}", $ipfw); - preg_match("/(\d+)\s+(\d+)\s+(\d+)\s+.*/", $ipfw[0], $matches); - $volume['input_pkts'] = $matches[2]; - $volume['input_bytes'] = $matches[3]; - - // Flush internal buffer - unset($matches); - - // Outgress - preg_match("/(\d+)\s+(\d+)\s+(\d+)\s+.*/", $ipfw[1], $matches); - $volume['output_pkts'] = $matches[2]; - $volume['output_bytes'] = $matches[3]; + $ipfwin = ""; + $ipfwout = ""; + $matchesin = ""; + $matchesout = ""; + exec("/sbin/ipfw table 3 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); + if ($ipfwout[0]) { + $ipfwout = split(" ", $ipfwout[0]); + $volume['output_pkts'] = $ipfwout[2]; + $volume['output_bytes'] = $ipfwout[3]; + } return $volume; } diff --git a/usr/local/captiveportal/index.php b/usr/local/captiveportal/index.php index 408e7f5..a1b2771 100755 --- a/usr/local/captiveportal/index.php +++ b/usr/local/captiveportal/index.php @@ -317,25 +317,24 @@ function portal_allow($clientip,$clientmac,$username,$password = null, $attribut $bw_down = isset($attributes['bw_down']) ? trim($attributes['bw_down']) : $config['captiveportal']['bwdefaultdn']; if ($peruserbw && !empty($bw_up) && is_numeric($bw_up)) { - $bw_up_pipeno = $ruleno + 40500; - exec("/sbin/ipfw add $ruleno set 2 pipe $bw_up_pipeno ip from $clientip to any in"); - exec("/sbin/ipfw pipe $bw_up_pipeno config bw {$bw_up}Kbit/s queue 100"); + $bw_up_pipeno = $ruleno + 20000; + mwexec("/sbin/ipfw pipe $bw_up_pipeno config bw {$bw_up}Kbit/s queue 100"); + mwexec("/sbin/ipfw table 3 add {$clientip} {$bw_up_pipeno}"); } else { - exec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from $clientip to any in"); + mwexec("/sbin/ipfw table 3 add {$clientip}"); } if ($peruserbw && !empty($bw_down) && is_numeric($bw_down)) { - $bw_down_pipeno = $ruleno + 45500; - exec("/sbin/ipfw add $ruleno set 2 pipe $bw_down_pipeno ip from any to $clientip out"); - exec("/sbin/ipfw pipe $bw_down_pipeno config bw {$bw_down}Kbit/s queue 100"); + $bw_down_pipeno = $ruleno + 20001; + mwexec("/sbin/ipfw pipe $bw_down_pipeno config bw {$bw_down}Kbit/s queue 100"); + mwexec("/sbin/ipfw table 4 add {$clientip} {$bw_down_pipeno}"); } else { - exec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from any to $clientip out"); + mwexec("/sbin/ipfw table 4 add {$clientip}"); } /* add ipfw rules for layer 2 */ if (!isset($config['captiveportal']['nomacfilter'])) { - $l2ruleno = $ruleno + 10000; - exec("/sbin/ipfw add $l2ruleno set 3 deny all from $clientip to any not MAC any $clientmac layer2 in"); - exec("/sbin/ipfw add $l2ruleno set 3 deny all from any to $clientip not MAC $clientmac any layer2 out"); + exec("/sbin/ipfw add $ruleno set 3 deny all from $clientip to any not MAC any $clientmac layer2 in"); + exec("/sbin/ipfw add $ruleno set 3 deny all from any to $clientip not MAC $clientmac any layer2 out"); } if ($attributes['voucher']) diff --git a/usr/local/captiveportal/radius_accounting.inc b/usr/local/captiveportal/radius_accounting.inc index fb8ece3..bfd0247 100644 --- a/usr/local/captiveportal/radius_accounting.inc +++ b/usr/local/captiveportal/radius_accounting.inc @@ -157,7 +157,7 @@ function RADIUS_ACCOUNTING_STOP($ruleno,$username,$sessionid,$start_time,$radius $radiusvendor = $config['captiveportal']['radiusvendor'] ? $config['captiveportal']['radiusvendor'] : null; $stop_time = (empty($stop_time)) ? time() : $stop_time; $session_time = $stop_time - $start_time; - $volume = getVolume($ruleno); + $volume = getVolume($clientip); $volume['input_bytes_radius'] = remainder($volume['input_bytes']); $volume['input_gigawords'] = gigawords($volume['input_bytes']); $volume['output_bytes_radius'] = remainder($volume['output_bytes']); @@ -306,4 +306,4 @@ function remainder($bytes) { } -?>
\ No newline at end of file +?> diff --git a/usr/local/www/status_captiveportal.php b/usr/local/www/status_captiveportal.php index 9e17d4b..f29e749 100755 --- a/usr/local/www/status_captiveportal.php +++ b/usr/local/www/status_captiveportal.php @@ -71,7 +71,7 @@ $concurrent = count($cpcontents); foreach ($cpcontents as $cpcontent) { $cpent = explode(",", $cpcontent); if ($_GET['showact']) - $cpent[5] = captiveportal_get_last_activity($cpent[1]); + $cpent[5] = captiveportal_get_last_activity($cpent[2]); $cpdb[] = $cpent; } if ($_GET['order']) { diff --git a/usr/local/www/widgets/widgets/captive_portal_status.widget.php b/usr/local/www/widgets/widgets/captive_portal_status.widget.php index 0d7468f..1b74d26 100644 --- a/usr/local/www/widgets/widgets/captive_portal_status.widget.php +++ b/usr/local/www/widgets/widgets/captive_portal_status.widget.php @@ -65,7 +65,7 @@ if ($fp) { foreach ($cpcontents as $cpcontent) { $cpent = explode(",", $cpcontent); if ($_GET['showact']) - $cpent[5] = captiveportal_get_last_activity($cpent[1]); + $cpent[5] = captiveportal_get_last_activity($cpent[2]); $cpdb[] = $cpent; } |