diff options
author | marjohn56 <martin@queens-park.com> | 2017-02-08 22:49:52 +0000 |
---|---|---|
committer | marjohn56 <martin@queens-park.com> | 2017-03-08 08:42:00 +0000 |
commit | 718cbc2d3921627e9767e59d539386c843dffcc4 (patch) | |
tree | c8a4b07d5ae0cf1023ca354d06fe9b92a1b375cc /src | |
parent | f0136b178022cf3b04a6c3d577d457cf3bc03418 (diff) | |
download | pfsense-718cbc2d3921627e9767e59d539386c843dffcc4.zip pfsense-718cbc2d3921627e9767e59d539386c843dffcc4.tar.gz |
New dhcp6c features REASONS and signals
This PR takes advantage of modifications and additions to dhcp6c.
Firstly, a fix has been made to dhcp6c where the pid was being deleted
before all processes had completed; this could leave dhcp6c sending
release signals but any check for the process using the pid would return
false; thus if the server was not responding or the WAN was down then
dhcp6c could sit there for tens of seconds even though it appeared to
have exited.
The env var REASON has been updated to provide information as to why the
script has been called. These can be one of the following:
REASON=INFO
REASON=REPLY
REASON=RENEW
REASON=RELEASE
REASON=REBIND
REASON=EXIT
REASON=OTHER
The OTHER is a final catch and should never happen.
The scripts take advantage of these vars, for example a renew no longer
calls rc.newwanipv6.
The use of SIGUSR1 and SIGUSR2 to terminate dhcp6c results in different
exits. SIGUSR1 will force an exit without sending a release to the
server, this is used in the case of a WAN down event to prevent dhcp6c
from hanging on a release signal. SIGUSR2 is used to send a relase
signal overiding the no-release flag ( if set ), no code or GUI
additions have been added to make use of this signal in this PR. The
existing SIGTERM will cause dhcp6c to exit normally obeying the
no-release flag if set.
NOTE - The code for SIGUSR2 is in place in this file but as yet it is not
included in dhcp6c. In the event of SIGUSR2 being called, it will fall
through to a standard SIGTERM exit.
Debugging messages have been added to the scripts
dhcp6c_{$interface}dhcp6withoutra_script.sh and
dhcp6c{$interface}_script.sh. These debug messages only appear if the
debug setting for dhcp6c has been set in the config, they also appear in
the dhcp log rather than the main system log.
This PR is dependant on PR#5 at hrs-allbsd:freebsd or
pfsense/FreeBSD-ports #299
These changes are in response to Redmine 5993, 6944, 7145 and 7185.
Updated to match new upstream dhcp6c
changed REASON=REPLY to REASON=REQUEST.
K&R Corrections
Diffstat (limited to 'src')
-rw-r--r-- | src/etc/inc/interfaces.inc | 179 |
1 files changed, 137 insertions, 42 deletions
diff --git a/src/etc/inc/interfaces.inc b/src/etc/inc/interfaces.inc index 74a8a33..273b8ff 100644 --- a/src/etc/inc/interfaces.inc +++ b/src/etc/inc/interfaces.inc @@ -1300,7 +1300,7 @@ function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = switch ($ifcfg['ipaddrv6']) { case "slaac": case "dhcp6": - kill_dhcp6client_process($realif, isset($ifcfg['dhcp6norelease'])); + kill_dhcp6client_process($realif, $destroy, false); unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf"); unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh"); unlink_if_exists("{$g['varetc_path']}/rtsold_{$realifv6}_script.sh"); @@ -3039,33 +3039,61 @@ function find_dhcp6c_process($interface) { return intval($pid); } -function kill_dhcp6client_process($interface, $norelease) { +function kill_dhcp6client_process($interface, $force, $release = false) { global $g; + $i = 0; + + /* + Beware of the following: Reason, the interface may be down, but + dhcp6c may still be running, it just complains it cannot send + and carries on. Commented out as will stop the call to kill. + if (empty($interface) || !does_interface_exist($interface)) { return; } + */ - if (($pid = find_dhcp6c_process($interface)) != 0) { - /* - * Kill -9 caused the pid to get left behind, also if we need a - * relase sent then it needs to be -15, this then allows dhcp6c - * to send the release, it will also clean up after itself - */ - $sig = (isset($norelease) ? SIGKILL : SIGTERM); - posix_kill($pid, $sig); - if(!isset($norelease)) { - /* - * Allow dhcp6c to send release and exit gracefully if - * needed. - */ - sleep(2); - } + /*********** Notes on signals for dhcp6c and this function ************* + + If we have Taken the WAN interface down, then dhcp6c sits there sending + a release and waiting for the response that never comes. + So we need to tell it that the interface is down and to just die quickly + otherwise a new client may launch and we have duplicate proceses. + In this case use SIGUSR1. + + If we want to exit normally obeying the no release flag then use SIGTERM. + If we want to exit with a release overiding the no release flag then + use SIGUSR2. + + If $Force is true it will use SIGUSR1, thus forcing dhcp6c to + exit quickly without sending release signals. + + If $Force is set to false and $release is also set to false dhcp6c will + follow the no-release flag. + + If $Force is set to false and $release is true then dhcp6c will send a + release regardless of the no-release flag. + ***********************************************************************/ + + if ($force == true) { + $psig=SIGUSR1; + } else if ($release == false) { + $psig=SIGTERM; + } else { + $psig=SIGUSR2; } - /* Clear the RTSOLD script created lock & tidy up */ + + while ((($pid = find_dhcp6c_process($interface)) != 0) && ($i < 3)) { + /* 3rd time make it die for sure */ + $sig = ($i == 2 ? SIGKILL : $psig); + posix_kill($pid, $sig); + sleep(1); + $i++; + } + /* Clear the RTSOLD script created lock & tidy up */ unlink_if_exists("/tmp/dhcp6c_{$interface}_lock"); - /* just in case! */ - unlink_if_exists("{$g['varrun_path']}/dhcp6c_{$interface}.pid"); + unlink_if_exists("{$g['varrun_path']}/dhcp6c_{$interface}.pid"); // just in case! } function run_dhcp6client_process($interface, $wancfg) { @@ -3083,8 +3111,7 @@ function run_dhcp6client_process($interface, $wancfg) { * lock deleted. */ if (!file_exists("/tmp/dhcp6c_{$interface}_lock")) { - kill_dhcp6client_process($interface, - isset($wancfg['dhcp6norelease'])); + kill_dhcp6client_process($realif, true); /* Lock it to avoid multiple runs */ touch("/tmp/dhcp6c_{$interface}_lock"); @@ -3940,6 +3967,13 @@ function interface_dhcpv6_configure($interface = "wan", $wancfg) { log_error(gettext("Failed to write user DUID file!")); } } + + /* accept router advertisements for this interface */ + /* Moved to early in the function as sometimes interface not ready */ + /* RTSOLD fails as interface does not accept ..... */ + + log_error("Accept router advertisements on interface {$wanif} "); + mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv"); if ($wancfg['adv_dhcp6_config_file_override']) { // DHCP6 Config File Override @@ -4017,6 +4051,9 @@ function interface_dhcpv6_configure($interface = "wan", $wancfg) { } } + $debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d"; + $noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : ""; + /* wide-dhcp6c works for now. */ if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) { printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n"); @@ -4025,20 +4062,55 @@ function interface_dhcpv6_configure($interface = "wan", $wancfg) { } unset($dhcp6cconf); - /* - * Script create for dhcp6withoutRA mode. - * dhcp6c will launch rtsold. rtsold will then run the wan ipv6 - * configure - */ - $dhcp6cscriptwithoutra = "#!/bin/sh\n"; + /*************** Script Debug Logging *************************** + Both dhcp6 scripts now have a logging message built in. + These logging messages ONLY appear if dhcp6c debug logging is set. + The logging messages appear in the dhcp section of the logs, + not in system. + + These scripts now also take advantage of the REASON= env vars + supplied by dhcp6c. + ****************************************************************/ + + /* Script create for dhcp6withoutRA mode */ + /* dhcp6c will launch rtsold. rtsold will then run the wan ipv6 configure */ + $dhcp6cscriptwithoutra = "#!/bin/sh\n"; $dhcp6cscriptwithoutra .= "# This shell script launches rtsold.\n"; $dhcp6cscriptwithoutra .= "dmips=\${new_domain_name_servers}\n"; $dhcp6cscriptwithoutra .= "dmnames=\${new_domain_name}\n"; + $dhcp6cscriptwithoutra .= "dreason=\${REASON}\n"; // Need to pass params to the final script $dhcp6cscriptwithoutra .= "echo \$dmips > /tmp/{$wanif}_domain_name_servers\n"; $dhcp6cscriptwithoutra .= "echo \$dmnames > /tmp/{$wanif}_new_domain_name\n"; + $dhcp6cscriptwithoutra .= "echo \$dreason > /tmp/{$wanif}_reason\n"; + $dhcp6cscriptwithoutra .= "case \$REASON in\n"; + $dhcp6cscriptwithoutra .= "REQUEST)\n"; + $dhcp6cscriptwithoutra .= "/bin/sleep 2\n"; $dhcp6cscriptwithoutra .= "/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}\n"; - + if ($debugOption == '-D') { + $dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c REQUEST on {$wanif} - running rc.newwanipv6\"\n"; + } + $dhcp6cscriptwithoutra .= ";;\n"; + $dhcp6cscriptwithoutra .= "REBIND)\n"; + if ($debugOption == '-D') { + $dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n"; + } + $dhcp6cscriptwithoutra .= ";;\n"; + if (isset($wancfg['dhcp6norelease'])) { + $dhcp6cscriptwithoutra .= "EXIT)\n"; + } else { + $dhcp6cscriptwithoutra .= "RELEASE)\n"; + } + if ($debugOption == '-D') { + $dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n"; + } + $dhcp6cscriptwithoutra .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n"; + $dhcp6cscriptwithoutra .= ";;\n"; + $dhcp6cscriptwithoutra .= "RENEW|INFO)\n"; + if ($debugOption == '-D') { + $dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n"; + } + $dhcp6cscriptwithoutra .= "esac\n"; if (!@file_put_contents( "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh", $dhcp6cscriptwithoutra)) { @@ -4048,6 +4120,7 @@ function interface_dhcpv6_configure($interface = "wan", $wancfg) { unset($dhcp6cscriptwithoutra); return 1; } + unset($dhcp6cscriptwithoutra); @chmod( "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh", @@ -4062,12 +4135,41 @@ function interface_dhcpv6_configure($interface = "wan", $wancfg) { if (!isset($wancfg['dhcp6withoutra'])) { $dhcp6cscript .= "dmips=\${new_domain_name_servers}\n"; $dhcp6cscript .= "dmnames=\${new_domain_name}\n"; + $dhcp6cscript .= "case \$REASON in\n"; + $dhcp6cscript .= "REQUEST)\n"; + $dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n"; + if ($debugOption == '-D') { + $dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c REQUEST on {$wanif} - running rc.newwanipv6\"\n"; + } + $dhcp6cscript .= ";;\n"; + $dhcp6cscript .= "REBIND)\n"; + if ($debugOption == '-D') { + $dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n"; + } + $dhcp6cscript .= ";;\n"; + if (isset($wancfg['dhcp6norelease'])) { + $dhcp6cscript .= "EXIT)\n"; + } else { + $dhcp6cscript .= "RELEASE)\n"; + } + if ($debugOption == '-D') { + $dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n"; + } + $dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n"; + $dhcp6cscript .= ";;\n"; + $dhcp6cscript .= "RENEW|INFO)\n"; + if ($debugOption == '-D') { + $dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n"; + } + $dhcp6cscript .= "esac\n"; } else { // Need to get the paramaters from the dhcp6cwithoutRA run $dhcp6cscript .= "dmips=\$(cat \"/tmp/{$wanif}_domain_name_servers\")\n"; $dhcp6cscript .= "dmnames=\$(cat \"/tmp/{$wanif}_new_domain_name\")\n"; + $dhcp6cscript .= "/bin/sleep 1\n"; + $dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n"; } - $dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n"; + /* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */ if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) { printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n"); @@ -4077,9 +4179,6 @@ function interface_dhcpv6_configure($interface = "wan", $wancfg) { unset($dhcp6cscript); @chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755); - $debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d"; - $noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : ""; - $rtsoldscript = "#!/bin/sh\n"; $rtsoldscript .= "# This shell script launches dhcp6c and configured gateways for this interface.\n"; $rtsoldscript .= "echo $2 > {$g['tmp_path']}/{$wanif}_routerv6\n"; @@ -4097,16 +4196,16 @@ function interface_dhcpv6_configure($interface = "wan", $wancfg) { * of dhcp6c being launched */ $rtsoldscript .= "if [ ! -f /tmp/dhcp6c_{$wanif}_lock ]; then\n"; - $rtsoldscript .= "\tif [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n"; - $rtsoldscript .= "\t\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n"; - $rtsoldscript .= "\t\t/bin/rm -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n"; - $rtsoldscript .= "\t\t/bin/sleep 1\n"; - $rtsoldscript .= "\tfi\n"; /* * Create the lock file, trying to prevent multiple instances * of dhcp6c being launched */ $rtsoldscript .= "\t/usr/bin/touch /tmp/dhcp6c_{$wanif}_lock\n"; + $rtsoldscript .= "\tif [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n"; + $rtsoldscript .= "\t\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n"; + $rtsoldscript .= "\t\t/bin/rm -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n"; + $rtsoldscript .= "\t\t/bin/sleep 1\n"; + $rtsoldscript .= "\tfi\n"; $rtsoldscript .= "\t/usr/local/sbin/dhcp6c {$debugOption} " . "{$noreleaseOption} -c {$g['varetc_path']}/dhcp6c_{$interface}.conf " . "-p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n"; @@ -4132,10 +4231,6 @@ function interface_dhcpv6_configure($interface = "wan", $wancfg) { unset($rtsoldscript); @chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755); - /* accept router advertisements for this interface */ - log_error("Accept router advertisements on interface {$wanif} "); - mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv"); - if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) { killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid"); sleep(2); |