3
\$\begingroup\$

I've developed a script to set up an encrypted tunnel between two Linux hosts, using iproute2, ssh and setkey. The goal is to allow setting up ad-hoc secure tunnels with minimum of setup and dependencies.

Mirrored here:

#!/bin/bash

# Setup encrypted IPv4 tunnel over IPv4 or IPv6 on two Linux nodes using SSH for tunnel setup.
# Requires only ipsec-tools, iproute2, ssh and necessry kernel modules locally and remotely.

# Warning: it flushes IPsec settings both locally and remotely.
# Don't use with other IPsec tunnnels.

# Sample usage:
# simplevpn -6 fc::1 fc::2    ssh -T root@fc::2
#    fc::1 is your IPv6 address
#    fc::2 is other peer's IPv6 address
# after successful run it should create tunnel named "simplevpn" locally and remotely
# and set up addresses 192.168.77.1 and 192.168.77.2 locally and remotely respectively

# Note: tested only once in my configuration. This is not a serious production-ready VPN solution.

# Implemented by Vitaly "_Vi" Shukela in 2013, License=MIT


MODE="ipip"
PROT="-4"

if [ "$1" == "-6" ]; then
    shift;
    MODE=ipip6
    PROT="-6"
fi

SRC="$1"; shift
DST="$1"; shift

if [ -z "$1" ]; then
    echo Usage: simplevpn [-6] source_ip destination_ip ssh_command_line
    exit 1;
fi
set -e

KEY1=0x`dd if=/dev/urandom count=32 bs=1 2> /dev/null| xxd -p -c 64`
KEY2=0x`dd if=/dev/urandom count=32 bs=1 2> /dev/null| xxd -p -c 64`

true ${LOCALIP:="192.168.77.1"}
true ${REMOTEIP:="192.168.77.2"}
true ${DEVNAME:="simplevpn"}

# 4 is encapsulated IPv4 both in IPv4 an IPv6
setkey -c << EOF
    flush; 
    spdflush; 
    spdadd $SRC $DST   4 -P out ipsec esp/transport//require  ah/transport//require; 
    spdadd $DST $SRC   4 -P in ipsec esp/transport//require  ah/transport//require;
    add $SRC $DST esp 0x4444 -E rijndael-cbc $KEY1 ; 
    add $DST $SRC esp 0x4444 -E rijndael-cbc $KEY1 ;
    add $SRC $DST ah 0x4445 -A hmac-sha256 $KEY2 ; 
    add $DST $SRC ah 0x4445 -A  hmac-sha256 $KEY2 ;
EOF

modprobe ip6_tunnel
ip $PROT tunnel del $DEVNAME || true

ip $PROT tunnel add  $DEVNAME mode $MODE local $SRC remote $DST
ip link set $DEVNAME up
ip -4 addr add $LOCALIP/32 dev $DEVNAME
ip -4 route add $REMOTEIP/32 dev $DEVNAME


"$@" << EOF
    set -e
    # the same as above, but "in" and "out" swapped
    setkey -c << EOF2
        flush; 
        spdflush; 
        spdadd $SRC $DST   4 -P in ipsec esp/transport//require  ah/transport//require; 
        spdadd $DST $SRC   4 -P out ipsec esp/transport//require  ah/transport//require;
        add $SRC $DST esp 0x4444 -E rijndael-cbc $KEY1 ; 
        add $DST $SRC esp 0x4444 -E rijndael-cbc $KEY1 ;
        add $SRC $DST ah 0x4445 -A hmac-sha256 $KEY2 ; 
        add $DST $SRC ah 0x4445 -A  hmac-sha256 $KEY2 ;
EOF2

    modprobe ip6_tunnel
    ip $PROT tunnel del $DEVNAME || true

    ip $PROT tunnel add  $DEVNAME mode $MODE remote $SRC local $DST
    ip link set $DEVNAME up
    ip -4 addr add $REMOTEIP/32 dev $DEVNAME
    ip -4 route add $LOCALIP/32 dev $DEVNAME
EOF

Are there any glaring errors? Do you have any suggestions (apart from not flushing entire security tables)? I'm primarily interested in security issues.

\$\endgroup\$
1
  • \$\begingroup\$ Note: filed a bug reproduced with this script. \$\endgroup\$
    – Vi.
    May 23, 2013 at 15:03

1 Answer 1

1
\$\begingroup\$
  • As far as I can tell, it checks if you provide too many options, but it doesn't check if you provide too few. This should be done before trying to do anything with SRC and DST. set -o errexit -o nounset as the first line would be prudent.
    • set stuff is not inherited by subshells. So to make a failure in the dd command propagate you should start with set -o errexit -o pipefail. A simpler way to achieve the same effect would be to add -o pipefail to set, create a function with the dd | xxd commands, and use this directly instead of assigning to variables.
  • What happens if dd fails, for whatever reason? For example, dd() { echo foo; } will override the command. Use command dd [sic] if you want to make sure it doesn't use shell builtins, aliases or functions.
  • There's no == operator in POSIX [ - AFAIK this only works by accident on some systems. You can either use Bash' [[ or a single =.
  • || true can hide issues with the preceding command. Either check first if the command should be run before trying (and not ignoring the error), or run the command and check if the exit code matches the one you expect.
  • Use More Quotes™

I can't comment on the safety of the KEYn generation or setkey use.

\$\endgroup\$
4
  • \$\begingroup\$ Thanks for the advices. The main concern is setkey. Can my tunnel suddenly become uncrypted? Is the encryption applied correctly? \$\endgroup\$
    – Vi.
    May 28, 2013 at 17:57
  • \$\begingroup\$ Doesn't set -e dig into backticked command? If dd failed I expect the script to exit. \$\endgroup\$
    – Vi.
    May 28, 2013 at 17:59
  • \$\begingroup\$ @Vi. Updated with tips. \$\endgroup\$
    – l0b0
    May 29, 2013 at 8:18
  • \$\begingroup\$ @Vi. As I said, I can't really comment on the inner security issues. You may want to strip down to the bare minimum code and ask on security. \$\endgroup\$
    – l0b0
    May 29, 2013 at 8:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.