#!/bin/bash #Copyright 1999-2002, William Stearns #Released under the GPL. TunnelClientVer='0.4.0' #sudo needed for: dd, insmod, ip, tc if using tc mode export PATH="/sbin:/usr/sbin:/bin:/usr/bin" MODE="equal" #tc or equal fail () { logger -s -t client_tunnel "$*, exiting." exit 1 } Action="start" unset TunnelName while [ -n "$1" ]; do case "$1" in [Ss][Tt][Aa][Rr][Tt]) Action='start' ;; [Rr][Ee][Ss][Tt][Aa][Rr][Tt]) Action='restart' ;; [Ss][Tt][Oo][Pp]) Action='stop' ;; -n) if [ -n "$2" ]; then TunnelName="$2" shift else fail "Missing -n TunnelName parameter" fi ;; *) fail "Unknown parameter \"$1\"" ;; esac shift done if [ -z "$TunnelName" ]; then fail "Missing TunnelName" fi unset TunnelServerIP ClientPermanentIP ClientCandidateIFs if [ -r /etc/tunnel.conf ]; then . /etc/tunnel.conf "$TunnelName" else fail "Missing or unreadable /etc/tunnel.conf" fi if [ -z "$TunnelServerIP" ] || [ -z "$ClientPermanentIP" ] || [ -z "$ClientCandidateIFs" ]; then fail "Missing configuration TunnelServerIP, ClientPermanentIP, and/or ClientCandidateIFs information for Tunnel $TunnelName" fi for OneIF in $ClientCandidateIFs ; do if [ -n "`ifconfig | grep '^'$OneIF | awk '{print $1}'`" ]; then ClientIFs="${ClientIFs} `ifconfig | grep '^'$OneIF | awk '{print $1}'`" fi done if [ -z "$ClientIFs" ] && [ "$Action" != 'stop' ]; then logger -s -t client_tunnel "No live interfaces, forcing a stop." Action='stop' fi logger -s -t client_tunnel "Attempting to $Action tunnel Client perm $ClientPermanentIP ($TunnelName) through interfaces $ClientIFs to Server $TunnelServerIP." case "$Action" in start) set -x if [ "$MODE" = 'tc' ]; then if [ `cat /proc/sys/net/ipv4/conf/all/rp_filter` -ne 0 ]; then echo 0 | sudo dd of=/proc/sys/net/ipv4/conf/all/rp_filter #required? fi fi if [ `lsmod | grep '^ip_gre' | wc -l` -eq 0 ]; then sudo insmod ip_gre >/dev/null 2>/dev/null fi if [ `cat /proc/sys/net/ipv4/ip_forward` -ne 1 ]; then echo 1 | sudo dd of=/proc/sys/net/ipv4/ip_forward 2>/dev/null #a sudo-friendly version of: echo 1 >/proc/sys/net/ipv4/ip_forward fi for OneIF in $ClientIFs ; do ClientTransientIPs="${ClientTransientIPs} `ifconfig $OneIF | grep 'inet addr' | awk '{print $2}' | sed -e 's/.*://'`" done echo $ClientTransientIPs #Sent to stdout so caller knows what transient IP's to give to server. if [ "$MODE" = 'equal' ]; then DefaultRouteCommand="sudo ip route add default equalize " #proto static doesn't seem to help, nor does scope global fi TunnelServerRouteCommand="sudo ip route add \"$TunnelServerIP/32\" equalize " for OneIF in $ClientIFs ; do sudo ip tunnel add "t$OneIF" mode gre remote "$TunnelServerIP" local `ifconfig "$OneIF" | grep 'inet addr' | awk '{print $2}' | sed -e 's/.*://'` ttl 255 sudo ip link set "t$OneIF" up sudo ip addr add "$ClientPermanentIP" dev "t$OneIF" if [ "$MODE" = 'equal' ]; then DefaultRouteCommand="${DefaultRouteCommand} nexthop dev \"t$OneIF\"" elif [ "$MODE" = 'tc' ]; then sudo tc qdisc add dev "t$OneIF" root teql0 #FIXME hardcoded teql0 fi TunnelServerRouteCommand="${TunnelServerRouteCommand} nexthop dev \"$OneIF\"" done if [ "$MODE" = 'tc' ]; then sudo ip link set dev teql0 up sudo ip addr add "$ClientPermanentIP" dev teql0 fi sudo ip route del "$TunnelServerIP/32" eval "$TunnelServerRouteCommand" sudo ip route del 0/0 if [ "$MODE" = 'equal' ]; then eval "$DefaultRouteCommand" elif [ "$MODE" = 'tc' ]; then sudo ip route add default dev teql0 fi ;; stop) set -x for OneIF in $ClientIFs ; do sudo ip link set "t$OneIF" down sudo ip tunnel del "t$OneIF" #sudo ip route del "$TunnelServerIP/32" done if [ "$MODE" = 'tc' ]; then sudo ip link set teql0 down fi #FIXME - reinstate default route. ;; restart) $0 stop -n "$TunnelName" $0 start -n "$TunnelName" ;; *) fail "Use \"$0 start\", \"$0 stop\" or \"$0 restart\"" ;; esac exit 0 #Graveyard: #OutIF="ppp0" #MODULE="ipip" ; TDev="tunl0" #MODULE="ip_gre" ; TDev="gre0" #TDev="bill" #TunnelServerIP="Z.Z.Z.Z" #ClientPermanentIP="Z.Z.Z.Y" #DefaultRouteDevs="`/sbin/route -n | grep '^0\.0\.0\.0[ \t]' | awk '{print $8}' | sort | uniq`" #DefaultRouteGws="`/sbin/route -n | grep '^0\.0\.0\.0[ \t]' | awk '{print $2}' | sort | uniq`" #if [ `echo "$DefaultRouteDevs" | wc -l` -ne 1 ]; then # echo Too many or few default route interfaces, exiting. >>/dev/stderr # exit 1 #fi #if [ `echo "$DefaultRouteGws" | wc -l` -ne 1 ]; then # echo Too many or few default route ips, exiting. >>/dev/stderr # exit 1 #fi #DESTS="${DESTS} Onetargetmachine Anothertargetmachine" #DESTS="${DESTS} 0.0.0.0/0.0.0.0" #Start # sudo insmod ip_gre >/dev/null 2>/dev/null # sudo ifconfig "$TDev" "$ClientPermanentIP" pointopoint "$TunnelServerIP" netmask 255.255.255.255 up # # sudo route del -host "$TunnelServerIP" "$TDev" # sudo route add -host "$TunnelServerIP" "$TDev" # for AHOST in $DESTS ; do # case "$AHOST" in # */*) # Network=${AHOST%%/*} # Netmask=${AHOST##*/} # sudo route add -net "$Network" netmask "$Netmask" gw "$TunnelServerIP" "$TDev" # if [ "$AHOST" = "0.0.0.0/0.0.0.0" ]; then # sudo route del default "$OutIF" # fi # ;; # *) # sudo route add -host "$AHOST" gw "$TunnelServerIP" "$TDev" # ;; # esac # done # sudo route del -host "$TunnelServerIP" "$TDev" # sudo route del -host "$TunnelServerIP" "$TDev" >/dev/null 2>/dev/null # # sudo route add -host "$TunnelServerIP" "$OutIF" #Stop # sudo route del -host "$TunnelServerIP" "$OutIF" # # for AHOST in $DESTS ; do # case "$AHOST" in # */*) # Network=${AHOST%%/*} # Netmask=${AHOST##*/} # #echo "Routing to network $Network, netmask $Netmask" >>/dev/stderr # sudo route del -net "$Network" netmask "$Netmask" gw "$TunnelServerIP" "$TDev" # if [ "$AHOST" = "0.0.0.0/0.0.0.0" ]; then # sudo route add default "$OutIF" # fi # ;; # *) # sudo route del -host "$AHOST" gw "$TunnelServerIP" "$TDev" # ;; # esac # done # # sudo ifconfig "$TDev" down # #sudo route add default "$OutIF" #Done above # sudo rmmod ip_gre #ip/tc notes. #for OneIF in $ClientIFs ; do # sudo tc qdisc add dev "$OneIF" root teql0 #done #sudo ip link set dev teql0 up #sudo ip addr add dev teql0 "$ClientPermanentIP" #sudo ip route add 0/0 dev teql0 #sudo ip route add default scope global nexthop via "$P1" dev "$IF1" weight 1 nexthop via "$P2" dev "$IF2" weight 1 # sudo tc qdisc add dev eth1 root teql0 # sudo tc qdisc add dev eth2 root teql0 # sudo ip link set dev teql0 up #Don't forget the 'ip link set up' command! #This needs to be done on both hosts. The device teql0 is basically a #roundrobin distributor over eth1 and eth2, for sending packets. No data #ever comes in over an teql device, that just appears on the 'raw' eth1 #and eth2. #But now we just have devices, we also need proper routing. One way to do #this is to assign a /31 network to both links, and a /31 to the teql0 #device as well: #FIXME: does this need something like 'nobroadcast'? A /31 is too small #to house a network address and a broadcast address - if this doesn't #work as planned, try a /30, and adjust the ip adresses accordingly. You #might even try to make eth1 and eth2 do without an IP address! #On router A: # ip addr add dev eth1 10.0.0.0/31 # ip addr add dev eth2 10.0.0.2/31 # ip addr add dev teql0 10.0.0.4/31