- Timestamp:
- 02/13/12 17:56:18 (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/DNSDB.pm
r231 r232 174 174 my $addr = shift; 175 175 176 return if $revrec ne 'y'; # this sub not useful in forward zones 177 178 $$addr = NetAddr::IP->new($$val); #necessary? 179 176 180 # subsub to split, reverse, and overlay an IP fragment on a netblock 177 181 sub __rev_overlay { … … 183 187 my $joinme = $splitme; 184 188 $splitme = '\.' if $splitme eq '.'; 185 my @working = reverse(split($splitme, $parnet->addr)) or warn $!;186 my @parts = reverse(split($splitme, $ val));189 my @working = reverse(split($splitme, $parnet->addr)); 190 my @parts = reverse(split($splitme, $$val)); 187 191 for (my $i = 0; $i <= $#parts; $i++) { 188 192 $working[$i] = $parts[$i]; 189 193 } 190 my $checkme = NetAddr::IP->new(join($joinme, reverse(@working))) or return ;191 return unless $checkme->within($parnet);194 my $checkme = NetAddr::IP->new(join($joinme, reverse(@working))) or return 0; 195 return 0 unless $checkme->within($parnet); 192 196 $$addr = $checkme; # force "correct" IP to be recorded. 193 197 return 1; … … 198 202 199 203 # Fail early on v6-in-v4 or v4-in-v6. We're not accepting these ATM. 200 return if $parnet->addr =~ /\./ && $val =~ /:/; 201 return if $parnet->addr =~ /:/ && $val =~ /\./; 202 203 # Arguably this is incorrect, but... 204 if ($val =~ /^::/) { 205 $val =~ s/^:+//; # gotta strip'em all... 206 return __rev_overlay(':', $parnet, $val, $addr); 207 } 208 if ($val =~ /^\./) { 209 $val =~ s/^\.+//; 210 return __rev_overlay('.', $parnet, $val, $addr); 211 } 212 213 if ($revrec eq 'y') { 214 if ($$addr && !$$addr->{isv6}) { 215 # argh. 12.1 == 12.0.0.1 (WTF?) 216 # so we do this The Hard Way, because of the stupid 217 if ($val =~ /^(?:\d{1,3}\.){3}\d{1,3}$/) { 218 # we really have a real IP. 219 return $dbh->selectrow_array("SELECT count(*) FROM revzones WHERE revnet >> ?", undef, ($val)); 220 } else { 221 return __rev_overlay('.', $parnet, $val, $addr); 222 } 223 } elsif ($$addr && $$addr->{isv6}) { 224 # real v6 address. 225 return $dbh->selectrow_array("SELECT count(*) FROM revzones WHERE revnet >> ?", undef, ($val)); 226 } else { 227 # v6 tail 204 return 0 if $parnet->addr =~ /\./ && $$val =~ /:/; 205 return 0 if $parnet->addr =~ /:/ && $$val =~ /\./; 206 207 if ($$addr && $$val =~ /^\d[\d:]+\d$/) { 208 # the only case where NetAddr::IP's acceptance of legitimate IPs is "correct" is for a proper IPv6 address. 209 # the rest we have to restructure before fiddling. *sigh* 210 return 1 if $$addr->within($parnet); 211 } else { 212 # We don't have a complete IP in $$val (yet) 213 if ($parnet->addr =~ /:/) { 214 $$val =~ s/^:+//; # gotta strip'em all... 228 215 return __rev_overlay(':', $parnet, $val, $addr); 216 } 217 if ($parnet->addr =~ /\./) { 218 $$val =~ s/^\.+//; 219 return __rev_overlay('.', $parnet, $val, $addr); 229 220 } 230 221 # should be impossible to get here... … … 234 225 } # end _ipparent() 235 226 227 # A little different than _ipparent above; this tries to *find* the parent zone of a hostname 228 sub _hostparent { 229 my $dbh = shift; 230 my $hname = shift; 231 232 my @hostbits = split /\./, $hname; 233 my $sth = $dbh->prepare("SELECT count(*),domain_id FROM domains WHERE domain = ? GROUP BY domain_id"); 234 foreach (@hostbits) { 235 $sth->execute($hname); 236 my ($found, $parid) = $sth->fetchrow_array; 237 if ($found) { 238 return $parid; 239 } 240 $hname =~ s/^$_\.//; 241 } 242 } # end _hostparent() 236 243 237 244 ## … … 253 260 254 261 # Check IP is well-formed, and that it's a v4 address 255 return ('FAIL'," Arecord must be a valid IPv4 address")262 return ('FAIL',"$typemap{${$args{rectype}}} record must be a valid IPv4 address") 256 263 unless $args{addr} && !$args{addr}->{isv6}; 257 264 # coerce IP/value to normalized form for storage 258 265 ${$args{val}} = $args{addr}->addr; 266 267 # Add the necessary fields. 268 ${$args{fields}} = 'domain_id,'; 269 push @{$args{vallist}}, $args{id}; 259 270 260 271 return ('OK','OK'); … … 316 327 # PTR record 317 328 sub _validate_12 { 329 my $dbh = shift; 330 331 my %args = @_; 332 333 if ($args{revrec} eq 'y') { 334 if ($args{defrec} eq 'n') { 335 return ('FAIL', "IP or IP fragment ${$args{val}} is not within ".revName($dbh, $args{id})) 336 unless _ipparent($dbh, $args{defrec}, $args{revrec}, $args{val}, $args{id}, \$args{addr}); 337 ${$args{val}} = $args{addr}->addr; 338 } else { 339 ${$args{val}} =~ s/^([:.]*)/ZONE$1/; 340 } 341 342 ${$args{fields}} = _recparent($args{defrec},$args{revrec}).","; 343 push @{$args{vallist}}, $args{id}; 344 345 # Multiple PTR records do NOT generally do what most people believe they do, 346 # and tend to fail in the most awkward way possible. Check and warn. 347 # We use $val instead of $addr->addr since we may be in a defrec, and may have eg "ZONE::42" or "ZONE.12" 348 my ($ptrcount) = $dbh->selectrow_array("SELECT count(*) FROM "._rectable($args{defrec},$args{revrec}). 349 " WHERE val = ?", undef, ${$args{val}}); 350 return ('WARN', "PTR record for ${$args{val}} already exists; adding another will probably not do what you want") 351 if $ptrcount; 352 } else { 353 # Not absolutely true but only useful if you hack things up for sub-/24 v4 reverse delegations 354 # Simpler to just create the reverse zone and grant access for the customer to edit it, and create direct 355 # PTR records on export 356 return ('FAIL',"Forward zones cannot contain PTR records"); 357 } 358 318 359 return ('OK','OK'); 319 360 } # done PTR record … … 369 410 370 411 # Check IP is well-formed, and that it's a v6 address 371 return ('FAIL'," AAAArecord must be a valid IPv6 address")412 return ('FAIL',"$typemap{${$args{rectype}}} record must be a valid IPv6 address") 372 413 unless $args{addr} && $args{addr}->{isv6}; 373 414 # coerce IP/value to normalized form for storage 374 415 ${$args{val}} = $args{addr}->addr; 416 417 # Add the necessary fields. 418 ${$args{fields}} = 'domain_id,'; 419 push @{$args{vallist}}, $args{id}; 375 420 376 421 return ('OK','OK'); … … 413 458 # Now the custom types 414 459 415 # A+PTR record 460 # A+PTR record. With a very little bit of magic we can also use this sub to validate AAAA+PTR. Whee! 416 461 sub _validate_65280 { 417 return ('OK','OK'); 462 my $dbh = shift; 463 464 my %args = @_; 465 466 my $code = 'OK'; 467 my $msg = 'OK'; 468 469 if ($args{defrec} eq 'n') { 470 # live record; revrec determines whether we validate the PTR or A component first. 471 if ($args{revrec} eq 'y') { 472 ($code,$msg) = _validate_12($dbh, %args); 473 return ($code,$msg) if $code eq 'FAIL'; 474 475 # Check if the reqested domain exists. If not, coerce the type down to PTR and warn. 476 if (!(${$args{domid}} = _hostparent($dbh, ${$args{host}}))) { 477 my $addmsg = "Record added as PTR instead of $typemap{${$args{rectype}}}; domain not found for ${$args{host}}"; 478 $msg .= "\n$addmsg" if $code eq 'WARN'; 479 $msg = $addmsg if $code eq 'OK'; 480 ${$args{rectype}} = $reverse_typemap{PTR}; 481 return ('WARN', $msg); 482 } 483 ${$args{fields}} .= "domain_id,"; 484 push @{$args{vallist}}, ${$args{domid}}; 485 486 } else { 487 ($code,$msg) = _validate_1($dbh, %args) if ${$args{rectype}} == 65280; 488 ($code,$msg) = _validate_28($dbh, %args) if ${$args{rectype}} == 65281; 489 return ($code,$msg) if $code eq 'FAIL'; 490 491 # Check if the requested reverse zone exists - note, an IP fragment won't 492 # work here since we don't *know* which parent to put it in. 493 my ($revid) = $dbh->selectrow_array("SELECT rdns_id FROM revzones WHERE revnet >> ?". 494 " ORDER BY masklen(revnet) DESC", undef, (${$args{val}})); 495 if (!$revid) { 496 $msg = "Record added as ".(${$args{rectype}} == 65280 ? 'A' : 'AAAA'). 497 " instead of $typemap{${$args{rectype}}}; reverse zone not found for ${$args{val}}"; 498 ${$args{rectype}} = (${$args{rectype}} == 65280 ? $reverse_typemap{A} : $reverse_typemap{AAAA}); 499 return ('WARN', $msg); 500 } 501 502 # Check for duplicate PTRs. Note we don't have to play games with $code and $msg, because 503 # by definition there can't be duplicate PTRs if the reverse zone isn't managed here. 504 my ($ptrcount) = $dbh->selectrow_array("SELECT count(*) FROM "._rectable($args{defrec},$args{revrec}). 505 " WHERE val = ?", undef, ${$args{val}}); 506 if ($ptrcount) { 507 $msg = "PTR record for ${$args{val}} already exists; adding another will probably not do what you want"; 508 $code = 'WARN'; 509 } 510 511 ${$args{fields}} .= "rdns_id,"; 512 push @{$args{vallist}}, $revid; 513 } 514 515 } else { 516 # defrec eq 'y' 517 } 518 519 return ($code, $msg); 418 520 } # done A+PTR record 419 521 420 522 # AAAA+PTR record 523 # A+PTR above has been magicked to handle AAAA+PTR as well. 421 524 sub _validate_65281 { 422 return ('OK','OK');525 return _validate_65280(@_); 423 526 } # done AAAA+PTR record 424 527
Note:
See TracChangeset
for help on using the changeset viewer.