+#!/bin/sh
+#
+# default updown script for use with NETKEY(XFRM)
+#
+# Copyright (C) 2003-2004 Nigel Metheringham
+# Copyright (C) 2002-2007 Michael Richardson <mcr@xelerance.com>
+# Copyright (C) 2007-2008 Paul Wouters <paul@xelerance.com>
+# Copyright (C) 2003-2020 Tuomo Soini <tis@foobar.fi>
+# Copyright (C) 2011-2016 Paul Wouters <pwouters@redhat.com>
+# Copyright (C) 2016 Antony Antony <antony@phenome.org>
+#
+# 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 <https://www.gnu.org/licenses/gpl2.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 your modified updown script 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 real interface used by encrypted traffic and IKE traffic
+#
+# 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_CFG_CLIENT=0|1
+# is MODECFG or IKEv2 Config client.
+#
+# PLUTO_CFG_SERVER=0|1
+# is MODECFG or IKEv2 Config server.
+#
+# PLUTO_CONNECTION_TYPE
+#
+# PLUTO_CONN_ADDRFAMILY
+# is the family type, "ipv4" or "ipv6"
+#
+# PLUTO_PROTO_STACK
+# is the local IPsec kernel stack used, eg NETKEY, NOSTACK
+#
+# PLUTO_IS_PEER_CISCO=0|1
+# remote server type is cisco. Add support for cisco extensions
+# when used with xauth.
+#
+# 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 base value.
+# ESP/AH out is base, ESP/AH in = base + 1
+# IPCOMP is base + 2 plus for inbound + 1
+#
+# PLUTO_SA_TYPE
+# The type of IPsec SA (ESP or AH)
+#
+# PLUTO_USERNAME
+# The username (XAUTH or GSSAPI) that was authenticated (if any)
+# for this SA
+#
+# PLUTO_VIRT_INTERFACE
+# is the name of ipsec interface used by clear traffic in/out
+#
+#
+# XAUTH_FAILED
+# If xauthfail=soft this will be set to 1 if XAUTH authentication
+# failed. If xauthfail=hard, the updown scripts never run.
+#
+# CONNMARK
+# If mark= is set on the connection, this variable will be
+# set with the value. It can be used for iptables or VTI.
+#
+# VTI_IFAC=iface
+# Name of VTI interface to create
+#
+# VTI_ROUTING=yes|no
+# Whether or not to perform ip rule and ip route commands
+# covering the IPsec SA address ranges to route those packets
+# into the VTI_IFACE interface. This should be enabled unless
+# the IPsec SA covers 0.0.0.0/0 <-> 0.0.0.0/0
+#
+# VTI_SHARED=yes|no
+# Whether or not more conns (or instances) share a VTI device.
+# If not shared, the VTI device is deleted when tunnel goes down.
+#
+# SPI_IN / SPI_OUT
+# The inbound and outbound SPI's of the connection.
+
+# 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
+
+BACKUP_RESOLV_CONF=/run/pluto/libreswan-resolv-conf-backup
+ETC_RESOLV_CONF=/etc/resolv.conf
+
+case "${PLUTO_CONN_ADDRFAMILY}" in
+ ipv4)
+ FAMILY=4
+ MAX_CIDR=32
+ SCOPE=50 # Use scope 50 to verify ip was added by addsource()
+ ;;
+ ipv6)
+ FAMILY=6
+ MAX_CIDR=128
+ SCOPE=global
+ ;;
+ *)
+ echo "unknown address family \"${PLUTO_CONN_ADDRFAMILY}\"" >&2
+ exit 1
+ ;;
+esac
+export FAMILY MAX_CIDR SCOPE
+
+# 2022-09-03 - mbaudier : Hack when having an IPv6 subnet
+export CLIENT_FAMILY=6
+export CLIENT_MAX_CIDR=128
+
+# Ignore parameter custom
+if [ "${1}" = "custom" ]; then
+ shift
+fi
+
+while [ $# -gt 0 ]; do
+ case ${1} in
+ --route)
+ case ${2} in
+ [Yy]*)
+ ROUTE=yes
+ PROXY_ARP_ROUTE=no
+ ;;
+ *)
+ ROUTE=
+ PROXY_ARP_ROUTE=
+ ;;
+ esac
+ shift; shift
+ ;;
+ --iproute)
+ IPRARGS="${2}"
+ shift; shift
+ ;;
+ *)
+ echo "$0: Unknown argument \"${1}\"" >&2
+ exit 1
+ ;;
+ esac
+done
+
+# utility functions for route manipulation
+# Meddling with this stuff should not be necessary and requires great care.
+uproute() {
+ doproxyarp add
+ doroute replace
+}
+
+downroute() {
+ doroute del
+ doproxyarp delete
+}
+
+downrule() {
+ if [ -n "${PLUTO_MY_SOURCEIP}" -a 0${PLUTO_IS_PEER_CISCO} -eq 1 ]; then
+ doroute del
+ fi
+}
+
+updateresolvconf() {
+ local domain
+ local nameserver
+ local new_nameserver
+ local new_resolv_conf
+ local new_search
+ local orig_domain
+ local orig_nameserver
+ local rc
+ rc=0
+ if [ 0${PLUTO_CFG_CLIENT} -eq 0 ]; then
+ return ${rc}
+ fi
+ if [ -n "$(pidof unbound)" -a \
+ -n "${PLUTO_PEER_DNS_INFO}" -a \
+ -n "${PLUTO_PEER_DOMAIN_INFO}" ]
+ then
+ for domain in ${PLUTO_PEER_DOMAIN_INFO}; do
+ echo "updating local nameserver for ${domain} with ${PLUTO_PEER_DNS_INFO}"
+ unbound-control forward_add ${domain} \
+ ${PLUTO_PEER_DNS_INFO}
+ unbound-control flush_zone ${domain}
+ unbound-control flush_requestlist
+ done
+ rc=$?
+ elif [ 0${PLUTO_NM_CONFIGURED} -eq 0 -a \
+ -n "${PLUTO_PEER_DNS_INFO}" ]
+ then
+ echo "updating resolvconf"
+
+ if [ ! -e "${ETC_RESOLV_CONF}" ]; then
+ echo "resolv.conf does not exist, so doing nothing"
+ return 0
+ fi
+
+ if [ -e "${BACKUP_RESOLV_CONF}" ]; then
+ if grep -q Libreswan "${ETC_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 -- "${BACKUP_RESOLV_CONF}"
+ cp -- "${ETC_RESOLV_CONF}" "${BACKUP_RESOLV_CONF}"
+
+ new_resolv_conf="# Generated by Libreswan (IPsec)"
+
+ orig_domain="$(grep ^domain "${ETC_RESOLV_CONF}" 2>/dev/null | \
+ awk '{ print $2 }')"
+
+ orig_search=$(grep ^search "${ETC_RESOLV_CONF}" 2>/dev/null | \
+ sed 's/^search[[:space:]]\+//;s/[[:space:]]*\#.*//')
+
+ if [ -n "${orig_domain}" ]; then
+ new_resolv_conf="${new_resolv_conf}
+domain ${orig_domain}"
+ fi
+
+ if [ -n "${orig_search}" ]; then
+ new_search="${orig_search}"
+ elif [ -n "${orig_domain}" ]; then
+ new_search="${orig_domain}"
+ fi
+
+ if [ -n "${PLUTO_PEER_DOMAIN_INFO}" ]; then
+ if [ -n "${new_search}" ]; then
+ new_search=$(echo $(echo "${new_search} ${PLUTO_PEER_DOMAIN_INFO}" | tr [:space:] '\n' | awk '!a[$0]++'))
+ else
+ new_search="${PLUTO_PEER_DOMAIN_INFO}"
+ fi
+ fi
+
+ if [ -n "${new_search}" ]; then
+ new_resolv_conf="${new_resolv_conf}
+search ${new_search}"
+ fi
+
+ orig_nameserver=$(grep -m 1 ^nameserver "${ETC_RESOLV_CONF}" | \
+ sed 's/^nameserver[[:space:]]\+//;s/[[:space:]]*\#.*//')
+ if [ -n "${orig_nameserver}" ]; then
+ new_nameserver=$(echo $(echo "${PLUTO_PEER_DNS_INFO} ${orig_nameserver}" | tr [:space:] '\n' | awk '!a[$0]++'))
+ else
+ new_nameserver="${PLUTO_PEER_DNS_INFO}"
+ fi
+
+ for nameserver in ${new_nameserver}; do
+ new_resolv_conf="${new_resolv_conf}
+nameserver ${nameserver}"
+ done
+
+ echo "${new_resolv_conf}" > "${ETC_RESOLV_CONF}"
+ rc=$?
+ fi
+ return ${rc}
+}
+
+restoreresolvconf() {
+ local domain
+ local rc
+ rc=0
+ if [ 0${PLUTO_CFG_CLIENT} -eq 0 ]; then
+ return ${rc}
+ fi
+ if [ -n "$(pidof unbound)" -a \
+ -n "${PLUTO_PEER_DNS_INFO}" -a \
+ -n "${PLUTO_PEER_DOMAIN_INFO}" ]
+ then
+ for domain in ${PLUTO_PEER_DOMAIN_INFO}; do
+ echo "flushing local nameserver of ${domain}"
+ unbound-control forward_remove ${domain}
+ unbound-control flush_zone ${domain}
+ unbound-control flush_requestlist
+ done
+ rc=$?
+ elif [ 0${PLUTO_NM_CONFIGURED} -eq 0 ]; then
+ # We only restore if current resolv.conf is made by us.
+ if grep -q Libreswan "${ETC_RESOLV_CONF}" 2>/dev/null; then
+ # And if there is a backup...
+ if [ -e "${BACKUP_RESOLV_CONF}" ]; then
+ echo "restoring resolvconf"
+ else
+ return 0
+ fi
+ cp -- "${BACKUP_RESOLV_CONF}" "${ETC_RESOLV_CONF}"
+ fi
+ rm -f -- "${BACKUP_RESOLV_CONF}"
+ rc=0
+ fi
+ return ${rc}
+}
+
+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 signal 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() {
+ local interface
+ local st
+ interface=lo
+ st=0
+
+ if [ -z "${PLUTO_MY_SOURCEIP}" ]; then
+ return ${st}
+ fi
+ # check if given sourceip is local and add as alias if not
+ if ! ip -${CLIENT_FAMILY} -o route get ${PLUTO_MY_SOURCEIP} | grep -q ^local; then
+ if [ -n "${VTI_IFACE}" -a "${VTI_ROUTING}" = yes ]; then
+ interface="${VTI_IFACE}"
+ elif [ -n "${PLUTO_XFRMI_ROUTE}" ]; then
+ interface=${PLUTO_VIRT_INTERFACE}
+ fi
+ it="ip addr add ${PLUTO_MY_SOURCEIP}/${CLIENT_MAX_CIDR} dev ${interface} scope ${SCOPE}"
+ 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}
+}
+
+delsource() {
+ local interface
+ local oops
+ local st
+ interface=lo
+ st=0
+ if [ -z "${PLUTO_MY_SOURCEIP}" ]; then
+ return ${st}
+ fi
+ # Remove source ip if it's not used any more.
+ if [ -z "$(ip -${CLIENT_FAMILY} -o route list src ${PLUTO_MY_SOURCEIP})" ]; then
+ if [ -n "${VTI_IFACE}" -a "${VTI_ROUTING}" = yes ]; then
+ interface="${VTI_IFACE}"
+ elif [ -n "${PLUTO_XFRMI_ROUTE}" ]; then
+ interface=${PLUTO_VIRT_INTERFACE}
+ fi
+ # If there is no ip we just return
+ if ! ip -${FAMILY} -o addr list dev ${interface} scope ${SCOPE} | \
+ grep -q ${PLUTO_MY_SOURCEIP}/${CLIENT_MAX_CIDR}
+ then
+ return ${st}
+ fi
+
+ if [ -n "${PLUTO_MOBIKE_EVENT}" ] ; then
+ return ${st}
+ fi
+
+ it="ip -${CLIENT_FAMILY} addr del ${PLUTO_MY_SOURCEIP}/${CLIENT_MAX_CIDR} dev ${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
+ ;;
+ 'RTNETLINK answers: Cannot assign'*)
+ # Address is not there to remove or is there with different
+ # netmask and in that case we must not remove it so we ignore
+ # the error.
+ oops=""
+ st=0
+ ;;
+ esac
+ if [ -n "${oops}" -o ${st} -ne 0 ]; then
+ echo "$0: delsource \"${it}\" failed (${oops})" >&2
+ fi
+ fi
+ return ${st}
+}
+
+doproxyarp() {
+ local cmd
+ local iface
+ cmd=${1}
+ # Check if client has a single ip only client net
+ if [ ${PLUTO_PEER_CLIENT#*/} = ${MAX_CIDR} ]; then
+ # Skip OE special connections and direct host-host connections
+ if [ "${PLUTO_PEER_CLIENT_NET}" = "0.0.0.0" -o \
+ "${PLUTO_PEER_CLIENT_NET}" = "::" -o \
+ "${PLUTO_PEER_CLIENT_NET}" = "${PLUTO_PEER}" -o \
+ "${PLUTO_MY_CLIENT_NET}" = "${PLUTO_ME}" ]
+ then
+ return 0
+ fi
+ # check if client is routeable
+ if ip -${FAMILY} -o route get ${PLUTO_PEER_CLIENT_NET} 2>/dev/null | \
+ grep -E -q -s -v " via |^local"
+ then
+ iface=$(ip -${FAMILY} -o route get ${PLUTO_PEER_CLIENT_NET} 2>/dev/null | \
+ 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 [ "${cmd}" = "add" ]; then
+ ip -${FAMILY} neigh add proxy ${PLUTO_PEER_CLIENT_NET} dev ${iface} \
+ lladdr ${macaddr} nud permanent
+ # Force routing, required for proxyarp to work
+ PROXY_ARP_ROUTE=yes
+ export PROXY_ARP_ROUTE
+ else
+ ip -${FAMILY} neigh del proxy ${PLUTO_PEER_CLIENT_NET} dev ${iface}
+ fi
+ fi
+ fi
+ fi
+}
+
+do_ip()
+{
+ local cmd="$1"
+ oops="$(eval ${cmd} 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}" -a ${st} -ne 0 ]; then
+ echo "$0: doroute \"${cmd}\" failed (${oops})" >&2
+ fi
+
+ return ${st}
+}
+
+doroute() {
+ local cmd
+ local esp_nexthop
+ local esp_peer_interface
+ local espipro
+ local ipru
+ local route_table
+ local oops
+ local parms
+ local parms2
+ local st
+ local xfrmi_route
+ local xfrmi_rule
+ cmd=${1}
+ route_table=50
+ st=0
+ xfrmi_route="${PLUTO_XFRMI_ROUTE}"
+
+ if [ ${cmd} != del ]; then
+ oops="$(ip -${FAMILY} route get ${PLUTO_PEER_CLIENT_NET} 2>&1)"
+ case "${oops}" in
+ 'RTNETLINK answers: No route to host'*)
+ if [ -z "${PLUTO_XFRMI_ROUTE}" ]; then
+ ROUTE=yes # Routing is mandatory for IPsec
+ fi
+ ;;
+ esac
+ fi
+
+ if [ -n "${PLUTO_XFRMI_FWMARK}" ]; then
+ xfrmi_rule=yes # we have to add "ip rules" and "ip route table"
+ ROUTE=no # xfrmi_route will add the route
+ fi
+
+ # skip routing if it's not enabled or necessary
+ if [ -z "${PLUTO_MY_SOURCEIP}" -a \
+ -z "${PLUTO_MTU}" -a \
+ "${PROXY_ARP_ROUTE}" != yes -a \
+ "${cmd}" != "del" ]
+ then
+ PROXY_ARP_ROUTE=no
+ fi
+
+ if [ -n "${PLUTO_MY_SOURCEIP}" -o -n "${PLUTO_MTU}" ]; then
+ ROUTE=yes
+ fi
+
+ if [ "${PLUTO_PEER_CLIENT}" = "${PLUTO_MY_CLIENT}" -a \
+ "${PLUTO_XFRMI_ROUTE}" = yes ]
+ then
+ xfrmi_route="samesubnets";
+ echo "leftsubet == rightsubnet = ${PLUTO_PEER_CLIENT} cannot add route"
+ fi
+
+ parms="${PLUTO_PEER_CLIENT}"
+ parms2=${IPRARGS}
+ # nexthop is not needed on ppp interfaces. unset it to make cases
+ # work, where left is set but no leftnexthop (e.g. left=%defaultroute)
+ if ip link show "${PLUTO_INTERFACE%:*}" | grep -q POINTOPOINT; then
+ POINTPOINT=yes
+ fi
+ # use nexthop if nexthop is not %direct and POINTPOINT is not set
+ if [ "${PLUTO_NEXT_HOP}" != "${PLUTO_PEER}" -a -z "${POINTPOINT}" ]; then
+ # XFRM interface needs no nexthop
+ if [ -z "${PLUTO_XFRMI_ROUTE}" ]; then
+ parms2="via ${PLUTO_NEXT_HOP}"
+ fi
+ esp_nexthop="via ${PLUTO_NEXT_HOP} "
+ fi
+ # route via proper interface according to routing table
+ if [ "${cmd}" = "del" ]; then
+ case "${PLUTO_PEER_CLIENT}" in
+ "0.0.0.0/0")
+ # in case of default route we use half routes
+ peer_interface=$(ip -${FAMILY} -o route list exact 0.0.0.0/1 | \
+ sed "s/^.*dev \([^ ]*\) .*/\1/")
+ ;;
+ "::/0")
+ # in case of default route we use half routes
+ peer_interface=$(ip -${FAMILY} -o route list exact 2000::/3 | \
+ sed "s/^.*dev \([^ ]*\) .*/\1/")
+ ;;
+ *)
+ peer_interface=$(ip -${CLIENT_FAMILY} -o route get ${PLUTO_PEER_CLIENT_NET} | \
+ sed "s/^.*dev \([^ ]*\) .*/\1/")
+ ;;
+ esac
+ else
+ peer_interface=$(ip -o route get ${PLUTO_NEXT_HOP} | \
+ sed "s/^.*dev \([^ ]*\) .*/\1/")
+ fi
+
+ esp_peer_interface=$(ip -${FAMILY} -o route get ${PLUTO_NEXT_HOP} \
+ from ${PLUTO_ME} | sed "s/^.*\(dev [^ ]*\) .*/\1/")
+ if [ -z "${esp_peer_interface}" ]; then
+ esp_peer_interface="dev ${PLUTO_INTERFACE}"
+ fi
+
+ if [ -z "${peer_interface}" ]; then
+ peer_interface=${PLUTO_INTERFACE}
+ fi
+
+ if [ "${PLUTO_XFRMI_ROUTE}" = "yes" ]; then
+ peer_interface=${PLUTO_VIRT_INTERFACE}
+ fi
+
+ if [ -n "${VTI_IFACE}" ]; then
+ addsource
+ peer_interface="${VTI_IFACE}"
+ fi
+
+ parms2="${parms2}${PLUTO_MTU:+ mtu ${PLUTO_MTU}}"
+ parms2="${parms2}${PLUTO_METRIC:+ metric ${PLUTO_METRIC}} ${IPROUTEARGS}"
+
+ parms2="${parms2} dev ${peer_interface%:*}"
+
+ # make sure we have sourceip locally in this machine
+ if [ "${cmd}" = "replace" -a -n "${PLUTO_MY_SOURCEIP}" ]; then
+ addsource
+ # use sourceip as route default source
+ parms2="${parms2} src ${PLUTO_MY_SOURCEIP}"
+ fi
+
+ case "${PLUTO_PEER_CLIENT}" in
+ "0.0.0.0/0")
+ # need to provide route that eclipses default, without
+ # replacing it.
+ it="ip -${FAMILY} route ${cmd} 0.0.0.0/1 ${parms2} && \
+ ip -${FAMILY} route ${cmd} 128.0.0.0/1 ${parms2}"
+ ;;
+ "::/0")
+ # need to provide route that eclipses default, without
+ # replacing it.
+ it="ip -${FAMILY} route ${cmd} 2000::/3 ${parms2}"
+ ;;
+ *)
+ it="ip -${CLIENT_FAMILY} route ${cmd} ${parms} ${parms2}"
+ ;;
+ esac
+
+ if [ "${ROUTE}" = yes -o \
+ "${xfrmi_route}" = yes -o \
+ "${PROXY_ARP_ROUTE}" = yes ]
+ then
+ do_ip "${it}"
+ st=$?
+ if [ ${st} -ne 0 ]; then
+ return ${st}
+ fi
+ fi
+
+ if [ "${xfrmi_rule}" = "yes" ]; then
+ espipro="ip -${FAMILY} route ${cmd} ${PLUTO_PEER}/${MAX_CIDR} ${esp_nexthop} ${esp_peer_interface%:*} table ${route_table}"
+ do_ip "${espipro}"
+
+ st=$?
+ if [ ${st} -ne 0 ]; then
+ return ${st}
+ fi
+
+ iprulecmd="${cmd}"
+ if [ "${cmd}" = "replace" ]; then
+ iprulecmd="add"
+ fi
+
+ ipru="ip -${FAMILY} rule ${iprulecmd} prio 100 to ${parms}"
+ ipru="${ipru} fwmark ${PLUTO_XFRMI_FWMARK} lookup ${route_table}"
+
+ do_ip "${ipru}"
+ st=$?
+ if [ ${st} -ne 0 ]; then
+ return ${st}
+ fi
+
+ fi
+ return 0
+}
+
+# TODO: We need to specify CIDR mask but our _MASK variables are in old school format
+# TODO: Exclude udp 4500 traffic
+addnflog() {
+ if [ -n "${NFLOG}" ]; then
+ iptables -I OUTPUT -m policy --dir out --pol ipsec \
+ -s ${PLUTO_MY_CLIENT} -d ${PLUTO_PEER_CLIENT} \
+ -j NFLOG --nflog-group ${NFLOG} --nflog-prefix ${PLUTO_CONNECTION}
+ iptables -I INPUT -m policy --dir in --pol ipsec \
+ -s ${PLUTO_PEER_CLIENT} -d ${PLUTO_MY_CLIENT} \
+ -j NFLOG --nflog-group ${NFLOG} --nflog-prefix ${PLUTO_CONNECTION}
+ fi
+}
+
+delnflog() {
+ if [ -n "${NFLOG}" ]; then
+ iptables -D OUTPUT -m policy --dir out --pol ipsec \
+ -s ${PLUTO_MY_CLIENT} -d ${PLUTO_PEER_CLIENT} \
+ -j NFLOG --nflog-group ${NFLOG} --nflog-prefix ${PLUTO_CONNECTION}
+ iptables -D INPUT -m policy --dir in --pol ipsec \
+ -s ${PLUTO_PEER_CLIENT} -d ${PLUTO_MY_CLIENT} \
+ -j NFLOG --nflog-group ${NFLOG} --nflog-prefix ${PLUTO_CONNECTION}
+ fi
+}
+
+addvtiiface() {
+ if [ -n "${VTI_IFACE}" ]; then
+ if [ -z "${CONNMARK_IN}" -o -z "${CONNMARK_OUT}" ]; then
+ echo "vti-interface option ignored because no mark was configured"
+ else
+ if [ ! -d "/proc/sys/net/ipv4/conf/${VTI_IFACE}" ]; then
+ # echo "creating vti interface"
+ vtipeer="${PLUTO_PEER}"
+ if [ "${PLUTO_CONN_KIND}" = CK_INSTANCE -o "${VTI_SHARED}" = "yes" ]; then
+ vtipeer="0.0.0.0"
+ fi
+ ip tunnel add ${VTI_IFACE} mode vti local ${PLUTO_ME} \
+ remote ${vtipeer} okey ${CONNMARK_OUT%/*} \
+ ikey ${CONNMARK_IN%/*}
+ sysctl -w net.ipv4.conf.${VTI_IFACE}.disable_policy=1
+ sysctl -w net.ipv4.conf.${VTI_IFACE}.rp_filter=0
+ sysctl -w net.ipv4.conf.${VTI_IFACE}.forwarding=1
+ if [ -n "${VTI_IP}" ]; then
+ ip addr add ${VTI_IP} dev ${VTI_IFACE}
+ fi
+ ip link set ${VTI_IFACE} up
+ else
+ # check there was no conflict if we are sharing - might be sensitive to /sbin/ip differences
+ if [ "${VTI_SHARED}" = yes ]; then
+ #test: ip/ip remote 3.4.5.6 local 1.2.3.4 ttl inherit key 5
+ cur="$(ip tun show ${VTI_IFACE})"
+ new="${VTI_IFACE}: ip/ip remote any local ${PLUTO_ME} ttl inherit key ${CONNMARK_OUT%/*}"
+ if [ "${cur}" != "${new}" ]; then
+ echo "vti interface \"${VTI_IFACE}\" already exists with conflicting setting"
+ echo "existing: ${cur}"
+ echo "wanted : ${new}"
+ else
+ # temp debug
+ echo "vti interface already exists with identical parameters, OK"
+ fi
+ else
+ echo "vti interface \"${VTI_IFACE}\" already exists with conflicting setting (perhaps need vti-sharing=yes ?"
+ fi
+ fi
+ fi
+ fi
+}
+
+addvti() {
+ if [ -n "${VTI_IFACE}" ]; then
+ if [ -z "${CONNMARK_IN}" -o -z "${CONNMARK_OUT}" ]; then
+ echo "vti-interface option ignored because no mark was configured"
+ else
+ if [ "${VTI_ROUTING}" = yes ]; then
+ # Tuomo should improve this with using ${PLUTO_MY_CLIENT_NET}
+ # echo "setting up vti routing"
+ r=add
+ ip route list | grep -q "${PLUTO_PEER_CLIENT%/*}" && r=change
+ if [ "${r}" = change ]; then
+ # resolve LAN conflict by forcing host route for default gw
+ gw="$(ip ro li | grep ^default | awk '{ print $3;}')"
+ gwdev="$(ip ro li | grep ^default | awk '{ print $5;}')"
+ # echo "ip route add ${gw} dev ${gwdev}"
+ ip route add ${gw} dev ${gwdev} >/dev/null ||:
+ fi
+ srcip=""
+ if [ -n "${PLUTO_MY_SOURCEIP}" ]; then
+ srcip=" src ${PLUTO_MY_SOURCEIP}"
+ fi
+ # echo "ip route ${r} ${PLUTO_PEER_CLIENT} dev ${VTI_IFACE} ${srcip}"
+ ip route ${r} ${PLUTO_PEER_CLIENT} dev ${VTI_IFACE} ${srcip}
+ echo "done ip route"
+ fi
+ fi
+ fi
+}
+
+delvti() {
+ if [ -n "${VTI_IFACE}" -a -d /proc/sys/net/ipv4/conf/${VTI_IFACE} ]; then
+ if [ "${VTI_ROUTING}" = yes ]; then
+ ip route del ${PLUTO_PEER_CLIENT} dev ${VTI_IFACE} \
+ src ${PLUTO_MY_SOURCEIP} ||:
+ fi
+ # TODO: we can't delete vti interface because we don't have proper reference
+ # counting.
+ #if [ "${VTI_SHARED}" = no -a "${PLUTO_CONN_KIND}" != CK_INSTANCE ]; then
+ # ip tun del ${VTI_IFACE} ||:
+ #fi
+ fi
+}
+
+# Client Address Translation CAT
+addcat() {
+ if [ -n "${CAT}" ] && [ "${PLUTO_MY_CLIENT_NET}" != "0.0.0.0" ] ; then
+ iptables -t nat -I POSTROUTING -m policy --dir out --pol ipsec \
+ -d ${PLUTO_PEER_CLIENT} -j SNAT --to-source ${PLUTO_MY_CLIENT_NET}
+ iptables -t nat -I PREROUTING -m policy --dir in --pol ipsec \
+ -d ${PLUTO_MY_CLIENT_NET} -s ${PLUTO_PEER_CLIENT} \
+ -j DNAT --to-destination ${PLUTO_ME}
+ fi
+}
+
+delcat() {
+ if [ -n "${CAT}" ]; then
+ iptables -t nat -D PREROUTING -m policy --dir in --pol ipsec \
+ -d ${PLUTO_MY_CLIENT_NET} -s ${PLUTO_PEER_CLIENT} \
+ -j DNAT --to-destination ${PLUTO_ME}
+ iptables -t nat -D POSTROUTING -m policy --dir out --pol ipsec \
+ -d ${PLUTO_PEER_CLIENT} -j SNAT --to-source ${PLUTO_MY_CLIENT_NET}
+ fi
+}
+
+# the big choice
+case "${PLUTO_VERB}" in
+ prepare-host|prepare-client)
+ addvtiiface
+ ;;
+ route-host|route-client)
+ # connection to me or my client subnet being routed
+ addvti
+ uproute
+ addnflog
+ ;;
+ unroute-host|unroute-client)
+ # connection to me or my client subnet being unrouted
+ downroute
+ delsource
+ ;;
+ up-host)
+ # connection to me coming up
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+ down-host)
+ # connection to me going down
+ downrule
+ delnflog
+ delcat
+ delvti
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+ up-client)
+ # connection to my client subnet coming up
+ addvtiiface
+ updateresolvconf
+ addcat
+ addsource
+ notifyNM connect
+ addvti
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+ down-client)
+ # connection to my client subnet going down
+ downrule
+ delnflog
+ delcat
+ delvti
+ restoreresolvconf
+ notifyNM disconnect
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+ #
+ # IPv6
+ #
+ prepare-host-v6|prepare-client-v6)
+ # prepare client for connection
+ ;;
+ route-host-v6|route-client-v6)
+ # connection to me or my client subnet being routed
+ uproute
+ ;;
+ unroute-host-v6|unroute-client-v6)
+ # connection to me or my client subnet being unrouted
+ downroute
+ delsource
+ ;;
+ up-host-v6)
+ # connection to me coming up
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+ down-host-v6)
+ # connection to me going down
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+ up-client-v6)
+ # connection to my client subnet coming up
+ addsource
+ updateresolvconf
+ notifyNM connect
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+ down-client-v6)
+ # connection to my client subnet going down
+ restoreresolvconf
+ notifyNM disconnect
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+ *) echo "$0: unknown verb \"${PLUTO_VERB}\" or parameter \"${1}\"" >&2
+ exit 1
+ ;;
+esac