128 changes: 68 additions & 60 deletions contrib/IXR/IXR_Library.php

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion contrib/simplepie/library/SimplePie/Parse/Date.php
Original file line number Diff line number Diff line change
Expand Up @@ -690,7 +690,7 @@ public function date_w3cdtf($date)
}

// Convert the number of seconds to an integer, taking decimals into account
$second = round($match[6] + $match[7] / pow(10, strlen($match[7])));
$second = round((int)$match[6] + (int)$match[7] / pow(10, strlen($match[7])));

return gmmktime($match[4], $match[5], $second, $match[2], $match[3], $match[1]) - $timezone;
}
Expand Down
140 changes: 108 additions & 32 deletions plist

Large diffs are not rendered by default.

34 changes: 19 additions & 15 deletions src/etc/inc/auth.inc
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ function isAuthLocalIP($http_host)
}
$address_in_list = function ($interface_list_ips, $http_host) {
foreach ($interface_list_ips as $ilips => $ifname) {
// remove scope from link-local IPv6 addresses
$ilips = preg_replace('/%.*/', '', $ilips);
if (strcasecmp($http_host, $ilips) == 0) {
return true;
}
Expand Down Expand Up @@ -91,9 +93,9 @@ function index_users()
{
global $config;

$userindex = array();
$userindex = [];

if (is_array($config['system']['user'])) {
if (!empty($config['system']['user'])) {
$i = 0;
foreach ($config['system']['user'] as $userent) {
$userindex[$userent['name']] = $i;
Expand Down Expand Up @@ -299,10 +301,10 @@ function local_user_set(&$user, $force_password = false, $userattrs = null)
global $config;

if (empty($user['password'])) {
log_error(sprintf(
log_msg(sprintf(
gettext('There is something wrong in your config because user %s password is missing!'),
$user['name']
));
), LOG_ERR);
return;
}

Expand Down Expand Up @@ -354,18 +356,20 @@ function local_user_set(&$user, $force_password = false, $userattrs = null)
// XXX: primary group id can only be wheel or nobody, otherwise we should map the correct numbers for comparison
$user_gid = $user_group == 'wheel' ? 0 : 65534;

/* passwords only when integrated auth is disabled or forced */
if (!$force_password && empty($config['system']['disableintegratedauth'])) {
$user_pass = '*';
}
if (!$force_password) {
/* passwords only when integrated auth is disabled or forced */
if (empty($config['system']['disableintegratedauth'])) {
$user_pass = '*';
}

/* read from pw db if not provided (batch mode) */
if ($userattrs === null) {
$fd = popen("/usr/sbin/pw usershow -n {$user_name}", 'r');
$pwread = fgets($fd);
pclose($fd);
if (substr_count($pwread, ':')) {
$userattrs = explode(':', trim($pwread));
/* read from pw db if not provided (batch mode) */
if ($userattrs === null) {
$fd = popen("/usr/sbin/pw usershow -n {$user_name}", 'r');
$pwread = fgets($fd);
pclose($fd);
if (substr_count($pwread, ':')) {
$userattrs = explode(':', trim($pwread));
}
}
}

Expand Down
43 changes: 9 additions & 34 deletions src/etc/inc/authgui.inc
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ function session_auth()
openlog("audit", LOG_ODELAY, LOG_AUTH);
log_msg($message, $prio);
closelog();
reopenlog();
}

if (session_status() == PHP_SESSION_NONE) {
Expand Down Expand Up @@ -295,7 +296,7 @@ if ($_SESSION['Username'] != 'root' && !$acl->isPageAccessible($_SESSION['Userna
if (!empty($_SERVER['REMOTE_ADDR'])) {
$username .= '@' . $_SERVER['REMOTE_ADDR'];
}
log_error("{$username} attempted to access {$_SERVER['REQUEST_URI']} but does not have access to that page. Redirecting to {$page}.");
log_msg("{$username} attempted to access {$_SERVER['REQUEST_URI']} but does not have access to that page. Redirecting to {$page}.");
header(url_safe("Location: /{$page}"));
exit;
} else {
Expand All @@ -309,9 +310,8 @@ if ($_SESSION['Username'] != 'root' && !$acl->isPageAccessible($_SESSION['Userna
*/
function display_error_form($text)
{
global $g;

$themename = htmlspecialchars(get_current_theme());
$product = product::getInstance();

?><!doctype html>
<html lang="en" class="no-js">
Expand All @@ -326,7 +326,7 @@ function display_error_form($text)
<meta name="copyright" content="" />
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />

<title><?= gettext('Error') ?> | <?= $g['product_name'] ?></title>
<title><?= gettext('Error') ?> | <?= $product->name() ?></title>

<link href="<?= cache_safe("/ui/themes/{$themename}/build/css/main.css") ?>" rel="stylesheet">
<link href="<?= cache_safe("/ui/themes/{$themename}/build/images/favicon.png") ?>" rel="shortcut icon">
Expand All @@ -347,30 +347,11 @@ function display_error_form($text)

function display_login_form($Login_Error)
{
global $config, $g;
global $config;

$themename = htmlspecialchars(get_current_theme());
$product = product::getInstance();

/*
* Check against locally configured IP addresses, which will catch when
* someone port-forwards WebGUI access from WAN to an internal IP on the
* router.
*/
$local_ip = isAuthLocalIP($http_host);

if (isset($config['openvpn']['openvpn-server'])) {
foreach ($config['openvpn']['openvpn-server'] as $ovpns) {
if (is_ipaddrv4($http_host) && !empty($ovpns['tunnel_network']) && ip_in_subnet($http_host, $ovpns['tunnel_network'])) {
$local_ip = true;
break;
}

if (is_ipaddrv6($http_host) && !empty($ovpns['tunnel_networkv6']) && ip_in_subnet($http_host, $ovpns['tunnel_networkv6'])) {
$local_ip = true;
break;
}
}
}
setcookie("cookie_test", bin2hex(random_bytes(16)), time() + 3600, '/', null, $config['system']['webgui']['protocol'] == "https", true);
$have_cookies = isset($_COOKIE["cookie_test"]);
?><!doctype html>
Expand All @@ -385,7 +366,7 @@ function display_login_form($Login_Error)
<meta name="copyright" content="" />
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />

<title><?= gettext('Login') ?> | <?= $g['product_name'] ?></title>
<title><?= gettext('Login') ?> | <?= $product->name() ?></title>

<link href="<?= cache_safe("/ui/themes/{$themename}/build/css/main.css") ?>" rel="stylesheet">
<link href="<?= cache_safe("/ui/themes/{$themename}/build/images/favicon.png") ?>" rel="shortcut icon">
Expand All @@ -400,12 +381,6 @@ function display_login_form($Login_Error)
<body class="page-login">

<div class="container">
<?php
if (is_ipaddr($http_host) && !$local_ip && !isset($config['system']['webgui']['nohttpreferercheck'])) {
print_info_box(sprintf(gettext("You are accessing this router by an IP address not configured locally, which may be forwarded by NAT or other means. %sIf you did not setup this forwarding, you may be the target of a man-in-the-middle attack."), '<br /><br />'));
}
?>

<main class="login-modal-container">
<header class="login-modal-head" style="height:50px;">
<div class="navbar-brand">
Expand Down Expand Up @@ -447,8 +422,8 @@ function display_login_form($Login_Error)

</main>
<div class="login-foot text-center">
<a target="_blank" href="<?=$g['product_website']?>"><?=$g['product_name']?></a> (c) <?=$g['product_copyright_years']?>
<a target="_blank" href="<?=$g['product_copyright_url']?>"><?=$g['product_copyright_owner']?></a>
<a target="_blank" href="<?= $product->website() ?>"><?= $product->name() ?></a> (c) <?= $product->copyright_years() ?>
<a target="_blank" href="<?= $product->copyright_url() ?>"><?= $product->copyright_owner() ?></a>
</div>

</div>
Expand Down
137 changes: 25 additions & 112 deletions src/etc/inc/certs.inc
Original file line number Diff line number Diff line change
Expand Up @@ -27,34 +27,30 @@
* POSSIBILITY OF SUCH DAMAGE.
*/

require_once('phpseclib/File/X509.php');
require_once('phpseclib/File/ASN1.php');
require_once('phpseclib/Math/BigInteger.php');
require_once('phpseclib/File/ASN1/Element.php');
require_once('phpseclib/Crypt/RSA.php');
require_once('phpseclib/Crypt/Hash.php');

define("CERT_CRL_STATUS_NOSTATUS", -1);
define("CERT_CRL_STATUS_UNSPECIFIED", 0);
define("CERT_CRL_STATUS_KEYCOMPROMISE", 1);
define("CERT_CRL_STATUS_CACOMPROMISE", 2);
define("CERT_CRL_STATUS_AFFILIATIONCHANGED", 3);
define("CERT_CRL_STATUS_SUPERSEDED", 4);
define("CERT_CRL_STATUS_CESSATIONOFOPERATION", 5);
define("CERT_CRL_STATUS_CERTIFICATEHOLD", 6);

function crl_status_code()
{
/* Array index 0 is a description, index 1 is the key used by phpseclib */
return array(
CERT_CRL_STATUS_NOSTATUS => ["No Status (default)", "unused"],
CERT_CRL_STATUS_UNSPECIFIED => ["Unspecified", "unused"],
CERT_CRL_STATUS_KEYCOMPROMISE => ["Key Compromise", "keyCompromise"],
CERT_CRL_STATUS_CACOMPROMISE => ["CA Compromise", "cACompromise"],
CERT_CRL_STATUS_AFFILIATIONCHANGED => ["Affiliation Changed", "affiliationChanged"],
CERT_CRL_STATUS_SUPERSEDED => ["Superseded", "superseded"],
CERT_CRL_STATUS_CESSATIONOFOPERATION => ["Cessation of Operation", "cessationOfOperation"],
CERT_CRL_STATUS_CERTIFICATEHOLD => ["Certificate Hold", "certificateHold"]
function phpseclib_autoload($namespace, $dir)
{
$split = '\\';
$ns = trim($namespace, DIRECTORY_SEPARATOR . $split);

return spl_autoload_register(
function ($class) use ($ns, $dir, $split) {
$prefix = $ns . $split;
$base_dir = $dir . DIRECTORY_SEPARATOR;
$len = strlen($prefix);
if (strncmp($prefix, $class, $len)) {
return;
}

$relative_class = substr($class, $len);

$file = $base_dir .
str_replace($split, DIRECTORY_SEPARATOR, $relative_class) .
'.php';

if (file_exists($file)) {
require_once $file;
}
}
);
}

Expand Down Expand Up @@ -598,88 +594,6 @@ function cert_in_use($certref)
is_ipsec_cert($certref));
}

function crl_update(&$crl)
{
$ca =& lookup_ca($crl['caref']);
if (!$ca) {
return false;
}
// If we have text but no certs, it was imported and cannot be updated.
if (!is_crl_internal($crl)) {
return false;
}

$crl['serial']++;
$ca_str_crt = base64_decode($ca['crt']);
$ca_str_key = base64_decode($ca['prv']);

/* Load in the CA's cert */
$ca_cert = new \phpseclib\File\X509();
$ca_cert->loadX509($ca_str_crt);
/* get the private key to sign the new (updated) CRL */
$ca_key = new \phpseclib\Crypt\RSA();
$ca_key->loadKey($ca_str_key);
$ca_cert->setPrivateKey($ca_key);

/* Load the CA for later signature validation */
$x509_crl = new \phpseclib\File\X509();
$x509_crl->loadCA($ca_str_crt);

/*
* create empty CRL. A quirk with phpseclib is that in order to correctly sign
* a new CRL, a CA must be loaded using a separate X509 container, which is passed
* to signCRL(). However, to validate the resulting signature, the original X509
* CRL container must load the same CA using loadCA() with a direct reference
* to the CA's public cert.
*/
$x509_crl->loadCRL($x509_crl->saveCRL($x509_crl->signCRL($ca_cert, $x509_crl)));

/* Now validate the CRL to see if everything went well */
if (!$x509_crl->validateSignature(false)) {
return false;
}

if (is_array($crl['cert']) && (count($crl['cert']) > 0)) {
foreach ($crl['cert'] as $cert) {
/* load the certificate in an x509 container to get its serial number and validate its signature */
$x509_cert = new \phpseclib\File\X509();
$x509_cert->loadCA($ca_str_crt);
$raw_cert = $x509_cert->loadX509(base64_decode($cert['crt']));
if (!$x509_cert->validateSignature(false)) {
return false;
}
/* Get serial number of cert */
$sn = $raw_cert['tbsCertificate']['serialNumber']->toString();
$x509_crl->setRevokedCertificateExtension($sn, 'id-ce-cRLReasons', crl_status_code()[$cert["reason"]][1]);
}
}
$x509_crl->setSerialNumber($crl['serial'], 10);
$x509_crl->setEndDate('+' . $crl['lifetime'] . ' days');
$new_crl = $x509_crl->signCRL($ca_cert, $x509_crl);
$crl_text = $x509_crl->saveCRL($new_crl);

/* Update the CRL */
$crl['text'] = base64_encode($crl_text);
return true;
}

function cert_revoke($cert, &$crl, $reason = CERT_CRL_STATUS_UNSPECIFIED)
{
if (is_cert_revoked($cert, $crl['refid'])) {
return true;
}
// If we have text but no certs, it was imported and cannot be updated.
if (!is_crl_internal($crl)) {
return false;
}
$cert["reason"] = $reason;
$cert["revoke_time"] = time();
$crl["cert"][] = $cert;
crl_update($crl);
return true;
}


/* Compare two certificates to see if they match. */
function cert_compare($cert1, $cert2)
{
Expand Down Expand Up @@ -747,10 +661,9 @@ function is_openvpn_server_crl($crlref)
return false;
}


function is_crl_internal($crl)
{
return (!(!empty($crl['text']) && empty($crl['cert'])) || ($crl["crlmethod"] == "internal"));
return ($crl["crlmethod"] ?? '') == "internal";
}

function cert_get_cn($crt, $isref = false)
Expand Down
72 changes: 67 additions & 5 deletions src/etc/inc/config.inc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php

/*
* Copyright (C) 2015-2017 Franco Fichtner <franco@opnsense.org>
* Copyright (C) 2015-2022 Franco Fichtner <franco@opnsense.org>
* Copyright (C) 2009 Erik Kristensen <erik@erikkristensen.com>
* Copyright (C) 2004-2010 Scott Ullrich <sullrich@gmail.com>
* Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>
Expand Down Expand Up @@ -29,14 +29,58 @@
* POSSIBILITY OF SUCH DAMAGE.
*/

/* XXX make this a getter function for traceability */
$g = json_decode(file_get_contents('/usr/local/opnsense/version/core'), true);
final class product
{
private static $instance = null;
private static $data = null;

public static function getInstance(): product
{
if (self::$instance === null) {
self::$instance = new self();
}

return self::$instance;
}

private function __construct()
{
self::$data = json_decode(file_get_contents('/usr/local/opnsense/version/core'), true);

/* boot detection via exit_on_bootup() */
$bootflag = '/var/run/booting';
@touch($bootflag);
$fp = fopen($bootflag, 'r');
self::$data['product_booting'] = $fp && !flock($fp, LOCK_SH | LOCK_NB);
}

private function __clone()
{
}

public function __wakeup()
{
throw new Exception('Cannot unserialize singleton');
}

public function __call($name, $arguments)
{
if (!empty(self::$data['product_' . $name])) {
return self::$data['product_' . $name];
}
}
}

function reopenlog()
{
openlog(product::getInstance()->id(), LOG_ODELAY, LOG_USER);
}

reopenlog();

openlog($g['product_id'], LOG_ODELAY, LOG_USER);
register_shutdown_function('closelog');

require_once("xmlparse.inc");
require_once("notices.inc");
require_once("legacy_bindings.inc");
require_once("certs.inc");

Expand Down Expand Up @@ -273,6 +317,24 @@ function legacy_config_get_interfaces($filters = array())
return $interfaces;
}

/**
* legacy helper to generate a uuid in a similar fashion as the model code would.
*/
function generate_uuid()
{
return sprintf(
'%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0x0fff) | 0x4000,
mt_rand(0, 0x3fff) | 0x8000,
mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0xffff)
);
}

/**
* parse stored json content, return empty when not found or expired
*/
Expand Down
80 changes: 40 additions & 40 deletions src/etc/inc/console.inc
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,13 @@ function _set_networking_interfaces_ports($probe = false)
$interactive = true;
$key = null;

$iflist_all = get_interface_list(false, true);
$iflist = get_interface_list(false, true);
$iflist_wlan = legacy_interface_listget('wlan');
$iflist_lagg = [];
$iflist = [];
$iflist_all = [];

foreach ($iflist_all as $iface => $ifa) {
$iflist[$iface] = $ifa;
foreach ($iflist as $iface => $ifa) {
$iflist_all[$iface] = $ifa;
interfaces_bring_up($iface);
}

Expand All @@ -122,8 +123,6 @@ function _set_networking_interfaces_ports($probe = false)
}
}

$ifnames = array_keys($iflist);

if (!empty($iflist)) {
echo <<<EOD
Do you want to configure LAGGs now? ${yes_no_prompt}
Expand Down Expand Up @@ -173,18 +172,22 @@ EOD;
}
}

/* add WLAN parents now as LAGG/VLAN are not capable of handling it */
foreach ($iflist_wlan as $iface) {
$iflist_all[$iface] = [
'dmesg' => 'WLAN device parent',
'mac' => '00:00:00:00:00:00',
];
}

echo <<<EOD
Valid interfaces are:
EOD;

/*
* We are checking $iflist here for physical members only, but
* iterate over $iflist_all when that sanity check succeeded.
*/
if (empty($iflist)) {
if (empty($iflist_all)) {
echo "No interfaces found!\n";
} else {
foreach ($iflist_all as $iface => $ifa) {
Expand All @@ -200,6 +203,8 @@ hitting 'a' to initiate auto detection.
EOD;

$ifnames = array_keys($iflist_all); /* only for non-interactive mode */

do {
echo "\nEnter the WAN interface name or 'a' for auto-detection: ";

Expand All @@ -217,16 +222,16 @@ EOD;

if ($wanif == 'a') {
$wanif = autodetect_interface('WAN', $fp);
if (!$wanif) {
if ($wanif == '') {
continue;
}
}

if (!array_key_exists($wanif, $iflist_all)) {
printf("\nInvalid interface name '%s'\n", $wanif);
unset($wanif);
$wanif = '';
}
} while (!$wanif);
} while ($wanif == '');

do {
echo "\nEnter the LAN interface name or 'a' for auto-detection\n" .
Expand All @@ -247,7 +252,7 @@ EOD;

if ($lanif == 'a') {
$lanif = autodetect_interface('LAN', $fp);
if (!$lanif) {
if ($lanif == '') {
continue;
}
}
Expand All @@ -257,15 +262,15 @@ EOD;
unset($lanif);
}

if ($wanif && $lanif == $wanif) {
unset($lanif);
if ($wanif != '' && $lanif == $wanif) {
$lanif = '';
echo <<<EOD
Error: you cannot assign the same interface name twice!
EOD;
}
} while (!$lanif);
} while ($lanif == '');

$done = false;
while (!$done) {
Expand All @@ -274,15 +279,11 @@ EOD;
$i = 0;

while (1) {
if ($optif[$i]) {
if (isset($optif[$i])) {
$i++;
}
$io = $i + 1;

if ($config['interfaces']['opt' . $io]['descr']) {
printf("\nOptional interface %s description found: %s", $io, $config['interfaces']['opt' . $io]['descr']);
}

printf("\nEnter the Optional interface %s name or 'a' for auto-detection\n" .
"(or nothing if finished): ", $io);

Expand All @@ -301,12 +302,11 @@ EOD;
}

if ($optif[$i] == 'a') {
$ad = autodetect_interface('OPT' . $io, $fp);
if (!$ad) {
$optif[$i] = autodetect_interface('OPT' . $io, $fp);
if ($optif[$i] == '') {
unset($optif[$i]);
continue;
}
$optif[$i] = $ad;
}

if (!array_key_exists($optif[$i], $iflist_all)) {
Expand All @@ -316,12 +316,12 @@ EOD;
}

/* check for double assignments */
$ifarr = array_merge(array($lanif, $wanif), $optif);
$ifarr = array_merge([$lanif, $wanif], $optif);
$again = false;

for ($k = 0; $k < (count($ifarr) - 1); $k++) {
for ($j = ($k + 1); $j < count($ifarr); $j++) {
if ($ifarr[$k] == $ifarr[$j]) {
if ($ifarr[$k] != '' && $ifarr[$k] == $ifarr[$j]) {
$again = true;
echo <<<EOD
Expand Down Expand Up @@ -374,7 +374,7 @@ EOD;
* XXX Ideally, at this point we'd import the default settings here,
* not hardcode them. It was this way before, so fixing for now.
*/
if ($lanif) {
if ($lanif != '') {
$new = false;

if (!isset($config['interfaces']['lan'])) {
Expand Down Expand Up @@ -404,8 +404,9 @@ EOD;
$config['nat']['outbound']['mode'] = 'automatic';
}

if (match_wireless_interface($lanif)) {
if (in_array($config['interfaces']['lan']['if'], $iflist_wlan)) {
config_read_array('interfaces', 'lan', 'wireless');
$config['interfaces']['lan']['if'] .= '_wlan0';
} elseif (isset($config['interfaces']['lan']['wireless'])) {
unset($config['interfaces']['lan']['wireless']);
}
Expand All @@ -428,19 +429,20 @@ EOD;
unset($config['interfaces']['lan']);
}

if ($wanif) {
if ($wanif != '') {
config_read_array('interfaces', 'wan');
$config['interfaces']['wan']['if'] = $wanif;
$config['interfaces']['wan']['enable'] = true;
$config['interfaces']['wan']['ipaddr'] = 'dhcp';
$config['interfaces']['wan']['ipaddrv6'] = 'dhcp6';
$config['interfaces']['wan']['blockbogons'] = true;
if ($lanif) {
if ($lanif != '') {
$config['interfaces']['wan']['blockpriv'] = true;
}

if (match_wireless_interface($wanif)) {
if (in_array($config['interfaces']['wan']['if'], $iflist_wlan)) {
config_read_array('interfaces', 'wan', 'wireless');
$config['interfaces']['wan']['if'] .= '_wlan0';
} elseif (isset($config['interfaces']['wan']['wireless'])) {
unset($config['interfaces']['wan']['wireless']);
}
Expand All @@ -453,17 +455,14 @@ EOD;
for ($i = 0; $i < count($optif); $i++) {
config_read_array('interfaces', 'opt' . ($i + 1));
$config['interfaces']['opt' . ($i + 1)]['if'] = $optif[$i];
$config['interfaces']['opt' . ($i + 1)]['enable'] = true;

if (match_wireless_interface($optif[$i])) {
if (in_array($config['interfaces']['opt' . ($i + 1)]['if'], $iflist_wlan)) {
config_read_array('interfaces', 'opt' . ($i + 1), 'wireless');
$config['interfaces']['opt' . ($i + 1)]['if'] .= '_wlan0';
} elseif (isset($config['interfaces']['opt' . ($i + 1)]['wireless'])) {
unset($config['interfaces']['opt' . ($i + 1)]['wireless']);
}

if (empty($config['interfaces']['opt' . ($i + 1)]['descr'])) {
$config['interfaces']['opt' . ($i + 1)]['descr'] = "OPT" . ($i + 1);
unset($config['interfaces']['opt' . ($i + 1)]['enable']);
}
}

/* remove all other (old) optional interfaces */
Expand Down Expand Up @@ -508,7 +507,7 @@ EOD;

echo "No link-up detected.\n";

return false;
return '';
}

function lagg_setup($iflist, $fp)
Expand Down Expand Up @@ -644,6 +643,7 @@ EOD;
echo 'Enter the VLAN tag (1-4094): ';
$vlan['tag'] = chop(fgets($fp));
$vlan['vlanif'] = "{$vlan['if']}_vlan{$vlan['tag']}";
$vlan['@attributes'] = ['uuid' => generate_uuid()];
if (!is_numericint($vlan['tag']) || ($vlan['tag'] < 1) || ($vlan['tag'] > 4094)) {
printf("\nInvalid VLAN tag '%s'\n", $vlan['tag']);
continue;
Expand Down
206 changes: 87 additions & 119 deletions src/etc/inc/filter.inc
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,15 @@ function filter_rules_sort()
return strnatcmp($a['interface'], $b['interface']);
}
});
/* strip the sequence numbers again */
/* strip the sequence numbers again, add uuid's where not available */
for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
unset($config['filter']['rule'][$i]['seq']);
if (
empty($config['filter']['rule'][$i]['@attributes'])
&& empty($config['filter']['rule'][$i]['@attributes']['uuid'])
) {
$config['filter']['rule'][$i]['@attributes'] = ['uuid' => generate_uuid()];
}
}
}

Expand Down Expand Up @@ -145,93 +151,26 @@ function ifgroup_setup()
}
}

/**
* XXX: replace with check on interfaces section (see pf_interfaces)
*/
function is_interface_group($if)
{
global $config;

if (isset($config['ifgroups']['ifgroupentry'])) {
foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
if ($groupentry['ifname'] === $if) {
return true;
}
}
}

return false;
}

function filter_configure_sync($verbose = false, $load_aliases = true)
{
global $config;
$sched_kill_states = array(); // kill states for schedules

if ($verbose) {
echo 'Configuring firewall.';
flush();
}
service_log('Configuring firewall.', $verbose);

/* Use filter lock to not allow concurrent filter reloads during this run. */
$filterlck = lock('filter', LOCK_EX);

ifgroup_setup();
if ($verbose) {
echo '.';
flush();
}

service_log('.', $verbose);

// initialize fw plugin object
$fw = filter_core_get_initialized_plugin_system();
filter_core_bootstrap($fw);
$cnfint = iterator_to_array($fw->getInterfaceMapping());
plugins_firewall($fw);

if (isset($config['filter']['rule'])) {
// register user rules
foreach ($config['filter']['rule'] as $rule) {
// calculate a hash for this area so we can track this rule, we should replace this
// with uuid's on the rules like the new style models do eventually.
$rule_hash = OPNsense\Firewall\Util::calcRuleHash($rule);
$rule['label'] = $rule_hash;
$sched = '';
$descr = '';

if (!empty($rule['sched'])) {
$sched = "({$rule['sched']})";
}
if (!empty($rule['descr'])) {
$descr = ": {$rule['descr']}";
}

$rule['descr'] = "{$sched}{$descr}";
if (isset($rule['floating'])) {
$prio = 200000;
} elseif (is_interface_group($rule['interface']) || in_array($rule['interface'], array("l2tp", "pptp", "pppoe", "enc0", "openvpn"))) {
$prio = 300000;
} else {
$prio = 400000;
}
/* is a time based rule schedule attached? */
if (!empty($rule['sched']) && !empty($config['schedules'])) {
foreach ($config['schedules']['schedule'] as $sched) {
if ($sched['name'] == $rule['sched']) {
if (!filter_get_time_based_rule_status($sched)) {
if (!isset($config['system']['schedule_states'])) {
$sched_kill_states[] = $rule['label'];
}
/* disable rule, suffix label to mark end of schedule */
$rule['disabled'] = true;
$rule['descr'] = "[FIN]" . $rule['descr'];
}
break;
}
}
}
$fw->registerFilterRule($prio, $rule);
}
}
// register user rules, returns kill states for schedules
$sched_kill_states = filter_core_rules_user($fw);

// manual outbound nat rules
if (
Expand Down Expand Up @@ -320,10 +259,10 @@ function filter_configure_sync($verbose = false, $load_aliases = true)
$down_gateways = return_down_gateways();
foreach (array("inet", "inet6") as $ipprotocol) {
if (!empty($down_gateways)) {
log_error(sprintf("Ignore down %s gateways : %s", $ipprotocol, implode(",", $down_gateways)));
log_msg(sprintf("Ignore down %s gateways : %s", $ipprotocol, implode(",", $down_gateways)), LOG_DEBUG);
}
$default_gw = $fw->getGateways()->getDefaultGW($down_gateways, $ipprotocol);
if ($default_gw !== null) {
if ($default_gw !== null && !empty($default_gw['gateway'])) {
system_default_route(
$default_gw['gateway'],
$ipprotocol,
Expand All @@ -340,20 +279,14 @@ function filter_configure_sync($verbose = false, $load_aliases = true)
$aliases .= "\n# Plugins tables\n";
$aliases .= $fw->tablesToText();

if ($verbose) {
echo '.';
flush();
}
service_log('.', $verbose);

$natrules = "\n# NAT Redirects\n";
$natrules .= "no nat proto carp all\n";
$natrules .= "no rdr proto carp all\n";
$natrules .= $fw->outputNatRules();

if ($verbose) {
echo '.';
flush();
}
service_log('.', $verbose);

/* enable pf if we need to, otherwise disable */
if (!isset($config['system']['disablefilter'])) {
Expand All @@ -363,18 +296,14 @@ function filter_configure_sync($verbose = false, $load_aliases = true)

unlock($filterlck);
closelog();
reopenlog();

if ($verbose) {
echo "done.\n";
}
service_log("done.\n", $verbose);

return;
}

if ($verbose) {
echo '.';
flush();
}
service_log('.', $verbose);

$limitrules = '';

Expand Down Expand Up @@ -422,7 +351,7 @@ function filter_configure_sync($verbose = false, $load_aliases = true)
$limitrules .= "set limit frags {$config['system']['maximumfrags']}\n";
}

if (isset($config['system']['lb_use_sticky']) && is_numeric($config['system']['srctrack']) && ($config['system']['srctrack'] > 0)) {
if (isset($config['system']['lb_use_sticky']) && is_numeric($config['system']['srctrack'] ?? null) && ($config['system']['srctrack'] > 0)) {
$limitrules .= "set timeout src.track {$config['system']['srctrack']}\n";
}

Expand All @@ -434,6 +363,12 @@ function filter_configure_sync($verbose = false, $load_aliases = true)
$limitrules .= "set syncookies {$config['system']['syncookies']} {$arange}\n";
}

/* if pf already generated a hostid, reuse it */
$current_hostid = get_current_hostid();
if (!empty($current_hostid)) {
$limitrules .= "set hostid {$current_hostid}\n";
}

$rules = "{$limitrules}\n";
$rules .= "{$aliases} \n";
$rules .= filter_setup_logging_interfaces($cnfint);
Expand All @@ -457,13 +392,13 @@ function filter_configure_sync($verbose = false, $load_aliases = true)

if (!@file_put_contents('/tmp/rules.debug', $rules, LOCK_EX)) {
syslog(LOG_ERR, 'ERROR: Could not write new rules!');
file_put_contents('/tmp/rules.error', gettext('ERROR: Could not write new rules!'));

unlock($filterlck);
closelog();
reopenlog();

if ($verbose) {
echo "failed.\n";
}
service_log("failed.\n", $verbose);

return;
}
Expand Down Expand Up @@ -493,24 +428,19 @@ function filter_configure_sync($verbose = false, $load_aliases = true)
}
}

/* Brutal ugly hack but required -- PF is stuck, unwedge */
if (strstr("$rules_error[0]", "busy")) {
exec('/sbin/pfctl -d; /sbin/pfctl -e; /sbin/pfctl -f /tmp/rules.debug');
syslog(LOG_WARNING, 'PF was wedged/busy and has been reset.');
file_notice(gettext('PF was wedged/busy and has been reset.'));
} else {
exec('/sbin/pfctl -f /tmp/rules.debug.old 2>&1');
}
mwexec('/sbin/pfctl -f /tmp/rules.debug.old');

syslog(LOG_ERR, sprintf('There were error(s) loading the rules: %s%s', $rules_error[0], $config_line));
file_notice(sprintf(gettext('There were error(s) loading the rules: %s%s'), $rules_error[0], $config_line));
syslog(LOG_ERR, trim(sprintf('There were error(s) loading the rules: %s%s', $rules_error[0], $config_line)));
file_put_contents(
'/tmp/rules.error',
sprintf(gettext('There were error(s) loading the rules: %s%s'), $rules_error[0], $config_line)
);

unlock($filterlck);
closelog();
reopenlog();

if ($verbose) {
echo "failed.\n";
}
service_log("failed.\n", $verbose);

return;
}
Expand All @@ -524,20 +454,14 @@ function filter_configure_sync($verbose = false, $load_aliases = true)
mwexec('/sbin/pfctl -t bogonsv6 -T kill');
}

if ($verbose) {
echo '.';
flush();
}
service_log('.', $verbose);

if ($load_aliases) {
configd_run('template reload OPNsense/Filter');
configd_run('filter refresh_aliases', true);
}

if ($verbose) {
echo '.';
flush();
}
service_log('.', $verbose);

/* enable permanent promiscuous mode to avoid dmesg noise */
mwexec('/sbin/ifconfig pflog0 promisc');
Expand All @@ -548,10 +472,9 @@ function filter_configure_sync($verbose = false, $load_aliases = true)

unlock($filterlck);
closelog();
reopenlog();

if ($verbose) {
echo "done.\n";
}
service_log("done.\n", $verbose);
}

function filter_generate_scrubbing(&$FilterIflist)
Expand Down Expand Up @@ -685,7 +608,10 @@ function filter_generate_aliases()
# the configuration.
$aliases .= "{$aliased['name']} = \"{ 0 <> 65535 }\"\n";
syslog(LOG_ERR, sprintf('URL port aliases types not supported [%s]', $aliased['name']));
file_notice(sprintf(gettext('URL port aliases types not supported [%s]'), $aliased['name']));
file_put_contents(
'/tmp/rules.error',
sprintf(gettext('URL port aliases types not supported [%s]'), $aliased['name'])
);
break;
case "port":
$tmp_ports = implode(" ", filter_core_get_port_alias($aliased['name'], [], $aliasObject, $all_aliases));
Expand Down Expand Up @@ -894,6 +820,17 @@ function default_state_size()
return $max_states;
}

function get_current_hostid()
{
exec('/sbin/pfctl -si -v 2>/dev/null', $output);
foreach ($output as $line) {
if (strpos($line, 'Hostid:') !== false) {
return preg_split("/(\s+)/", $line)[1];
}
}
return null;
}

function get_protocols()
{
$protocols = array('any', 'TCP', 'UDP', 'TCP/UDP', 'ICMP', 'ESP', 'AH', 'GRE', 'IGMP', 'PIM', 'OSPF');
Expand All @@ -914,3 +851,34 @@ function get_protocols()
}
return $protocols;
}

/**
* Return array of possible TOS values
*/
function get_tos_values($blank_label = '')
{
$ret = array(
'' => $blank_label,
'lowdelay' => gettext('lowdelay'),
'critical' => gettext('critical'),
'inetcontrol' => gettext('inetcontrol'),
'netcontrol' => gettext('netcontrol'),
'throughput' => gettext('throughput'),
'reliability' => gettext('reliability'),
'ef' => 'EF',
);

foreach (array(11, 12, 13, 21, 22, 23, 31, 32, 33, 41 ,42, 43) as $val) {
$ret["af$val"] = "AF$val";
}

foreach (range(0, 7) as $val) {
$ret["cs$val"] = "CS$val";
}

foreach (range(0, 255) as $val) {
$ret['0x' . dechex($val)] = sprintf('0x%02X', $val);
}

return $ret;
}
105 changes: 74 additions & 31 deletions src/etc/inc/filter.lib.inc
Original file line number Diff line number Diff line change
Expand Up @@ -90,21 +90,13 @@ function filter_core_get_antilockout()
{
global $config;

$lockout_ports = array();
$lockout_if = null;

if (isset($config['system']['webgui']['noantilockout'])) {
return array();
return [];
}

if (!empty($config['interfaces']['lan']['if'])) {
$lockout_if = 'lan';
} elseif (!empty($config['interfaces']['opt1']['if'])) {
$lockout_if = 'opt1';
} elseif (count(get_configured_interface_with_descr()) == 1 && !empty($config['interfaces']['wan']['if'])) {
$lockout_if = 'wan';
} else {
return array();
$lockout_if = get_primary_interface_from_list(array_keys(legacy_config_get_interfaces(['virtual' => false])));
if (empty($lockout_if)) {
return [];
}

/*
Expand All @@ -118,6 +110,7 @@ function filter_core_get_antilockout()
* and no ssh has ever been configured. This is in line
* with how the plugin behaves, but probably looks odd.
*/
$lockout_ports = [];
if (empty($config['system']['webgui']['port'])) {
$lockout_ports[] = $config['system']['webgui']['protocol'] == 'https' ? '443' : '80';
} else {
Expand All @@ -134,13 +127,13 @@ function filter_core_get_antilockout()
}

if (!count($lockout_ports)) {
return array();
return [];
}

sort($lockout_ports);

/* return a convenient one-entry array to iterate over for our callers */
return array($lockout_if => $lockout_ports);
return [$lockout_if => $lockout_ports];
}

/**
Expand Down Expand Up @@ -568,23 +561,6 @@ function filter_core_rules_system($fw, $defaults)
);
}

// TODO: move to pptpd plugin when filter.lib.inc is part of the standard release
$pptpdcfg = $config['pptpd'];
if (isset($pptpdcfg['mode']) && $pptpdcfg['mode'] == 'server') {
$fw->registerFilterRule(
5,
array('direction' => 'in', 'interface' => 'wan', 'statetype' => 'modulate','protocol' => 'tcp',
'to' => '(self)', 'to_port' => '1723', 'quick' => false, 'descr' => 'allow pptpd'),
$defaults['pass']
);
$fw->registerFilterRule(
5,
array('direction' => 'in', 'interface' => 'wan', 'statetype' => 'modulate',
'protocol' => 'gre', 'descr' => 'allow pptpd', 'quick' => false),
$defaults['pass']
);
}

// [out from this Firewall, using the selected gateway].
// Our default setting has been to force traffic leaving a specific interface to use the associated gateway.
// This behaviour can be disabled, so settings can be customized using manual firewall rules.
Expand Down Expand Up @@ -620,3 +596,70 @@ function filter_core_rules_system($fw, $defaults)
}
}
}

/**
* register user rules, returns kill states for schedules
*/
function filter_core_rules_user($fw)
{
global $config;

$sched_kill_states = [];

$ifgroups = ["l2tp", "pptp", "pppoe", "enc0", "openvpn"];
if (isset($config['ifgroups']['ifgroupentry'])) {
foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
$ifgroups[] = $groupentry['ifname'];
}
}

if (isset($config['filter']['rule'])) {
// register user rules
foreach ($config['filter']['rule'] as $idx => $rule) {
// calculate a hash for this area so we can track this rule, we should replace this
// with uuid's on the rules like the new style models do eventually.
$rule['label'] = OPNsense\Firewall\Util::calcRuleHash($rule);

$intf = !empty($rule['floating']) ? 'FloatingRules' : $rule['interface'];
$rule['#ref'] = sprintf('firewall_rules_edit.php?if=%s&id=%s', $intf, $idx);
$rule['seq'] = $idx; // current rule sequence (used as id in firewall pages)
$sched = '';
$descr = '';

if (!empty($rule['sched'])) {
$sched = "({$rule['sched']})";
}
if (!empty($rule['descr'])) {
$descr = ": {$rule['descr']}";
}

$rule['descr'] = "{$sched}{$descr}";
if (isset($rule['floating'])) {
$prio = 200000;
} elseif (in_array($rule['interface'], $ifgroups)) {
$prio = 300000;
} else {
$prio = 400000;
}
/* is a time based rule schedule attached? */
if (!empty($rule['sched']) && !empty($config['schedules'])) {
foreach ($config['schedules']['schedule'] as $sched) {
if ($sched['name'] == $rule['sched']) {
if (!filter_get_time_based_rule_status($sched)) {
if (!isset($config['system']['schedule_states'])) {
$sched_kill_states[] = $rule['label'];
}
/* disable rule, suffix label to mark end of schedule */
$rule['disabled'] = true;
$rule['descr'] = "[FIN]" . $rule['descr'];
}
break;
}
}
}
$fw->registerFilterRule($prio, $rule);
}
}

return $sched_kill_states;
}
745 changes: 354 additions & 391 deletions src/etc/inc/interfaces.inc

Large diffs are not rendered by default.

199 changes: 166 additions & 33 deletions src/etc/inc/interfaces.lib.inc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php

/*
* Copyright (c) 2015-2021 Franco Fichtner <franco@opnsense.org>
* Copyright (c) 2015-2022 Franco Fichtner <franco@opnsense.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand All @@ -26,12 +26,23 @@
* POSSIBILITY OF SUCH DAMAGE.
*/

function legacy_interface_listget($flag = '')
function legacy_interface_error($cmd, $opt = null)
{
$msg = 'The command `' . $cmd . '\' failed to execute';

if ($opt !== null) {
$msg .= " ({$opt})";
}

log_msg($msg, LOG_ERR);
}

function legacy_interface_listget($flag = 'all')
{
$cmd_wlan = 'sysctl -n net.wlan.devices';
$cmd = '/sbin/ifconfig -l';
$ifs_wlan = null;
$ifs = null;
$ifs_wlan = [];
$ifs = [];

exec($cmd_wlan . ' 2>&1', $out_wlan, $ret_wlan);
if (!$ret_wlan && !empty($out_wlan[0])) {
Expand All @@ -40,21 +51,21 @@ function legacy_interface_listget($flag = '')

if ($flag === 'up') {
$cmd .= 'u';
} elseif ($flag === 'down') {
$cmd .= 'd';
} elseif ($flag === 'wlan') {
return ($ifs_wlan);
}

exec($cmd . ' 2>&1', $out, $ret);
if ($ret) {
log_error('The command `' . $cmd . '\' failed to execute');
legacy_interface_error($cmd);
return ($ifs);
}

if (isset($out[0])) {
$ifs = explode(' ', $out[0]);
}

if ($ifs_wlan != null) {
if (count($ifs_wlan)) {
$ifs = array_merge($ifs, $ifs_wlan);
}

Expand All @@ -68,7 +79,7 @@ function legacy_interface_flags($ifs, $flag, $report_errors = true)

exec($cmd . ' 2>&1', $out, $ret);
if (!empty($ret) && $report_errors) {
log_error('The command `' . $cmd . '\' failed to execute');
legacy_interface_error($cmd);
}
}

Expand All @@ -79,7 +90,7 @@ function legacy_interface_create($ifs, $name = null)

exec($cmd . ' 2>&1', $out, $ret);
if ($ret) {
log_error('The command `' . $cmd . '\' failed to execute');
legacy_interface_error($cmd);
return ($new);
}

Expand All @@ -92,7 +103,7 @@ function legacy_interface_create($ifs, $name = null)

exec($cmd . ' 2>&1', $out, $ret);
if ($ret) {
log_error('The command `' . $cmd . '\' failed to execute');
legacy_interface_error($cmd);
}

/* return new name here anyway to force proper device not found errors later */
Expand All @@ -109,7 +120,7 @@ function legacy_interface_destroy($ifs)
exec($cmd . ' 2>&1', $out, $ret);
if ($ret) {
/* disable error reporting to avoid spurious errors on first configuration */
//log_error('The command `' . $cmd . '\' failed to execute');
//legacy_interface_error($cmd);
}
}

Expand All @@ -119,7 +130,7 @@ function legacy_interface_setaddress($ifs, $addr, $family = 4)

exec($cmd . ' 2>&1', $out, $ret);
if ($ret) {
log_error('The command `' . $cmd . '\' failed to execute');
legacy_interface_error($cmd);
}
}

Expand All @@ -129,7 +140,7 @@ function legacy_interface_deladdress($ifs, $addr, $family = 4)

exec($cmd . ' 2>&1', $out, $ret);
if ($ret) {
log_error('The command `' . $cmd . '\' failed to execute');
legacy_interface_error($cmd);
}
}

Expand All @@ -139,7 +150,7 @@ function legacy_interface_mtu($ifs, $mtu)

exec($cmd . ' 2>&1', $out, $ret);
if ($ret) {
log_error('The command `' . $cmd . '\' failed to execute');
legacy_interface_error($cmd);
}
}

Expand All @@ -149,17 +160,17 @@ function legacy_bridge_member($ifs, $member)

exec($cmd . ' 2>&1', $out, $ret);
if ($ret) {
log_error('The command `' . $cmd . '\' failed to execute');
legacy_interface_error($cmd);
}
}

function legacy_vlan_tag($ifs, $member, $tag, $pcp)
function legacy_vlan_tag($ifs, $member, $tag, $pcp, $proto)
{
$cmd = '/sbin/ifconfig ' . escapeshellarg($ifs) . ' vlandev ' . escapeshellarg($member) . ' vlan ' . escapeshellarg($tag) . ' vlanpcp ' . escapeshellarg($pcp);
$cmd = '/sbin/ifconfig ' . escapeshellarg($ifs) . ' vlan ' . escapeshellarg($tag) . ' vlandev ' . escapeshellarg($member) . ' vlanpcp ' . escapeshellarg($pcp) . ' vlanproto ' . escapeshellarg($proto);

exec($cmd . ' 2>&1', $out, $ret);
if ($ret) {
log_error('The command `' . $cmd . '\' failed to execute');
legacy_interface_error($cmd);
}
}

Expand All @@ -169,7 +180,7 @@ function legacy_vlan_remove_tag($ifs)

exec($cmd . ' 2>&1', $out, $ret);
if ($ret) {
log_error('The command `' . $cmd . '\' failed to execute');
legacy_interface_error($cmd);
}
}

Expand All @@ -179,7 +190,17 @@ function legacy_vlan_pcp($ifs, $pcp)

exec($cmd . ' 2>&1', $out, $ret);
if ($ret) {
log_error('The command `' . $cmd . '\' failed to execute');
legacy_interface_error($cmd);
}
}

function legacy_vlan_proto($ifs, $proto)
{
$cmd = '/sbin/ifconfig ' . escapeshellarg($ifs) . ' vlanproto ' . escapeshellarg($proto);

exec($cmd . ' 2>&1', $out, $ret);
if ($ret) {
legacy_interface_error($cmd);
}
}

Expand All @@ -196,7 +217,7 @@ function legacy_interface_stats($ifs = null)

exec($cmd . ' 2>&1', $out, $ret);
if ($ret) {
log_error('The command `' . $cmd . '\' failed to execute');
legacy_interface_error($cmd);
return $stats;
}

Expand Down Expand Up @@ -236,7 +257,7 @@ function legacy_interfaces_details($intf = null)
if ($ret) {
/* only error if no explicit interface was chosen */
if (empty($intf)) {
log_error('The command `' . $cmd . '\' failed to execute ' . implode(' ', $ifconfig_data));
legacy_interface_error($cmd, implode(' ', $ifconfig_data));
}
return $result;
}
Expand Down Expand Up @@ -269,7 +290,7 @@ function legacy_interfaces_details($intf = null)
foreach (explode(',', $capabilities) as $capability) {
$result[$current_interface]["capabilities"][] = strtolower(trim($capability));
}
} elseif (strpos(trim($line), 'options=') !== false) {
} elseif (strpos(trim($line), 'options=') === 0) {
// parse options
$options = substr($line, strpos($line, '<') + 1, -1);
foreach (explode(',', $options) as $option) {
Expand Down Expand Up @@ -306,7 +327,7 @@ function legacy_interfaces_details($intf = null)
$tmp = [
'deprecated' => false,
'ipaddr' => $addr,
'link-local' => strpos($addr, 'fe80:') === 0,
'link-local' => preg_match('/^fe[89ab][0-9a-f]:/i', $addr),
'tentative' => false,
'tunnel' => false,
];
Expand Down Expand Up @@ -412,7 +433,9 @@ function legacy_interfaces_details($intf = null)
$result[$current_interface]["vxlan"]["local"] = $line_parts[4];
if ($line_parts[5] == "group") {
$result[$current_interface]["vxlan"]["group"] = $line_parts[6];
$result[$current_interface]['vxlan']['remote'] = null;
} else {
$result[$current_interface]['vxlan']['group'] = null;
$result[$current_interface]["vxlan"]["remote"] = $line_parts[6];
}
}
Expand Down Expand Up @@ -448,7 +471,12 @@ function configure_interface_hardware($ifs, $intf_details = null)

$hwsettings = $config['system'];

if (strstr($ifs, 'vlan') || strstr($ifs, 'qinq') || strpos($ifs, '/') === 0) {
/* XXX this needs fixing, lots of devices are not capable */
if (
strstr($ifs, 'vlan') || strpos($ifs, 'qinq') === 0 ||
strpos($ifs, 'lo') === 0 || strpos($ifs, 'vxlan') === 0 ||
strpos($ifs, 'ipsec') === 0 || strpos($ifs, '/') === 0
) {
/* skip checksumming */
return;
}
Expand Down Expand Up @@ -506,13 +534,11 @@ function configure_interface_hardware($ifs, $intf_details = null)
if (!isset($hwsettings['disablevlanhwfilter']) || $hwsettings['disablevlanhwfilter'] == 1) {
// probe already selected options
$selected_opts = [];
if (!empty($intf_details['options'])) {
foreach ($intf_details['options'] as $opt) {
if ($opt == 'vlan_hwtagging') {
$selected_opts[] = 'vlanhwtag';
} else {
$selected_opts[] = str_replace('_', '', $opt);
}
foreach ($intf_details['options'] as $opt) {
if ($opt == 'vlan_hwtagging') {
$selected_opts[] = 'vlanhwtag';
} else {
$selected_opts[] = str_replace('_', '', $opt);
}
}
// set one tag at a time to avoid driver issues
Expand All @@ -526,3 +552,110 @@ function configure_interface_hardware($ifs, $intf_details = null)
}
}
}

/*
* get_interface_list() - Return a list of all physical interfaces
* along with MAC, IPv4 and status.
*
* $only_active = false -- interfaces that are available in the system
* true -- interfaces that are physically connected
*
* $include_dmesg = false -- skip probing dmesg for more information
* true -- probe dmesg for more information
*/
function get_interface_list($only_active = false, $include_dmesg = false)
{
$dmesg_arr = [];
$iflist = [];

if ($include_dmesg) {
exec('/sbin/dmesg', $dmesg_arr);
}

/* XXX list of virtual interface types, device 'pattern' actually registers them */
$vfaces = [
'_stf',
'_vlan',
'_wlan',
'bridge',
'carp',
'enc',
'gif',
'gre',
'ipfw', /* ipfw logging device, not enabled by default */
'ipsec',
'l2tp',
'lagg',
'lo',
'ng',
'ovpnc',
'ovpns',
'pflog',
'pfsync',
'plip',
'ppp',
'pppoe',
'pptp',
'qinq',
'tap',
'tun',
'vlan',
'vxlan',
];

$ifnames_wlan = legacy_interface_listget('wlan');
$ifnames_up = legacy_interface_listget('up');
$ifnames = legacy_interface_listget();

$all_interfaces = legacy_config_get_interfaces(['virtual' => false]);
$all_interface_data = legacy_interfaces_details();

if ($only_active) {
$_ifnames = [];
$all_stats = legacy_interface_stats();
foreach ($ifnames as $ifname) {
$ifinfo = $all_stats[$ifname];
if (!empty($ifinfo['link state']) && $ifinfo['link state'] == '2') {
$_ifnames[] = $ifname;
}
}
$ifnames = $_ifnames;
}

foreach ($ifnames as $ifname) {
$tmp_ifnames = preg_split('/\d+/', $ifname);
if (count(array_intersect($tmp_ifnames, $vfaces))) {
continue;
}
if (in_array($ifname, $ifnames_wlan)) {
continue;
}

$ifdata = !empty($all_interface_data[$ifname]) ? $all_interface_data[$ifname] : [];
$toput = [
'up' => in_array($ifname, $ifnames_up),
'ipaddr' => !empty($ifdata['ipv4'][0]['ipaddr']) ? $ifdata['ipv4'][0]['ipaddr'] : null,
'mac' => !empty($ifdata['macaddr']) ? $ifdata['macaddr'] : null,
'dmesg' => '',
];

foreach ($all_interfaces as $name => $int) {
if ($int['if'] == $ifname) {
$toput['friendly'] = $name;
break;
}
}

foreach ($dmesg_arr as $dmesg_line) {
$dmesg = [];
if (preg_match("/^{$ifname}: <(.*?)>/i", $dmesg_line, $dmesg) == 1) {
$toput['dmesg'] = $dmesg[1];
break;
}
}

$iflist[$ifname] = $toput;
}

return $iflist;
}
95 changes: 0 additions & 95 deletions src/etc/inc/notices.inc

This file was deleted.

30 changes: 14 additions & 16 deletions src/etc/inc/plugins.inc
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,11 @@ function plugins_interfaces()
}
// traverse and diff interface properties with known configuration
foreach ($intf_data as $prop_name => $prop_value) {
if ((empty($intf_config[$prop_name]) && !empty($prop_value)) || $intf_config[$prop_name] != $prop_value) {
if ((empty($intf_config[$prop_name]) && !empty($prop_value)) || ($intf_config[$prop_name] ?? '') != $prop_value) {
if (is_array($prop_value) && !count($prop_value) && isset($intf_config[$prop_name]) && $intf_config[$prop_name] === '') {
/* if value is '' in config and property is [] force a match (OpenVPN group networks) */
continue;
}
$intf_config[$prop_name] = $prop_value;
$changed = true;
}
Expand Down Expand Up @@ -244,11 +248,11 @@ function plugins_firewall($fw)
return $fw;
}

function plugins_configure($hook, $verbose = false, $args = array())
function plugins_configure($hook, $verbose = false, $args = [])
{
array_unshift($args, $verbose);

syslog(LOG_NOTICE, sprintf('plugins_configure %s (%s)', $hook, implode(',', $args)));
log_msg(sprintf('plugins_configure %s (%s)', $hook, implode(',', $args)), LOG_INFO);

foreach (plugins_scan() as $name => $path) {
try {
Expand Down Expand Up @@ -278,12 +282,12 @@ function plugins_configure($hook, $verbose = false, $args = array())
if ($argc > count($args)) {
$argc = count($args);
}
syslog(LOG_NOTICE, sprintf(
log_msg(sprintf(
'plugins_configure %s (execute task : %s(%s))',
$hook,
$argf,
implode(',', array_slice($args, 0, $argc))
));
), LOG_DEBUG);
try {
call_user_func_array($argf, array_slice($args, 0, $argc));
} catch (\Error $e) {
Expand All @@ -296,13 +300,10 @@ function plugins_configure($hook, $verbose = false, $args = array())
}
}

function plugins_run($hook, $verbose = false, $args = array())
function plugins_run($hook, $args = [])
{
array_unshift($args, $verbose);
$ret = [];

syslog(LOG_DEBUG, sprintf('plugins_run %s (%s)', $hook, implode(',', $args)));

foreach (plugins_scan() as $name => $path) {
try {
include_once $path;
Expand Down Expand Up @@ -330,14 +331,11 @@ function plugins_run($hook, $verbose = false, $args = array())
if ($argc > count($args)) {
$argc = count($args);
}
syslog(LOG_DEBUG, sprintf(
'plugins_run %s (execute task : %s(%s))',
$hook,
$argf,
implode(',', array_slice($args, 0, $argc))
));
try {
$ret[$name] = call_user_func_array($argf, array_slice($args, 0, $argc));
$result = call_user_func_array($argf, array_slice($args, 0, $argc));
if (!empty($result)) {
$ret[$name] = $result;
}
} catch (\Error $e) {
error_log($e);
}
Expand Down
172 changes: 140 additions & 32 deletions src/etc/inc/plugins.inc.d/core.inc
Original file line number Diff line number Diff line change
Expand Up @@ -131,62 +131,162 @@ function core_services()
return $services;
}

function core_device_names($key, $sections)
{
$names = [];

foreach (call_user_func_array('config_read_array', $sections) as $dev) {
$names[] = $dev[$key];
}

return $names;
}

function core_devices()
{
$devices = [];

$bridge_names = [];

foreach (config_read_array('bridges', 'bridged') as $dev) {
$bridge_names[$dev['bridgeif']] = [
'descr' => sprintf('%s (%s)', $dev['bridgeif'], $dev['descr']),
'ifdescr' => sprintf('%s', $dev['descr']),
'name' => $dev['bridgeif'],
];
}

$devices[] = [
'names' => core_device_names('bridgeif', ['bridges', 'bridged']),
'function' => 'interfaces_bridge_configure',
'names' => $bridge_names,
'pattern' => '^bridge',
'volatile' => true,
'type' => 'bridge',
];

$gif_names = [];

foreach (config_read_array('gifs', 'gif') as $dev) {
$gif_names[$dev['gifif']] = [
'descr' => sprintf('%s %s (%s)', $dev['gifif'], $dev['remote-addr'], $dev['descr']),
'ifdescr' => sprintf('%s', $dev['descr']),
'name' => $dev['gifif'],
];
}

$devices[] = [
'names' => core_device_names('gifif', ['gifs', 'gif']),
'function' => 'interfaces_gif_configure',
'configurable' => false,
'names' => $gif_names,
'pattern' => '^gif',
'volatile' => true,
'type' => 'gif',
];

$gre_names = [];

foreach (config_read_array('gres', 'gre') as $dev) {
$gre_names[$dev['greif']] = [
'descr' => sprintf('%s %s (%s)', $dev['greif'], $dev['remote-addr'], $dev['descr']),
'ifdescr' => sprintf('%s', $dev['descr']),
'name' => $dev['greif'],
];
}

$devices[] = [
'names' => core_device_names('greif', ['gres', 'gre']),
'function' => 'interfaces_gre_configure',
'configurable' => false,
'names' => $gre_names,
'pattern' => '^gre',
'volatile' => true,
'type' => 'gre',
];

# XXX is a plugin collection...
$devices[] = array('pattern' => '^cua', 'volatile' => true);
$devices[] = array('pattern' => '^l2tp', 'volatile' => true);
$devices[] = array('pattern' => '^lagg', 'volatile' => true);
$devices[] = array('pattern' => '^ocvpn', 'volatile' => true);
$devices[] = array('pattern' => '^ppp', 'volatile' => true);
$devices[] = array('pattern' => '^pptp', 'volatile' => true);
$devices[] = array('pattern' => '^tinc', 'volatile' => true);
$devices[] = array('pattern' => '^tun|^tap', 'volatile' => true);
$devices[] = array('pattern' => '^ue', 'volatile' => true);
$devices[] = array('pattern' => '^wg', 'volatile' => true);
$devices[] = array('pattern' => '^zt', 'volatile' => true);
$devices[] = array('pattern' => '_stf', 'volatile' => true);
$devices[] = array('pattern' => '_vlan|^vlan|^qinq', 'volatile' => true);
$devices[] = array('pattern' => '_wlan', 'volatile' => true);
$lagg_names = [];

foreach (config_read_array('laggs', 'lagg') as $dev) {
$lagg_names[$dev['laggif']] = [
'descr' => sprintf('%s (%s)', $dev['laggif'], $dev['descr']),
'ifdescr' => sprintf('%s', $dev['descr']),
'exclude' => explode(',', $dev['members']),
'name' => $dev['laggif'],
];
}

$devices[] = [
'names' => $lagg_names,
'pattern' => '^lagg',
'volatile' => true,
'type' => 'lagg',
];

$ppp_names = [];

foreach (config_read_array('ppps', 'ppp') as $dev) {
$ppp_names[$dev['if']] = [
'descr' => sprintf('%s (%s) - %s %s', $dev['if'], $dev['ports'], $dev['descr'], $dev['username']),
'ifdescr' => sprintf('%s', $dev['descr']),
'ipaddr' => $dev['type'],
'name' => $dev['if'],
];
}

$devices[] = [
'pattern' => '^cua|^l2tp|^ppp|^pptp', /* XXX ^cua likely doesn't match since it's a /dev node */
'names' => $ppp_names,
'volatile' => true,
'type' => 'ppp',
];

$vlan_names = [];

foreach (config_read_array('vlans', 'vlan') as $dev) {
$vlan_names[$dev['vlanif']] = [
'descr' => sprintf(gettext('%s %s (Parent: %s, Tag: %s)'), $dev['vlanif'], $dev['descr'], $dev['if'], $dev['tag']),
'ifdescr' => sprintf('%s', $dev['descr']),
'name' => $dev['vlanif'],
];
}

$devices[] = [
'pattern' => '_vlan|^vlan|^qinq',
'names' => $vlan_names,
'volatile' => true,
'type' => 'vlan',
];

$wlan_names = [];

foreach (config_read_array('wireless', 'clone') as $dev) {
$wlan_names[$dev['cloneif']] = [
'descr' => sprintf('%s (%s)', $dev['cloneif'], $dev['descr']),
'ifdescr' => sprintf('%s', $dev['descr']),
'name' => $dev['cloneif'],
];
}

/* also need to find implied clones that do not have explicit cloneif set */
foreach (legacy_config_get_interfaces() as $id => $conf) {
if (isset($conf['wireless']) && !isset($wlan_names[$conf['if']])) {
$wlan_names[$conf['if']] = [
'descr' => sprintf('%s (%s)', $conf['if'], gettext('wireless clone')),
'ifdescr' => gettext('wireless clone'),
'name' => $conf['if'],
];

$realif = get_real_interface($id);
if ($realif == $conf['if']) {
continue;
}

/* return both implicit and explicit clone if implicit clone was given */
$wlan_names[$realif] = [
'descr' => sprintf('%s (%s)', $realif, gettext('wireless clone')),
'ifdescr' => gettext('wireless clone'),
'name' => $realif,
];
}
}

$devices[] = [
'function' => 'interfaces_wlan_clone',
'names' => $wlan_names,
'pattern' => '_wlan',
'volatile' => true,
'type' => 'wlan',
];

/* historic handling of tunnel devices and other unstable things */
$devices[] = ['pattern' => '_stf|^tap|^tun|^ue', 'volatile' => true];

return $devices;
}
Expand Down Expand Up @@ -375,9 +475,17 @@ function core_xmlrpc_sync()

function core_configure()
{
return array(
'user_changed' => array('core_user_changed_groups:2'),
);
return [
'dns_reload' => ['system_resolvconf_generate', 'system_hosts_generate'],
'user_changed' => ['core_user_changed_groups:2'],
];
}

function core_run()
{
return [
'host_routes' => 'system_resolvconf_host_routes',
];
}

/**
Expand Down
153 changes: 65 additions & 88 deletions src/etc/inc/plugins.inc.d/dhcpd.inc

Large diffs are not rendered by default.

11 changes: 3 additions & 8 deletions src/etc/inc/plugins.inc.d/dnsmasq.inc
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ function dnsmasq_configure()
'dns' => array('dnsmasq_configure_do'),
'hosts' => array('dnsmasq_hosts_generate:0'),
'local' => array('dnsmasq_configure_do'),
'newwanip' => array('dnsmasq_configure_do'),
);
}

Expand Down Expand Up @@ -99,10 +100,7 @@ function dnsmasq_configure_do($verbose = false)
return;
}

if ($verbose) {
echo 'Starting Dnsmasq DNS...';
flush();
}
service_log('Starting Dnsmasq DNS...', $verbose);

$args = '';
if (!isset($config['system']['webgui']['nodnsrebindcheck'])) {
Expand Down Expand Up @@ -177,7 +175,6 @@ function dnsmasq_configure_do($verbose = false)

if (isset($config['dnsmasq']['dnssec'])) {
$args .= ' --dnssec ';
$args .= ' --trust-anchor=.,19036,8,2,49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5 ';
$args .= ' --trust-anchor=.,20326,8,2,E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D ';
}

Expand All @@ -200,9 +197,7 @@ function dnsmasq_configure_do($verbose = false)

_dnsmasq_dhcpleases_start();

if ($verbose) {
echo "done.\n";
}
service_log("done.\n", $verbose);
}

function _dnsmasq_add_host_entries()
Expand Down
181 changes: 90 additions & 91 deletions src/etc/inc/plugins.inc.d/dpinger.inc
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,12 @@ function dpinger_services()
continue;
}

$pconfig = array();
$pconfig = [];
$pconfig['description'] = sprintf(gettext('Gateway Monitor (%s)'), $gateway['name']);
$pconfig['php']['restart'] = array('dpinger_configure_do');
$pconfig['php']['start'] = array('dpinger_configure_do');
$pconfig['php']['restart'] = ['dpinger_configure_do'];
$pconfig['php']['start'] = ['dpinger_configure_do'];
$pconfig['pidfile'] = "/var/run/dpinger_{$gateway['name']}.pid";
$pconfig['php']['args'] = array('verbose', 'id');
$pconfig['php']['args'] = ['verbose', 'id'];
$pconfig['name'] = 'dpinger';
$pconfig['verbose'] = false;
$pconfig['id'] = $gateway['name'];
Expand Down Expand Up @@ -96,13 +96,68 @@ function dpinger_syslog()
return $logfacilities;
}

function dpinger_configure_do($verbose = false, $gwname = null, $bootup = false)
function dpinger_host_routes()
{
if ($verbose) {
echo 'Setting up gateway monitors...';
flush();
$routes = [];

foreach (dpinger_instances() as $gateway) {
if (isset($gateway['monitor_noroute'])) {
/* no need to register */
continue;
} elseif (empty($gateway['gateway'])) {
/* previously reported as empty */
continue;
} elseif (isset($routes[$gateway['monitor']])) {
log_msg("Duplicated monitor route ignored for {$gateway['monitor']} on {$gateway['interface']}", LOG_WARNING);
continue;
}

$routes[$gateway['monitor']] = $gateway['gateway'];
}

return $routes;
}

function dpinger_instances($ifconfig_details = null)
{
$instances = [];

$gateways = new \OPNsense\Routing\Gateways($ifconfig_details ?? legacy_interfaces_details());

foreach ($gateways->gatewaysIndexedByName(true) as $name => $gateway) {
if (empty($gateway['monitor'])) {
/* skip monitors not currently attached */
continue;
} elseif (isset($gateway['disabled']) || isset($gateway['monitor_disable'])) {
/* do not monitor if such was requested */
continue;
}

/*
* If gateway is a local link and 'monitor' is global routable
* then the ICMP6 response would not find its way back home.
*/
if (is_linklocal($gateway['monitor']) && strpos($gateway['monitor'], '%') === false) {
$gateway['monitor'] .= '%' . get_real_interface($gateway['interface'], 'inet6');
}
if (!empty($gateway['gateway'])) {
if (is_linklocal($gateway['gateway']) && strpos($gateway['gateway'], '%') === false) {
$gateway['gateway'] .= '%' . get_real_interface($gateway['interface'], 'inet6');
}
} else {
log_msg("Gateway currently empty for {$gateway['monitor']} on {$gateway['interface']}");
}

$instances[$name] = $gateway;
}

return $instances;
}

function dpinger_configure_do($verbose = false, $gwname = null, $bootup = false)
{
service_log(sprintf('Setting up gateway monitor%s...', empty($gwname) ? 's' : " {$gwname}"), $verbose);

foreach (dpinger_processes() as $running_gwname => $process) {
if (!empty($gwname) && $running_gwname != $gwname) {
continue;
Expand All @@ -113,21 +168,16 @@ function dpinger_configure_do($verbose = false, $gwname = null, $bootup = false)
}

$ifconfig_details = legacy_interfaces_details();
$gateways = new \OPNsense\Routing\Gateways($ifconfig_details);
$monitor_ips = array();

$dpinger_default = dpinger_defaults();
foreach ($gateways->gatewaysIndexedByName(true) as $name => $gateway) {
$routes = [];

foreach (dpinger_instances($ifconfig_details) as $name => $gateway) {
if (!empty($gwname) && $gwname != $name) {
continue;
} elseif (empty($gateway['monitor'])) {
log_error(sprintf('The %s monitor address is empty, skipping.', $name));
continue;
} elseif (in_array($gateway['monitor'], $monitor_ips)) {
log_error(sprintf('The %s monitor address "%s" cannot be used twice, skipping.', $name, $gateway['monitor']));
continue;
}

$gwifip = null;

/*
* Interface IP is needed since dpinger will bind a socket to it.
* However the config GUI should already have checked this and when
Expand All @@ -137,9 +187,7 @@ function dpinger_configure_do($verbose = false, $gwname = null, $bootup = false)
* "dynamic" case) are present inside the if block. So using
* $gateway['ipprotocol'] is the better option.
*/
if ($gateway['ipprotocol'] == "inet") { // This is an IPv4 gateway...
$gwifip = null;

if ($gateway['ipprotocol'] == 'inet') {
if (is_ipaddrv4($gateway['gateway'])) {
foreach (interfaces_addresses($gateway['interface'], false, $ifconfig_details) as $addr) {
/* explicitly do not require $addr['alias'] to be true here */
Expand All @@ -156,50 +204,26 @@ function dpinger_configure_do($verbose = false, $gwname = null, $bootup = false)
}
}

if ($gwifip == null) {
if (empty($gwifip)) {
list ($gwifip) = interfaces_primary_address($gateway['interface'], $ifconfig_details);
if (!empty($gwifip) && is_ipaddrv4($gateway['gateway'])) {
log_error(sprintf('Chose to bind %s on %s since we could not find a proper match.', $name, $gwifip));
log_msg(sprintf('Chose to bind %s on %s since we could not find a proper match.', $name, $gwifip));
}
}

if (empty($gwifip)) {
log_error(sprintf('The required %s IPv4 interface address could not be found, skipping.', $name));
continue;
}

/* flush the monitor unconditionally */
if (is_ipaddrv4($gateway['gateway']) && $gateway['monitor'] != $gateway['gateway']) {
log_error("Removing static route for monitor {$gateway['monitor']} via {$gateway['gateway']}");
system_host_route($gateway['monitor'], $gateway['gateway'], true, false);
}

/* Do not monitor if such was requested */
if (isset($gateway['disabled']) || isset($gateway['monitor_disable'])) {
log_msg(sprintf('The required %s IPv4 interface address could not be found, skipping.', $name), LOG_WARNING);
continue;
}

/*
* If the gateway is the same as the monitor we do not add a
* route as this will break the routing table.
* Add static routes for each gateway with their monitor IP
* not strictly necessary but is an added level of protection.
*/
if (is_ipaddrv4($gateway['gateway']) && $gateway['monitor'] != $gateway['gateway']) {
log_error("Adding static route for monitor {$gateway['monitor']} via {$gateway['gateway']}");
system_host_route($gateway['monitor'], $gateway['gateway'], false, true);
}
} elseif ($gateway['ipprotocol'] == "inet6") { // This is an IPv6 gateway...
$gwifip = null;

} elseif ($gateway['ipprotocol'] == 'inet6') {
if (is_linklocal($gateway['monitor'])) {
/* link local monitor needs a link local address for the "src" part */
list ($gwifip) = interfaces_scoped_address6($gateway['interface'], $ifconfig_details);
} else {
list ($gwifip) = interfaces_primary_address6($gateway['interface'], $ifconfig_details);
}

if ($gwifip == null && is_ipaddrv6($gateway['gateway'])) {
if (empty($gwifip) && is_ipaddrv6($gateway['gateway'])) {
foreach (interfaces_addresses($gateway['interface'], false, $ifconfig_details) as $addr) {
if ($addr['family'] != 'inet6' || !$addr['alias']) {
continue;
Expand All @@ -215,47 +239,23 @@ function dpinger_configure_do($verbose = false, $gwname = null, $bootup = false)
}

if (empty($gwifip)) {
log_error(sprintf('The required %s IPv6 interface address could not be found, skipping.', $name));
log_msg(sprintf('The required %s IPv6 interface address could not be found, skipping.', $name), LOG_WARNING);
continue;
}

/*
* If gateway is a local link and 'monitor' is global routable
* then the ICMP6 response would not find its way back home.
*/
if (is_linklocal($gateway['monitor']) && strpos($gateway['monitor'], '%') === false) {
$gateway['monitor'] .= '%' . get_real_interface($gateway['interface'], 'inet6');
}
if (is_linklocal($gateway['gateway']) && strpos($gateway['gateway'], '%') === false) {
$gateway['gateway'] .= '%' . get_real_interface($gateway['interface'], 'inet6');
}

/* flush the monitor unconditionally */
if (is_ipaddrv6($gateway['gateway']) && $gateway['monitor'] != $gateway['gateway']) {
log_error("Removing static route for monitor {$gateway['monitor']} via {$gateway['gateway']}");
system_host_route($gateway['monitor'], $gateway['gateway'], true, false);
}

/* Do not monitor if such was requested */
if (isset($gateway['disabled']) || isset($gateway['monitor_disable'])) {
continue;
}

/*
* If the gateway is the same as the monitor we do not add a
* route as this will break the routing table.
* Add static routes for each gateway with their monitor IP
* not strictly necessary but is an added level of protection.
*/
if (is_ipaddrv6($gateway['gateway']) && $gateway['monitor'] != $gateway['gateway']) {
log_error("Adding static route for monitor {$gateway['monitor']} via {$gateway['gateway']}");
system_host_route($gateway['monitor'], $gateway['gateway'], false, true);
}
} else {
log_error(sprintf('Unknown address family "%s" during monitor setup', $gateway['ipprotocol']));
log_msg(sprintf('Unknown address family "%s" during monitor setup', $gateway['ipprotocol']), LOG_ERR);
continue;
}

if (!empty($gateway['gateway']) && !isset($gateway['monitor_noroute'])) {
if (isset($routes[$gateway['monitor']])) {
log_msg("Duplicated monitor route ignored for {$gateway['monitor']} on {$gateway['interface']}", LOG_WARNING);
} else {
system_host_route($gateway['monitor'], $gateway['gateway']);
$routes[$gateway['monitor']] = $gateway['gateway'];
}
}

/*
* Create custom RRD graph with suitable settings that
* may differ from the daemon's standards.
Expand Down Expand Up @@ -307,19 +307,18 @@ function dpinger_configure_do($verbose = false, $gwname = null, $bootup = false)
mwexec_bg("/usr/local/bin/dpinger -f {$params}");
}

if ($verbose) {
echo "done.\n";
}
service_log("done.\n", $verbose);
}

function dpinger_run()
{
return array(
return [
'host_routes' => 'dpinger_host_routes',
'return_gateways_status' => 'dpinger_status',
);
];
}

function dpinger_status($verbose = false)
function dpinger_status()
{
$status = array();
$gateways_arr = array();
Expand Down
1,470 changes: 688 additions & 782 deletions src/etc/inc/plugins.inc.d/ipsec.inc

Large diffs are not rendered by default.

17 changes: 10 additions & 7 deletions src/etc/inc/plugins.inc.d/loopback.inc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php

/*
* Copyright (C) 2019 Deciso B.V.
* Copyright (C) 2019-2022 Deciso B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -55,7 +55,11 @@ function loopback_devices()
$names = [];

foreach (iterator_to_array((new \OPNsense\Interfaces\Loopback())->loopback->iterateItems()) as $loopback) {
$names[] = "lo{$loopback->deviceId}";
$names["lo{$loopback->deviceId}"] = [
'descr' => sprintf('lo%s (%s)', $loopback->deviceId, $loopback->description),
'ifdescr' => sprintf('%s', $loopback->description),
'name' => "lo{$loopback->deviceId}",
];
}

return [[
Expand All @@ -75,9 +79,8 @@ function loopback_configure_do($verbose = false, $device = null)
$configured_devices = ['lo0']; // lo0 should always be configured
$loopbacks = iterator_to_array((new \OPNsense\Interfaces\Loopback())->loopback->iterateItems());

if ($verbose && !empty($loopbacks)) {
echo 'Configuring Loopback interfaces...';
flush();
if (!empty($loopbacks)) {
service_log(sprintf('Configuring Loopback interface%s...', empty($device) ? 's' : " {$device}"), $verbose);
}

// (re)configure loopback devices
Expand All @@ -103,8 +106,8 @@ function loopback_configure_do($verbose = false, $device = null)
}
}

if ($verbose && !empty($loopbacks)) {
echo "done.\n";
if (!empty($loopbacks)) {
service_log("done.\n", $verbose);
}
}

Expand Down
9 changes: 2 additions & 7 deletions src/etc/inc/plugins.inc.d/ntpd.inc
Original file line number Diff line number Diff line change
Expand Up @@ -177,10 +177,7 @@ function ntpd_configure_do($verbose = false)
return;
}

if ($verbose) {
echo 'Starting NTP service...';
flush();
}
service_log('Starting NTP service...', $verbose);

$driftfile = '/var/db/ntpd.drift';
$statsdir = '/var/log/ntp';
Expand Down Expand Up @@ -462,7 +459,5 @@ function ntpd_configure_do($verbose = false)
mwexecf_bg('/usr/local/sbin/ntpd -q -g -c %s', ['/var/etc/ntpd.conf']);
}

if ($verbose) {
echo "done.\n";
}
service_log("done.\n", $verbose);
}
23 changes: 10 additions & 13 deletions src/etc/inc/plugins.inc.d/opendns.inc
Original file line number Diff line number Diff line change
Expand Up @@ -28,27 +28,24 @@

function opendns_configure()
{
return array(
'bootup' => array('opendns_configure_do'),
'local' => array('opendns_configure_do'),
'newwanip' => array('opendns_configure_do'),
);
return [
'bootup' => ['opendns_configure_do'],
'local' => ['opendns_configure_do'],
'newwanip' => ['opendns_configure_do'],
];
}

function opendns_configure_do($verbose = false)
{
global $config;

if (!empty($config['opendns']['enable'])) {
if ($verbose) {
echo 'Configure OpenDNS...';
flush();
}
service_log('Configure OpenDNS...', $verbose);

$result = opendns_register($config['opendns']);
syslog(LOG_NOTICE, "opendns response: $result");
if ($verbose) {
echo "done.\n";
}
log_msg("opendns response: $result");

service_log("done.\n", $verbose);
}
}

Expand Down
18 changes: 5 additions & 13 deletions src/etc/inc/plugins.inc.d/openssh.inc
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,10 @@ function openssh_configure_do($verbose = false, $interface = '')
}

if ($generate_keys) {
/* XXX replace with file lock */
if (is_subsystem_dirty('sshdkeys')) {
return;
}
log_error('Started creating your SSH keys. SSH startup is being delayed a wee bit.');
mark_subsystem_dirty('sshdkeys');
foreach ($keys as $type => $name) {
$file = "/conf/sshd/{$name}";
Expand All @@ -160,7 +160,6 @@ function openssh_configure_do($verbose = false, $interface = '')
mwexecf('/usr/local/bin/ssh-keygen -t %s -N "" -f %s', array($type, $file));
}
clear_subsystem_dirty('sshdkeys');
log_error('Completed creating your SSH keys. SSH will now be started.');
}

$sshport = isset($sshcfg['port']) ? $sshcfg['port'] : 22;
Expand Down Expand Up @@ -213,7 +212,7 @@ function openssh_configure_do($verbose = false, $interface = '')
}

if (count($listeners) >= 16) {
log_error("The SSH listening address $tmpaddr cannot be added due to MAX_LISTEN_SOCKS limit reached.");
log_msg("The SSH listening address $tmpaddr cannot be added due to MAX_LISTEN_SOCKS limit reached.", LOG_WARNING);
continue;
}

Expand Down Expand Up @@ -262,18 +261,11 @@ function openssh_configure_do($verbose = false, $interface = '')

file_put_contents("/usr/local/etc/ssh/sshd_config", $sshconf);

if ($verbose) {
echo 'Configuring OpenSSH...';
flush();
}
service_log('Configuring OpenSSH...', $verbose);

if ((count($interfaces) && !count($listeners)) || mwexecf('/usr/bin/protect -i /usr/local/sbin/sshd')) {
if ($verbose) {
echo "failed.\n";
}
service_log("failed.\n", $verbose);
} else {
if ($verbose) {
echo "done.\n";
}
service_log("done.\n", $verbose);
}
}
29 changes: 13 additions & 16 deletions src/etc/inc/plugins.inc.d/openvpn.inc
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,11 @@ function openvpn_devices()
foreach (['server', 'client'] as $mode) {
if (!empty($config['openvpn']["openvpn-{$mode}"])) {
foreach ($config['openvpn']["openvpn-{$mode}"] as $settings) {
$names[] = "ovpn{$mode[0]}{$settings['vpnid']}";
$names["ovpn{$mode[0]}{$settings['vpnid']}"] = [
'descr' => sprintf('ovpn%s%s (OpenVPN %s %s)', $mode[0], $settings['vpnid'], $mode == 'server' ? gettext('Server') : gettext('Client'), $settings['description']),
'ifdescr' => sprintf('%s', $settings['description']),
'name' => "ovpn{$mode[0]}{$settings['vpnid']}",
];
}
}
}
Expand Down Expand Up @@ -518,7 +522,7 @@ function openvpn_reconfigure($mode, $settings, $device_only = false)
$conf .= "dev-node /dev/{$devnode}\n";
$conf .= "writepid /var/run/openvpn_{$mode_id}.pid\n";
$conf .= "script-security 3\n";
$conf .= "daemon\n";
$conf .= "daemon openvpn_{$mode_id}\n";
$conf .= "keepalive 10 60\n";
$conf .= "ping-timer-rem\n";
$conf .= "persist-tun\n";
Expand Down Expand Up @@ -831,7 +835,6 @@ function openvpn_reconfigure($mode, $settings, $device_only = false)
}
if (!empty($settings['crlref'])) {
$crl = lookup_crl($settings['crlref']);
crl_update($crl);
openvpn_add_keyfile($crl['text'], $conf, $mode_id, "crl-verify");
}
if ($settings['tls']) {
Expand Down Expand Up @@ -943,9 +946,9 @@ function openvpn_restart($mode, $settings, $carp_event = false)
if (!mwexecf('/usr/local/sbin/openvpn --config %s', "/var/etc/openvpn/{$mode_id}.conf")) {
$pid = waitforpid("/var/run/openvpn_{$mode_id}.pid", 10);
if ($pid) {
log_error(sprintf('OpenVPN %s %s instance started on PID %s.', $mode, $vpnid, $pid));
log_msg(sprintf('OpenVPN %s %s instance started on PID %s.', $mode, $vpnid, $pid));
} else {
log_error(sprintf('OpenVPN %s %s instance start timed out.', $mode, $vpnid));
log_msg(sprintf('OpenVPN %s %s instance start timed out.', $mode, $vpnid), LOG_WARNING);
}
}
}
Expand Down Expand Up @@ -1132,18 +1135,15 @@ function openvpn_configure_do($verbose = false, $interface = '', $carp_event = f
}

if (!empty($interface)) {
log_error(sprintf(
log_msg(sprintf(
'Resyncing OpenVPN instances for interface %s.',
convert_friendly_interface_to_friendly_descr($interface)
));
), LOG_INFO);
} else {
log_error('Resyncing OpenVPN instances.');
log_msg('Resyncing OpenVPN instances.', LOG_INFO);
}

if ($verbose) {
echo 'Syncing OpenVPN settings...';
flush();
}
service_log('Syncing OpenVPN settings...', $verbose);

$reconfigure_count = 0;
foreach (array('server', 'client') as $mode) {
Expand All @@ -1162,9 +1162,7 @@ function openvpn_configure_do($verbose = false, $interface = '', $carp_event = f
configd_run('filter reload'); /* XXX really needed? */
}

if ($verbose) {
echo "done.\n";
}
service_log("done.\n", $verbose);
}

function openvpn_get_active_servers($type = 'multipoint')
Expand Down Expand Up @@ -1536,7 +1534,6 @@ function openvpn_refresh_crls()
case 'server_user':
if (!empty($settings['crlref'])) {
$crl = lookup_crl($settings['crlref']);
crl_update($crl);
$fpath = "/var/etc/openvpn/server{$settings['vpnid']}.crl-verify";
file_put_contents($fpath, base64_decode($crl['text']));
@chmod($fpath, 0644);
Expand Down
6 changes: 2 additions & 4 deletions src/etc/inc/plugins.inc.d/openvpn/ovpn-linkdown
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
#!/bin/sh

/sbin/pfctl -i ${1} -Fs

/bin/rm -f /tmp/${1}_router
/bin/rm -f /tmp/${1}_routerv6
/usr/local/sbin/ifctl -4ci ${1}
/usr/local/sbin/ifctl -6ci ${1}
20 changes: 13 additions & 7 deletions src/etc/inc/plugins.inc.d/openvpn/ovpn-linkup
Original file line number Diff line number Diff line change
@@ -1,26 +1,32 @@
#!/bin/sh

ROUTERV4=
ROUTERV6=

if [ -n "${route_vpn_gateway}" ]; then
/bin/echo ${route_vpn_gateway} > /tmp/${1}_router
ROUTERV4="-a ${route_vpn_gateway}"
elif [ -n "${ifconfig_remote}" ]; then
/bin/echo ${ifconfig_remote} > /tmp/${1}_router
ROUTERV4="-a ${ifconfig_remote}"
elif [ -n "${ifconfig_local}" ]; then
# XXX: We can't reliably determine the tunnels endpoint, other than parsing ifconfig.
# Use our standard parser to request the tunnels other end. Eventually we could pass this to configd if
# needed, but openvpn has elevated rights anyway at the moment.
/usr/local/etc/inc/plugins.inc.d/openvpn/tunnel_endpoint.php ${1} > /tmp/${1}_router
ROUTERV4="-a $(/usr/local/etc/inc/plugins.inc.d/openvpn/tunnel_endpoint.php ${1})"
elif [ "${dev_type}" = "tun" -a -n "${5}" ]; then
/bin/echo ${5} > /tmp/${1}_router
ROUTERV4="-a ${5}"
fi

if [ -n "${route_ipv6_gateway_1}" ]; then
/bin/echo ${route_ipv6_gateway_1} > /tmp/${1}_routerv6
ROUTERV6="-a ${route_ipv6_gateway_1}"
elif [ -n "${ifconfig_ipv6_remote}" ]; then
/bin/echo ${ifconfig_ipv6_remote} > /tmp/${1}_routerv6
ROUTERV6="-a ${ifconfig_ipv6_remote}"
elif [ -n "${ifconfig_ipv6_local}" ]; then
/bin/echo ${ifconfig_ipv6_local} > /tmp/${1}_routerv6
ROUTERV6="-a ${ifconfig_ipv6_local}"
fi

/usr/local/sbin/ifctl -4rd -i ${1} ${ROUTERV4}
/usr/local/sbin/ifctl -6rd -i ${1} ${ROUTERV6}

/usr/local/sbin/configctl -d interface newip ${1}

exit 0
3 changes: 0 additions & 3 deletions src/etc/inc/plugins.inc.d/openvpn/wizard.inc
Original file line number Diff line number Diff line change
Expand Up @@ -715,9 +715,6 @@ function step12_submitphpaction()
if (isset($pconfig['step10']['dynip'])) {
$server['dynamic_ip'] = $pconfig['step10']['dynip'];
}
if (isset($pconfig['step10']['addrpool'])) {
$server['pool_enable'] = $pconfig['step10']['addrpool'];
}
if (isset($pconfig['step10']['defaultdomain'])) {
$server['dns_domain'] = $pconfig['step10']['defaultdomain'];
}
Expand Down
Loading