File Coverage

blib/lib/DNS/Config/File/Nsd.pm
Criterion Covered Total %
statement 24 458 5.2
branch 0 200 0.0
condition 0 42 0.0
subroutine 8 20 40.0
pod 0 12 0.0
total 32 732 4.3


line stmt bran cond sub pod time code
1             #!/usr/local/bin/perl -w
2             ######################################################################
3             #
4             # DNS/Config/File/Nsd.pm
5             #
6             # $Id: Nsd.pm,v 1.3 2003/02/16 10:15:32 awolf Exp $
7             # $Revision: 1.3 $
8             # $Author: awolf $
9             # $Date: 2003/02/16 10:15:32 $
10             #
11             # Copyright (C)2003 Bruce Campbell. All rights reserved.
12             # Base Class (Bind9) (C)2001-2003 Andy Wolf. All rights reserved.
13             #
14             # This library is free software; you can redistribute it and/or
15             # modify it under the same terms as Perl itself.
16             #
17             ######################################################################
18              
19             package DNS::Config::File::Nsd;
20              
21 1     1   649 no warnings 'portable';
  1         1  
  1         34  
22 1     1   11 use 5.6.0;
  1         3  
  1         39  
23 1     1   5 use strict;
  1         2  
  1         28  
24 1     1   5 use warnings;
  1         2  
  1         31  
25              
26 1     1   4 use vars qw(@ISA);
  1         3  
  1         47  
27              
28 1     1   6 use DNS::Config;
  1         1  
  1         30  
29 1     1   569 use DNS::Config::Server;
  1         2  
  1         26  
30 1     1   552 use DNS::Config::Statement;
  1         3  
  1         5810  
