File Coverage

blib/lib/Regexp/Common/dns.pm
Criterion Covered Total %
statement 23 23 100.0
branch 4 4 100.0
condition 9 11 81.8
subroutine 4 4 100.0
pod 0 1 0.0
total 40 43 93.0


line stmt bran cond sub pod time code
1             package Regexp::Common::dns;
2             #
3             # $Id: dns.pm,v 1.10 2003/11/19 02:43:46 ctriv Exp $
4             #
5              
6 8     8   223805 use strict;
  8         19  
  8         527  
7 8     8   43 use vars qw($VERSION);
  8         16  
  8         501  
8              
9             $VERSION = '0.00_01';
10              
11 8     8   1576 use Regexp::Common qw/pattern net/;
  8         5897  
  8         77  
12              
13             our $DEFAULT_RFC = 'hybrid';
14              
15             =head1 NAME
16              
17             Regexp::Common::dns - Common DNS Regular Expressions
18              
19             =head1 SYNOPSIS
20              
21             use Regexp::Common qw/dns/;
22            
23             while (<>) {
24             $RE{'dns'}{'data'}{'mx'} and print 'an mx';
25             $RE{'dns'}{'data'}{'soa'} and print 'a soa';
26             }
27              
28             if ($host =~ $RE{'dns'}{'domain'}) {
29             print "hostname found';
30             }
31              
32             =head1 PATTERNS
33              
34             =head2 $RE{'dns'}{'int16'}
35              
36             Matches a 16 bit unsigned integer in base 10 format.
37              
38             =cut
39              
40             # 16 bit unsigned int is 65535
41             pattern name => [qw(dns int16)],
42             create => '(?k:6553[0-5]|655[0-2]\d|65[0-4]\d\d|6[0-4]\d{1,3}|[0-5]?\d{1,4})'
43             ;
44              
45              
46              
47             =head2 $RE{'dns'}{'int32'}
48              
49             Matches a 32 bit integer in base 10 format.
50              
51             =cut
52            
53             # 32 bit unsigned int is 4294967295
54             pattern name => [qw(dns int32)],
55             create => '(?k:429496729[0-5]|42949672[0-8]\d|4294967[0-1]\d\d|429496[0-6]\d{1,3}|42949[0-5]\d{1,4}|4294[0-8]\d{1,5}|429[0-3]\d{1,6}|42[0-8]\d{1,7}|4[0-1]\d{1,8}|[0-3]?\d{1,9})'
56             ;
57              
58             =head2 $RE{'dns'}{'domain'}
59              
60             Matches a DNS domain name.
61              
62             By default this regexp uses a pragmatic combination of rfc1035, and
63             rfc2181. This is intended to be in sprit with current DNS operation
64             practices. This hybrid approach is simlar to rfc1035, but allows for
65             underscores, and for underscores and hyphens to begin or end a lable.
66             It also allows for wilcarding.
67              
68             The default rule can be set with the C<$Regexp::Common::dns::DEFAULT_RFC>
69             global, which is not exported by this package.
70            
71            
72             By default this regexp matches a domain name according to the rules of
73             L section 2.3.1:
74              
75             ::= | " "
76            
77             ::=
78            
79            
80            
81             ::= |
82              
83             ::= | "-"
84              
85             ::= |
86              
87             ::= <[A-Za-z]>
88              
89             ::= <[0-9]>
90              
91             Labels must be 63 characters or less.
92              
93             Domain names must be 255 octets or less.
94              
95             RFC 1035 does not allow for wildcarding (C<*.example.com>). If you want to
96             match a wildcarded domain name, use the C<-wildcard> flag:
97              
98             $Regexp::Common::dns::DEFAULT_RFC = '1035'
99              
100             '*.example.com' =~ $RE{'dns'}{'domain'}{-wildcard}; # match
101             '*.example.com' =~ $RE{'dns'}{'domain'}; # no match
102            
103              
104             RFC 1035 has been superseded by L
105             section 11:
106              
107             =over 2
108              
109             =item *
110              
111             Labels can be any character except a C<.>.
112              
113             =item *
114              
115             Each label is no shorter than one octet.
116              
117             =item *
118              
119             Each lable is no longer than 63 octets.
120              
121             =item *
122              
123             A complete domain name may be no longer than 255 octets, including the separators.
124              
125             =back
126              
127             For example:
128              
129             '_fancy.spf.record=4.org' =~ $RE{'dns'}{'domain'}{-rfc => 2181};
130              
131             This regular expression does not match a single C<.>.
132            
133             The minimum number of lables can be specified with the C<-minlables> flag:
134              
135             'org' =~ $RE{'dns'}{'domain'} # match
136             'org' =~ $RE{'dns'}{'domain'}{-minlables => 2} # no match
137             'co.org' =~ $RE{'dns'}{'domain'}{-minlables => 2} # match
138              
139             The C<-rfc> flag can be used to specify any of the three rule sets. The
140             pragmatic ruleset discussed earlier is labled as C.
141              
142             =cut
143              
144             pattern name => [qw(dns domain -rfc= -minlables= -wildcard=)],
145             create => sub {
146             my $pattern = domain(@_);
147            
148             return qq/(?=^.{1,255}\$)(?k:$pattern)/;
149             }
150             ;
151              
152              
153             sub domain {
154 655     655 0 974 my $flags = $_[1];
155            
156 655         885 my $sep = '\.';
157            
158 655         791 my $letter = '[a-zA-Z]';
159 655         762 my $let_dig = '[a-zA-Z0-9]';
160 655         746 my $let_dig_hyp = '[-a-zA-Z0-9]';
161            
162 655         6552 my %lables = (
163             1035 => "(?:$letter(?:$let_dig|$let_dig_hyp\{1,61}$let_dig)?)",
164             2181 => '[^.]{1,63}',
165             hybrid => '[a-zA-Z0-9_-]{1,63}'
166             );
167            
168 655   66     2445 $flags->{'-rfc'} ||= $DEFAULT_RFC;
169            
170 655   50     1979 my $lable = $lables{$flags->{'-rfc'}} || die("Unknown DNS RFC: $flags->{'-rfc'}");
171            
172 655 100 100     3678 if ($flags->{'-rfc'} ne 2181 && exists $flags->{'-wildcard'} && not defined $flags->{'-wildcard'}) {
      100        
173 8         24 $lable = "(?:\\*|$lable)";
174             }
175              
176 655         963 my $quant = '*';
177 655 100       1433 if ($flags->{'-minlables'}) {
178 97         230 $quant = '{' . ($flags->{'-minlables'} - 1) . ',}';
179             }
180            
181 655         3383 return qq/(?:$lable$sep)$quant$lable$sep?/;
182             }
183              
184              
185             =head2 $RE{'dns'}{'data'}{'a'}
186              
187             Matches the data section of an A record. This is a dotted decimal representation
188             of a IPv4 address.
189              
190             =cut
191              
192             pattern name => [qw(dns data a)],
193             create => qq/(?k:$RE{'net'}{'IPv4'})/;
194            
195            
196             =head2 $RE{'dns'}{'data'}{'cname'}
197              
198             Matches the data section of a CNAME record. This pattern accepts the same
199             flags as C<$RE{'dns'}{'domain'}>.
200              
201             =cut
202              
203             pattern name => [qw(dns data cname -rfc= -minlables= -wildcard=)],
204             create => sub {
205             my $cname = domain(@_);
206            
207             return qq/(?k:$cname)/;
208             }
209             ;
210            
211              
212             =head2 $RE{'dns'}{'data'}{'mx'}
213              
214             Matches the data section of a MX record. This pattern accepts the same
215             flags as C<$RE{'dns'}{'domain'}>.
216              
217             If keep is turned on, then the C<$n> variables are filled as follows:
218              
219             =over 2
220              
221             =item $1
222              
223             The entire data section.
224              
225             =item $2
226              
227             The preference.
228              
229             =item $3
230              
231             The exchange.
232              
233             =back
234              
235             =cut
236              
237             pattern name => [qw(dns data mx -rfc= -minlables= -wildcard=)],
238             create => sub {
239             my $exchange = domain(@_);
240             my $prefence = $RE{'dns'}{'int16'};
241            
242             return qq/(?k:(?k:$prefence)\\s+(?k:$exchange))/;
243             }
244             ;
245              
246              
247             =head2 $RE{'dns'}{'data'}{'soa'}
248              
249             Matches the data section of a MX record. This pattern accepts the C<-rfc>
250             flag.
251              
252             If keep is turned on, then the C<$n> variables are filled as follows:
253              
254             =over 2
255              
256             =item $1
257              
258             The entire data section.
259              
260             =item $2
261              
262             The mname.
263              
264             =item $3
265              
266             The rname.
267              
268             =item $4
269              
270             The serial number.
271              
272             =item $5
273              
274             The refresh time interval.
275              
276             =item $6
277              
278             The retry time interval.
279              
280             =item $7
281              
282             The expire time value.
283              
284             =item $8
285              
286             The minimum TTL.
287              
288             =back
289              
290             =cut
291              
292             pattern name => [qw(dns data soa -rfc=)],
293             create => sub {
294             my $flags = $_[1];
295            
296             my $mname = domain(@_);
297             my $rname = do {
298             local $flags->{'-minlables'} = 2;
299            
300             domain(@_);
301             };
302            
303             my $serial = $RE{'dns'}{'int32'};
304             my $refresh = $RE{'dns'}{'int32'};
305             my $retry = $RE{'dns'}{'int32'};
306             my $expire = $RE{'dns'}{'int32'};
307             my $minimum = $RE{'dns'}{'int32'};
308            
309             my $regexp = qq/(?k:
310             (?k:$mname)
311             \\s+
312             (?k:$rname)
313             \\s+
314             (?k:$serial)
315             \\s+
316             (?k:$refresh)
317             \\s+
318             (?k:$retry)
319             \\s+
320             (?k:$expire)
321             \\s+
322             (?k:$minimum)
323             )/;
324            
325            
326             $regexp =~ s/\s+//g;
327            
328             return $regexp;
329             }
330             ;
331            
332              
333             =head1 TODO
334              
335             Several RR data patterns are missing:
336              
337             HINFO
338             MB
339             MG
340             MINFO
341             MR
342             NULL (easy!)
343             PTR
344             TXT
345             WKS
346             RP
347             LOC
348             AAAA
349             OPT
350             SRV
351             DNAME
352              
353             and more.
354              
355             Patterns for whole RR records, TTLs, classes, and types are missing.
356              
357             Ideally patterns for the various compenent of a data section would
358             be provided, for example to match the mname section of a soa record:
359              
360             $RE{'dns'}{'data'}{'soa'}{'mname'}
361            
362             The author is not sure that the C<$RE{'dns'}{'data'}{'rr'}> namespace is
363             needed, perhaps C<$RE{'dns'}{'rr'}> would suffice.
364              
365             =head1 AUTHOR
366              
367             Chris Reinhardt
368             cpan@triv.org
369              
370             =head1 COPYRIGHT
371              
372             Copyright (c) 2003 Chris Reinhardt.
373              
374             All rights reserved. This program is free software; you may redistribute
375             it and/or modify it under the same terms as Perl itself.
376              
377             =head1 SEE ALSO
378              
379             L, perl(1).
380              
381             =cut
382              
383              
384              
385             1;
386             __END__