#
# usage:
# udptunnel
+# [ -l[<local-command/arg>] ... . ]
# <public-local-host/addr>,<public-local-port>
# <public-remote-host/addr>,<public-remote-port>
# <private-local-addr>,<private-remote-addr>,<mtu>,<proto>
# udptunnel will userv ipif locally, as
# userv root ipif <private-local-addr>,<private-remote-addr>,<mtu>,<proto>
# <extra-local-nets>
+# or, if -lc was given, userv root ipif is replaced with the argument(s) to
+# successive -lc options.
use Socket;
use POSIX;
return inet_ntoa($s[1]).','.$s[0];
}
+@lcmd= ();
+
+while ($ARGV[0] =~ m/^-/) {
+ $_= shift @ARGV;
+ last if $_ eq '--';
+ if (s/^-l//) {
+ push @lcmd,$_ if length;
+ while (@ARGV && ($_= shift @ARGV) ne '-') { push @lcmd, $_; }
+ } else {
+ quit("unknown option \`$_'");
+ }
+}
+
($las,$lps)= eat_addr_port('print|silent');
$la= conv_host_addr($las);
$lp= conv_port_number($lps);
if ($lps eq 'print') { print($lsp,"\n") or quit("write port to stdout: $!"); }
+@lcmd= qw(userv root ipif) unless @lcmd;
+
debug("using remote $rsp local $lsp");
+push @lcmd, ("$lva,$rva,$mtu,$proto",$lepn);
+debug("local command @lcmd");
pipe(UR,UW) or fail("up pipe");
pipe(DR,DW) or fail("down pipe");
close UR; close DW;
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: $!");
+ exec @lcmd;
+ quit("cannot execute $lcmd[0]: $!");
}
close UW;
close DR;
quit "tunnel endpoint closed by system";
}
while (($p= index($upbuf,"\300")) >= 0) {
- if (!defined(send L,substr($upbuf,0,$p+1),0,$rs)) {
+ if ($p && !defined(send L,substr($upbuf,0,$p),0,$rs)) {
warning("transmit error: $!");
} else {
if (!$upyet) {
warning("got packet from incorrect peer $rsp_from");
next;
}
+ $downbuf= "\300".$downbuf."\300";
if (!defined($r= syswrite(DW,$downbuf,length $downbuf))) {
warning("tunnel endpoint write error: $!");
} elsif ($r != length $downbuf) {
alarm($timeout) if $timeout;
}
}
+ if ($! == ECONNREFUSED) { quit("tunnel closed at remote end"); }
$! == EAGAIN || warning("receive error: $!");
}