From ig25@mvmap66.ciw.uni-karlsruhe.de Sat Feb  1 19:01:52 1997
Received: from cygnus.com by tweedledumb.cygnus.com (4.1/4.7) id AA02068; Sat, 1 Feb 97 18:32:40 EST
Received: from tardis.ethz.ch (tardis-etz-fddi.ethz.ch [129.132.98.160]) by cygnus.com (8.6.12/8.6.9) with ESMTP id PAA04826 for <eichin@cygnus.com>; Sat, 1 Feb 1997 15:32:38 -0800
Received: (from slist@localhost) by tardis.ethz.ch (8.8.4/8.8.3) id AAA28169; Sun, 2 Feb 1997 00:28:01 +0100 (MET)
Resent-Date: Sun, 2 Feb 1997 00:28:01 +0100 (MET)
Old-Return-Path: <ig25@mvmap66.ciw.uni-karlsruhe.de>
Message-Id: <199702012327.AAA03161@mvmap66.ciw.uni-karlsruhe.de>
Subject: UDP forwarder
To: challenge@list.ee.ethz.ch (challenge)
Date: Sun, 2 Feb 1997 00:27:26 +0100 (MET)
From: Thomas Koenig <ig25@mvmap66.ciw.uni-karlsruhe.de>
Reply-To: Thomas.Koenig@ciw.uni-karlsruhe.de (Thomas =?ISO-8859-1?Q?K=F6nig?=)
X-Mailer: ELM [version 2.4ME+ PL17 (25)]
Mime-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Resent-Message-Id: <"7lebxD.A.n3G.mF98y"@tardis>
Resent-From: challenge@list.ee.ethz.ch
X-Mailing-List: <challenge@list.ee.ethz.ch> archive/latest/63
X-Loop: challenge@list.ee.ethz.ch
Precedence: list
Resent-Sender: challenge-request@list.ee.ethz.ch
Lines: 113
Xref: maneki-neko.cygnus.com mail.misc:11497

Hi, gang;

for those of you who have a whole room of machines firewalled from the
outside world, here's a UDP forwarder.

It's hacked together a bit, and makes a bit of noise about undefined
variables and void usages of gethostbyname and such, but it seems to
work otherwise.

Usage (on bastion_host):

udp_fwd 7531 kom30.ethz.ch

Then, let all the clients run with
client -e bastion_host

There may be trouble because of the finite number of sockets a single
process can have.  If you start seeing messages about "failed socket",
then you need a second machine to do more forwarding.  Bletcherous, but
the only alternative would have been using raw packets, and that
requires root privilege, plus some extra hacking that I'm not prepared
to do :-)

#! /usr/bin/perl -w

require 5.002;
use Socket;
use Sys::Hostname;

$port = $ARGV[0] or die "Need local port number!\n";
$host = $ARGV[1] or die "Need remote hostname!\n";
$proto = getprotobyname('udp') or die "Can't find protocol udp\n";
$remport = $ARGV[2] or $remport = $port;
$iaddr = gethostbyname($host) or die "Cannot find $host, aborting\n";
$paddr = sockaddr_in($remport, $iaddr);

warn "Forwarding requests to local port $port to $host, port $remport\n"; 

socket(KA, PF_INET, SOCK_DGRAM, $proto)
    or die "Can't create local socket: $\n";

bind(KA, sockaddr_in($port, INADDR_ANY))
    or die "Can't bind local socket:$!\n";

$kain = $rin = '';
vec($kain,fileno(KA),1) = 1;
$rin = $kain;

$lasttime = time;
while (1) {
    $nfound = select($rout=$rin, undef, undef, 60.);
    next if $nfound == 0;
    $nowtime = time;

    if (vec($rout, fileno(KA),1)) {
	$addr = recv ( KA,$packet, 200, 0);
        ($fport, $fiaddr) = unpack_sockaddr_in($addr);
	$name = $name{$addr} = inet_ntoa($fiaddr) . "."  .$fport;
	# print "Getting packet from $name{$addr}; filehandle: ";
	# print $filehandle{$name} if $filehandle{$name};
	if (!$filehandle{$name}) {
	    if ($lasttime{$name}) {
		next;
	    }
	    $i ++;
	    $filehandle{$name} = CHFILE . $i;
	    print "Generating new socket for $name{$addr}\n";
	    if (socket($filehandle{$name}, PF_INET, SOCK_DGRAM, $proto)) {
		if (connect($filehandle{$name}, $paddr)) {
		    $fn = fileno($filehandle{$name});
		    vec($rin, $fn,1) = 1;
		    $fromaddr{$fn} = $addr;
		    $fh{$fn} = $filehandle{$name};
		}
		else {
		    warn "Connect failed for $name{$addr}\n";
		    close($filehandle{$name});
		    undef($filehandle{$name});
		    next;
		}
	    }
	    else {
		warn "Socket failed for $name{$addr}\n";
		undef $filehandle{$name};
		next;
	    }
	}

	$lasttime{$name} = $nowtime;
	send($filehandle{$name}, $packet, 0);
	vec($rout, fileno(KA), 1) = 0;
    }
    if ($rout !~ /^\000*$/) {
	foreach $fn (keys %fromaddr) {
	    if (vec($rout, $fn, 1)) {
		recv($fh{$fn}, $packet, 200, 0);
		send(KA, $packet, 0, $fromaddr{$fn});
	    }
	}
    }

    if ($nowtime - $lasttime > 30.) {
	for (keys %filehandle) {
	    if ($nowtime - $lasttime{$_} > 3600.) {
		close($filehandle{$_});
		undef $filehandle{$_};
	    }
	}
	$lasttime = $nowtime;
    }
}



From ig25@mvmap66.ciw.uni-karlsruhe.de Sun Feb  2 00:47:50 1997
Received: from cygnus.com by tweedledumb.cygnus.com (4.1/4.7) id AA05163; Sat, 1 Feb 97 21:21:04 EST
Received: from tardis.ethz.ch (tardis-etz-fddi.ethz.ch [129.132.98.160]) by cygnus.com (8.6.12/8.6.9) with ESMTP id SAA10363 for <eichin@cygnus.com>; Sat, 1 Feb 1997 18:21:01 -0800
Received: (from slist@localhost) by tardis.ethz.ch (8.8.4/8.8.3) id DAA01839; Sun, 2 Feb 1997 03:19:53 +0100 (MET)
Resent-Date: Sun, 2 Feb 1997 03:19:53 +0100 (MET)
Old-Return-Path: <ig25@mvmap66.ciw.uni-karlsruhe.de>
Message-Id: <199702020219.DAA03519@mvmap66.ciw.uni-karlsruhe.de>
Subject: UDP forwarder
To: challenge@list.ee.ethz.ch (challenge)
Date: Sun, 2 Feb 1997 03:19:22 +0100 (MET)
From: Thomas Koenig <ig25@mvmap66.ciw.uni-karlsruhe.de>
Reply-To: Thomas.Koenig@ciw.uni-karlsruhe.de (Thomas =?ISO-8859-1?Q?K=F6nig?=)
X-Mailer: ELM [version 2.4ME+ PL17 (25)]
Mime-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Resent-Message-Id: <"fXsdeD.A.kc.ym_8y"@tardis>
Resent-From: challenge@list.ee.ethz.ch
X-Mailing-List: <challenge@list.ee.ethz.ch> archive/latest/65
X-Loop: challenge@list.ee.ethz.ch
Precedence: list
Resent-Sender: challenge-request@list.ee.ethz.ch
Lines: 64
Xref: maneki-neko.cygnus.com mail.misc:11502

Well, the version I just sent out only worked for a few hours,
then got caught up in some race condition or other.

Here's a patch.  Long live non-blocking I/O! :-)

--- udp_fwd.old	Sun Feb  2 03:17:06 1997
+++ udp_fwd	Sun Feb  2 02:57:47 1997
@@ -3,6 +3,7 @@
 require 5.002;
 use Socket;
 use Sys::Hostname;
+use Fcntl;
 
 $port = $ARGV[0] or die "Need local port number!\n";
 $host = $ARGV[1] or die "Need remote hostname!\n";
@@ -19,6 +20,8 @@
 bind(KA, sockaddr_in($port, INADDR_ANY))
     or die "Can't bind local socket:$!\n";
 
+fcntl(KA, F_SETFL, O_NONBLOCK);
+
 $kain = $rin = '';
 vec($kain,fileno(KA),1) = 1;
 $rin = $kain;
@@ -31,6 +34,7 @@
 
     if (vec($rout, fileno(KA),1)) {
 	$addr = recv ( KA,$packet, 200, 0);
+	next unless $addr;
         ($fport, $fiaddr) = unpack_sockaddr_in($addr);
 	$name = $name{$addr} = inet_ntoa($fiaddr) . "."  .$fport;
 	# print "Getting packet from $name{$addr}; filehandle: ";
@@ -48,6 +52,7 @@
 		    vec($rin, $fn,1) = 1;
 		    $fromaddr{$fn} = $addr;
 		    $fh{$fn} = $filehandle{$name};
+	            fcntl($filehandle{$name}, F_SETFL, O_NONBLOCK);
 		}
 		else {
 		    warn "Connect failed for $name{$addr}\n";
@@ -70,7 +75,8 @@
     if ($rout !~ /^\000*$/) {
 	foreach $fn (keys %fromaddr) {
 	    if (vec($rout, $fn, 1)) {
-		recv($fh{$fn}, $packet, 200, 0);
+		$val = recv($fh{$fn}, $packet, 200, 0);
+		next unless $val;
 		send(KA, $packet, 0, $fromaddr{$fn});
 	    }
 	}
@@ -81,6 +87,7 @@
 	    if ($nowtime - $lasttime{$_} > 3600.) {
 		close($filehandle{$_});
 		undef $filehandle{$_};
+		warn "Removing stale client $_\n";
 	    }
 	}
 	$lasttime = $nowtime;
-- 
Thomas Koenig, Thomas.Koenig@ciw.uni-karlsruhe.de, ig25@dkauni2.bitnet.
The joy of engineering is to find a straight line on a double
logarithmic diagram.



