From 7503dd1b4eaaffbd203652835e171ae5e810b3e5 Mon Sep 17 00:00:00 2001 From: doktornotor Date: Sat, 28 Nov 2015 21:08:42 +0100 Subject: Add lots of input validations to sanitize configuration, plus other fixes - Allow reverse proxy to be used without running normal Squid proxy - Force users to select at least one proxy or reverse proxy interface when enabling Squid (unless reverse proxy is enabled) - Only allow to configure transparent proxy on interfaces where Squid is actually running (never had any effect otherwise anyway) - Only allow to configure HTTPS/SSL Interception on interfaces where transparent proxy is enabled (never had any effect otherwise anyway) - Do not add loopback interface twice when transparent proxy is enabled and loopback is selected in Proxy Interface(s) - Avoid adding empty localnet ACL - Fix HTTPS proxy default port - Some code style fixes and cleanups --- config/squid3/34/squid.inc | 159 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 121 insertions(+), 38 deletions(-) diff --git a/config/squid3/34/squid.inc b/config/squid3/34/squid.inc index aab4d134..763fe34c 100755 --- a/config/squid3/34/squid.inc +++ b/config/squid3/34/squid.inc @@ -66,7 +66,7 @@ define('SQUID_CONFBASE', SQUID_LOCALBASE .'/etc/squid'); define('SQUID_CONFFILE', SQUID_CONFBASE . '/squid.conf'); define('SQUID_ACLDIR', '/var/squid/acl'); define('SQUID_PASSWD', '/var/etc/squid.passwd'); -define('SQUID_SSL_DB','/var/squid/lib/ssl_db'); +define('SQUID_SSL_DB', '/var/squid/lib/ssl_db'); $valid_acls = array(); @@ -148,15 +148,11 @@ function squid_enabled() { // check whether Squid is enabled ... if ($config['installedpackages']['squid']['config'][0]['enable_squid'] == "on") { // ... and has at least one interface configured ... - if ($config['installedpackages']['squid']['config'][0]['active_interface'] != "") { + if (!empty($config['installedpackages']['squid']['config'][0]['active_interface'])) { + $proxy_enabled = true; + // ... or whether Squid reverse proxy is enabled + } elseif (squid_reverse_enabled()) { $proxy_enabled = true; - } else { - // ... or has at least one reverse interface configured - if (is_array($config['installedpackages']['squidreversegeneral']['config'])) { - if ($config['installedpackages']['squidreversegeneral']['config'][0]['reverse_interface'] != "") { - $proxy_enabled = true; - } - } } } } @@ -724,16 +720,27 @@ function squid_validate_general($post, &$input_errors) { // force users to configure cache if (!is_array($config['installedpackages']['squidcache']['config'])) { - $input_errors[] = 'Please, configure and save \'Local Cache\' settings first.'; + $input_errors[] = "Please, configure and save 'Local Cache' settings first."; } - $port = ($settings['proxy_port'] ? $settings['proxy_port'] : 3128); - $port = $post['proxy_port'] ? $post['proxy_port'] : $port; + // force users to select at least one proxy or reverse proxy interface when enabling Squid + if ($post['enable_squid'] == "on") { + // if reverse proxy is configured, perhaps the user wants to use the reverse proxy features only + if (!squid_reverse_enabled()) { + if (empty($post['active_interface'])) { + $input_errors[] = "You must select at least one interface under 'Proxy Interface(s)' to enable Squid proxy."; + $input_errors[] = "If you intend to use Squid as reverse proxy ONLY, then visit Services: Squid Proxy Server: General, configure and save the reverse proxy settings first."; + } + } else { + log_error("[squid] Enabled as reverse proxy ONLY. If this is not what you intended, visit Services: Squid Proxy Server: General and configure proxy interfaces."); + } + } $icp_port = trim($post['icp_port']); if (!empty($icp_port) && !is_port($icp_port)) { - $input_errors[] = 'You must enter a valid port number in the \'ICP port\' field.'; + $input_errors[] = "You must enter a valid port number in the 'ICP port' field."; } + unset($icp_port); if (substr($post['log_dir'], -1, 1) == '/') { $input_errors[] = 'Log location must not end with a / character.'; @@ -748,26 +755,66 @@ function squid_validate_general($post, &$input_errors) { } $log_rotate = trim($post['log_rotate']); - if (!empty($log_rotate) && (!is_numericint($log_rotate) or ($log_rotate < 1))) { $input_errors[] = "You must enter a valid number of days in the 'Log rotate' field."; } + unset($log_rotate); + // check that the proxy port does not clash with WebGUI + $port = ($settings['proxy_port'] ? $settings['proxy_port'] : 3128); + $port = $post['proxy_port'] ? $post['proxy_port'] : $port; $webgui_port = $config['system']['webgui']['port']; - if (($config['system']['webgui']['port'] == "") && ($config['system']['webgui']['protocol'] == "http")) { $webgui_port = 80; } if (($config['system']['webgui']['port'] == "") && ($config['system']['webgui']['protocol'] == "https")) { $webgui_port = 443; } - if (($post['transparent_proxy'] != 'on') && ($port == $webgui_port)) { $input_errors[] = "You can not run Squid on the same port as the pfSense WebGUI"; } + unset($port, $webgui_port); + + if ($post['transparent_proxy'] == 'on') { + if (empty($post['transparent_active_interface'])) { + $input_errors[] = "You must select at least one interface under 'Transparent Proxy Interface(s)' when 'Transparent HTTP Proxy' is enabled."; + } else { + // allow transparent proxy only on interfaces where Squid is actually running to keep configuration sane + $a_ifaces = $post['active_interface'] ?: array(); + $t_ifaces = $post['transparent_active_interface']; + foreach ($t_ifaces as $t_iface) { + if (!in_array($t_iface, $a_ifaces)) { + $err_iface = convert_friendly_interface_to_friendly_descr($t_iface); + $input_errors[] = "'Transparent Proxy Interface(s)' may only contain interfaces also selected in 'Proxy Interface(s)' above. '{$err_iface}' is not valid."; + unset($err_iface); + } + } + unset($a_ifaces, $t_iface, $t_ifaces); + } + } - if (($post['ssl_proxy'] == 'on') && ( $post['dca'] == '')) { - $input_errors[] = "SSL interception cannot be enabled without a CA."; + if ($post['ssl_proxy'] == 'on') { + if ($post['transparent_proxy'] != 'on') { + $input_errors[] = "SSL interception cannot be enabled without enabling 'Transparent HTTP Proxy'."; + } + if ($post['dca'] == 'none') { + $input_errors[] = "SSL interception cannot be enabled without a CA."; + } + if (empty($post['ssl_active_interface'])) { + $input_errors[] = "You must select at least one interface under 'SSL Intercept Interface(s)' when 'HTTPS/SSL Interception' is enabled."; + } else { + // allow HTTPS/SSL Interception only on interfaces where transparent proxy is enabled + $t_ifaces = $post['transparent_active_interface'] ?: array(); + $s_ifaces = $post['ssl_active_interface']; + foreach ($s_ifaces as $s_iface) { + if (!in_array($s_iface, $t_ifaces)) { + $err_iface = convert_friendly_interface_to_friendly_descr($s_iface); + $input_errors[] = "'SSL Intercept Interface(s)' may only contain interfaces also selected in 'Transparent Proxy Interface(s)' above. '{$err_iface}' is not valid."; + unset($err_iface); + } + } + unset($t_ifaces, $s_ifaces, $s_iface); + } } foreach (array('defined_ip_proxy_off') as $hosts) { @@ -778,6 +825,8 @@ function squid_validate_general($post, &$input_errors) { } } } + unset($host, $hosts); + foreach (array('defined_ip_proxy_off_dest') as $hosts) { foreach (explode(";", $post[$hosts]) as $host) { $host = trim($host); @@ -786,6 +835,7 @@ function squid_validate_general($post, &$input_errors) { } } } + unset($host, $hosts); if (!empty($post['dns_nameservers'])) { $altdns = explode(";", ($post['dns_nameservers'])); @@ -796,6 +846,7 @@ function squid_validate_general($post, &$input_errors) { } } } + unset($altdns, $dnssrv); } /* Proxy Server: Remote Proxy Settings input validation */ @@ -823,6 +874,7 @@ function squid_validate_upstream($post, &$input_errors) { } } } + unset($port); } /* Proxy Server: Cache Management input validation */ @@ -846,17 +898,20 @@ function squid_validate_cache($post, &$input_errors) { $input_errors[] = "You must enter a valid value for '$field'."; } } + unset($num_fields); $value = trim($post['minimum_object_size']); if (!is_numericint($value)) { $input_errors[] = "You must enter a valid value for 'Minimum object size'."; } + unset($value); if (!empty($post['cache_swap_low'])) { $value = trim($post['cache_swap_low']); if (!is_numericint($value) || ($value > 100)) { $input_errors[] = "You must enter a valid value for 'Low-water-mark'."; } + unset($value); } if (!empty($post['cache_swap_high'])) { @@ -864,6 +919,7 @@ function squid_validate_cache($post, &$input_errors) { if (!is_numericint($value) || ($value > 100)) { $input_errors[] = "You must enter a valid value for 'High-water-mark'."; } + unset($value); } if ($post['donotcache'] != "") { @@ -873,6 +929,7 @@ function squid_validate_cache($post, &$input_errors) { $input_errors[] = "The host '$host' is not a valid IP or hostname."; } } + unset($host); } if (substr($post['harddisk_cache_location'], -1, 1) == '/') { @@ -897,6 +954,7 @@ function squid_validate_nac($post, &$input_errors) { $input_errors[] = "'Allowed Subnets' must be a valid CIDR range or 'all'. The subnet '$subnet' is not valid."; } } + unset($allowed_subnets); foreach (array('unrestricted_hosts', 'banned_hosts') as $hosts) { if (preg_match_all("@([0-9.]+)(/[0-9.]+|)@", $_POST[$hosts], $matches)) { @@ -921,6 +979,7 @@ function squid_validate_nac($post, &$input_errors) { $input_errors[] = "'$mac' is not a valid MAC address."; } } + unset($mac); } foreach (explode(",", $post['timelist']) as $time) { @@ -929,6 +988,7 @@ function squid_validate_nac($post, &$input_errors) { $input_errors[] = "The time range '$time' is not a valid time range."; } } + unset($time); if (!empty($post['ext_cachemanager'])) { $extmgr = explode(";", ($post['ext_cachemanager'])); @@ -938,6 +998,7 @@ function squid_validate_nac($post, &$input_errors) { } } } + unset($extmgr); } /* Proxy server: Traffic Management input validation */ @@ -955,6 +1016,7 @@ function squid_validate_traffic($post, &$input_errors) { $input_errors[] = "The '$name' field must contain a positive integer."; } } + unset($num_fields); if (!empty($post['quick_abort_min'])) { $value = trim($post['quick_abort_min']); @@ -982,6 +1044,7 @@ function squid_validate_traffic($post, &$input_errors) { if ($post['throttle_binaries'] == "" && $post['throttle_cdimages'] == "" && $post['throttle_multimedia'] == "" && $others == "") { $input_errors[] = "'Throttle Only Specific Extensions' enabled but no extensions specified. Select some options under 'Squid Transfer Extension Settings' or disable this option."; } + unset($others); } } @@ -999,6 +1062,7 @@ function squid_validate_auth($post, &$input_errors) { $input_errors[] = "The '{$field[1]}' field must contain a valid number greater than {$field[2]}"; } } + unset($num_fields); $auth_method = $post['auth_method']; if (($auth_method != 'none') && ($auth_method != 'local') && ($auth_method != 'cp')) { @@ -1046,6 +1110,7 @@ function squid_validate_auth($post, &$input_errors) { } } } + unset($auth_method, $port, $server, $secret, $user); } /* Proxy Server: General Settings configuration handler */ @@ -1108,7 +1173,7 @@ function squid_resync_general() { } } $port = ($settings['proxy_port'] ? $settings['proxy_port'] : 3128); - $ssl_port = ($settings['ssl_proxy_port'] ? $settings['ssl_proxy_port'] : 3127); + $ssl_port = ($settings['ssl_proxy_port'] ? $settings['ssl_proxy_port'] : 3129); // Read assigned interfaces $real_ifaces = array(); @@ -1116,7 +1181,7 @@ function squid_resync_general() { if ($settings['active_interface']) { $proxy_ifaces = explode(",", $settings['active_interface']); } else { - $proxy_ifaces = array("lan"); + $proxy_ifaces = array(); } if ($settings['transparent_proxy'] == "on") { @@ -1136,7 +1201,7 @@ function squid_resync_general() { foreach ($ssl_ifaces as $s_iface) { $s_iface_ip = squid_get_real_interface_address($s_iface); if ($s_iface_ip[0]) { - $real_ifaces[]=$s_iface_ip; + $real_ifaces[] = $s_iface_ip; } } } else { @@ -1147,11 +1212,16 @@ function squid_resync_general() { foreach ($proxy_ifaces as $iface) { $iface_ip = squid_get_real_interface_address($iface); if ($iface_ip[0]) { - $real_ifaces[] = $iface_ip; - if (in_array($iface, $ssl_ifaces)) { - $conf .= "http_port {$iface_ip[0]}:{$port} {$ssl_interception}\n"; + // do not add loopback twice when transparent proxy is enabled + if ($iface_ip[0] == "127.0.0.1" && $settings['transparent_proxy'] == "on") { + continue; } else { - $conf .= "http_port {$iface_ip[0]}:{$port}\n"; + $real_ifaces[] = $iface_ip; + if (in_array($iface, $ssl_ifaces)) { + $conf .= "http_port {$iface_ip[0]}:{$port} {$ssl_interception}\n"; + } else { + $conf .= "http_port {$iface_ip[0]}:{$port}\n"; + } } } } @@ -1165,7 +1235,7 @@ function squid_resync_general() { } } $icp_port = ($settings['icp_port'] ? $settings['icp_port'] : 0); - $dns_v4_first = ($settings['dns_v4_first'] == "on" ? "on" : "off" ); + $dns_v4_first = ($settings['dns_v4_first'] == "on" ? "on" : "off"); $piddir = "{$g['varrun_path']}/squid"; $pidfile = "{$piddir}/squid.pid"; if (!is_dir($piddir)) { @@ -1237,9 +1307,11 @@ EOD; } } } - $conf .= "# Allow local network(s) on interface(s)\n"; - $conf .= "acl localnet src $src\n"; - $valid_acls[] = 'localnet'; + if (!empty($src)) { + $conf .= "# Allow local network(s) on interface(s)\n"; + $conf .= "acl localnet src $src\n"; + $valid_acls[] = 'localnet'; + } } if ($settings['xforward_mode']) { @@ -1411,25 +1483,33 @@ function squid_resync_upstream() { function squid_resync_nac() { global $config, $valid_acls; - $port = ($settings['proxy_port'] ? $settings['proxy_port'] : 3128); if (is_array($config['installedpackages']['squidnac'])) { $settings = $config['installedpackages']['squidnac']['config'][0]; } else { $settings = array(); } + if (is_array($config['installedpackages']['squid'])) { + $squidsettings = $config['installedpackages']['squid']['config'][0]; + } else { + $squidsettings = array(); + } + $webgui_port = $config['system']['webgui']['port']; $addtl_ports = $settings['addtl_ports']; $addtl_sslports = $settings['addtl_sslports']; - $port = ($settings['proxy_port'] ? $settings['proxy_port'] : 3128); - $ssl_port = ($settings['ssl_proxy_port'] ? $settings['ssl_proxy_port'] : 3127); + // do not add (default) proxy ports when using Squid as reverse proxy only + if (!empty($squidsettings['active_interface'])) { + $port = $squidsettings['proxy_port'] ? $squidsettings['proxy_port'] : 3128; + $ssl_port = $squidsettings['ssl_proxy_port'] ? $squidsettings['ssl_proxy_port'] : 3129; + } $conf = <<< EOD # Setup some default acls # From 3.2 further configuration cleanups have been done to make things easier and safer. The manager, localhost, and to_localhost ACL definitions are now built-in. # acl localhost src 127.0.0.1/32 acl allsrc src all -acl safeports port 21 70 80 210 280 443 488 563 591 631 777 901 $webgui_port $port $ssl_port 1025-65535 $addtl_ports -acl sslports port 443 563 $webgui_port $addtl_sslports +acl safeports port 21 70 80 210 280 443 488 563 591 631 777 901 {$webgui_port} {$port} {$ssl_port} 1025-65535 {$addtl_ports} +acl sslports port 443 563 {$webgui_port} {$addtl_sslports} # From 3.2 further configuration cleanups have been done to make things easier and safer. The manager, localhost, and to_localhost ACL definitions are now built-in. #acl manager proto cache_object @@ -1731,9 +1811,9 @@ function squid_resync_auth() { $conf .= "always_direct allow all\n"; $conf .= "ssl_bump server-first all\n"; } - $conf .= "# Setup allowed acls\n"; + $conf .= "# Setup allowed ACLs\n"; $allowed = array('allowed_subnets'); - if ($settingsconfig['allow_interface'] == 'on') { + if ($settingsconfig['allow_interface'] == 'on' && !empty($settingsconfig['active_interface'])) { $conf .= "# Allow local network(s) on interface(s)\n"; $allowed[] = "localnet"; } @@ -1952,10 +2032,13 @@ function squid_generate_rules($type) { file_put_contents($cp_file, $new_cp_inc, LOCK_EX); } - // do not install any firewall rules if Squid is disabled + // do not install any firewall rules if Squid is disabled or used as reverse proxy only if (!squid_enabled()) { log_error("[squid] Installed but disabled. Not installing '{$type}' rules."); return; + } elseif (empty($squid_conf['active_interface'])) { + log_error("[squid] Configured as reverse proxy only. Not installing '{$type}' rules."); + return; } // normal squid rule check @@ -1984,7 +2067,7 @@ function squid_generate_rules($type) { } $port = ($squid_conf['proxy_port'] ? $squid_conf['proxy_port'] : 3128); - $ssl_port = ($squid_conf['ssl_proxy_port'] ? $squid_conf['ssl_proxy_port'] : 3127); + $ssl_port = ($squid_conf['ssl_proxy_port'] ? $squid_conf['ssl_proxy_port'] : 3129); $fw_aliases = filter_generate_aliases(); if (strstr($fw_aliases, "pptp =")) { -- cgit v1.2.3