#!/usr/bin/perl # # Module: vyos-restore-static-ipv6.pl # # **** License **** # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # Copyright (C) 2014 VyOS Development Group # # **** End License **** use lib "/opt/vyatta/share/perl5"; use strict; use warnings; use POSIX; use Fcntl; use Sys::Syslog; use Vyatta::Config; use Vyatta::Interface; use Data::Dumper; use constant { # Program settings PROGRAM_NAME => "vyos-intfwatchd", PROGRAM_VERSION => "1.0", PID_FILE => "/var/run/vyos-intfwatchd.pid", # Program exit codes SUCCESS => 0, ERROR => 1, # Subroutine error codes SUB_ERROR => 0, SUB_SUCCESS => 1, # Fcntl file lock/unlock constants SET_EXCLUSIVE_LOCK => 2, UNLOCK => 8 }; my $debug = 0; sub daemonize { syslog("info", "%s", "Starting in daemon mode"); my $pid = fork(); if (!defined($pid)) { # Fork failed die "Could not spawn child process: $!, exiting"; } elsif ($pid > 0) { # Child has been spawned succefully, # parent should terminate now exit(SUCCESS); } chdir("/"); umask(0); setsid(); # Close standard i/o stream descriptors open STDIN, "/dev/null" or die "Can't read /dev/null: $!"; open STDOUT, ">>/dev/null" or die "Can't write to /dev/null: $!"; open STDERR, ">>/dev/null" or die "Can't write to /dev/null: $!"; } sub writePid { my ($pid, $fh) = @_; unless (flock($fh, SET_EXCLUSIVE_LOCK)) { syslog("err", "%s", "Could not lock PID file: $!"); exit(ERROR); } print($fh $pid); } sub releasePid { my $fh = shift; flock($fh, UNLOCK); close($fh); unlink(PID_FILE); } daemonize(); my $pidFile = PID_FILE; unless (open PID_HANDLE, ">$pidFile") { syslog("err", "%s", "Could not create PID file: $!"); exit(1); } writePid($$, \*PID_HANDLE); my $config = new Vyatta::Config(); my $ip_monitor = "ip monitor link"; unless (open(HANDLE, "$ip_monitor|")) { syslog("err", "%s", qq{Could not start IP monitor: $!\n}); exit(1); } sub terminate { my $error = shift; syslog("notice", "%s", PROGRAM_NAME." is terminating"); releasePid(\*PID_HANDLE); exit(0); } $SIG{'INT'} = \&terminate; $SIG{'TERM'} = \&terminate; $SIG{'KILL'} = sub { exit(0); }; # This solution should be bad enough to be fixed immediately # when feasible. while() { if( $_ =~ /^[0-9]+:\s+([^@]+)(@.*)*:\s+<.*UP,.*>/ ) { my $intf_name = $1; my $intf = new Vyatta::Interface($intf_name); my $intf_addr_path = $intf->path() . " address"; # Get IPv6 addresses my @addresses = grep /:/, $config->returnEffectiveValues($intf_addr_path); print Dumper(@addresses) if $debug; foreach my $address (@addresses) { system("ip address add $address dev $intf_name"); if( $? != 0 ) { syslog("err", "%s", "Could not add address $address: $!"); } else { syslog("notice", "%s", "Restoring address $address on interface $intf_name"); } } $intf = undef; } }