Update VERSION
[userv-utils] / ipif / udptunnel
index 08b75a3..09595d1 100755 (executable)
@@ -1,6 +1,10 @@
 #!/usr/bin/perl
 # Simple tunnel for userv-ipif tunnels.
 #
+# 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
+#
 # usage:
 #  udptunnel
 #        [ -l[<local-command/arg>] ... .
@@ -15,8 +19,8 @@
 #            <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>
+#            <keepalive>,<timeout>[,<reannounce>]
+#            <extra-nets-for-local-cmd> <extra-nets-for-remote-cmd>
 #          [ <remote-command> [<remote-args> ...] ]
 #
 # proto may be slip or cslip
@@ -37,8 +41,8 @@
 #                     <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>
+#                     <keepalive>,<timeout>[,<reannounce>]
+#                     <extra-nets-for-remote-cmd> <extra-nets-for-local-cmd>
 #
 
 # If it was given Print for <public-remote-foo'>, this command's first
 #   <public-local-foo>   <public-local-foo'>     <public-local-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>
+#                    <extra-nets-for-local-cmd>
 # or, if -l was given, userv root ipif is replaced with the argument(s)
 # following -l option(s) until `.'.
 #
@@ -159,15 +164,13 @@ sub show_addr_port ($) {
     return show_addr($s).','.show_port($s);
 }
 sub arg_value ($$) {
-    my ($val,$opt);
+    my ($val,$opt) = @_;
     $_= '-';
     return $val if length $val;
     @ARGV or quit("$opt needs value");
     return shift @ARGV;
 }
 
-$|=1;
-
 @lcmd= ();
 @encryption= ();
 $masq= 0;
@@ -187,14 +190,17 @@ while ($ARGV[0] =~ m/^-/) {
            $fcmd= arg_value($_,'-f');
        } elsif (s/^-e//) {
            $encrarg= arg_value($_,'-e');
-           push @encrargs, "-e$encrarg";
-           push @encryption, split m#/#, $encrarg;
+           push @remoteopts, "-e$encrarg";
+           @thisencryption= split m#/#, $encrarg;
+           $thisencryption[0] =~ s/^/\|/;
+           push @encryption, @thisencryption;
        } elsif (s/^-m/-/) {
            $masq= 1;
        } elsif (s/^-d/-/) {
            $dump= 1;
        } elsif (s/^-Dcrypto$/-/) {
            $xfwdopts.= 'K';
+           push @remoteopts, '-Dcrypto';
        } else {
            quit("unknown option \`$_'");
        }
@@ -221,8 +227,16 @@ m/^([.0-9]+),([.0-9]+),(\d+),(slip|cslip)$/
 ($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;
 
@@ -259,22 +273,21 @@ if (@ARGV) {
     $rad= xform_remote(show_addr($rs),$ras);
     $rpd= xform_remote(show_port($rs),$rps);
     @rcmd= (@ARGV,
-           @encrargs,
+           @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(DUMPKEYS,RCMDWRITESUB) or fail("pipe");
+    pipe(RCMDWRITESUB,DUMPKEYS) or fail("pipe");
     defined($c_rcmd= fork) or fail("fork for remote");
     if (!$c_rcmd) {
-       open STDIN, ">&RCMDWRITESUB" or fail("reopen stdin for remote command");
+       open STDIN, "<&RCMDWRITESUB" or fail("reopen stdin for remote command");
        open STDOUT, ">&RCMDREADSUB" or fail("reopen stdout for remote command")
            if $rapcmd;
        close RAPREAD if $rapcmd;
@@ -288,30 +301,33 @@ if (@ARGV) {
     
     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");
@@ -353,14 +369,14 @@ $xfwdopts.= 'w' if $dump;
 
 @fcmd= ($fcmd, $xfwdopts,
        fileno(L), fileno(DW), fileno(UR), fileno(DUMPKEYS),
-       $mtu, $keepalive, $timeout,
+       $mtu, $keepalive, $timeout, $reannounce,
        @rapf,
        @encryption);
 debug("forwarding command @fcmd.");
 
 defined($c_fwd= fork) or fail("fork for udptunnel-forwarder");
 if (!$c_fwd) {
-    foreach $fd (qw(L DW UR)) {
+    foreach $fd (qw(L DW UR DUMPKEYS)) {
        fcntl($fd, F_SETFD, 0) or fail("set no-close-on-exec $fd");
     }
     exec @fcmd; fail("cannot execute $fcmd[0]");
@@ -381,11 +397,12 @@ $estatus= 0;
 while (keys %procs) {
     ($c= wait) >0 or
        fail("wait failed (expecting ". join('; ',keys %procs). ")");
-    warning("unexpected child reaped: pid $c, code $?"), next
+    $status= $?;
+    warning("unexpected child reaped: pid $c, code $status"), next
        unless exists $procs{$c};
     $str= $procs{$c};
     delete $procs{$c};
-    $? ? warning("subprocess $str failed with code $?")
+    $status ? warning("subprocess $str failed with code $status")
        : debug("subprocess $str finished");
     if ($c==$c_lcmd || $c==$c_fwd || $c==$c_rcmd) {
        kill 15, grep (exists $procs{$_}, $c_fwd, $c_rcmd);