summaryrefslogtreecommitdiffstats
path: root/src/etc/inc/interfaces.inc
diff options
context:
space:
mode:
authormarjohn56 <martin@queens-park.com>2017-01-20 14:42:09 +0000
committermarjohn56 <martin@queens-park.com>2017-01-20 14:42:09 +0000
commitcdb6c8ac8e65f98a2ac0fa469c963c055a5c522d (patch)
tree5dc77255dc69e82866f79ec952c228d46c0790d1 /src/etc/inc/interfaces.inc
parentc744b0de92b17ced8238723042a314db45b76c53 (diff)
downloadpfsense-cdb6c8ac8e65f98a2ac0fa469c963c055a5c522d.zip
pfsense-cdb6c8ac8e65f98a2ac0fa469c963c055a5c522d.tar.gz
RTSOLD lock creation, dhcp6c launch & kill changes #3
Added lock file creation and check to RTSOLD script creation. This is to prevent mutliple launches of dhcp6c, this appears to happen when multiple RA's are received in rapid succession at the start of a session. Once created dhcp6c cannot be launched again until the lock file is deleted, this is done within the kill_dhcp6_client process locking the two together. The kill vlaue used to kill the dhcp6c client is now variable. The value -9 causes the process to exit without sending a release if required, and if the timing is just rignt can cause the pid file to be left behind; -15 allows for a graceful exit and if the release flag is not set then it sends and waits for the release confirnation, the value now switches between those depending on the configuration option 'No Release'. If no release is true then -9 is used as the type. Any left behind pid is removed automatically. This change will make it possible to stop the use of the -n flag, thus allowing the dcp6c to send a release manually, if so required. The launch of dhcp6c when in dhcp6withoutRA is moved to its own function, as uch as anything this makes the code tidy around the bottom of nterface_dhcpv6_configure(). A completely new method of implimenting dhcp6wihtoutRA is used. In default mode RTSOLD launches dhcp6c. In dhcp6wihtoutRA mode dhcp6 aunches RTSOLD. New scripts are created and old ones modified to handle this mode, the dhcp6 conf file changes depending on the mode calling a different script for each mode. In simple terms its dcp6->rtsold- lan_configure. Whenever dhcp6 gets a response that launches its script then it will run rtsold, the RA in turn will cause the wan6 configure script to run. This method also means the script only ever runs once and no modified dhcp6c is required. The scripts are dynamic and change depending on the mode. Creation takes into account that the domain-name-server variables created by dhcp6 and passed to the script it calls are passed on. In default mode this is simple as it calls the dhcp6c_*_script which calls the rc.newwanipv6 script directly, in dhcp6withoutRA its RTSOLD that calls the dhcp6c_*_script, so in order to make this change work the variables are echoed to the tmp folder and retreived by the dhcp6withoutRA version of dhcp6c_*_script when that calls rc.newwanip.
Diffstat (limited to 'src/etc/inc/interfaces.inc')
-rw-r--r--src/etc/inc/interfaces.inc122
1 files changed, 97 insertions, 25 deletions
diff --git a/src/etc/inc/interfaces.inc b/src/etc/inc/interfaces.inc
index f2d2e30..c03d713 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);
+ kill_dhcp6client_process($realif,isset($ifcfg['dhcp6norelease']));
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,14 +3039,44 @@ function find_dhcp6c_process($interface) {
return intval($pid);
}
-function kill_dhcp6client_process($interface) {
+function kill_dhcp6client_process($interface,$norelease) {
+ global $g;
+
if (empty($interface) || !does_interface_exist($interface)) {
return;
}
if (($pid = find_dhcp6c_process($interface)) != 0) {
- mwexec("kill -9 {$pid}");
- sleep(1);
+ /* 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 */
+ // Debug - next line remove if not required
+ mwexec("/usr/bin/logger -t info 'shutting down dhcp6c process'");
+ $killtype = isset($norelease) ? "-9" : "-15";
+ mwexec("kill {$killtype} {$pid}");
+ if(!isset($norelease)) {
+ sleep(2); //Allow dhcp6c to send releae and exit gracefully if needed.
+ }
+ }
+ /* Clear the RTSOLD script created lock & tidy up */
+ unlink_if_exists("/tmp/dhcp6c_{$interface}_lock");
+ unlink_if_exists("{$g['varrun_path']}/dhcp6c_{$interface}.pid"); // just in case!
+}
+
+function run_dhcp6client_process($interface, $wancfg) {
+ global $g;
+
+ $debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
+ $noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
+ // Only run this if the lock does not exist. In theory the lock being there in this mode means the user has selected dhcp6withoutRA while a session is active in the other mode
+ // It should not happen as the process should have been killed and the lock deleted.
+ if(!file_exists("/tmp/dhcp6c_{$interface}_lock"))
+ {
+ kill_dhcp6client_process($interface,isset($wancfg['dhcp6norelease'])); //Should not be required, but belts an
+
+ touch("/tmp/dhcp6c_{$interface}_lock"); // Lock it, only one run please.
+ mwexec("/usr/local/sbin/dhcp6c {$debugOption} {$noreleaseOption} -c {$g['varetc_path']}/dhcp6c_wan.conf -p {$g['varrun_path']}/dhcp6c_{$interface}.pid {$interface}");
+ mwexec("/usr/bin/logger -t info 'Starting dhcp6 client for interface wan({$wanif} in DHCP6 without RA mode)'");
}
}
@@ -3892,7 +3922,7 @@ function interface_dhcpv6_configure($interface = "wan", $wancfg) {
log_error(gettext("Failed to write user DUID file!"));
}
}
-
+
if ($wancfg['adv_dhcp6_config_file_override']) {
// DHCP6 Config File Override
$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
@@ -3929,7 +3959,13 @@ function interface_dhcpv6_configure($interface = "wan", $wancfg) {
$dhcp6cconf .= "\trequest domain-name-servers;\n";
$dhcp6cconf .= "\trequest domain-name;\n";
+
+ /* dhcp6c will run different scripts depending on whether dhcpwithoutra is set or unset. */
+ if (isset($wancfg['dhcp6withoutra'])) {
+ $dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\"; # we'd like nameservers and RTSOLD to do all the work\n";
+ } else {
$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
+ }
$dhcp6cconf .= "};\n";
if (!isset($wancfg['dhcp6prefixonly'])) {
@@ -3968,10 +4004,37 @@ 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";
+ $dhcp6cscriptwithoutra .= "# This shell script launches rtsold.\n";
+ $dhcp6cscriptwithoutra .= "dmips=\${new_domain_name_servers}\n";
+ $dhcp6cscriptwithoutra .= "dmnames=\${new_domain_name}\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 .= "/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}\n";
+
+ if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh", $dhcp6cscriptwithoutra)) {
+ printf("Error: cannot open dhcp6c_{$interface}_dhcp6cwithoutra_script.sh in interface_dhcpv6_configure() for writing.\n");
+ unset($dhcp6cscriptwithoutra);
+ return 1;
+ }
+ unset($dhcp6cscriptwithoutra);
+ @chmod("{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh", 0755);
+
+ /* Dual mode wan_dhcp6c script with variations depending on node */
+ /* dhcp6 will run the wan ipv6 configure */
$dhcp6cscript = "#!/bin/sh\n";
$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
- $dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
- $dhcp6cscript .= "dmnames=\${new_domain_name}\n";
+ if (!isset($wancfg['dhcp6withoutra'])) {
+ $dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
+ $dhcp6cscript .= "dmnames=\${new_domain_name}\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 .= "/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)) {
@@ -3982,6 +4045,9 @@ 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";
@@ -3990,22 +4056,25 @@ function interface_dhcpv6_configure($interface = "wan", $wancfg) {
/* non ipoe Process */
if (!isset($wancfg['dhcp6withoutra'])) {
+ // We only want this script to run once, and if it runs twice then do not launch dhcp6c again, this only happens if dhcpwithoutra is not set
+ // Check for a lock file, trying to prevent multiple instances of dhcp6c being launched
+ $rtsoldscript .= "if [ ! -f /tmp/dhcp6c_{$wanif}_lock ]; then\n";
$rtsoldscript .= "if [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
$rtsoldscript .= "\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
+ $rtsoldscript .= "\t/bin/rm -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
$rtsoldscript .= "\t/bin/sleep 1\n";
$rtsoldscript .= "fi\n";
- } else {
- $rtsoldscript .= "{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\n";
- $rtsoldscript .= "/bin/sleep 1\n";
- }
- $debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
- $noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
-
-
- /* add the start of dhcp6c to the rtsold script if we are going to wait for ra */
- if (!isset($wancfg['dhcp6withoutra'])) {
+ // Create the lock file, trying to prevent multiple instances of dhcp6c being launched
+ $rtsoldscript .= "/usr/bin/touch /tmp/dhcp6c_{$wanif}_lock\n";
$rtsoldscript .= "/usr/local/sbin/dhcp6c {$debugOption} {$noreleaseOption} -c {$g['varetc_path']}/dhcp6c_{$interface}.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
$rtsoldscript .= "/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
+ // else statement is really just debugger info and can be removed if not required.
+ $rtsoldscript .= "else\n";
+ $rtsoldscript .= "/usr/bin/logger -t rtsold \"RTSOLD Lock in place\"\n";
+ $rtsoldscript .= "fi\n";
+ } else {
+ $rtsoldscript .= "{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\n"; // The script needs to run in dhcp6withoutra mode as RA may not have been received, or there can be a delay with certain ISPs
+ $rtsoldscript .= "/bin/sleep 1\n";
}
/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
@@ -4020,21 +4089,24 @@ function interface_dhcpv6_configure($interface = "wan", $wancfg) {
log_error("Accept router advertisements on interface {$wanif} ");
mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
- /* fire up rtsold for IPv6 RAs first, this backgrounds immediately. It will call dhcp6c */
if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
sleep(2);
}
- /* start dhcp6c here if we don't want to wait for ra */
if (isset($wancfg['dhcp6withoutra'])) {
- kill_dhcp6client_process($wanif);
-
- mwexec("/usr/local/sbin/dhcp6c {$debugOption} {$noreleaseOption} -c {$g['varetc_path']}/dhcp6c_wan.conf -p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}");
- mwexec("/usr/bin/logger -t info 'Starting dhcp6 client for interface wan({$wanif} in DHCP6 without RA mode)'");
+ /* start dhcp6c here if we don't want to wait for ra - calls seperate function */
+ // In this mode dhcp6c launches rtsold via its script. RTSOLD will then run the configure on receipt of the RA.
+ if(!file_exists("/tmp/dhcp6c_{$wanif}_lock")) // Already started. interface_dhcpv6_configure() appears to get called multiple times. Taking the interface down or releasing will kill the client.
+ {
+ // If the interface is being brought up, wait for the interface to configure accept RA before launching. Otherwise it is not ready to accept and will fail.
+ sleep(3);
+ run_dhcp6client_process($wanif,$wancfg);
+ }
+ } else {
+ /* fire up rtsold for IPv6 RAs, this backgrounds immediately ( it does not background, it exits! ) It will launch dhcp6c if dhcpwihtoutra is not set*/
+ mwexec("/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}");
}
- mwexec("/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}");
-
/* NOTE: will be called from rtsold invoked script
* link_interface_to_track6($interface, "update");
*/
OpenPOWER on IntegriCloud