source: fedkit/gateway_lib.pm @ 2edec46

axis_examplecompt_changesinfo-opsversion-3.01version-3.02
Last change on this file since 2edec46 was 2edec46, checked in by Ted Faber <faber@…>, 14 years ago

Factored gateway implementation. Initial import.

  • Property mode set to 100644
File size: 5.1 KB
Line 
1#!/usr/bin/perl
2
3package gateway_lib;
4
5require Exporter;
6@ISA=qw(Exporter);
7@EXPORT_OK=qw(set_sshd_params import_key wait_for_DNS deter_tunnelip
8    configure_outgoing_iface add_route bind_tap_to_iface iface_to_addr
9    dest_to_iface addr_to_iface);
10
11use strict;
12
13use IO::File;
14use IO::Pipe;
15
16use File::Temp;
17use File::Copy;
18
19my $IFCONFIG = "/sbin/ifconfig";
20my $ROUTE = "/sbin/route";
21my $TMCC = "/usr/local/etc/emulab/tmcc";
22my $FINDIF = "/usr/local/etc/emulab/findif";
23
24sub set_sshd_params {
25    my($keys, $file) = @_;
26    my $f;
27    my $t;
28
29    $file = "/etc/ssh/sshd_config" unless $file;
30    $f = new IO::File("$file") || die "Can't read $f: $!\n";
31    $t = new File::Temp() || die "Can't open tempfile: $!\n";
32
33    while (<$f>) {
34        foreach my $k (keys %{$keys}) {
35            s/^\s*#?\s*$k.*/$k $keys->{$k}/;
36        }
37        print $t $_;
38    }
39    $f->close();
40    $t->close();
41    copy("$file", "$file.hold");
42    copy($t->filename, $file);
43    # When $t goes out of scope, the tmpfile is deleted
44}
45
46sub import_key {
47    my($keyfile, $authkeys) = @_;
48
49    my $kf = new IO::File($keyfile) || die "Can't open $keyfile:$!\n";
50    my $ak = new IO::File(">>$authkeys") || die "Can't open $authkeys: $!\n";
51
52    while (<$kf>) {
53        print $ak $_;
54    }
55    $kf->close();
56    $ak->close();
57}
58
59
60sub wait_for_DNS {
61    my($name, $timeout) = @_;
62    my $start = time();
63    my @rv;
64
65    while (!@rv) {
66        @rv = gethostbyname($name);
67        die "Timeout waiting for DNS to get $name\n" 
68            if ($timeout && time() - $start > $timeout);
69    }
70}
71
72sub deter_tunnelip {
73    # To parse tmcc
74    my $tmcc = new IO::Pipe || die "Can't create tmcc pipe: $!\n";
75    my $interface;              # Interface with external address
76    my $ip;                     # IP address of external interface
77    my $mac;                    # MAC address
78    my $netmask;                # Netmask
79    my $router;                 # Router for the internet
80
81
82    # Parse out the info about tunnelips
83    $tmcc->reader("$TMCC tunnelip");
84    while (<$tmcc>) {
85        chomp;
86        /TUNNELIP=([\d\.]*)/ && do { $ip = $1; };
87        /TUNNELMASK=([\d\.]*)/ && do { $netmask = $1; };
88        /TUNNELMAC=([[:xdigit:]]*)/ && do { $mac = $1; };
89        /TUNNELROUTER=([\d\.]*)/ && do { $router = $1; };
90    }
91    $tmcc->close();
92
93    die "No MAC information for tunnel.\n" unless $mac;
94
95    # Use the emulab findif command to get the right interface to configure
96    $interface = `$FINDIF $mac`;
97    chomp $interface;
98    die "Can't get interface for mac address $mac: $?" if $? || !$interface;
99
100    return ($interface, $ip, $netmask, $mac, $router);
101}
102
103sub configure_outgoing_iface {
104    my ($interface, $ip, $netmask, $mac) = @_;
105
106    my @ifconfig = ($IFCONFIG, $interface, $ip);
107    push(@ifconfig, 'netmask', $netmask) if $netmask;
108
109    system(@ifconfig);
110    die join(" ", @ifconfig) . " failed: $!\n" if $?;
111}
112
113sub add_route {
114    my($routedest, $router, $wait, $timeout) = @_;
115    my @cmd;
116    # Linux and FreeBSD use slightly different route syntax, so get the OS
117    my $os = `uname`;
118    chomp $os;
119
120    $timeout = 0 unless $timeout;
121    die "add_host_route needs a router and a destination\n"
122        unless $router && $routedest;
123
124    wait_for_DNS($routedest, $timeout) if $wait;
125
126    if ( $os =~ /^Linux/ ) { 
127        @cmd = ($ROUTE, 'add', $routedest, 'gw', $router);
128    }
129    elsif ( $os =~ /^FreeBSD/ ) {
130        @cmd = ($ROUTE, 'add', $routedest, $router);
131    }
132    else {
133        die "Unknown OS: $os\n";
134    }
135    system(@cmd);
136    warn join(" ", @cmd) . " failed: $?\n" if $?;
137    return $?;
138}
139
140sub bind_tap_to_iface {
141    my($tapno, $iface) = @_;
142    my $bridge = "bridge$tapno";
143    my $tap = "tap$tapno";
144    my @addr = iface_to_addr($iface);
145
146    # Wait for the tap
147    system("$IFCONFIG $tap > /dev/null 2>/dev/null");
148    while ($?) {
149        system("$IFCONFIG $tap > /dev/null 2>/dev/null");
150    }
151
152    system("ifconfig $bridge create");
153    warn "Cannot create bridge: $?\n" if $?;
154    foreach my $a (@addr) {
155        system("ifconfig $iface delete $a");
156        warn "Cannot delete address $a: $?\n" if $?;
157    }
158    system("ifconfig $bridge addm $iface up");
159    warn "Cannot add intefrace $iface to bridge: $?\n" if $?;
160    system("ifconfig $bridge addm $tap");
161    warn "Cannot add intefrace $tap to bridge: $?\n" if $?;
162    return $?;
163}
164
165sub iface_to_addr {
166    my($iface) = @_;
167    my $ipipe = new IO::Pipe() || die "Can't create pipe for ifconfig: $!\n";
168    my @addr;
169
170    $ipipe->reader("$IFCONFIG $iface");
171    while(<$ipipe>) {
172        /inet\s+([0-9\.]+)/ && push(@addr, $1);
173    }
174    $ipipe->close();
175    return @addr;
176}
177
178sub dest_to_iface {
179    my($dest) =@_;
180    my $rpipe = new IO::Pipe() || die "Can't create pipe for route: $!\n";
181
182    $rpipe->reader("$ROUTE get $dest");
183    while (<$rpipe>) {
184        /interface:\s*([[:alnum:]]+)/ && do {
185            my $iface = $1;
186            $rpipe->close();
187            return $iface;
188        };
189    }
190    $rpipe->close();
191
192    die "No route to $dest\n";
193}
194
195sub addr_to_iface {
196    my($addr) = @_;
197    my $ipipe = new IO::Pipe() || die "Can't create pipe for ifconfig: $!\n";
198    my $iface;
199
200    $ipipe->reader("$IFCONFIG");
201    while(<$ipipe>) {
202        /^([[:alnum:]]+):/ && do {
203            $iface = $1;
204            next;
205        };
206        /inet\s+([0-9\.]+)/ && do {
207            if ($1 eq $addr) {
208                $ipipe->close();
209                return $iface;
210            }
211        };
212    }
213    $ipipe->close();
214    die "Cannot match $addr to an interface\n";
215}
216
2171;
Note: See TracBrowser for help on using the repository browser.