Commit c61babf7 authored by Franco Fichtner's avatar Franco Fichtner

rfc2136: groundwork for #1478

parent 4388146c
...@@ -165,8 +165,10 @@ function plugins_firewall($fw) ...@@ -165,8 +165,10 @@ function plugins_firewall($fw)
return $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) { foreach (plugins_scan() as $name => $path) {
require_once $path; require_once $path;
$func = sprintf('%s_configure', $name); $func = sprintf('%s_configure', $name);
...@@ -175,7 +177,19 @@ function plugins_configure($hook, $verbose = false) ...@@ -175,7 +177,19 @@ function plugins_configure($hook, $verbose = false)
foreach ($workers as $when => $worker) { foreach ($workers as $when => $worker) {
if ($hook == $when && is_array($worker)) { if ($hook == $when && is_array($worker)) {
foreach ($worker as $task) { 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));
} }
} }
} }
......
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
POSSIBILITY OF SUCH DAMAGE. POSSIBILITY OF SUCH DAMAGE.
*/ */
function ipfw_services() function ipfw_services()
{ {
global $config; global $config;
......
<?php
/*
Copyright (C) 2014-2017 Franco Fichtner <franco@opnsense.org>
Copyright (C) 2010 Ermal Luci
Copyright (C) 2005-2006 Colin Smith <ethethlay@gmail.com>
Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>
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 = <<<EOD
Private-key-format: v1.2
Algorithm: 157 (HMAC)
Key: {$dnsupdate['keydata']}
EOD;
fwrite($fd, $privkey);
fclose($fd);
/* write public key file */
if ($dnsupdate['keytype'] == "zone") {
$flags = 257;
$proto = 3;
} elseif ($dnsupdate['keytype'] == "host") {
$flags = 513;
$proto = 3;
} elseif ($dnsupdate['keytype'] == "user") {
$flags = 0;
$proto = 2;
}
$fd = fopen("/var/etc/K{$i}{$keyname}+157+00000.key", "w");
fwrite($fd, "{$keyname} IN KEY {$flags} {$proto} 157 {$dnsupdate['keydata']}\n");
fclose($fd);
/* generate update instructions */
$upinst = "";
if (!empty($dnsupdate['server'])) {
$upinst .= "server {$dnsupdate['server']}\n";
}
if (file_exists($cacheFile)) {
list($cachedipv4, $cacheTimev4) = explode("|", file_get_contents($cacheFile));
}
if (file_exists("{$cacheFile}.ipv6")) {
list($cachedipv6, $cacheTimev6) = explode("|", file_get_contents("{$cacheFile}.ipv6"));
}
// 25 Days
$maxCacheAgeSecs = 25 * 24 * 60 * 60;
$need_update = false;
/* Update IPv4 if we have it. */
if (is_ipaddrv4($wanip) && (empty($dnsupdate['recordtype']) || $dnsupdate['recordtype'] == 'A')) {
if (($wanip != $cachedipv4) || (($currentTime - $cacheTimev4) > $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);
}
}
<?php <?php
/* /*
Copyright (C) 2014-2016 Franco Fichtner <franco@opnsense.org> Copyright (C) 2014-2017 Franco Fichtner <franco@opnsense.org>
Copyright (C) 2010 Ermal Luci Copyright (C) 2010 Ermal Luci
Copyright (C) 2005-2006 Colin Smith <ethethlay@gmail.com> Copyright (C) 2005-2006 Colin Smith <ethethlay@gmail.com>
Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net> Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>
...@@ -30,23 +30,24 @@ ...@@ -30,23 +30,24 @@
*/ */
/* /*
* Best case this shouldn't be here but DNS (and DHCP) * Base services are slowly being converted into plugins,
* are deeply tied into several internals in system.inc * hooks are created and expanded to accomodate for their
* and services.inc. services.inc itself has always * feature set, which allows us to build a better plugin
* been a workaround for holding multiple features away * system in general.
* from system.inc, but its movable parts belong to
* system.inc, while all services belong to their own
* files. Maybe eventually this will change...
* *
* ... it does, but now we also chain IPsec and OpenVPN * Ideally this may allow us to remove all service-relevant
* through this in order to remove the widespread usage * parts from system.inc and services.inc so that the latter
* of includes and switch them for a cleaner "services.inc" * will eventually become obsolete.
* include. *
* 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('plugins.inc.d/dnsmasq.inc');
require_once('dyndns.class'); /* XXX move to plugin */ require_once('dyndns.class'); /* XXX move to plugin */
require_once('plugins.inc.d/ipsec.inc'); require_once('plugins.inc.d/ipsec.inc');
require_once('plugins.inc.d/openvpn.inc'); require_once('plugins.inc.d/openvpn.inc');
require_once('plugins.inc.d/rfc2136.inc');
require_once('plugins.inc.d/unbound.inc'); require_once('plugins.inc.d/unbound.inc');
function generate_ipv6_from_mac($mac) function generate_ipv6_from_mac($mac)
...@@ -1676,147 +1677,6 @@ function dyndnsCheckIP($int) ...@@ -1676,147 +1677,6 @@ function dyndnsCheckIP($int)
return $ip_address; 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 = <<<EOD
Private-key-format: v1.2
Algorithm: 157 (HMAC)
Key: {$dnsupdate['keydata']}
EOD;
fwrite($fd, $privkey);
fclose($fd);
/* write public key file */
if ($dnsupdate['keytype'] == "zone") {
$flags = 257;
$proto = 3;
} elseif ($dnsupdate['keytype'] == "host") {
$flags = 513;
$proto = 3;
} elseif ($dnsupdate['keytype'] == "user") {
$flags = 0;
$proto = 2;
}
$fd = fopen("/var/etc/K{$i}{$keyname}+157+00000.key", "w");
fwrite($fd, "{$keyname} IN KEY {$flags} {$proto} 157 {$dnsupdate['keydata']}\n");
fclose($fd);
/* generate update instructions */
$upinst = "";
if (!empty($dnsupdate['server'])) {
$upinst .= "server {$dnsupdate['server']}\n";
}
if (file_exists($cacheFile)) {
list($cachedipv4, $cacheTimev4) = explode("|", file_get_contents($cacheFile));
}
if (file_exists("{$cacheFile}.ipv6")) {
list($cachedipv6, $cacheTimev6) = explode("|", file_get_contents("{$cacheFile}.ipv6"));
}
// 25 Days
$maxCacheAgeSecs = 25 * 24 * 60 * 60;
$need_update = false;
/* Update IPv4 if we have it. */
if (is_ipaddrv4($wanip) && (empty($dnsupdate['recordtype']) || $dnsupdate['recordtype'] == 'A')) {
if (($wanip != $cachedipv4) || (($currentTime - $cacheTimev4) > $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() function is_apinger_enabled()
{ {
global $config; global $config;
......
...@@ -41,13 +41,14 @@ if (isset($argv[1])) { ...@@ -41,13 +41,14 @@ if (isset($argv[1])) {
$argument = null; $argument = null;
} }
if(empty($argument)) { if (empty($argument)) {
services_dyndns_configure(); services_dyndns_configure();
services_dnsupdate_process(); rfc2136_configure_do(false);
} else { } else {
$interface = lookup_gateway_interface_by_name($argument); $interface = lookup_gateway_interface_by_name($argument);
if (empty($interface)) if (empty($interface)) {
$interface = $argument; $interface = $argument;
}
services_dyndns_configure($interface); services_dyndns_configure($interface);
services_dnsupdate_process($interface); rfc2136_configure_do(false, $interface);
} }
...@@ -181,9 +181,6 @@ if (!is_ipaddr($oldip) || $curwanip != $oldip || !is_ipaddrv4($config['interface ...@@ -181,9 +181,6 @@ if (!is_ipaddr($oldip) || $curwanip != $oldip || !is_ipaddrv4($config['interface
@file_put_contents("/var/db/{$interface}_cacheip", $curwanip); @file_put_contents("/var/db/{$interface}_cacheip", $curwanip);
} }
/* perform RFC 2136 DNS update */
services_dnsupdate_process($interface);
/* signal dyndns update */ /* signal dyndns update */
services_dyndns_configure($interface); services_dyndns_configure($interface);
...@@ -201,7 +198,7 @@ if (!is_ipaddr($oldip) || $curwanip != $oldip || !is_ipaddrv4($config['interface ...@@ -201,7 +198,7 @@ if (!is_ipaddr($oldip) || $curwanip != $oldip || !is_ipaddrv4($config['interface
enable_rrd_graphing(); enable_rrd_graphing();
/* reload plugins */ /* reload plugins */
plugins_configure('interface'); plugins_configure('interface', false, array($interface));
} }
/* reload filter, don't try to sync to carp slave */ /* reload filter, don't try to sync to carp slave */
......
...@@ -139,9 +139,6 @@ if (is_ipaddrv6($oldipv6)) { ...@@ -139,9 +139,6 @@ if (is_ipaddrv6($oldipv6)) {
file_put_contents("/var/db/{$interface}_cacheipv6", $curwanipv6); file_put_contents("/var/db/{$interface}_cacheipv6", $curwanipv6);
} }
/* perform RFC 2136 DNS update */
services_dnsupdate_process($interface);
/* signal dyndns update */ /* signal dyndns update */
services_dyndns_configure($interface); services_dyndns_configure($interface);
......
...@@ -111,21 +111,19 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') { ...@@ -111,21 +111,19 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
write_config('New/Edited RFC2136 dnsupdate entry was posted'); write_config('New/Edited RFC2136 dnsupdate entry was posted');
if (!empty($pconfig['force'])) { if (!empty($pconfig['force'])) {
services_dnsupdate_process("", $rfc2136['host'], true); rfc2136_configure_do(false, '', $rfc2136['host'], true);
} else { } else {
services_dnsupdate_process(); rfc2136_configure_do();
} }
header(url_safe('Location: /services_rfc2136.php')); header(url_safe('Location: /services_rfc2136.php'));
exit; exit;
} }
} }
legacy_html_escape_form_data($pconfig); legacy_html_escape_form_data($pconfig);
include("head.inc"); include("head.inc");
?>
?>
<body> <body>
<?php include("fbegin.inc"); ?> <?php include("fbegin.inc"); ?>
<section class="page-content-main"> <section class="page-content-main">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment