Index: fedkit/Makefile
===================================================================
--- fedkit/Makefile	(revision b641cc7baf72a5c9437a6fb1a34e1a710529b3d9)
+++ fedkit/Makefile	(revision 2edec46a08f5778e13975de1b192598484e2ca02)
@@ -1,10 +1,15 @@
 BINARIES=federate.sh smbmount.FreeBSD.pl smbmount.Linux.pl \
 	 make_hosts fed-tun.pl fed_evrepeater rc.fedaccounts \
-	 config_from_tunnelip.pl
+	 config_from_tunnelip.pl active_config.pl combo_active.pl \
+	 prep_gateway.pl port_forward.pl setup_bridge.pl
+
+LIBRARIES=gateway_lib.pm 
 
 fedkit.tgz:	${BINARIES} ${PATCHES}
 	mkdir -p /tmp/fedkit/local/federation/bin
+	mkdir -p /tmp/fedkit/local/federation/lib
 	mkdir -p /tmp/fedkit/local/federation/etc
 	cp ${BINARIES} /tmp/fedkit/local/federation/bin
+	cp ${LIBRARIES} /tmp/fedkit/local/federation/lib
 	tar czf fedkit.tgz -C /tmp/fedkit local
 	rm -rf /tmp/fedkit
Index: fedkit/active_config.pl
===================================================================
--- fedkit/active_config.pl	(revision 2edec46a08f5778e13975de1b192598484e2ca02)
+++ fedkit/active_config.pl	(revision 2edec46a08f5778e13975de1b192598484e2ca02)
@@ -0,0 +1,56 @@
+#!/usr/bin/perl
+
+use strict;
+
+use gateway_lib;
+
+use IO::File;
+
+use Getopt::Long;
+
+my $ssh_pubkey;
+my $ssh_privkey;
+my $tunnelip;
+my $peer;
+my $fedkit_dir= "/usr/local/federation";
+my $perl = "/usr/bin/perl";
+my $iface_file;
+my $ssh = "/usr/bin/ssh";
+
+exit(20) unless GetOptions(
+    'ssh_pubkey=s' => \$ssh_pubkey,
+    'ssh_privkey=s' => \$ssh_privkey,
+    'tunnelip' => \$tunnelip,
+    'peer=s' => \$peer,
+    'fedkit=s' => \$fedkit_dir,
+    'perl=s' => \$perl,
+    'interfaces=s' => \$iface_file,
+    'ssh=s' => \$ssh,
+);
+
+
+my $tunnelparam = $tunnelip ? '--tunnelip' : '';
+
+system("$perl -I$fedkit_dir/lib $fedkit_dir/bin/prep_gateway.pl --peer=$peer " .
+    "--ssh_pubkey=$ssh_pubkey $tunnelparam");
+exit(20) if $?;
+
+my $f = new IO::File($iface_file) || die "Can't open $iface_file: $!\n";
+my $ifnum = 0;
+
+while (<$f>) {
+    /([[:alnum:]]+)\s+([\d\.]+)/ && do {
+	my ($iface, $addr) = ($1, $2);
+
+	my $cmd = "$ssh -w $ifnum:$ifnum -o \"Tunnel ethernet\" " . 
+	    "-o \"StrictHostKeyChecking no\" -i $ssh_privkey " .
+	    "$peer perl -I$fedkit_dir/lib $fedkit_dir/bin/setup_bridge.pl " .
+	    "--tapno=$ifnum --dest=$addr &";
+	system($cmd);
+	die if $?;
+	gateway_lib::bind_tap_to_iface($ifnum, $iface, $addr);
+	$ifnum++;
+    };
+}
+$f->close();
+exit(0);
Index: fedkit/combo_active.pl
===================================================================
--- fedkit/combo_active.pl	(revision 2edec46a08f5778e13975de1b192598484e2ca02)
+++ fedkit/combo_active.pl	(revision 2edec46a08f5778e13975de1b192598484e2ca02)
@@ -0,0 +1,50 @@
+#!/usr/bin/perl
+
+use strict;
+
+use gateway_lib;
+
+use IO::File;
+
+use Getopt::Long;
+
+my $ssh_pubkey;
+my $ssh_privkey;
+my $tunnelip;
+my $peer;
+my $fedkit_dir= "/usr/local/federation";
+my $perl = "/usr/bin/perl";
+my $iface_file;
+my $ssh = "/usr/bin/ssh";
+my @ports;
+
+exit(20) unless GetOptions(
+    'ssh_pubkey=s' => \$ssh_pubkey,
+    'ssh_privkey=s' => \$ssh_privkey,
+    'tunnelip' => \$tunnelip,
+    'peer=s' => \$peer,
+    'fedkit=s' => \$fedkit_dir,
+    'perl=s' => \$perl,
+    'interfaces=s' => \$iface_file,
+    'ssh=s' => \$ssh,
+    'port=s', \@ports,
+);
+
+
+my $tunnelparam = $tunnelip ? '--tunnelip' : '';
+my $portparam = join(" --port=", @ports);
+
+# join doesn't prefix the first one
+$portparam="--port=$portparam" if $portparam;
+
+system("$perl -I$fedkit_dir/lib $fedkit_dir/bin/active_config.pl " .
+    "--peer=$peer --ssh_pubkey=$ssh_pubkey --ssh_privkey=$ssh_privkey " .
+    " $tunnelparam --fedkit=$fedkit_dir --perl=$perl " .
+    "--ssh=$ssh --interfaces=$iface_file");
+exit(20) if $?;
+
+system("$perl -I$fedkit_dir/lib $fedkit_dir/bin/port_forward.pl " .
+    "--peer=$peer --ssh_pubkey=$ssh_pubkey --ssh_privkey=$ssh_privkey " .
+    " $tunnelparam --fedkit=$fedkit_dir --perl=$perl " .
+    "--ssh=$ssh $portparam");
+exit(20) if $?;
Index: fedkit/gateway_lib.pm
===================================================================
--- fedkit/gateway_lib.pm	(revision 2edec46a08f5778e13975de1b192598484e2ca02)
+++ fedkit/gateway_lib.pm	(revision 2edec46a08f5778e13975de1b192598484e2ca02)
@@ -0,0 +1,217 @@
+#!/usr/bin/perl
+
+package gateway_lib;
+
+require Exporter;
+@ISA=qw(Exporter);
+@EXPORT_OK=qw(set_sshd_params import_key wait_for_DNS deter_tunnelip 
+    configure_outgoing_iface add_route bind_tap_to_iface iface_to_addr
+    dest_to_iface addr_to_iface);
+
+use strict;
+
+use IO::File;
+use IO::Pipe;
+
+use File::Temp;
+use File::Copy;
+
+my $IFCONFIG = "/sbin/ifconfig";
+my $ROUTE = "/sbin/route";
+my $TMCC = "/usr/local/etc/emulab/tmcc";
+my $FINDIF = "/usr/local/etc/emulab/findif";
+
+sub set_sshd_params {
+    my($keys, $file) = @_;
+    my $f;
+    my $t;
+
+    $file = "/etc/ssh/sshd_config" unless $file;
+    $f = new IO::File("$file") || die "Can't read $f: $!\n";
+    $t = new File::Temp() || die "Can't open tempfile: $!\n";
+
+    while (<$f>) {
+	foreach my $k (keys %{$keys}) {
+	    s/^\s*#?\s*$k.*/$k $keys->{$k}/;
+	}
+	print $t $_;
+    }
+    $f->close();
+    $t->close();
+    copy("$file", "$file.hold");
+    copy($t->filename, $file);
+    # When $t goes out of scope, the tmpfile is deleted
+}
+
+sub import_key {
+    my($keyfile, $authkeys) = @_;
+
+    my $kf = new IO::File($keyfile) || die "Can't open $keyfile:$!\n";
+    my $ak = new IO::File(">>$authkeys") || die "Can't open $authkeys: $!\n";
+
+    while (<$kf>) {
+	print $ak $_;
+    }
+    $kf->close();
+    $ak->close();
+}
+
+
+sub wait_for_DNS {
+    my($name, $timeout) = @_;
+    my $start = time();
+    my @rv;
+
+    while (!@rv) {
+	@rv = gethostbyname($name);
+	die "Timeout waiting for DNS to get $name\n" 
+	    if ($timeout && time() - $start > $timeout);
+    }
+}
+
+sub deter_tunnelip {
+    # To parse tmcc
+    my $tmcc = new IO::Pipe || die "Can't create tmcc pipe: $!\n";
+    my $interface;		# Interface with external address
+    my $ip;			# IP address of external interface
+    my $mac;			# MAC address
+    my $netmask;		# Netmask
+    my $router;			# Router for the internet
+
+
+    # Parse out the info about tunnelips
+    $tmcc->reader("$TMCC tunnelip");
+    while (<$tmcc>) {
+	chomp;
+	/TUNNELIP=([\d\.]*)/ && do { $ip = $1; };
+	/TUNNELMASK=([\d\.]*)/ && do { $netmask = $1; };
+	/TUNNELMAC=([[:xdigit:]]*)/ && do { $mac = $1; };
+	/TUNNELROUTER=([\d\.]*)/ && do { $router = $1; };
+    }
+    $tmcc->close();
+
+    die "No MAC information for tunnel.\n" unless $mac;
+
+    # Use the emulab findif command to get the right interface to configure
+    $interface = `$FINDIF $mac`;
+    chomp $interface;
+    die "Can't get interface for mac address $mac: $?" if $? || !$interface;
+
+    return ($interface, $ip, $netmask, $mac, $router);
+}
+
+sub configure_outgoing_iface {
+    my ($interface, $ip, $netmask, $mac) = @_;
+
+    my @ifconfig = ($IFCONFIG, $interface, $ip);
+    push(@ifconfig, 'netmask', $netmask) if $netmask;
+
+    system(@ifconfig);
+    die join(" ", @ifconfig) . " failed: $!\n" if $?;
+}
+
+sub add_route {
+    my($routedest, $router, $wait, $timeout) = @_;
+    my @cmd;
+    # Linux and FreeBSD use slightly different route syntax, so get the OS
+    my $os = `uname`;
+    chomp $os;
+
+    $timeout = 0 unless $timeout;
+    die "add_host_route needs a router and a destination\n"
+	unless $router && $routedest;
+
+    wait_for_DNS($routedest, $timeout) if $wait;
+
+    if ( $os =~ /^Linux/ ) { 
+	@cmd = ($ROUTE, 'add', $routedest, 'gw', $router);
+    }
+    elsif ( $os =~ /^FreeBSD/ ) {
+	@cmd = ($ROUTE, 'add', $routedest, $router);
+    }
+    else {
+	die "Unknown OS: $os\n";
+    }
+    system(@cmd);
+    warn join(" ", @cmd) . " failed: $?\n" if $?;
+    return $?;
+}
+
+sub bind_tap_to_iface {
+    my($tapno, $iface) = @_;
+    my $bridge = "bridge$tapno";
+    my $tap = "tap$tapno";
+    my @addr = iface_to_addr($iface);
+
+    # Wait for the tap
+    system("$IFCONFIG $tap > /dev/null 2>/dev/null");
+    while ($?) {
+	system("$IFCONFIG $tap > /dev/null 2>/dev/null");
+    }
+
+    system("ifconfig $bridge create");
+    warn "Cannot create bridge: $?\n" if $?;
+    foreach my $a (@addr) {
+	system("ifconfig $iface delete $a");
+	warn "Cannot delete address $a: $?\n" if $?;
+    }
+    system("ifconfig $bridge addm $iface up");
+    warn "Cannot add intefrace $iface to bridge: $?\n" if $?;
+    system("ifconfig $bridge addm $tap");
+    warn "Cannot add intefrace $tap to bridge: $?\n" if $?;
+    return $?;
+}
+
+sub iface_to_addr {
+    my($iface) = @_;
+    my $ipipe = new IO::Pipe() || die "Can't create pipe for ifconfig: $!\n";
+    my @addr;
+
+    $ipipe->reader("$IFCONFIG $iface");
+    while(<$ipipe>) {
+	/inet\s+([0-9\.]+)/ && push(@addr, $1);
+    }
+    $ipipe->close();
+    return @addr;
+}
+
+sub dest_to_iface {
+    my($dest) =@_;
+    my $rpipe = new IO::Pipe() || die "Can't create pipe for route: $!\n";
+
+    $rpipe->reader("$ROUTE get $dest");
+    while (<$rpipe>) {
+	/interface:\s*([[:alnum:]]+)/ && do {
+	    my $iface = $1;
+	    $rpipe->close();
+	    return $iface;
+	};
+    }
+    $rpipe->close();
+
+    die "No route to $dest\n";
+}
+
+sub addr_to_iface {
+    my($addr) = @_;
+    my $ipipe = new IO::Pipe() || die "Can't create pipe for ifconfig: $!\n";
+    my $iface;
+
+    $ipipe->reader("$IFCONFIG");
+    while(<$ipipe>) {
+	/^([[:alnum:]]+):/ && do {
+	    $iface = $1;
+	    next;
+	};
+	/inet\s+([0-9\.]+)/ && do {
+	    if ($1 eq $addr) {
+		$ipipe->close();
+		return $iface;
+	    }
+	};
+    }
+    $ipipe->close();
+    die "Cannot match $addr to an interface\n";
+}
+
+1;
Index: fedkit/prep_gateway.pl
===================================================================
--- fedkit/prep_gateway.pl	(revision 2edec46a08f5778e13975de1b192598484e2ca02)
+++ fedkit/prep_gateway.pl	(revision 2edec46a08f5778e13975de1b192598484e2ca02)
@@ -0,0 +1,41 @@
+#!/usr/bin/perl
+
+use strict;
+
+use gateway_lib;
+
+use Getopt::Long;
+
+my $ssh_pubkey;
+my $tunnelip;
+my $peer;
+
+exit(20) unless GetOptions('ssh_pubkey=s' => \$ssh_pubkey,
+    'tunnelip' => \$tunnelip,
+    'peer=s' => \$peer,
+);
+
+gateway_lib::set_sshd_params( 
+    { 'GatewayPorts' => 'yes', 'PermitTunnel' => 'yes' } );
+system("/etc/rc.d/sshd restart");
+
+gateway_lib::import_key($ssh_pubkey,'/root/.ssh/authorized_keys')
+    if $ssh_pubkey;
+
+# Need these to make the Ethernet tap and bridge work.
+system("kldload /boot/kernel/bridgestp.ko") 
+    if -r "/boot/kernel/bridgestp.ko"; 
+system("kldload /boot/kernel/if_bridge.ko");
+system("kldload /boot/kernel/if_tap.ko");
+
+if ( $tunnelip ) {
+    my ($interface, $ip, $netmask, $mac, $router) = 
+	gateway_lib::deter_tunnelip();
+
+    gateway_lib::configure_outgoing_iface($interface, $ip, $netmask, $mac);
+    # Add the route to a peer.  Wait up to an hour for the peer's IP address to
+    # appear in the DNS.
+    gateway_lib::add_route($peer, $router, 1, 60 *60);
+}
+
+exit(0);
