Changeset 725 for branches/stable
- Timestamp:
- 06/20/16 13:18:07 (9 years ago)
- Location:
- branches/stable
- Files:
-
- 9 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
branches/stable
-
branches/stable/DNSDB.pm
r696 r725 222 222 template_skip_0 => 0, # publish .0 by default 223 223 template_skip_255 => 0, # publish .255 by default 224 # allow TXT records to be dealt with mostly automatically by DNS server? 225 autotxt => 1, 224 226 ); 225 227 … … 252 254 # Several settings are booleans. Handle multiple possible ways of setting them. 253 255 for my $boolopt ('log_failures', 'force_refresh', 'lowercase', 'usecache', 254 'template_skip_0', 'template_skip_255' ) {256 'template_skip_0', 'template_skip_255', 'autotxt') { 255 257 if ($self->{$boolopt} ne '1' && $self->{$boolopt} ne '0') { 256 258 # true/false, on/off, yes/no all valid. … … 990 992 # Not strictly true, but SRV records not following this convention won't be found. 991 993 return ('FAIL',"SRV records must begin with _service._protocol [${$args{host}}]") 992 unless ${$args{host}} =~ /^_[A-Za-z ]+\._[A-Za-z]+\.[a-zA-Z0-9-]+/;994 unless ${$args{host}} =~ /^_[A-Za-z-]+\._[A-Za-z]+\.[a-zA-Z0-9-]+/; 993 995 994 996 # SRV target check - IP addresses not allowed. Must be a more or less well-formed hostname. … … 1852 1854 $cfg->{template_skip_0} = $1 if /^template_skip_0\s*=\s*([a-z01]+)/i; 1853 1855 $cfg->{template_skip_255} = $1 if /^template_skip_255\s*=\s*([a-z01]+)/i; 1856 $cfg->{autotxt} = $1 if /^autotxt\s*=\s*([a-z01]+)/i; 1854 1857 # not supported in dns.cgi yet 1855 1858 # $cfg->{templatedir} = $1 if m{^templatedir\s*=\s*([a-z0-9/_.-]+)}i; … … 2316 2319 # Add a domain 2317 2320 # Takes a database handle, domain name, numeric group, boolean(ish) state (active/inactive), 2318 # and user info hash (for logging).2321 # and a default location indicator 2319 2322 # Returns a status code and message 2320 2323 sub addDomain { … … 2341 2344 return ('FAIL', "Invalid characters in domain") if $domain !~ /^[a-zA-Z0-9_.-]+$/; 2342 2345 2343 my $sth = $dbh->prepare("SELECT domain_id FROM domains WHERE lower(domain) = lower(?) ");2346 my $sth = $dbh->prepare("SELECT domain_id FROM domains WHERE lower(domain) = lower(?) AND default_location = ?"); 2344 2347 my $dom_id; 2345 2348 2346 2349 # quick check to start to see if we've already got one 2347 $sth->execute($domain );2350 $sth->execute($domain, $defloc); 2348 2351 ($dom_id) = $sth->fetchrow_array; 2349 2352 … … 2362 2365 2363 2366 # get the ID... 2364 ($dom_id) = $dbh->selectrow_array("SELECT domain_id FROM domains WHERE lower(domain) = lower(?) ",2365 undef, ($domain ));2367 ($dom_id) = $dbh->selectrow_array("SELECT domain_id FROM domains WHERE lower(domain) = lower(?) AND default_location = ?", 2368 undef, ($domain, $defloc)); 2366 2369 2367 2370 $self->_log(domain_id => $dom_id, group_id => $group, … … 2537 2540 my $dbh = $self->{dbh}; 2538 2541 my $domain = shift; 2539 my ($domid) = $dbh->selectrow_array("SELECT domain_id FROM domains WHERE lower(domain) = lower(?)", 2540 undef, ($domain) ); 2542 my $location = shift; 2543 2544 # Note that location may be *empty*, but it may not be *undefined* 2545 if (!defined($location)) { 2546 $errstr = "Missing location"; 2547 return; 2548 } 2549 2550 my ($domid) = $dbh->selectrow_array( 2551 "SELECT domain_id FROM domains WHERE lower(domain) = lower(?) AND default_location = ?", 2552 undef, ($domain, $location) ); 2541 2553 if (!$domid) { 2542 2554 if ($dbh->err) { … … 2558 2570 my $dbh = $self->{dbh}; 2559 2571 my $revzone = shift; 2560 my ($revid) = $dbh->selectrow_array("SELECT rdns_id FROM revzones WHERE revnet=?", undef, ($revzone) ); 2572 my $location = shift; 2573 2574 # Note that location may be *empty*, but it may not be *undefined* 2575 if (!defined($location)) { 2576 $errstr = "Missing location"; 2577 return; 2578 } 2579 2580 my ($revid) = $dbh->selectrow_array( 2581 "SELECT rdns_id FROM revzones WHERE revnet = ? AND default_location = ?", 2582 undef, ($revzone, $location) ); 2561 2583 if (!$revid) { 2562 2584 if ($dbh->err) { … … 2602 2624 2603 2625 # quick check to start to see if we've already got one 2604 my ($rdns_id) = $dbh->selectrow_array("SELECT rdns_id FROM revzones WHERE revnet=?", undef, ("$zone")); 2626 my ($rdns_id) = $dbh->selectrow_array("SELECT rdns_id FROM revzones WHERE revnet = ? AND default_location = ?", 2627 undef, ("$zone", $defloc)); 2605 2628 2606 2629 return ('FAIL', "Zone already exists") if $rdns_id; … … 2843 2866 if ($args{revrec} eq 'n') { 2844 2867 $args{sortby} = 'domain' if !$args{sortby} || !grep /^$args{sortby}$/, ('domain','group','status'); 2845 $sql = "SELECT domain_id AS zoneid,domain AS zone,status,groups.group_name AS group FROM domains". 2846 " INNER JOIN groups ON domains.group_id=groups.group_id". 2847 " WHERE domains.group_id IN ($args{curgroup}".($args{childlist} ? ",$args{childlist}" : '').")". 2868 $sql = q(SELECT 2869 domain_id AS zoneid, 2870 domain AS zone, 2871 status, 2872 groups.group_name AS group, 2873 l.description AS location 2874 FROM domains 2875 LEFT JOIN locations l ON domains.default_location=l.location 2876 INNER JOIN groups ON domains.group_id=groups.group_id ). 2877 "WHERE domains.group_id IN ($args{curgroup}".($args{childlist} ? ",$args{childlist}" : '').")". 2848 2878 ($args{startwith} ? " AND domain ~* ?" : ''). 2849 2879 ($args{filter} ? " AND domain ~* ?" : ''); … … 2851 2881 ##fixme: arguably startwith here is irrelevant. depends on the UI though. 2852 2882 $args{sortby} = 'revnet' if !$args{sortby} || !grep /^$args{sortby}$/, ('revnet','group','status'); 2853 $sql = "SELECT rdns_id AS zoneid,revnet AS zone,status,groups.group_name AS group FROM revzones". 2854 " INNER JOIN groups ON revzones.group_id=groups.group_id". 2883 $sql = q(SELECT 2884 rdns_id AS zoneid, 2885 revnet AS zone, 2886 status, 2887 groups.group_name AS group, 2888 l.description AS location 2889 FROM revzones 2890 LEFT JOIN locations l ON revzones.default_location=l.location 2891 INNER JOIN groups ON revzones.group_id=groups.group_id ). 2855 2892 " WHERE revzones.group_id IN ($args{curgroup}".($args{childlist} ? ",$args{childlist}" : '').")". 2856 2893 ($args{startwith} ? " AND CAST(revnet AS VARCHAR) ~* ?" : ''); … … 3472 3509 my $sel = shift || 0; 3473 3510 3474 my $sth = $dbh->prepare("SELECT username,user_id FROM users WHERE group_id=? ");3511 my $sth = $dbh->prepare("SELECT username,user_id FROM users WHERE group_id=? AND password <> 'RPC'"); 3475 3512 $sth->execute($grp); 3476 3513 … … 3689 3726 my $self = shift; 3690 3727 my $dbh = $self->{dbh}; 3691 my $grp = shift; 3692 my $shdesc = shift; 3693 my $comments = shift; 3694 my $iplist = shift; 3728 my %args = @_; 3729 3730 my $grp = $args{group}; 3731 my $shdesc = $args{desc}; 3732 my $comments = $args{comments}; 3733 my $iplist = $args{iplist}; 3695 3734 3696 3735 # $shdesc gets set to the generated location ID if possible, but these can be de-undefined here. … … 3698 3737 $iplist = '' if !$iplist; 3699 3738 3700 my $loc; 3739 # allow requesting a specific location entry. 3740 my $loc = $args{loc}; 3701 3741 3702 3742 # Generate a location ID. This is, by spec, a two-character widget. We'll use [a-z][a-z] 3703 3743 # for now; 676 locations should satisfy all but the largest of the huge networks. 3704 # Not sure whether these are case-sensitive, or what other rules might apply - in any case 3705 # the absolute maximum is 16K (256*256) since it's parsed by tinydns as a two-character field. 3744 3745 # just to be as clear as possible; as per http://cr.yp.to/djbdns/tinydns-data.html: 3746 3747 #For versions 1.04 and above: You may include a client location on each line. The line is ignored for clients 3748 #outside that location. Client locations are specified by % lines: 3749 # 3750 # %lo:ipprefix 3751 # 3752 #means that IP addresses starting with ipprefix are in location lo. lo is a sequence of one or two ASCII letters. 3753 3754 # this has been confirmed by experiment; locations "lo", "Lo", and "lO" are all distinct. 3706 3755 3707 3756 # add just after "my $origloc = $loc;": … … 3725 3774 eval { 3726 3775 # Get the "last" location. Note this is the only use for loc_id, because selecting on location Does Funky Things 3727 ($loc) = $dbh->selectrow_array("SELECT location FROM locations ORDER BY loc_id DESC LIMIT 1"); 3728 ($loc) = ($loc =~ /^(..)/) if $loc; 3729 my $origloc = $loc; 3730 $loc = 'aa' if !$loc; 3776 my ($newloc) = $dbh->selectrow_array("SELECT location FROM locations ORDER BY loc_id DESC LIMIT 1"); 3777 3778 no warnings qw(uninitialized); 3779 3780 my $ecnt = $dbh->prepare("SELECT count(*) FROM locations WHERE location LIKE ?"); 3781 3782 if ($loc) { 3783 $ecnt->execute($loc); 3784 if (($ecnt->fetchrow_array())[0]) { 3785 # too bad, so sad, requested location is unavailable. 3786 ##fixme: known failure case: caller requests a location ID that is not two characters. 3787 die "Requested location is already defined\n" if $args{reqonly}; 3788 # fall back to autoincrement 3789 } 3790 $newloc = $loc; 3791 } 3792 3793 # Either the requested location ID is unavailable and the caller isn't too attached 3794 # to it, OR, the caller hasn't specified a location ID. (The second case should be 3795 # far more common.) Find the "next available" location identifier. 3796 3797 ($newloc) = ($newloc =~ /^(..)/) if $newloc; 3798 my $origloc = $newloc; 3799 $newloc = 'aa' if !$newloc; 3731 3800 # Make a change... 3732 $loc++;3733 3801 # ... and keep changing if it exists 3734 while ($dbh->selectrow_array("SELECT count(*) FROM locations WHERE location LIKE ?", undef, ($ loc.'%'))) {3735 $ loc++;3736 ($ loc) = ($loc =~ /^(..)/);3737 die "too many locations in use, can't add another one\n" if $ loc eq $origloc;3802 while ($dbh->selectrow_array("SELECT count(*) FROM locations WHERE location LIKE ?", undef, ($newloc.'%'))) { 3803 $newloc++; 3804 ($newloc) = ($newloc =~ /^(..)/); 3805 die "too many locations in use, can't add another one\n" if $newloc eq $origloc; 3738 3806 ##fixme: really need to handle this case faster somehow 3739 3807 #if $loc eq $origloc die "<thwap> bad admin: all locations used, your network is too fragmented"; 3740 3808 } 3741 # And now we should have a unique location. tinydns fundamentally limits the 3742 # number of these but there's no doc on what characters are valid. 3743 $shdesc = $loc if !$shdesc; 3809 # And now we should have a unique location. 3810 $shdesc = $newloc if !$shdesc; 3744 3811 $dbh->do("INSERT INTO locations (location, group_id, iplist, description, comments) VALUES (?,?,?,?,?)", 3745 undef, ($ loc, $grp, $iplist, $shdesc, $comments) );3812 undef, ($newloc, $grp, $iplist, $shdesc, $comments) ); 3746 3813 $self->_log(entry => "Added location ($shdesc, '$iplist')"); 3814 $loc = $newloc; 3747 3815 $dbh->commit; 3748 3816 }; … … 4140 4208 $args{defrec} = 'n' if !$args{defrec}; 4141 4209 4210 # RPC callers generally want the "true" IP. Flag argument for those to bypass showrev_arpa 4211 ##fixme: this will still blow up if some idiot has actually stored .arpa names in the DB. 4212 # ... do we care? 4213 $args{rpc} = 0 if !$args{rpc}; 4214 4142 4215 # protection against bad or missing arguments 4143 4216 $args{sortorder} = 'ASC' if !$args{sortorder} || !grep /^$args{sortorder}$/, ('ASC','DESC'); … … 4150 4223 $args{offset} = 0 if !$args{offset} || $args{offset} !~ /^(?:all|\d+)$/; 4151 4224 my $perpage = ($args{nrecs} ? $args{nrecs} : $self->{perpage}); 4152 4153 4225 4154 4226 ##fixme: do we need a knob to twist to switch from unix epoch to postgres time string? … … 4181 4253 4182 4254 # Filtering on other fields 4183 foreach (qw(type distance weight port ttl description )) {4255 foreach (qw(type distance weight port ttl description location)) { 4184 4256 if ($args{$_}) { 4185 $sql .= " AND $_ ~* ?";4257 $sql .= " AND r.$_ ~* ?"; 4186 4258 push @bindvars, $args{$_}; 4187 4259 } … … 4212 4284 $recsth->execute(@bindvars); 4213 4285 while (my $rec = $recsth->fetchrow_hashref) { 4214 if ( $args{revrec} eq 'y' && $args{defrec} eq 'n' &&4286 if (!$args{rpc} && $args{revrec} eq 'y' && $args{defrec} eq 'n' && 4215 4287 ($self->{showrev_arpa} eq 'record' || $self->{showrev_arpa} eq 'all') && 4216 4288 $rec->{val} !~ /\.arpa$/ ) { … … 4818 4890 my $dbh = $self->{dbh}; 4819 4891 my $cidr = shift; 4820 my $group = shift || 1; # just in case 4892 my %args = @_; 4893 $args{group} = 1 if !$args{group}; # just in case 4894 $args{location} = '' if !$args{location}; 4821 4895 4822 4896 # for speed! Casting and comparing even ~7K records takes ~2.5s, so narrow it down to one revzone first. … … 4826 4900 ##fixme? may need to narrow things down more by octet-chopping and doing text comparisons before casting. 4827 4901 my ($revpatt) = $dbh->selectrow_array("SELECT host FROM records ". 4828 "WHERE (type in (12,65280,65281,65282,65283,65284)) AND rdns_id = ? AND inetlazy(val) >>= ? ". 4829 "ORDER BY inetlazy(val) DESC LIMIT 1", undef, ($revid, $cidr) ); 4902 "WHERE (type in (12,65280,65281,65282,65283,65284)) AND rdns_id = ? ". 4903 "AND location = ? AND inetlazy(val) >>= ? ". 4904 "ORDER BY inetlazy(val) DESC LIMIT 1", 4905 undef, ($revid, $args{location}, $cidr) ); 4906 4830 4907 return $revpatt; 4831 4908 } # end getRevPattern() … … 4839 4916 my $dbh = $self->{dbh}; 4840 4917 my $cidr = shift; 4841 my $group = shift || 1; # just in case 4918 my %args = @_; 4919 $args{group} = 1 if !$args{group}; # just in case 4920 $args{location} = '' if !$args{location}; 4842 4921 4843 4922 # for speed! Casting and comparing even ~7K records takes ~2.5s, so narrow it down to one revzone first. … … 4855 4934 4856 4935 my $sth = $dbh->prepare("SELECT val, host FROM records ". 4857 "WHERE (type in (12,65280,65281,65282,65283,65284)) AND rdns_id = ? AND inetlazy(val) = ?");4936 "WHERE (type in (12,65280,65281,65282,65283,65284)) AND rdns_id = ? AND location = ? AND inetlazy(val) = ?"); 4858 4937 4859 4938 my @ret; 4860 4939 foreach my $ip (@{$cidr->splitref()}) { 4861 $sth->execute($revid, $ ip);4940 $sth->execute($revid, $args{location}, $ip); 4862 4941 my @data = $sth->fetchrow_array(); 4863 4942 my %row; … … 5127 5206 ## DNSDB::getZonesByCIDR() 5128 5207 # Get a list of zone names and IDs that records for a passed CIDR block are within. 5208 # Optionally restrict to a specific location/view 5209 # Optionally leave off the default_location field 5129 5210 sub getZonesByCIDR { 5130 5211 my $self = shift; 5131 5212 my $dbh = $self->{dbh}; 5132 5213 my %args = @_; 5133 5134 my $result = $dbh->selectall_arrayref("SELECT rdns_id,revnet FROM revzones WHERE revnet >>= ? OR revnet <<= ?", 5135 { Slice => {} }, ($args{cidr}, $args{cidr}) ); 5214 $args{return_location} = 1 if !defined($args{return_location}); 5215 5216 my $sql = "SELECT rdns_id,revnet".($args{return_location} ? ',default_location' : ''). 5217 " FROM revzones WHERE (revnet >>= ? OR revnet <<= ?)". 5218 (defined($args{location}) ? " AND default_location = ?" : ''); 5219 my @svals = ($args{cidr}, $args{cidr}); 5220 push @svals, $args{location} if defined $args{location}; 5221 5222 my $result = $dbh->selectall_arrayref($sql, { Slice => {} }, @svals ); 5136 5223 return $result; 5137 5224 } # end getZonesByCIDR() … … 5295 5382 ##fixme: serial 5296 5383 $dbh->do("INSERT INTO domains (domain,group_id,status) VALUES (?,?,?)", undef, 5297 ($zone, $group, $args{status}) ) ;5384 ($zone, $group, $args{status}) ) or die $dbh->errstr; 5298 5385 # get domain id so we can do the records 5299 5386 ($zone_id) = $dbh->selectrow_array("SELECT currval('domains_domain_id_seq')"); … … 6222 6309 6223 6310 ($host,$val) = __revswap($host,$val) if $revrec eq 'y'; 6224 ##fixme: split v-e-r-y long TXT strings? will need to do so for BIND export, at least 6225 $val =~ s/:/\\072/g; # may need to replace other symbols 6226 print $datafile "'$host:$val:$ttl:$stamp:$loc\n" or die $!; 6311 # le sigh. Some idiot DNS implementations don't seem to like tinydns autosplitting 6312 # long TXT records at 127 characters instead of 255. Hand-crafting a record seems 6313 # to paper over the remote stupid. We will NOT try to split on whitespace; the 6314 # contents of a TXT record are opaque and clients who can't deal are even more broken 6315 # than the ones that don't like them split at 127 characters... because BIND tries 6316 # to "intelligently" split TXT data, and abso-by-damn-lutely generates chunks <255 6317 # characters, and anything that can't interpret BIND's DNS responses has no business 6318 # trying to interpret DNS data at all. 6319 6320 if ($self->{autotxt}) { 6321 # let tinydns deal with splitting the record. note tinydns autosplits at 127 6322 # characters, not 255. Because Reasons. 6323 $val =~ s/:/\\072/g; # may need to replace other symbols 6324 print $datafile "'$host:$val:$ttl:$stamp:$loc\n" or die $!; 6325 } else { 6326 print $datafile ":$host:16:"; 6327 my @txtsegs = $val =~ /.{1,255}/g; 6328 foreach (@txtsegs) { 6329 my $len = length($_); 6330 s/:/\\072/g; 6331 printf $datafile "\\%0.3o%s", $len, $_; 6332 } 6333 print $datafile ":$ttl:$stamp:$loc\n"; 6334 } 6227 6335 6228 6336 # by-hand TXT -
branches/stable/Makefile
r696 r725 3 3 4 4 PKGNAME=dnsadmin 5 VERSION=1.2. 5p25 VERSION=1.2.6 6 6 RELEASE=1 7 7 … … 46 46 INSTALL COPYING TODO Makefile dnsadmin.spec \ 47 47 \ 48 dns.sql dns-1.0-1.2.sql dns-1.2.3-1.2.4.sql \48 dns.sql dns-1.0-1.2.sql dns-1.2.3-1.2.4.sql dns-upd-1.2.6.sql\ 49 49 \ 50 50 $(SCRIPTS) $(MODULES) \ -
branches/stable/dns-rpc.cgi
r690 r725 137 137 ## 138 138 139 ## 140 ## Internal utility subs 141 ## 142 139 143 # Check RPC ACL 140 144 sub _aclcheck { … … 174 178 } 175 179 176 # set ttl to zone defa ilt minttl if none is specified180 # set ttl to zone default minttl if none is specified 177 181 sub _ttlcheck { 178 182 my $argref = shift; … … 182 186 } 183 187 } 188 189 # Check if the hashrefs passed in refer to identical record data, so we can skip 190 # the actual update if nothing has actually changed. This is mainly useful for 191 # reducing log noise due to chained calls orginating with updateRevSet() since 192 # "many" records could be sent for update but only one or two have actually changed. 193 sub _checkRecMod { 194 my $oldrec = shift; 195 my $newrec = shift; 196 197 # Because we don't know which fields we've even been passed 198 no warnings qw(uninitialized); 199 200 my $modflag = 0; 201 # order by most common change. host should be first, due to rDNS RPC calls 202 for my $field qw(host type val) { 203 return 1 if ( 204 defined($newrec->{$field}) && 205 $oldrec->{$field} ne $newrec->{$field} ); 206 } 207 208 return 0; 209 } # _checRecMod 210 211 212 ## 213 ## Shims for DNSDB core subs 214 ## 184 215 185 216 #sub connectDB { … … 215 246 ($code,$msg) = $dnsdb->delZone($args{zone}, $args{revrec}); 216 247 } else { 248 die "Need zone location\n" if !defined($args{location}); 217 249 my $zoneid; 218 $zoneid = $dnsdb->domainID($args{zone} ) if $args{revrec} eq 'n';219 $zoneid = $dnsdb->revID($args{zone} ) if $args{revrec} eq 'y';250 $zoneid = $dnsdb->domainID($args{zone}, $args{location}) if $args{revrec} eq 'n'; 251 $zoneid = $dnsdb->revID($args{zone}, $args{location}) if $args{revrec} eq 'y'; 220 252 die "Can't find zone: ".$dnsdb->errstr."\n" if !$zoneid; 221 253 ($code,$msg) = $dnsdb->delZone($zoneid, $args{revrec}); … … 233 265 _commoncheck(\%args, 'y'); 234 266 235 my $domid = $dnsdb->domainID($args{domain} );267 my $domid = $dnsdb->domainID($args{domain}, $args{location}); 236 268 die $dnsdb->errstr."\n" if !$domid; 237 269 return $domid; … … 419 451 die "Missing zone ID\n" if !$args{id}; 420 452 453 # caller may not know about zone IDs. accept the zone name, but require a location if so 454 if ($args{id} !~ /^\d+$/) { 455 die "Location required to use the zone name\n" if !defined($args{location}); 456 } 457 421 458 # set some optional args 422 459 $args{offset} = 0 if !$args{offset}; … … 430 467 if ($args{defrec} eq 'n') { 431 468 if ($args{revrec} eq 'n') { 432 $args{id} = $dnsdb->domainID($args{id} ) if $args{id} !~ /^\d+$/;469 $args{id} = $dnsdb->domainID($args{id}, $args{location}) if $args{id} !~ /^\d+$/; 433 470 } else { 434 $args{id} = $dnsdb->revID($args{id} ) if $args{id} !~ /^\d+$/471 $args{id} = $dnsdb->revID($args{id}, $args{location}) if $args{id} !~ /^\d+$/ 435 472 } 436 473 } … … 454 491 455 492 _reccheck(\%args); 493 494 # caller may not know about zone IDs. accept the zone name, but require a location if so 495 if ($args{id} !~ /^\d+$/) { 496 die "Location required to use the zone name\n" if !defined($args{location}); 497 } 456 498 457 499 # set some optional args … … 462 504 $args{direction} = 'ASC' if !$args{direction}; 463 505 506 # convert zone name to zone ID, if needed 507 if ($args{defrec} eq 'n') { 508 if ($args{revrec} eq 'n') { 509 $args{id} = $dnsdb->domainID($args{id}, $args{location}) if $args{id} !~ /^\d+$/; 510 } else { 511 $args{id} = $dnsdb->revID($args{id}, $args{location}) if $args{id} !~ /^\d+$/ 512 } 513 } 514 515 # fail if we *still* don't have a valid zone ID 516 die $dnsdb->errstr."\n" if !$args{id}; 517 464 518 my $ret = $dnsdb->getRecCount(defrec => $args{defrec}, revrec => $args{revrec}, 465 519 id => $args{id}, filter => $args{filter}); … … 468 522 469 523 return $ret; 470 } 524 } # getRecCount() 471 525 472 526 # The core sub uses references for some arguments to allow limited modification for … … 534 588 } # rpc_updateRec 535 589 590 536 591 # Takes a passed CIDR block and DNS pattern; adds a new record or updates the record(s) affected 537 592 sub addOrUpdateRevRec { … … 541 596 my $cidr = new NetAddr::IP $args{cidr}; 542 597 543 ##fixme: Minor edge case; if we receive calls one after the other to update 544 # to the same thing, we bulk out the log with useless notices. Leaving this 545 # for future development since this should be rare in practice. 598 # Location required so we don't turn up unrelated zones in getZonesByCIDR(). 599 # Caller should generally have some knowledge of this. 600 die "Need location\n" if !defined($args{location}); 546 601 547 602 my $zonelist = $dnsdb->getZonesByCIDR(%args); … … 552 607 my $zone = new NetAddr::IP $zonelist->[0]->{revnet}; 553 608 if ($zone->contains($cidr)) { 554 # We need to strip the CIDR mask on IPv4 /32 assignments, or we just add a new record all the time. 555 my $filt = ($cidr->{isv6} || $cidr->masklen != 32 ? "$cidr" : $cidr->addr); 556 my $reclist = $dnsdb->getRecList(defrec => 'n', revrec => 'y', 609 # We need to strip the CIDR mask on IPv4 /32 or v6 /128 assignments, or we just add a new record all the time. 610 my $filt = ( $cidr->{isv6} ? ($cidr->masklen != 128 ? "$cidr" : $cidr->addr) : 611 ($cidr->masklen != 32 ? "$cidr" : $cidr->addr) ); 612 my $reclist = $dnsdb->getRecList(rpc => 1, defrec => 'n', revrec => 'y', 557 613 id => $zonelist->[0]->{rdns_id}, filter => $filt); 558 614 ##fixme: Figure some new magic to automerge new incoming A(AAA)+PTR requests … … 570 626 || $rec->{type} == 65282 || $rec->{type} == 65283 || $rec->{type} == 65284; 571 627 next unless $rec->{val} eq $filt; # make sure we really update the record we want to update. 628 # canonicalize the IP values so funny IPv6 short forms don't 629 # cause non-updates by not being literally string-equal 630 $rec->{val} = new NetAddr::IP $rec->{val}; 631 my $tmpcidr = new NetAddr::IP $args{cidr}; 632 my %newrec = (host => $args{name}, val => $tmpcidr, type => $args{type}); 572 633 rpc_updateRec(defrec =>'n', revrec => 'y', id => $rec->{record_id}, 573 parent_id => $zonelist->[0]->{rdns_id}, address => "$cidr", %args); 634 parent_id => $zonelist->[0]->{rdns_id}, address => "$cidr", %args) 635 if _checkRecMod($rec, \%newrec); # and only do the update if there really is something to change 574 636 $flag = 1; 575 637 last; # only do one record. … … 590 652 # that spans multiple reverse zones (eg, /23 CIDR -> 2 /24 rzones) 591 653 foreach my $zdata (@$zonelist) { 592 my $reclist = $dnsdb->getRecList( defrec => 'n', revrec => 'y',654 my $reclist = $dnsdb->getRecList(rpc => 1, defrec => 'n', revrec => 'y', 593 655 id => $zdata->{rdns_id}, filter => $zdata->{revnet}); 594 656 if (scalar(@$reclist) == 0) { … … 597 659 address => "$args{cidr}", %args); 598 660 } else { 661 my $updflag = 0; 599 662 foreach my $rec (@$reclist) { 600 663 # only the composite and/or template types; pure PTR or nontemplate composite 601 664 # types are nominally impossible here. 602 665 next unless $rec->{type} == 65282 || $rec->{type} == 65283 || $rec->{type} == 65284; 666 my %newrec = (host => $args{name}, val => $zdata->{revnet}, type => $args{type}); 603 667 rpc_updateRec(defrec => 'n', revrec => 'y', id => $rec->{record_id}, 604 parent_id => $zdata->{rdns_id}, %args); 668 parent_id => $zdata->{rdns_id}, %args) 669 if _checkRecMod($rec, \%newrec); # and only do the update if there really is something to change 670 $updflag = 1; 605 671 last; # only do one record. 606 672 } 607 } 673 # catch the case of "oops, no zone-sized template record and need to add a new one", 674 # because the SOA and NS records will be returned from the getRecList() call above 675 unless ($updflag) { 676 my $type = ($cidr->{isv6} ? 65284 : 65283); 677 rpc_addRec(defrec => 'n', revrec => 'y', parent_id => $zdata->{rdns_id}, type => $type, 678 address => $zdata->{revnet}, %args); 679 } 680 } # scalar(@$reclist) != 0 608 681 } # iterate zones within $cidr 609 682 } # done $cidr-contains-zones … … 623 696 next unless $key =~ m{^host_((?:[\d.]+|[\da-f:]+)(?:/\d+)?)$}; 624 697 my $ip = $1; 625 push @ret, addOrUpdateRevRec(cidr => $ip, name => $args{$key}, %args); 626 } 698 push @ret, addOrUpdateRevRec(%args, cidr => $ip, name => $args{$key}); 699 } 700 701 # now we check the parts of the block that didn't get passed to see if they should be deleted 702 my $block = new NetAddr::IP $args{cidr}; 703 if (!$block->{isv6}) { 704 foreach my $ip (@{$block->splitref(32)}) { 705 my $bare = $ip->addr; 706 next if $args{"host_$bare"}; 707 delByCIDR(delforward => 1, delsubs => 0, cidr => $bare, location => $args{location}, 708 rpcuser => $args{rpcuser}, rpcsystem => $args{rpcsystem}); 709 } 710 } 711 627 712 ##fixme: what about errors? what about warnings? 628 713 return \@ret; … … 637 722 638 723 my $cidr = new NetAddr::IP $args{cidr}; 724 725 # Location required so we don't turn up unrelated zones in getZonesByCIDR(). 726 # Caller should generally have some knowledge of this. 727 die "Need location\n" if !defined($args{location}); 639 728 640 729 my $zonelist = $dnsdb->getZonesByCIDR(%args); … … 647 736 if ($zone->contains($cidr)) { 648 737 # Find the first record in the reverse zone that matches the CIDR we're splitting... 649 my $reclist = $dnsdb->getRecList( defrec => 'n', revrec => 'y',738 my $reclist = $dnsdb->getRecList(rpc => 1, defrec => 'n', revrec => 'y', 650 739 id => $zonelist->[0]->{rdns_id}, filter => $cidr, sortby => 'val', sortorder => 'DESC'); 651 740 my $oldrec; … … 706 795 707 796 my $up_res; 797 798 # Location required so we don't turn up unrelated zones in getZonesByCIDR(). 799 # Caller should generally have some knowledge of this. 800 die "Need location\n" if !defined($args{location}); 708 801 709 802 my $zonelist = $dnsdb->getZonesByCIDR(%args); … … 769 862 my @retlist; 770 863 771 my $zsth = $dnsdb->{dbh}->prepare("SELECT rdns_id,group_id FROM revzones WHERE revnet >>= ?"); 864 # Location required so we don't turn up unrelated zones 865 die "Need location\n" if !defined($args{location}); 866 867 my $zsth = $dnsdb->{dbh}->prepare("SELECT rdns_id,group_id FROM revzones WHERE revnet >>= ? AND location = ?"); 772 868 # Going to assume template records with no expiry 773 869 # Also note IPv6 template records don't expand sanely the way v4 records do … … 792 888 eval { 793 889 foreach my $template (@{$args{templates}}) { 794 $zsth->execute($template );890 $zsth->execute($template, $args{location}); 795 891 my ($zid,$zgrp) = $zsth->fetchrow_array; 796 892 if (!$zid) { … … 851 947 # Caller may pass 'n' in delsubs. Assume it should be false/undefined 852 948 # unless the caller explicitly requested 'yes' 853 $args{delsubs} = 0 if $args{delsubs} ne 'y';949 $args{delsubs} = 0 if !$args{delsubs} || $args{delsubs} ne 'y'; 854 950 855 951 # Don't delete the A component of an A+PTR by default 856 952 $args{delforward} = 0 if !$args{delforward}; 953 954 # Location required so we don't turn up unrelated zones in getZonesByCIDR(). 955 die "Need location\n" if !defined($args{location}); 857 956 858 957 # much like addOrUpdateRevRec() … … 869 968 if ($args{delsubs}) { 870 969 # Delete ALL EVARYTHING!!one11!! in $args{cidr} 871 my $reclist = $dnsdb->getRecList( defrec => 'n', revrec => 'y', id => $zonelist->[0]->{rdns_id});970 my $reclist = $dnsdb->getRecList(rpc => 1, defrec => 'n', revrec => 'y', id => $zonelist->[0]->{rdns_id}); 872 971 foreach my $rec (@$reclist) { 873 972 my $reccidr = new NetAddr::IP $rec->{val}; … … 895 994 # Selectively delete only exact matches on $args{cidr} 896 995 # We need to strip the CIDR mask on IPv4 /32 assignments, or we can't find single-IP records 897 my $filt = ($cidr->{isv6} || $cidr->masklen != 32 ? "$cidr" : $cidr->addr); 898 my $reclist = $dnsdb->getRecList(defrec => 'n', revrec => 'y', 996 my $filt = ( $cidr->{isv6} ? ($cidr->masklen != 128 ? "$cidr" : $cidr->addr) : 997 ($cidr->masklen != 32 ? "$cidr" : $cidr->addr) ); 998 my $reclist = $dnsdb->getRecList(rpc => 1, defrec => 'n', revrec => 'y', location => $args{location}, 899 999 id => $zonelist->[0]->{rdns_id}, filter => $filt, sortby => 'val', sortorder => 'DESC'); 900 1000 foreach my $rec (@$reclist) { … … 924 1024 # that spans multiple reverse zones (eg, /23 CIDR -> 2 /24 rzones) 925 1025 foreach my $zdata (@$zonelist) { 926 my $reclist = $dnsdb->getRecList( defrec => 'n', revrec => 'y', id => $zdata->{rdns_id});1026 my $reclist = $dnsdb->getRecList(rpc => 1, defrec => 'n', revrec => 'y', id => $zdata->{rdns_id}); 927 1027 if (scalar(@$reclist) == 0) { 928 1028 # nothing to do? or do we (re)add a record based on the parent? … … 981 1081 _commoncheck(\%args, 'y'); 982 1082 983 return $dnsdb->getRevPattern($args{cidr}, $args{group});1083 return $dnsdb->getRevPattern($args{cidr}, location => $args{location}, group => $args{group}); 984 1084 } 985 1085 … … 989 1089 _commoncheck(\%args, 'y'); 990 1090 991 return $dnsdb->getRevSet($args{cidr}, $args{group});1091 return $dnsdb->getRevSet($args{cidr}, location => $args{location}, group => $args{group}); 992 1092 } 993 1093 -
branches/stable/dns-upd-1.2.6.sql
r711 r725 2 2 3 3 -- Allow zones to be duplicated, so long as each version is in a unique location 4 ALTER TABLE domains DROP CONSTRAINT domains_pkey; 5 ALTER TABLE domains ADD PRIMARY KEY (domain,default_location); 4 ALTER TABLE ONLY domains 5 DROP CONSTRAINT domains_pkey; 6 ALTER TABLE ONLY domains 7 ADD PRIMARY KEY (domain,default_location); 6 8 7 ALTER TABLE revzones DROP CONSTRAINT revzones_pkey; 8 ALTER TABLE revzones ADD PRIMARY KEY (revnet,default_location); 9 ALTER TABLE ONLY revzones 10 DROP CONSTRAINT revzones_pkey; 11 ALTER TABLE ONLY revzones 12 ADD PRIMARY KEY (revnet,default_location); 13 14 -- MIA unique constraint to match domains table. Arguably not strictly necessary. 15 ALTER TABLE ONLY revzones 16 ADD CONSTRAINT revzones_rdns_id_key UNIQUE (rdns_id); 17 18 -- Update dbversion 19 UPDATE misc SET value='1.2.6' WHERE key='dbversion'; -
branches/stable/dns.cgi
r690 r725 25 25 use CGI::Simple; 26 26 use HTML::Template; 27 use CGI::Session ;27 use CGI::Session '-ip_match'; 28 28 use Net::DNS; 29 29 use DBI; … … 158 158 } 159 159 if (defined($webvar{filter})) { 160 $session->param($webvar{page}.'filter', '') if !$session->param($webvar{page}.'filter'); 160 161 if ($webvar{filter} ne $session->param($webvar{page}.'filter')) { 161 162 $uri_self =~ s/\&offset=[^&]//; … … 528 529 529 530 fill_grouplist("grouplist"); 530 my $loclist = $dnsdb->getLocDropdown($curgroup); 531 $page->param(loclist => $loclist); 531 fill_loclist($curgroup, $webvar{defloc} ? $webvar{defloc} : ''); 532 532 533 533 # prepopulate revpatt with the matching default record … … 1525 1525 unless ($permissions{admin} || $permissions{location_create}); 1526 1526 1527 my ($code,$msg) = $dnsdb->addLoc($curgroup, $webvar{locname}, $webvar{comments}, $webvar{iplist}); 1527 my ($code,$msg) = $dnsdb->addLoc(group => $curgroup, desc => $webvar{locname}, 1528 comments => $webvar{comments}, iplist => $webvar{iplist}); 1528 1529 1529 1530 if ($code eq 'OK' || $code eq 'WARN') { … … 1621 1622 } elsif ($webvar{page} eq 'dnsq') { 1622 1623 1623 $page->param(qfor => $webvar{qfor}) if $webvar{qfor}; 1624 if ($webvar{qfor}) { 1625 $webvar{qfor} =~ s/^\s*//; 1626 $webvar{qfor} =~ s/\s*$//; 1627 $page->param(qfor => $webvar{qfor}); 1628 } 1629 if ($webvar{resolver}) { 1630 $webvar{resolver} =~ s/^\s*//; 1631 $webvar{resolver} =~ s/\s*$//; 1632 $page->param(resolver => $webvar{resolver}); 1633 } 1624 1634 $page->param(typelist => $dnsdb->getTypelist('l', ($webvar{type} ? $webvar{type} : undef))); 1625 1635 $page->param(nrecurse => $webvar{nrecurse}) if $webvar{nrecurse}; 1626 $page->param(resolver => $webvar{resolver}) if $webvar{resolver};1627 1636 1628 1637 if ($webvar{qfor}) { -
branches/stable/dns.sql
r649 r725 31 31 32 32 COPY misc (misc_id, key, value) FROM stdin; 33 1 dbversion 1.2. 433 1 dbversion 1.2.6 34 34 \. 35 35 … … 86 86 CREATE TABLE domains ( 87 87 domain_id serial NOT NULL, 88 "domain" character varying(80) NOT NULL PRIMARY KEY,88 "domain" character varying(80) NOT NULL, 89 89 group_id integer DEFAULT 1 NOT NULL, 90 90 description character varying(255) DEFAULT ''::character varying NOT NULL, … … 101 101 CREATE TABLE revzones ( 102 102 rdns_id serial NOT NULL, 103 revnet cidr NOT NULL PRIMARY KEY,103 revnet cidr NOT NULL, 104 104 group_id integer DEFAULT 1 NOT NULL, 105 105 description character varying(255) DEFAULT ''::character varying NOT NULL, … … 108 108 sertype character(1) DEFAULT 'D'::bpchar, 109 109 changed boolean DEFAULT true NOT NULL, 110 default_location character varying (4) DEFAULT ''NOT NULL110 default_location character varying(4) DEFAULT ''::character varying NOT NULL 111 111 ); 112 112 CREATE INDEX rev_status_index ON revzones USING btree (status); … … 313 313 ADD CONSTRAINT domains_domain_id_key UNIQUE (domain_id); 314 314 315 ALTER TABLE ONLY domains 316 ADD CONSTRAINT domains_pkey PRIMARY KEY ("domain", default_location); 317 315 318 ALTER TABLE ONLY default_records 316 319 ADD CONSTRAINT default_records_pkey PRIMARY KEY (record_id); … … 321 324 ALTER TABLE ONLY rectypes 322 325 ADD CONSTRAINT rectypes_pkey PRIMARY KEY (val, name); 326 327 ALTER TABLE ONLY revzones 328 ADD CONSTRAINT revzones_rdns_id_key UNIQUE (rdns_id); 329 330 ALTER TABLE ONLY revzones 331 ADD CONSTRAINT revzones_pkey PRIMARY KEY (revnet, default_location); 323 332 324 333 ALTER TABLE ONLY users -
branches/stable/dnsdb.conf
r690 r725 49 49 #showrev_arpa = 0 50 50 51 # Let DNS server autosplit long TXT records however it pleases, or hand-generate the split points? 52 #autosplit = 1 51 53 52 54 ## General RPC options -
branches/stable/notes
r545 r725 327 327 -> would solve the conundrum of what to do with the unsightly CNAME 328 328 records presented in the UI to indicate sub-octet zone delegation 329 330 BIND reference for views/locations/split-horizon 331 https://kb.isc.org/article/AA-00851/0/Understanding-views-in-BIND-9-by-example.html -
branches/stable/templates/domlist.tmpl
r649 r725 42 42 <TMPL_LOOP name=domtable> 43 43 <tr class="row<TMPL_IF __odd__>0<TMPL_ELSE>1</TMPL_IF>"> 44 <td align="left"><a href="<TMPL_VAR NAME=script_self>&page=reclist&id=<TMPL_VAR NAME=zoneid>&defrec=n<TMPL_UNLESS domlist>&revrec=y</TMPL_UNLESS>"><TMPL_VAR NAME=zone></a>< /td>44 <td align="left"><a href="<TMPL_VAR NAME=script_self>&page=reclist&id=<TMPL_VAR NAME=zoneid>&defrec=n<TMPL_UNLESS domlist>&revrec=y</TMPL_UNLESS>"><TMPL_VAR NAME=zone></a><TMPL_IF location> (<TMPL_VAR NAME=location>)</TMPL_IF></td> 45 45 <td><TMPL_IF status>Active<TMPL_ELSE>Inactive</TMPL_IF></td> 46 46 <td><TMPL_VAR name=group></td>
Note:
See TracChangeset
for help on using the changeset viewer.