Changeset 1047 for branches/stable/DNSDB.pm
- Timestamp:
- 02/27/26 16:40:46 (4 hours ago)
- Location:
- branches/stable
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/stable
- Property svn:mergeinfo changed
/trunk merged: 797-798,828,831,833,838-839,844-846,879,883-885,887,894,903,905-909
- Property svn:mergeinfo changed
-
branches/stable/DNSDB.pm
r1037 r1047 3 3 ## 4 4 # $Id$ 5 # Copyright 2008-20 19Kris Deugau <kdeugau@deepnet.cx>5 # Copyright 2008-2025 Kris Deugau <kdeugau@deepnet.cx> 6 6 # 7 7 # This program is free software: you can redistribute it and/or modify … … 396 396 sub _maybeip { 397 397 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]+)?$,; 399 399 } 400 400 … … 514 514 } 515 515 } # 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 526 sub _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 516 558 517 559 … … 1049 1091 1050 1092 # 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" 1051 1094 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:]+)$/; 1053 1096 } else { 1054 1097 # hm. we can't do anything sane with IP values here; part of the record data is in … … 1064 1107 1065 1108 # 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" 1066 1110 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:]+)$/; 1068 1112 1069 1113 # SRV records in reverse zones get stricter treatment. The UI bars adding them in … … 1867 1911 my $tmpl = shift; 1868 1912 my $ip = shift; 1869 my $subnet = shift; # for %ngb and %c1913 my $subnet = shift; # for %ngb, %c, and %x 1870 1914 my $ipindex = shift; # for %c 1871 1915 … … 2691 2735 my $failmsg = ''; 2692 2736 my $zone = ($revrec eq 'n' ? $self->domainName($zoneid) : $self->revName($zoneid)); 2737 my $zonestatus = $self->zoneStatus($zoneid, $revrec); 2693 2738 2694 2739 return ('FAIL', ($revrec eq 'n' ? 'Domain' : 'Reverse zone')." ID $zoneid doesn't exist") if !$zone; … … 2730 2775 } 2731 2776 2732 $msg = "Deleted ".($ revrec eq 'n' ? 'domain' : 'reverse zone')." $zone";2777 $msg = "Deleted ".($zonestatus ? '' : 'inactive ').($revrec eq 'n' ? 'domain' : 'reverse zone')." $zone"; 2733 2778 $loghash{entry} = $msg; 2734 2779 $self->_log(%loghash); … … 4529 4574 # Filtering on host/val (mainly normal record list) 4530 4575 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); 4555 4577 } 4556 4578 … … 4626 4648 # Filtering on host/val (mainly normal record list) 4627 4649 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); 4652 4651 } 4653 4652 … … 4700 4699 return ('FAIL', "host must contain a value") if !$$host; 4701 4700 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'); 4702 4705 4703 4706 # Spaces are evil. … … 4796 4799 local $dbh->{RaiseError} = 1; 4797 4800 4801 my $retid; 4798 4802 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'; 4801 4807 $self->_updateserial(%logdata); 4802 4808 $self->_log(%logdata); … … 4816 4822 4817 4823 $resultstr = $logdata{entry}; 4818 return ($retcode, $retmsg );4824 return ($retcode, $retmsg, $retid); 4819 4825 4820 4826 } # end addRec() … … 4853 4859 # just set it to an empty string; failures will be caught later. 4854 4860 $$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'); 4855 4865 4856 4866 # Spaces are evil. … … 5258 5268 JOIN rectypes t ON r.type = t.val 5259 5269 LEFT JOIN locations l ON r.location = l.location 5260 WHERE r.type <> 6 AND (r.host ~* ? OR r.val ~* ?) 5261 ); 5270 WHERE r.type <> 6); 5262 5271 5263 5272 … … 5271 5280 5272 5281 my $sql = "SELECT count(*)".$recsearchsqlbase; 5282 5283 my @bindargs; 5284 _recfilter(filter => $args{searchfor}, sql => \$sql, bindvars => \@bindargs); 5273 5285 5274 5286 # Limit scope based on group … … 5286 5298 } 5287 5299 5288 my $count = $dbh->selectrow_array($sql, undef, $args{searchfor}, $args{searchfor});5300 my $count = $dbh->selectrow_array($sql, undef, @bindargs); 5289 5301 $errstr = $dbh->errstr if !$count; 5290 5302 return $count; … … 5308 5320 r.host, t.name AS rectype, r.val, l.description AS location, r.record_id). 5309 5321 $recsearchsqlbase; 5322 5323 my @bindargs; 5324 _recfilter(filter => $args{searchfor}, sql => \$sql, bindvars => \@bindargs); 5310 5325 5311 5326 # Limit scope based on group … … 5345 5360 5346 5361 ##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) 5348 5363 or warn $dbh->errstr; 5349 5364 return $ret; … … 6459 6474 "FROM records WHERE domain_id=? AND type=6"); 6460 6475 $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)"); 6462 6478 # "FROM records WHERE domain_id=? AND type < 65280"); # Just exclude all types relating to rDNS 6463 6479 my $domsth = $dbh->prepare("SELECT domain_id,domain,status,changed FROM domains WHERE status=1 ORDER BY domain_id"); … … 6690 6706 my $stamp = shift; 6691 6707 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; 6693 6721 my $ptronly = shift || 0; 6694 6722 … … 6809 6837 } else { 6810 6838 # call sub to convert 1-4 hex digits to 2 string-rep octal bytes 6811 $altconv[$altgrp++] = octalize($_) 6839 $altconv[$altgrp++] = octalize($_); 6812 6840 } 6813 6841 } … … 6934 6962 elsif ($typemap{$type} eq 'PTR') { 6935 6963 $$recflags{$val}++; 6964 6965 # technically a PTR template thing, but Bad Data Happens 6966 return if $host =~ /\%blank\%/; 6967 6936 6968 if ($revrec eq 'y') { 6937 6969 … … 6965 6997 elsif ($type == 65280) { # A+PTR 6966 6998 $$recflags{$val}++; 6999 7000 # technically a PTR template thing, but Bad Data Happens 7001 return if $host =~ /\%blank\%/; 7002 6967 7003 print $datafile "=$host:$val:$ttl:$stamp:$loc\n" or die $!; 6968 7004 } # A+PTR
Note:
See TracChangeset
for help on using the changeset viewer.
![[ DNS Administrator ]](/fx/dnsadmin-logo.png)