#!/bin/sh # IPSEC startup and shutdown script # Copyright (C) 1998, 1999 Henry Spencer. # # 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. See . # # 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. # # RCSID $Id: setup,v 1.82 2000/05/24 16:49:33 henry Exp $ # # ipsec init.d script for starting and stopping # the IPSEC security subsystem (KLIPS and Pluto). # # This script becomes /etc/rc.d/init.d/ipsec (or possibly /etc/init.d/ipsec) # and is also accessible as "ipsec setup" (the preferred route for human # invocation). # # The startup and shutdown times are a difficult compromise (in particular, # it is almost impossible to reconcile them with the insanely early/late # times of NFS filesystem startup/shutdown). Startup is after startup of # syslog and pcmcia support; shutdown is just before shutdown of syslog. # # chkconfig: 2345 47 68 # description: IPSEC provides encrypted and authenticated communications; \ # KLIPS is the kernel half of it, Pluto is the user-level management daemon. if test " $IPSECDIR" = " " # if we were not called by the ipsec command then # we must establish a suitable PATH ourselves PATH=/usr/local/sbin:/sbin:/usr/sbin:/usr/local/bin:/bin:/usr/bin export PATH fi me='ipsec setup' # for messages # make sure output of (e.g.) ifconfig is in English LANG= LC_ALL= export LANG LC_ALL # verify permissions if test " `id -u`" != " 0" then echo "permission denied (must be superuser)" | logger -s -p daemon.error -t ipsec_setup exit 1 fi # Check that the ipsec command is available. found= for dir in `echo $PATH | tr ':' ' '` do if test -f $dir/ipsec -a -x $dir/ipsec then found=yes break # NOTE BREAK OUT fi done if ! test "$found" then echo "cannot find ipsec command -- aborting" | logger -s -p daemon.error -t ipsec_setup exit 1 fi # Pick up IPSEC configuration (until we have done this, successfully, we # do not know where errors should go, hence the explicit "daemon.error"s.) eval `ipsec _confread --varprefix IPSEC --type config setup` if test " $IPSEC_confreadstatus" != " " then echo "$IPSEC_confreadstatus -- aborting" | logger -s -p daemon.error -t ipsec_setup exit 1 fi # Misc. configuration (this should be overrideable from ipsec.conf someday). plutopid=/var/run/pluto.pid subsyslock=/var/lock/subsys/ipsec info=/var/run/ipsec.info umask 022 # some shell functions, to clarify the actual code # start KLIPS startklips() { # load module if necessary if test ! -f /proc/net/ipsec_version then depmod -a >/dev/null 2>&1 && modprobe ipsec if test ! -f /proc/net/ipsec_version then echo "KLIPS module-load attempt appears to have failed." echo "Fatal error, kernel appears to lack KLIPS." exit 1 fi fi # figure out debugging flags case "$IPSECklipsdebug" in '') IPSECklipsdebug=none ;; esac echo "KLIPS debug \`$IPSECklipsdebug'" | logonly case "$IPSECklipsdebug" in none) ipsec klipsdebug --none ;; all) ipsec klipsdebug --all ;; *) ipsec klipsdebug --none for d in $IPSECklipsdebug do ipsec klipsdebug --set $d done ;; esac # clear tables out in case dregs have been left over ipsec eroute --clear ipsec spi --clear # figure out interfaces for i in $IPSECinterfaces do case "$i" in ipsec*=?*) klipsinterface "$i" ;; %defaultroute) defaultinterface ;; *) echo "$me: interface \`$i' not understood, ignored" >&2 ;; esac done } # interfaces=%defaultroute: put ipsec0 on top of default route's interface defaultinterface() { phys=`netstat -nr | awk '$1 == "0.0.0.0" && $3 == "0.0.0.0" { print $NF }'` if test " $phys" = " " then echo "$me: no default route, %defaultroute cannot cope!!!" >&2 return # really should exit, hard to arrange fi if test `echo " $phys" | wc -l` -gt 1 then echo "$me: multiple default routes, %defaultroute cannot cope!!!" >&2 return # really should exit, hard to arrange fi next=`netstat -nr | awk '$1 == "0.0.0.0" && $3 == "0.0.0.0" { print $2 }'` klipsinterface "ipsec0=$phys" $next } # set up a Klips interface klipsinterface() { # pull apart the interface spec virt=`expr $1 : '\([^=]*\)=.*'` phys=`expr $1 : '[^=]*=\(.*\)'` # figure out ifconfig for interface addr= eval `ifconfig $phys | awk '$1 == "inet" && $2 ~ /^addr:/ && $4 ~ /^Mask:/ { gsub(/:/, " ", $0) print "addr=" $3 if ($4 == "Bcast") print "type=broadcast" else if ($4 == "P-t-P") print "type=pointopoint" else print "type=" print "otheraddr=" $5 print "mask=" $7 }'` if test " $addr" = " " then echo "$me: unable to determine address of \`$phys'" >&2 exit 1 fi if test " $type" = " " then echo "$me: \`$phys' is of an unknown type, can't use it" >&2 return fi echo "KLIPS $virt on $phys $addr/$mask $type $otheraddr" | logonly # attach the interface and bring it up ipsec tncfg --attach --virtual $virt --physical $phys ifconfig $virt inet $addr $type $otheraddr netmask $mask # if %defaultroute, note the facts if test " $2" != " " then ( echo "defaultroutephys=$phys" echo "defaultroutevirt=$virt" echo "defaultrouteaddr=$addr" if test " $2" != " 0.0.0.0" then echo "defaultroutenexthop=$2" fi ) >$info fi # check for advanced-router trouble checkif $virt checkif $phys } # check an interface for problems checkif() { rpf=/proc/sys/net/ipv4/conf/$1/rp_filter if test -f $rpf then r="`cat $rpf`" if test " $r" != " 0" then echo "WARNING: $1 has route filtering turned on, KLIPS may not work" echo " ($rpf = \`$r', should be 0)" fi fi } # set up manually-keyed connections manualconns() { if test " $IPSECmanualstart" != " " then for tu in $IPSECmanualstart do ipsec manual --up $tu done fi } # internal setup for Pluto start # sets up vars, so must do its own logging to avoid subprocess plutopre() { # searches, if needed if test " $IPSECplutoload" = " %search" then eval `ipsec _confread --varprefix PLUTO --search auto add start` if test " $PLUTO_confreadstatus" != " " then echo "$PLUTO_confreadstatus (load search) -- aborting" | logit exit 1 fi IPSECplutoload="$PLUTO_confreadnames" fi if test " $IPSECplutostart" = " %search" then eval `ipsec _confread --varprefix PLUTO --search auto start` if test " $PLUTO_confreadstatus" != " " then echo "$PLUTO_confreadstatus (start search) -- aborting" | logit exit 1 fi IPSECplutostart="$PLUTO_confreadnames" fi # ensure plutoload is a superset of plutostart for s in $IPSECplutostart do found= for lo in $IPSECplutoload do if test " $lo" = " $s" then found=yes fi done if test ! "$found" then IPSECplutoload="$IPSECplutoload $s" fi done # execute any preliminaries if test " $IPSECprepluto" != " " then $IPSECprepluto 2>&1 | logit fi } # start Pluto daemon plutodaemon() { # double-check one little detail if test ! -e /dev/random then echo "Cannot start Pluto, system lacks /dev/random !!!" exit 1 fi # figure out options pd= for d in $IPSECplutodebug do pd="$pd --debug-$d" done # do it if test " $IPSECdumpdir" = " " then ulimit -c 0 # preclude core dumps elif test ! -d "$IPSECdumpdir" then echo "Dumpdir \`$IPSECdumpdir' does not exist, ignored." ulimit -c 0 # preclude core dumps else cd $IPSECdumpdir # put them where desired ulimit -c unlimited # and permit them fi echo "Pluto debug \`$IPSECplutodebug'" | logonly ipsec pluto $pd } # Pluto subsystem startup and cleanup, after daemon is running plutopost() { # database load if test " $IPSECplutoload" != " " then echo "$IPSECplutoload" | tr ' ' '\n' | column -x -c 100 | tr -s '\t ' ' ' | while read bunch do for tu in $bunch do ipsec auto --add $tu done done fi # enable listening ipsec auto --ready # execute any cleanup if test " $IPSECpostpluto" != " " then $IPSECpostpluto fi # quickly establish routing if test " $IPSECplutostart" != " " then echo "$IPSECplutostart" | tr ' ' '\n' | column -x -c 100 | tr -s '\t ' ' ' | while read bunch do for tu in $bunch do ipsec auto --route $tu done done fi } # Pluto negotiation start (if any) plutogo() { # tunnel initiation, which may take a while if test " $IPSECplutostart" != " " then async= p= if test " $IPSECplutowait" = " no" then async="--asynchronous" p=" (asynchronously)" fi for tu in $IPSECplutostart do #echo "Initiating Pluto tunnel \`$tu'$p:" ipsec auto --up $async $tu done fi } # logging control logit() { IPSECsyslog=${IPSECsyslog-daemon.error} logger -s -p $IPSECsyslog -t ipsec_setup 2>&1 } logonly() { IPSECsyslog=${IPSECsyslog-daemon.error} logger -p $IPSECsyslog -t ipsec_setup } # the mainline code # backward compatibility, defaults. if test " $IPSECdump" = " yes" -a " $IPSECdumpdir" = " " then IPSECdumpdir=/var/tmp fi # do it case "$1" in start|--start) # Start things rolling. # (Warning, changes to this log message may affect barf.) version="`ipsec --version | awk 'NR == 1 { print $3 }'`" echo "Starting FreeS/WAN IPSEC $version..." | logit rm -f $info if test ! -r /dev/random then echo "...unable to start FreeS/WAN IPSEC, no /dev/random!" | logit exit 1 fi startklips 2>&1 | logit if test -d `dirname $subsyslock` then touch $subsyslock fi manualconns 2>&1 | logit if test " $IPSECpluto" = " no" then pluto=no elif test " $IPSECplutobackgroundload" = " yes" then pluto=back else pluto=fore fi case $pluto in fore|back) plutopre plutodaemon 2>&1 | logit sleep 1 # give it a moment to get going ;; esac case $pluto in fore) plutopost 2>&1 | logit ;; back) ( plutopost ; plutogo ) 2>&1 | logonly & ;; esac if test " $IPSECforwardcontrol" = " yes" then echo "Enabling IP forwarding:" | logonly echo 1 >/proc/sys/net/ipv4/ip_forward fi case $pluto in fore) plutogo 2>&1 | logit ;; esac echo "...FreeS/WAN IPSEC started" | logonly ;; stop|--stop) # Shut things down. echo "Stopping FreeS/WAN IPSEC..." | logit if test " $IPSECforwardcontrol" = " yes" then echo "Disabling IP forwarding:" | logonly echo 0 >/proc/sys/net/ipv4/ip_forward fi if test ! -f $plutopid then : nothing elif test ! -s $plutopid then echo "Removing empty $plutopid -- pluto still running?" | logit rm -f $plutopid elif kill -0 `cat $plutopid` 2>/dev/null then ipsec whack --shutdown | awk '$1 != "002"' | logit sleep 1 # general paranoia if test -s $plutopid then echo "Pluto did not go away! Killing it:" | logit kill `cat $plutopid` 2>&1 | logit sleep 5 fi rm -f $plutopid # harmless if already gone else echo "Removing orphaned $plutopid:" | logit rm -f $plutopid fi for i in `ifconfig | awk '/^ipsec/ { print $1 }'` do ifconfig $i down 2>&1 | logit ipsec tncfg --detach --virtual $i 2>&1 | logit done ipsec klipsdebug --none 2>&1 | logit ipsec eroute --clear 2>&1 | logit ipsec spi --clear 2>&1 | logit i=`lsmod 2>&1 | awk '$1 == "ipsec" { print $1 }'` if test " $i" = " ipsec" then rmmod ipsec 2>&1 | logit fi if test -d `dirname $subsyslock` then rm -f $subsyslock fi rm -f $info echo "...FreeS/WAN IPSEC stopped" | logonly ;; restart|--restart) $0 stop $0 start ;; --version) echo "1" exit 0 ;; --help) echo "Usage: $me {--start|--stop|--restart}" exit 0 ;; *) echo "Usage: $me {--start|--stop|--restart}" >&2 exit 2 esac exit 0