#!/usr/bin/perl -w #---------------------------------------------------------------------- # Ipsec actions # Copyright (C) 2015 John Crisp # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # 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 or more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #---------------------------------------------------------------------- # Note that we do not need to use the init ipsec script - we can start and # stop directly using /usr/sbin/ipsec which will call the init script # Probably ought to check somewhere that the status of services is public # But if it is private then you have to re-expand masq someplace use strict; use warnings; use esmith::ConfigDB; my $configDB = esmith::ConfigDB->open or die("can't open Config DB"); my $ipsecDB = esmith::ConfigDB->open('ipsec_connections') or die("Ipsec Error - cant connect to ipsec database"); my $ipsecDBkey = 'ipsec'; my $xl2tpdDBkey = 'xl2tpd'; my $xl2tpdipsecprop = "L2TPD-PSK"; # Check on access status - we'll use this later # If status goes to disabled we should set this private my $ipsec_access = $configDB->get_prop( $ipsecDBkey, 'access' ) || 'private'; print "Ipsec Information - IpsecAccessState: $ipsec_access\n"; # If the service is set disabled then make sure it is stopped # Note that ipsec is not a service so we cannot use the normal service commands if ( $configDB->get_prop( $ipsecDBkey, 'status' ) eq 'disabled' ) { # Always reset redirects on stop print "Ipsec Information - reset redirects"; resetRedirects(); # Sort out xl2tpd - if ipsec is disabled it has to be stopped print "Xl2tpd Information - ipsec is disabled - Stopping xl2tpd \n"; my $myStopXl2tpd = qx(/etc/rc.d/init.d/xl2tpd stop) || die("xl2tpd Error - Unable to launch xl2tpd stop : $!\n"); if ( not defined $myStopXl2tpd ) { die("Ipsec Error - Unable to stop xl2tpd( error code $?)\n") if $?; } # Do we check if it is already stopped ? # For now we stop it regardless print "Ipsec Information - ipsec disabled - Stopping ipsec \n"; my $myStopConnection = qx(/etc/rc.d/init.d/ipsec stop) || die("Ipsec Error - Unable to launch ipsec stop : $!\n"); if ( not defined $myStopConnection ) { die("Ipsec Error - Unable to stop ipsec( error code $?)\n") if $?; } exit 0; } # If the ipsec service is set to enabled AND running (then check the connections) if ( $configDB->get_prop( $ipsecDBkey, 'status' ) eq 'enabled' ) { # Sort out xl2tpd - if ipsec is enabled, AND xl2tpd then see if it is started my $xl2tpdstatus = $configDB->get_prop( $xl2tpdDBkey, 'status' ) || 'disabled'; if ( $xl2tpdstatus eq 'enabled' ) { my $xl2tpdService = (`ps ax | grep -v grep | grep xl2tpd`); #If the service is not running then start it unless ( $xl2tpdService =~ m/xl2tpd/ ) { print "Xl2tpd Information - xl2tpd enabled but stopped - restarting xl2tpd \n"; my $myStartXl2tpd = qx(/etc/rc.d/init.d/xl2tpd restart) || die("xl2tpd Error - Unable to launch xl2tpd restart : $!\n"); if ( not defined $myStartXl2tpd ) { die("Ipsec Error - Unable to stop xl2tpd( error code $?)\n") if $?; } } } my $status = (`ps ax | grep -v grep | grep pluto`); # If the ipsec service is running if ( $status =~ m/_plutorun/ ) { # Lets do some stuff print "Ipsec Information - ipsec is running !\n"; # make sure reDirects are right setRedirects(); # Load the connections my @connections = $ipsecDB->keys; foreach my $ipsecprop (@connections) { #Check the individual connection status my $ipsecstatus = $ipsecDB->get_prop( "$ipsecprop", 'status' ) || "disabled"; # What type of connection are we ? my $connection = $ipsecDB->get_prop( "$ipsecprop", 'auto' ) || ''; # Lets check the last state and if it doesn't exist set it disabled if ( not defined( $ipsecDB->get_prop( $ipsecprop, 'PreviousState' ) ) ) { my $previpsecstatus = "disabled"; $ipsecDB->set_prop( $ipsecprop, "PreviousState", $previpsecstatus ); } # Now we should have it my $previpsecstatus = $ipsecDB->get_prop( $ipsecprop, 'PreviousState' ); print "Ipsec Information - PrevState: $previpsecstatus CurrState: $ipsecstatus\n"; # Lets reread secrets anyway print "Ipsec Information - Restart - ReReading Secrets\n"; my $reread = qx(/usr/sbin/ipsec auto --rereadsecrets); die("Ipsec Error - Unable launch ipsec reread secrets : $!\n") if not defined $reread; die("Ipsec Error - Unable to reread ipsec secrets ( error code $?)\n") if $?; # If we are enabled if ( ( $previpsecstatus eq "enabled" ) && ( $ipsecstatus eq "enabled" ) ) { # Restart print "Ipsec Information - Restarting connection - $ipsecprop\n"; # Have to use system here as replace usually returns 1280 # Replace just rereads the config and does --delete --add system("/usr/sbin/ipsec auto --replace $ipsecprop"); print "Ipsec Information - Restart system - replace return code: $?\n"; # If connection = start then bring it up if ( $connection eq 'start' ) { print "Ipsec Information - En - En - Auto --async --up $ipsecprop\n"; # If it is start rather than add we try and force it to come up startConnection($ipsecprop); print "Ipsec Information - En - En auto --up\n"; print "Ipsec Information - Restart system - up return code: $?\n"; } # Set Previous status changeState( $ipsecprop, $ipsecstatus ); } # If status is disabled then stop it elsif (( $previpsecstatus eq "disabled" ) && ( $ipsecstatus eq "disabled" ) ) { # Stop print "Ipsec Information - Stop connection - $ipsecprop\n"; stopConnection($ipsecprop); # Set Previous status changeState( $ipsecDBkey, $ipsecstatus ); } # If status was disabled and now enabled then start it elsif (( $previpsecstatus eq "disabled" ) && ( $ipsecstatus eq "enabled" ) ) { # Start print "Enabling connection $ipsecprop\n"; # Have to use system here as replace usually returns 1280 and not 0 system("/usr/sbin/ipsec auto --replace $ipsecprop"); print "Ipsec Information - Restart system - return code: $?\n"; if ( $connection eq 'start' ) { # Have to use exec here as system waits for a return and if the connection # does not come up it will just hang. So fire 'n forget print "Ipsec Information - Dis- En - - Auto --async --up $ipsecprop\n"; startConnection($ipsecprop); print "Ipsec Information - Dis - En auto --up\n"; print "Ipsec Information - Restart system - up return code: $?\n"; #or die "exec failed!"; } # Set Previous status changeState( $ipsecprop, $ipsecstatus ); } # If status was enabled and now disabled then stop it elsif (( $previpsecstatus eq "enabled" ) && ( $ipsecstatus eq "disabled" ) ) { # Stop and remove - do we need to ? print "Ipsec Information - Stopping connection $ipsecprop\n "; stopConnection($ipsecprop); # Set Previous status changeState( $ipsecprop, $ipsecstatus ); } # Should never be here as it means the statuses are other than enabled or disabled else { print "Ipsec Error - Something went wrong with ipsec connection status\n"; } } } # If it isn't running then start it up # Auto connections start themselves. Added connections wait else { print "Ipsec Information - Disable Reverse Path Filtering\n"; setRedirects(); # Make sure access = public unless ( $ipsec_access eq 'public' ) { $configDB->set_prop( $ipsecDBkey, 'access', 'public' ); } print "Ipsec Information - ipsec enabled - Starting ipsec\n "; my $myStartConnection = qx(/etc/rc.d/init.d/ipsec start); die("Ipsec Error - Unable to launch ipsec start : $!\n ") if not defined $myStartConnection; die("Ipsec Error - Unable to launch ipsec start ( error code $?)\n ") if $?; exit 0; } exit 0; } #### Subroutines here sub changeState { #@_ contains $ipsecDBkey and $ipsecstatus $ipsecDB->set_prop( $_[0], 'PreviousState', $_[1] ); } sub startConnection { system("/usr/sbin/ipsec auto --asynchronous --up $_[0]"); } sub stopConnection { print "Ipsec Information - SubRoutine - stop connection $_[0]\n "; system("/usr/sbin/ipsec auto --down $_[0]"); print "Ipsec Information - system down code: $?\n"; system("/usr/sbin/ipsec auto --delete $_[0]"); print "Ipsec Information - system delete code: $?\n"; } sub setRedirects { my $internalIf = $configDB->get_prop( 'InternalInterface', 'Name' ); my $externalIf = $configDB->get_prop( 'ExternalInterface', 'Name' ); # Big warning - this is a potential security issue # Make sure you read and understand what happens ! # If I knew which specific interfaces to change we could reduce the lines here system("/sbin/sysctl -w net.ipv4.conf.all.send_redirects=0") == 0 or die("Ipsec Error - A problem occurred with sysctl: $?"); system("/sbin/sysctl -w net.ipv4.conf.default.send_redirects=0") == 0 or die("Ipsec Error - A problem occurred with sysctl: $?"); system("/sbin/sysctl -w net.ipv4.conf.all.accept_redirects=0") == 0 or die("Ipsec Error - A problem occurred with sysctl: $?"); system("/sbin/sysctl -w net.ipv4.conf.default.accept_redirects=0") == 0 or die("Ipsec Error - A problem occurred with sysctl: $?"); system("/sbin/sysctl -w net.ipv4.conf.default.rp_filter=0") == 0 or die("Ipsec Error - A problem occurred with sysctl: $?"); system("/sbin/sysctl -w net.ipv4.conf.all.rp_filter=0") == 0 or die("Ipsec Error - A problem occurred with sysctl: $?"); system("/sbin/sysctl -w net.ipv4.conf.$externalIf.rp_filter=0") == 0 or die("Ipsec Error - A problem occurred with sysctl: $?"); system("/sbin/sysctl -w net.ipv4.conf.$internalIf.rp_filter=0") == 0 or die("Ipsec Error - A problem occurred with sysctl: $?"); } sub resetRedirects { # /etc/syctl.conf is expanded on ipsec-update # This should reload the file - if ipsec is disabled it should reset to defaults # If ipsec is enabled it should disable rp_filtering system("/sbin/sysctl -p") == 0 or die("Ipsec Error - A problem occurred with sysctl: $?"); }