From 672e8ba9e14e9c12dbd7822552dd0f39645be41b Mon Sep 17 00:00:00 2001 From: Franco Fichtner Date: Tue, 12 Mar 2024 12:41:37 +0100 Subject: [PATCH] dhcrelay: functional replacement #6983 Since we are not ISC we can make a new menu spot. Keep the legacy reconfiguration spot as we end up building a complex command line to run and this doesn't have to go into a template that just stuffs args into a variable to start it, which then requires and rc.d file. Though we want to move it out of dhcpd.inc at some point. Apparently the new MVC page is missing an apply button. ;) --- plist | 1 + src/etc/inc/plugins.inc.d/dhcpd.inc | 152 ++++++------------ .../models/OPNsense/DHCRelay/Menu/Menu.xml | 7 + 3 files changed, 58 insertions(+), 102 deletions(-) create mode 100644 src/opnsense/mvc/app/models/OPNsense/DHCRelay/Menu/Menu.xml diff --git a/plist b/plist index 81832fe69..b9f61f4a6 100644 --- a/plist +++ b/plist @@ -599,6 +599,7 @@ /usr/local/opnsense/mvc/app/models/OPNsense/Cron/Migrations/M1_0_4.php /usr/local/opnsense/mvc/app/models/OPNsense/DHCRelay/DHCRelay.php /usr/local/opnsense/mvc/app/models/OPNsense/DHCRelay/DHCRelay.xml +/usr/local/opnsense/mvc/app/models/OPNsense/DHCRelay/Menu/Menu.xml /usr/local/opnsense/mvc/app/models/OPNsense/DHCRelay/Migrations/M1_0_0.php /usr/local/opnsense/mvc/app/models/OPNsense/Diagnostics/ACL/ACL.xml /usr/local/opnsense/mvc/app/models/OPNsense/Diagnostics/DnsDiagnostics.php diff --git a/src/etc/inc/plugins.inc.d/dhcpd.inc b/src/etc/inc/plugins.inc.d/dhcpd.inc index fd3111cbd..781f13526 100644 --- a/src/etc/inc/plugins.inc.d/dhcpd.inc +++ b/src/etc/inc/plugins.inc.d/dhcpd.inc @@ -1,7 +1,7 @@ + * Copyright (C) 2014-2024 Franco Fichtner * Copyright (C) 2010 Ermal Luçi * Copyright (C) 2005-2006 Colin Smith * Copyright (C) 2003-2004 Manuel Kasper @@ -116,14 +116,17 @@ function dhcpd_services() $services[] = $pconfig; } - if (isset($config['dhcrelay']['enable'])) { - $pconfig = array(); - $pconfig['name'] = "dhcrelay"; - $pconfig['description'] = gettext("DHCPv4 Relay"); - $pconfig['php']['restart'] = array('dhcpd_dhcrelay4_configure'); - $pconfig['php']['start'] = array('dhcpd_dhcrelay4_configure'); - $pconfig['pidfile'] = '/var/run/dhcrelay.pid'; - $services[] = $pconfig; + foreach ((new \OPNsense\DHCRelay\DHCRelay())->relays->iterateItems() as $relay) { + if ((string)$relay->enabled == '1') { + $pconfig = []; + $pconfig['name'] = 'dhcrelay'; + $pconfig['description'] = gettext('DHCPv4 Relay') . " ({$relay->interface})"; + $pconfig['php']['restart'] = ['dhcpd_dhcrelay4_configure']; + $pconfig['php']['start'] = ['dhcpd_dhcrelay4_configure']; + $pconfig['pidfile'] = "/var/run/dhcrelay-{$relay->getAttribute('uuid')}.pid"; + $pconfig['id'] = $relay->getAttribute('uuid'); + $services[] = $pconfig; + } } if (isset($config['dhcrelay6']['enable'])) { @@ -1623,113 +1626,58 @@ function dhcpd_dhcrelay_configure($verbose = false, $family = null) function dhcpd_dhcrelay4_configure($verbose = false) { - global $config; + $mdl = new \OPNsense\DHCRelay\DHCRelay(); + $relays = []; - $dhcrelaycfg = &config_read_array('dhcrelay'); - $dhcrelayifs = []; + foreach ($mdl->relays->iterateItems() as $relay) { + if ((string)$relay->enabled == '1') { + $relays[] = $relay; + } - if (!isset($dhcrelaycfg['enable'])) { - killbypid('/var/run/dhcrelay.pid'); + killbypid("/var/run/dhcrelay-{$relay->getAttribute('uuid')}.pid"); + } + + if (!count($relays)) { return; } service_log('Starting DHCPv4 relay...', $verbose); - killbypid('/var/run/dhcrelay.pid'); - $iflist = get_configured_interface_with_descr(); $ifconfig_details = legacy_interfaces_details(); - $a_gateways = (new \OPNsense\Routing\Gateways())->gatewaysIndexedByName(); - $dhcifaces = explode(",", $dhcrelaycfg['interface']); - foreach ($dhcifaces as $dhcrelayif) { - if (isset($iflist[$dhcrelayif]) && get_interface_ip($dhcrelayif, $ifconfig_details)) { - $dhcrelayifs[] = get_real_interface($dhcrelayif); - } - } - /* - * In order for the relay to work, it needs to be active - * on the interface in which the destination server sits. - */ - $srvips = explode(",", $dhcrelaycfg['server']); - foreach ($srvips as $srvip) { - $destif = null; + foreach ($relays as $relay) { + $interface = (string)$relay->interface; + $device = get_real_interface($interface); - /* XXX runs multiple times because of server address loop :( */ - foreach (array_keys($iflist) as $ifname) { - list (, $subnet) = interfaces_primary_address($ifname, $ifconfig_details); - if (!is_subnetv4($subnet)) { - continue; - } - if (ip_in_subnet($srvip, $subnet)) { - $destif = get_real_interface($ifname, $ifconfig_details); - break; - } - } - - if (empty($destif)) { - foreach (get_staticroutes() as $rtent) { - if (ip_in_subnet($srvip, $rtent['network'])) { - $destif = $a_gateways[$rtent['gateway']]['if']; - break; - } - } - } - - if (empty($destif)) { - /* Create an array from the existing route table */ - exec("/usr/bin/netstat -rnWf inet", $route_str); - array_shift($route_str); - array_shift($route_str); - array_shift($route_str); - array_shift($route_str); - foreach ($route_str as $routeline) { - $items = preg_split("/[ ]+/i", $routeline); - if (is_subnetv4($items[0])) { - $subnet = $items[0]; - } elseif (is_ipaddrv4($items[0])) { - $subnet = "{$items[0]}/32"; - } else { - // Not a subnet or IP address, skip to the next line. - continue; - } - if (ip_in_subnet($srvip, $subnet)) { - $destif = trim($items[6]); - break; - } - } - } - - if (empty($destif)) { - foreach ($a_gateways as $gateway) { - if (!empty($gateway['defaultgw']) && $gateway['ipprotocol'] == 'inet') { - $destif = $gateway['if']; - break; - } - } - } - - if (!empty($destif) && isset($ifconfig_details[$destif]) && $ifconfig_details[$destif]['macaddr'] == '00:00:00:00:00:00') { - /* explicit skip when interface has no valid mac address */ + if (!isset($iflist[$interface]) || !get_interface_ip($interface, $ifconfig_details)) { + log_msg("dhcpd_dhcrelay4_configure() found no IP address for $interface($device)", LOG_WARNING); continue; - } elseif (!empty($destif)) { - $dhcrelayifs[] = $destif; - } else { - log_msg("dhcpd_dhcrelay4_configure() found no suitable interface for {$srvip}", LOG_WARNING); - } - } - - $dhcrelayifs = array_unique($dhcrelayifs); - - if (!empty($dhcrelayifs)) { - $cmd = "/usr/local/sbin/dhcrelay -i " . implode(" -i ", $dhcrelayifs); - - if (isset($dhcrelaycfg['agentoption'])) { - $cmd .= ' -a -m replace'; } - $cmd .= " " . implode(" ", $srvips); - mwexec($cmd); + if (empty($device) || isset($ifconfig_details[$device]) && $ifconfig_details[$device]['macaddr'] == '00:00:00:00:00:00') { + log_msg("dhcpd_dhcrelay4_configure() found no ethernet address for $interface($device)", LOG_WARNING); + continue; + } + + $destination = $mdl->getNodeByReference("destinations.{$relay->destination}"); + if ($destination == null) { + log_msg("dhcpd_dhcrelay4_configure() found no destination server for $interface($device)", LOG_WARNING); + continue; + } + + $cmd = [exec_safe('daemon -f -p %s', "/var/run/dhcrelay-{$relay->getAttribute('uuid')}.pid")]; + $cmd[] = '/usr/local/sbin/dhcrelay -d'; + if (!empty((string)$relay->agent_info)) { + $cmd[] = '-or'; + } + $cmd[] = exec_safe('-i %s', $device); + + foreach (explode(',', (string)$destination->server) as $server) { + $cmd[] = exec_safe('%s', $server); + } + + mwexec(join(' ', $cmd)); } service_log("done.\n", $verbose); diff --git a/src/opnsense/mvc/app/models/OPNsense/DHCRelay/Menu/Menu.xml b/src/opnsense/mvc/app/models/OPNsense/DHCRelay/Menu/Menu.xml new file mode 100644 index 000000000..295c2572b --- /dev/null +++ b/src/opnsense/mvc/app/models/OPNsense/DHCRelay/Menu/Menu.xml @@ -0,0 +1,7 @@ + + + + + + +