diff --git a/src/etc/inc/globals.inc b/src/etc/inc/globals.inc index 9911f1cca7..6aba6653cd 100644 --- a/src/etc/inc/globals.inc +++ b/src/etc/inc/globals.inc @@ -32,6 +32,9 @@ define("IPV6", 6); define("IPV4V6", 2); define("ALIAS", 1); +// Interface Name Size +define("IF_NAMESIZE", 15); /* 16 minus the terminating NULL */ + // AddPassword method defines define('DMYPWD', "********"); @@ -71,7 +74,7 @@ $g = array( "disablecrashreporter" => false, "crashreporterurl" => "https://crashreporter.pfsense.org/crash_reporter.php", "debug" => false, - "latest_config" => "17.1", + "latest_config" => "17.2", "minimum_ram_warning" => "101", "minimum_ram_warning_text" => "128 MB", "wan_interface_name" => "wan", diff --git a/src/etc/inc/interfaces.inc b/src/etc/inc/interfaces.inc index aad7d6ee31..7736e964e6 100644 --- a/src/etc/inc/interfaces.inc +++ b/src/etc/inc/interfaces.inc @@ -200,6 +200,91 @@ function interfaces_loopback_configure() { return 0; } +function vlan_valid_tag($tag = NULL) { + + if ($tag == NULL || empty($tag) || + !is_numericint($tag) || intval($tag) < 1 || intval($tag) > 4094) { + return (false); + } + return (true); +} + +function qinq_inuse($qinq = NULL, $inqtag = NULL) { + global $config; + + if ($qinq == NULL || $inqtag == NULL || + !is_array($qinq) || !vlan_valid_tag($inqtag)) { + return (false); + } + + $iflist = get_configured_interface_list(true); + foreach ($iflist as $if) { + if ($config['interfaces'][$if]['if'] == qinq_interface($qinq, $inqtag)) { + return (true); + } + } + + return (false); +} + +function qinq_interface($qinq = NULL, $inqtag = NULL) { + + if ($qinq == NULL || $inqtag == NULL || !is_array($qinq) || + !isset($qinq['if']) || !isset($qinq['tag']) || + !vlan_valid_tag($qinq['tag']) || !vlan_valid_tag($inqtag)) { + return (NULL); + } + return ("{$qinq['if']}.{$qinq['tag']}.{$inqtag}"); +} + +function interface_is_qinq($if = NULL) { + global $config; + + if ($if == NULL || empty($if) || !is_array($config['qinqs']['qinqentry'])) { + return (NULL); + } + + /* Check basic format. */ + list($qinqif, $vlantag, $inqtag) = explode(".", $if); + if (empty($qinqif) || empty($vlantag) || empty($inqtag) || + !vlan_valid_tag($vlantag) || !vlan_valid_tag($inqtag)) { + return (NULL); + } + + foreach ($config['qinqs']['qinqentry'] as $qinqidx => $qinq) { + if ("{$qinqif}.{$vlantag}" != $qinq['vlanif']) { + continue; + } + if (empty($qinq['members'])) { + continue; + } + foreach (explode(" ", $qinq['members']) as $tag) { + if ($if == qinq_interface($qinq, $tag)) { + return ($qinq); + } + } + } + + return (NULL); +} + +function vlan_inuse($vlan) { + global $config; + + if ($vlan == NULL || !is_array($vlan)) { + return (false); + } + + $iflist = get_configured_interface_list(true); + foreach ($iflist as $if) { + if ($config['interfaces'][$if]['if'] == $vlan['vlanif']) { + return (true); + } + } + + return (false); +} + function interface_is_vlan($if = NULL) { global $config; @@ -227,7 +312,8 @@ function interface_is_vlan($if = NULL) { function vlan_interface($vlan = NULL) { if ($vlan == NULL || !is_array($vlan) || - !isset($vlan['if']) || !isset($vlan['tag'])) { + !isset($vlan['if']) || !isset($vlan['tag']) || + intval($vlan['tag']) < 0 || intval($vlan['tag']) > 4094) { return (NULL); } return ("{$vlan['if']}.{$vlan['tag']}"); @@ -311,16 +397,16 @@ function interface_vlan_configure(&$vlan) { return $vlanif; } -function interface_qinq_configure(&$vlan, $fd = NULL) { +function interface_qinq_configure(&$qinq, $fd = NULL) { global $config, $g; - if (!is_array($vlan)) { + if (!is_array($qinq)) { log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n")); return; } - $qinqif = $vlan['if']; - $tag = $vlan['tag']; + $qinqif = $qinq['if']; + $tag = $qinq['tag']; if (empty($qinqif)) { log_error(sprintf(gettext("interface_qinq_configure called with if undefined.%s"), "\n")); return; @@ -331,8 +417,8 @@ function interface_qinq_configure(&$vlan, $fd = NULL) { return; } - $vlanif = interface_vlan_configure($vlan); - if ($vlanif == NULL) { + $vlanif = interface_vlan_configure($qinq); + if ($vlanif == NULL || $vlanif != $qinq['vlanif']) { log_error(gettext("interface_qinq_configure cannot create VLAN interface")); return; } @@ -347,47 +433,53 @@ function interface_qinq_configure(&$vlan, $fd = NULL) { interfaces_bring_up($qinqif); pfSense_ngctl_attach(".", $qinqif); + $ngif = str_replace(".", "_", $vlanif); if (!empty($vlanif) && does_interface_exist($vlanif)) { - fwrite($fd, "shutdown {$vlanif}qinq:\n"); - exec("/usr/sbin/ngctl msg {$vlanif}qinq: gettable", $result); + exec("/usr/sbin/ngctl shutdown {$ngif}qinq: > /dev/null 2>&1"); + exec("/usr/sbin/ngctl msg {$ngif}qinq: gettable > /dev/null 2>&1", $result); if (empty($result)) { - fwrite($fd, "mkpeer {$vlanif}: vlan lower downstream\n"); - fwrite($fd, "name {$vlanif}:lower {$vlanif}qinq\n"); - fwrite($fd, "connect {$vlanif}: {$vlanif}qinq: upper nomatch\n"); + fwrite($fd, "mkpeer {$ngif}: vlan lower downstream\n"); + fwrite($fd, "name {$ngif}:lower {$ngif}qinq\n"); + fwrite($fd, "connect {$ngif}: {$ngif}qinq: upper nomatch\n"); } } else { - fwrite($fd, "mkpeer {$vlanif}: vlan lower downstream\n"); - fwrite($fd, "name {$vlanif}:lower {$vlanif}qinq\n"); - fwrite($fd, "connect {$vlanif}: {$vlanif}qinq: upper nomatch\n"); + fwrite($fd, "mkpeer {$ngif}: vlan lower downstream\n"); + fwrite($fd, "name {$ngif}:lower {$ngif}qinq\n"); + fwrite($fd, "connect {$ngif}: {$ngif}qinq: upper nomatch\n"); } /* invalidate interface cache */ get_interface_arr(true); - if (!stristr($qinqif, "_vlan")) { + if (interface_is_vlan($qinqif) == NULL) { mwexec("/sbin/ifconfig {$qinqif} promisc\n"); } $macaddr = get_interface_mac($qinqif); - if (!empty($vlan['members'])) { - $members = explode(" ", $vlan['members']); + if (!empty($qinq['members'])) { + $qinqcmdbuf = ""; + $members = explode(" ", $qinq['members']); foreach ($members as $qtag) { - $qinq = array(); - $qinq['tag'] = $qtag; - $qinq['if'] = $vlanif; - interface_qinq2_configure($qinq, $fd, $macaddr); + $qinq2 = array(); + $qinq2['tag'] = $qtag; + $qinq2['if'] = $vlanif; + interface_qinq2_configure($qinq2, $qinqcmdbuf, $macaddr); + unset($qinq2); + } + if (strlen($qinqcmdbuf) > 0) { + fwrite($fd, $qinqcmdbuf); } } if ($exec == true) { fclose($fd); - mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd"); + mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd > /dev/null 2>&1"); } interfaces_bring_up($qinqif); - if (!empty($vlan['members'])) { - $members = explode(" ", $vlan['members']); - foreach ($members as $qif) { - interfaces_bring_up("{$vlanif}_{$qif}"); + if (!empty($qinq['members'])) { + $members = explode(" ", $qinq['members']); + foreach ($members as $qtag) { + interfaces_bring_up(qinq_interface($qinq, $qtag)); } } @@ -410,7 +502,7 @@ function interfaces_qinq_configure() { } } -function interface_qinq2_configure(&$qinq, $fd, $macaddr) { +function interface_qinq2_configure(&$qinq, &$cmdbuf, $macaddr) { global $config, $g; if (!is_array($qinq)) { @@ -419,19 +511,25 @@ function interface_qinq2_configure(&$qinq, $fd, $macaddr) { } $if = $qinq['if']; - $tag = $qinq['tag']; - $vlanif = "{$if}_{$tag}"; if (empty($if)) { log_error(sprintf(gettext("interface_qinq2_configure called with if undefined.%s"), "\n")); return; } + $tag = $qinq['tag']; + $vlanif = "{$if}.{$tag}"; + $ngif = str_replace(".", "_", $if); + if (strlen($vlanif) > IF_NAMESIZE) { + log_error(sprintf(gettext("interface_qinq2_configure interface name too big %s. (max. size: %d).%s"), + $vlanif, IF_NAMESIZE, "\n")); + return; + } - fwrite($fd, "shutdown {$if}h{$tag}:\n"); - fwrite($fd, "mkpeer {$if}qinq: eiface {$if}{$tag} ether\n"); - fwrite($fd, "name {$if}qinq:{$if}{$tag} {$if}h{$tag}\n"); - fwrite($fd, "msg {$if}qinq: addfilter { vlan={$tag} hook=\"{$if}{$tag}\" }\n"); - fwrite($fd, "msg {$if}h{$tag}: setifname \"{$vlanif}\"\n"); - fwrite($fd, "msg {$if}h{$tag}: set {$macaddr}\n"); + exec("/usr/sbin/ngctl shutdown {$ngif}h{$tag}: > /dev/null 2>&1"); + $cmdbuf .= "mkpeer {$ngif}qinq: eiface {$ngif}{$tag} ether\n"; + $cmdbuf .= "name {$ngif}qinq:{$ngif}{$tag} {$ngif}h{$tag}\n"; + $cmdbuf .= "msg {$ngif}qinq: addfilter { vlan={$tag} hook=\"{$ngif}{$tag}\" }\n"; + $cmdbuf .= "msg {$ngif}h{$tag}: setifname \"{$vlanif}\"\n"; + $cmdbuf .= "msg {$ngif}h{$tag}: set {$macaddr}\n"; /* invalidate interface cache */ get_interface_arr(true); diff --git a/src/etc/inc/upgrade_config.inc b/src/etc/inc/upgrade_config.inc index 1eeb4ce795..6983a4d85a 100644 --- a/src/etc/inc/upgrade_config.inc +++ b/src/etc/inc/upgrade_config.inc @@ -5442,6 +5442,35 @@ function upgrade_170_to_171() { } } +/* Upgrade the QinQ interface names to use $if.$tag instead of $if_$tag. + * This helps keep the interface names smaller than the limit (but they are still + * big with the QinQ subtag). + */ +function upgrade_171_to_172() { + global $config; + + if (!is_array($config['qinqs']['qinqentry']) || count($config['qinqs']['qinqentry']) == 0) { + return; + } + $iflist = get_configured_interface_list(true); + foreach ($config['qinqs']['qinqentry'] as $id => $qinq) { + $config['qinqs']['qinqentry'][$id]['vlanif'] = vlan_interface($qinq); + + if (!isset($qinq['members'])) { + continue; + } + foreach (explode(" ", $qinq['members']) as $tag) { + /* Make sure to update the interfaces section with the new name. */ + $vlan_name = "{$qinq['if']}_{$qinq['tag']}_{$tag}"; + foreach ($iflist as $ifname) { + if ($config['interfaces'][$ifname]['if'] == $vlan_name) { + $config['interfaces'][$ifname]['if'] = qinq_interface($qinq, $tag); + } + } + } + } +} + /* * Special function that is called independent of current config version. It's * a workaround to have config_upgrade running on older versions after next diff --git a/src/etc/inc/util.inc b/src/etc/inc/util.inc index ef39ebf592..12cedb5f9d 100644 --- a/src/etc/inc/util.inc +++ b/src/etc/inc/util.inc @@ -2154,6 +2154,7 @@ function is_interface_mismatch() { if (is_array($config['interfaces'])) { foreach ($config['interfaces'] as $ifname => $ifcfg) { if (interface_is_vlan($ifcfg['if']) != NULL || + interface_is_qinq($ifcfg['if']) != NULL || preg_match("/^enc|^cua|^tun|^tap|^l2tp|^pptp|^ppp|^ovpn|^gif|^gre|^lagg|^bridge|vlan|_wlan|_\d{0,4}_\d{0,4}$/i", $ifcfg['if'])) { // Do not check these interfaces. $i++; diff --git a/src/usr/local/www/interfaces_assign.php b/src/usr/local/www/interfaces_assign.php index f949df9439..79d11e398a 100644 --- a/src/usr/local/www/interfaces_assign.php +++ b/src/usr/local/www/interfaces_assign.php @@ -163,8 +163,8 @@ if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry /* QinQ members */ $qinqifs = explode(' ', $qinq['members']); foreach ($qinqifs as $qinqif) { - $portlist["{$qinq['vlanif']}_{$qinqif}"]['descr'] = "QinQ {$qinqif} on VLAN {$qinq['tag']} on {$qinq['if']}"; - $portlist["{$qinq['vlanif']}_{$qinqif}"]['isqinq'] = true; + $portlist["{$qinq['vlanif']}.{$qinqif}"]['descr'] = "QinQ {$qinqif} on VLAN {$qinq['tag']} on {$qinq['if']}"; + $portlist["{$qinq['vlanif']}.{$qinqif}"]['isqinq'] = true; } } } diff --git a/src/usr/local/www/interfaces_qinq.php b/src/usr/local/www/interfaces_qinq.php index 3fff40bb5f..b2081983bd 100644 --- a/src/usr/local/www/interfaces_qinq.php +++ b/src/usr/local/www/interfaces_qinq.php @@ -35,24 +35,11 @@ if (!is_array($config['qinqs']['qinqentry'])) { $a_qinqs = &$config['qinqs']['qinqentry']; -function qinq_inuse($num) { - global $config, $a_qinqs; - - $iflist = get_configured_interface_list(true); - foreach ($iflist as $if) { - if ($config['interfaces'][$if]['if'] == $a_qinqs[$num]['qinqif']) { - return true; - } - } - - return false; -} - if ($_POST['act'] == "del") { $id = $_POST['id']; /* check if still in use */ - if (qinq_inuse($id)) { + if (isset($a_qinqs) && vlan_inuse($a_qinqs[$id])) { $input_errors[] = gettext("This QinQ cannot be deleted because it is still being used as an interface."); } elseif (empty($a_qinqs[$id]['vlanif']) || !does_interface_exist($a_qinqs[$id]['vlanif'])) { $input_errors[] = gettext("QinQ interface does not exist"); @@ -60,13 +47,24 @@ if ($_POST['act'] == "del") { $qinq =& $a_qinqs[$id]; $delmembers = explode(" ", $qinq['members']); - if (count($delmembers) > 0) { - foreach ($delmembers as $tag) { - mwexec("/usr/sbin/ngctl shutdown {$qinq['vlanif']}h{$tag}:"); + foreach ($delmembers as $tag) { + if (qinq_inuse($qinq, $tag)) { + $input_errors[] = gettext("This QinQ cannot be deleted because one of it tags is still being used as an interface."); + break; } } - mwexec("/usr/sbin/ngctl shutdown {$qinq['vlanif']}qinq:"); - mwexec("/usr/sbin/ngctl shutdown {$qinq['vlanif']}:"); + } + + if (empty($input_errors)) { + $qinq =& $a_qinqs[$id]; + + $ngif = str_replace(".", "_", $qinq['vlanif']); + $delmembers = explode(" ", $qinq['members']); + foreach ($delmembers as $tag) { + mwexec("/usr/sbin/ngctl shutdown {$ngif}h{$tag}: > /dev/null 2>&1"); + } + mwexec("/usr/sbin/ngctl shutdown {$ngif}qinq: > /dev/null 2>&1"); + mwexec("/usr/sbin/ngctl shutdown {$ngif}: > /dev/null 2>&1"); pfSense_interface_destroy($qinq['vlanif']); unset($a_qinqs[$id]); diff --git a/src/usr/local/www/interfaces_qinq_edit.php b/src/usr/local/www/interfaces_qinq_edit.php index e75d02b692..95fa3c974e 100644 --- a/src/usr/local/www/interfaces_qinq_edit.php +++ b/src/usr/local/www/interfaces_qinq_edit.php @@ -143,10 +143,22 @@ if ($_POST['save']) { $input_errors[] = gettext("At least one tag must be entered."); } + $nmembers = explode(" ", $members); + if (isset($id) && $a_qinqs[$id]) { + $omembers = explode(" ", $a_qinqs[$id]['members']); + $delmembers = array_diff($omembers, $nmembers); + foreach ($delmembers as $tag) { + if (qinq_inuse($a_qinqs[$id], $tag)) { + $input_errors[] = gettext("This QinQ tag cannot be deleted because it is still being used as an interface."); + break; + } + } + } + if (!$input_errors) { $qinqentry['members'] = $members; $qinqentry['descr'] = $_POST['descr']; - $qinqentry['vlanif'] = "{$_POST['if']}_{$_POST['tag']}"; + $qinqentry['vlanif'] = vlan_interface($_POST); $nmembers = explode(" ", $members); if (isset($id) && $a_qinqs[$id]) { @@ -155,22 +167,29 @@ if ($_POST['save']) { $addmembers = array_diff($nmembers, $omembers); if ((count($delmembers) > 0) || (count($addmembers) > 0)) { - $fd = fopen("{$g['tmp_path']}/netgraphcmd", "w"); foreach ($delmembers as $tag) { - fwrite($fd, "shutdown {$qinqentry['vlanif']}h{$tag}:\n"); - fwrite($fd, "msg {$qinqentry['vlanif']}qinq: delfilter \\\"{$qinqentry['vlanif']}{$tag}\\\"\n"); + $ngif = str_replace(".", "_", $qinqentry['vlanif']); + exec("/usr/sbin/ngctl shutdown {$ngif}h{$tag}: > /dev/null 2>&1"); + exec("/usr/sbin/ngctl msg {$ngif}qinq: delfilter \\\"{$ngif}{$tag}\\\" > /dev/null 2>&1"); } + $qinqcmdbuf = ""; foreach ($addmembers as $member) { $qinq = array(); $qinq['if'] = $qinqentry['vlanif']; $qinq['tag'] = $member; $macaddr = get_interface_mac($qinqentry['vlanif']); - interface_qinq2_configure($qinq, $fd, $macaddr); + interface_qinq2_configure($qinq, $qinqcmdbuf, $macaddr); } - fclose($fd); - mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd"); + if (strlen($qinqcmdbuf) > 0) { + $fd = fopen("{$g['tmp_path']}/netgraphcmd", "w"); + if ($fd) { + fwrite($fd, $qinqcmdbuf); + fclose($fd); + mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd > /dev/null 2>&1"); + } + } } $a_qinqs[$id] = $qinqentry; } else { @@ -189,7 +208,7 @@ if ($_POST['save']) { } $additions = ""; foreach ($nmembers as $qtag) { - $additions .= "{$qinqentry['vlanif']}_{$qtag} "; + $additions .= qinq_interface($qinqentry, $qtag) . " "; } $additions .= "{$qinqentry['vlanif']}"; if ($found == true) { diff --git a/src/usr/local/www/interfaces_vlan.php b/src/usr/local/www/interfaces_vlan.php index d944616e4f..6510e3abae 100644 --- a/src/usr/local/www/interfaces_vlan.php +++ b/src/usr/local/www/interfaces_vlan.php @@ -38,26 +38,13 @@ if (!is_array($config['vlans']['vlan'])) { $a_vlans = &$config['vlans']['vlan'] ; -function vlan_inuse($num) { - global $config, $a_vlans; - - $iflist = get_configured_interface_list(true); - foreach ($iflist as $if) { - if ($config['interfaces'][$if]['if'] == $a_vlans[$num]['vlanif']) { - return true; - } - } - - return false; -} - if ($_POST['act'] == "del") { if (!isset($_POST['id'])) { $input_errors[] = gettext("Wrong parameters supplied"); } else if (empty($a_vlans[$_POST['id']])) { $input_errors[] = gettext("Wrong index supplied"); /* check if still in use */ - } else if (vlan_inuse($_POST['id'])) { + } else if (vlan_inuse($a_vlans[$_POST['id']])) { $input_errors[] = gettext("This VLAN cannot be deleted because it is still being used as an interface."); } else { if (does_interface_exist($a_vlans[$_POST['id']]['vlanif'])) {