diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2015-04-01 16:21:40 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2015-04-01 16:21:40 +0300 |
commit | 2fd19a6808a9d7b86ad294ae20ad9dcf1c4f6325 (patch) | |
tree | b8374035974b329af6dd8244b395833fae2f49b0 | |
parent | 4ccb3de29040a53fa55866c84d846639f8ac532a (diff) | |
download | dnstools-2fd19a6808a9d7b86ad294ae20ad9dcf1c4f6325.tar.gz dnstools-2fd19a6808a9d7b86ad294ae20ad9dcf1c4f6325.tar.bz2 |
nsdbimport: implement import to the database; optionally expand $GENERATE directives
-rwxr-xr-x | nsdbimport/nsdbimport | 203 |
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; | |||
20 | use Pod::Usage; | 20 | use Pod::Usage; |
21 | use Pod::Man; | 21 | use Pod::Man; |
22 | use String::Regexp; | 22 | use String::Regexp; |
23 | use DBI; | ||
23 | 24 | ||
24 | use constant EX_OK => 0; | 25 | use constant EX_OK => 0; |
25 | use constant EX_USAGE => 64; # command line usage error | 26 | use constant EX_USAGE => 64; # command line usage error |
@@ -34,8 +35,11 @@ use constant EX_CONFIG => 78; # configuration error | |||
34 | my $progname = basename($0); # This script name; | 35 | my $progname = basename($0); # This script name; |
35 | my $progdescr = "converts BIND zone files to SQL database"; | 36 | my $progdescr = "converts BIND zone files to SQL database"; |
36 | my $debug; | 37 | my $debug; |
38 | my $dry_run; | ||
37 | my $bind_directory; | 39 | my $bind_directory; |
38 | my $bind_config; | 40 | my $bind_config; |
41 | my $dbd; | ||
42 | my $generate_seen; | ||
39 | 43 | ||
40 | sub error { | 44 | sub error { |
41 | my $msg = shift; | 45 | my $msg = shift; |
@@ -60,10 +64,11 @@ sub abend { | |||
60 | my %config; | 64 | my %config; |
61 | 65 | ||
62 | sub readconfig { | 66 | sub 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 | ||
105 | sub istrue { | ||
106 | my $s = shift; | ||
107 | return $s =~ /^([1yt])|(yes)|(true)|(enable)$/i; | ||
108 | } | ||
109 | |||
99 | # ################### | 110 | # ################### |
100 | sub parse_named_conf { | 111 | sub 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 | # ################### |
136 | my $rx_class = array_to_regexp('IN', 'HS', 'CH'); | ||
137 | my @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'); | ||
145 | my $rx_rr = array_to_regexp(@rrtypes); | ||
146 | |||
147 | # ################### | ||
125 | sub replvar { | 148 | sub 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 | ||
161 | sub query_expand { | 184 | sub 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 | ||
191 | sub 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 | |||
204 | sub 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 | |||
171 | sub generate { | 222 | sub 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 | ||
212 | sub insert_rr { | 278 |