16 #include "timeoutread.h"
17 #include "timeoutwrite.h"
20 #define FATAL "axfr-get: fatal: "
24 strerr_die1x(100,"axfr-get: usage: axfr-get zone fn fn.tmp");
26 void die_generate(void)
28 strerr_die2sys(111,FATAL
,"unable to generate AXFR query: ");
32 strerr_die2sys(111,FATAL
,"unable to parse AXFR results: ");
34 unsigned int x_copy(char *buf
,unsigned int len
,unsigned int pos
,char *out
,unsigned int outlen
)
36 pos
= dns_packet_copy(buf
,len
,pos
,out
,outlen
);
37 if (!pos
) die_parse();
40 unsigned int x_getname(char *buf
,unsigned int len
,unsigned int pos
,char **out
)
42 pos
= dns_packet_getname(buf
,len
,pos
,out
);
43 if (!pos
) die_parse();
46 unsigned int x_skipname(char *buf
,unsigned int len
,unsigned int pos
)
48 pos
= dns_packet_skipname(buf
,len
,pos
);
49 if (!pos
) die_parse();
58 void die_netread(void)
60 strerr_die2sys(111,FATAL
,"unable to read from network: ");
62 void die_netwrite(void)
64 strerr_die2sys(111,FATAL
,"unable to write to network: ");
68 strerr_die4sys(111,FATAL
,"unable to read ",fn
,": ");
72 strerr_die4sys(111,FATAL
,"unable to write ",fntmp
,": ");
75 int saferead(int fd
,char *buf
,unsigned int len
)
78 r
= timeoutread(60,fd
,buf
,len
);
79 if (r
== 0) { errno
= error_proto
; die_parse(); }
80 if (r
<= 0) die_netread();
83 int safewrite(int fd
,char *buf
,unsigned int len
)
86 r
= timeoutwrite(60,fd
,buf
,len
);
87 if (r
<= 0) die_netwrite();
90 char netreadspace
[1024];
91 buffer netread
= BUFFER_INIT(saferead
,6,netreadspace
,sizeof netreadspace
);
92 char netwritespace
[1024];
93 buffer netwrite
= BUFFER_INIT(safewrite
,7,netwritespace
,sizeof netwritespace
);
95 void netget(char *buf
,unsigned int len
)
100 r
= buffer_get(&netread
,buf
,len
);
109 void put(char *buf
,unsigned int len
)
111 if (buffer_put(&b
,buf
,len
) == -1) die_write();
114 int printable(char ch
)
116 if (ch
== '.') return 1;
117 if ((ch
>= 'a') && (ch
<= 'z')) return 1;
118 if ((ch
>= '0') && (ch
<= '9')) return 1;
119 if ((ch
>= 'A') && (ch
<= 'Z')) return 1;
120 if (ch
== '-') return 1;
133 unsigned int doit(char *buf
,unsigned int len
,unsigned int pos
)
142 pos
= x_getname(buf
,len
,pos
,&d1
);
143 pos
= x_copy(buf
,len
,pos
,data
,10);
144 uint16_unpack_big(data
,&typenum
);
145 uint32_unpack_big(data
+ 4,&ttl
);
146 uint16_unpack_big(data
+ 8,&dlen
);
147 if (len
- pos
< dlen
) { errno
= error_proto
; return 0; }
150 if (!dns_domain_suffix(d1
,zone
)) return len
;
151 if (byte_diff(data
+ 2,2,DNS_C_IN
)) return len
;
153 if (byte_equal(data
,2,DNS_T_SOA
)) {
154 if (++numsoa
>= 2) return len
;
155 pos
= x_getname(buf
,len
,pos
,&d2
);
156 pos
= x_getname(buf
,len
,pos
,&d3
);
157 x_copy(buf
,len
,pos
,data
,20);
158 uint32_unpack_big(data
,&u32
);
159 if (!stralloc_copys(&line
,"#")) return 0;
160 if (!stralloc_catulong0(&line
,u32
,0)) return 0;
161 if (!stralloc_cats(&line
," auto axfr-get\n")) return 0;
162 if (!stralloc_cats(&line
,"Z")) return 0;
163 if (!dns_domain_todot_cat(&line
,d1
)) return 0;
164 if (!stralloc_cats(&line
,":")) return 0;
165 if (!dns_domain_todot_cat(&line
,d2
)) return 0;
166 if (!stralloc_cats(&line
,".:")) return 0;
167 if (!dns_domain_todot_cat(&line
,d3
)) return 0;
168 if (!stralloc_cats(&line
,".")) return 0;
169 for (i
= 0;i
< 5;++i
) {
170 uint32_unpack_big(data
+ 4 * i
,&u32
);
171 if (!stralloc_cats(&line
,":")) return 0;
172 if (!stralloc_catulong0(&line
,u32
,0)) return 0;
175 else if (byte_equal(data
,2,DNS_T_NS
)) {
176 if (!stralloc_copys(&line
,"&")) return 0;
177 if (byte_equal(d1
,2,"\1*")) { errno
= error_proto
; return 0; }
178 if (!dns_domain_todot_cat(&line
,d1
)) return 0;
179 if (!stralloc_cats(&line
,"::")) return 0;
180 x_getname(buf
,len
,pos
,&d1
);
181 if (!dns_domain_todot_cat(&line
,d1
)) return 0;
182 if (!stralloc_cats(&line
,".")) return 0;
184 else if (byte_equal(data
,2,DNS_T_CNAME
)) {
185 if (!stralloc_copys(&line
,"C")) return 0;
186 if (!dns_domain_todot_cat(&line
,d1
)) return 0;
187 if (!stralloc_cats(&line
,":")) return 0;
188 x_getname(buf
,len
,pos
,&d1
);
189 if (!dns_domain_todot_cat(&line
,d1
)) return 0;
190 if (!stralloc_cats(&line
,".")) return 0;
192 else if (byte_equal(data
,2,DNS_T_PTR
)) {
193 if (!stralloc_copys(&line
,"^")) return 0;
194 if (!dns_domain_todot_cat(&line
,d1
)) return 0;
195 if (!stralloc_cats(&line
,":")) return 0;
196 x_getname(buf
,len
,pos
,&d1
);
197 if (!dns_domain_todot_cat(&line
,d1
)) return 0;
198 if (!stralloc_cats(&line
,".")) return 0;
200 else if (byte_equal(data
,2,DNS_T_MX
)) {
202 if (!stralloc_copys(&line
,"@")) return 0;
203 if (!dns_domain_todot_cat(&line
,d1
)) return 0;
204 if (!stralloc_cats(&line
,"::")) return 0;
205 pos
= x_copy(buf
,len
,pos
,data
,2);
206 uint16_unpack_big(data
,&dist
);
207 x_getname(buf
,len
,pos
,&d1
);
208 if (!dns_domain_todot_cat(&line
,d1
)) return 0;
209 if (!stralloc_cats(&line
,".:")) return 0;
210 if (!stralloc_catulong0(&line
,dist
,0)) return 0;
212 else if (byte_equal(data
,2,DNS_T_A
) && (dlen
== 4)) {
214 if (!stralloc_copys(&line
,"+")) return 0;
215 if (!dns_domain_todot_cat(&line
,d1
)) return 0;
216 if (!stralloc_cats(&line
,":")) return 0;
217 x_copy(buf
,len
,pos
,data
,4);
218 if (!stralloc_catb(&line
,ipstr
,ip4_fmt(ipstr
,data
))) return 0;
223 if (!stralloc_copys(&line
,":")) return 0;
224 if (!dns_domain_todot_cat(&line
,d1
)) return 0;
225 if (!stralloc_cats(&line
,":")) return 0;
226 if (!stralloc_catulong0(&line
,typenum
,0)) return 0;
227 if (!stralloc_cats(&line
,":")) return 0;
228 for (i
= 0;i
< dlen
;++i
) {
229 pos
= x_copy(buf
,len
,pos
,data
,1);
232 if (!stralloc_catb(&line
,&ch
,1)) return 0;
235 if (!stralloc_cats(&line
,"\\")) return 0;
236 ch2
= '0' + ((ch
>> 6) & 7);
237 if (!stralloc_catb(&line
,&ch2
,1)) return 0;
238 ch2
= '0' + ((ch
>> 3) & 7);
239 if (!stralloc_catb(&line
,&ch2
,1)) return 0;
240 ch2
= '0' + (ch
& 7);
241 if (!stralloc_catb(&line
,&ch2
,1)) return 0;
245 if (!stralloc_cats(&line
,":")) return 0;
246 if (!stralloc_catulong0(&line
,ttl
,0)) return 0;
247 if (!stralloc_cats(&line
,"\n")) return 0;
248 put(line
.s
,line
.len
);
255 int main(int argc
,char **argv
)
261 uint32 oldserial
= 0;
262 uint32 newserial
= 0;
266 if (!*argv
) die_usage();
268 if (!*++argv
) die_usage();
269 if (!dns_domain_fromdot(&zone
,*argv
,str_len(*argv
))) die_generate();
270 zonelen
= dns_domain_length(zone
);
272 if (!*++argv
) die_usage();
274 if (!*++argv
) die_usage();
279 if (errno
!= error_noent
) die_read();
282 buffer_init(&b
,buffer_unixread
,fd
,bspace
,sizeof bspace
);
283 if (getln(&b
,&line
,&match
,'\n') == -1) die_read();
284 if (!stralloc_0(&line
)) die_read();
285 if (line
.s
[0] == '#') {
286 scan_ulong(line
.s
+ 1,&u
);
292 if (!stralloc_copyb(&packet
,"\0\0\0\0\0\1\0\0\0\0\0\0",12)) die_generate();
293 if (!stralloc_catb(&packet
,zone
,zonelen
)) die_generate();
294 if (!stralloc_catb(&packet
,DNS_T_SOA DNS_C_IN
,4)) die_generate();
295 uint16_pack_big(out
,packet
.len
);
296 buffer_put(&netwrite
,out
,2);
297 buffer_put(&netwrite
,packet
.s
,packet
.len
);
298 buffer_flush(&netwrite
);
301 uint16_unpack_big(out
,&dlen
);
302 if (!stralloc_ready(&packet
,dlen
)) die_parse();
303 netget(packet
.s
,dlen
);
306 pos
= x_copy(packet
.s
,packet
.len
,0,out
,12);
307 uint16_unpack_big(out
+ 4,&numqueries
);
308 uint16_unpack_big(out
+ 6,&numanswers
);
312 pos
= x_skipname(packet
.s
,packet
.len
,pos
);
316 if (!numanswers
) { errno
= error_proto
; die_parse(); }
317 pos
= x_getname(packet
.s
,packet
.len
,pos
,&d1
);
318 if (!dns_domain_equal(zone
,d1
)) { errno
= error_proto
; die_parse(); }
319 pos
= x_copy(packet
.s
,packet
.len
,pos
,out
,10);
320 if (byte_diff(out
,4,DNS_T_SOA DNS_C_IN
)) { errno
= error_proto
; die_parse(); }
321 pos
= x_skipname(packet
.s
,packet
.len
,pos
);
322 pos
= x_skipname(packet
.s
,packet
.len
,pos
);
323 pos
= x_copy(packet
.s
,packet
.len
,pos
,out
,4);
325 uint32_unpack_big(out
,&newserial
);
328 if (oldserial
&& newserial
) /* allow 0 for very recently modified zones */
329 if (oldserial
== newserial
) /* allow serial numbers to move backwards */
333 fd
= open_trunc(fntmp
);
334 if (fd
== -1) die_write();
335 buffer_init(&b
,buffer_unixwrite
,fd
,bspace
,sizeof bspace
);
337 if (!stralloc_copyb(&packet
,"\0\0\0\0\0\1\0\0\0\0\0\0",12)) die_generate();
338 if (!stralloc_catb(&packet
,zone
,zonelen
)) die_generate();
339 if (!stralloc_catb(&packet
,DNS_T_AXFR DNS_C_IN
,4)) die_generate();
340 uint16_pack_big(out
,packet
.len
);
341 buffer_put(&netwrite
,out
,2);
342 buffer_put(&netwrite
,packet
.s
,packet
.len
);
343 buffer_flush(&netwrite
);
348 uint16_unpack_big(out
,&dlen
);
349 if (!stralloc_ready(&packet
,dlen
)) die_parse();
350 netget(packet
.s
,dlen
);
353 pos
= x_copy(packet
.s
,packet
.len
,0,out
,12);
354 uint16_unpack_big(out
+ 4,&numqueries
);
358 pos
= x_skipname(packet
.s
,packet
.len
,pos
);
361 while (pos
< packet
.len
) {
362 pos
= doit(packet
.s
,packet
.len
,pos
);
363 if (!pos
) die_parse();
367 if (buffer_flush(&b
) == -1) die_write();
368 if (fsync(fd
) == -1) die_write();
369 if (close(fd
) == -1) die_write(); /* NFS dorks */
370 if (rename(fntmp
,fn
) == -1)
371 strerr_die6sys(111,FATAL
,"unable to move ",fntmp
," to ",fn
,": ");