From c61babf7bb7db6fc6a1196899a637ec44baa8934 Mon Sep 17 00:00:00 2001 From: Franco Fichtner Date: Sat, 18 Mar 2017 11:20:47 +0100 Subject: [PATCH] rfc2136: groundwork for #1478 --- src/etc/inc/plugins.inc | 18 ++- src/etc/inc/plugins.inc.d/ipfw.inc | 1 - src/etc/inc/plugins.inc.d/rfc2136.inc | 180 ++++++++++++++++++++++++++ src/etc/inc/services.inc | 166 ++---------------------- src/etc/rc.dyndns.update | 9 +- src/etc/rc.newwanip | 5 +- src/etc/rc.newwanipv6 | 3 - src/www/services_rfc2136_edit.php | 8 +- 8 files changed, 218 insertions(+), 172 deletions(-) create mode 100644 src/etc/inc/plugins.inc.d/rfc2136.inc diff --git a/src/etc/inc/plugins.inc b/src/etc/inc/plugins.inc index 4c77b5c65..ebf1cfda8 100644 --- a/src/etc/inc/plugins.inc +++ b/src/etc/inc/plugins.inc @@ -165,8 +165,10 @@ function plugins_firewall($fw) return $fw; } -function plugins_configure($hook, $verbose = false) +function plugins_configure($hook, $verbose = false, $args = array()) { + array_unshift($args, $verbose); + foreach (plugins_scan() as $name => $path) { require_once $path; $func = sprintf('%s_configure', $name); @@ -175,7 +177,19 @@ function plugins_configure($hook, $verbose = false) foreach ($workers as $when => $worker) { if ($hook == $when && is_array($worker)) { foreach ($worker as $task) { - $task($verbose); + /* + * An optional argument count parameter can be + * given by the plugin, which allows to securely + * pull more info from the configure call spot. + */ + list($argf, $argc) = explode(':', $task); + if (empty($argc) || !is_numeric($argc)) { + $argc = 1; + } + if ($argc > count($args)) { + $argc = count($args); + } + call_user_func_array($argf, array_slice($args, 0, $argc)); } } } diff --git a/src/etc/inc/plugins.inc.d/ipfw.inc b/src/etc/inc/plugins.inc.d/ipfw.inc index 8f379ee39..d6af2c770 100644 --- a/src/etc/inc/plugins.inc.d/ipfw.inc +++ b/src/etc/inc/plugins.inc.d/ipfw.inc @@ -26,7 +26,6 @@ POSSIBILITY OF SUCH DAMAGE. */ - function ipfw_services() { global $config; diff --git a/src/etc/inc/plugins.inc.d/rfc2136.inc b/src/etc/inc/plugins.inc.d/rfc2136.inc new file mode 100644 index 000000000..2dc4e0b1e --- /dev/null +++ b/src/etc/inc/plugins.inc.d/rfc2136.inc @@ -0,0 +1,180 @@ + + Copyright (C) 2010 Ermal Luci + Copyright (C) 2005-2006 Colin Smith + Copyright (C) 2003-2004 Manuel Kasper + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +function rfc2136_configure() +{ + return array( + 'interface' => array('rfc2136_configure_do:2'), + ); +} + +function rfc2136_configure_do($verbose = false, $int = '', $updatehost = '', $forced = false) +{ + global $config; + + if (!isset($config['dnsupdates']['dnsupdate'])) { + return; + } + + $notify_text = ''; + + foreach ($config['dnsupdates']['dnsupdate'] as $i => $dnsupdate) { + if (!isset($dnsupdate['enable'])) { + continue; + } elseif (!empty($int) && $int != $dnsupdate['interface']) { + continue; + } elseif (!empty($updatehost) && ($updatehost != $dnsupdate['host'])) { + continue; + } + + $if = get_real_interface($dnsupdate['interface']); + + if (isset($dnsupdate['usepublicip'])) { + $wanip = dyndnsCheckIP($dnsupdate['interface']); + } else { + $wanip = get_interface_ip($dnsupdate['interface']); + } + + $wanipv6 = get_interface_ipv6($dnsupdate['interface']); + $cacheFile = "/conf/dyndns_{$dnsupdate['interface']}_rfc2136_" . escapeshellarg($dnsupdate['host']) . "_{$dnsupdate['server']}.cache"; + $currentTime = time(); + + if ($wanip || $wanipv6) { + $keyname = $dnsupdate['keyname']; + /* trailing dot */ + if (substr($keyname, -1) != ".") { + $keyname .= "."; + } + + $hostname = $dnsupdate['host']; + /* trailing dot */ + if (substr($hostname, -1) != ".") { + $hostname .= "."; + } + + /* write private key file + this is dumb - public and private keys are the same for HMAC-MD5, + but nsupdate insists on having both */ + $fd = fopen("/var/etc/K{$i}{$keyname}+157+00000.private", "w"); + $privkey = << $maxCacheAgeSecs) || $forced) { + $upinst .= "update delete {$dnsupdate['host']}. A\n"; + $upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} A {$wanip}\n"; + $notify_text .= sprintf(gettext('Dynamic DNS updated IP Address (A) for %s on %s (%s) to %s'), $dnsupdate['host'], convert_real_interface_to_friendly_descr($if), $if, $wanip) . "\n"; + @file_put_contents($cacheFile, "{$wanip}|{$currentTime}"); + log_error("Dynamic DNS: updating cache file {$cacheFile}: {$wanip}"); + $need_update = true; + } else { + log_error("Dynamic DNS: Not updating {$dnsupdate['host']} A record because the IP address has not changed."); + } + } else { + @unlink($cacheFile); + } + + /* Update IPv6 if we have it. */ + if (is_ipaddrv6($wanipv6) && (empty($dnsupdate['recordtype']) || $dnsupdate['recordtype'] == 'AAAA')) { + if (($wanipv6 != $cachedipv6) || (($currentTime - $cacheTimev6) > $maxCacheAgeSecs) || $forced) { + $upinst .= "update delete {$dnsupdate['host']}. AAAA\n"; + $upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} AAAA {$wanipv6}\n"; + $notify_text .= sprintf(gettext('Dynamic DNS updated IPv6 Address (AAAA) for %s on %s (%s) to %s'), $dnsupdate['host'], convert_real_interface_to_friendly_descr($if), $if, $wanipv6) . "\n"; + @file_put_contents("{$cacheFile}.ipv6", "{$wanipv6}|{$currentTime}"); + log_error("Dynamic DNS: updating cache file {$cacheFile}.ipv6: {$wanipv6}"); + $need_update = true; + } else { + log_error("Dynamic DNS: Not updating {$dnsupdate['host']} AAAA record because the IPv6 address has not changed."); + } + } else { + @unlink("{$cacheFile}.ipv6"); + } + + $upinst .= "\n"; /* mind that trailing newline! */ + + if ($need_update) { + @file_put_contents("/var/etc/nsupdatecmds{$i}", $upinst); + unset($upinst); + /* invoke nsupdate */ + $cmd = "/usr/local/bin/nsupdate -k /var/etc/K{$i}{$keyname}+157+00000.key"; + if (isset($dnsupdate['usetcp'])) + $cmd .= " -v"; + $cmd .= " /var/etc/nsupdatecmds{$i}"; + mwexec_bg($cmd); + unset($cmd); + } + } + } + + if (!empty($notify_text)) { + notify_all_remote($notify_text); + } +} diff --git a/src/etc/inc/services.inc b/src/etc/inc/services.inc index 14047b515..f8c76dc1a 100644 --- a/src/etc/inc/services.inc +++ b/src/etc/inc/services.inc @@ -1,7 +1,7 @@ + Copyright (C) 2014-2017 Franco Fichtner Copyright (C) 2010 Ermal Luci Copyright (C) 2005-2006 Colin Smith Copyright (C) 2003-2004 Manuel Kasper @@ -30,23 +30,24 @@ */ /* - * Best case this shouldn't be here but DNS (and DHCP) - * are deeply tied into several internals in system.inc - * and services.inc. services.inc itself has always - * been a workaround for holding multiple features away - * from system.inc, but its movable parts belong to - * system.inc, while all services belong to their own - * files. Maybe eventually this will change... + * Base services are slowly being converted into plugins, + * hooks are created and expanded to accomodate for their + * feature set, which allows us to build a better plugin + * system in general. * - * ... it does, but now we also chain IPsec and OpenVPN - * through this in order to remove the widespread usage - * of includes and switch them for a cleaner "services.inc" - * include. + * Ideally this may allow us to remove all service-relevant + * parts from system.inc and services.inc so that the latter + * will eventually become obsolete. + * + * The goal may not be to remove all of the base system + * as plugins, but the things listed below are viable + * targets in the future: */ require_once('plugins.inc.d/dnsmasq.inc'); require_once('dyndns.class'); /* XXX move to plugin */ require_once('plugins.inc.d/ipsec.inc'); require_once('plugins.inc.d/openvpn.inc'); +require_once('plugins.inc.d/rfc2136.inc'); require_once('plugins.inc.d/unbound.inc'); function generate_ipv6_from_mac($mac) @@ -1676,147 +1677,6 @@ function dyndnsCheckIP($int) return $ip_address; } -function services_dnsupdate_process($int = '', $updatehost = '', $forced = false) -{ - global $config; - - if (isset($config['dnsupdates']['dnsupdate'])) { - $notify_text = ""; - foreach ($config['dnsupdates']['dnsupdate'] as $i => $dnsupdate) { - if (!isset($dnsupdate['enable'])) { - continue; - } elseif (!empty($int) && $int != $dnsupdate['interface']) { - continue; - } elseif (!empty($updatehost) && ($updatehost != $dnsupdate['host'])) { - continue; - } - - $if = get_real_interface($dnsupdate['interface']); - - if (isset($dnsupdate['usepublicip'])) { - $wanip = dyndnsCheckIP($dnsupdate['interface']); - } else { - $wanip = get_interface_ip($dnsupdate['interface']); - } - - $wanipv6 = get_interface_ipv6($dnsupdate['interface']); - $cacheFile = "/conf/dyndns_{$dnsupdate['interface']}_rfc2136_" . escapeshellarg($dnsupdate['host']) . "_{$dnsupdate['server']}.cache"; - $currentTime = time(); - - if ($wanip || $wanipv6) { - $keyname = $dnsupdate['keyname']; - /* trailing dot */ - if (substr($keyname, -1) != ".") { - $keyname .= "."; - } - - $hostname = $dnsupdate['host']; - /* trailing dot */ - if (substr($hostname, -1) != ".") { - $hostname .= "."; - } - - /* write private key file - this is dumb - public and private keys are the same for HMAC-MD5, - but nsupdate insists on having both */ - $fd = fopen("/var/etc/K{$i}{$keyname}+157+00000.private", "w"); - $privkey = << $maxCacheAgeSecs) || $forced) { - $upinst .= "update delete {$dnsupdate['host']}. A\n"; - $upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} A {$wanip}\n"; - $notify_text .= sprintf(gettext('Dynamic DNS updated IP Address (A) for %s on %s (%s) to %s'), $dnsupdate['host'], convert_real_interface_to_friendly_descr($if), $if, $wanip) . "\n"; - @file_put_contents($cacheFile, "{$wanip}|{$currentTime}"); - log_error("Dynamic DNS: updating cache file {$cacheFile}: {$wanip}"); - $need_update = true; - } else { - log_error("Dynamic DNS: Not updating {$dnsupdate['host']} A record because the IP address has not changed."); - } - } else { - @unlink($cacheFile); - } - - /* Update IPv6 if we have it. */ - if (is_ipaddrv6($wanipv6) && (empty($dnsupdate['recordtype']) || $dnsupdate['recordtype'] == 'AAAA')) { - if (($wanipv6 != $cachedipv6) || (($currentTime - $cacheTimev6) > $maxCacheAgeSecs) || $forced) { - $upinst .= "update delete {$dnsupdate['host']}. AAAA\n"; - $upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} AAAA {$wanipv6}\n"; - $notify_text .= sprintf(gettext('Dynamic DNS updated IPv6 Address (AAAA) for %s on %s (%s) to %s'), $dnsupdate['host'], convert_real_interface_to_friendly_descr($if), $if, $wanipv6) . "\n"; - @file_put_contents("{$cacheFile}.ipv6", "{$wanipv6}|{$currentTime}"); - log_error("Dynamic DNS: updating cache file {$cacheFile}.ipv6: {$wanipv6}"); - $need_update = true; - } else { - log_error("Dynamic DNS: Not updating {$dnsupdate['host']} AAAA record because the IPv6 address has not changed."); - } - } else { - @unlink("{$cacheFile}.ipv6"); - } - - $upinst .= "\n"; /* mind that trailing newline! */ - - if ($need_update) { - @file_put_contents("/var/etc/nsupdatecmds{$i}", $upinst); - unset($upinst); - /* invoke nsupdate */ - $cmd = "/usr/local/bin/nsupdate -k /var/etc/K{$i}{$keyname}+157+00000.key"; - if (isset($dnsupdate['usetcp'])) - $cmd .= " -v"; - $cmd .= " /var/etc/nsupdatecmds{$i}"; - mwexec_bg($cmd); - unset($cmd); - } - } - } - if (!empty($notify_text)) { - notify_all_remote($notify_text); - } - } - - return 0; -} - function is_apinger_enabled() { global $config; diff --git a/src/etc/rc.dyndns.update b/src/etc/rc.dyndns.update index a09889f07..737c77d88 100755 --- a/src/etc/rc.dyndns.update +++ b/src/etc/rc.dyndns.update @@ -41,13 +41,14 @@ if (isset($argv[1])) { $argument = null; } -if(empty($argument)) { +if (empty($argument)) { services_dyndns_configure(); - services_dnsupdate_process(); + rfc2136_configure_do(false); } else { $interface = lookup_gateway_interface_by_name($argument); - if (empty($interface)) + if (empty($interface)) { $interface = $argument; + } services_dyndns_configure($interface); - services_dnsupdate_process($interface); + rfc2136_configure_do(false, $interface); } diff --git a/src/etc/rc.newwanip b/src/etc/rc.newwanip index f28467722..9a4fa2005 100755 --- a/src/etc/rc.newwanip +++ b/src/etc/rc.newwanip @@ -181,9 +181,6 @@ if (!is_ipaddr($oldip) || $curwanip != $oldip || !is_ipaddrv4($config['interface @file_put_contents("/var/db/{$interface}_cacheip", $curwanip); } - /* perform RFC 2136 DNS update */ - services_dnsupdate_process($interface); - /* signal dyndns update */ services_dyndns_configure($interface); @@ -201,7 +198,7 @@ if (!is_ipaddr($oldip) || $curwanip != $oldip || !is_ipaddrv4($config['interface enable_rrd_graphing(); /* reload plugins */ - plugins_configure('interface'); + plugins_configure('interface', false, array($interface)); } /* reload filter, don't try to sync to carp slave */ diff --git a/src/etc/rc.newwanipv6 b/src/etc/rc.newwanipv6 index 41af49e3e..5205c91a1 100755 --- a/src/etc/rc.newwanipv6 +++ b/src/etc/rc.newwanipv6 @@ -139,9 +139,6 @@ if (is_ipaddrv6($oldipv6)) { file_put_contents("/var/db/{$interface}_cacheipv6", $curwanipv6); } -/* perform RFC 2136 DNS update */ -services_dnsupdate_process($interface); - /* signal dyndns update */ services_dyndns_configure($interface); diff --git a/src/www/services_rfc2136_edit.php b/src/www/services_rfc2136_edit.php index 8e11f2801..faa168247 100644 --- a/src/www/services_rfc2136_edit.php +++ b/src/www/services_rfc2136_edit.php @@ -111,21 +111,19 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') { write_config('New/Edited RFC2136 dnsupdate entry was posted'); if (!empty($pconfig['force'])) { - services_dnsupdate_process("", $rfc2136['host'], true); + rfc2136_configure_do(false, '', $rfc2136['host'], true); } else { - services_dnsupdate_process(); + rfc2136_configure_do(); } header(url_safe('Location: /services_rfc2136.php')); exit; } } - - legacy_html_escape_form_data($pconfig); include("head.inc"); -?> +?>