Changeset 807


Ignore:
Timestamp:
11/24/20 14:00:26 (4 years ago)
Author:
Kris Deugau
Message:

/trunk

Commit work in progress to bind2hosts

  • incremental improvement in CNAME chain following
  • clean up some debugging glop
  • add some structure to possibly allow setting CNAME chain depth as an argument
  • refine record type capture Just In Case
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/bind2hosts

    r806 r807  
    3333my $skipfile;
    3434my $dryrun = 0;
     35# CNAME chain depth
     36my $maxdepth = 3;
    3537
    3638GetOptions(
     
    5052                octet-reversed form.  Specify multiple times to skip multiple
    5153                different record patterns.
    52         --skip-file
     54        --skipfile
    5355                A file containing patterns to skip.  Patterns from the file and
    5456                any --skip arguments are merged.
     
    8486my $dnsdb = new DNSDB;
    8587
    86 ##fixme:  retrieve defttl from SOA record
    87 #my $zonettl = 900;
    88 #my $defttl = $zonettl;
    8988# need an ultimate fallback for this one
    9089my $defttl = 900;
     
    101100  next if $rec =~ /^\s*;/;
    102101  next if $rec =~ /^\s*\)/;     # SOA closing (possibly other records too?)
    103                         # arguably should do some more targeted voodoo when parsing the SOA details
    104 #print "$i: ($rec)\n";
    105 #last if ++$i > 5;
     102                                # arguably should do some more targeted voodoo when parsing the SOA details
    106103
    107104  my $skipflag = 0;
    108105  foreach (@skipdefs) {
    109 #print "skipdbg: $_ =~ $rec\n" if $rec =~ /207/;
    110106    if ($rec =~ /\Q$_\E/) {
    111107      $skipflag = 1;
    112 #      print "skip: $rec\n";
     108      # might want to do something with the skipped records someday
    113109    }
    114110  }
     
    138134  my $origrec = $rec;
    139135
    140 ##fixme:  convert to optional skipfile?
    141 # skip stale records that have no value
    142 #next if /^ip-\d+-\d+-\d+/;
    143 #next if /^ip.pre.fix.\d+.static.colo/;
    144 
    145136  # leading whitespace indicates "same label as last record"
    146137  if ($rec =~ /^\s/) {
     
    167158  $rec =~ s/^([\w\@_.-]*)\s+//;
    168159
     160  # now that we've collected and trimmed off the record's label, unpack the class, TTL, and type.
     161  # class and TTL may be omitted, and may appear in either class,TTL or TTL,class order.
    169162  my $nc = 0;
    170163  my %seenatoms;
     
    176169  my $badrec;
    177170  my $curatom = 'class';
    178 
    179   # now that we've collected and trimmed off the record's label, unpack the class, TTL, and type.
    180   # class and TTL may be omitted, and may appear in either class,TTL or TTL,class order.
    181171  eval {
    182172    for (; $nc < 3; $nc++) {
     
    204194        $class = $atom;
    205195      }
    206       elsif ($atom =~ /^[A-Z]+/) {
     196      elsif ($atom =~ /^[A-Z\d-]+/) {
    207197        # check against dnsadmin's internal list of known DNS types.
    208198        if ($reverse_typemap{$atom}) {
     
    221211  }
    222212
    223 
    224213  $ttl = $defttl if !defined($ttl);
    225214
    226   my $itype = $reverse_typemap{$type};
     215  # Just In Case we need the original rdata after we've sliced off more pieces
    227216  my $rdata = $rec;
    228 
    229217  $prevlabel = $curlabel;
    230218
     
    237225    # There are probably more efficient ways to do this but the SOA record
    238226    # format is essentially character based, not line-based.
    239     # In theory the SOA serial etc may be spread over up to 5 lines, in any combination.
     227    # In theory the SOA serial etc may be spread over "many" lines, bounded by ().
    240228
    241229    # Parse fields from $rdata if present
     
    266254  elsif ($type eq 'A') {
    267255    # need the name->IP map so we can reverse-map the CNAMEs on output
    268 #    $amap{$curlabel}{$rdata}++;
    269256    push @{$amap{$curlabel}}, $rdata;
    270 # why doesn't this work?  causes ALL cases of multi-named IPs to get skipped, not just duplicates.  O_o
    271 #    push @{$namemap{$rdata}}, $curlabel unless grep $curlabel, @{$namemap{$rdata}};
    272 #    push @{$namemap{$rdata}}, $curlabel;# unless grep $curlabel, @{$namemap{$rdata}};
    273257    $namemap{$rdata}{$curlabel}++;
    274 
    275258  } # A record
    276259
    277260  elsif ($type eq 'CNAME') {
    278 ##todo:  expand $rdata with $origin if unqualified
    279261    $cmap{$curlabel} = $rdata.($rdata =~ /\./ ? '' : ".$origin");
    280262  } # CNAME record
     
    284266} # <STDIN>
    285267
    286 
    287 
    288 
    289268#print Dumper \%cmap;
    290269
    291 while (my ($cn, $targ) = each %cmap) {
     270# Walk the CNAME list and see if we can match the targets in-zone.
     271# Out-of-zone CNAMEs are out of scope for this conversion.
     272foreach my $cn (sort keys %cmap) {
     273  my $targ = $cmap{$cn};
    292274#print "dbg: ".Dumper($targ);
    293   if (!$amap{$targ}) {
    294     if ($cmap{$targ}) {
    295 warn "chained cname $cn => $targ\n";
    296       my $tmpcn = $targ;
    297       $targ = $cmap{$tmpcn};
    298 warn "  chain target $cn => $tmpcn => $targ\n";
    299 #      next if !$amap{$targ};
    300       if (!$amap{$targ}) {
    301         if ($cmap{$targ}) {
    302 #print "  second chain?\n";
    303           $tmpcn = $targ;
    304           $targ = $cmap{$tmpcn};
    305         } else {
    306 #print "not found\n";
    307 next;
    308         }
    309       }
    310     } else {
    311       # skip depth-3 (?) CNAMES;  any such zone does not belong as a hosts file anyway
    312       warn "CNAME $cn => $targ not found\n";
    313       next;
    314     }
    315   }
    316 #  print Dumper (\%{$amap{$cmap{$cn}}});
    317 #  print "$cn -> $cmap{$cn}\n";
    318 #  $amap{$cmap{$cn}}{$cn}++ if $cmap{$cn} =~ /$zname.$/ && $amap{$cmap{$cn}};
    319 #  print "dangling CNAME $cn\n" if !$namemap{$cmap{$cn}};
    320 #  print "$cn -> $cmap{$cn}\n";
    321 #  warn "CNAME $cn out of zone\n" if !$namemap{$cn};
    322   my $targip = $amap{$targ}[0];
    323 #print "$cn => $targ\n" if $targ =~ /(webftp|landing)/;
    324 #print $targip;
    325 #  push @{$namemap{$targip}}, $targ unless grep $targ, @{$namemap{$targip}};
    326   $namemap{$targip}{$cn}++;# unless grep $targ, @{$namemap{$targip}};
    327 }
     275  my @targlist;
     276#  push @targlist, $targ;  # mostly for error reporting
     277my $dangle = 0;
     278
     279my $depth = 1;  # CNAME -> A
     280
     281# check this as a loop for consistent fail/break conditions.  bonus:  may allow user choice for CNAME depth?
     282  for (; $dangle == 0; $depth++) {
     283
     284#print "d:$depth  checking $cn -> $targ\n";
     285push @targlist, $targ;
     286
     287  # Depth limit.  If made user-selectable should arguably set a hard
     288  # limit because deeply chained CNAMEs are Baaaaad, mmkaay?
     289  if ($depth >= $maxdepth) {
     290    warn "CNAMEs too deeply chained, skipping: $cn => ".join(' => ', @targlist)."\n";
     291    last;
     292  }
     293
     294# break if CNAME target is in the A record list
     295  last if $amap{$targ};
     296  if ($cmap{$targ}) {
     297#     note the new target
     298    my $tmpcn = $targ;
     299    $targ = $cmap{$tmpcn};
     300#print "    chaining $tmpcn to new $targ\n";
     301  } else {
     302#     target is either out of zone or doesn't exist
     303    $dangle = 1;
     304    last;
     305  }
     306
     307
     308#warn "chained cname $cn => $targ\n";
     309    # CNAME to another CNAME
     310#$tmpcn => $targ\n";
     311
     312#  last if $dangle;
     313
     314#      if (!$amap{$targ}) {
     315#        if ($cmap{$targ}) {
     316#          $tmpcn = $targ;
     317#          $targ = $cmap{$tmpcn};
     318#push @targlist, $targ;
     319#warn "  chain target $cn => ".join(' => ', @targlist).
     320#       "\n";
     321#        } else {
     322#          warn "skipping dangling CNAME $cn => $targlist[0] => $targlist[1]\n";
     323#          next;
     324#        }
     325#      }
     326#    } else {
     327#      # skip depth-3 (?) CNAMES;  any such zone does not belong as a hosts file anyway
     328#      warn "skipping dangling CNAME $cn => $targ\n";
     329#      next;
     330#    }
     331#  }
     332
     333
     334  } # CNAME recursion loop
     335
     336next if $dangle;
     337
     338#print "    chain target $cn => ".join(' => ', @targlist)."\n";
     339  if ($amap{$targ}) {
     340    # absent any criteria, we use the first IP a name was associated with
     341    my $targip = $amap{$targ}[0];
     342    $namemap{$targip}{$cn}++;
     343  } else {
     344  }
     345} # each %cmap
    328346
    329347#print Dumper \%amap;
Note: See TracChangeset for help on using the changeset viewer.