#!/usr/bin/perl
-# Simple tunnel for userv-ipif tunnels.
+# Encrypting VPN tunnel for use with userv-ipif.
#
-# Example test invocation
-#
-# ./udptunnel -e nonce -e timestamp/10/30 -e pkcs5/8 -e blowfish-cbcmac/128 -e blowfish-cbc/128 -m -f ./udptunnel-forwarder davenant,Any anarres,Command 172.30.206.1,172.30.206.2,1000,cslip 15,70 '' '' rsh anarres things/userv-utils/ipif/udptunnel -f things/userv-utils/ipif/udptunnel-forwarder
+# This comment is reference documentation. See ipif/INSTALL for the
+# installation instructions and setup tutorial.
#
# usage:
-# udptunnel
-# [ -l[<local-command/arg>] ... .
+# To make a tunnel between two machines `alice' and `bob',
+# on `alice', the active endpoint, run:
+#
+# udptunnel
+# [ -l[<alice-command/arg>] ... .
# | -e <encryption-mech>[/<encryption-parameter>...]
-# | -m (`masquerade support': subcommand gets `Wait' instead of our addr/port)
-# | -d (`dump keys': when no subcmd, spew keys rather than reading them;
-# we always send keys to our subcmd if there is one)
+# | -m (`masquerade support': bob gets `Wait' instead of our addr/port)
+# | -d (`dump keys': when no peer, spew keys rather than reading them;
+# we always send keys to our peer if there is one)
# | -Dcrypto (debug crypto - use with care, prints keys, packets &c on screen!)
# | -f<path-to-udptunnel-forwarder>
# ...
# ]
-# <public-local-addr>,<public-local-port>
-# <public-remote-addr>,<public-remote-port>
-# <private-local-addr>,<private-remote-addr>,<mtu>,<proto>
-# <keepalive>,<timeout>
-# <extra-local-nets> <extra-remote-nets>
-# [ <remote-command> [<remote-args> ...] ]
+# <alice-phys-addr>,<alice-phys-port>
+# <bob-phys-addr>,<bob-phys-port>
+# <alice-virt-addr>,<bob-virt-addr>,<mtu>,<proto>
+# <keepalive>,<timeout>[,<reannounce>]
+# <alice-priv-nets> <bob-priv-nets>
+# [ <bob-command> [<bob-args> ...] ]
+#
+# This will run udptunnel-forwarder on alice, and use <bob-command>
+# (usually an ssh invocation) to run udptunnel appropriately on bob.
+# Key material will be generated by alice and fed to udptunnel on bob
+# via <bob-command>'s stdin, and the physical address and port on bob
+# will be (if so configured) returned via <bob-command>'s stdout.
+#
+# The tunnel will stay up until one of the subprocesses involved dies,
+# or the keepalive timeout expires. If you want the tunnel to remain
+# up permanently, you must arrange to invoke it repeatedly (eg, from
+# inittab). See INSTALL.
#
-# proto may be slip or cslip
+# <proto> may be slip or cslip
#
-# Any <..-addr> may also be hostname
+# <mtu> will be the MTU of the tunnel interfaces; it is best if this
+# is enough smaller than the path MTU between the physical interfaces
+# that the encapsulated packets will fit without fragmentation.
#
-# Local addr's and ports may also be:
+# Any <..-addr> supplied to udptunnel may also be hostname; these will
+# all be looked up on alice and IP addresses passed to bob.
+#
+# The `local' physical address and ports (ie, alice's own details),
+# may have these special values:
+# `Any' choose one ourselves and do not print it (the port chosen
+# will be supplied to bob)
# `Print' choose one ourselves and print both port and addr
-# `Any' choose one ourselves and do not print it
-# Remote addr's and ports may also be:
-# `Wait' wait to receive a packet before assigning address
-# `Command' run a subcommand and wait for it to tell us the values
-# When any addr or port is `Command' then <remote-command> must be specified.
+# (this is not usually useful specified directly; it's
+# used by udptunnel when it invokes itself on bob via
+# <bob-command>, to have its other self print the
+# relevant value.
#
-# If <remote-command> is specified it should run udptunnel at the
-# remote end; it will be invoked as
-# <remote-command> [ <-e arguments passed along> ]
-# <public-remote-addr'>,<public-remote-port'>
-# <public-local-addr'>,<public-local-port'>
-# <private-remote-addr>,<private-local-addr>,<mtu>,<proto>
-# <keepalive>,<timeout>
-# <extra-remote-nets> <extra-local-nets>
+# The `remote' physical address and port (ie, on alice, bob's details),
+# may also have the special values:
+# `Command' wait for <bob-command> to tell us the values (this is
+# usually the right choice on alice for at least the
+# port). <bob-command> must be specified (ie, this
+# only makes sense on alice).
+# `Wait' alice will wait to receive a packet from bob and use
+# whatever address and port it came from
#
-
-# If it was given Print for <public-remote-foo'>, this command's first
-# stdout output should be the real
-# <public-remote-addr>,<public-remote-port> pair (and of course this
-# udptunnel's output will be). It may then produce more stdout which,
-# if any, will be forwarded to the local end's stdout as debugging info.
+# These special values are case-sensitive. When alice runs udptunnel
+# on bob they are automatically translated to appropriate other values
+# in the arguments to bob's udptunnel.
+#
+# If <bob-command> is specified it should run udptunnel at the
+# bob end; it will be invoked as
+# <bob-command> [ <bob-args> ... ]
+# [ <-e arguments passed along> ]
+# <bob-phys-addr'>,<bob-phys-port'>
+# <alice-phys-addr'>,<alice-phys-port'>
+# <bob-virt-addr>,<alice-virt-addr>,<mtu>,<proto>
+# <keepalive>,<timeout>[,<reannounce>]
+# <bob-priv-nets> <alice-priv-nets>
#
-# After this, if any encryption was specified, the encryption
-# parameters will be fed into its stdin. See the documentation in the
-# mech-*.c files for details of the parameters. udptunnel will
-# arrange to feed the keys fd of udptunnel-forwarder into the stdin of
-# the remote command.
+# If it was given Print for <bob-phys-foo'>, udptunnel's first stdout
+# output will be the real <bob-phys-addr>,<bob-phys-port> pair. It
+# may then produce more stdout which, if any, will be forwarded to the
+# local end's stdout as debugging info.
#
-# <public-remote-foo'> is as follows:
-# <public-remote-foo> <public-remote-foo'>
-# actual addr/port that addr/port
-# `Command' `Print'
-# `Wait' `Any'
+# After this, if any encryption was specified, the encryption key
+# material will be fed into its stdin. See the documentation in the
+# mech-*.c files for details of the parameters. udptunnel on alice
+# will arrange to feed the keys fd of udptunnel-forwarder into the
+# stdin of the udptunnel on bob.
#
-# <public-local-foo'> is as follows:
-# <public-local-foo> <public-local-foo'> <public-local-foo'>
-# (-m not specified) (-m specified)
+# <bob-phys-foo'> is as follows:
+# <bob-phys-foo> <bob-phys-foo'>
+# actual addr/port that addr/port
+# `Command' `Print'
+# `Wait' `Any'
+#
+# <alice-phys-foo'> is as follows:
+# <alice-phys-foo> <alice-phys-foo'> <alice-phys-foo'>
+# (-m not specified) (-m specified)
# actual addr/port that addr/port `Wait'
-# `Wait' the chosen address `Wait'
# `Print' the chosen address `Wait'
+# `Any' `Wait' for addr, `Wait'
+# chosen port for port
#
-# udptunnel will userv ipif locally, as
-# userv root ipif <private-local-addr>,<private-remote-addr>,<mtu>,<proto>
-# <extra-local-nets>
+# In each case udptunnel will run userv ipif locally, as
+# userv root ipif <local-virt-addr>,<remote-virt-addr>,<mtu>,<proto>
+# <remote-priv-nets>
# or, if -l was given, userv root ipif is replaced with the argument(s)
# following -l option(s) until `.'.
#
-# udptunnel will also run udptunnel-forwarder with appropriate options
+# udptunnel will also run udptunnel-forwarder with appropriate options.
#
# recommended encryption parameters are:
# -e nonce (prepend 32 bit counter)
# -e pkcs5/8 (pad as per PKCS#5 to 8-byte boundary)
# -e blowfish-cbcmac/128 (prepend CBC MAC with random IV and 128 bit key)
# -e blowfish-cbc/128 (encrypt with CBC, random IV and 128 bit key)
-# where <max-skew> is perhaps 10 and <max-age> perhaps 30.
+# where <max-skew> is perhaps 10 and <max-age> perhaps 30. If your
+# clocks are not sufficiently well synchronised, you could replace
+# `-e nonce -e timestamp/...' with just `-e sequence'. Do not just
+# remove `-e timestamp/...'.
# Copyright (C) 1999-2000 Ian Jackson
#
return shift @ARGV;
}
-$|=1;
-
@lcmd= ();
@encryption= ();
$masq= 0;
($lva,$rva,$mtu,$proto) = ($1,$2,$3,$4);
$_= shift @ARGV;
-m/^(\d+),(\d+)$/ or quit("keepalive,timeout missing or bad syntax");
-($keepalive,$timeout)= ($1,$2);
+if (m/^(\d+),(\d+)$/) {
+ ($keepalive,$timeout,$reannounce)= ($1+0,$2+0,0);
+ $ka_to_ra= "$keepalive,$timeout";
+} elsif (m/^(\d+),(\d+),(\d+)$/) {
+ ($keepalive,$timeout,$reannounce)= ($1+0,$2+0,$3);
+ "$keepalive,$timeout",
+ $ka_to_ra= "$keepalive,$timeout,$reannounce";
+} else {
+ quit("keepalive,timeout missing or bad syntax");
+}
$keepalive && ($timeout > $keepalive*2) or quit("timeout must be < 2*keepalive")
if $timeout;
@rcmd= (@ARGV,
@remoteopts,
"$rad,$rpd",
- $masq ? 'Wait,Wait' : $lapd,
+ $masq ? 'Wait,Wait' : $las eq 'Any' ? "Wait,$lpd" : $lapd,
"$rva,$lva,$mtu,$proto",
- "$keepalive,$timeout",
+ $ka_to_ra,
$rexn, $lexn);
debug("remote command @rcmd");
if ($rapcmd) {
pipe(RAPREAD,RCMDREADSUB) or fail("pipe");
- select(RCMDREADSUB); $|=1; select(STDOUT);
}
pipe(RCMDWRITESUB,DUMPKEYS) or fail("pipe");
defined($c_rcmd= fork) or fail("fork for remote");
if ($rapcmd) {
close RCMDREADSUB if $rapcmd;
- $!=0; $_= <RAPREAD>; $e="$!";
+ $_= '';
+ while (!m/\n/) {
+ $!=0;
+ defined($nread= sysread(RAPREAD,$_,1,length))
+ or fail("read from remote command");
+ if (!$nread) {
+ close DUMPKEYS;
+ close RAPREAD;
+ waitpid $c_rcmd,0 or fail("wait for remote command");
+ quit($? ? "remote command failed (code $?)" :
+ "no details received from remote");
+ }
+ }
+ chomp;
+ m/^([.0-9]+)\,(\d+)$/ or quit("invalid details from remote end: \`$_'");
+ ($rar,$rpr) = ($1,$2);
+ $ra= conv_host_addr($rar);
+ $rp= conv_port_number($rpr);
defined($c_catremdebug= fork) or fail("fork for cat remote debug");
if (!$c_catremdebug) {
open(STDIN,"<&RAPREAD") or fail("redirect remote debug");
- close RAPREAD;
close DUMPKEYS;
close L;
exec "cat"; fail("execute cat");
}
close RAPREAD;
-
- if (!length) {
- close DUMPKEYS;
- waitpid $c_rcmd,0 or fail("wait for remote command");
- quit($? ? "remote command failed (code $?)" :
- $e ? "read error from remote command: $e" :
- "no details received from remote");
- }
- chomp;
- m/^([.0-9]+)\,(\d+)$/ or quit("invalid details from remote end: \`$_'");
- ($rar,$rpr) = ($1,$2);
- $ra= conv_host_addr($rar);
- $rp= conv_port_number($rpr);
}
} elsif ($dump) {
open DUMPKEYS, ">&STDOUT" or fail("reopen stdout for key material");
@fcmd= ($fcmd, $xfwdopts,
fileno(L), fileno(DW), fileno(UR), fileno(DUMPKEYS),
- $mtu, $keepalive, $timeout,
+ $mtu, $keepalive, $timeout, $reannounce,
@rapf,
@encryption);
debug("forwarding command @fcmd.");