chiark / gitweb /
Bugfixes, now seems to be getting there.
authorian <ian>
Sat, 25 Sep 1999 00:14:10 +0000 (00:14 +0000)
committerian <ian>
Sat, 25 Sep 1999 00:14:10 +0000 (00:14 +0000)
ipif/udptunnel

index 1c022ba..8a2dbc5 100755 (executable)
 #    <remote-command> <public-remote-host/addr>,print
 #                     <public-local-addr>,<public-local-port>
 #                     <private-remote-addr>,<private-local-addr>,<mtu>,<proto>
-#                     <extra-local-nets>
+#                     <keepalive>,<timeout>
+#                     <extra-remote-nets> <extra-local-nets>
 #
 # udptunnel will userv ipif locally, as
-#    userv ipif <private-local-addr>,<private-remote-addr>,<mtu>,<proto>
-#               <extra-local-nets>
+#    userv root ipif <private-local-addr>,<private-remote-addr>,<mtu>,<proto>
+#                    <extra-local-nets>
 
 use Socket;
 use POSIX;
@@ -51,7 +52,7 @@ sub conv_host_addr ($) {
     defined($r= inet_aton($s)) or quit("$s: cannot convert to address");
     return $r;
 }
-sub conv_port_addr ($) {
+sub conv_port_number ($) {
     my ($s,$r) = @_;
     if ($s =~ m/\d/) {
        $r= $s+0;
@@ -79,11 +80,11 @@ $ra= $rps eq 'command' ? '' : conv_host_addr($ras);
 $_= shift @ARGV;
 m/^([.0-9]+),([.0-9]+),(\d+),(slip|cslip)$/
     or quit("lvaddr,rvaddr,mtu,proto missing or bad syntax or proto not [c]slip");
-($lva,$rva,$mtu,$proto= $1,$2;
+($lva,$rva,$mtu,$proto) = ($1,$2,$3,$4);
 
 $_= shift @ARGV;
-m/^(\d+),(\d+)$/ or quit("timeout missing or bad syntax");
-($keepalive,$timeout)= $1,$2;
+m/^(\d+),(\d+)$/ or quit("keepalive,timeout missing or bad syntax");
+($keepalive,$timeout)= ($1,$2);
 $keepalive && ($timeout > $keepalive*2) or quit("timeout must be < 2*keepalive")
     if $timeout;
 
@@ -100,13 +101,13 @@ defined($ls= getsockname(L)) or fail("getsockname");
 $lsp= show_addr_port($ls);
 
 if ($rps eq 'command') {
-    $lepn= shift @ARGV;
     quit("when using ,command for remote, must supply command") unless @ARGV;
+    @rcmd= (@ARGV, "$ras,print", "$lsp", "$rva,$lva,$mtu,$proto",
+           "$keepalive,$timeout", $repn, $lepn);
+    debug("remote command @rcmd");
     defined($c= open C,"-|") or fail("fork for remote");
     if (!$c) {
-       push @ARGV, "$ras,print", "$lsp", "$rva,$lva,$mtu,$proto", $lepn;
-       debug("remote command @ARGV");
-       exec @ARGV; die "$progname: error: failed to execute $ARGV[0]: $!\n";
+       exec @rcmd; die "$progname: error: failed to execute $rcmd[0]: $!\n";
     }
     $_= <C>;
     if (!length) {
@@ -117,10 +118,10 @@ if ($rps eq 'command') {
     m/^([.0-9]+)\,(\d+)$/ or quit("invalid details from remote end ($_)");
     ($ras,$rps) = ($1,$2);
     $ra= conv_host_addr($ras);
-    $rp= conv_port_addr($rps);
+    $rp= conv_port_number($rps);
     defined($c2= fork) or fail("fork for cat");
     if (!$c2) {
-       open STDIN,">&C" or fail("redirect remote pipe to stdin");
+       open(STDIN,"<&C") or fail("redirect remote pipe to stdin");
        close C;
        exec "cat"; fail("execute cat");
     }
@@ -131,11 +132,9 @@ if ($rps eq 'command') {
 $rs= pack_sockaddr_in $rp,$ra;
 $rsp= show_addr_port($rs);
 
-debug("using remote $rsp");
+if ($lps eq 'print') { print($lsp,"\n") or quit("write port to stdout: $!"); }
 
-if ($lps eq 'print') { print $lsp,"\n" or quit("write port to stdout: $!"); }
-
-debug("public address $lsp");
+debug("using remote $rsp local $lsp");
 
 pipe(UR,UW) or fail("up pipe");
 pipe(DR,DW) or fail("down pipe");
@@ -143,9 +142,9 @@ pipe(DR,DW) or fail("down pipe");
 defined($c3= fork) or fail("fork for ipif");
 if (!$c3) {
     close UR; close DW;
-    open STDIN,"<&DR" or fail("reopen stdin for packets");
-    open STDOUT,"<&UW" or fail("reopen stdout for packets");
-    exec "userv","ipif","$lva,$rva,$mtu,$proto",$lepn;
+    open(STDIN,"<&DR") or fail("reopen stdin for packets");
+    open(STDOUT,">&UW") or fail("reopen stdout for packets");
+    exec "userv","root","ipif","$lva,$rva,$mtu,$proto",$lepn;
     quit("cannot execute userv ipif: $!");
 }
 close UW;
@@ -155,8 +154,8 @@ $upyet= 0;
 $downyet= 0;
 
 $wantreadfds='';
-vec($wantreadfds,fileno(UR))= 1;
-vec($wantreadfds,fileno(L))= 1;
+vec($wantreadfds,fileno(UR),1)= 1;
+vec($wantreadfds,fileno(L),1)= 1;
 
 sub nonblock ($) {
     my ($fh,$fl) = @_;
@@ -170,8 +169,23 @@ nonblock('L');
 
 $upbuf= '';
 
+sub now () { my ($v); defined($v= time) or fail("get time"); return $v; }
+if ($keepalive) { $nextsendka= now(); }
+
 for (;;) {
-    select($readfds=$wantreadfds,'','',undef);
+    if ($keepalive) {
+       $now= now();
+       $timeout= $nextsendka-$now;
+       if ($timeout < 0) {
+           defined(send L,"\300",0,$rs)
+               or warning("transmit keepalive error: $!");
+           $nextsendka= $now+$keepalive;
+           $timeout= $keepalive;
+       }
+    } else {
+       $timeout= undef;
+    }
+    select($readfds=$wantreadfds,'','',$timeout);
     for (;;) {
        if (!defined($r= sysread(UR,$upbuf,$mtu*2+3,length($upbuf)))) {
            $! == EAGAIN || warning("tunnel endpoint read error: $!");
@@ -181,11 +195,11 @@ for (;;) {
            quit "tunnel endpoint closed by system";
        }
        while (($p= index($upbuf,"\300")) >= 0) {
-           if (defined(send L,substr($upbuf,0,$p),0,$rs)) {
+           if (!defined(send L,substr($upbuf,0,$p),0,$rs)) {
+               warning("transmit error: $!");
+           } elsif (!$upyet) {
                $upyet= 1;
                debug($downyet ? "tunnel open" : "transmit channel open");
-           } else {
-               warning("transmit error: $!");
            }
            $upbuf= substr($upbuf+1,$p);
        }
@@ -194,15 +208,18 @@ for (;;) {
        $rsp_from= show_addr_port($rs_from);
        if ($rsp_from ne $rsp) {
            warning("got packet from incorrect peer $rsp_from");
-           continue;
+           next;
        }
        if (!defined($r= syswrite(DW,$downbuf,length $downbuf))) {
            warning("tunnel endpoint write error: $!");
-       } elsif ($r != length $downbuf) {
+       } elsif ($r != length $downbuf) {
            warning("tunnel endpoint wrong write length");
        } else {
-           $downyet= 1;
-           debug($upyet ? "tunnel open" : "receive channel open");
+           if (!$downyet) {
+               $downyet= 1;
+               debug($upyet ? "tunnel open" : "receive channel open");
+           }
+           alarm($timeout) if $timeout;
        }
     }
     $! == EAGAIN || warning("receive error: $!");