source: trunk/tiny-import.pl@ 348

Last change on this file since 348 was 348, checked in by Kris Deugau, 12 years ago

/trunk

Add partially-fleshed-out stub tinydns flatfile import script.
Actual import functionality should probably be moved to a module.

  • Property svn:executable set to *
  • Property svn:keywords set to Date Rev Author Id
File size: 7.9 KB
Line 
1#!/usr/bin/perl
2# dnsadmin shell-based import tool for tinydns flatfiles
3##
4# $Id: tiny-import.pl 348 2012-06-15 22:13:16Z kdeugau $
5# Copyright 2012 Kris Deugau <kdeugau@deepnet.cx>
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19##
20
21use strict;
22use warnings;
23
24use lib '.';
25use DNSDB qw(:ALL);
26
27if (!loadConfig()) {
28 warn "Using default configuration; unable to load custom settings: $DNSDB::errstr";
29}
30
31my $code;
32my ($dbh,$msg) = connectDB($config{dbname}, $config{dbuser}, $config{dbpass}, $config{dbhost});
33initGlobals($dbh) if $dbh;
34
35$dbh->{AutoCommit} = 0;
36$dbh->{RaiseError} = 1;
37
38my %cnt;
39my @deferred;
40
41foreach my $file (@ARGV) {
42 eval {
43 import(file => $file);
44# import(file => $file, nosoa => 1);
45 $dbh->rollback;
46# $dbh->commit;
47 };
48 if ($@) {
49 print "bleh: $@\n";
50die "die harder\n";
51 }
52}
53
54 foreach (keys %cnt) {
55 print " $_ $cnt{$_}\n";
56 }
57
58exit 0;
59
60sub import {
61 our %args = @_;
62 my $flatfile = $args{file};
63 open FLAT, "<$flatfile";
64
65 our $recsth = $dbh->prepare("INSERT INTO records (domain_id,rdns_id,host,type,val,distance,weight,port,ttl) ".
66 " VALUES (?,?,?,?,?,?,?,?,?)");
67
68 while (<FLAT>) {
69 next if /^#/;
70 next if /^\s*$/;
71 chomp;
72 recslurp($_);
73 }
74
75 # Try the deferred records again, once.
76 foreach (@deferred) {
77 # print "trying $_ again\n";
78 recslurp($_, 1);
79 }
80
81 # Sub for various nonstandard types with lots of pure bytes expressed in octal
82 # Takes a tinydns rdata string and count, returns a lis of $count bytes as well
83 # as trimming those logical bytes off the front of the rdata string.
84 sub _byteparse {
85 my $src = shift;
86 my $count = shift;
87 my @ret;
88 for (my $i = 0; $i < $count; $i++) {
89 if ($$src =~ /^\\/) {
90 # we should have an octal bit
91 my ($tmp) = ($$src =~ /^(\\\d{3})/);
92 $tmp =~ s/\\/0/;
93 push @ret, oct($tmp);
94 $$src =~ s/^\\\d{3}//;
95 } else {
96 # we seem to have a byte expressed as an ASCII character
97 my ($tmp) = ($$src =~ /^(.)/);
98 push @ret, ord($tmp);
99 $$src =~ s/^.//;
100 }
101 }
102 return @ret;
103 }
104
105 sub recslurp {
106 my $rec = shift;
107 my $nodefer = shift || 0;
108
109 if ($rec =~ /^=/) {
110 $cnt{APTR}++;
111if ($rec !~ /^=(?:\*|\\052)?[a-z0-9\._-]+:[\d\.]+:\d*/i) {
112 print "bad A+PTR $rec\n";
113 return;
114#=sud-rr-iGi0-1_sud-gw1-iGi4-2.vianet.ca::10.10.10.13:900::in
115}
116 my ($host,$ip,$ttl,$time,$loc) = split /:/, $rec;
117 $host =~ s/^=//;
118 $host =~ s/\.$//;
119 $time = '' if !$time;
120 $loc = '' if !$loc;
121 print "bleh, bad A+PTR! $rec\n" if $loc =~ /:/;
122 my $fparent = DNSDB::_hostparent($dbh, $host);
123 my ($rparent) = $dbh->selectrow_array("SELECT rdns_id FROM revzones WHERE revnet >> ?", undef, ($ip));
124 if ($fparent && $rparent) {
125 $dbh->do("INSERT INTO records (domain_id,rdns_id,host,type,val,ttl) VALUES (?,?,?,?,?,?)", undef,
126 ($fparent, $rparent, $host, 65280, $ip, $ttl));
127 } else {
128 push @deferred, $rec unless $nodefer;
129 # print "$tmporig deferred; can't find both forward and reverse zone parents\n";
130 }
131
132 } elsif ($rec =~ /^C/) {
133 $cnt{CNAME}++;
134 my ($host,$targ,$ttl,$time,$loc) = split /:/, $rec;
135 $host =~ s/^C//;
136 $host =~ s/\.$//;
137 $time = '' if !$time;
138 $loc = '' if !$loc;
139 my $fparent = DNSDB::_hostparent($dbh, $host);
140 if ($fparent) {
141
142 } else {
143 push @deferred, $rec unless $nodefer;
144 # print "$tmporig deferred; can't find parent zone\n";
145 }
146
147 } elsif ($rec =~ /^\&/) {
148 $cnt{NS}++;
149 } elsif ($rec =~ /^\^/) {
150 $cnt{PTR}++;
151 } elsif ($rec =~ /^\+/) {
152 $cnt{A}++;
153 } elsif ($rec =~ /^Z/) {
154 $cnt{SOA}++;
155#Z128.91.209.in-addr.arpa:ns1.vianet.ca.:dnsadmin.vianet.ca.::1209600:1209600:900:900:900:
156 my ($zone,$master,$contact,$serial,$refresh,$retry,$expire,$minttl,$ttl,$time,$loc) = split /:/, $rec;
157 $zone =~ s/^Z//;
158 $zone =~ s/\.$//;
159 $master =~ s/\.$//;
160 $contact =~ s/\.$//;
161 $time = '' if !$time;
162 $loc = '' if !$loc;
163 if ($zone =~ /\.arpa$/) {
164 ($code,$msg) = DNSDB::_zone2cidr($zone);
165 $dbh->do("INSERT INTO revzones (revnet,group_id,status) VALUES (?,1,1)", undef, ($msg));
166 my ($rdns) = $dbh->selectrow_array("SELECT currval('revzones_rdns_id_seq')");
167 $dbh->do("INSERT INTO records (rdns_id,host,type,val,ttl) VALUES (?,?,6,?,?)", undef,
168 ($rdns, "$contact:$master", "$refresh:$retry:$expire:$minttl", $ttl));
169 } else {
170 $dbh->do("INSERT INTO domains (domain,group_id,status) VALUES (?,1,1)", undef, ($zone));
171 my ($domid) = $dbh->selectrow_array("SELECT currval('domains_domain_id_seq')");
172 $dbh->do("INSERT INTO records (rdns_id,host,type,val,ttl) VALUES (?,?,6,?,?)", undef,
173 ($domid, "$contact:$master", "$refresh:$retry:$expire:$minttl", $ttl));
174 }
175
176 } elsif ($rec =~ /^\@/) {
177 $cnt{MX}++;
178 } elsif ($rec =~ /^'/) {
179 $cnt{TXT}++;
180
181sub _deoctal {
182 my $targ = shift;
183 while ($$targ =~ /\\(\d{3})/) {
184 my $sub = chr(oct($1));
185 $$targ =~ s/\\$1/$sub/g;
186 }
187}
188
189 my ($fqdn, $rdata, $ttl, $time, $loc) = split /:/, $rec;
190 $fqdn =~ s/^'//;
191 _deoctal(\$rdata);
192
193print "$fqdn TXT '$rdata'\n" if $fqdn =~ /^\*/;
194 my $domid = DNSDB::_hostparent($dbh, $fqdn);
195 if ($domid) {
196 $recsth->execute($domid, 0, $fqdn, 16, $rdata, 0, 0, 0, $ttl);
197 } else {
198 push @deferred, $rec unless $nodefer;
199 }
200
201 } elsif ($rec =~ /^\./) {
202 $cnt{NSASOA}++;
203 } elsif ($rec =~ /^:/) {
204 $cnt{NCUST}++;
205# Big section. Since tinydns can publish anything you can encode properly, but only provides official
206# recognition and handling for the core common types, this must deal with the leftovers.
207# :fqdn:type:rdata:ttl:time:loc
208#:mx2.sys.vianet.ca:44:\001\001\215\272\152\152\123\142\120\071\320\106\160\364\107\372\153\116\036\111\247\135:900::sys
209#:_sipfederationtls._tcp.ncstechnology.com:33:\000\144\000\001\023\305\006sipfed\006online\004lync\003com\000:3600::
210
211my (undef, $fqdn, $type, $rdata, $ttl, $time, $loc) = split /:/, $rec;
212
213if ($type == 33) {
214 # SRV
215 my ($prio, $weight, $port, $target) = (0,0,0,0);
216
217 my @tmp = _byteparse(\$rdata, 2);
218 $prio = $tmp[0] * 256 + $tmp[1];
219 @tmp = _byteparse(\$rdata, 2);
220 $weight = $tmp[0] * 256 + $tmp[1];
221 @tmp = _byteparse(\$rdata, 2);
222 $port = $tmp[0] * 256 + $tmp[1];
223
224 $rdata =~ s/\\\d{3}/./g;
225 ($target) = ($rdata =~ /^\.(.+)\.$/);
226# hmm. the above *should* work, but What If(TM) we have ASCII-range bytes
227# representing the target's fqdn part length(s)? axfr-get doesn't seem to,
228# probably because dec. 33->63 includes most punctuation and all the numbers
229# while ($rdata =~ /(\\\d{3})/) {
230# my $cnt = $1;
231# $rdata =~ s/^$cnt//;
232# $cnt =~ s/^\\/0/;
233# $cnt = oct($cnt);
234# my ($seg) = ($rdata =~ /^(.{$cnt})/);
235# $target .=
236# }
237
238 my $domid = DNSDB::_hostparent($dbh, $fqdn);
239 if ($domid) {
240 $recsth->execute($domid, 0, $fqdn, $type, $target, $prio, $weight, $port, $ttl) if $domid;
241 } else {
242 push @deferred, $rec unless $nodefer;
243 }
244
245} elsif ($type == 28) {
246 # AAAA
247
248 my @v6;
249
250 for (my $i=0; $i < 8; $i++) {
251 my @tmp = _byteparse(\$rdata, 2);
252 push @v6, sprintf("%0.4x", $tmp[0] * 256 + $tmp[1]);
253 }
254 my $val = NetAddr::IP->new(join(':', @v6));
255
256 my $domid = DNSDB::_hostparent($dbh, $fqdn);
257 if ($domid) {
258 $recsth->execute($domid, 0, $fqdn, $type, $val->addr, 0, 0, 0, $ttl) if $domid;
259 } else {
260 push @deferred, $rec unless $nodefer;
261 }
262
263} else {
264 # ... uhhh, dunno
265}
266
267 } else {
268 $cnt{other}++;
269 print " $_\n";
270 }
271 }
272
273 close FLAT;
274}
Note: See TracBrowser for help on using the repository browser.