Changeset 1054
- Timestamp:
- 03/13/26 14:00:58 (42 hours ago)
- Location:
- branches/stable
- Files:
-
- 5 edited
- 3 copied
-
. (modified) (1 prop)
-
DNSDB.pm (modified) (15 diffs)
-
collision-truth-table.ods (copied) (copied from trunk/collision-truth-table.ods )
-
dnsdb.conf (modified) (1 diff)
-
t/DNSTest.pm (modified) (5 diffs)
-
t/cname.t (copied) (copied from trunk/t/cname.t )
-
t/dns-unitbase.sql (modified) (6 diffs)
-
t/test-cname-timestamps.sql (copied) (copied from trunk/t/test-cname-timestamps.sql )
Legend:
- Unmodified
- Added
- Removed
-
branches/stable
- Property svn:mergeinfo changed
/branches/cname-collision (added) merged: 936-942,949-956,958-960,962-964,967-970,972-984,986-1001,1003-1006,1008-1031,1038-1046 /trunk merged: 1051
- Property svn:mergeinfo changed
-
branches/stable/DNSDB.pm
r1049 r1054 33 33 use Fcntl qw(:flock); 34 34 use Time::TAI64 qw(:tai64); 35 use Date::Parse; 35 36 36 37 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); … … 213 214 force_refresh => 1, 214 215 lowercase => 0, # mangle as little as possible by default 216 # tinker with timestamps if adding or updating a record would 217 # cause overlapping CNAME and other in some way 218 coerce_cname_timestamp => 'none', 215 219 # show IPs and CIDR blocks as-is for reverse zones. valid values are 216 220 # 'none' (default, show natural IP or CIDR) … … 275 279 $self->{showrev_arpa} = 'none'; 276 280 } 281 if (!grep /$self->{coerce_cname_timestamp}/, ('none','adjust','full')) { 282 warn "Bad coerce_cname_timestamp setting $self->{coerce_cname_timestamp}, using default\n"; 283 $self->{coerce_cname_timestamp} = 'none'; 284 } 277 285 278 286 # Try to connect to the DB, and initialize a number of handy globals. … … 561 569 ## Record validation subs. 562 570 ## 571 572 # Check for name collisions relating to CNAMEs. Needs to be called from all other validators. 573 sub _cname_collision { 574 my $self = shift; 575 my $dbh = $self->{dbh}; 576 577 my %args = @_; 578 579 my $hcheck = ($args{revrec} eq 'y' ? ${$args{val}} : ${$args{host}}); 580 my $hfield = ($args{revrec} eq 'y' ? 'val' : 'host'); 581 582 # $hcheck should be normalized by the time this sub is called. Convert to the formal .arpa name for error reporting in reverse zones. 583 my $arpaname = ''; 584 if ($args{revrec} eq 'y') { 585 $arpaname = NetAddr::IP->new($hcheck); 586 ##fixme: more voodoo if global and/or per-user ARPA display mode flag set this way or that 587 $arpaname = _ZONE($arpaname, 'ZONE', 'r', '.').($arpaname->{isv6} ? '.ip6.arpa' : '.in-addr.arpa'); 588 } 589 590 # The record type comparison is the only difference between two passes through this chunk of code. 591 # CNAME records require both passes, where other records only need the second one. Downside is 592 # that returning error messages needs to check the loop variable on top of whatever else it references. 593 foreach my $tcompare ('<>', '=') { 594 next if $tcompare eq '<>' && ${$args{rectype}} != 5; 595 596 # Merging these sets of SQL statements is far too messy and doesn't reasonably 597 # allow for more fine-grained error/warning messages to be returned 598 599 # First lookup fails out collisions with records without timestamps or default records (which can not have timestamps) 600 my $sql = "SELECT count(*) FROM "._rectable($args{defrec}, $args{revrec}). 601 " WHERE "._recparent($args{defrec}, $args{revrec})." = ? AND type $tcompare 5 AND $hfield = ?"; 602 my @lookupargs = ($args{id}, $hcheck); 603 $sql .= " AND stampactive = 'f'" if $args{defrec} eq 'n'; 604 if ($args{update}) { 605 $sql .= " AND record_id <> ?"; 606 push @lookupargs, $args{update}; 607 } 608 my @t = $dbh->selectrow_array($sql, undef, @lookupargs); 609 if ($t[0] > 0) { 610 if ($tcompare eq '<>') { 611 return ('FAIL', "One or more non-CNAME records already exist for ".($args{revrec} eq 'y' ? $arpaname : $hcheck). 612 ". CNAME records cannot use the same name as other records."); 613 } else { 614 return ('FAIL', "There is already a CNAME present for ".($args{revrec} eq 'y' ? $arpaname : $hcheck). 615 ". Only one CNAME may be present for a given name."); 616 } 617 } 618 619 # By this point, all failure cases for default records have been checked. 620 # Default records cannot carry timestamps, so cannot have timestamp-based collisions 621 return ('OK','OK') if $args{defrec} ne 'n'; 622 623 # Second lookup fails out various timestamp-exists collision cases when adding/updating with a timestamp 624 $sql = "SELECT count(*) FROM "._rectable($args{defrec}, $args{revrec}). 625 " WHERE "._recparent($args{defrec}, $args{revrec})." = ? AND type $tcompare 5 AND $hfield = ?". 626 " AND stampactive = 't'"; 627 @lookupargs = ($args{id}, $hcheck); 628 if (${$args{stamp}} && ${$args{expires}}) { 629 $sql .= " AND expires = ?"; 630 push @lookupargs, ${$args{expires}}; 631 if ($self->{coerce_cname_timestamp} eq 'none') { 632 # no coercion means new valid-after < existing expires or new expires > existing valid-after will fail 633 $sql .= " AND ". (${$args{expires}} eq 'f' ? "expires = 't' AND stamp <= ?)" : "expires = 'f' AND stamp >= ?"); 634 push @lookupargs, ${$args{stamp}}; 635 } 636 } 637 if ($args{update}) { 638 $sql .= " AND record_id <> ?"; 639 push @lookupargs, $args{update}; 640 } 641 @t = $dbh->selectrow_array($sql, undef, @lookupargs); 642 if ($t[0] > 0) { 643 if ($tcompare eq '<>') { 644 return ('FAIL', "One or more non-CNAME records with timestamps already exist for ".($args{revrec} eq 'y' ? $arpaname : $hcheck). 645 ". CNAME records must expire before or become valid after any records with the same name."); 646 } else { 647 return ('FAIL', "There is already a CNAME with a timestamp present for ".($args{revrec} eq 'y' ? $arpaname : $hcheck). 648 ". Records with a matching name must expire before or become valid after this CNAME."); 649 } 650 } 651 652 # Third check starts retrieving actual timestamps to see if we need to, 653 # and then if we can, coerce the new/updated record's timestamp to match 654 $sql = "SELECT extract(epoch from stamp),expires,stamp < now() FROM "._rectable($args{defrec}, $args{revrec}). 655 " WHERE "._recparent($args{defrec}, $args{revrec})." = ? AND type $tcompare 5 AND $hfield = ?". 656 " AND stampactive = 't'"; 657 @lookupargs = ($args{id}, $hcheck); 658 if ($args{update}) { 659 $sql .= " AND record_id <> ?"; 660 push @lookupargs, $args{update}; 661 } 662 if (${$args{stamp}}) { 663 $sql .= " ORDER BY stamp ".(${$args{expires}} eq 'f' ? 'ASC' : 'DESC' )." LIMIT 1"; 664 } else { 665 $sql .= " ORDER BY stamp LIMIT 1"; 666 } 667 @t = $dbh->selectrow_array($sql, undef, @lookupargs); 668 if (@t) { 669 # caller requested an expiry time 670 my $reqstamp = str2time(${$args{stamp}}); 671 if (${$args{expires}} eq 'f') { 672 if ($reqstamp > $t[0]) { 673 # do nothing, new record goes valid after the expiring record we found 674 } else { 675 if ($self->{coerce_cname_timestamp} eq 'adjust') { 676 # coerce the valid-after timestamp 677 ${$args{stamp}} = strftime('%Y-%m-%d %H:%M:%S', localtime($t[0])); 678 return ('WARN', $typemap{${$args{rectype}}}." ".($args{update} ? 'updated' : 'added'). 679 " with modified valid-after time; conflicting expiring record found"); 680 } else { 681 # New valid-after overlaps existing expiry, and not configured to adjust it 682 my $fill = ($tcompare eq '<>' ? ' CNAME, another record' : $typemap{${$args{rectype}}}.', a CNAME'); 683 return ('FAIL', "Cannot ".($args{update} ? 'update' : 'add').$fill. 684 " with a valid-after time already exists for this name"); 685 } 686 } # else ($reqstamp < $t[0]) 687 } else { 688 if ($reqstamp < $t[0]) { 689 # do nothing, new record will expire before the one we found 690 } else { 691 if ($self->{coerce_cname_timestamp} eq 'adjust') { 692 if ($t[2] == 1) { 693 # found a valid-after, but it's in the past, so adding an expiring record to match doesn't make 694 # sense since it's effectively expired. 695 ##fixme: should probably remove this case once we get around to stripping valid-after timestamps once exported as active 696 return ('FAIL', "Cannot ".($args{update} ? 'update' : 'add')." ".$typemap{${$args{rectype}}}. 697 ", an existing valid-after record is already active for this name"); 698 } else { 699 # coerce the expiry timestamp 700 ${$args{stamp}} = strftime('%Y-%m-%d %H:%M:%S', localtime($t[0])); 701 return ('WARN', $typemap{${$args{rectype}}}." ".($args{update} ? 'updated' : 'added'). 702 " with modified expiry time; conflicting valid-after record found"); 703 } 704 } else { 705 return ('FAIL', "Cannot ".($args{update} ? 'update' : 'add')." ".$typemap{${$args{rectype}}}. 706 ", another record with an overlapping valid-after timestamp already exists for this name"); 707 } 708 } 709 } # args{expires} ne 'f' 710 } # if @t 711 712 } # each $tcompare 713 714 return ('OK', 'OK'); 715 } # _cname_collision() 563 716 564 717 ## All of these subs take substantially the same arguments: … … 758 911 return ('FAIL', "The bare zone name may not be a CNAME") if ${$args{host}} eq $pname || ${$args{host}} =~ /^\@/; 759 912 760 ##enhance: Look up the passed value to see if it exists. Ooo, fancy.761 913 return ('FAIL', $errstr) if ! _check_hostname_form(${$args{val}}, ${$args{rectype}}, $args{defrec}, $args{revrec}); 914 762 915 } # $zname !~ .rpz 763 916 } # revzone eq 'n' … … 1616 1769 1617 1770 return ('WARN', join("\n", $errstr, $warnmsg) ) if $warnmsg; 1618 1771 1619 1772 return ('OK','OK'); 1620 1773 } # done ALIAS record … … 2156 2309 $cfg->{lowercase} = $1 if /^lowercase\s*=\s*([a-z01]+)/i; 2157 2310 $cfg->{showrev_arpa} = $1 if /^showrev_arpa\s*=\s*([a-z]+)/i; 2311 $cfg->{coerce_cname_timestamp} = $1 if /^coerce_cname_timestamp\s*=\s*([a-z]+)/i; 2158 2312 $cfg->{template_skip_0} = $1 if /^template_skip_0\s*=\s*([a-z01]+)/i; 2159 2313 $cfg->{template_skip_255} = $1 if /^template_skip_255\s*=\s*([a-z01]+)/i; … … 4694 4848 4695 4849 my $expires = shift || ''; 4696 $expires = 1 if $expires eq 'until'; # Turn some special values into the appropriate booleans. 4697 $expires = 0 if $expires eq 'after'; 4850 $expires = 't' if $expires eq 'until'; # Turn some special values into the appropriate booleans. 4851 $expires = 'f' if $expires eq 'after'; 4852 $expires = 't' if $expires eq '1'; 4853 $expires = 'f' if $expires eq '0'; 4698 4854 my $stamp = shift; 4699 4855 $stamp = '' if !$stamp; # Timestamp should be a string at this point. … … 4705 4861 return ('FAIL', "expires must be 1, 't', or 'until', or 0, 'f', or 'after'") 4706 4862 if ($stamp && !defined($expires)) 4707 || ($stamp && $expires ne ' 0' && $expires ne '1' && $expires ne 't' && $expires ne 'f');4863 || ($stamp && $expires ne 't' && $expires ne 'f'); 4708 4864 4709 4865 # Spaces are evil. … … 4745 4901 host => $host, rectype => $rectype, val => $val, addr => $addr, 4746 4902 dist => \$dist, port => \$port, weight => \$weight, 4903 stamp => \$stamp, expires => \$expires, 4747 4904 fields => \$fields, vallist => \@vallist); 4748 4905 4749 4906 return ($retcode,$retmsg) if $retcode eq 'FAIL'; 4907 4908 # Check for CNAME collisions. 4909 ##fixme: should trim the list of arguments, not all of these should be required for CNAME collision checking 4910 my ($ccode,$cmsg) = _cname_collision($self, defrec => $defrec, revrec => $revrec, id => $id, 4911 host => $host, rectype => $rectype, val => $val, addr => $addr, 4912 dist => \$dist, port => \$port, weight => \$weight, 4913 stamp => \$stamp, expires => \$expires, 4914 fields => \$fields, vallist => \@vallist); 4915 4916 return ($ccode,$cmsg) if $ccode eq 'FAIL'; 4917 4918 # If both the validator and CNAME collision check return warnings, glue them together 4919 if ($ccode eq 'WARN') { 4920 if ($retcode eq 'WARN') { 4921 $retmsg .= "<br>\n$cmsg"; 4922 } else { 4923 $retmsg = $cmsg; 4924 } 4925 $retcode = 'WARN'; 4926 } 4750 4927 4751 4928 # Minor cleanup of invalid DNS labels … … 4806 4983 $logdata{entry} .= "', TTL $ttl"; 4807 4984 $logdata{entry} .= ", location ".$self->getLoc($location)->{description} if $location; 4808 $logdata{entry} .= ($expires ? ', expires at ' : ', valid after ').$stamp if $stamp;4985 $logdata{entry} .= ($expires eq 't' ? ', expires at ' : ', valid after ').$stamp if $stamp; 4809 4986 4810 4987 # Allow transactions, and raise an exception on errors so we can catch it later. … … 4866 5043 4867 5044 my $expires = shift || ''; 4868 $expires = 1 if $expires eq 'until'; # Turn some special values into the appropriate booleans. 4869 $expires = 0 if $expires eq 'after'; 5045 $expires = 't' if $expires eq 'until'; # Turn some special values into the appropriate booleans. 5046 $expires = 'f' if $expires eq 'after'; 5047 $expires = 't' if $expires eq '1'; 5048 $expires = 'f' if $expires eq '0'; 4870 5049 my $stamp = shift; 4871 5050 $stamp = '' if !$stamp; # Timestamp should be a string at this point. … … 4876 5055 return ('FAIL', "expires must be 1, 't', or 'until', or 0, 'f', or 'after'") 4877 5056 if ($stamp && !defined($expires)) 4878 || ($stamp && $expires ne ' 0' && $expires ne '1' && $expires ne 't' && $expires ne 'f');5057 || ($stamp && $expires ne 't' && $expires ne 'f'); 4879 5058 4880 5059 # Spaces are evil. … … 4922 5101 host => $host, rectype => $rectype, val => $val, addr => $addr, 4923 5102 dist => \$dist, port => \$port, weight => \$weight, 5103 stamp => \$stamp, expires => \$expires, 4924 5104 fields => \$fields, vallist => \@vallist, 4925 5105 update => $id); 4926 5106 4927 5107 return ($retcode,$retmsg) if $retcode eq 'FAIL'; 5108 5109 # Check for CNAME collisions. 5110 ##fixme: should trim the list of arguments, not all of these should be required for CNAME collision checking 5111 my ($ccode,$cmsg) = _cname_collision($self, defrec => $defrec, revrec => $revrec, 5112 id => ($defrec eq 'y' ? $oldrec->{group_id} : ($revrec eq 'n' ? $oldrec->{domain_id} : $oldrec->{rdns_id})), 5113 host => $host, rectype => $rectype, val => $val, addr => $addr, 5114 dist => \$dist, port => \$port, weight => \$weight, 5115 stamp => \$stamp, expires => \$expires, 5116 fields => \$fields, vallist => \@vallist, 5117 update => $id); 5118 5119 return ($ccode,$cmsg) if $ccode eq 'FAIL'; 5120 5121 # If both the validator and CNAME collision check return warnings, glue them together 5122 if ($ccode eq 'WARN') { 5123 if ($retcode eq 'WARN') { 5124 $retmsg .= "<br>\n$cmsg"; 5125 } else { 5126 $retmsg = $cmsg; 5127 } 5128 $retcode = 'WARN'; 5129 } 4928 5130 4929 5131 # Minor cleanup of invalid DNS labels … … 5024 5226 $logdata{entry} .= "', TTL $ttl"; 5025 5227 $logdata{entry} .= ", location ".$self->getLoc($location)->{description} if $location; 5026 $logdata{entry} .= ($expires ? ', expires at ' : ', valid after ').$stamp if $stamp;5228 $logdata{entry} .= ($expires eq 't' ? ', expires at ' : ', valid after ').$stamp if $stamp; 5027 5229 5028 5230 local $dbh->{AutoCommit} = 0; -
branches/stable/dnsdb.conf
r1047 r1054 46 46 #lowercase = 0 47 47 48 # Variously coerce timestamp and valid-after/expiry flags onto a new/updated record if the 49 # record as requested would cause a CNAME to overlap with another record. 50 # adjust: Adjust the timestamp where an expiry+valid-after would overlap 51 # - existing record expires, new record has valid-after before expiry => adjust timestamp to match existing record 52 # - existing record is valid-after, new record has expiry after valid-after => adjust timestamp to match existing record 53 # none: (default) Do not make changes to timestamps to avoid overlap 54 #coerce_cname_timestamp = none 55 48 56 # Show formal .arpa zone name instead of the natural IP or CIDR for reverse zone names and records? 49 57 # Valid values are none, zone, record, or all -
branches/stable/t/DNSTest.pm
r1050 r1054 5 5 ## 6 6 # $Id$ 7 # Copyright 2025 Kris Deugau <kdeugau@deepnet.cx>7 # Copyright 2025,2026 Kris Deugau <kdeugau@deepnet.cx> 8 8 # 9 9 # This program is free software: you can redistribute it and/or modify … … 48 48 dbuser => 'dnstest', 49 49 dbpass => 'dnstestpwd', 50 51 # This exercises more branches of the CNAME collision check with more fine-grained results. 52 coerce_cname_timestamp => 'adjust', 50 53 ); 51 54 ok( defined $dnsdb ); … … 61 64 62 65 my ($dcount) = $dbh->selectrow_array("SELECT count(*) FROM domains WHERE NOT domain IN ". 63 "('example.com','example.net','example.org','expiry1.test','expiry2.test' )");66 "('example.com','example.net','example.org','expiry1.test','expiry2.test','expiry3.test','cname-blocks1.test')"); 64 67 BAIL_OUT("# DB looks like it may not be a test DB, found $dcount > 0 non-test domains!\n") 65 68 if $dcount > 0; … … 68 71 my ($rcount) = $dbh->selectrow_array(qq{SELECT count(*) FROM records WHERE NOT ( 69 72 host like '%example.com' or host like '%example.net' or host like '%example.org' or 70 host like '%expiry1.test' or host like '%expiry2.test' or inetlazy(val) << '192.168.2.0/27' 73 host like '%expiry_.test' or host like '%cname-blocks_.test' or 74 inetlazy(val) << '192.168.2.0/27' 71 75 )}); 72 76 my $maxrecs = 0; 73 BAIL_OUT("# DB looks like it may not be a test DB, found $rcount > $maxrecs records!\n")77 BAIL_OUT("# DB looks like it may not be a test DB, found $rcount > $maxrecs non-test records!\n") 74 78 if $rcount > $maxrecs; 75 79 cmp_ok( $rcount, '<=', $maxrecs, "non-test record ($rcount): looks like a test DB" ); … … 83 87 my $reload = qx( psql -h $dnsdb->{dbhost} -U $dnsdb->{dbuser} $dnsdb->{dbname} 2>&1 < t/dns-unitbase.sql ); 84 88 diag( $reload ) if $debug; 89 # Set timestamps to a sliding window 90 my $stampwindow = qx( psql -h $dnsdb->{dbhost} -U $dnsdb->{dbuser} $dnsdb->{dbname} 2>&1 < t/test-cname-timestamps.sql ); 91 diag( $stampwindow ) if $debug; 85 92 undef $ENV{PGPASSWORD}; 86 93 } # new() -
branches/stable/t/dns-unitbase.sql
r1050 r1054 657 657 2 example.org 1 1 2025121800 D f ac 658 658 3 example.net 1 1 2025121800 D f ab 659 4 expiry1.test 1 1 1765992407 D f 659 4 expiry1.test 1 1 2026011400 D t 660 5 expiry2.test 1 1 2026011901 D t 661 6 expiry3.test 1 1 2026020509 D t 662 7 cname-blocks1.test 1 1 2026021811 D t 660 663 \. 661 664 … … 665 668 -- 666 669 667 SELECT pg_catalog.setval('public.domains_domain_id_seq', 4, true);670 SELECT pg_catalog.setval('public.domains_domain_id_seq', 7, true); 668 671 669 672 … … 761 764 53 0 1 1 admin Initial User Added record '192.168.2.17 TXT imma blocker!', TTL 2560 2025-12-23 13:06:20.492137-05 1 0 762 765 55 0 1 1 admin Initial User Added record '192.168.2.18 CNAME 18-2.arpa.example.com', TTL 2560 2026-01-07 16:37:03.094557-05 1 0 766 56 4 1 1 admin Initial User Added record 'expired1.expiry1.test A 192.168.2.23', TTL 5400, expires at 2025-12-24 18:30 2026-01-07 17:55:46.022401-05 0 0 767 57 4 1 1 admin Initial User Added record 'expired2.expiry1.test TXT imma expire soon', TTL 5400, expires at 2026-01-10 07:00 2026-01-07 17:57:07.015962-05 0 0 768 58 4 1 1 admin Initial User Added record 'active-after1.expiry1.test TXT not active yet', TTL 5400, valid after 2026-01-11 11:30 2026-01-07 18:12:57.491476-05 0 0 769 59 4 1 1 admin Initial User Added record 'active-after2.expiry1.test TXT I'm done waiting', TTL 5400, expires at 2025-12-31 14:00 2026-01-14 18:02:13.876839-05 0 0 770 60 5 1 1 admin Initial User Added active domain expiry2.test 2026-01-15 12:08:59.951774-05 0 0 771 61 5 1 1 admin Initial User [new expiry2.test] Added SOA record [contact ns1.example.com] [master hostmaster.expiry2.test] [refresh 10800] [retry 3600] [expire 604800] [minttl 5400], TTL 86400 2026-01-15 12:08:59.951774-05 0 60 772 62 5 1 1 admin Initial User [new expiry2.test] Added record 'expiry2.test NS ns2.example.com', TTL 7200 2026-01-15 12:08:59.951774-05 0 60 773 63 5 1 1 admin Initial User [new expiry2.test] Added record 'expiry2.test NS ns1.example.com', TTL 7200 2026-01-15 12:08:59.951774-05 0 60 774 64 5 1 1 admin Initial User [new expiry2.test] Added record 'expiry2.test A 10.0.0.4', TTL 7200 2026-01-15 12:08:59.951774-05 0 60 775 65 5 1 1 admin Initial User [new expiry2.test] Added record 'expiry2.test MX [distance 10] mx1.example.com', TTL 7200 2026-01-15 12:08:59.951774-05 0 60 776 66 5 1 1 admin Initial User [new expiry2.test] Added record 'www.expiry2.test CNAME expiry2.test', TTL 10800 2026-01-15 12:08:59.951774-05 0 60 777 67 5 1 1 admin Initial User [new expiry2.test] Added record 'expiry2.test TXT "v=spf1 a mx -all"', TTL 10800 2026-01-15 12:08:59.951774-05 0 60 778 68 5 1 1 admin Initial User Added record 'expires-at1.expiry2.test TXT Hanging around', TTL 5400 2026-01-15 12:57:28.411931-05 0 0 779 69 5 1 1 admin Initial User Added record 'expires-at2.expiry2.test TXT imma expire soon', TTL 5400, expires at 2026-01-15 18:00 2026-01-15 12:58:51.09629-05 0 0 780 70 5 1 1 admin Initial User Added record 'expires-at3.expiry2.test TXT active after pending expiry', TTL 5400, expires at 2026-01-15 18:00 2026-01-15 13:21:31.833257-05 0 0 781 71 5 1 1 admin Initial User Added record 'expires-at4.expiry2.test TXT active before pending expiry', TTL 5400, expires at 2026-01-15 18:00 2026-01-15 17:59:01.61806-05 0 0 782 72 5 1 1 admin Initial User Added record 'expires-at5.expiry2.test TXT expired before now', TTL 5400, expires at 2026-01-15 18:00 2026-01-16 11:50:43.678446-05 0 0 783 73 5 1 1 admin Initial User Added record 'valid-after1.expiry2.test TXT always here', TTL 5400 2026-01-16 13:36:36.066418-05 0 0 784 74 5 1 1 admin Initial User Added record 'valid-after2.expiry2.test TXT valid soon', TTL 5400, expires at 2026-01-15 18:00 2026-01-16 13:38:57.274666-05 0 0 785 75 5 1 1 admin Initial User Added record 'valid-after3.expiry2.test TXT valid days ago', TTL 5400, expires at 2026-01-15 18:00 2026-01-16 13:45:27.179614-05 0 0 786 76 5 1 1 admin Initial User Added record 'valid-after4.expiry2.test TXT valid quite soon', TTL 5400, expires at 2026-01-15 18:00 2026-01-19 11:40:07.438603-05 0 0 787 77 5 1 1 admin Initial User Added record 'valid-after5.expiry2.test TXT expires before pending valid', TTL 5400, expires at 2026-01-15 18:00 2026-01-19 11:40:55.325144-05 0 0 788 78 6 1 1 admin Initial User Added active domain expiry3.test 2026-01-29 18:05:53.678277-05 0 0 789 79 6 1 1 admin Initial User [new expiry3.test] Added SOA record [contact ns1.example.com] [master hostmaster.expiry3.test] [refresh 10800] [retry 3600] [expire 604800] [minttl 5400], TTL 86400 2026-01-29 18:05:53.678277-05 0 78 790 80 6 1 1 admin Initial User [new expiry3.test] Added record 'expiry3.test NS ns2.example.com', TTL 7200 2026-01-29 18:05:53.678277-05 0 78 791 81 6 1 1 admin Initial User [new expiry3.test] Added record 'expiry3.test NS ns1.example.com', TTL 7200 2026-01-29 18:05:53.678277-05 0 78 792 82 6 1 1 admin Initial User [new expiry3.test] Added record 'expiry3.test A 10.0.0.4', TTL 7200 2026-01-29 18:05:53.678277-05 0 78 793 83 6 1 1 admin Initial User [new expiry3.test] Added record 'expiry3.test MX [distance 10] mx1.example.com', TTL 7200 2026-01-29 18:05:53.678277-05 0 78 794 84 6 1 1 admin Initial User [new expiry3.test] Added record 'www.expiry3.test CNAME expiry3.test', TTL 10800 2026-01-29 18:05:53.678277-05 0 78 795 85 6 1 1 admin Initial User [new expiry3.test] Added record 'expiry3.test TXT "v=spf1 a mx -all"', TTL 10800 2026-01-29 18:05:53.678277-05 0 78 796 86 6 1 1 admin Initial User Added record 'nostamp1a.expiry3.test TXT target - expired', TTL 5400, expires at 2026-01-29 14:00 2026-01-30 15:07:08.695134-05 0 0 797 87 6 1 1 admin Initial User Added record 'nostamp2a.expiry3.test TXT target - soon to expire', TTL 5400, expires at 2026-01-31 14:00 2026-01-30 15:07:34.780671-05 0 0 798 88 6 1 1 admin Initial User Added record 'nostamp3a.expiry3.test TXT target - valid soon', TTL 5400, valid after 2026-01-31 14:00 2026-01-30 15:07:53.379107-05 0 0 799 89 6 1 1 admin Initial User Added record 'nostamp4a.expiry3.test TXT target - already valid', TTL 5400, valid after 2026-01-29 14:00 2026-01-30 15:08:15.4399-05 0 0 800 90 6 1 1 admin Initial User Added record 'nostamp1b.expiry3.test TXT to change', TTL 5400 2026-01-30 15:29:48.433198-05 0 0 801 91 6 1 1 admin Initial User Added record 'nostamp2b.expiry3.test TXT to change', TTL 5400 2026-01-30 15:29:53.902318-05 0 0 802 92 6 1 1 admin Initial User Added record 'nostamp3b.expiry3.test TXT to change', TTL 5400 2026-01-30 15:29:57.875273-05 0 0 803 93 6 1 1 admin Initial User Added record 'nostamp4b.expiry3.test TXT to change', TTL 5400 2026-01-30 15:30:01.924263-05 0 0 804 94 6 1 1 admin Initial User Added record 'expires1a.expiry3.test TXT target - no timestamp', TTL 5400 2026-02-03 12:02:32.883354-05 0 0 805 95 6 1 1 admin Initial User Added record 'expires2a.expiry3.test TXT target - expired', TTL 5400, expires at 2026-01-29 14:00 2026-02-03 12:03:09.031474-05 0 0 806 96 6 1 1 admin Initial User Added record 'expires3a.expiry3.test TXT target - expires soon', TTL 5400, expires at 2026-01-31 14:00 2026-02-03 12:04:30.954558-05 0 0 807 97 6 1 1 admin Initial User Added record 'expires4a.expiry3.test TXT target - valid soon', TTL 5400, valid after 2026-01-31 14:00 2026-02-03 12:04:52.864866-05 0 0 808 98 6 1 1 admin Initial User Added record 'expires5a.expiry3.test TXT target - already valid', TTL 5400, valid after 2026-01-29 14:00 2026-02-03 12:05:10.629373-05 0 0 809 99 6 1 1 admin Initial User Added record 'expires6a.expiry3.test TXT target - valid less soon', TTL 5400, valid after 2026-01-15 18:00 2026-02-03 12:05:31.096289-05 0 0 810 100 6 1 1 admin Initial User Added record 'expires1b.expiry3.test TXT to change', TTL 5400 2026-02-03 12:05:33.779645-05 0 0 811 101 6 1 1 admin Initial User Added record 'expires2b.expiry3.test TXT to change', TTL 5400 2026-02-03 12:05:44.12329-05 0 0 812 102 6 1 1 admin Initial User Added record 'expires3b.expiry3.test TXT to change', TTL 5400 2026-02-03 12:05:50.968888-05 0 0 813 103 6 1 1 admin Initial User Added record 'expires4b.expiry3.test TXT to change', TTL 5400 2026-02-03 12:05:56.415551-05 0 0 814 104 6 1 1 admin Initial User Added record 'expires5b.expiry3.test TXT to change', TTL 5400 2026-02-03 12:06:01.591204-05 0 0 815 105 6 1 1 admin Initial User Added record 'expires6b.expiry3.test TXT to change', TTL 5400 2026-02-03 12:06:34.192183-05 0 0 816 106 6 1 1 admin Initial User Added record 'validafter1a.expiry3.test TXT target - no timestamp', TTL 5400 2026-02-05 17:06:17.118891-05 0 0 817 107 6 1 1 admin Initial User Added record 'validafter2a.expiry3.test TXT target - expires in the future', TTL 5400, expires at 2026-02-05 17:30 2026-02-05 17:07:12.29965-05 0 0 818 108 6 1 1 admin Initial User Added record 'validafter3a.expiry3.test TXT target - expires soon', TTL 5400, expires at 2026-02-05 17:30 2026-02-05 17:07:49.064852-05 0 0 819 109 6 1 1 admin Initial User Added record 'validafter4a.expiry3.test TXT target - valid less soon', TTL 5400, valid after 2026-02-05 17:30 2026-02-05 17:14:01.474778-05 0 0 820 110 6 1 1 admin Initial User Added record 'validafter5a.expiry3.test TXT target - valid soon', TTL 5400, valid after 2026-02-05 17:30 2026-02-05 17:14:25.354496-05 0 0 821 111 6 1 1 admin Initial User Added record 'validafter1b.expiry3.test TXT to change', TTL 5400 2026-02-05 17:16:49.945082-05 0 0 822 112 6 1 1 admin Initial User Added record 'validafter2b.expiry3.test TXT to change', TTL 5400 2026-02-05 17:16:59.246035-05 0 0 823 113 6 1 1 admin Initial User Added record 'validafter3b.expiry3.test TXT to change', TTL 5400 2026-02-05 17:17:04.371248-05 0 0 824 114 6 1 1 admin Initial User Added record 'validafter4b.expiry3.test TXT to change', TTL 5400 2026-02-05 17:17:09.60198-05 0 0 825 115 6 1 1 admin Initial User Added record 'validafter5b.expiry3.test TXT to change', TTL 5400 2026-02-05 17:17:15.012334-05 0 0 826 116 7 1 1 admin Initial User Added active domain cname-blocks1.test 2026-02-18 18:00:14.727439-05 0 0 827 117 7 1 1 admin Initial User [new cname-blocks1.test] Added SOA record [contact ns1.example.com] [master hostmaster.cname-blocks1.test] [refresh 10800] [retry 3600] [expire 604800] [minttl 5400], TTL 86400 2026-02-18 18:00:14.727439-05 0 116 828 118 7 1 1 admin Initial User [new cname-blocks1.test] Added record 'cname-blocks1.test NS ns2.example.com', TTL 7200 2026-02-18 18:00:14.727439-05 0 116 829 119 7 1 1 admin Initial User [new cname-blocks1.test] Added record 'cname-blocks1.test NS ns1.example.com', TTL 7200 2026-02-18 18:00:14.727439-05 0 116 830 120 7 1 1 admin Initial User [new cname-blocks1.test] Added record 'cname-blocks1.test A 10.0.0.4', TTL 7200 2026-02-18 18:00:14.727439-05 0 116 831 121 7 1 1 admin Initial User [new cname-blocks1.test] Added record 'cname-blocks1.test MX [distance 10] mx1.example.com', TTL 7200 2026-02-18 18:00:14.727439-05 0 116 832 122 7 1 1 admin Initial User [new cname-blocks1.test] Added record 'www.cname-blocks1.test CNAME cname-blocks1.test', TTL 10800 2026-02-18 18:00:14.727439-05 0 116 833 123 7 1 1 admin Initial User [new cname-blocks1.test] Added record 'cname-blocks1.test TXT "v=spf1 a mx -all"', TTL 10800 2026-02-18 18:00:14.727439-05 0 116 834 124 7 1 1 admin Initial User Added record 'blocker01.cname-blocks1.test TXT I do not collide', TTL 5400 2026-02-18 18:00:35.918847-05 0 0 835 125 7 1 1 admin Initial User Added record 'blocker02.cname-blocks1.test CNAME target.example.com', TTL 5400 2026-02-18 18:00:54.003589-05 0 0 836 126 7 1 1 admin Initial User Added record 'blocker03.cname-blocks1.test CNAME target.example.com', TTL 5400, expires at 2026-02-20 20:20:00-05 2026-02-18 18:01:13.009519-05 0 0 837 127 7 1 1 admin Initial User Added record 'blocker04.cname-blocks1.test CNAME target.example.com', TTL 5400, valid after 2026-02-20 20:20:00-05 2026-02-18 18:01:24.142491-05 0 0 838 128 7 1 1 admin Initial User Added record 'blocker05.cname-blocks1.test CNAME target.example.com', TTL 5400 2026-02-18 18:02:22.263541-05 0 0 839 129 7 1 1 admin Initial User Added record 'blocker06.cname-blocks1.test CNAME target.example.com', TTL 5400, expires at 2026-02-20 20:20:00-05 2026-02-18 18:02:37.418389-05 0 0 840 130 7 1 1 admin Initial User Added record 'blocker07.cname-blocks1.test CNAME target.example.com', TTL 5400, valid after 2026-02-20 20:20:00-05 2026-02-18 18:02:47.023266-05 0 0 841 131 7 1 1 admin Initial User Added record 'blocker08.cname-blocks1.test CNAME target.example.com', TTL 5400, valid after 2026-02-20 20:20:00-05 2026-02-18 18:02:52.405397-05 0 0 842 132 7 1 1 admin Initial User Added record 'blocker09.cname-blocks1.test CNAME target.example.com', TTL 5400 2026-02-18 18:03:11.617403-05 0 0 843 133 7 1 1 admin Initial User Added record 'blocker10.cname-blocks1.test CNAME target.example.com', TTL 5400, expires at 2026-02-20 20:20:00-05 2026-02-18 18:03:25.888935-05 0 0 844 134 7 1 1 admin Initial User Added record 'blocker11.cname-blocks1.test CNAME target.example.com', TTL 5400, expires at 2026-02-20 20:20:00-05 2026-02-18 18:03:33.383937-05 0 0 845 135 7 1 1 admin Initial User Added record 'blocker12.cname-blocks1.test CNAME target.example.com', TTL 5400, valid after 2026-02-20 20:20:00-05 2026-02-18 18:03:41.441495-05 0 0 763 846 \. 764 847 … … 768 851 -- 769 852 770 SELECT pg_catalog.setval('public.log_log_id_seq', 55, true);853 SELECT pg_catalog.setval('public.log_log_id_seq', 135, true); 771 854 772 855 … … 855 938 0 45 imma blocker! 16 192.168.2.17 0 0 0 2560 \N 1 1969-12-31 19:00:00-05 f f \N 856 939 0 46 18-2.arpa.example.com 5 192.168.2.18 0 0 0 2560 \N 1 1969-12-31 19:00:00-05 f f \N 940 4 47 expired1.expiry1.test 1 192.168.2.23 0 0 0 5400 \N 0 2025-12-24 18:30:00-05 t t \N 941 4 48 expired2.expiry1.test 16 imma expire soon 0 0 0 5400 \N 0 2026-01-10 07:00:00-05 t t \N 942 4 49 active-after1.expiry1.test 16 not active yet 0 0 0 5400 \N 0 2026-01-11 11:30:00-05 f t \N 943 4 50 active-after2.expiry1.test 16 I'm done waiting 0 0 0 5400 \N 0 2025-12-31 14:00:00-05 f t \N 944 5 51 ns1.example.com:hostmaster.expiry2.test 6 10800:3600:604800:5400 0 0 0 86400 \N 0 1969-12-31 19:00:00-05 f f \N 945 5 52 expiry2.test 2 ns2.example.com 0 0 0 7200 \N 0 1969-12-31 19:00:00-05 f f \N 946 5 53 expiry2.test 2 ns1.example.com 0 0 0 7200 \N 0 1969-12-31 19:00:00-05 f f \N 947 5 54 expiry2.test 1 10.0.0.4 0 0 0 7200 \N 0 1969-12-31 19:00:00-05 f f \N 948 5 55 expiry2.test 15 mx1.example.com 10 0 0 7200 \N 0 1969-12-31 19:00:00-05 f f \N 949 5 56 www.expiry2.test 5 expiry2.test 0 0 0 10800 \N 0 1969-12-31 19:00:00-05 f f \N 950 5 57 expiry2.test 16 "v=spf1 a mx -all" 0 0 0 10800 \N 0 1969-12-31 19:00:00-05 f f \N 951 5 58 expires-at1.expiry2.test 16 Hanging around 0 0 0 5400 \N 0 1969-12-31 19:00:00-05 f f \N 952 5 59 expires-at2.expiry2.test 16 imma expire soon 0 0 0 5400 \N 0 2026-01-15 18:00:00-05 t t \N 953 5 60 expires-at3.expiry2.test 16 active after pending expiry 0 0 0 5400 \N 0 2026-01-15 18:00:00-05 f t \N 954 5 61 expires-at4.expiry2.test 16 active before pending expiry 0 0 0 5400 \N 0 2026-01-15 18:00:00-05 f t \N 955 5 62 expires-at5.expiry2.test 16 expired before now 0 0 0 5400 \N 0 2026-01-15 18:00:00-05 t t \N 956 5 63 valid-after1.expiry2.test 16 always here 0 0 0 5400 \N 0 1969-12-31 19:00:00-05 f f \N 957 5 64 valid-after2.expiry2.test 16 expires soon 0 0 0 5400 \N 0 2026-01-15 18:00:00-05 t t \N 958 5 65 valid-after3.expiry2.test 16 valid days ago 0 0 0 5400 \N 0 2026-01-15 18:00:00-05 f t \N 959 5 66 valid-after4.expiry2.test 16 valid quite soon 0 0 0 5400 \N 0 2026-01-15 18:00:00-05 f t \N 960 5 67 valid-after5.expiry2.test 16 expires before pending valid 0 0 0 5400 \N 0 2026-01-15 18:00:00-05 t t \N 961 6 68 ns1.example.com:hostmaster.expiry3.test 6 10800:3600:604800:5400 0 0 0 86400 \N 0 1969-12-31 19:00:00-05 f f \N 962 6 69 expiry3.test 2 ns2.example.com 0 0 0 7200 \N 0 1969-12-31 19:00:00-05 f f \N 963 6 70 expiry3.test 2 ns1.example.com 0 0 0 7200 \N 0 1969-12-31 19:00:00-05 f f \N 964 6 71 expiry3.test 1 10.0.0.4 0 0 0 7200 \N 0 1969-12-31 19:00:00-05 f f \N 965 6 72 expiry3.test 15 mx1.example.com 10 0 0 7200 \N 0 1969-12-31 19:00:00-05 f f \N 966 6 73 www.expiry3.test 5 expiry3.test 0 0 0 10800 \N 0 1969-12-31 19:00:00-05 f f \N 967 6 74 expiry3.test 16 "v=spf1 a mx -all" 0 0 0 10800 \N 0 1969-12-31 19:00:00-05 f f \N 968 6 75 nostamp1a.expiry3.test 16 target - expired 0 0 0 5400 \N 0 2026-01-29 14:00:00-05 t t \N 969 6 76 nostamp2a.expiry3.test 16 target - soon to expire 0 0 0 5400 \N 0 2026-01-31 14:00:00-05 t t \N 970 6 77 nostamp3a.expiry3.test 16 target - valid soon 0 0 0 5400 \N 0 2026-01-31 14:00:00-05 f t \N 971 6 78 nostamp4a.expiry3.test 16 target - already valid 0 0 0 5400 \N 0 2026-01-29 14:00:00-05 f t \N 972 6 79 nostamp1b.expiry3.test 16 to change 0 0 0 5400 \N 0 1969-12-31 19:00:00-05 f f \N 973 6 80 nostamp2b.expiry3.test 16 to change 0 0 0 5400 \N 0 1969-12-31 19:00:00-05 f f \N 974 6 81 nostamp3b.expiry3.test 16 to change 0 0 0 5400 \N 0 1969-12-31 19:00:00-05 f f \N 975 6 82 nostamp4b.expiry3.test 16 to change 0 0 0 5400 \N 0 1969-12-31 19:00:00-05 f f \N 976 6 83 expires1a.expiry3.test 16 target - no timestamp 0 0 0 5400 \N 0 1969-12-31 19:00:00-05 f f \N 977 6 84 expires2a.expiry3.test 16 target - expired 0 0 0 5400 \N 0 2026-01-29 14:00:00-05 t t \N 978 6 85 expires3a.expiry3.test 16 target - expires soon 0 0 0 5400 \N 0 2026-01-31 14:00:00-05 t t \N 979 6 86 expires4a.expiry3.test 16 target - valid soon 0 0 0 5400 \N 0 2026-01-31 14:00:00-05 f t \N 980 6 87 expires5a.expiry3.test 16 target - already valid 0 0 0 5400 \N 0 2026-01-29 14:00:00-05 f t \N 981 6 88 expires6a.expiry3.test 16 target - valid less soon 0 0 0 5400 \N 0 2026-01-29 14:00:00-05 f t \N 982 6 89 expires1b.expiry3.test 16 to change 0 0 0 5400 \N 0 1969-12-31 19:00:00-05 f f \N 983 6 90 expires2b.expiry3.test 16 to change 0 0 0 5400 \N 0 1969-12-31 19:00:00-05 f f \N 984 6 91 expires3b.expiry3.test 16 to change 0 0 0 5400 \N 0 1969-12-31 19:00:00-05 f f \N 985 6 92 expires4b.expiry3.test 16 to change 0 0 0 5400 \N 0 1969-12-31 19:00:00-05 f f \N 986 6 93 expires5b.expiry3.test 16 to change 0 0 0 5400 \N 0 1969-12-31 19:00:00-05 f f \N 987 6 94 expires6b.expiry3.test 16 to change 0 0 0 5400 \N 0 1969-12-31 19:00:00-05 f f \N 988 6 95 validafter1a.expiry3.test 16 target - no timestamp 0 0 0 5400 \N 0 1969-12-31 19:00:00-05 f f \N 989 6 96 validafter2a.expiry3.test 16 target - expires in the future 0 0 0 5400 \N 0 2026-02-05 17:30:00-05 t t \N 990 6 97 validafter3a.expiry3.test 16 target - expires soon 0 0 0 5400 \N 0 2026-02-05 17:30:00-05 t t \N 991 6 98 validafter4a.expiry3.test 16 target - valid less soon 0 0 0 5400 \N 0 2026-02-05 17:30:00-05 f t \N 992 6 99 validafter5a.expiry3.test 16 target - valid soon 0 0 0 5400 \N 0 2026-02-05 17:30:00-05 f t \N 993 6 100 validafter1b.expiry3.test 16 to change 0 0 0 5400 \N 0 1969-12-31 19:00:00-05 f f \N 994 6 101 validafter2b.expiry3.test 16 to change 0 0 0 5400 \N 0 1969-12-31 19:00:00-05 f f \N 995 6 102 validafter3b.expiry3.test 16 to change 0 0 0 5400 \N 0 1969-12-31 19:00:00-05 f f \N 996 6 103 validafter4b.expiry3.test 16 to change 0 0 0 5400 \N 0 1969-12-31 19:00:00-05 f f \N 997 6 104 validafter5b.expiry3.test 16 to change 0 0 0 5400 \N 0 1969-12-31 19:00:00-05 f f \N 998 7 105 ns1.example.com:hostmaster.cname-blocks1.test 6 10800:3600:604800:5400 0 0 0 86400 \N 0 1969-12-31 19:00:00-05 f f \N 999 7 106 cname-blocks1.test 2 ns2.example.com 0 0 0 7200 \N 0 1969-12-31 19:00:00-05 f f \N 1000 7 107 cname-blocks1.test 2 ns1.example.com 0 0 0 7200 \N 0 1969-12-31 19:00:00-05 f f \N 1001 7 108 cname-blocks1.test 1 10.0.0.4 0 0 0 7200 \N 0 1969-12-31 19:00:00-05 f f \N 1002 7 109 cname-blocks1.test 15 mx1.example.com 10 0 0 7200 \N 0 1969-12-31 19:00:00-05 f f \N 1003 7 110 www.cname-blocks1.test 5 cname-blocks1.test 0 0 0 10800 \N 0 1969-12-31 19:00:00-05 f f \N 1004 7 111 cname-blocks1.test 16 "v=spf1 a mx -all" 0 0 0 10800 \N 0 1969-12-31 19:00:00-05 f f \N 1005 7 112 blocker01.cname-blocks1.test 16 I do not collide 0 0 0 5400 \N 0 1969-12-31 19:00:00-05 f f \N 1006 7 113 blocker02.cname-blocks1.test 5 target.example.com 0 0 0 5400 \N 0 1969-12-31 19:00:00-05 f f \N 1007 7 114 blocker03.cname-blocks1.test 5 target.example.com 0 0 0 5400 \N 0 2026-02-20 20:20:00-05 t t \N 1008 7 115 blocker04.cname-blocks1.test 5 target.example.com 0 0 0 5400 \N 0 2026-02-20 20:20:00-05 f t \N 1009 7 116 blocker05.cname-blocks1.test 5 target.example.com 0 0 0 5400 \N 0 1969-12-31 19:00:00-05 f f \N 1010 7 117 blocker06.cname-blocks1.test 5 target.example.com 0 0 0 5400 \N 0 2026-02-20 20:20:00-05 t t \N 1011 7 118 blocker07.cname-blocks1.test 5 target.example.com 0 0 0 5400 \N 0 2026-02-20 20:20:00-05 f t \N 1012 7 119 blocker08.cname-blocks1.test 5 target.example.com 0 0 0 5400 \N 0 2026-02-20 20:20:00-05 f t \N 1013 7 120 blocker09.cname-blocks1.test 5 target.example.com 0 0 0 5400 \N 0 1969-12-31 19:00:00-05 f f \N 1014 7 121 blocker10.cname-blocks1.test 5 target.example.com 0 0 0 5400 \N 0 2026-02-20 20:20:00-05 t t \N 1015 7 122 blocker11.cname-blocks1.test 5 target.example.com 0 0 0 5400 \N 0 2026-02-20 20:20:00-05 t t \N 1016 7 123 blocker12.cname-blocks1.test 5 target.example.com 0 0 0 5400 \N 0 2026-02-20 20:20:00-05 f t \N 857 1017 \. 858 1018 … … 862 1022 -- 863 1023 864 SELECT pg_catalog.setval('public.records_record_id_seq', 46, true);1024 SELECT pg_catalog.setval('public.records_record_id_seq', 123, true); 865 1025 866 1026
Note:
See TracChangeset
for help on using the changeset viewer.
![[ DNS Administrator ]](/fx/dnsadmin-logo.png)