File Coverage

blib/lib/Net/DNS/ZoneParse/Parser/Native.pm
Criterion Covered Total %
statement 65 81 80.2
branch 19 32 59.3
condition n/a
subroutine 10 10 100.0
pod 2 2 100.0
total 96 125 76.8


line stmt bran cond sub pod time code
1             package Net::DNS::ZoneParse::Parser::Native;
2              
3 5     5   6835 use 5.008000;
  5         17  
  5         188  
4 5     5   27 use strict;
  5         10  
  5         160  
5 5     5   163 use warnings;
  5         81  
  5         187  
6 5     5   25 use vars qw($VERSION);
  5         9  
  5         248  
7              
8 5     5   31 use Net::DNS;
  5         10  
  5         29847  
9              
10             require Net::DNS::ZoneParse::Parser::Native::DNSext
11             unless Net::DNS::RR->can("new_from_filestring");
12             $VERSION = 0.103;
13              
14             =pod
15              
16             =head1 NAME
17              
18             Net::DNS::ZoneParse::Parser::Native - Net::DNS::ZoneParse's native parser.
19              
20             =head1 DESCRIPTION
21              
22             the Native parser can be used without any external dependencies - except
23             of Net::DNS. It supports the directives $TTL, $ORIGIN, $INCLUDE and
24             $GENERATE.
25             It can handle all RRs supported by Net::DNS, as it uses their parsing routines.
26              
27             =cut
28              
29             ###############
30             # Global Data #
31             ###############
32              
33             # This RE matches only, if there where the same number of opening as of closing
34             # brackets
35             my $_matchparentheses;
36             $_matchparentheses = qr/(?>[^()]+|\((??{$_matchparentheses})\))*/;
37              
38             # This RE matches any possible TTL - with bind extensions
39             my $_dns_ttlre = qr/^(\d+[\dwdhms]*)$/;
40              
41             # This contains the functions for the different directives defined in RFC1035
42             # and the BIND-extension $TTL and $GENERATE
43             my %_dns_directives = (
44             ORIGIN => \&Net::DNS::ZoneParse::_dns_test_set_origin,
45             TTL => sub {
46             return unless($_[0] =~ $_dns_ttlre);
47             $_[1]->{ttl} = $1;
48             },
49             INCLUDE => sub {
50             my ($line, $param, $self, $rr) = @_;
51             my $filename = dns_next_item($line);
52             return unless($filename);
53             my $fh = $param->{fh};
54             $param->{fh} = undef;
55             open($param->{fh}, "<", $filename) or return;
56              
57             my $origin = $param->{origin};
58             my $neworigin = dns_next_item($line);
59             $param->{origin} = $neworigin if $neworigin;
60              
61             parse($self, $param, $rr);
62              
63             close($param->{fh});
64             $param->{fh} = $fh;
65             $param->{origin} = $origin;
66             },
67             GENERATE => sub {
68             my ($line, $param, $self, $rr) = @_;
69             my ($first, $last) = split(/-/,dns_next_item($line),2);
70             return unless( defined $first);
71             $last = $first unless( defined $last);
72             for($first .. $last) {
73             my $aline = $line;
74             $aline =~ s/\$/$_/g;
75             my $ele = _dns_parse_line($self, $aline, $param, $rr);
76             push(@{$rr}, $ele) if($ele);
77             }
78             },
79             );
80              
81             # A Lookup-table for all valid DNS Classes.
82             my %_dns_classes = ( IN => 1, CS => 1, CH => 1, HS => 1 );
83              
84             #####################
85             # private functions #
86             #####################
87              
88             # read a full line and strips all comments
89             sub _dns_read_line {
90 14     14   17 my ($file);
91 14         36 ($_, $file) = @_;
92 14         27 s/(?
93 14         565 while(not m/^$_matchparentheses$/) {
94 0         0 my $tail = <$file>;
95 0 0       0 last unless $tail;
96 0         0 chomp;
97 0         0 $tail =~ s/(?
98 0         0 $_ .= $tail;
99             }
100 14         119 return $_;
101             }
102              
103             # Find the correct domain-name for the next item; aware of directives
104             sub _dns_find_name {
105 14     14   133 my $name = dns_next_item(@_);
106 14 100       53 return $name if(substr($name,0,1) eq '$');
107 8         48 return Net::DNS::RR->dns_fqdn($name, $_[2]->{origin});
108             }
109              
110             # parse one (chomped) line of the file
111             sub _dns_parse_line {
112 14     14   30 my ($self, $line, $param, $ret, $lnr, $name) = @_;
113 14 50       120 $name = _dns_find_name($line, $name?$name.".":$name , $param);
114 14 100       43 if(substr($name, 0, 1) eq '$') {
115 6         11 my $directive = substr($name,1);
116 6 50       20 unless ($_dns_directives{$directive}) {
117 0         0 warn("Unknown directive '$directive'\n");
118 0         0 return undef;
119             }
120 6         8 &{$_dns_directives{$directive}}($line, $param, $self, $ret);
  6         28  
121 6         16 return undef;
122             }
123 8         14 $_[5] = $name;
124 8 100       41 return undef if($line =~ m/^\s*$/);
125 4         40 my %prep = (
126             name => $name,
127             ttl => $param->{ttl},
128             class => '',
129             rdlength => 0,
130             rdata => '',
131             Line => $lnr,
132             );
133 4         18 while( not exists $prep{type}) {
134 9         38 my $type = dns_next_item($line);
135 9 50       34 last unless $type;
136 9 100       27 if($_dns_classes{uc($type)}) {
137 4         26 $prep{class} = uc($type);
138 4         14 next;
139             }
140 5 100       28 if($type =~ $_dns_ttlre) {
141 1         3 $prep{ttl} = $1;
142 1         4 next;
143             }
144 4         20 $prep{type} = uc($type);
145             };
146 4 50       21 return undef unless($prep{type});
147 4         26 $line =~ s/\s*$//;
148 4         145 my $subclass = Net::DNS::RR->_get_subclass($prep{type});
149 0         0 my $ele = \%prep;
150 0         0 $ele = $subclass->new_from_filestring($ele, $line, $param);
151 0         0 return $ele;
152             }
153              
154             =pod
155              
156             =head2 EXPORT
157              
158             =head3 parse
159              
160             $rr = Net::DNS::ZoneParse::Parser::Native->parse($param)
161              
162             This is the real parsing-routine, used by Net::DNS::ZoneParse.
163              
164             =cut
165              
166             sub parse {
167 4     4 1 17 my ($self, $param, $ret) = @_;
168 4         13 my $name = $param->{name}.".";
169 4 50       18 $ret = [] unless $ret;
170 4         10 my $fh = $param->{fh};
171 4         52 while(<$fh>) {
172 14         30 my $line = $.;
173 14         27 chomp;
174 14         29 $_ = _dns_read_line($_, $fh);
175 14         116 my $ele = _dns_parse_line(
176             $param->{self}, $_, $param, $ret, $line, $name);
177 10 50       49 next unless $ele;
178 0 0       0 if($ele->can("check")) { next unless $ele->check(); }
  0 0       0  
179 0         0 push(@{$ret}, $ele);
  0         0  
180             }
181 0         0 return $ret;
182             }
183              
184             =pod
185              
186             =head3 dns_next_item
187              
188             $item = dns_next_item($line[, $default])
189              
190             This will return the next item on the given line. If default is given and
191             the line is empty or starts with blanks, $default is returned.
192              
193             $line will be modified to start with the following - not returned - item.
194              
195             This functions is inteded to be used by the extension of Net::DNS::RR::xx
196             parsing functionality.
197              
198             =cut
199              
200             sub dns_next_item {
201 23     23 1 29 local($_);
202 23         23 my $name;
203 23         50 ($_, $name) = @_;
204 23 50       147 if(s/^"(.*?)\s*(?
    100          
205 0         0 $name = $1;
206             } elsif(s/^(\S+)\s*//) {
207 19         179 $name = $1;
208             } else {
209 4         15 s/^\s*//;
210             }
211 23         75 $_[0] = $_;
212 23         54 return $name;
213             }
214              
215              
216             =pod
217              
218             =head1 SEE ALSO
219              
220             Net::DNS::ZoneParse
221              
222             =head1 AUTHOR
223              
224             Benjamin Tietz Ebenjamin@micronet24.deE
225              
226             =head1 COPYRIGHT
227              
228             Copyright (C) 2010 by Benjamin Tietz
229              
230             This library is free software; you can redistribute it and/or modify
231             it under the same terms as Perl itself, either Perl version 5.10.0 or,
232             at your option, any later version of Perl 5 you may have available.
233              
234             =cut
235              
236             1;
237