allow * MX records
[freeside.git] / FS / FS / domain_record.pm
1 package FS::domain_record;
2
3 use strict;
4 use vars qw( @ISA );
5 #use FS::Record qw( qsearch qsearchs );
6 use FS::Record qw( qsearchs );
7 use FS::svc_domain;
8
9 @ISA = qw(FS::Record);
10
11 =head1 NAME
12
13 FS::domain_record - Object methods for domain_record records
14
15 =head1 SYNOPSIS
16
17   use FS::domain_record;
18
19   $record = new FS::domain_record \%hash;
20   $record = new FS::domain_record { 'column' => 'value' };
21
22   $error = $record->insert;
23
24   $error = $new_record->replace($old_record);
25
26   $error = $record->delete;
27
28   $error = $record->check;
29
30 =head1 DESCRIPTION
31
32 An FS::domain_record object represents an entry in a DNS zone.
33 FS::domain_record inherits from FS::Record.  The following fields are currently
34 supported:
35
36 =over 4
37
38 =item recnum - primary key
39
40 =item svcnum - Domain (see L<FS::svc_domain>) of this entry
41
42 =item reczone - partial (or full) zone for this entry
43
44 =item recaf - address family for this entry, currently only `IN' is recognized.
45
46 =item rectype - record type for this entry (A, MX, etc.)
47
48 =item recdata - data for this entry
49
50 =back
51
52 =head1 METHODS
53
54 =over 4
55
56 =item new HASHREF
57
58 Creates a new entry.  To add the example to the database, see L<"insert">.
59
60 Note that this stores the hash reference, not a distinct copy of the hash it
61 points to.  You can ask the object for a copy with the I<hash> method.
62
63 =cut
64
65 sub table { 'domain_record'; }
66
67 =item insert
68
69 Adds this record to the database.  If there is an error, returns the error,
70 otherwise returns false.
71
72 =cut
73
74 =item delete
75
76 Delete this record from the database.
77
78 =cut
79
80 =item replace OLD_RECORD
81
82 Replaces the OLD_RECORD with this one in the database.  If there is an error,
83 returns the error, otherwise returns false.
84
85 =cut
86
87 =item check
88
89 Checks all fields to make sure this is a valid example.  If there is
90 an error, returns the error, otherwise returns false.  Called by the insert
91 and replace methods.
92
93 =cut
94
95 # the check method should currently be supplied - FS::Record contains some
96 # data checking routines
97
98 sub check {
99   my $self = shift;
100
101   my $error = 
102     $self->ut_numbern('recnum')
103     || $self->ut_number('svcnum')
104   ;
105   return $error if $error;
106
107   return "Unknown svcnum (in svc_domain)"
108     unless qsearchs('svc_domain', { 'svcnum' => $self->svcnum } );
109
110   $self->reczone =~ /^(@|[a-z0-9\.\-\*]+)$/i
111     or return "Illegal reczone: ". $self->reczone;
112   $self->reczone($1);
113
114   $self->recaf =~ /^(IN)$/ or return "Illegal recaf: ". $self->recaf;
115   $self->recaf($1);
116
117   $self->rectype =~ /^(SOA|NS|MX|A|PTR|CNAME)$/
118     or return "Illegal rectype (only SOA NS MX A PTR CNAME recognized): ".
119               $self->rectype;
120   $self->rectype($1);
121
122   return "Illegal reczone for ". $self->rectype. ": ". $self->reczone
123     if $self->rectype !~ /^MX$/i && $self->reczone =~ /\*/;
124
125   if ( $self->rectype eq 'SOA' ) {
126     my $recdata = $self->recdata;
127     $recdata =~ s/\s+/ /g;
128     $recdata =~ /^([a-z0-9\.\-]+ [\w\-\+]+\.[a-z0-9\.\-]+ \( (\d+ ){5}\))$/i
129       or return "Illegal data for SOA record: $recdata";
130     $self->recdata($1);
131   } elsif ( $self->rectype eq 'NS' ) {
132     $self->recdata =~ /^([a-z0-9\.\-]+)$/i
133       or return "Illegal data for NS record: ". $self->recdata;
134     $self->recdata($1);
135   } elsif ( $self->rectype eq 'MX' ) {
136     $self->recdata =~ /^(\d+)\s+([a-z0-9\.\-]+)$/i
137       or return "Illegal data for MX record: ". $self->recdata;
138     $self->recdata("$1 $2");
139   } elsif ( $self->rectype eq 'A' ) {
140     $self->recdata =~ /^((\d{1,3}\.){3}\d{1,3})$/
141       or return "Illegal data for A record: ". $self->recdata;
142     $self->recdata($1);
143   } elsif ( $self->rectype eq 'PTR' ) {
144     $self->recdata =~ /^([a-z0-9\.\-]+)$/i
145       or return "Illegal data for PTR record: ". $self->recdata;
146     $self->recdata($1);
147   } elsif ( $self->rectype eq 'CNAME' ) {
148     $self->recdata =~ /^([a-z0-9\.\-]+)$/i
149       or return "Illegal data for CNAME record: ". $self->recdata;
150     $self->recdata($1);
151   } else {
152     die "ack!";
153   }
154
155   ''; #no error
156 }
157
158 =back
159
160 =head1 VERSION
161
162 $Id: domain_record.pm,v 1.6 2002-04-20 10:49:33 ivan Exp $
163
164 =head1 BUGS
165
166 The data validation doesn't check everything it could.  In particular,
167 there is no protection against bad data that passes the regex, duplicate
168 SOA records, forgetting the trailing `.', impossible IP addersses, etc.  Of
169 course, it's still better than editing the zone files directly.  :)
170
171 =head1 SEE ALSO
172
173 L<FS::Record>, schema.html from the base documentation.
174
175 =cut
176
177 1;
178