#! /bin/sh
###
### TRIPE_SLIPIF dynamic allocation script for use with `userv-ipif'
###
### (c) 2012 Mark Wooding
###
###----- Licensing notice ---------------------------------------------------
###
### This file is part of Trivial IP Encryption (TrIPE).
###
### TrIPE 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 3 of the License, or (at your
### option) any later version.
###
### TrIPE 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.
###
### You should have received a copy of the GNU General Public License
### along with TrIPE. If not, see .
###--------------------------------------------------------------------------
### Instructions.
###
### This script is an adaptor for attaching tripe's `slip' tunnel driver to
### `userv-ipif'. The latter is a service for GNU Userv which allows
### otherwise unprivileged users to implement network devices, subject to
### administrative limitations on which addresses can be configured and which
### prefixes routed through them. The software is available as part of the
### `userv-utils' package.
###
### To use this script, you'll need to set up a configuration file
### `$TRIPEDIR/ipif.tab'. This file may contain comments (begining `#') and
### blank lines, both of which are ignored, and entries of the form
###
### PEER REMOTE-EXT LOCAL-INT REMOTE-INT ROUTE,...
###
### The PEER names a peer, as given to tripe's ADD command. REMOTE-EXT is
### the external IP address of the peer, i.e., the one which tripe will send
### its packets to. LOCAL-INT and REMOTE-INT are the local and remote
### addresses to be associated with the point-to-point interface. Finally,
### the ROUTEs are a comma-separated list of PREFIX/LEN pairs declaring
### which prefixes should be routed over this interface. The *-INT and
### ROUTEs fields are passed on to the `userv-ipif' service. The REMOTE-EXT
### field is used (a) by the accompanying `ipif-peers' script to set up the
### peer association, and (b) to determine the correct MTU to set; it
### should have the form ADDRESS[:PORT], where the PORT defaults to 4070 if
### it's not given explicitly, and an IPv6 ADDRESS is enclosed in square
### brackets (because of the stupid syntax decision to use colons in IPv6
### address literals).
###
### Having done all of that, and having configured userv-ipif correctly,
### you should set TRIPE_SLIPIF=.../tripe-ipif and everything should just
### work. If you drop the script `ipif-peers' into the $TRIPEDIR/peers
### directory, then the init script will run it and all of the configured
### peers with known remote addresses will be added on startup.
set -e
quis=${0##*/}
: ${TRIPEDIR=@configdir@}
: ${logfile=@logfile@}
: ${TRIPE_IPIF_LOG=${logfile%/*}/tripe-ipif.log}
## Parse the command line.
case $# in 1) ;; *) echo >&2 "Usage: $quis PEER"; exit 1 ;; esac
case ${TRIPEDIR+t} in
t) ;;
*) echo >&2 "$quis: \`TRIPEDIR' unset"; exit 1 ;;
esac
peer=$1
## Arrange for errors to go somewhere.
exec 2>>"$TRIPE_IPIF_LOG"
now=$(date +"%Y-%m-%d %H:%M:%S")
echo >&2 "$now $quis[$$] running for peer \`$peer'"
## Find the record in the peer table.
foundp=nil
while read name remote_ext local_int remote_int routes; do
case $name in "$peer") foundp=t; break ;; esac
done <$TRIPEDIR/ipif.tab
case $foundp in
nil) echo >&2 "$quis[$$]: unknown peer \`$peer'"; exit 1 ;;
esac
## Announce the interface name. We actually have no way to determine this,
## so lie and hope that nobody cares.
echo "userv-$peer"
## Now we can interrogate the server without deadlocking it.
algs=$(tripectl algs) overhead=nil
while read line; do
for i in $line; do
case $i in bulk-overhead=*) overhead=${i#*=} ;; esac
done
done <&2 "$quis[$$]: failed to discover overhead"; exit 1 ;;
esac
## Determine the remote address if none is specified; strip off a port number
## if there is one.
case "$remote_ext" in
-)
addr=$(tripectl addr $peer)
set -- $addr
case $1 in
INET | INET6) remote_af=$1 remote_ext=$2 ;;
*) echo >&2 "$quis: unexpected address family \`$1'"; exit 1 ;;
esac
;;
\[*\]:*)
remote_af=INET6
remote_ext=${remote_ext#\[}
remote_ext=${remote_ext%\]:*}
;;
*:*)
remote_af=INET
remote_ext=${remote_ext%:*}
;;
esac
## Determine the MTU based on the path.
pmtu=$(pathmtu $remote_ext)
case $remote_af in
INET) iphdrsz=20 ;;
INET6) iphdrsz=40 ;;
esac
mtu=$(( $pmtu - $iphdrsz - 8 - $overhead - 1 ))
## Obtain the tunnel and run it.
now=$(date +"%Y-%m-%d %H:%M:%S")
info="invoking \`userv ipif' for \`$peer'; mtu = $mtu"
info="$info; $local_int -> $remote_int${routes+ $routes}"
echo >&2 "$now $quis[$$] $info"
exec userv root ipif $local_int,$remote_int,$mtu,slip $routes
###----- That's all, folks --------------------------------------------------