Changeset 232 for trunk


Ignore:
Timestamp:
02/13/12 17:56:18 (13 years ago)
Author:
Kris Deugau
Message:

/trunk

Checkpoint - almost done PTR, A/AAAA+PTR types. Still need to
figure out validation on default-record inputs.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/DNSDB.pm

    r231 r232  
    174174  my $addr = shift;
    175175
     176  return if $revrec ne 'y';     # this sub not useful in forward zones
     177
     178  $$addr = NetAddr::IP->new($$val);      #necessary?
     179
    176180  # subsub to split, reverse, and overlay an IP fragment on a netblock
    177181  sub __rev_overlay {
     
    183187    my $joinme = $splitme;
    184188    $splitme = '\.' if $splitme eq '.';
    185     my @working = reverse(split($splitme, $parnet->addr)) or warn $!;
    186     my @parts = reverse(split($splitme, $val));
     189    my @working = reverse(split($splitme, $parnet->addr));
     190    my @parts = reverse(split($splitme, $$val));
    187191    for (my $i = 0; $i <= $#parts; $i++) {
    188192      $working[$i] = $parts[$i];
    189193    }
    190     my $checkme = NetAddr::IP->new(join($joinme, reverse(@working))) or return;
    191     return unless $checkme->within($parnet);
     194    my $checkme = NetAddr::IP->new(join($joinme, reverse(@working))) or return 0;
     195    return 0 unless $checkme->within($parnet);
    192196    $$addr = $checkme;  # force "correct" IP to be recorded.
    193197    return 1;
     
    198202
    199203  # Fail early on v6-in-v4 or v4-in-v6.  We're not accepting these ATM.
    200   return if $parnet->addr =~ /\./ && $val =~ /:/;
    201   return if $parnet->addr =~ /:/ && $val =~ /\./;
    202 
    203   # Arguably this is incorrect, but...
    204   if ($val =~ /^::/) {
    205     $val =~ s/^:+//;     # gotta strip'em all...
    206     return __rev_overlay(':', $parnet, $val, $addr);
    207   }
    208   if ($val =~ /^\./) {
    209     $val =~ s/^\.+//;
    210     return __rev_overlay('.', $parnet, $val, $addr);
    211   }
    212 
    213   if ($revrec eq 'y') {
    214     if ($$addr && !$$addr->{isv6}) {
    215       # argh.  12.1 == 12.0.0.1  (WTF?)
    216       # so we do this The Hard Way, because of the stupid
    217       if ($val =~ /^(?:\d{1,3}\.){3}\d{1,3}$/) {
    218         # we really have a real IP.
    219         return $dbh->selectrow_array("SELECT count(*) FROM revzones WHERE revnet >> ?", undef, ($val));
    220       } else {
    221         return __rev_overlay('.', $parnet, $val, $addr);
    222       }
    223     } elsif ($$addr && $$addr->{isv6}) {
    224       # real v6 address.
    225       return $dbh->selectrow_array("SELECT count(*) FROM revzones WHERE revnet >> ?", undef, ($val));
    226     } else {
    227       # v6 tail
     204  return 0 if $parnet->addr =~ /\./ && $$val =~ /:/;
     205  return 0 if $parnet->addr =~ /:/ && $$val =~ /\./;
     206
     207  if ($$addr && $$val =~ /^\d[\d:]+\d$/) {
     208    # the only case where NetAddr::IP's acceptance of legitimate IPs is "correct" is for a proper IPv6 address.
     209    # the rest we have to restructure before fiddling.  *sigh*
     210    return 1 if $$addr->within($parnet);
     211  } else {
     212    # We don't have a complete IP in $$val (yet)
     213    if ($parnet->addr =~ /:/) {
     214      $$val =~ s/^:+//;  # gotta strip'em all...
    228215      return __rev_overlay(':', $parnet, $val, $addr);
     216    }
     217    if ($parnet->addr =~ /\./) {
     218      $$val =~ s/^\.+//;
     219      return __rev_overlay('.', $parnet, $val, $addr);
    229220    }
    230221    # should be impossible to get here...
     
    234225} # end _ipparent()
    235226
     227# A little different than _ipparent above;  this tries to *find* the parent zone of a hostname
     228sub _hostparent {
     229  my $dbh = shift;
     230  my $hname = shift;
     231 
     232  my @hostbits = split /\./, $hname;
     233  my $sth = $dbh->prepare("SELECT count(*),domain_id FROM domains WHERE domain = ? GROUP BY domain_id");
     234  foreach (@hostbits) {
     235    $sth->execute($hname);
     236    my ($found, $parid) = $sth->fetchrow_array;
     237    if ($found) {
     238      return $parid;
     239    }
     240    $hname =~ s/^$_\.//;
     241  }
     242} # end _hostparent()
    236243
    237244##
     
    253260
    254261  # Check IP is well-formed, and that it's a v4 address
    255   return ('FAIL',"A record must be a valid IPv4 address")
     262  return ('FAIL',"$typemap{${$args{rectype}}} record must be a valid IPv4 address")
    256263        unless $args{addr} && !$args{addr}->{isv6};
    257264  # coerce IP/value to normalized form for storage
    258265  ${$args{val}} = $args{addr}->addr;
     266
     267  # Add the necessary fields.
     268  ${$args{fields}} = 'domain_id,';
     269  push @{$args{vallist}}, $args{id};
    259270
    260271  return ('OK','OK');
     
    316327# PTR record
    317328sub _validate_12 {
     329  my $dbh = shift;
     330
     331  my %args = @_;
     332
     333  if ($args{revrec} eq 'y') {
     334    if ($args{defrec} eq 'n') {
     335      return ('FAIL', "IP or IP fragment ${$args{val}} is not within ".revName($dbh, $args{id}))
     336        unless _ipparent($dbh, $args{defrec}, $args{revrec}, $args{val}, $args{id}, \$args{addr});
     337      ${$args{val}} = $args{addr}->addr;
     338    } else {
     339      ${$args{val}} =~ s/^([:.]*)/ZONE$1/;
     340    }
     341
     342    ${$args{fields}} = _recparent($args{defrec},$args{revrec}).",";
     343    push @{$args{vallist}}, $args{id};
     344
     345# Multiple PTR records do NOT generally do what most people believe they do,
     346# and tend to fail in the most awkward way possible.  Check and warn.
     347# We use $val instead of $addr->addr since we may be in a defrec, and may have eg "ZONE::42" or "ZONE.12"
     348    my ($ptrcount) = $dbh->selectrow_array("SELECT count(*) FROM "._rectable($args{defrec},$args{revrec}).
     349        " WHERE val = ?", undef, ${$args{val}});
     350    return ('WARN', "PTR record for ${$args{val}} already exists;  adding another will probably not do what you want")
     351        if $ptrcount;
     352  } else {
     353    # Not absolutely true but only useful if you hack things up for sub-/24 v4 reverse delegations
     354    # Simpler to just create the reverse zone and grant access for the customer to edit it, and create direct
     355    # PTR records on export
     356    return ('FAIL',"Forward zones cannot contain PTR records");
     357  }
     358
    318359  return ('OK','OK');
    319360} # done PTR record
     
    369410
    370411  # Check IP is well-formed, and that it's a v6 address
    371   return ('FAIL',"AAAA record must be a valid IPv6 address")
     412  return ('FAIL',"$typemap{${$args{rectype}}} record must be a valid IPv6 address")
    372413        unless $args{addr} && $args{addr}->{isv6};
    373414  # coerce IP/value to normalized form for storage
    374415  ${$args{val}} = $args{addr}->addr;
     416
     417  # Add the necessary fields.
     418  ${$args{fields}} = 'domain_id,';
     419  push @{$args{vallist}}, $args{id};
    375420
    376421  return ('OK','OK');
     
    413458# Now the custom types
    414459
    415 # A+PTR record
     460# A+PTR record.  With a very little bit of magic we can also use this sub to validate AAAA+PTR.  Whee!
    416461sub _validate_65280 {
    417   return ('OK','OK');
     462  my $dbh = shift;
     463
     464  my %args = @_;
     465
     466  my $code = 'OK';
     467  my $msg = 'OK';
     468
     469  if ($args{defrec} eq 'n') {
     470    # live record;  revrec determines whether we validate the PTR or A component first.
     471    if ($args{revrec} eq 'y') {
     472      ($code,$msg) = _validate_12($dbh, %args);
     473      return ($code,$msg) if $code eq 'FAIL';
     474
     475      # Check if the reqested domain exists.  If not, coerce the type down to PTR and warn.
     476      if (!(${$args{domid}} = _hostparent($dbh, ${$args{host}}))) {
     477        my $addmsg = "Record added as PTR instead of $typemap{${$args{rectype}}};  domain not found for ${$args{host}}";
     478        $msg .= "\n$addmsg" if $code eq 'WARN';
     479        $msg = $addmsg if $code eq 'OK';
     480        ${$args{rectype}} = $reverse_typemap{PTR};
     481        return ('WARN', $msg);
     482      }
     483      ${$args{fields}} .= "domain_id,";
     484      push @{$args{vallist}}, ${$args{domid}};
     485
     486    } else {
     487      ($code,$msg) = _validate_1($dbh, %args) if ${$args{rectype}} == 65280;
     488      ($code,$msg) = _validate_28($dbh, %args) if ${$args{rectype}} == 65281;
     489      return ($code,$msg) if $code eq 'FAIL';
     490
     491      # Check if the requested reverse zone exists - note, an IP fragment won't
     492      # work here since we don't *know* which parent to put it in.
     493      my ($revid) = $dbh->selectrow_array("SELECT rdns_id FROM revzones WHERE revnet >> ?".
     494        " ORDER BY masklen(revnet) DESC", undef, (${$args{val}}));
     495      if (!$revid) {
     496        $msg = "Record added as ".(${$args{rectype}} == 65280 ? 'A' : 'AAAA').
     497                " instead of $typemap{${$args{rectype}}};  reverse zone not found for ${$args{val}}";
     498        ${$args{rectype}} = (${$args{rectype}} == 65280 ? $reverse_typemap{A} : $reverse_typemap{AAAA});
     499        return ('WARN', $msg);
     500      }
     501
     502      # Check for duplicate PTRs.  Note we don't have to play games with $code and $msg, because
     503      # by definition there can't be duplicate PTRs if the reverse zone isn't managed here.
     504      my ($ptrcount) = $dbh->selectrow_array("SELECT count(*) FROM "._rectable($args{defrec},$args{revrec}).
     505        " WHERE val = ?", undef, ${$args{val}});
     506      if ($ptrcount) {
     507        $msg = "PTR record for ${$args{val}} already exists;  adding another will probably not do what you want";
     508        $code = 'WARN';
     509      }
     510
     511      ${$args{fields}} .= "rdns_id,";
     512      push @{$args{vallist}}, $revid;
     513    }
     514
     515  } else {
     516    # defrec eq 'y'
     517  }
     518
     519  return ($code, $msg);
    418520} # done A+PTR record
    419521
    420522# AAAA+PTR record
     523# A+PTR above has been magicked to handle AAAA+PTR as well.
    421524sub _validate_65281 {
    422   return ('OK','OK');
     525  return _validate_65280(@_);
    423526} # done AAAA+PTR record
    424527
Note: See TracChangeset for help on using the changeset viewer.