- Cleanup and code added to allow FUTURE stuff like volume limits etc. to be implemented
- Added User Volume Stats in captive portal status page
- RADIUS mac authentication now works on local subnet even if "Disable MAC filtering" is activated
- - Firewall ruleno should now wrap more cleanly when having lots of sessions, REBOOT after you change CP Allowed-ip-addresses
- - fixed bug in RADIUS Session-Timeout handling so it'll also work even if reauthentication is disabled
+ - Firewall ruleno now uses a more intelligent pool, this fixes a bug where a ruleno could be used even if it is already been assigned
+ - Fixed bug in RADIUS Session-Timeout handling so it'll also work even if reauthentication is disabled
- added "disable port mapping" option to advanced outbound NAT (helps with certain IPsec
VPN gateways that insist on the IKE source port being 500) (mkasper)
if (!$clientmac && $macfilter) {
/* unable to find MAC address - shouldn't happen! - bail out */
captiveportal_logportalauth("unauthenticated","noclientmac",$clientip,"ERROR");
- /* We should return an error page to the client explaining what went wrong instead of exiting */
exit;
}
$moddb = true;
}
}
- if ($moddb)
+ if ($moddb)portal_reply_page($redirurl, "error", $auth_list['error']);
write_config();
$userdb = &$config['captiveportal']['user'];
return FALSE;
}
-function portal_allow($clientip,$clientmac,$clientuser,$password = null, $attributes = null) {
+function portal_allow($clientip,$clientmac,$clientuser,$password = null, $attributes = null, $ruleno = null) {
global $redirurl, $g, $config;
kick_concurrent_logins($clientuser);
captiveportal_lock();
-
- $ruleno = get_next_ipfw_ruleno();
+
+ /* if no ruleno is passed to this function we will look one up in the pool */
+ $ruleno = (!is_null($ruleno)) ? $ruleno : captiveportal_get_next_ipfw_ruleno();
+
+ /* if the pool is empty, return appropriate message and exit */
+ if (is_null($ruleno)) {
+ portal_reply_page($redirurl, "error", "System reached maximum login capacity");
+ captiveportal_unlock();
+ exit;
+ }
/* generate unique session ID */
$tod = gettimeofday();
$sessionid = substr(md5(mt_rand() . $tod['sec'] . $tod['usec'] . $clientip . $clientmac), 0, 16);
-
+
/* add ipfw rules for layer 3 */
exec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from $clientip to any in");
exec("/sbin/ipfw add $ruleno set 2 skipto 50000 ip from any to $clientip out");
-
+
/* 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");
}
-
+
/* read in client database */
$cpdb = captiveportal_read_db();
-
+
$radiusservers = captiveportal_get_radius_servers();
/* find an existing entry and delete it */
unset($cpdb[$i]);
break;
}
- }
+ }
/* encode password in Base64 just in case it contains commas */
$bpassword = base64_encode($password);
/* rewrite information to database */
captiveportal_write_db($cpdb);
- /* Builtin wrap safety for allowedip */
- $allowedipno = (is_array($config['captiveportal']['allowedip'])) ? count($config['captiveportal']['allowedip']) : 0;
-
- /* write next rule number */
- $fd = @fopen("{$g['vardb_path']}/captiveportal.nextrule", "w");
- if ($fd) {
- $ruleno++;
- if ($ruleno > 19899)
- $ruleno = 10000 + $allowedipno; /* wrap around */
- fwrite($fd, $ruleno);
- fclose($fd);
- }
-
captiveportal_unlock();
-
+
/* redirect user to desired destination */
if ($url_redirection)
$my_redirurl = $url_redirection;
$my_redirurl = $config['captiveportal']['redirurl'];
else
$my_redirurl = $redirurl;
-
+
if(isset($config['captiveportal']['logoutwin_enable'])) {
-
+
if (isset($config['captiveportal']['httpslogin']))
$logouturl = "https://{$config['captiveportal']['httpsname']}:8001/";
else
$logouturl = "http://{$config['interfaces'][$config['captiveportal']['interface']]['ipaddr']}:8000/";
-
+
echo <<<EOD
<HTML>
<HEAD><TITLE>Redirecting...</TITLE></HEAD>
captiveportal_unlock();
}
-function get_next_ipfw_ruleno() {
-
- global $g;
-
- /* 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 */
-
- return $ruleno;
-}
?>
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");
function captiveportal_allowedip_configure() {
global $config, $g;
-
+
captiveportal_lock();
/* clear out existing allowed ips, if necessary */
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;
+ return 1;
}
-
+
foreach ($config['captiveportal']['allowedip'] as $ipent) {
-
+
+ /* 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);
+ captiveportal_unlock();
+ return 1;
+ }
+
/* 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'] . " 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);
}
+
+ 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;
}
function radius($username,$password,$clientip,$clientmac,$type) {
global $g, $config;
- $next_ruleno = get_next_ipfw_ruleno();
+ $ruleno = captiveportal_get_next_ipfw_ruleno();
+
+ /* if the pool is empty, return apprioriate message and fail authentication */
+ if (is_null($ruleno)) {
+ $auth_list = array();
+ $auth_list['auth_val'] = 1;
+ $auth_list['error'] = "System reached maximum login capacity";
+ return $auth_list;
+ }
+
$radiusservers = captiveportal_get_radius_servers();
$radacct_enable = isset($config['captiveportal']['radacct_enable']);
$clientmac,
$username,
$password,
- $auth_list);
+ $auth_list,
+ $ruleno);
if ($radacct_enable) {
- $auth_list['acct_val'] = RADIUS_ACCOUNTING_START($next_ruleno,
+ $auth_list['acct_val'] = RADIUS_ACCOUNTING_START($ruleno,
$username,
$sessionid,
$radiusservers[0]['ipaddr'],
return 0;
}
+/**
+ * This function will calculate the lowest free firewall ruleno
+ * within the range specified based on the actual installed rules
+ *
+ */
+
+function captiveportal_get_next_ipfw_ruleno() {
+
+ exec("/sbin/ipfw show", $fwrules);
+ foreach ($fwrules as $fwrule) {
+ preg_match("/^(\d+)\s+/", $fwrule, $matches);
+ $rulenos_used[] = $matches[1];
+ }
+ $rulenos_pool = range(10000, 19899);
+ $rulenos_used = array_unique($rulenos_used);
+ $rulenos_free = array_diff($rulenos_pool, $rulenos_used);
+ $ruleno = array_shift($rulenos_free);
+
+ return $ruleno;
+}
+
+
/**
* This function will calculate the traffic produced by a client
* based on its firewall rule