File: //usr/libexec/ipsec/_updown.klips
#! /bin/sh
# iproute2 version, default updown script
#
# Copyright (C) 2003-2004 Nigel Metheringham
# Copyright (C) 2002-2007 Michael Richardson <mcr@xelerance.com>
# Copyright (C) 2003-2013 Tuomo Soini <tis@foobar.fi>
# Copyright (C) 2003-2007 Paul Wouters <paul@xelerance.com>
#
# 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 <http://www.fsf.org/copyleft/gpl.txt>.
#
# 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.
# CAUTION: Installing a new version of Libreswan will install a new
# copy of this script, wiping out any custom changes you make. If
# you need changes, make a copy of this under another name, and customize
# that, and use the (left/right)updown= parameters in ipsec.conf to make
# Libreswan use yours instead of this default one.
test ${IPSEC_INIT_SCRIPT_DEBUG} && set -v -x
LC_ALL=C
export LC_ALL
# things that this script gets (from ipsec_pluto(8) man page)
#
#
# PLUTO_VERSION
# indicates what version of this interface is being
# used. This document describes version 1.1. This
# is upwardly compatible with version 1.0.
#
# PLUTO_VERB
# specifies the name of the operation to be performed
# (prepare-host, prepare-client, up-host, up-client,
# down-host, or down-client). If the address family
# for security gateway to security gateway communications
# is IPv6, then a suffix of -v6 is added to the
# verb.
#
# PLUTO_CONNECTION
# is the name of the connection for which we are
# routing.
#
# PLUTO_CONN_POLICY
# the policy of the connection, as in:
# RSASIG+ENCRYPT+TUNNEL+PFS+DONTREKEY+OPPORTUNISTIC
# +failureDROP+lKOD+rKOD
#
# PLUTO_NEXT_HOP
# is the next hop to which packets bound for the peer
# must be sent.
#
# PLUTO_INTERFACE
# is the name of the ipsec interface to be used.
#
# PLUTO_ME
# is the IP address of our host.
#
# PLUTO_METRIC
# is the metric to set for the route
#
# PLUTO_MTU
# is the mtu to set for the route
#
# PLUTO_MY_CLIENT
# is the IP address / count of our client subnet. If
# the client is just the host, this will be the
# host's own IP address / mask (where max is 32 for
# IPv4 and 128 for IPv6).
#
# PLUTO_MY_CLIENT_NET
# is the IP address of our client net. If the client
# is just the host, this will be the host's own IP
# address.
#
# PLUTO_MY_CLIENT_MASK
# is the mask for our client net. If the client is
# just the host, this will be 255.255.255.255.
#
# PLUTO_MY_SOURCEIP
# if non-empty, then the source address for the route will be
# set to this IP address.
#
# PLUTO_MY_PROTOCOL
# is the protocol for this connection. Useful for
# firewalling.
#
# PLUTO_MY_PORT
# is the port. Useful for firewalling.
#
# PLUTO_PEER
# is the IP address of our peer.
#
# PLUTO_PEER_CLIENT
# is the IP address / count of the peer's client subnet.
# If the client is just the peer, this will be
# the peer's own IP address / mask (where max is 32
# for IPv4 and 128 for IPv6).
#
# PLUTO_PEER_CLIENT_NET
# is the IP address of the peer's client net. If the
# client is just the peer, this will be the peer's
# own IP address.
#
# PLUTO_PEER_CLIENT_MASK
# is the mask for the peer's client net. If the
# client is just the peer, this will be
# 255.255.255.255.
#
# PLUTO_PEER_PROTOCOL
# is the protocol set for remote end with port
# selector.
#
# PLUTO_PEER_PORT
# is the peer's port. Useful for firewalling.
#
# PLUTO_CONNECTION_TYPE
#
# PLUTO_CONN_ADDRFAMILY
# is the family type, "ipv4" or "ipv6"
#
# PLUTO_STACK
# the kernel stack being used (eg protostack= value)
#
# PLUTO_NM_CONFIGURED=0|1
# is NetworkManager used for resolv.conf update
#
# PLUTO_SA_REQID
# When using KAME or XFRM/NETKEY, the IPsec SA reqid value
# Import default _updown configs from the
# /etc/[sysconfig|default]/pluto_updown file
#
# Two variables can be set in this file:
#
# IPROUTETABLE
# is the default value for IPROUTETABLE
#
# IPROUTEARGS
# is the extra argument list for ip route command
#
# IPRULEARGS
# is the extra argument list for ip rule command
# rpm based systems
if [ -f /etc/sysconfig/pluto_updown ]; then
. /etc/sysconfig/pluto_updown
# deb based systems
elif [ -f /etc/default/pluto_updown ]; then
. /etc/default/pluto_updown
fi
LIBRESWAN_RESOLV_CONF=/run/pluto/libreswan-resolv-conf-backup
ORIG_RESOLV_CONF=/etc/resolv.conf
MAX_CIDR=32 # for ipv4
[ "${PLUTO_CONN_ADDRFAMILY}" = ipv6 ] && MAX_CIDR=128
# check parameter(s)
case "${1}:$*" in
':')
# no parameters
;;
custom:*)
# custom parameters (see above CAUTION comment)
;;
*)
echo "${0}: unknown parameters \"$*\"" >&2
exit 2
;;
esac
# utility functions for route manipulation
# Meddling with this stuff should not be necessary and requires great care.
uproute() {
doproxyarp add
doroute add
ip route flush cache
}
downroute() {
doroute delete
ip route flush cache
doproxyarp delete
}
uprule() {
# policy based advanced routing
if [ -n "${IPROUTETABLE}" ]; then
dorule delete
dorule add
fi
# virtual sourceip support
if [ -n "${PLUTO_MY_SOURCEIP}" ]; then
addsource
changesource
fi
ip route flush cache
}
downrule() {
if [ -n "${PLUTO_MY_SOURCEIP}" -a ${PLUTO_IS_PEER_CISCO} -eq 1 ]; then
dorule delete
ip route flush cache
fi
}
updateresolvconf() {
if [ -z "${PLUTO_PEER_DNS_INFO}" -o -z "${PLUTO_PEER_DOMAIN_INFO}" ]; then
return 0
fi
if [ -n "$(pidof unbound)" ]; then
echo "updating local nameserver for ${PLUTO_PEER_DOMAIN_INFO} with ${PLUTO_PEER_DNS_INFO}"
/usr/sbin/unbound-control forward_add ${PLUTO_PEER_DOMAIN_INFO} \
${PLUTO_PEER_DNS_INFO}
/usr/sbin/unbound-control flush_zone ${PLUTO_PEER_DOMAIN_INFO}
/usr/sbin/unbound-control flush_requestlist
return 0
fi
if [ 0${PLUTO_NM_CONFIGURED} -eq 0 ]; then
echo "updating resolvconf"
if [ ! -e "${ORIG_RESOLV_CONF}" ]; then
echo "resolv.conf does not exist, so doing nothing"
return 0
fi
if [ -e "${LIBRESWAN_RESOLV_CONF}" ]; then
if grep -q Libreswan "${ORIG_RESOLV_CONF}"; then
echo "Current resolv.conf is generated by Libreswan, and backup resolv.conf already exists, so doing nothing"
return 0
else
echo "backup resolv.conf exists, but current resolv.conf is not generated by Libreswan"
fi
fi
rm -f -- "${LIBRESWAN_RESOLV_CONF}"
cp -- "${ORIG_RESOLV_CONF}" "${LIBRESWAN_RESOLV_CONF}"
RESOLVE_CONF="# Generated by Libreswan (IPsec)"
if [ -n "${PLUTO_PEER_DOMAIN_INFO}" ]; then
if grep -q ^domain "${ORIG_RESOLV_CONF}"; then
RESOLVE_CONF="${RESOLVE_CONF}
domain ${PLUTO_PEER_DOMAIN_INFO}
search ${PLUTO_PEER_DOMAIN_INFO}"
else
RESOLVE_CONF="${RESOLVE_CONF}
search ${PLUTO_PEER_DOMAIN_INFO}"
fi
fi
if [ -n "${PLUTO_PEER_DNS_INFO}" ]; then
for resolver in ${PLUTO_PEER_DNS_INFO}; do
RESOLVE_CONF="${RESOLVE_CONF}
nameserver ${resolver}"
done
fi
ORIG_NAMESERVER=$(grep --max-count 1 ^nameserver "${ORIG_RESOLV_CONF}")
RESOLVE_CONF="${RESOLVE_CONF}
${ORIG_NAMESERVER}"
rm -f -- "${ORIG_RESOLV_CONF}"
echo "${RESOLVE_CONF}" > "${ORIG_RESOLV_CONF}"
return $?
fi
}
restoreresolvconf() {
if [ -z "${PLUTO_PEER_DNS_INFO}" -o -z "${PLUTO_PEER_DOMAIN_INFO}" ]; then
return 0
fi
if [ -n "$(pidof unbound)" ]; then
echo "flushing local nameserver of ${PLUTO_PEER_DOMAIN_INFO}"
/usr/sbin/unbound-control forward_remove ${PLUTO_PEER_DOMAIN_INFO}
/usr/sbin/unbound-control flush_zone ${PLUTO_PEER_DOMAIN_INFO}
/usr/sbin/unbound-control flush_requestlist
return 0
fi
if [ 0${PLUTO_NM_CONFIGURED} -eq 0 ]; then
echo "restoring resolvconf"
if [ ! -e "${LIBRESWAN_RESOLV_CONF}" ]; then
echo "Problem in restoring the resolv.conf, as there is no backup file"
return 2
fi
if grep -q Libreswan "${ORIG_RESOLV_CONF}"; then
cp -- "${LIBRESWAN_RESOLV_CONF}" "${ORIG_RESOLV_CONF}"
else
echo "Current resolv.conf is not generated by Libreswan, so doing nothing"
fi
rm -f -- "${LIBRESWAN_RESOLV_CONF}"
return 0
fi
}
notifyNM() {
# This will be called whenever a connection is established or
# fails to establish (either phase 1, xauth phase, or phase 2)
# or whenever an already established connection is being terminated.
# This will send a singal to NetworkManager over dbus so that NM
# can keep track of the coonnections.
if [ 0${PLUTO_NM_CONFIGURED} -eq 1 ]; then
echo "sending $1 signal to NetworkManager"
libreswan_reason=$1
export libreswan_reason
export PLUTO_PEER_DOMAIN_INFO
export PLUTO_PEER_DNS_INFO
export PLUTO_PEER_BANNER
export PLUTO_MY_SOURCEIP
export PLUTO_PEER
[ -x /usr/libexec/nm-libreswan-service-helper ] && \
/usr/libexec/nm-libreswan-service-helper
fi
return 0
}
addsource() {
st=0
# check if given sourceip is local and add as alias if not
if ! ip -o route get ${PLUTO_MY_SOURCEIP} | grep -q ^local; then
it="ip addr add ${PLUTO_MY_SOURCEIP}/${MAX_CIDR} dev ${PLUTO_INTERFACE%:*}"
oops="$(eval ${it} 2>&1)"
st=$?
if [ -z "${oops}" -a ${st} -ne 0 ]; then
oops="silent error, exit status ${st}"
fi
case "${oops}" in
'RTNETLINK answers: File exists'*)
# should not happen, but ... ignore if the
# address was already assigned on interface
oops=""
st=0
;;
esac
if [ -n "${oops}" -o ${st} -ne 0 ]; then
echo "${0}: addsource \"${it}\" failed (${oops})" >&2
fi
fi
return ${st}
}
changesource() {
st=0
parms="${PLUTO_PEER_CLIENT}"
parms2="dev ${PLUTO_INTERFACE}"
parms3="src ${PLUTO_MY_SOURCEIP}"
if [ -n "${IPROUTETABLE}" ]; then
parms3="${parms3} table ${IPROUTETABLE}"
fi
it="ip route replace ${parms} ${parms2} ${parms3}${PLUTO_MTU:+ mtu ${PLUTO_MTU}} ${PLUTO_METRIC:+ metric ${PLUTO_METRIC}}"
case "${PLUTO_PEER_CLIENT}" in
"0.0.0.0/0"|"::/0")
# opportunistic encryption work around
it=
;;
esac
oops="$(eval ${it} 2>&1)"
st=$?
if [ -z "${oops}" -a ${st} -ne 0 ]; then
oops="silent error, exit status ${st}"
fi
if [ -n "${oops}" -o ${st} -ne 0 ]; then
echo "${0}: changesource \"${it}\" failed (${oops})" >&2
fi
return ${st}
}
dorule() {
st=0
it2=
iprule="from ${PLUTO_MY_CLIENT}"
iprule2="to ${PLUTO_PEER_CLIENT}"
if [ -n "${IPROUTETABLE}" ]; then
iprule2="${iprule2} table ${IPROUTETABLE}"
fi
iprule2="${iprule2} ${IPRULEARGS}"
case "${PLUTO_PEER_CLIENT}" in
"0.0.0.0/0"|"::/0")
# opportunistic encryption work around
st=0
;;
*)
if [ -z "${PLUTO_MY_SOURCEIP}" ]; then
if [ "${PLUTO_ME}" = "${PLUTO_MY_CLIENT%/*}" ]; then
it="ip rule ${1} iif lo ${iprule2}"
else
it="ip rule ${1} ${iprule} ${iprule2}"
fi
else
if [ "${PLUTO_MY_SOURCEIP}" = "${PLUTO_MY_CLIENT%/*}" ]; then
it="ip rule ${1} iif lo ${iprule2}"
else
it="ip rule ${1} ${iprule} ${iprule2}"
it2="ip rule ${1} iif lo ${iprule2}"
fi
fi
oops="$(eval ${it} 2>&1)"
st=$?
if [ -z "${oops}" -a ${st} -ne 0 ]; then
oops="silent error, exit status ${st}"
fi
case "${oops}" in
'RTNETLINK answers: No such process'*)
# This is what ip rule gives
# for "could not find such a rule"
oops=
st=0
;;
esac
if [ -n "${oops}" -o ${st} -ne 0 ]; then
echo "${0}: dorule \"${it}\" failed (${oops})" >&2
fi
if [ ${st} -eq 0 -a -n "${it2}" ]; then
oops="$(eval ${it2} 2>&1)"
st=$?
if [ -z "${oops}" -a ${st} -ne 0 ]; then
oops="silent error, exit status ${st}"
fi
case "${oops}" in
'RTNETLINK answers: No such process'*)
# This is what ip rule gives
# for "could not find such a rule"
oops=
st=0
;;
esac
if [ -n "${oops}" -o ${st} -ne 0 ]; then
echo "${0}: dorule \"${it2}\" failed (${oops})" >&2
fi
fi
;;
esac
return ${st}
}
doproxyarp() {
# Check if client has a single ip only client net
if [ ${PLUTO_PEER_CLIENT#*/} = ${MAX_CIDR} ]; then
# Skip OE special connections
if [ ${PLUTO_PEER_CLIENT_NET} = 0.0.0.0 -o \
${PLUTO_PEER_CLIENT_NET} = "::" ]; then
return 0
fi
# check if client is routeable
if ip -o route get ${PLUTO_PEER_CLIENT_NET} | \
egrep -q -s -v " via |^local"; then
iface=$(ip -o route get ${PLUTO_PEER_CLIENT_NET} | \
awk '{print $3}')
if [ -r /sys/class/net/${iface}/address ]; then
macaddr=$(cat /sys/class/net/${iface}/address)
fi
# add/remove arp entry for the client on ethernet devices only
if [ -n "${macaddr}" ]; then
if [ "$1" = add ]; then
ip neigh add proxy ${PLUTO_PEER_CLIENT_NET} dev ${iface} \
lladdr ${macaddr} nud permanent
else
ip neigh del proxy ${PLUTO_PEER_CLIENT_NET} dev ${iface}
fi
fi
fi
fi
}
doroute() {
st=0
parms="${PLUTO_PEER_CLIENT}"
parms2=
if [ -n "${PLUTO_NEXT_HOP}" -a "${PLUTO_NEXT_HOP}" != "${PLUTO_PEER}" ]; then
# nexthop is not needed on ppp interfaces. unset it to make cases
# work, where left is set but no leftnexthop (e.g. left=%defaultroute)
ip link show "${PLUTO_INTERFACE%:*}" | grep -qs POINTOPOINT && unset PLUTO_NEXT_HOP
# skip routing via nexthop if it is not reachable through any
# directly connected network (but via default route only):
ip route list match "${PLUTO_NEXT_HOP}" dev "${PLUTO_INTERFACE}" | \
grep -qs -v default || unset PLUTO_NEXT_HOP
if [ -n "${PLUTO_NEXT_HOP}" ]; then
parms2="via ${PLUTO_NEXT_HOP}"
fi
fi
parms2="${parms2} dev ${PLUTO_INTERFACE}${PLUTO_MTU:+ mtu ${PLUTO_MTU}}${PLUTO_METRIC:+ metric ${PLUTO_METRIC}}"
parms3="${IPROUTEARGS}"
if [ -n "${IPROUTETABLE}" ]; then
parms3="${parms3} table ${IPROUTETABLE}"
fi
if [ "${1}" = "add" -a -n "${PLUTO_MY_SOURCEIP}" ]; then
addsource
parms3="${parms3} src ${PLUTO_MY_SOURCEIP}"
fi
case "${PLUTO_PEER_CLIENT}" in
"0.0.0.0/0")
# opportunistic encryption work around
# need to provide route that eclipses default, without
# replacing it.
it="ip route ${1} 0.0.0.0/1 ${parms2} ${parms3} &&
ip route ${1} 128.0.0.0/1 ${parms2} ${parms3}"
;;
"::/0")
# opportunistic encryption work around
# need to provide route that eclipses default, without
# replacing it.
it="ip -6 route ${1} 0::/1 ${parms2} ${parms3} &&
ip -6 route ${1} 8000::/1 ${parms2} ${parms3}"
;;
*)
# Despite not having -6, the ip route commands works for ipv6
it="ip route ${1} ${parms} ${parms2} ${parms3}"
;;
esac
oops="$(eval ${it} 2>&1)"
st=$?
if [ -z "${oops}" -a ${st} -ne 0 ]; then
oops="silent error, exit status ${st}"
fi
case "${oops}" in
'RTNETLINK answers: No such process'*)
# should not happen, but ... ignore if the
# route was already removed
oops=""
st=0
;;
esac
if [ -n "${oops}" -o ${st} -ne 0 ]; then
echo "${0}: doroute \"${it}\" failed (${oops})" >&2
fi
return ${st}
}
# the big choice
case "${PLUTO_VERB}:${1}" in
prepare-host:*|prepare-client:*)
# delete possibly-existing route (preliminary to adding a route)
case "${PLUTO_PEER_CLIENT}" in
"0.0.0.0/0")
# need to provide route that eclipses default, without
# replacing it.
parms1="0.0.0.0/1"
parms2="128.0.0.0/1"
it="ip route delete ${parms1} ${IPROUTEARGS} 2>&1 ; ip route delete ${parms2} ${IPROUTEARGS} 2>&1"
oops="$(ip route delete ${parms1} ${IPROUTEARGS} 2>&1 ; ip route delete ${parms2} ${IPROUTEARGS} 2>&1)"
;;
"::/0")
# need to provide route that eclipses default, without
# replacing it.
parms1="0::/1"
parms2="8000::/1"
it="ip route delete ${parms1} ${IPROUTEARGS} 2>&1 ; ip route delete ${parms2} ${IPROUTEARGS} 2>&1"
oops="$(ip route delete ${parms1} ${IPROUTEARGS} 2>&1 ; ip route delete ${parms2} ${IPROUTEARGS} 2>&1)"
;;
*)
parms="${PLUTO_PEER_CLIENT} ${IPROUTEARGS}"
if [ -n "${IPROUTETABLE}" ]; then
parms="${parms} table ${IPROUTETABLE}"
fi
it="ip route delete ${parms} 2>&1"
oops="$(ip route delete ${parms} 2>&1)"
;;
esac
st="$?"
if [ -z "${oops}" -a ${st} -ne 0 ]; then
oops="silent error, exit status ${st}"
fi
case "${oops}" in
*'RTNETLINK answers: No such process'*)
# This is what route (currently -- not documented!) gives
# for "could not find such a route".
oops=
st=0
;;
esac
if [ -n "${oops}" -o ${st} -ne 0 ]; then
echo "${0}: \"${it}\" failed (${oops})" >&2
fi
exit ${st}
;;
route-host:*|route-client:*)
# connection to me or my client subnet being routed
uproute
;;
unroute-host:*|unroute-client:*)
# connection to me or my client subnet being unrouted
downroute
;;
up-host:*)
# connection to me coming up
uprule
# If you are doing a custom version, firewall commands go here.
;;
down-host:*)
# connection to me going down
downrule
# If you are doing a custom version, firewall commands go here.
;;
up-client:)
# connection to my client subnet coming up
uprule
# If you are doing a custom version, firewall commands go here.
updateresolvconf
notifyNM connect
;;
down-client:)
# connection to my client subnet going down
downrule
# If you are doing a custom version, firewall commands go here.
restoreresolvconf
notifyNM disconnect
;;
#
# IPv6
#
prepare-host-v6:*|prepare-client-v6:*)
case "${PLUTO_PEER_CLIENT_NET}" in
"0.0.0.0"|"::"|"%any")
;;
*)
ip -6 route del ${PLUTO_PEER_CLIENT} || echo
;;
esac
;;
route-host-v6:*|route-client-v6:*)
# connection to me or my client subnet being routed
uproute
#uproute_v6
;;
unroute-host-v6:*|unroute-client-v6:*)
# connection to me or my client subnet being unrouted
downroute
#downroute_v6
;;
up-host-v6:*)
# connection to me coming up
uprule
# If you are doing a custom version, firewall commands go here.
;;
down-host-v6:*)
# connection to me going down
downrule
# If you are doing a custom version, firewall commands go here.
;;
up-client-v6:)
# connection to my client subnet coming up
uprule
# If you are doing a custom version, firewall commands go here.
;;
down-client-v6:)
# connection to my client subnet going down
downrule
# If you are doing a custom version, firewall commands go here.
;;
*)
echo "${0}: unknown verb \"${PLUTO_VERB}\" or parameter \"${1}\"" >&2
exit 1
;;
esac