31              
32             @ISA = qw(DNS::Config::File);
33              
34             my $VERSION = '0.66';
35             my $REVISION = sprintf("%d.%02d", q$Revision: 1.3 $ =~ /(\d+)\.(\d+)/);
36              
37             # FILE is the nsd.zones file.
38             sub new {
39 0     0 0   my($pkg, $file, $config) = @_;
40 0   0       my $class = ref($pkg) || $pkg;
41              
42 0           my $self = {
43             'FILE' => $file
44             };
45              
46 0 0         $self->{'CONFIG'} = $config if($config);
47            
48 0           bless $self, $class;
49            
50 0           return $self;
51             }
52              
53             # NSD has an additional config file for nsdc. Return the filename
54             # if it has been defined.
55             sub nsdc {
56 0     0 0   my( $self, $file ) = (@_);
57              
58 0 0         if( defined( $file ) ){
59 0           $self->{'NSDC'} = $file;
60             }
61              
62 0           return( $self->{'NSDC'} );
63             }
64              
65             # NSD has a directory for TSIG keys. Return the directory if it
66             # has been defined.
67             sub nsdkeysdir {
68 0     0 0   my( $self, $dir ) = (@_);
69              
70 0 0         if( defined( $dir ) ){
71 0           $self->{'NSDKEYSDIR'} = $dir;
72             }
73              
74 0           return( $self->{'NSDKEYSDIR'} );
75             }
76              
77              
78             sub do_gettsig {
79 0     0 0   my $self = shift;
80 0           my $tsigdir = shift;
81 0           my $keyname = shift;
82              
83             # This really should be a subroutine in DNS::Config::Statement::Keys.
84 0           my %algs = (
85             "157", "hmac-md5",
86             );
87              
88             # Get what it is.
89 0           my $t_type = undef;
90 0           my $t_zone = undef;
91 0           my $t_ip = undef;
92 0 0         if( $keyname =~ /^\s*(zi)\-(\S+)\-([^\-]+)\s*$/i ){
    0          
93 0           $t_type = lc( $1 );
94 0           $t_zone = $2;
95 0           $t_ip = $3;
96             }elsif( $keyname =~ /^\s*(ip|zo)\-(\S+)\s*$/i ){
97             # either zo-$zone or ip-$ip
98 0           $t_type = lc($1);
99 0           $t_zone = $2;
100 0 0         if( $t_type eq "ip" ){
101 0           $t_ip = $t_zone;
102 0           $t_zone = undef;
103             }
104             }else{
105 0           $t_type = "unknown";
106             }
107              
108             # We return a string (or maybe not) that should be inserted into
109             # the main stream. Usually we define a key, or a server statement,
110             # but only if we haven't already done so for this key or server.
111 0           my $retmain = undef;
112 0           my $retkey = undef;
113              
114 0 0         if( ! defined( $self->{'TSIG'} ) ){
115 0           %{$self->{'TSIG'}} = ();
  0            
116             }
117              
118 0 0         if( ! defined( ${$self->{'TSIG'}}{$keyname} ) ){
  0            
119             # We need to read in the file.
120 0           my $t_file = "$tsigdir" . "/" . "$keyname" . ".tsiginfo";
121 0 0         if( -f "$t_file" ){
122             #
123 0 0         if( open( TSIGINPUT, "$t_file" ) ){
124             # Server IP address.
125 0           my $t_addr = ;
126 0           my $t_name = ;
127 0           my $t_alg = ;
128 0           my $t_sec = undef;
129 0           while( my $line = ){
130 0           chomp( $line );
131 0           $t_sec .= $line;
132             }
133 0           close( TSIGINPUT );
134              
135 0           chomp( $t_addr );
136 0           chomp( $t_name );
137 0           chomp( $t_alg );
138 0           chomp( $t_sec );
139              
140             # print STDERR "Blot - $t_addr $t_name $t_alg $t_sec\n";
141              
142             # Store it here, and elsewhere.
143 0           ${$self->{'TSIG'}}{$keyname}{'ip'} = $t_addr;
  0            
144 0           ${$self->{'TSIG'}}{$keyname}{'name'} = $t_name;
  0            
145 0           ${$self->{'TSIG'}}{$keyname}{'algorithm-num'} = $t_alg;
  0            
146 0 0         if( defined( $algs{$t_alg} ) ){
147 0           ${$self->{'TSIG'}}{$keyname}{'algorithm'} = $algs{$t_alg};
  0            
148             }else{
149 0           ${$self->{'TSIG'}}{$keyname}{'algorithm'} = $t_alg;
  0            
150             }
151            
152 0           ${$self->{'TSIG'}}{$keyname}{'secret'} = $t_sec;
  0            
153 0           ${$self->{'TSIG'}}{$keyname}{'realname'} = "___$t_name";
  0            
154            
155             }
156             }
157             }
158              
159             # See if we've got this one.
160 0 0         if( defined( ${$self->{'TSIG'}}{$keyname} ) ){
  0            
161             # We've got it. Whats the actual keyname?
162 0           my $t_real = ${$self->{'TSIG'}}{$keyname}{'realname'};
  0            
163              
164             # If its not there, copy it.
165 0 0         if( ! defined( ${$self->{'TSIG'}}{$t_real} ) ){
  0            
166 0           ${$self->{'TSIG'}}{$t_real}{'ip'} = ${$self->{'TSIG'}}{$keyname}{'ip'};
  0            
  0            
167 0           ${$self->{'TSIG'}}{$t_real}{'name'} = ${$self->{'TSIG'}}{$keyname}{'name'};
  0            
  0            
168 0           ${$self->{'TSIG'}}{$t_real}{'secret'} = ${$self->{'TSIG'}}{$keyname}{'secret'};
  0            
  0            
169 0           ${$self->{'TSIG'}}{$t_real}{'algorithm'} = ${$self->{'TSIG'}}{$keyname}{'algorithm'};
  0            
  0            
170 0           ${$self->{'TSIG'}}{$t_real}{'algorithm-num'} = ${$self->{'TSIG'}}{$keyname}{'algorithm-num'};
  0            
  0            
171             }
172              
173             # Whats the name of this one?
174 0           $retkey = ${$self->{'TSIG'}}{$t_real}{'name'};
  0            
175              
176             # Do we need to define this one?
177 0 0         if( ! defined( ${$self->{'TSIG'}}{$t_real}{'done'} ) ){
  0            
178             # We do need to define it.
179 0           $retmain .= " key " . ${$self->{'TSIG'}}{$t_real}{'name'} . " {";
  0            
180 0           $retmain .= " algorithm " . ${$self->{'TSIG'}}{$t_real}{'algorithm'} . ";";
  0            
181 0           $retmain .= " secret \"" . ${$self->{'TSIG'}}{$t_real}{'secret'} . "\";";
  0            
182 0           $retmain .= " };";
183              
184             # Say that we've defined this one.
185 0           ${$self->{'TSIG'}}{$t_real}{'done'}++;
  0            
186             }
187              
188 0 0 0       if( $t_type eq "ip" && ! defined( ${$self->{'TSIG'}}{$keyname}{'done'} ) && defined( $t_ip ) ){
  0   0        
189             # We now need to use this key with the server.
190 0           $retmain .= " server $t_ip { keys { " . ${$self->{'TSIG'}}{$keyname}{'name'} . "; }; };";
  0            
191 0           ${$self->{'TSIG'}}{$keyname}{'done'}++;
  0            
192              
193             # print STDERR "Foo - $retmain\n";
194             }
195             }
196              
197              
198 0           return( $retmain, $retkey );
199              
200             }
201              
202             sub parse {
203 0     0 0   my($self, $file) = @_;
204              
205 0   0       $file = $file || $self->{'FILE'};
206              
207 0           my @lines = $self->read($file);
208              
209 0           my @nsdc = $self->read( $self->nsdc() );
210              
211             # This space left blank for any includes.
212            
213 0 0         return undef unless(scalar @lines);
214              
215 0 0         $self->{'CONFIG'} = new DNS::Config() if(!$self->{'CONFIG'});
216            
217 0           my $result;
218              
219 0           my %nsdc_h = (
220             "namedxfer", "CP:named-xfer VAL;",
221             "nsdzonesdir", "CP:directory VAL;",
222             "nsdflags", "SPECIAL",
223             "nsdkeysdir", "SPECIAL",
224             );
225              
226 0           $result .= " options {";
227              
228             # Loop through the nsdc lines.
229 0           my $nsdkeysdir = undef;
230              
231 0           for my $line (@nsdc) {
232              
233 0 0         next unless( $line =~ /^\s*(\S+)\s*=\s*\"(.*)\"\s*(\#.*)?$/ );
234 0           my $name = lc( $1 );
235 0           my $fill = $2;
236              
237 0 0         next unless( defined( $nsdc_h{$name} ) );
238              
239 0           my $tval = $nsdc_h{$name};
240 0 0 0       if( $tval =~ /^CP:(\S+.*)\s*$/ ){
    0 0        
    0          
241 0           $tval = $1;
242 0           $tval =~ s/VAL/$fill/g;
243 0           $result .= " $tval";
244             }elsif( $tval eq 'SPECIAL' && $name eq 'nsdflags' ){
245             # Special processing required.
246 0           my @tsplit = split( /\s+/, $fill );
247 0           my $curflag = undef;
248 0           my @addys = ();
249 0           my $port = 53;
250 0           foreach my $kkey( @tsplit ){
251 0 0         if( $kkey =~ /^\s*\-[ap]\s*$/ ){
    0          
252 0           $curflag = $kkey;
253             }elsif( defined($curflag) ){
254 0 0         if( $curflag eq '-a' ){
    0          
255 0           push @addys, $kkey;
256             }elsif( $curflag eq '-p' ){
257 0           $port = $kkey;
258             }
259             }
260             }
261              
262              
263 0           $result .= " listen-on port $port {";
264 0           foreach my $kkey( @addys ){
265 0           $result .= " $kkey;";
266             }
267              
268 0           $result .= " };";
269             }elsif( $tval eq 'SPECIAL' && $name eq 'nsdkeysdir' ){
270 0           $nsdkeysdir = $fill;
271             }else{
272 0           next;
273             }
274              
275             }
276              
277 0           $nsdkeysdir = $self->nsdkeysdir( $nsdkeysdir );
278              
279 0           $result .= " };";
280              
281             # tsig stuff. Wheee.
282 0           my %tsigs = ();
283              
284             # Loop through the lines in nsd.zones.
285 0           for my $line (@lines) {
286            
287             # replace lots of space with one space.
288 0           $line =~ s/\s+/ /g;
289              
290             # Remove '//' style comments.
291 0           $line =~ s/\/\/.*$//g;
292              
293             # Remove '#' style comments.
294 0           $line =~ s/\#.*$//g;
295              
296             # nsd.zones only has lines beginning with 'zone'.
297 0 0         next unless( $line =~ /^\s*zone\s+(\S+)\s+(\S+)\s*(\S*.*)\s*$/ );
298 0           my $this_zone=$1;
299 0           my $this_file=$2;
300 0           my $this_rest=$3;
301              
302             # We rework the string into Bind9-style, as the code for
303             # dealing with this is nice and solid.
304              
305             # Set up a temporary line first. We may need to insert
306             # stuff into the stream beforehand (With BIND, you need to
307             # define keys before you use them. By inserting stuff in
308             # this stream before we use them, we hopefully stop people
309             # shooting themselves in the foot if they generate a named.conf
310             # file by simply dumping the config out.
311              
312 0           my $tmpresult = " zone \"$this_zone\" in { file \"$this_file\";";
313              
314 0           my $tmptype = "master";
315 0 0         if( $this_rest =~ /masters\s*((\s+(\d+\.){3,3}\d+|\s+(([0-9a-f]*:){1,15}(:[0-9a-f]+){1,15}))){1,}\s*(notify|$)/ ){
316 0           my @tmpres3 = split( / /, $1 );
317 0           $tmpresult .= " masters {";
318 0           foreach my $tval ( @tmpres3 ){
319 0           $tmpresult .= " $tval";
320 0 0         if( defined( $nsdkeysdir ) ){
321 0 0         if( -f $nsdkeysdir . "/ip-" . $tval . ".tsiginfo" ){
322             # print STDERR "Got dir $nsdkeysdir\n";
323             # we need to predefine a key.
324 0           my ($tmpstr, $keyname) = $self->do_gettsig( $nsdkeysdir, "ip-$tval" );
325 0 0         $result .= $tmpstr if( defined( $tmpstr ) );
326             }
327 0 0         if( -f $nsdkeysdir . "/zi-" . $this_zone . "-" . $tval . ".tsiginfo" ){
    0          
328             # This key gets used for this
329             # one.
330 0           my ($tmpstr, $keyname) = $self->do_gettsig( $nsdkeysdir, "zi-$this_zone-$tval" );
331 0 0         $result .= $tmpstr if( defined( $tmpstr ) );
332 0 0         $tmpresult .= " key $keyname" if( defined( $keyname ) );
333             }elsif( -f $nsdkeysdir . "/zo-" . $this_zone . ".tsiginfo" ){
334             # This key gets used for this
335             # one.
336 0           my ($tmpstr, $keyname) = $self->do_gettsig( $nsdkeysdir, "zo-$this_zone" );
337 0 0         $result .= $tmpstr if( defined( $tmpstr ) );
338 0 0         $tmpresult .= " key $keyname" if( defined( $keyname ) );
339             }
340             }
341              
342 0           $tmpresult .= ";";
343             }
344 0           $tmpresult .= " };";
345 0           $tmptype = "slave";
346             }
347              
348 0 0         if( $this_rest =~ /notify\s*((\s+(\d+\.){3,3}\d+|\s+(([0-9a-f]*:){1,15}(:[0-9a-f]+){1,15}))){1,}\s*(masters|$)/ ){
349              
350 0           my @tmpres3 = split( / /, $1 );
351 0           $tmpresult .= " also-notify {";
352 0           foreach my $tval ( @tmpres3 ){
353 0           $tmpresult .= " $tval;";
354             }
355 0           $tmpresult .= " };"
356             }
357              
358             # We need to check for tsig keys now.
359 0 0         if( defined( $nsdkeysdir ) ){
360 0 0         if( -f $nsdkeysdir . "/zo-" . $this_zone . ".tsiginfo" ){
361 0           my ($tmpstr, $keyname) = $self->do_gettsig( $nsdkeysdir, "zo-$this_zone" );
362 0 0         $result .= $tmpstr if( defined( $tmpstr ) );
363 0 0         $tmpresult .= "allow-transfer { key $keyname;};" if( defined( $keyname ) );
364             }
365             }
366            
367             # Now that we've put tsig stuff beforehand, put in the zone.
368 0           $result .= " $tmpresult type $tmptype;";
369             # and end it.
370 0           $result .= " };";
371             }
372              
373 0           my $tree = &analyze_brackets($result);
374 0           my @res = &analyze_statements(@$tree);
375              
376 0           foreach my $temp (@res) {
377 0           my @temp = @$temp;
378 0           my $type = shift @temp;
379              
380 0           my $statement;
381              
382 0           eval {
383 0           my $tmp = 'DNS::Config::Statement::' . ucfirst(lc $type);
384              
385 0 0         if ( eval "require $tmp" ){
386 0           $statement = $tmp->new();
387 0           $statement->parse_tree(@temp);
388             }else{
389             # Doesn't exist.
390 0           print STDERR "Require of $tmp failed\n";
391             }
392             };
393              
394 0 0         if($@) {
395             #warn $@;
396            
397 0           $statement = DNS::Config::Statement->new();
398 0           $statement->parse_tree($type, @temp);
399             }
400              
401 0           $self->{'CONFIG'}->add($statement);
402             }
403            
404 0           return $self;
405             }
406              
407              
408             # This routine only dumps the nsd.zones file.
409             sub dump_nsd_zones {
410 0     0 0   my($self, $file) = @_;
411            
412 0   0       $file = $file || $self->{'FILE'};
413              
414 0 0         return undef unless($file);
415 0 0         return undef unless($self->{'CONFIG'});
416              
417 0           my $config = $self->config;
418 0           my @statements = $config->statements;
419              
420 0           my $infile = 0;
421 0           my $old_fh = undef;
422 0 0         if($file) {
423 0 0         if(open(FILE, ">$file")) {
424 0           $old_fh = select(FILE);
425 0           $infile = 1;
426             }else{
427 0           return( undef );
428             }
429             }
430              
431             # We need to iterate through the config outselves
432 0           foreach my $statement ( @statements ){
433 0           my $tmpref = ref $statement;
434              
435             # Dump only the zone mentions.
436 0 0         next unless( $tmpref =~ /^DNS::Config::Statement::Zone$/ );
437              
438             # ; zone^Iname^I^Ifilename^I^I[ masters/notify ip-address ]$
439             # zone^I.^I^Iprimary/root.zone^Inotify 128.9.0.107 192.33.4.12 128.8.10.90$
440             # zone^Iww.net^I^Iprimary/ww.net$
441             # zone^Inlnetlabs.nl^Isecondary/nlnetlabs.nl^Imasters 213.53.69.1$
442 0           print "zone\t" . $statement->{'NAME'} . "\t\t" . $statement->{'FILE'};
443 0           my @masters = $statement->masters();
444 0           my @anotify = $statement->also_notifys();
445 0 0         if( ( scalar @masters ) > 0 ){
446 0           print "\tmasters";
447 0           foreach my $kkey( @masters ){
448 0           my @foo = @{$kkey};
  0            
449 0           foreach my $kkey2( @foo ){
450 0           print " $kkey2";
451             }
452             }
453             }
454 0 0         if( ( scalar @anotify ) > 0 ){
455 0           print "\tnotify";
456 0           foreach my $kkey( @anotify ){
457 0           my @foo = @{$kkey};
  0            
458 0           foreach my $kkey2( @foo ){
459 0           print " $kkey2";
460             }
461             }
462             }
463 0           print "\n";
464             # print "Foo " . $statement->master . "\n";
465             }
466              
467              
468             # If we're in a file, select() back.
469 0 0         if( $infile ){
470             # map { $_->dump() } $self->config()->statements();
471 0           select($old_fh);
472 0           close FILE;
473 0           $infile = 0;
474             }
475            
476 0           return $self;
477             }
478              
479             sub dump_nsdc {
480 0     0 0   my($self, $file) = @_;
481            
482 0   0       $file = $file || $self->{'FILE'};
483              
484 0 0         return undef unless($file);
485 0 0         return undef unless($self->{'CONFIG'});
486              
487 0           my $config = $self->config;
488 0           my @statements = $config->statements;
489              
490 0           my $infile = 0;
491 0           my $old_fh = undef;
492 0 0         if($file) {
493 0 0         if(open(FILE, ">$file")) {
494 0           $old_fh = select(FILE);
495 0           $infile = 1;
496             }else{
497 0           return( undef );
498             }
499             }
500              
501             # We need to iterate through the config outselves
502 0           foreach my $statement ( @statements ){
503 0           my $tmpref = ref $statement;
504              
505             # Dump only the option mentions.
506 0 0         next unless( $tmpref =~ /^DNS::Config::Statement::Options$/ );
507              
508             # Where named-xfer is.
509 0 0         if( defined( $statement->{'NAMED-XFER'} ) ){
510 0           print "NAMEDXFER=\"" . $statement->{'NAMED-XFER'} . "\"\n";
511             }
512              
513             # Where NSDZONES is.
514 0 0         if( defined( $statement->{'DIRECTORY'} ) ){
515 0           print "NSDZONES=\"" . $statement->{'DIRECTORY'} . "\"\n";
516             }
517              
518             # Where the NSDKEYSDIR is.
519             # nsdkeysdir isn't expected to be in the Options statement.
520 0 0         if( defined( $self->nsdkeysdir() ) ){
    0          
    0          
521 0           print "NSDKEYSDIR=\"" . $self->nsdkeysdir() . "\"\n";
522             }elsif( defined( $statement->{'NSDKEYSDIR'} ) ){
523 0           print "NSDKEYSDIR=\"" . $statement->{'NSDKEYSDIR'} . "\"\n";
524             }elsif( defined( $statement->{'DIRECTORY'} ) ){
525 0           print "NSDKEYSDIR=\"" . $statement->{'DIRECTORY'} . "\"\n";
526             }
527              
528             # Now for the flags. Oh my.
529 0 0         if( defined( $statement->{'LISTEN-ON'} ) ){
530              
531 0           print "NSDFLAGS=\"";
532              
533 0           my @tsplit = @{ $statement->{'LISTEN-ON'} };
  0            
534              
535 0           foreach my $kkey( @tsplit ){
536 0 0         if( ! ref( $kkey ) ){
537 0 0         if( $kkey =~ /port/i ){
538 0           print " -p";
539             }else{
540 0           print " $kkey";
541             }
542             }else{
543 0           my @tref1 = @{$kkey};
  0            
544 0           foreach my $kkey2( @tref1 ){
545 0 0         if( ref( $kkey2 ) ){
546 0           push @tref1, @{$kkey2};
  0            
547 0           next;
548             }
549 0 0         if( $kkey2 =~ /any/ ){
550             # NSD doesn't handle
551             # multiple interfaces
552             # correctly. This is
553             # a hack to deal with
554             # these cases.
555 0           print " \`ifconfig -a | perl -e \'while(<>){ next unless(m/^\\s*inet(4|6)?(\\s+addr:)?\\s*(((\\d+\\.){3,3}\\d+)|(([0-9a-f]*:){1,15}(:[0-9a-f]+){1,15}))(\\/\\d+)?\\s+/); print \" -a \$3\"; }\'\`";
556             }else{
557 0           print " -a $kkey2";
558             }
559             }
560             }
561             }
562              
563 0           print "\"\n";
564             }
565 0           print "\n";
566             }
567              
568              
569             # If we're in a file, select() back.
570 0 0         if( $infile ){
571             # map { $_->dump() } $self->config()->statements();
572 0           select($old_fh);
573 0           close FILE;
574 0           $infile = 0;
575             }
576            
577 0           return $self;
578             }
579              
580             sub dump_tsig() {
581 0     0 0   my($self, $dir) = @_;
582              
583 0   0       $dir = $dir || $self->nsdkeysdir();
584              
585 0 0         return( undef ) unless( defined( $dir ) );
586              
587             # Make sure that its useful.
588 0 0         return( undef ) unless( -d $dir );
589 0 0         return( undef ) unless( -r $dir );
590 0 0         return( undef ) unless( -w $dir );
591 0 0         return( undef ) unless( -x $dir );
592              
593             # Map the algorithms.
594             # Should really be invoking DNS::Config::Statement::Key for this.
595 0           my %algs = (
596             "157", "hmac-md5",
597             "hmac-md5", "157",
598             );
599              
600             # Run through the statements.
601 0           my $config = $self->config;
602 0           my @statements = $config->statements;
603              
604 0           my %keys = ();
605 0           my %keys_written = ();
606 0           my %want_keys = ();
607              
608 0           foreach my $statement( @statements ){
609 0           my $tref = ref( $statement );
610              
611             # We only want Key, Zone or Server statements.
612 0 0         next unless( $tref =~ /^DNS::Config::Statement::(Key|Zone|Server)$/ );
613              
614 0           my $this_ref = $1;
615 0 0         if( $this_ref eq 'Key' ){
    0          
    0          
616 0           my $tname = $statement->name();
617 0           my $talg = $statement->algorithm();
618 0           my $tsecret = $statement->secret();
619              
620 0 0         if( $talg =~ /\D/ ){
621 0           $talg = $algs{$talg};
622             }
623              
624 0           $keys{$tname}{'name'} = $tname;
625 0           $keys{$tname}{'algorithm'} = $talg;
626 0           $keys{$tname}{'secret'} = $tsecret;
627             }elsif( $this_ref eq 'Server' ){
628              
629 0           my $tname = $statement->name();
630 0           my @tkeys = $statement->keys();
631 0           my %usekeys = ();
632 0           foreach my $kkey( @tkeys ){
633 0 0         if( ref( $kkey ) ){
634 0           push @tkeys, @{$kkey};
  0            
635             }else{
636 0           $usekeys{"$kkey"}++;
637             }
638             }
639              
640 0           foreach my $kkey( keys %usekeys ){
641 0           my $tstr = "ip-$tname.tsiginfo";
642 0           $want_keys{$tstr} = $kkey;
643             }
644             }elsif( $this_ref eq 'Zone' ){
645 0           my $tname = $statement->name();
646              
647 0           my @masters = $statement->masters();
648              
649 0           my $loop = 0;
650              
651             # This is possibly multiple levels of array, that
652             # should be the sequence of things in the 'masters'
653             # field of the zone statement. We *should* have
654             # 'ip', 'port', 'port_num', 'key', 'key_id', 'ip' (etc)
655             # with the 'port', 'port_num' and 'key', 'key_id'
656             # sequences optional.
657 0           while( $loop < scalar @masters ){
658 0           my $kkey = $masters[$loop];
659 0 0         if( ref( $kkey ) ){
660 0           push @masters, @{$kkey};
  0            
661 0           $loop++;
662             }else{
663             # $ip key $keyname
664 0           my $tip = $kkey;
665 0           $loop++;
666 0           my $tport = undef;
667 0           my $tkey = undef;
668 0   0       while( ( $loop + 2 ) < ( scalar @masters ) && ! ref( $masters[$loop] ) && ! ref( $masters[$loop+1] ) && $masters[$loop] =~ /(port|key)/i ){
      0        
      0        
669 0           my $twhat=$1;
670 0 0         if( $twhat =~ /key/i ){
    0          
671 0           $tkey = $masters[$loop+1];
672 0           $loop++;
673             }elsif( $twhat =~ /port/i ){
674 0           $tport = $masters[$loop+1];
675 0           $loop++;
676             }
677 0           $loop++;
678             }
679              
680             # We found a key for this zone. Yay!
681 0 0         if( defined( $tkey ) ){
682 0           my $tstr = "zi-$tname-$tip.tsiginfo";
683 0           $want_keys{$tstr} = $tkey;
684             }
685             }
686             }
687             }
688             }
689              
690             # Now write out all of the keys.
691 0           foreach my $kkey( keys %want_keys ){
692 0           my $tkey = $want_keys{$kkey};
693              
694 0           print STDERR "Key - $kkey - $tkey\n";
695 0 0         next if( defined( $keys_written{$kkey} ) );
696 0 0         next if( ! defined( $keys{$tkey}{'name'} ) );
697              
698             # Wheres the IP address?
699 0           my $tip = "IPADDRESS";
700              
701             # zi-$zone-$ip.tsiginfo
702 0 0         if( $kkey =~ /^zi-\S+-([^\-]+).tsiginfo$/ ){
    0          
703 0           $tip=$1;
704             # ip-$ip.tsiginfo
705             }elsif( $kkey =~/^ip-(\S+).tsiginfo$/ ){
706 0           $tip=$1;
707             }
708              
709             # Write out the file.
710              
711 0 0         if( open( TSIGOUT, "> $dir/$kkey" ) ){
712 0           print TSIGOUT "$tip\n";
713 0           print TSIGOUT $keys{$tkey}{'name'} . "\n";
714 0           print TSIGOUT $keys{$tkey}{'algorithm'} . "\n";
715              
716             # Deal with the secret.
717 0           my $toutsec = undef;
718 0 0         if( ref( $keys{$tkey}{'secret'} ) ){
719 0           $toutsec = join( ' ', @{$keys{$tkey}{'secret'}} ) ;
  0            
720             }else{
721 0           $toutsec = $keys{$tkey}{'secret'};
722             }
723 0           $toutsec =~ s/^"//g;
724 0           $toutsec =~ s/"$//g;
725 0           print TSIGOUT "$toutsec";
726 0           print TSIGOUT "\n";
727 0           close( TSIGOUT );
728 0           $keys_written{$kkey}++;
729             }
730            
731             }
732            
733 0           return( $self );
734             }
735              
736             sub dump {
737 0     0 0   my($self, $file) = @_;
738              
739             # Eventually this could dump all of it, but you need to specify
740             # multiple files.
741 0           return( $self->dump_nsd_zones( $file ) );
742             }
743              
744             sub config {
745 0     0 0   my($self) = @_;
746            
747 0           return($self->{'CONFIG'});
748             }
749              
750             sub analyze_brackets {
751 0     0 0   my($string) = @_;
752            
753 0           my @chars = split //, $string;
754              
755 0           my $tree = [];
756 0           my @chunks;
757             my @stack;
758              
759 0           my %matching = (
760             '(' => ')',
761             '[' => ']',
762             '<' => '>',
763             '{' => '}',
764             );
765              
766 0           for my $char (@chars) {
767 0 0         if(grep {$char eq $_} keys(%matching)) {
  0 0          
  0            
768 0           my $temp = [];
769 0           push @$tree, $temp;
770 0           push @chunks, $tree;
771 0           push @stack, $matching{$char};
772 0           $tree = $temp;
773             }
774             elsif(grep {$char eq $_} values(%matching)) {
775 0           my $expected = pop @stack;
776 0 0 0       die "Invalid order !\n" if((!defined $expected) || ($char ne $expected));
777 0           $tree = pop @chunks;
778 0 0         die "Unmatched closing !\n" if(!ref($tree));
779             }
780             else {
781 0           my $noe = scalar(@$tree);
782            
783 0 0 0       if((!$noe) || (ref($$tree[$noe-1]) eq 'ARRAY')) {
784 0           push @$tree, ($char);
785             }
786             else {
787 0           $$tree[$noe-1] .= $char;
788             }
789             }
790             }
791              
792 0 0         die "Unbalanced !\n" if(scalar @stack);
793              
794 0           return($tree);
795             }
796              
797             sub analyze_statements {
798 0     0 0   my(@array) = @_;
799 0           my @result;
800             my $full;
801            
802 0           for my $line (@array) {
803 0 0         if(!ref($line)) {
804 0           $line =~ s/\s*\;\s*/\;/g;
805              
806 0           my(@parts) = split /;/, $line, -1;
807              
808 0 0         shift @parts if(!$parts[0]);
809              
810 0 0         if($parts[$#parts-1] eq '') {
811 0           $full = 1;
812 0           pop @parts;
813             }
814             else {
815 0           $full = 0;
816             }
817              
818 0           for my $temp (@parts) {
819 0 0         if($temp) {
820 0           $temp =~ s/^\s*//g;
821            
822 0           my @chunks = split / /, $temp;
823              
824 0           push @result, (\@chunks);
825             }
826             }
827             }
828             else {
829 0           my @statements = &analyze_statements(@$line);
830              
831 0           my @temp;
832 0 0         if(!$full) { my $temp = pop @result; @temp = @$temp; }
  0            
  0            
833 0           push @temp, (\@statements);
834 0           push @result, (\@temp);
835             }
836             }
837              
838 0           return(@result);
839             }
840              
841             1;
842              
843             __END__