Changeset 824


Ignore:
Timestamp:
12/15/20 17:28:55 (3 years ago)
Author:
Kris Deugau
Message:

/trunk

Refresh leading chunk of bind-import from bind2hosts, remove multiple
previous development comment chunks

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/bind-import

    r822 r824  
    188188                                # arguably should do some more targeted voodoo when parsing the SOA details
    189189
    190 ##fixme:  would prefer to break the loop below *AND* next; the while starting above
    191190    # check skiplist.  do this early since it's (mostly) a simple string match against the raw record line
    192191    my $skipflag = 0;
    193192    foreach (@skipdefs) {
    194 #print "skipdbg: $_ =~ $rec\n" if $rec =~ /207/;
    195193      if ($rec =~ /\Q$_\E/) {
    196194        $skipflag = 1;
    197 #        print "skip: $rec\n";
     195        # might want to do something with the skipped records someday
    198196      }
    199197    }
    200198    next if $skipflag;
    201199
    202 ##fixme:  use external skiplist
    203 #  # skip stale records that have no value
    204 #  next if /^ip-192-168-1(12|20)-\d+/;
    205 #  next if /ip.add.re.\d+\s*$/;
    206200
    207201$i++;
     
    218212        }
    219213      } elsif ($macro eq 'ORIGIN') {
    220 ##fixme:  going to skip the stupid case of "$ORIGIN com." and the like that lie
    221 # between . and the root domain we were told we're importing;  anyone using such
    222 # a mess outside the root servers is clearly insane
    223 
    224 # $ORIGIN supports cascading/nesting, by watching for fully-qualified names vs partial names.
    225 
    226 print "origin ($mdetail)\n";
     214        # $ORIGIN supports cascading/nesting, by watching for fully-qualified names vs partial names.
    227215        if ($mdetail =~ /\.$/) {
    228216          $origin = $mdetail;
     
    231219          $origin = "$mdetail.$origin";
    232220        }
    233 
    234 #      if ($mdetail eq '.' || $mdetail =~ /$zname\.$/ || $zname =~ /$mdetail\.$/) {
    235 #        $origin = $mdetail;
    236 #      } else {
    237 #        # if we continue, we either use an $ORIGIN that's out of zone, or ignore it and potentially publish incorrect records.
    238 #        die "bad \$ORIGIN: $_\n";
    239 #      }
    240 
    241221      }
    242222      elsif ($macro eq 'GENERATE') {
    243223# needs to generate CIDR range(s) as needed to match the start/stop points
    244224      }
    245     # not handling $INCLUDE or $GENERATE (altho the latter seems to be mostly a less-flexible version of the template types)
     225##fixme: should arguably handle $INCLUDE
    246226      next;
    247227    }
     
    257237    }
    258238
    259 #print "  found '$curlabel'\n";
     239    # yay for special cases
     240    $origin = '' if $origin eq '.';
     241
     242    # leading whitespace indicates "same label as last record"
     243    if ($rec =~ /^\s/) {
     244      $curlabel = $prevlabel;
     245    } else {
     246      ($curlabel) = ($rec =~ /^([\w\@_.-]+)\s/);
     247    }
    260248
    261249    # magic name!
     
    264252    # append $ORIGIN if name is not fully qualified.
    265253    if ($curlabel !~ /\.$/) {
    266       $curlabel .= ($origin eq '.' ? '.' : ".$origin");
    267     }
    268 #print "  expanded '$curlabel'\n";
    269 
    270 # hack pthbptt
    271 #$curlabel =~ s/\.\.$/./;
     254      $curlabel .= ".$origin";
     255    }
     256
    272257    # check for zone scope.  skip bad records.
    273258    if ($curlabel !~ /$zname.$/) {
     
    281266    $rec =~ s/^([\w\@_.-]*)\s+//;
    282267
    283 #  # records must begin in the first column, no leading whitespace
    284 #  my ($name) = /^([\w\@_.-]+)\s/;
    285 
    286 # foo IN A 1.2.3.4
    287 #   IN A 2.3.4.5
    288 # =
    289 # foo.zone. IN A 1.2.3.4
    290 # foo.zone. IN A 2.3.4.5
    291 
    292 #  # "empty" label records inherit the previous label
    293 #  # RRs start in the first column by definition, so leading whitespace indicates an inherited label
    294 #  if (/^\s+/) {
    295 #    # fatal error.  if there is no previous label, we can by definition not set
    296 #    # the current label based on it.  this can only happen on the very first
    297 #    # record, following records will *ALWAYS* have a previous label
    298 #    die "bad first record ($_):  no previous label\n" if !$prevlabel;
    299 #    $name = $prevlabel;
    300 #  }
    301 
    302 #print "$i ($rec)\n";#\t$curlabel";
    303 
    304 
    305 
    306 
    307 #  # append zone name to record name if missing AND not dot-terminated;
    308 #  # this happens automagically for forward zones, but not reverse because Reasons.  (fixme?)
    309 #  # suck up and deal with the error if the dot-termiated name is out of zone;  should be
    310 #  # impossible with valid BIND zone file but...
    311 #  if ($name !~ /\.$/) {
    312 #    $name .= ".$zname" if $name !~ /$zname$/;
    313 #  } else {
    314 #    warn "skipping out-of-zone record:\n\t($_)\n" if $name !~ /$zname\.$/;
    315 #    next;
    316 #  }
    317 
    318 
     268    # now that we've collected and trimmed off the record's label, unpack the class, TTL, and type.
     269    # class and TTL may be omitted, and may appear in either class,TTL or TTL,class order.
    319270    my $nc = 0;
     271    # we don't actually use these but we have to recognize them
    320272    my $class = 'IN';
     273    # not preset as we need to detect whether it's present in the record
     274    my $ttl;
    321275    my $type;
    322     my $ttl;
    323     my $distance;
    324     my $weight;
    325     my $port;
    326276    my $badrec;
    327277    my $curatom = 'class';
    328 
    329     # unpack the class, TTL, and type
    330278    eval {
    331279      for (; $nc < 3; $nc++) {
     280        last if $type;  # short-circuit if we've got a type, further data is record-specific.
    332281        my ($atom) = ($rec =~ /^([\w\d.]+)\s/);
    333282        # should be safe?
    334283        last if !$atom;
    335         last if $type;
    336 #print "nc:$nc: $atom\n";
    337284        if ($atom =~ /^\d+$/) {
    338285          if (defined($ttl)) {
     286            # we already have a TTL, so another all-numeric field is invalid.
    339287            die "bad record ($origrec)\n";
    340 #            warn "bad record ($origrec)\n";
    341 #            $badrec = 1;
    342 #            last;
    343288          } else {
    344289            if ($curatom ne 'class' && $curatom ne 'ttl') {
    345290              die "bad record ($origrec)\n";
    346 #              warn "bad record ($origrec)\n";
    347 #              $badrec = 1;
    348 #              last;
    349291            }
    350292            $curatom = 'ttl';
     
    352294          }
    353295        }
    354 
    355296        elsif ($atom =~ /^IN|CS|CH|HS$/) {
    356 #print "a$nc: d2: atom [$atom]\n        $rec\n" if $i == $debugid;
    357297          if ($atom =~ /CS|CH|HS/) {
    358298            die "unsupported class $atom in record ($origrec)\n";
    359 #            warn "unsupported class $atom in record ($origrec)\n";
    360 #            $badrec = 1;
    361 #            last;
    362299          }
    363300          $curatom = 'class';
    364301          $class = $atom;
    365302        }
    366 
    367         elsif ($atom =~ /^[A-Z]+/) {
    368 #      print "dbg: type $atom\n";
     303        elsif ($atom =~ /^[A-Z\d-]+/) {
     304          # check against dnsadmin's internal list of known DNS types.
    369305          if ($reverse_typemap{$atom}) {
    370306            $type = $atom;
     
    372308            die "unknown type $atom in record ($origrec)\n";
    373309          }
     310          $curatom = 'type';
    374311        }
    375312        $rec =~ s/^$atom\s*//;
    376313      }
    377     }; # record class/type/TTL parse
     314    }; # record class/type/TTL loop
    378315    if ($@) {
    379316      warn $@;
     
    387324#next if $badrec;
    388325
     326
     327    # Just In Case we need the original rdata after we've sliced off more pieces
     328    my $rdata = $rec;
    389329    $prevlabel = $curlabel;
    390330
    391 
    392 ## by convention the optional TTL leads the optional class, but they're apparently swappable.
    393 #  my ($ttl) = /^(\d+)?\s/;
    394 #  if (defined $ttl) {
    395 #    # TTL may be zero
    396 #    s/(\d+)?\s+//;
    397 #  } else {
    398 #    # Fall back to zone default TTL
    399 #    $ttl = $zonettl;
    400 #  }
    401 #  my ($class) = /^(IN|CS|CH|HS|\d+)\s/;
    402 #  if (defined $class) {
    403 #    if ($class =~ /\d+/) {
    404 #     
    405 #    }
    406 #    if ($class ne 'IN') {
    407 #      warn "Non-Internet class ($class) records not supported:\n\t$origrec\n";
    408 #      next;
    409 #    }
    410 #    s/(IN|CS|CH|HS)\s+//;
    411 #  } else {
    412 #    $class = 'IN';
    413 #  }
    414 #  my ($type) = /([A-Z-]+)\s/;
    415 #  if (!$reverse_typemap{$type}) {
    416 #    warn "Unknown type $type, skipping\n\t($rec)\n";
    417 #    next;
    418 #  }
    419 #  s/([A-Z-]+)\s+//;
    420 #  chomp;
    421 
     331    # part of the record data, when present
     332    my $distance;
     333    my $weight;
     334    my $port;
    422335
    423336    my $itype = $reverse_typemap{$type};
    424     my $rdata = $rec;
    425 
    426   # SOA is the only type that may span multiple lines.  Probably.  Note even AXFRed zones write multiline SOA records:
    427   #@       IN      SOA     test.example.invalid.   test.example.invalid.   (2020082500 7200 900 604800 3600)
    428   #        IN      NS      olddns.example.com.
    429   #        IN      MX      1 fred.foo.bar.invalid.
    430   #foo     IN      A       192.168.16.45
    431   # AXFR'ed zone file gets written as
    432   #$ORIGIN .
    433   #$TTL 3600       ; 1 hour
    434   #example.invalid         IN SOA  test.example.invalid. test.example.invalid. (
    435   #                                2020082500 ; serial
    436   #                                7200       ; refresh (2 hours)
    437   #                                900        ; retry (15 minutes)
    438   #                                604800     ; expire (1 week)
    439   #                                3600       ; minimum (1 hour)
    440   #                                )
    441   #                        NS      olddns.example.com.
    442   #                        MX      1 fred.foo.bar.invalid.
    443   #$ORIGIN example.invalid.
    444   #foo                     A       192.168.16.45
    445   $foundtypes{$type}++;
     337
     338
     339# See RFC1035 and successors for the canonical zone file format reference.  We'll
     340# ignore a number of edge cases because they're quite horrible to parse.
     341# Of particular note is use of () to continue entries across multiple lines.  Use
     342# outside of SOA records is quite rare, although some compliant zone file
     343# *writers* may use it on TXT records.
     344# We'll also ignore the strict interpretation in SOA records in favour of spotting
     345# the more standard pattern where the SOA serial, refresh, retry, expire, and minttl
     346# numbers are in ():
     347
     348#example.invalid         IN SOA  test.example.invalid. test.example.invalid. (
     349#                                2020082500 ; serial
     350#                                7200       ; refresh (2 hours)
     351#                                900        ; retry (15 minutes)
     352#                                604800     ; expire (1 week)
     353#                                3600       ; minimum (1 hour)
     354#                                )
     355
     356    $foundtypes{$type}++;
    446357
    447358##fixme:  strip trailing . here?  dnsadmin's normalized internal format omits it, some validation fails or may go funky
     
    451362      die "Can't parse gibberish SOAish record: $rec\n" if !$ns;
    452363      $rdata =~ s/([\w.]+)\s+([\w.]+)\s+\(\s*//;
    453 
    454       # There are probably more efficient ways to do this but the SOA record
    455       # format is essentially character based, not line-based.
    456       # In theory the SOA serial etc may be spread over up to 5 lines, in any combination.
    457364
    458365      # Parse fields from $rdata if present
     
    488395        $dnsdb->{dbh}->do("INSERT INTO records (domain_id,host,type,val,ttl,location) VALUES (?,?,?,?,?,?)", undef, @soavals);
    489396      }
    490 #  $dnsdb->{dbh}->do("INSERT INTO records () VALUES ()");
    491 #  next;
    492 #Zfqdn:mname:rname:ser:ref:ret:exp:min:ttl:timestamp:lo
    493 #print "Z$zname:$ns:$adminmail:$soabits[0]:$soabits[1]:$soabits[2]:$soabits[3]:$soabits[4]:$ttl\n";
    494397      # skip insert at end of loop;  SOA records are not handled by DNSDB::addRec()
    495398      next;
Note: See TracChangeset for help on using the changeset viewer.