From 643315be4aff3a518694fc0da930f9512569c00c Mon Sep 17 00:00:00 2001 From: plumbeo Date: Fri, 2 Mar 2018 11:59:12 +0100 Subject: [PATCH 1/6] Captive portal: always use the RADIUS-provided session timeout value if the option is enabled --- src/etc/inc/captiveportal.inc | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/etc/inc/captiveportal.inc b/src/etc/inc/captiveportal.inc index 78a3179f2e..5cf6eb87a5 100644 --- a/src/etc/inc/captiveportal.inc +++ b/src/etc/inc/captiveportal.inc @@ -784,7 +784,10 @@ function captiveportal_prune_old() { } $radiusservers = $radiussrvs[$cpentry[11]]; - /* hard timeout? */ + /* hard timeout or session_timeout from radius if enabled */ + if (isset($cpcfg['radiussession_timeout'])) { + $timeout = (is_numeric($cpentry[7])) ? $cpentry[7] : $timeout; + } if ($timeout) { if (($pruning_time - $cpentry[0]) >= $timeout) { $timedout = true; @@ -827,14 +830,6 @@ function captiveportal_prune_old() { } } - /* 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($cpcfg['radiussession_timeout']) && !empty($cpentry[7])) { - if ($pruning_time >= ($cpentry[0] + $cpentry[7])) { - $timedout = true; - $term_cause = 5; // Session-Timeout - } - } - if ($timedout) { captiveportal_disconnect($cpentry, $radiusservers, $term_cause, $stop_time); captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "TIMEOUT"); From acbd943da1579985dcd9fef05030bc486189c776 Mon Sep 17 00:00:00 2001 From: plumbeo Date: Fri, 2 Mar 2018 11:59:43 +0100 Subject: [PATCH 2/6] Captive portal: add a traffic quota option Add a new option to disconnect users after they exceed a traffic quota (sum of downloaded data and uploaded data). --- src/etc/inc/captiveportal.inc | 17 ++++++++++++++++- src/usr/local/www/services_captiveportal.php | 15 +++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/etc/inc/captiveportal.inc b/src/etc/inc/captiveportal.inc index 5cf6eb87a5..b464c0a6d3 100644 --- a/src/etc/inc/captiveportal.inc +++ b/src/etc/inc/captiveportal.inc @@ -755,8 +755,14 @@ function captiveportal_prune_old() { $idletimeout = $cpcfg['idletimeout'] * 60; } + /* check for entries exceeding their traffic quota */ + $trafficquota = 0; + if (!empty($cpcfg['trafficquota']) && is_numeric($cpcfg['trafficquota'])) { + $trafficquota = $cpcfg['trafficquota'] * 1048576; + } + /* Is there any job to do? */ - if (!$timeout && !$idletimeout && !isset($cpcfg['reauthenticate']) && + if (!$timeout && !$idletimeout && !$trafficquota && !isset($cpcfg['reauthenticate']) && !isset($cpcfg['radiussession_timeout']) && !isset($vcpcfg['enable'])) { return; } @@ -830,6 +836,15 @@ function captiveportal_prune_old() { } } + /* traffic quota */ + if (!$timedout && $trafficquota > 0) { + $volume = getVolume($cpentry[2], $cpentry[3]); + if (($volume['input_bytes'] + $volume['output_bytes']) > $trafficquota) { + $timedout = true; + $term_cause = 10; // NAS-Request + } + } + if ($timedout) { captiveportal_disconnect($cpentry, $radiusservers, $term_cause, $stop_time); captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "TIMEOUT"); diff --git a/src/usr/local/www/services_captiveportal.php b/src/usr/local/www/services_captiveportal.php index 237c8b4df9..93a7e33c93 100644 --- a/src/usr/local/www/services_captiveportal.php +++ b/src/usr/local/www/services_captiveportal.php @@ -145,6 +145,7 @@ if ($a_cp[$cpzone]) { $pconfig['maxprocperip'] = $a_cp[$cpzone]['maxprocperip']; $pconfig['timeout'] = $a_cp[$cpzone]['timeout']; $pconfig['idletimeout'] = $a_cp[$cpzone]['idletimeout']; + $pconfig['trafficquota'] = $a_cp[$cpzone]['trafficquota']; $pconfig['freelogins_count'] = $a_cp[$cpzone]['freelogins_count']; $pconfig['freelogins_resettimeout'] = $a_cp[$cpzone]['freelogins_resettimeout']; $pconfig['freelogins_updatetimeouts'] = isset($a_cp[$cpzone]['freelogins_updatetimeouts']); @@ -281,6 +282,10 @@ if ($_POST['save']) { $input_errors[] = gettext("The idle timeout must be at least 1 minute."); } + if ($_POST['trafficquota'] && (!is_numeric($_POST['trafficquota']) || ($_POST['trafficquota'] < 1))) { + $input_errors[] = gettext("The traffic quota must be at least 1 megabyte."); + } + if ($_POST['freelogins_count'] && (!is_numeric($_POST['freelogins_count']))) { $input_errors[] = gettext("The pass-through credit count must be a number or left blank."); } else if ($_POST['freelogins_count'] && is_numeric($_POST['freelogins_count']) && ($_POST['freelogins_count'] >= 1)) { @@ -353,6 +358,7 @@ if ($_POST['save']) { $newcp['maxprocperip'] = $_POST['maxprocperip'] ? $_POST['maxprocperip'] : false; $newcp['timeout'] = $_POST['timeout']; $newcp['idletimeout'] = $_POST['idletimeout']; + $newcp['trafficquota'] = $_POST['trafficquota']; $newcp['freelogins_count'] = $_POST['freelogins_count']; $newcp['freelogins_resettimeout'] = $_POST['freelogins_resettimeout']; $newcp['freelogins_updatetimeouts'] = $_POST['freelogins_updatetimeouts'] ? true : false; @@ -569,6 +575,14 @@ $section->addInput(new Form_Input( ))->setHelp('Clients will be disconnected after this amount of time, regardless of activity. They may log in again immediately, though. ' . 'Leave this field blank for no hard timeout (not recommended unless an idle timeout is set).'); +$section->addInput(new Form_Input( + 'trafficquota', + 'Traffic quota (Megabytes)', + 'number', + $pconfig['trafficquota'] +))->setHelp('Clients will be disconnected after exceeding this amount of traffic, inclusive of both downloads and uploads. They may log in again immediately, though. ' . + 'Leave this field blank for no traffic quota.'); + $section->addInput(new Form_Input( 'freelogins_count', 'Pass-through credits per MAC address.', @@ -1234,6 +1248,7 @@ events.push(function() { hideInput('maxprocperip', hide); hideInput('idletimeout', hide); hideInput('timeout', hide); + hideInput('trafficquota', hide); hideInput('freelogins_count', hide); hideInput('freelogins_resettimeout', hide); hideCheckbox('freelogins_updatetimeouts', hide); From f3e403d5e65d0158c6ddab2e548aa5fb4e5cdd1a Mon Sep 17 00:00:00 2001 From: plumbeo Date: Fri, 2 Mar 2018 12:00:18 +0100 Subject: [PATCH 3/6] Captive portal: add option to retrieve the traffic quota value from RADIUS Add an option to enable retrieving a user's traffic quota from RADIUS. The code uses a new vendor-specific attribute so the RADIUS server must be configured appropriately and load the pfSense dictionary. --- src/etc/inc/captiveportal.inc | 46 +++++++++++--------- src/etc/inc/radius.inc | 15 +++++++ src/usr/local/www/services_captiveportal.php | 9 ++++ 3 files changed, 50 insertions(+), 20 deletions(-) diff --git a/src/etc/inc/captiveportal.inc b/src/etc/inc/captiveportal.inc index b464c0a6d3..c36ea2acc1 100644 --- a/src/etc/inc/captiveportal.inc +++ b/src/etc/inc/captiveportal.inc @@ -731,7 +731,7 @@ function captiveportal_delete_rules($pipes_to_remove = array()) { /* * Remove clients that have been around for longer than the specified amount of time * db file structure: - * timestamp,ipfw_rule_no,clientip,clientmac,username,sessionid,password,session_timeout,idle_timeout,session_terminate_time,interim_interval + * timestamp,ipfw_rule_no,clientip,clientmac,username,sessionid,password,session_timeout,idle_timeout,session_terminate_time,interim_interval,traffic_quota,radiusctx * (password is in Base64 and only saved when reauthentication is enabled) */ function captiveportal_prune_old() { @@ -763,7 +763,8 @@ function captiveportal_prune_old() { /* Is there any job to do? */ if (!$timeout && !$idletimeout && !$trafficquota && !isset($cpcfg['reauthenticate']) && - !isset($cpcfg['radiussession_timeout']) && !isset($vcpcfg['enable'])) { + !isset($cpcfg['radiussession_timeout']) && !isset($cpcfg['radiustraffic_quota']) && + !isset($vcpcfg['enable'])) { return; } @@ -785,10 +786,10 @@ function captiveportal_prune_old() { $timedout = false; $term_cause = 1; - if (empty($cpentry[11])) { - $cpentry[11] = 'first'; + if (empty($cpentry[12])) { + $cpentry[12] = 'first'; } - $radiusservers = $radiussrvs[$cpentry[11]]; + $radiusservers = $radiussrvs[$cpentry[12]]; /* hard timeout or session_timeout from radius if enabled */ if (isset($cpcfg['radiussession_timeout'])) { @@ -836,7 +837,10 @@ function captiveportal_prune_old() { } } - /* traffic quota */ + /* traffic quota, value retrieved from the radius attribute if the option is enabled */ + if (isset($cpcfg['radiustraffic_quota'])) { + $trafficquota = (is_numeric($cpentry[11])) ? $cpentry[11] : $trafficquota; + } if (!$timedout && $trafficquota > 0) { $volume = getVolume($cpentry[2], $cpentry[3]); if (($volume['input_bytes'] + $volume['output_bytes']) > $trafficquota) { @@ -1108,10 +1112,10 @@ function captiveportal_disconnect_client($sessionid, $term_cause = 1, $logoutRea captiveportal_write_db("DELETE FROM captiveportal WHERE sessionid = '{$sessionid}'"); foreach ($result as $cpentry) { - if (empty($cpentry[11])) { - $cpentry[11] = 'first'; + if (empty($cpentry[12])) { + $cpentry[12] = 'first'; } - captiveportal_disconnect($cpentry, $radiusservers[$cpentry[11]], $term_cause); + captiveportal_disconnect($cpentry, $radiusservers[$cpentry[12]], $term_cause); captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "DISCONNECT"); } unset($result); @@ -1165,15 +1169,15 @@ function captiveportal_radius_stop_all($term_cause = 6, $logoutReason = "DISCONN foreach ($cpdb as $cpentry) { if ($radacct) { if (!empty($radiusservers)) { - if (empty($cpentry[11])) { - $cpentry[11] = 'first'; + if (empty($cpentry[12])) { + $cpentry[12] = 'first'; } - if (!empty($radiusservers[$cpentry[11]])) { + if (!empty($radiusservers[$cpentry[12]])) { RADIUS_ACCOUNTING_STOP($cpentry[1], // ruleno $cpentry[4], // username $cpentry[5], // sessionid $cpentry[0], // start time - $radiusservers[$cpentry[11]], + $radiusservers[$cpentry[12]], $cpentry[2], // clientip $cpentry[3], // clientmac $term_cause); @@ -1623,7 +1627,8 @@ function captiveportal_opendb() { $createquery = "CREATE TABLE IF NOT EXISTS captiveportal (" . "allow_time INTEGER, pipeno INTEGER, ip TEXT, mac TEXT, username TEXT, " . "sessionid TEXT, bpassword TEXT, session_timeout INTEGER, idle_timeout INTEGER, " . - "session_terminate_time INTEGER, interim_interval INTEGER, radiusctx TEXT); " . + "session_terminate_time INTEGER, interim_interval INTEGER, traffic_quota INTEGER, " . + "radiusctx TEXT); " . "CREATE UNIQUE INDEX IF NOT EXISTS idx_active ON captiveportal (sessionid, username); " . "CREATE INDEX IF NOT EXISTS user ON captiveportal (username); " . "CREATE INDEX IF NOT EXISTS ip ON captiveportal (ip); " . @@ -2246,8 +2251,8 @@ function portal_allow($clientip, $clientmac, $username, $password = null, $attri } foreach ($cpdb as $cpentry) { - if (empty($cpentry[11])) { - $cpentry[11] = 'first'; + if (empty($cpentry[12])) { + $cpentry[12] = 'first'; } /* on the same ip */ if ($cpentry[2] == $clientip) { @@ -2267,7 +2272,7 @@ function portal_allow($clientip, $clientmac, $username, $password = null, $attri } /* This user was already logged in so we disconnect the old one */ - captiveportal_disconnect($cpentry, $radiusservers[$cpentry[11]], 13); + captiveportal_disconnect($cpentry, $radiusservers[$cpentry[12]], 13); captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "CONCURRENT LOGIN - TERMINATING OLD SESSION"); $unsetindexes[] = $cpentry[5]; break; @@ -2275,7 +2280,7 @@ function portal_allow($clientip, $clientmac, $username, $password = null, $attri /* on the same username */ if (strcasecmp($cpentry[4], $username) == 0) { /* This user was already logged in so we disconnect the old one */ - captiveportal_disconnect($cpentry, $radiusservers[$cpentry[11]], 13); + captiveportal_disconnect($cpentry, $radiusservers[$cpentry[12]], 13); captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "CONCURRENT LOGIN - TERMINATING OLD SESSION"); $unsetindexes[] = $cpentry[5]; break; @@ -2384,15 +2389,16 @@ function portal_allow($clientip, $clientmac, $username, $password = null, $attri $idle_timeout = (!empty($attributes['idle_timeout'])) ? $attributes['idle_timeout'] : 'NULL'; $session_terminate_time = (!empty($attributes['session_terminate_time'])) ? $attributes['session_terminate_time'] : 'NULL'; $interim_interval = (!empty($attributes['interim_interval'])) ? $attributes['interim_interval'] : 'NULL'; + $traffic_quota = (!empty($attributes['maxbytes'])) ? $attributes['maxbytes'] : 'NULL'; /* escape username */ $safe_username = SQLite3::escapeString($username); /* encode password in Base64 just in case it contains commas */ $bpassword = (isset($config['captiveportal'][$cpzone]['reauthenticate'])) ? base64_encode($password) : ''; - $insertquery = "INSERT INTO captiveportal (allow_time, pipeno, ip, mac, username, sessionid, bpassword, session_timeout, idle_timeout, session_terminate_time, interim_interval, radiusctx) "; + $insertquery = "INSERT INTO captiveportal (allow_time, pipeno, ip, mac, username, sessionid, bpassword, session_timeout, idle_timeout, session_terminate_time, interim_interval, traffic_quota, radiusctx) "; $insertquery .= "VALUES ({$allow_time}, {$pipeno}, '{$clientip}', '{$clientmac}', '{$safe_username}', '{$sessionid}', '{$bpassword}', "; - $insertquery .= "{$session_timeout}, {$idle_timeout}, {$session_terminate_time}, {$interim_interval}, '{$radiusctx}')"; + $insertquery .= "{$session_timeout}, {$idle_timeout}, {$session_terminate_time}, {$interim_interval}, {$traffic_quota}, '{$radiusctx}')"; /* store information to database */ captiveportal_write_db($insertquery); diff --git a/src/etc/inc/radius.inc b/src/etc/inc/radius.inc index d9d152151e..50014dad4d 100644 --- a/src/etc/inc/radius.inc +++ b/src/etc/inc/radius.inc @@ -44,6 +44,7 @@ * Adding of VENDOR Nomadix * Adding of VENDOR WISPr (Wi-Fi Alliance) * Adding of VENDOR ChilliSpot (bandwidth-attributes only) + * Adding of VENDOR pfSense (Netgate) */ @@ -696,6 +697,20 @@ class Auth_RADIUS extends PEAR { } } + elseif ($vendor == 13644) { /* Netgate */ + switch ($attrv) { + case 1: /* pfSense-Bandwidth-Max-Up */ + $this->attributes['bw_up'] = radius_cvt_int($datav); + break; + case 2: /* pfSense-Bandwidth-Max-Down */ + $this->attributes['bw_down'] = radius_cvt_int($datav); + break; + case 3: /* pfSense-Max-Total-Octets */ + $this->attributes['maxbytes'] = radius_cvt_int($datav); + break; + } + } + break; case 85: /* Acct-Interim-Interval: RFC 2869 */ diff --git a/src/usr/local/www/services_captiveportal.php b/src/usr/local/www/services_captiveportal.php index 93a7e33c93..14898e0eaa 100644 --- a/src/usr/local/www/services_captiveportal.php +++ b/src/usr/local/www/services_captiveportal.php @@ -186,6 +186,7 @@ if ($a_cp[$cpzone]) { $pconfig['radiuskey4'] = $a_cp[$cpzone]['radiuskey4']; $pconfig['radiusvendor'] = $a_cp[$cpzone]['radiusvendor']; $pconfig['radiussession_timeout'] = isset($a_cp[$cpzone]['radiussession_timeout']); + $pconfig['radiustraffic_quota'] = isset($a_cp[$cpzone]['radiustraffic_quota']); $pconfig['radiussrcip_attribute'] = $a_cp[$cpzone]['radiussrcip_attribute']; $pconfig['passthrumacadd'] = isset($a_cp[$cpzone]['passthrumacadd']); $pconfig['passthrumacaddusername'] = isset($a_cp[$cpzone]['passthrumacaddusername']); @@ -435,6 +436,7 @@ if ($_POST['save']) { $newcp['radiuskey4'] = $_POST['radiuskey4']; $newcp['radiusvendor'] = $_POST['radiusvendor'] ? $_POST['radiusvendor'] : false; $newcp['radiussession_timeout'] = $_POST['radiussession_timeout'] ? true : false; + $newcp['radiustraffic_quota'] = $_POST['radiustraffic_quota'] ? true : false; $newcp['radiussrcip_attribute'] = $_POST['radiussrcip_attribute']; $newcp['passthrumacadd'] = $_POST['passthrumacadd'] ? true : false; $newcp['passthrumacaddusername'] = $_POST['passthrumacaddusername'] ? true : false; @@ -977,6 +979,13 @@ $section->addInput(new Form_Checkbox( $pconfig['radiussession_timeout'] ))->setHelp('When enabled, clients will be disconnected after the amount of time retrieved from the RADIUS Session-Timeout attribute.'); +$section->addInput(new Form_Checkbox( + 'radiustraffic_quota', + 'Traffic quota', + 'Use RADIUS pfSense-Max-Total-Octets attribute', + $pconfig['radiustraffic_quota'] +))->setHelp('When enabled, clients will be disconnected after exceeding the amount of traffic, inclusive of both downloads and uploads, retrieved from the RADIUS pfSense-Max-Total-Octets attribute.'); + $section->addInput(new Form_Select( 'radiusvendor', 'Type', From e4c34f173192babdd2fa343d226c248d3ada0260 Mon Sep 17 00:00:00 2001 From: plumbeo Date: Fri, 2 Mar 2018 12:02:10 +0100 Subject: [PATCH 4/6] Captive portal: add the explicit reason why a user was disconnected to the log --- src/etc/inc/captiveportal.inc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/etc/inc/captiveportal.inc b/src/etc/inc/captiveportal.inc index c36ea2acc1..3939be94a3 100644 --- a/src/etc/inc/captiveportal.inc +++ b/src/etc/inc/captiveportal.inc @@ -786,6 +786,7 @@ function captiveportal_prune_old() { $timedout = false; $term_cause = 1; + $logout_cause = 'TIMEOUT'; if (empty($cpentry[12])) { $cpentry[12] = 'first'; } @@ -799,6 +800,7 @@ function captiveportal_prune_old() { if (($pruning_time - $cpentry[0]) >= $timeout) { $timedout = true; $term_cause = 5; // Session-Timeout + $logout_cause = 'SESSION TIMEOUT'; } } @@ -807,6 +809,7 @@ function captiveportal_prune_old() { if ($pruning_time >= $cpentry[9]) { $timedout = true; $term_cause = 5; // Session-Timeout + $logout_cause = 'SESSION TIMEOUT'; } } @@ -822,6 +825,7 @@ function captiveportal_prune_old() { if ($lastact && (($pruning_time - $lastact) >= $uidletimeout)) { $timedout = true; $term_cause = 4; // Idle-Timeout + $logout_cause = 'IDLE TIMEOUT'; if (!isset($config['captiveportal'][$cpzone]['includeidletime'])) { $stop_time = $lastact; } @@ -833,6 +837,7 @@ function captiveportal_prune_old() { if ($pruning_time >= ($cpentry[0] + $cpentry[7])) { $timedout = true; $term_cause = 5; // Session-Timeout + $logout_cause = 'SESSION TIMEOUT'; $voucher_needs_sync = true; } } @@ -846,12 +851,13 @@ function captiveportal_prune_old() { if (($volume['input_bytes'] + $volume['output_bytes']) > $trafficquota) { $timedout = true; $term_cause = 10; // NAS-Request + $logout_cause = 'QUOTA EXCEEDED'; } } if ($timedout) { captiveportal_disconnect($cpentry, $radiusservers, $term_cause, $stop_time); - captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "TIMEOUT"); + captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], $logout_cause); $unsetindexes[] = $cpentry[5]; } From f87ddb3b37c715bf8a86f1b9e13f9ebf344796c4 Mon Sep 17 00:00:00 2001 From: plumbeo Date: Thu, 5 Apr 2018 15:35:59 +0200 Subject: [PATCH 5/6] Captive portal: add option to choose whether to use the bandwidth limits retrieved from RADIUS or not Automatically upgrade config to preserve old RADIUS bandwidth limits behaviour on existing installations. --- src/etc/inc/captiveportal.inc | 19 ++++++++-- src/etc/inc/globals.inc | 2 +- src/etc/inc/upgrade_config.inc | 39 ++++++++++++++------ src/usr/local/www/services_captiveportal.php | 10 +++++ 4 files changed, 53 insertions(+), 17 deletions(-) diff --git a/src/etc/inc/captiveportal.inc b/src/etc/inc/captiveportal.inc index 3939be94a3..dff751453f 100644 --- a/src/etc/inc/captiveportal.inc +++ b/src/etc/inc/captiveportal.inc @@ -2168,8 +2168,14 @@ function captiveportal_reapply_attributes($cpentry, $attributes) { $dwfaultbw_up = $dwfaultbw_down = 0; } /* pipe throughputs must always be an integer, enforce that restriction again here. */ - $bw_up = round(!empty($attributes['bw_up']) ? intval($attributes['bw_up'])/1000 : $dwfaultbw_up, 0); - $bw_down = round(!empty($attributes['bw_down']) ? intval($attributes['bw_down'])/1000 : $dwfaultbw_down, 0); + if (isset($config['captiveportal'][$cpzone]['radiusperuserbw'])) { + $bw_up = round(!empty($attributes['bw_up']) ? intval($attributes['bw_up'])/1000 : $dwfaultbw_up, 0); + $bw_down = round(!empty($attributes['bw_down']) ? intval($attributes['bw_down'])/1000 : $dwfaultbw_down, 0); + } else { + $bw_up = round($dwfaultbw_up,0); + $bw_down = round($dwfaultbw_down,0); + } + $bw_up_pipeno = $cpentry[1]; $bw_down_pipeno = $cpentry[1]+1; @@ -2315,8 +2321,13 @@ function portal_allow($clientip, $clientmac, $username, $password = null, $attri $dwfaultbw_up = $dwfaultbw_down = 0; } /* pipe throughputs must always be an integer, enforce that restriction again here. */ - $bw_up = round(!empty($attributes['bw_up']) ? intval($attributes['bw_up'])/1000 : $dwfaultbw_up, 0); - $bw_down = round(!empty($attributes['bw_down']) ? intval($attributes['bw_down'])/1000 : $dwfaultbw_down, 0); + if (isset($config['captiveportal'][$cpzone]['radiusperuserbw'])) { + $bw_up = round(!empty($attributes['bw_up']) ? intval($attributes['bw_up'])/1000 : $dwfaultbw_up, 0); + $bw_down = round(!empty($attributes['bw_down']) ? intval($attributes['bw_down'])/1000 : $dwfaultbw_down, 0); + } else { + $bw_up = round($dwfaultbw_up,0); + $bw_down = round($dwfaultbw_down,0); + } if ($passthrumac) { diff --git a/src/etc/inc/globals.inc b/src/etc/inc/globals.inc index d15b620b29..0a4034991a 100644 --- a/src/etc/inc/globals.inc +++ b/src/etc/inc/globals.inc @@ -74,7 +74,7 @@ $g = array( "disablecrashreporter" => false, "crashreporterurl" => "https://crashreporter.pfsense.org/crash_reporter.php", "debug" => false, - "latest_config" => "18.0", + "latest_config" => "18.1", "minimum_ram_warning" => "101", "minimum_ram_warning_text" => "128 MB", "wan_interface_name" => "wan", diff --git a/src/etc/inc/upgrade_config.inc b/src/etc/inc/upgrade_config.inc index 56cc86b3b7..467b87022b 100644 --- a/src/etc/inc/upgrade_config.inc +++ b/src/etc/inc/upgrade_config.inc @@ -5478,18 +5478,6 @@ function upgrade_173_to_174() { } } -/* - * Special function that is called independent of current config version. It's - * a workaround to have config_upgrade running on older versions after next - * config version was already taken by newer pfSense. - * - * XXX Change the way we handle config version to make it based on product - * version - */ -function additional_config_upgrade() { - global $config; -} - /* IPsec Phase1 now supports multiple authentication ciphers to be specified from the webgui. * This is usefull for mobile users using different OS's supporting different ciphers. */ @@ -5554,4 +5542,31 @@ function upgrade_179_to_180() { } } +/* + * Automatically enable retrieving captive portal bandwidth limits from RADIUS for each captive portal + */ +function upgrade_180_to_181() { + global $config; + + if (is_array($config['captiveportal'])) { + foreach ($config['captiveportal'] as $cpzone => $cpcfg) { + if ($cpcfg['auth_method'] == "radius") { + $config['captiveportal'][$cpzone]['radiusperuserbw'] = true; + } + } + } +} + +/* + * Special function that is called independent of current config version. It's + * a workaround to have config_upgrade running on older versions after next + * config version was already taken by newer pfSense. + * + * XXX Change the way we handle config version to make it based on product + * version + */ +function additional_config_upgrade() { + global $config; +} + ?> diff --git a/src/usr/local/www/services_captiveportal.php b/src/usr/local/www/services_captiveportal.php index 14898e0eaa..3b82c7d7a7 100644 --- a/src/usr/local/www/services_captiveportal.php +++ b/src/usr/local/www/services_captiveportal.php @@ -187,6 +187,7 @@ if ($a_cp[$cpzone]) { $pconfig['radiusvendor'] = $a_cp[$cpzone]['radiusvendor']; $pconfig['radiussession_timeout'] = isset($a_cp[$cpzone]['radiussession_timeout']); $pconfig['radiustraffic_quota'] = isset($a_cp[$cpzone]['radiustraffic_quota']); + $pconfig['radiusperuserbw'] = isset($a_cp[$cpzone]['radiusperuserbw']); $pconfig['radiussrcip_attribute'] = $a_cp[$cpzone]['radiussrcip_attribute']; $pconfig['passthrumacadd'] = isset($a_cp[$cpzone]['passthrumacadd']); $pconfig['passthrumacaddusername'] = isset($a_cp[$cpzone]['passthrumacaddusername']); @@ -437,6 +438,7 @@ if ($_POST['save']) { $newcp['radiusvendor'] = $_POST['radiusvendor'] ? $_POST['radiusvendor'] : false; $newcp['radiussession_timeout'] = $_POST['radiussession_timeout'] ? true : false; $newcp['radiustraffic_quota'] = $_POST['radiustraffic_quota'] ? true : false; + $newcp['radiusperuserbw'] = $_POST['radiusperuserbw'] ? true : false; $newcp['radiussrcip_attribute'] = $_POST['radiussrcip_attribute']; $newcp['passthrumacadd'] = $_POST['passthrumacadd'] ? true : false; $newcp['passthrumacaddusername'] = $_POST['passthrumacaddusername'] ? true : false; @@ -986,6 +988,14 @@ $section->addInput(new Form_Checkbox( $pconfig['radiustraffic_quota'] ))->setHelp('When enabled, clients will be disconnected after exceeding the amount of traffic, inclusive of both downloads and uploads, retrieved from the RADIUS pfSense-Max-Total-Octets attribute.'); +$section->addInput(new Form_Checkbox( + 'radiusperuserbw', + 'Per-user bandwidth restrictions', + 'Use RADIUS pfSense-Bandwidth-Max-Up and pfSense-Bandwidth-Max-Down attributes', + $pconfig['radiusperuserbw'] +))->setHelp('When enabled, the bandwidth assigned to a client will be limited to the values retrieved from the RADIUS pfSense-Bandwidth-Max-Up and ' . + 'pfSense-Bandwidth-Max-Down attributes or from the comparable WISPr attributes.'); + $section->addInput(new Form_Select( 'radiusvendor', 'Type', From 066335a36550f6534e0bc6d28db389812b0ab97e Mon Sep 17 00:00:00 2001 From: plumbeo Date: Fri, 2 Mar 2018 12:30:36 +0100 Subject: [PATCH 6/6] Captive portal: Add custom RADIUS dictionary with the new pfSense vendor-specific attributes --- src/usr/share/doc/radius/dictionary.pfsense | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/usr/share/doc/radius/dictionary.pfsense diff --git a/src/usr/share/doc/radius/dictionary.pfsense b/src/usr/share/doc/radius/dictionary.pfsense new file mode 100644 index 0000000000..4f0186ba05 --- /dev/null +++ b/src/usr/share/doc/radius/dictionary.pfsense @@ -0,0 +1,18 @@ +# -*- text -*- +############################################################################## +# +# pfSense Captive Portal +# +# $Id$ +# +############################################################################## + +VENDOR pfSense 13644 + +BEGIN-VENDOR pfSense + +ATTRIBUTE pfSense-Bandwidth-Max-Up 1 integer +ATTRIBUTE pfSense-Bandwidth-Max-Down 2 integer +ATTRIBUTE pfSense-Max-Total-Octets 3 integer + +END-VENDOR pfSense