X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=blobdiff_plain;f=FS%2FFS%2Fdomain_record.pm;h=e7e9f70b742f78ad579dd58b664ba470e3b9da92;hp=d3682c351488efbc70297fbfc33187cfdf24c4b0;hb=9bdca2fe23584918219395b62effbb9ef0fc5f1c;hpb=fdf62da26a4a9127fd43f359163f231a89bc692d diff --git a/FS/FS/domain_record.pm b/FS/FS/domain_record.pm index d3682c351..e7e9f70b7 100644 --- a/FS/FS/domain_record.pm +++ b/FS/FS/domain_record.pm @@ -1,7 +1,8 @@ package FS::domain_record; use strict; -use vars qw( @ISA $noserial_hack ); +use vars qw( @ISA $noserial_hack $DEBUG ); +use FS::Conf; #use FS::Record qw( qsearch qsearchs ); use FS::Record qw( qsearchs dbh ); use FS::svc_domain; @@ -9,6 +10,8 @@ use FS::svc_www; @ISA = qw(FS::Record); +$DEBUG = 0; + =head1 NAME FS::domain_record - Object methods for domain_record records @@ -56,7 +59,7 @@ supported: =item new HASHREF -Creates a new entry. To add the example to the database, see L<"insert">. +Creates a new entry. To add the entry to the database, see L<"insert">. Note that this stores the hash reference, not a distinct copy of the hash it points to. You can ask the object for a copy with the I method. @@ -110,6 +113,18 @@ sub insert { } } + my $conf = new FS::Conf; + if ( $self->rectype =~ /^A$/ && ! $conf->exists('disable_autoreverse') ) { + my $reverse = $self->reverse_record; + if ( $reverse && ! $reverse->recnum ) { + my $error = $reverse->insert; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "error adding corresponding reverse-ARPA record: $error"; + } + } + } + $dbh->commit or die $dbh->errstr if $oldAutoCommit; ''; @@ -153,6 +168,18 @@ sub delete { } } + my $conf = new FS::Conf; + if ( $self->rectype =~ /^A$/ && ! $conf->exists('disable_autoreverse') ) { + my $reverse = $self->reverse_record; + if ( $reverse && $reverse->recnum && $reverse->recdata eq $self->zone.'.' ){ + my $error = $reverse->delete; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "error removing corresponding reverse-ARPA record: $error"; + } + } + } + $dbh->commit or die $dbh->errstr if $oldAutoCommit; ''; @@ -202,7 +229,7 @@ sub replace { =item check -Checks all fields to make sure this is a valid example. If there is +Checks all fields to make sure this is a valid entry. If there is an error, returns the error, otherwise returns false. Called by the insert and replace methods. @@ -223,15 +250,23 @@ sub check { return "Unknown svcnum (in svc_domain)" unless qsearchs('svc_domain', { 'svcnum' => $self->svcnum } ); - $self->reczone =~ /^(@|[a-z0-9\.\-\*]+)$/i - or return "Illegal reczone: ". $self->reczone; - $self->reczone($1); + my $conf = new FS::Conf; + + if ( $conf->exists('zone-underscore') ) { + $self->reczone =~ /^(@|[a-z0-9_\.\-\*]+)$/i + or return "Illegal reczone: ". $self->reczone; + $self->reczone($1); + } else { + $self->reczone =~ /^(@|[a-z0-9\.\-\*]+)$/i + or return "Illegal reczone: ". $self->reczone; + $self->reczone($1); + } $self->recaf =~ /^(IN)$/ or return "Illegal recaf: ". $self->recaf; $self->recaf($1); - $self->rectype =~ /^(SOA|NS|MX|A|PTR|CNAME|_mstr)$/ - or return "Illegal rectype (only SOA NS MX A PTR CNAME recognized): ". + $self->rectype =~ /^(SOA|NS|MX|A|PTR|CNAME|TXT|_mstr)$/ + or return "Illegal rectype (only SOA NS MX A PTR CNAME TXT recognized): ". $self->rectype; $self->rectype($1); @@ -241,7 +276,7 @@ sub check { if ( $self->rectype eq 'SOA' ) { my $recdata = $self->recdata; $recdata =~ s/\s+/ /g; - $recdata =~ /^([a-z0-9\.\-]+ [\w\-\+]+\.[a-z0-9\.\-]+ \( ([\dwdhmsWDHMS]+ ){5}\))$/i + $recdata =~ /^([a-z0-9\.\-]+ [\w\-\+]+\.[a-z0-9\.\-]+ \( ((\d+|((\d+[WDHMS])+)) ){5}\))$/i or return "Illegal data for SOA record: $recdata"; $self->recdata($1); } elsif ( $self->rectype eq 'NS' ) { @@ -257,13 +292,26 @@ sub check { or return "Illegal data for A record: ". $self->recdata; $self->recdata($1); } elsif ( $self->rectype eq 'PTR' ) { - $self->recdata =~ /^([a-z0-9\.\-]+)$/i - or return "Illegal data for PTR record: ". $self->recdata; - $self->recdata($1); + if ( $conf->exists('zone-underscore') ) { + $self->recdata =~ /^([a-z0-9_\.\-]+)$/i + or return "Illegal data for PTR record: ". $self->recdata; + $self->recdata($1); + } else { + $self->recdata =~ /^([a-z0-9\.\-]+)$/i + or return "Illegal data for PTR record: ". $self->recdata; + $self->recdata($1); + } } elsif ( $self->rectype eq 'CNAME' ) { $self->recdata =~ /^([a-z0-9\.\-]+|\@)$/i or return "Illegal data for CNAME record: ". $self->recdata; $self->recdata($1); + } elsif ( $self->rectype eq 'TXT' ) { + if ( $self->recdata =~ /^((?:\S+)|(?:".+"))$/ ) { + $self->recdata($1); + } else { + $self->recdata('"'. $self->recdata. '"'); #? + } + # or return "Illegal data for TXT record: ". $self->recdata; } elsif ( $self->rectype eq '_mstr' ) { $self->recdata =~ /^((\d{1,3}\.){3}\d{1,3})$/ or return "Illegal data for _master pseudo-record: ". $self->recdata; @@ -271,7 +319,7 @@ sub check { die "ack!"; } - ''; #no error + $self->SUPER::check; } =item increment_serial @@ -284,10 +332,16 @@ sub increment_serial { my $soa = qsearchs('domain_record', { svcnum => $self->svcnum, - reczone => '@', #or full domain ? + reczone => '@', + recaf => 'IN', + rectype => 'SOA', } ) + || qsearchs('domain_record', { + svcnum => $self->svcnum, + reczone => $self->svc_domain->domain.'.', recaf => 'IN', rectype => 'SOA', - } ) or return "soa record not found; can't increment serial"; + } ) + or return "soa record not found; can't increment serial"; my $data = $soa->recdata; $data =~ s/(\(\D*)(\d+)/$1.($2+1)/e; #well, it works. @@ -328,11 +382,56 @@ sub zone { $zone; } -=back +=item reverse_record -=head1 VERSION +Returns the corresponding reverse-ARPA record as another FS::domain_record +object. If the specific record does not exist in the database but the +reverse-ARPA zone itself does, an appropriate new record is created. If no +reverse-ARPA zone is available at all, returns false. + +(You can test whether or not record itself exists in the database or is a new +object that might need to be inserted by checking the recnum field) + +Mostly used by the insert and delete methods - probably should see them for +examples. + +=cut -$Id: domain_record.pm,v 1.14 2003-04-24 18:45:03 khoff Exp $ +sub reverse_record { + my $self = shift; + warn "reverse_record called\n" if $DEBUG; + #should support classless reverse-ARPA ala rfc2317 too + $self->recdata =~ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/ + or return ''; + my $domain = "$3.$2.$1.in-addr.arpa"; + my $ptr_reczone = $4; + warn "reverse_record: searching for domain: $domain\n" if $DEBUG; + my $svc_domain = qsearchs('svc_domain', { 'domain' => $domain } ) + or return ''; + warn "reverse_record: found domain: $domain\n" if $DEBUG; + my %hash = ( + 'svcnum' => $svc_domain->svcnum, + 'reczone' => $ptr_reczone, + 'recaf' => 'IN', + 'rectype' => 'PTR', + ); + qsearchs('domain_record', \%hash ) + or new FS::domain_record { %hash, 'recdata' => $self->zone.'.' }; +} + +=item rectypes + +=cut +#http://en.wikipedia.org/wiki/List_of_DNS_record_types +#DHCID? other things? +sub rectypes { + [ qw(A AAAA CNAME MX NS PTR SPF SRV TXT), #most common types + #qw(DNAME), #uncommon types + qw(DLV DNSKEY DS NSEC NSEC3 NSEC3PARAM RRSIG), #DNSSEC types + ]; +} + +=back =head1 BUGS