Ignore:
Timestamp:
02/27/26 16:40:46 (4 hours ago)
Author:
Kris Deugau
Message:

/branches/stable

Rollup merge through r909 for core dnsadmin - excludes BIND export, changes
to auxiliary scripts (compatc-recs.pl, mergerecs.pl, etc)

Location:
branches/stable
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/stable

  • branches/stable/DNSDB.pm

    r1037 r1047  
    33##
    44# $Id$
    5 # Copyright 2008-2019 Kris Deugau <kdeugau@deepnet.cx>
     5# Copyright 2008-2025 Kris Deugau <kdeugau@deepnet.cx>
    66#
    77#    This program is free software: you can redistribute it and/or modify
     
    396396sub _maybeip {
    397397  my $izzit = shift;  # reference
    398   return 1 if $$izzit =~ m,^(?:[\d\./]+|[0-9a-fA-F:/]+)$,;
     398  return 1 if $$izzit =~ m,^(?:[0-9\.]+|[0-9a-fA-F:]+)(?:/[0-9]+)?$,;
    399399}
    400400
     
    514514  }
    515515} # end _updateserial()
     516
     517
     518## DNSDB::_recfilter()
     519# Utility sub to construct an SQL fragment for host/value filtering based on a filter argument
     520# Deconstructs the argument to apply Postgres CIDR operators or Postgres string-matching operators as appropriate
     521# Used by recSearchCount(), recSearch(), getRecList(), and getRecCount()
     522# Takes a hash of:
     523#   filter - string to create SQL fragment from
     524#   sql - reference to SQL string.  SQL fragment will be appended to this string
     525#   bindvars - reference to list of DBI bind variable scalars to be fed to DBI on execute
     526sub _recfilter {
     527  my %args = @_;
     528
     529  # flag for "was this an IPish filter argument?", since we want to fall through
     530  # to the second top-level if() if *any* of the ones in the first block fail
     531  my $ipfilt = 0;
     532
     533  if ($args{filter} =~ /^\s*(<|<=|=|>=|>|<>|<<|<<=|>>|>>=)\s*([\da-fA-F].+)\s*$/) {
     534    # filter argument starts with a Postgres CIDR operator, followed by something that could be a CIDR value
     535    my $filt_op = $1;
     536    my $filt_val = $2;
     537    # do we have an IP-ish value?
     538    if ($filt_val =~ m,^(?:[\d.]+|[0-9a-f]+)(?:/\d+)?$,) {
     539      # now make sure
     540      my $tmp = new NetAddr::IP $filt_val;
     541      if ($tmp) {
     542        ${$args{sql}} .= " AND inetlazy(r.val) $filt_op ?";
     543        push @{$args{bindvars}}, $filt_val;
     544        $ipfilt = 1;
     545      } # really looks like a valid IP/CIDR
     546    } # looks IPish
     547  } # has CIDR operator
     548
     549  if (!$ipfilt) {
     550    # simple text matching, with a bit of mix-n-match to account for .arpa names
     551    ${$args{sql}} .= " AND (r.host ~* ? OR r.val ~* ? OR r.host ~* ? OR r.val ~* ?)";
     552    my $tmp = join('.',reverse(split(/\./,$args{filter})));
     553    push @{$args{bindvars}}, ($args{filter},$args{filter});
     554    push @{$args{bindvars}}, ($tmp, $tmp);
     555  }
     556
     557} # _recfilter
    516558
    517559
     
    10491091
    10501092    # SRV target check - IP addresses not allowed.  Must be a more or less well-formed hostname.
     1093    # Allow a bare . to indicate "this service does not exist"
    10511094    return ('FAIL', "SRV records cannot point directly to an IP address")
    1052       if ${$args{val}} =~ /^(?:[\d.]+|[0-9a-fA-F:]+)$/;
     1095      if ${$args{val}} ne '.' && ${$args{val}} =~ /^(?:[\d.]+|[0-9a-fA-F:]+)$/;
    10531096  } else {
    10541097    # hm.  we can't do anything sane with IP values here;  part of the record data is in
     
    10641107
    10651108    # SRV target check - IP addresses not allowed.  Must be a more or less well-formed hostname.
     1109    # Allow a bare . to indicate "this service does not exist"
    10661110    return ('FAIL', "SRV records cannot point directly to an IP address")
    1067       if ${$args{host}} =~ /^(?:[\d.]+|[0-9a-fA-F:]+)$/;
     1111      if ${$args{host}} ne '.' && ${$args{host}} =~ /^(?:[\d.]+|[0-9a-fA-F:]+)$/;
    10681112
    10691113    # SRV records in reverse zones get stricter treatment.  The UI bars adding them in
     
    18671911  my $tmpl = shift;
    18681912  my $ip = shift;
    1869   my $subnet = shift;   # for %ngb and %c
     1913  my $subnet = shift;   # for %ngb, %c, and %x
    18701914  my $ipindex = shift;  # for %c
    18711915
     
    26912735  my $failmsg = '';
    26922736  my $zone = ($revrec eq 'n' ? $self->domainName($zoneid) : $self->revName($zoneid));
     2737  my $zonestatus = $self->zoneStatus($zoneid, $revrec);
    26932738
    26942739  return ('FAIL', ($revrec eq 'n' ? 'Domain' : 'Reverse zone')." ID $zoneid doesn't exist") if !$zone;
     
    27302775    }
    27312776
    2732     $msg = "Deleted ".($revrec eq 'n' ? 'domain' : 'reverse zone')." $zone";
     2777    $msg = "Deleted ".($zonestatus ? '' : 'inactive ').($revrec eq 'n' ? 'domain' : 'reverse zone')." $zone";
    27332778    $loghash{entry} = $msg;
    27342779    $self->_log(%loghash);
     
    45294574  # Filtering on host/val (mainly normal record list)
    45304575  if ($args{filter}) {
    4531     # not much use to end users, but internal callers may want more fine-grained restriction on CIDR ranges
    4532     # we'll only support the value-comparison operators;  bitwise/add/subtract don't make much sense in this context
    4533     my $ipfilt = 0;
    4534     if ($args{filter} =~ /^\s*(<|<=|=|>=|>|<>|<<|<<=|>>|>>=)\s*([\da-fA-F].+)\s*$/) {
    4535       my $filt_op = $1;
    4536       my $filt_val = $2;
    4537       # do we have an IP-ish value?
    4538       if ($filt_val =~ m,^(?:[\d.]+|[0-9a-f]+)(?:/\d+)?$,) {
    4539         # now make sure
    4540         my $tmp = new NetAddr::IP $filt_val;
    4541         if ($tmp) {
    4542           $sql .= " AND inetlazy(r.val) $filt_op ?";
    4543           push @bindvars, $filt_val;
    4544           $ipfilt = 1;
    4545         } # really looks like a valid IP/CIDR
    4546       } # looks IPish
    4547     } # has CIDR operator
    4548     if (!$ipfilt) {
    4549       # simple text matching, with a bit of mix-n-match to account for .arpa names
    4550       $sql .= " AND (r.host ~* ? OR r.val ~* ? OR r.host ~* ? OR r.val ~* ?)";
    4551       my $tmp = join('.',reverse(split(/\./,$args{filter})));
    4552       push @bindvars, ($args{filter},$args{filter});
    4553       push @bindvars, ($tmp, $tmp);
    4554     }
     4576    _recfilter(filter => $args{filter}, sql => \$sql, bindvars => \@bindvars);
    45554577  }
    45564578
     
    46264648  # Filtering on host/val (mainly normal record list)
    46274649  if ($args{filter}) {
    4628     # not much use to end users, but internal callers may want more fine-grained restriction on CIDR ranges
    4629     # we'll only support the value-comparison operators;  bitwise/add/subtract don't make much sense in this context
    4630     my $ipfilt = 0;
    4631     if ($args{filter} =~ /^\s*(<|<=|=|>=|>|<>|<<|<<=|>>|>>=)\s*([\da-fA-F].+)\s*$/) {
    4632       my $filt_op = $1;
    4633       my $filt_val = $2;
    4634       # do we have an IP-ish value?
    4635       if ($filt_val =~ m,^(?:[\d.]+|[0-9a-f]+)(?:/\d+)?$,) {
    4636         # now make sure
    4637         my $tmp = new NetAddr::IP $filt_val;
    4638         if ($tmp) {
    4639           $sql .= " AND inetlazy(r.val) $filt_op ?";
    4640           push @bindvars, $filt_val;
    4641           $ipfilt = 1;
    4642         } # really looks like a valid IP/CIDR
    4643       } # looks IPish
    4644     } # has CIDR operator
    4645     if (!$ipfilt) {
    4646       # simple text matching, with a bit of mix-n-match to account for .arpa names
    4647       $sql .= " AND (r.host ~* ? OR r.val ~* ? OR r.host ~* ? OR r.val ~* ?)";
    4648       my $tmp = join('.',reverse(split(/\./,$args{filter})));
    4649       push @bindvars, ($args{filter},$args{filter});
    4650       push @bindvars, ($tmp, $tmp);
    4651     }
     4650    _recfilter(filter => $args{filter}, sql => \$sql, bindvars => \@bindvars);
    46524651  }
    46534652
     
    47004699  return ('FAIL', "host must contain a value") if !$$host;
    47014700  return ('FAIL', "val must contain a value") if !$$val;
     4701
     4702  return ('FAIL', "expires must be 1, 't', or 'until',  or 0, 'f', or 'after'")
     4703        if ($stamp && !$expires)
     4704        || ($stamp && $expires ne '0' && $expires ne '1' && $expires ne 't' && $expires ne 'f');
    47024705
    47034706  # Spaces are evil.
     
    47964799  local $dbh->{RaiseError} = 1;
    47974800
     4801  my $retid;
    47984802  eval {
    4799     $dbh->do("INSERT INTO "._rectable($defrec, $revrec)." ($fields) VALUES ($vallen)",
    4800         undef, @vallist);
     4803    ($retid) = $dbh->selectrow_array("INSERT INTO "._rectable($defrec, $revrec)." ($fields) VALUES ($vallen) RETURNING record_id",
     4804        undef,
     4805        @vallist
     4806        ) || 'Falsey ID returned';
    48014807    $self->_updateserial(%logdata);
    48024808    $self->_log(%logdata);
     
    48164822
    48174823  $resultstr = $logdata{entry};
    4818   return ($retcode, $retmsg);
     4824  return ($retcode, $retmsg, $retid);
    48194825
    48204826} # end addRec()
     
    48534859  # just set it to an empty string;  failures will be caught later.
    48544860  $$host = '' if !$$host;
     4861
     4862  return ('FAIL', "expires must be 1, 't', or 'until',  or 0, 'f', or 'after'")
     4863        if ($stamp && !$expires)
     4864        || ($stamp && $expires ne '0' && $expires ne '1' && $expires ne 't' && $expires ne 'f');
    48554865
    48564866  # Spaces are evil.
     
    52585268JOIN rectypes t ON r.type = t.val
    52595269LEFT JOIN locations l ON r.location = l.location
    5260 WHERE r.type <> 6 AND (r.host ~* ? OR r.val ~* ?)
    5261 );
     5270WHERE r.type <> 6);
    52625271
    52635272
     
    52715280
    52725281  my $sql = "SELECT count(*)".$recsearchsqlbase;
     5282
     5283  my @bindargs;
     5284  _recfilter(filter => $args{searchfor}, sql => \$sql, bindvars => \@bindargs);
    52735285
    52745286  # Limit scope based on group
     
    52865298  }
    52875299
    5288   my $count = $dbh->selectrow_array($sql, undef, $args{searchfor}, $args{searchfor});
     5300  my $count = $dbh->selectrow_array($sql, undef, @bindargs);
    52895301  $errstr = $dbh->errstr if !$count;
    52905302  return $count;
     
    53085320    r.host, t.name AS rectype, r.val, l.description AS location, r.record_id).
    53095321    $recsearchsqlbase;
     5322
     5323  my @bindargs;
     5324  _recfilter(filter => $args{searchfor}, sql => \$sql, bindvars => \@bindargs);
    53105325
    53115326  # Limit scope based on group
     
    53455360
    53465361##fixme: should probably sent the warning somewhere else
    5347   my $ret = $dbh->selectall_arrayref($sql, { Slice => {} }, $args{searchfor}, $args{searchfor})
     5362  my $ret = $dbh->selectall_arrayref($sql, { Slice => {} }, @bindargs)
    53485363    or warn $dbh->errstr;
    53495364  return $ret;
     
    64596474        "FROM records WHERE domain_id=? AND type=6");
    64606475  $recsth = $dbh->prepare("SELECT host,type,val,distance,weight,port,ttl,record_id,location,extract(epoch from stamp),expires,stampactive ".
    6461         "FROM records WHERE domain_id=? AND NOT type=6");       # Just exclude all types relating to rDNS
     6476        "FROM records WHERE domain_id=? AND NOT type=6".        # Just exclude all types relating to rDNS
     6477        "ORDER BY masklen(inetlazy(val)) DESC, inetlazy(val)");
    64626478#       "FROM records WHERE domain_id=? AND type < 65280");     # Just exclude all types relating to rDNS
    64636479  my $domsth = $dbh->prepare("SELECT domain_id,domain,status,changed FROM domains WHERE status=1 ORDER BY domain_id");
     
    66906706    my $stamp = shift;
    66916707    my $loc = shift;
    6692     my $zone = new NetAddr::IP shift;
     6708    my $zone = shift;
     6709    # error/sanity check - if $zone is not an IP address, make sure we're just
     6710    # converting a string that looks like an IP into a NetAddr::IP, instead of
     6711    # doing a DNS lookup that is virtually guaranteed to be wrong.  still a
     6712    # little hazy where this functionality in NetAddr::IP is useful.
     6713    # instead, fall back to the octet-boundary CIDR derived from $sub.
     6714    if ($zone !~ m,^\d+\.\d+\.\d+\.\d+/\d+$,) {
     6715      $zone = $sub;
     6716      $zone =~ s,\d+/\d+$,0/24,;   ##fixme:  case of larger than /24?
     6717      # could apply another sanity check here?  as above anything much larger
     6718      # than a /16 is WAY too time-consuming to publish in one go
     6719    }
     6720    $zone = new NetAddr::IP $zone;
    66936721    my $ptronly = shift || 0;
    66946722
     
    68096837      } else {
    68106838        # call sub to convert 1-4 hex digits to 2 string-rep octal bytes
    6811         $altconv[$altgrp++] = octalize($_)
     6839        $altconv[$altgrp++] = octalize($_);
    68126840      }
    68136841    }
     
    69346962  elsif ($typemap{$type} eq 'PTR') {
    69356963    $$recflags{$val}++;
     6964
     6965    # technically a PTR template thing, but Bad Data Happens
     6966    return if $host =~ /\%blank\%/;
     6967
    69366968    if ($revrec eq 'y') {
    69376969
     
    69656997  elsif ($type == 65280) { # A+PTR
    69666998    $$recflags{$val}++;
     6999
     7000    # technically a PTR template thing, but Bad Data Happens
     7001    return if $host =~ /\%blank\%/;
     7002
    69677003    print $datafile "=$host:$val:$ttl:$stamp:$loc\n" or die $!;
    69687004  } # A+PTR
Note: See TracChangeset for help on using the changeset viewer.