#!/usr/local/bin/perl # # cisco config -> DNS interface names # # # -e xref with DNS server and report errors # -g generate full forward and reverse tables # -f use different config file # -v strip off vlan interface # # # maf@net.ohio-state.edu Jan '97 # # BUGS/TODO # optionally output in interface.router format require "getopts.pl"; &Getopts("ef:gnv"); $CFG = ($opt_f ne '') ? $opt_f : "ifdns.cfg"; # # condition the resolver # $ENV{'RESOLV_SERV_ORDER'} = 'bind'; $ENV{'RESOLV_SPOOF_CHECK'} = 'off'; # # read our configuration file # open (CFG, "<$CFG") || die "Can't open $CFG\n"; while () { chomp; # ignore comments and blank lines next if /^#/; next if /^$/; @field = split; # top level if ($field[0] =~ /^top/) { $field[1] = '.' . $field[1] if (!($field[1] =~ /^\./) && ($field[1] ne '')); $TOP = $field[1]; next; } # router POP if ($field[0] =~ /^rpop/) { $field[2] = '.' . $field[2] if (!($field[2] =~ /^\./) && ($field[2] ne '')); $RPOP{$field[1]} = "$field[2]"; next; } # interface abbreviation if ($field[0] =~ /^ifshort/) { $field[1] =~ tr [A-Z] [a-z]; $IFSHORT{$field[1]} = "$field[2]"; next; } # interfaces that need special top level suffix if ($field[0] =~ /^ifspectop/) { $field[2] = '.' . $field[2] if (!($field[2] =~ /^\./) && ($field[2] ne '')); $IFSPECTOP{$field[1]} = "$field[2]"; next; } # interfaces that need special POP if ($field[0] =~ /^ifspecpop/) { $field[2] = '.' . $field[2] if (!($field[2] =~ /^\./) && ($field[2] ne '')); $IFSPECPOP{$field[1]} = "$field[2]"; next; } # interfaces that need special rewrite if ($field[0] =~ /^ifrewrite/) { $IFREWRITE{$field[1]} = "$field[2]"; next; } print STDERR "can't parse line: $_\n"; exit (1); } close CFG; # # IP multiplier table # @MUL = (16777216, 65536, 256, 1); # # create a list of possible domain suffixes # $IFSPECTOP{"foobar"} = $TOP; foreach $name (keys(%IFSPECTOP)) { foreach $name2 (keys(%IFSPECPOP)) { $DOMAINS{"$IFSPECTOP{$name}$IFSPECPOP{$name2}"} = 1; } foreach $name2 (keys(%RPOP)) { $DOMAINS{"$RPOP{$name2}$IFSPECTOP{$name}"} = 1; } } ############################################################################## foreach $name (keys(%domains)) { print "domain = $name\n"; } # # read the cisco configuration # while (<>) { if (/^hostname/) { # # hostname router # $hostname = (split)[1]; $pop = $RPOP{"$hostname"}; next; } # hostname if (/^interface/) { # # interface Ethernet0 # No IP # interface Ethernet0/0 # IP # interface Ethernet0/0/0 # VIP # interface ATM0/0.1 # IP w. sub interface # interface Serial8/1:23 # IP w. channels # interface loopback 0 # undistilled config # no addresses defined for this interface yet undef @ifaddr_list; undef @ifaddr_list2; $iflong = join ('', (split)[1..99]); $iflong =~ s/multipoint//; $iflong =~ s/point-to-point//; $rest = $iflong; # strip everything before the first #, this is the first field $rest =~ s/^[a-zA-Z]*//; # strip everything after the first #, this is the long name $iflong =~ s/[0-9]+.*//; $iflong =~ tr [A-Z] [a-z]; # convert long name to abbreviated short name if (($ifshort = $IFSHORT{"$iflong"}) eq "") { die "No short name interface defined for $iflong\n"; } # slashes to dashes. @nums = split('/', $rest); # the last field may have a . or :. Change it to a s or c. @nums[@nums-1] =~ s/\./s/; @nums[@nums-1] =~ s/\:/c/; $ifname = "$hostname-$ifshort" . join ("-", @nums); $ifname = $hostname if ($opt_v && ($iflong eq "vlan")); if (defined $IFSPECPOP{"$ifname"}) { $ifpop = $IFSPECPOP{"$ifname"}; } else { $ifpop = $pop; } if (defined $IFSPECTOP{"$ifname"}) { $iftop = $IFSPECTOP{"$ifname"}; } else { $iftop = $TOP; } next; } # interface if (/^ *ip address/) { # # ip address 128.146.222.1 255.255.255.0 # or # ip address 128.146.222.1 255.255.255.0 secondary # $ip = (split)[2]; $secondary = (split)[4]; # if generating a nocol config file, don't bother # with the secondary addresses next if ($secondary && $opt_n); # special rewritten interfaces $iftmp = ($IFREWRITE{"$ifname$ifpop$iftop"} eq '') ? "$ifname$ifpop$iftop" : $IFREWRITE{"$ifname$ifpop$iftop"}; $dnsmap{"$ip"} = $iftmp; $dnsmap3{"$ip"} = "$ifname"; # create decimal entries for easy sorting @parts = split (/\./, $ip); for ($x = 0, $total = 0; $x <= $#parts; ++$x) { $total += $parts[$x] * $MUL[$x] } $dnsmap2{"$total"} = $ip; # keep track of what ip addresses are on the current interface push (@ifaddr_list, $ip); push (@ifaddr_list2, $total); next; } # ip address if (/^ shutdown/) { # # shutdown # foreach $name (@ifaddr_list) { delete $dnsmap{"$name"}; } foreach $name (@ifaddr_list2) { delete $dnsmap2{"$name"}; } next; } # shutdown } # while (<>) ############################################################################## # # option g, generate forward and reverse tables # ############################################################################## if ($opt_g) { # # sort by IP address and output reverse tables # $olddomain = ''; foreach $name (sort bynum keys(%dnsmap2)) { # # assume all delegations on /24 boundries for easy cut and pasting # # split ip address into a.b.c and d @parts = split (/\./, $dnsmap2{$name}); $lo = pop (@parts); $curdomain = join ('.', @parts); # if this is a new /24, print a small header if ($curdomain ne $olddomain) { print " ; ; $curdomain.0 ;\n\n"; $olddomain = $curdomain; } # the DNS RR print "$lo\tIN\tPTR\t$dnsmap{$dnsmap2{$name}}.\n"; } # # sort by IP address, then by domain, and output forward tables # $olddomain = ''; $oldaddr = ''; foreach $domain (sort keys(%DOMAINS)) { foreach $name (sort bynum keys(%dnsmap2)) { # split fqdn into hostname and domainname $curdomain = $dnsmap{$dnsmap2{$name}}; @parts = split (/\./, $curdomain); $hostname = shift (@parts); $curdomain = '.' . join ('.', @parts); # skip if not this domain next if ($curdomain ne $domain); # if this is a new domainname, print a small header if ($curdomain ne $olddomain) { print " ; ; $curdomain ;\n\n"; $olddomain = $curdomain; } # split ip address into a.b.c and d @parts = split (/\./, $dnsmap2{$name}); pop (@parts); $curaddr = join ('.', @parts); # if this is a new /24, print a small header if ($curaddr ne $oldaddr) { print " ; ; $curaddr.0 ;\n\n"; $oldaddr = $curaddr; } # the DNS RR print "$hostname\tIN\tA\t$dnsmap2{$name}\n"; } # name } # domain exit 0; } # opt_g ############################################################################## # # option e, xfef with nameserver # ############################################################################## if ($opt_e) { # create a hostname/iplist map foreach $name (keys(%dnsmap2)) { $ip = $dnsmap2{$name}; $fqdn = $dnsmap{$ip}; $dnsmap4{$fqdn} .= "$ip "; } foreach $name (sort bynum keys(%dnsmap2)) { $ip = $dnsmap2{$name}; $fqdn = $dnsmap{$ip}; @octets = split (/\./, $ip); $x = pack('C4', $octets[0], $octets[1], $octets[2], $octets[3]); ($hostname,$aliases,$type,$len,@addrs) = gethostbyaddr($x, 2); if ($hostname ne $fqdn) { print "REV CHANGE $ip TO $fqdn\n"; } } foreach $fqdn (keys(%dnsmap4)) { @correct_addrs = split (/ /, $dnsmap4{$fqdn}); ($hostname, $aliases, $type, $len, @addrs) = gethostbyname($fqdn); undef @iplist; foreach $addr (@addrs) { push (@iplist, join ('.', unpack ('C4', $addr))); } # if the list of correct addresses lists an address that # was not in DNS, flag to add it foreach $addr (@correct_addrs) { $foundit = 0; foreach $addr2 (@iplist) { if ($addr2 eq $addr) { $foundit = 1; last; } } if (!$foundit) { print "FWD ADD $fqdn $addr\n"; } } # if the list of addresses returned by DNS has an entry # that is not in correct_addrs, flag to delete foreach $addr (@iplist) { $foundit = 0; foreach $addr2 (@correct_addrs) { if ($addr2 eq $addr) { $foundit = 1; last; } } if (!$foundit) { print "FWD DELETE $fqdn $addr\n"; } } } # name } # opt_e ############################################################################## # # option n, generate nocol ipnodes file # ############################################################################## if ($opt_n) { foreach $name (sort bynum keys(%dnsmap2)) { $ip = $dnsmap2{$name}; $hostname = $dnsmap3{$dnsmap2{$name}}; print " $hostname\t$ip\n"; } # name exit 0; } # opt_n ############################################################################## # # sort by number # sub bynum { $a <=> $b; }