#!/usr/local/bin/perl # -*- perl -*- # Copyright (c) 1999 by Jeff Weisberg # Author: Jeff Weisberg # Announce routes via RIPv2 # see RFC{1058,1388} use Socket; use Sys::Hostname; use Getopt::Std; srand( $$ ^ $^T ); getopts('b:c:m:np:Tv'); # -b broadcastaddr # -c configfile # -m metric # -n no forking # -p port # -T Test Mode # -v verbose # ToDo: # aggregate # get addresses, from config file or set of test addrs # addresses in file may optionally be followed by /len and/or :metric # eg. www.example.com/32:1 # NB: config file metric is ADDed to -m metric (if any) if( ! $opt_T ){ $config = $opt_c || "/etc/hosts.rip"; open(C, $config ) || die "Cannot open $config: $!\n"; @addr = ; chop @addr; close C; }else{ @addr = map { "10.1.2.$_:$_" } (1 .. 5); } # resolve addresses foreach $a ( @addr ){ print STDERR "$a " if $opt_v; $ip = cannon($a); die "cannot resolve '$a'\n" if length($ip->[0]) != 4; $a = $ip; } print STDERR "\n" if $opt_v; $proto = getprotobyname('udp'); socket(S, PF_INET, SOCK_DGRAM, $proto) || die "socket: $!"; setsockopt(S, SOL_SOCKET, SO_BROADCAST, 1); # needed for linux if( $opt_b ){ $mip = resolve($opt_b); }else{ $mip = resolve(hostname()); substr($mip, 3, 1) = "\xFF"; # XXX - magic handwaving... } print STDERR "B: ", join(".", unpack("CCCC", $mip)), "\n" if $opt_v; $sin = sockaddr_in($opt_p || 520, $mip); connect(S, $sin) || die "connect: $!\n"; $riphdr = pack("CCn", 2, 2, 0); $metric = $opt_m || 1; if( !$opt_n ){ exit if fork; # to the background, Robin! } while( 1 ){ if( $opt_n || !fork ){ while( 1 ){ $nip = 0; $rip = ''; foreach $ip ( @addr ){ $rip .= pack( "nnA4NNN", # af, rt, addr, mask, nexthop, metric 2, 0, $ip->[0], $ip->[1], 0, $ip->[2] + $metric ); if( $nip++ == 25 ){ print "sending RIP ($nip)\n" if $opt_v; send(S, $riphdr . $rip, 0) || die "send: $!\n"; $nip = 0; $rip = ''; } } if( $nip ){ print "sending RIP ($nip)\n" if $opt_v; send(S, $riphdr . $rip, 0) || die "send: $!\n"; } sleep( 25 + rand(10) ); } }else{ # process died - restart wait; print STDERR "RIP respawning\n"; } } sub cannon { my( $a ) = @_; my( $addr, $len, $metric, $ip, $mask ); ($addr, $len, $metric) = $a =~ /([^:\/]*)(?:\/(\d+))?(?::(\d+))?/; print STDERR "A:$addr L:$len M:$metric\n" if $opt_v; $ip = resolve($addr); $mask = l2m($len || 32); [ $ip, $mask, $metric || 0 ]; } sub l2m { my( $l ) = @_; my( $i, $r ); $r = 2**32 - 2**(32-$l); $r; } sub resolve { my( $a ) = @_; my( $ip, @o ); if( $a =~ /^\d+\.\d+\.\d+\.\d+$/ ){ @o = split( /\./, $a ); $ip = pack ("CCCC", @o); }else{ $ip = gethostbyname($a); if( length($ip) != 4){ sleep(1); $ip = gethostbyname($a); } } $ip; }