aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2015-04-01 16:21:40 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2015-04-01 16:21:40 +0300
commit2fd19a6808a9d7b86ad294ae20ad9dcf1c4f6325 (patch)
treeb8374035974b329af6dd8244b395833fae2f49b0
parent4ccb3de29040a53fa55866c84d846639f8ac532a (diff)
downloaddnstools-2fd19a6808a9d7b86ad294ae20ad9dcf1c4f6325.tar.gz
dnstools-2fd19a6808a9d7b86ad294ae20ad9dcf1c4f6325.tar.bz2
nsdbimport: implement import to the database; optionally expand $GENERATE directives
-rwxr-xr-xnsdbimport/nsdbimport203
1 files changed, 155 insertions, 48 deletions
diff --git a/nsdbimport/nsdbimport b/nsdbimport/nsdbimport
index a1db672..da6b501 100755
--- a/nsdbimport/nsdbimport
+++ b/nsdbimport/nsdbimport
@@ -20,6 +20,7 @@ use File::Basename;
20use Pod::Usage; 20use Pod::Usage;
21use Pod::Man; 21use Pod::Man;
22use String::Regexp; 22use String::Regexp;
23use DBI;
23 24
24use constant EX_OK => 0; 25use constant EX_OK => 0;
25use constant EX_USAGE => 64; # command line usage error 26use constant EX_USAGE => 64; # command line usage error
@@ -34,8 +35,11 @@ use constant EX_CONFIG => 78; # configuration error
34my $progname = basename($0); # This script name; 35my $progname = basename($0); # This script name;
35my $progdescr = "converts BIND zone files to SQL database"; 36my $progdescr = "converts BIND zone files to SQL database";
36my $debug; 37my $debug;
38my $dry_run;
37my $bind_directory; 39my $bind_directory;
38my $bind_config; 40my $bind_config;
41my $dbd;
42my $generate_seen;
39 43
40sub error { 44sub error {
41 my $msg = shift; 45 my $msg = shift;
@@ -60,10 +64,11 @@ sub abend {
60my %config; 64my %config;
61 65
62sub readconfig { 66sub readconfig {
63 my $file = shift; 67 my ($file, $kw) = @_;
64 open(my $fd, "<", $file) 68 open(my $fd, "<", $file)
65 or abend(EX_UNAVAILABLE, "can't open configuration file $file: $!"); 69 or abend(EX_UNAVAILABLE, "can't open configuration file $file: $!");
66 my $line; 70 my $line;
71 my $err;
67 while (<$fd>) { 72 while (<$fd>) {
68 ++$line; 73 ++$line;
69 chomp; 74 chomp;
@@ -84,18 +89,24 @@ sub readconfig {
84 } 89 }
85 my ($k,$v) = ($1, $2); 90 my ($k,$v) = ($1, $2);
86 91
87 # unless (exists($config{$k})) { 92 unless (exists($kw->{$k})) {
88 # error("$file:$line: unknown keyword $k"); 93 error("$file:$line: unknown keyword $k");
89 # next; 94 ++$err;
90 # } 95 next;
91 96 }
92 $config{$k} = $v; 97 $config{$k} = $v;
93 } 98 }
94 close $fd; 99 close $fd;
100 exit(EX_CONFIG) if $err;
95 abend(EX_CONFIG, "rr-query is not defined in $file") 101 abend(EX_CONFIG, "rr-query is not defined in $file")
96 unless defined($config{'rr-query'}); 102 unless defined($config{'rr-query'});
97} 103}
98 104
105sub istrue {
106 my $s = shift;
107 return $s =~ /^([1yt])|(yes)|(true)|(enable)$/i;
108}
109
99# ################### 110# ###################
100sub parse_named_conf { 111sub parse_named_conf {
101 my %zone; 112 my %zone;
@@ -122,20 +133,32 @@ sub parse_named_conf {
122 return %files; 133 return %files;
123} 134}
124# ################### 135# ###################
136my $rx_class = array_to_regexp('IN', 'HS', 'CH');
137my @rrtypes = ('A', 'AAAA', 'A6', 'AFSDB',
138 'CNAME', 'DNAME', 'DNSKEY', 'DS',
139 'EUI48', 'EUI64', 'HINFO', 'ISDN',
140 'KEY', 'LOC', 'MX', 'NAPTR',
141 'NS', 'NSEC', 'NXT', 'NXT',
142 'PTR', 'RP', 'RRSIG', 'RT',
143 'SIG', 'SOA', 'SPF', 'SRV',
144 'TXT', 'WKS', 'X25');
145my $rx_rr = array_to_regexp(@rrtypes);
146
147# ###################
125sub replvar { 148sub replvar {
126 my ($rec, $var, $opt) = @_; 149 my ($rec, $var, $opt) = @_;
127 my %option; 150 my %option;
128 if (defined($opt)) { 151 if (defined($opt)) {
129 foreach my $x (split /,/, $opt) { 152 foreach my $x (split /,/, $opt) {
130 if ($x =~ /([?+\.-@])(.*)/) { 153 if ($x =~ /([?+\.@-])(.*)/) {
131 $option{$1} = $2; 154 $option{$1} = $2;
132 } 155 }
133 } 156 }
134 } 157 }
135 158
136 my $val = $rec->{$var}; 159 my $val = $rec->{$var} || '';
137 160
138 if (!defined($val)) { 161 if ($val eq '') {
139 if (defined($option{'-'})) { 162 if (defined($option{'-'})) {
140 $val = $option{'-'}; 163 $val = $option{'-'};
141 } elsif (defined($option{'?'})) { 164 } elsif (defined($option{'?'})) {
@@ -146,7 +169,7 @@ sub replvar {
146 $val = $option{'+'}; 169 $val = $option{'+'};
147 } 170 }
148 171
149 if (defined($val)) { 172 if ($val ne '') {
150 if ($val eq '@' and defined($option{'@'})) { 173 if ($val eq '@' and defined($option{'@'})) {
151 $val = $option{'@'} || $rec->{origin}; 174 $val = $option{'@'} || $rec->{origin};
152 $val .= '.' unless $val =~ /\.$/; 175 $val .= '.' unless $val =~ /\.$/;
@@ -160,17 +183,62 @@ sub replvar {
160 183
161sub query_expand { 184sub query_expand {
162 my ($q, $rec) = @_; 185 my ($q, $rec) = @_;
163 $q =~ s/\$\{([\w_-]+)(?::(.+))?\}/replvar($rec, $1, $2)/gex; 186 $q =~ s/\$\{([\w_-]+)(?::(.+?))?\}/replvar($rec, $1, $2)/gex;
164 debug(2, "$rec->{locus}: $q"); 187 debug(2, "$rec->{locus}: $q");
165 return $q; 188 return $q;
166} 189}
167 190
191sub sql_query {
192 my ($tmpl, $rec) = @_;
193 my $q = query_expand($tmpl, $rec);
194 unless ($dry_run) {
195 $dbd->do($q)
196 or abend(EX_UNAVAILABLE, $dbd->errstr."\nFailed query: $q");
197 }
198}
199
168# generate($expr, $origin, $file, $line); 200# generate($expr, $origin, $file, $line);
169# $GENERATE start-stop[/step] lhs[{offset[,width[,type]]}] rr-type rhs[{offset[,width[,type]]}] 201# $GENERATE start-stop[/step] lhs[{offset[,width[,type]]}] rr-type rhs[{offset[,width[,type]]}]
170# http://www.zytrax.com/books/dns/ch8/generate.html 202# http://www.zytrax.com/books/dns/ch8/generate.html
203
204sub format_part {
205 my ($i, $xhs, $xwid, $xtyp, $loc) = @_;
206 my $ctr;
207
208 if ($xtyp =~ /^[doxX]$/) {
209 $ctr = sprintf($xwid > 0 ? "%0${xwid}$xtyp" : "%$xtyp", $i);
210 } elsif ($xtyp =~ /[nN]/) {
211 my $f = $xtyp eq 'n' ? '%x' : '%X';
212 my @a = reverse(split(//, sprintf("%x", $i)));
213 unshift @a, '0' while (($#a+1) < $xwid);
214 $ctr = join('.', @a);
215 } else {
216 error("invalid type $xtyp in \$GENERATE", prefix => $loc);
217 }
218 $xhs =~ s/\$/$ctr/;
219 return $xhs;
220}
221
171sub generate { 222sub generate {
172 my ($expr, $origin, $file, $line) = @_; 223 my ($expr, $origin, $ttl, $file, $line) = @_;
173 # FIXME 224 my $p = '([^\s\{]+)(?:\{(\d+)(?:(?:,(\d+))(?:,([doxXnN])))\})?';
225 if ($expr =~ /(\d+)-(\d+)(?:\/(\d+))?\s+$p\s+($rx_rr)\s+$p/) {
226 my ($start,$stop,$step,
227 $lhs,$loff,$lwid,$ltyp,
228 $rr,
229 $rhs,$roff,$rwid,$rtyp) = ($1, $2, $3 || 1,
230 $4, $5 || 0, $6 || 0, $7 || 'd',
231 $8,
232 $9, $10 || 0, $11 || 0, $12 || 'd');
233 for (my $i = $start; $i <= $stop; $i += $step) {
234 import_record({origin => $origin,
235 locus => "$file:$line",
236 ttl => $ttl,
237 rr => $rr,
238 label => format_part($i + $loff,$lhs,$lwid,$ltyp),
239 data => format_part($i + $roff,$rhs,$rwid,$rtyp)});
240 }
241 }
174} 242}
175 243
176# ################### 244# ###################
@@ -185,8 +253,7 @@ sub insert_soa {
185 $rec->{retry} = parsetime($5, $rec->{origin}); 253 $rec->{retry} = parsetime($5, $rec->{origin});
186 $rec->{expire} = parsetime($6, $rec->{origin}); 254 $rec->{expire} = parsetime($6, $rec->{origin});
187 $rec->{minimum} = parsetime($7, $rec->{origin}); 255 $rec->{minimum} = parsetime($7, $rec->{origin});
188 my $q = query_expand($tmpl, $rec); 256 sql_query($tmpl, $rec);
189 # FIXME: SQL
190 } else { 257 } else {
191 error("malformed SOA: '$rec->{data}'", 258 error("malformed SOA: '$rec->{data}'",
192 prefix => "warning: $rec->{locus}"); 259 prefix => "warning: $rec->{locus}");
@@ -198,8 +265,7 @@ sub insert_mx {
198 if ($rec->{data} =~ /^(\d+)\s+(.+)$/) { 265 if ($rec->{data} =~ /^(\d+)\s+(.+)$/) {
199 $rec->{mx_priority} = $1; 266 $rec->{mx_priority} = $1;
200 $rec->{mx} = $2; 267 $rec->{mx} = $2;
201 my $q = query_expand($tmpl, $rec); 268 sql_query($tmpl, $rec);
202 # FIXME: SQL
203 } else { 269 } else {
204 error("malformed MX: '$rec->{data}'", 270 error("malformed MX: '$rec->{data}'",
205 prefix => "warning: $rec->{locus}"); 271 prefix => "warning: $rec->{locus}");
@@ -211,8 +277,7 @@ my %rrfun = (SOA => \&insert_soa,
211 277
212sub insert_rr { 278