djbdnscurve6  38
djbdnscurve6
axfr-get.c
Go to the documentation of this file.
1 #include <unistd.h>
2 #include "uint_t.h"
3 #include "stralloc.h"
4 #include "logmsg.h"
5 #include "getln.h"
6 #include "buffer.h"
7 #include "exit.h"
8 #include "open.h"
9 #include "scan.h"
10 #include "byte.h"
11 #include "str.h"
12 #include "ip.h"
13 #include "timeout.h"
14 #include "dns.h"
15 
16 #define WHO "axfr-get"
17 
18 int rename(const char *,const char *); // keep compiler silent
19 
20 void die_usage(void)
21 {
22  logmsg(WHO,100,USAGE,"axfr-get zone fn fn.tmp");
23 }
24 void die_generate(void)
25 {
26  logmsg(WHO,111,FATAL,"unable to generate AXFR query");
27 }
28 void die_parse(void)
29 {
30  logmsg(WHO,111,FATAL,"unable to parse AXFR results");
31 }
32 unsigned int x_copy(char *buf,unsigned int len,unsigned int pos,char *out,unsigned int outlen)
33 {
34  pos = dns_packet_copy(buf,len,pos,out,outlen);
35  if (!pos) die_parse();
36  return pos;
37 }
38 unsigned int x_getname(char *buf,unsigned int len,unsigned int pos,char **out)
39 {
40  pos = dns_packet_getname(buf,len,pos,out);
41  if (!pos) die_parse();
42  return pos;
43 }
44 unsigned int x_skipname(char *buf,unsigned int len,unsigned int pos)
45 {
46  pos = dns_packet_skipname(buf,len,pos);
47  if (!pos) die_parse();
48  return pos;
49 }
50 
51 static char *zone;
52 unsigned int zonelen;
53 char *fn;
54 char *fntmp;
55 
56 void die_netread(void)
57 {
58  logmsg(WHO,111,FATAL,"unable to read from network");
59 }
60 void die_netwrite(void)
61 {
62  logmsg(WHO,111,FATAL,"unable to write to network");
63 }
64 void die_read(void)
65 {
66  logmsg(WHO,111,FATAL,B("unable to read: ",fn));
67 }
68 void die_write(void)
69 {
70  logmsg(WHO,111,FATAL,B("unable to write: ",fntmp));
71 }
72 
73 int saferead(int fd,char *buf,unsigned int len)
74 {
75  int r;
76  r = timeoutread(60,fd,buf,len);
77  if (r == 0) { errno = EPROTO; die_parse(); }
78  if (r <= 0) die_netread();
79  return r;
80 }
81 int safewrite(int fd,char *buf,unsigned int len)
82 {
83  int r;
84  r = timeoutwrite(60,fd,buf,len);
85  if (r <= 0) die_netwrite();
86  return r;
87 }
88 char netreadspace[1024];
89 buffer netread = BUFFER_INIT(saferead,6,netreadspace,sizeof(netreadspace));
90 char netwritespace[1024];
91 buffer netwrite = BUFFER_INIT(safewrite,7,netwritespace,sizeof(netwritespace));
92 
93 void netget(char *buf,unsigned int len)
94 {
95  int r;
96 
97  while (len > 0) {
98  r = buffer_get(&netread,buf,len);
99  buf += r; len -= r;
100  }
101 }
102 
103 int fd;
104 buffer b;
105 char bspace[1024];
106 
107 void put(char *buf,unsigned int len)
108 {
109  if (buffer_put(&b,buf,len) == -1) die_write();
110 }
111 
112 int printable(char ch)
113 {
114  if (ch == '.') return 1;
115  if ((ch >= 'a') && (ch <= 'z')) return 1;
116  if ((ch >= '0') && (ch <= '9')) return 1;
117  if ((ch >= 'A') && (ch <= 'Z')) return 1;
118  if (ch == '-') return 1;
119  return 0;
120 }
121 
122 static char *d1;
123 static char *d2;
124 static char *d3;
125 
126 stralloc line;
127 int match;
128 
129 int numsoa;
130 
131 unsigned int doit(char *buf,unsigned int len,unsigned int pos)
132 {
133  char data[20];
134  uint32 ttl;
135  uint16 dlen;
136  uint16 typenum;
137  uint32 u32;
138  int i;
139 
140  pos = x_getname(buf,len,pos,&d1);
141  pos = x_copy(buf,len,pos,data,10);
142  uint16_unpack_big(data,&typenum);
143  uint32_unpack_big(data + 4,&ttl);
144  uint16_unpack_big(data + 8,&dlen);
145  if (len - pos < dlen) { errno = EPROTO; return 0; }
146  len = pos + dlen;
147 
148  if (!dns_domain_suffix(d1,zone)) return len;
149  if (byte_diff(data + 2,2,DNS_C_IN)) return len;
150 
151  if (byte_equal(data,2,DNS_T_SOA)) {
152  if (++numsoa >= 2) return len;
153  pos = x_getname(buf,len,pos,&d2);
154  pos = x_getname(buf,len,pos,&d3);
155  x_copy(buf,len,pos,data,20);
156  uint32_unpack_big(data,&u32);
157  if (!stralloc_copys(&line,"#")) return 0;
158  if (!stralloc_catulong0(&line,u32,0)) return 0;
159  if (!stralloc_cats(&line," auto axfr-get\n")) return 0;
160  if (!stralloc_cats(&line,"Z")) return 0;
161  if (dns_domain_todot_cat(&line,d1) <= 0) return 0;
162  if (!stralloc_cats(&line,"|")) return 0;
163  if (dns_domain_todot_cat(&line,d2) <= 0) return 0;
164  if (!stralloc_cats(&line,".|")) return 0;
165  if (dns_domain_todot_cat(&line,d3) <= 0) return 0;
166  if (!stralloc_cats(&line,".")) return 0;
167  for (i = 0; i < 5; ++i) {
168  uint32_unpack_big(data + 4 * i,&u32);
169  if (!stralloc_cats(&line,"|")) return 0;
170  if (!stralloc_catulong0(&line,u32,0)) return 0;
171  }
172  }
173  else if (byte_equal(data,2,DNS_T_NS)) {
174  if (!stralloc_copys(&line,"&")) return 0;
175  if (byte_equal(d1,2,"\1*")) { errno = EPROTO; return 0; }
176  if (dns_domain_todot_cat(&line,d1) <= 0) return 0;
177  if (!stralloc_cats(&line,"||")) return 0;
178  x_getname(buf,len,pos,&d1);
179  if (dns_domain_todot_cat(&line,d1) <= 0) return 0;
180  if (!stralloc_cats(&line,".")) return 0;
181  }
182  else if (byte_equal(data,2,DNS_T_CNAME)) {
183  if (!stralloc_copys(&line,"C")) return 0;
184  if (dns_domain_todot_cat(&line,d1) <= 0) return 0;
185  if (!stralloc_cats(&line,"|")) return 0;
186  x_getname(buf,len,pos,&d1);
187  if (dns_domain_todot_cat(&line,d1) <= 0) return 0;
188  if (!stralloc_cats(&line,".")) return 0;
189  }
190  else if (byte_equal(data,2,DNS_T_PTR)) {
191  if (!stralloc_copys(&line,"^")) return 0;
192  if (dns_domain_todot_cat(&line,d1) <= 0) return 0;
193  if (!stralloc_cats(&line,"|")) return 0;
194  x_getname(buf,len,pos,&d1);
195  if (dns_domain_todot_cat(&line,d1) <= 0) return 0;
196  if (!stralloc_cats(&line,".")) return 0;
197  }
198  else if (byte_equal(data,2,DNS_T_MX)) {
199  uint16 dist;
200  if (!stralloc_copys(&line,"@")) return 0;
201  if (dns_domain_todot_cat(&line,d1) <= 0) return 0;
202  if (!stralloc_cats(&line,"||")) return 0;
203  pos = x_copy(buf,len,pos,data,2);
204  uint16_unpack_big(data,&dist);
205  x_getname(buf,len,pos,&d1);
206  if (dns_domain_todot_cat(&line,d1) <= 0) return 0;
207  if (!stralloc_cats(&line,".|")) return 0;
208  if (!stralloc_catulong0(&line,dist,0)) return 0;
209  }
210  else if (byte_equal(data,2,DNS_T_A) && (dlen == 4)) {
211  char ipstr[IP4_FMT];
212  if (!stralloc_copys(&line,"+")) return 0;
213  if (dns_domain_todot_cat(&line,d1) <= 0) return 0;
214  if (!stralloc_cats(&line,"|")) return 0;
215  x_copy(buf,len,pos,data,4);
216  if (!stralloc_catb(&line,ipstr,ip4_fmt(ipstr,data))) return 0;
217  }
218  else if (byte_equal(data,2,DNS_T_AAAA)) {
219  char ipstr[IP6_FMT];
220  if (!stralloc_copys(&line,":")) return 0;
221  if (dns_domain_todot_cat(&line,d1) <= 0) return 0;
222  if (!stralloc_cats(&line,"|")) return 0;
223  x_copy(buf,len,pos,data,16);
224  if (!stralloc_catb(&line,ipstr,ip6_fmt(ipstr,data))) return 0;
225  }
226  else {
227  unsigned char ch;
228  unsigned char ch2;
229  if (!stralloc_copys(&line,"|")) return 0;
230  if (dns_domain_todot_cat(&line,d1) <= 0) return 0;
231  if (!stralloc_cats(&line,"|")) return 0;
232  if (!stralloc_catulong0(&line,typenum,0)) return 0;
233  if (!stralloc_cats(&line,"|")) return 0;
234  for (i = 0; i < dlen; ++i) {
235  pos = x_copy(buf,len,pos,data,1);
236  ch = data[0];
237  if (printable(ch)) {
238  if (!stralloc_catb(&line,&ch,1)) return 0;
239  }
240  else {
241  if (!stralloc_cats(&line,"\\")) return 0;
242  ch2 = '0' + ((ch >> 6) & 7);
243  if (!stralloc_catb(&line,&ch2,1)) return 0;
244  ch2 = '0' + ((ch >> 3) & 7);
245  if (!stralloc_catb(&line,&ch2,1)) return 0;
246  ch2 = '0' + (ch & 7);
247  if (!stralloc_catb(&line,&ch2,1)) return 0;
248  }
249  }
250  }
251  if (!stralloc_cats(&line,"|")) return 0;
252  if (!stralloc_catulong0(&line,ttl,0)) return 0;
253  if (!stralloc_cats(&line,"\n")) return 0;
254  put(line.s,line.len);
255 
256  return len;
257 }
258 
259 stralloc packet;
260 
261 int main(int argc,char **argv)
262 {
263  char out[20];
264  unsigned long u;
265  uint16 dlen;
266  unsigned int pos;
267  uint32 oldserial = 0;
268  uint32 newserial = 0;
269  uint16 numqueries;
270  uint16 numanswers;
271 
272  if (!*argv) die_usage();
273 
274  if (!*++argv) die_usage();
275  if (dns_domain_fromdot(&zone,*argv,str_len(*argv)) <= 0) die_generate();
276  zonelen = dns_domain_length(zone);
277 
278  if (!*++argv) die_usage();
279  fn = *argv;
280  if (!*++argv) die_usage();
281  fntmp = *argv;
282 
283  fd = open_read(fn);
284  if (fd == -1) {
285  if (errno != ENOENT) die_read();
286  }
287  else {
288  buffer_init(&b,buffer_unixread,fd,bspace,sizeof(bspace));
289  if (getln(&b,&line,&match,'\n') == -1) die_read();
290  if (!stralloc_0(&line)) die_read();
291  if (line.s[0] == '#') {
292  scan_ulong(line.s + 1,&u);
293  oldserial = u;
294  }
295  close(fd);
296  }
297 
298  if (!stralloc_copyb(&packet,"\0\0\0\0\0\1\0\0\0\0\0\0",12)) die_generate();
299  if (!stralloc_catb(&packet,zone,zonelen)) die_generate();
300  if (!stralloc_catb(&packet,DNS_T_SOA DNS_C_IN,4)) die_generate();
301  uint16_pack_big(out,packet.len);
302  buffer_put(&netwrite,out,2);
303  buffer_put(&netwrite,packet.s,packet.len);
304  buffer_flush(&netwrite);
305 
306  netget(out,2);
307  uint16_unpack_big(out,&dlen);
308  if (!stralloc_ready(&packet,dlen)) die_parse();
309  netget(packet.s,dlen);
310  packet.len = dlen;
311 
312  pos = x_copy(packet.s,packet.len,0,out,12);
313  uint16_unpack_big(out + 4,&numqueries);
314  uint16_unpack_big(out + 6,&numanswers);
315 
316  while (numqueries) {
317  --numqueries;
318  pos = x_skipname(packet.s,packet.len,pos);
319  pos += 4;
320  }
321 
322  if (!numanswers) { errno = EPROTO; die_parse(); }
323  pos = x_getname(packet.s,packet.len,pos,&d1);
324  if (!dns_domain_equal(zone,d1)) { errno = EPROTO; die_parse(); }
325  pos = x_copy(packet.s,packet.len,pos,out,10);
326  if (byte_diff(out,4,DNS_T_SOA DNS_C_IN)) { errno = EPROTO; die_parse(); }
327  pos = x_skipname(packet.s,packet.len,pos);
328  pos = x_skipname(packet.s,packet.len,pos);
329  pos = x_copy(packet.s,packet.len,pos,out,4);
330 
331  uint32_unpack_big(out,&newserial);
332 
333 
334  if (oldserial && newserial) /* allow 0 for very recently modified zones */
335  if (oldserial == newserial) /* allow serial numbers to move backwards */
336  _exit(0);
337 
338 
339  fd = open_trunc(fntmp);
340  if (fd == -1) die_write();
341  buffer_init(&b,buffer_unixwrite,fd,bspace,sizeof(bspace));
342 
343  if (!stralloc_copyb(&packet,"\0\0\0\0\0\1\0\0\0\0\0\0",12)) die_generate();
344  if (!stralloc_catb(&packet,zone,zonelen)) die_generate();
345  if (!stralloc_catb(&packet,DNS_T_AXFR DNS_C_IN,4)) die_generate();
346  uint16_pack_big(out,packet.len);
347  buffer_put(&netwrite,out,2);
348  buffer_put(&netwrite,packet.s,packet.len);
349  buffer_flush(&netwrite);
350 
351  numsoa = 0;
352  while (numsoa < 2) {
353  netget(out,2);
354  uint16_unpack_big(out,&dlen);
355  if (!stralloc_ready(&packet,dlen)) die_parse();
356  netget(packet.s,dlen);
357  packet.len = dlen;
358 
359  pos = x_copy(packet.s,packet.len,0,out,12);
360  uint16_unpack_big(out + 4,&numqueries);
361 
362  while (numqueries) {
363  --numqueries;
364  pos = x_skipname(packet.s,packet.len,pos);
365  pos += 4;
366  }
367  while (pos < packet.len) {
368  pos = doit(packet.s,packet.len,pos);
369  if (!pos) die_parse();
370  }
371  }
372 
373  if (buffer_flush(&b) == -1) die_write();
374  if (fsync(fd) == -1) die_write();
375  if (close(fd) == -1) die_write(); /* NFS dorks */
376  if (rename(fntmp,fn) == -1)
377  logmsg(WHO,111,FATAL,B("unable to move ",fntmp," to: ",fn));
378  _exit(0);
379 }
void die_write(void)
Definition: axfr-get.c:68
char * fntmp
Definition: axfr-get.c:54
char bspace[1024]
Definition: axfr-get.c:105
void die_usage(void)
Definition: axfr-get.c:20
int printable(char ch)
Definition: axfr-get.c:112
void put(char *buf, unsigned int len)
Definition: axfr-get.c:107
int main(int argc, char **argv)
Definition: axfr-get.c:261
unsigned int x_getname(char *buf, unsigned int len, unsigned int pos, char **out)
Definition: axfr-get.c:38
int rename(const char *, const char *)
char netwritespace[1024]
Definition: axfr-get.c:90
void die_netwrite(void)
Definition: axfr-get.c:60
unsigned int x_skipname(char *buf, unsigned int len, unsigned int pos)
Definition: axfr-get.c:44
void die_netread(void)
Definition: axfr-get.c:56
buffer b
Definition: axfr-get.c:104
unsigned int x_copy(char *buf, unsigned int len, unsigned int pos, char *out, unsigned int outlen)
Definition: axfr-get.c:32
void die_read(void)
Definition: axfr-get.c:64
stralloc packet
Definition: axfr-get.c:259
int fd
Definition: axfr-get.c:103
int safewrite(int fd, char *buf, unsigned int len)
Definition: axfr-get.c:81
void die_parse(void)
Definition: axfr-get.c:28
unsigned int zonelen
Definition: axfr-get.c:52
int saferead(int fd, char *buf, unsigned int len)
Definition: axfr-get.c:73
void netget(char *buf, unsigned int len)
Definition: axfr-get.c:93
stralloc line
Definition: axfr-get.c:126
void die_generate(void)
Definition: axfr-get.c:24
char * fn
Definition: axfr-get.c:53
unsigned int doit(char *buf, unsigned int len, unsigned int pos)
Definition: axfr-get.c:131
buffer netread
Definition: axfr-get.c:89
int match
Definition: axfr-get.c:127
char netreadspace[1024]
Definition: axfr-get.c:88
buffer netwrite
Definition: axfr-get.c:91
#define WHO
Definition: axfr-get.c:16
int numsoa
Definition: axfr-get.c:129
char data[32767]
Definition: axfrdns.c:131
uint16 len
Definition: axfrdns.c:302
char buf[MSGSIZE]
Definition: axfrdns.c:301
uint32 dlen
Definition: axfrdns.c:132
unsigned int dns_packet_copy(const char *, unsigned int, unsigned int, char *, unsigned int)
Definition: dns_packet.c:8
#define DNS_T_A
Definition: dns.h:37
int dns_domain_equal(const char *, const char *)
Definition: dns_domain.c:39
#define DNS_T_AXFR
Definition: dns.h:65
int dns_domain_fromdot(char **, const char *, unsigned int)
Definition: dns_dfd.c:6
int dns_domain_todot_cat(stralloc *, const char *)
Definition: dns_dtda.c:11
#define DNS_C_IN
Definition: dns.h:34
int dns_domain_suffix(const char *, const char *)
Definition: dns_domain.c:50
unsigned int dns_packet_skipname(const char *, unsigned int, unsigned int)
Definition: dns_packet.c:18
unsigned int dns_domain_length(const char *)
Definition: dns_domain.c:6
#define DNS_T_PTR
Definition: dns.h:41
#define DNS_T_SOA
Definition: dns.h:40
#define DNS_T_NS
Definition: dns.h:38
#define DNS_T_CNAME
Definition: dns.h:39
#define DNS_T_AAAA
Definition: dns.h:48
unsigned int dns_packet_getname(const char *, unsigned int, unsigned int, char **)
Definition: dns_packet.c:35
#define DNS_T_MX
Definition: dns.h:43
uint64 numqueries
Definition: dnscache.c:70
char ipstr[IP6_FMT]
Definition: dnstrace.c:31
void out(const char *s, unsigned int len)
Definition: generic-conf.c:54
unsigned long u
Definition: utime.c:10
Definition: dnsfilter.c:23