djbdnscurve6  38
djbdnscurve6
axfrdns.c
Go to the documentation of this file.
1 #include <unistd.h>
2 #include "droproot.h"
3 #include "exit.h"
4 #include "env.h"
5 #include "uint_t.h"
6 #include "ip.h"
7 #include "tai.h"
8 #include "buffer.h"
9 #include "timeout.h"
10 #include "open.h"
11 #include "seek.h"
12 #include "cdbread.h"
13 #include "stralloc.h"
14 #include "logmsg.h"
15 #include "str.h"
16 #include "byte.h"
17 #include "case.h"
18 #include "dns.h"
19 #include "scan.h"
20 #include "qlog.h"
21 #include "response.h"
22 #include "clientloc.h"
23 #include "edns0.h"
24 
25 extern int respond(char *,char *,char *);
26 
27 #define WHO "axfrdns"
28 
29 void nomem()
30 {
31  logmsg(WHO,111,FATAL,"out of memory");
32 }
34 {
35  logmsg(WHO,111,FATAL,"truncated request");
36 }
38 {
39  logmsg(WHO,111,FATAL,"unable to write to network");
40 }
42 {
43  logmsg(WHO,111,FATAL,"unable to read from network");
44 }
46 {
47  logmsg(WHO,111,FATAL,"unable to locate information in data.cdb");
48 }
50 {
51  logmsg(WHO,111,FATAL,"unable to read data.cdb");
52 }
54 {
55  logmsg(WHO,111,FATAL,B("unable to read data.cdb: ","format error"));
56 }
57 
58 int safewrite(int fd,char *buf,unsigned int len)
59 {
60  int w;
61 
62  w = timeoutwrite(60,fd,buf,len);
63  if (w <= 0) die_netwrite();
64  return w;
65 }
66 
67 char netwritespace[1024];
68 buffer netwrite = BUFFER_INIT(safewrite,1,netwritespace,sizeof(netwritespace));
69 
70 void print(char *buf,unsigned int len)
71 {
72  char tcpheader[2];
73  uint16_pack_big(tcpheader,len);
74  buffer_put(&netwrite,tcpheader,2);
75  buffer_put(&netwrite,buf,len);
76  buffer_flush(&netwrite);
77 }
78 
79 char *axfr;
80 static char *axfrok;
81 
82 void axfrcheck(char *q)
83 {
84  int i;
85  int j;
86 
87  if (!axfr) return;
88 
89  i = j = 0;
90  for (;;) {
91  if (!axfr[i] || (axfr[i] == '/')) {
92  if (i > j) {
93  if (dns_domain_fromdot(&axfrok,axfr + j,i - j) <= 0) nomem();
94  if (dns_domain_equal(q,axfrok)) return;
95  }
96  j = i + 1;
97  }
98  if (!axfr[i]) break;
99  ++i;
100  }
101 
102  logmsg(WHO,111,FATAL,"disallowed zone transfer request");
103 }
104 
105 static char *zone;
106 unsigned int zonelen;
107 char typeclass[4];
108 
109 int fdcdb;
110 buffer bcdb;
111 char bcdbspace[1024];
112 
113 void get(char *buf,unsigned int len)
114 {
115  int r;
116 
117  while (len > 0) {
118  r = buffer_get(&bcdb,buf,len);
119  if (r < 0) die_cdbread();
120  if (!r) die_cdbformat();
121  buf += r;
122  len -= r;
123  }
124 }
125 
126 char ip[16];
127 unsigned long port;
128 char clientloc[2];
129 
130 struct tai now;
131 char data[32767];
132 uint32 dlen;
133 uint32 dpos;
134 
135 void copy(char *buf,unsigned int len)
136 {
138  if (!dpos) die_cdbread();
139 }
140 
141 void doname(stralloc *sa)
142 {
143  static char *d;
145  if (!dpos) die_cdbread();
146  if (!stralloc_catb(sa,d,dns_domain_length(d))) nomem();
147 }
148 
149 int build(stralloc *sa,char *q,int flagsoa,char id[2])
150 {
151  unsigned int rdatapos;
152  char misc[20];
153  char type[2];
154  char recordloc[2];
155  char ttl[4];
156  char ttd[8];
157  struct tai cutoff;
158 
159  dpos = 0;
160  copy(type,2);
161  if (flagsoa) if (byte_diff(type,2,DNS_T_SOA)) return 0;
162  if (!flagsoa) if (byte_equal(type,2,DNS_T_SOA)) return 0;
163 
164  if (!stralloc_copyb(sa,id,2)) nomem();
165  if (!stralloc_catb(sa,"\204\000\0\0\0\1\0\0\0\0",10)) nomem();
166  copy(misc,1);
167  if ((misc[0] == '=' + 1) || (misc[0] == '*' + 1)) {
168  --misc[0];
169  copy(recordloc,2);
170  if (byte_diff(recordloc,2,clientloc)) return 0;
171  }
172  if (misc[0] == '*') {
173  if (flagsoa) return 0;
174  if (!stralloc_catb(sa,"\1*",2)) nomem();
175  }
176  if (!stralloc_catb(sa,q,dns_domain_length(q))) nomem();
177  if (!stralloc_catb(sa,type,2)) nomem();
178 
179  copy(ttl,4);
180  copy(ttd,8);
181  if (byte_diff(ttd,8,"\0\0\0\0\0\0\0\0")) {
182  tai_unpack(ttd,&cutoff);
183  if (byte_equal(ttl,4,"\0\0\0\0")) {
184  if (tai_less(&cutoff,&now)) return 0;
185  uint32_pack_big(ttl,2);
186  }
187  else
188  if (!tai_less(&cutoff,&now)) return 0;
189  }
190 
191  if (!stralloc_catb(sa,DNS_C_IN,2)) nomem();
192  if (!stralloc_catb(sa,ttl,4)) nomem();
193  if (!stralloc_catb(sa,"\0\0",2)) nomem();
194  rdatapos = sa->len;
195 
196  if (byte_equal(type,2,DNS_T_SOA)) {
197  doname(sa);
198  doname(sa);
199  copy(misc,20);
200  if (!stralloc_catb(sa,misc,20)) nomem();
201  }
202  else if (byte_equal(type,2,DNS_T_NS) || byte_equal(type,2,DNS_T_PTR) || byte_equal(type,2,DNS_T_CNAME)) {
203  doname(sa);
204  }
205  else if (byte_equal(type,2,DNS_T_MX)) {
206  copy(misc,2);
207  if (!stralloc_catb(sa,misc,2)) nomem();
208  doname(sa);
209  }
210  else
211  if (!stralloc_catb(sa,data + dpos,dlen - dpos)) nomem();
212 
213  if (sa->len > 65535) die_cdbformat();
214  uint16_pack_big(sa->s + rdatapos - 2,sa->len - rdatapos);
215  return 1;
216 }
217 
218 static struct cdb c;
219 static char *q;
220 static stralloc soa;
221 static stralloc message;
222 
223 void doaxfr(char id[2])
224 {
225  char key[MSGSIZE];
226  uint32 klen;
227  char num[4];
228  uint32 eod;
229  uint32 pos;
230  int r;
231 
232  axfrcheck(zone);
233 
235 
236  tai_now(&now);
237  cdb_init(&c,fdcdb);
238 
239  cdb_findstart(&c);
240  for (;;) {
241  r = cdb_findnext(&c,zone,zonelen);
242  if (r == -1) die_cdbread();
243  if (!r) die_outside();
244  dlen = cdb_datalen(&c);
245  if (dlen > sizeof(data)) die_cdbformat();
246  if (cdb_read(&c,data,dlen,cdb_datapos(&c)) == -1) die_cdbformat();
247  if (build(&soa,zone,1,id)) break;
248  }
249 
250  cdb_free(&c);
251  print(soa.s,soa.len);
252 
253  seek_begin(fdcdb);
254  buffer_init(&bcdb,buffer_unixread,fdcdb,bcdbspace,sizeof(bcdbspace));
255 
256  pos = 0;
257  get(num,4); pos += 4;
258  uint32_unpack(num,&eod);
259  while (pos < 2048) { get(num,4); pos += 4; }
260 
261  while (pos < eod) {
262  if (eod - pos < 8) die_cdbformat();
263  get(num,4); pos += 4;
264  uint32_unpack(num,&klen);
265  get(num,4); pos += 4;
266  uint32_unpack(num,&dlen);
267  if (eod - pos < klen) die_cdbformat();
268  pos += klen;
269  if (eod - pos < dlen) die_cdbformat();
270  pos += dlen;
271 
272  if (klen > sizeof(key)) die_cdbformat();
273  get(key,klen);
274  if (dlen > sizeof(data)) die_cdbformat();
275  get(data,dlen);
276 
277  if ((klen > 1) && (key[0] == 0)) continue; /* location */
278  if (klen < 1) die_cdbformat();
279  if (dns_packet_getname(key,klen,0,&q) != klen) die_cdbformat();
280  if (!dns_domain_suffix(q,zone)) continue;
281  if (!build(&message,q,0,id)) continue;
282  print(message.s,message.len);
283  }
284 
285  print(soa.s,soa.len);
286 }
287 
288 void netread(char *buf,unsigned int len)
289 {
290  int r;
291 
292  while (len > 0) {
293  r = timeoutread(60,0,buf,len);
294  if (r == 0) _exit(0);
295  if (r < 0) die_netread();
296  buf += r; len -= r;
297  }
298 }
299 
300 char tcpheader[2];
301 char buf[MSGSIZE];
302 uint16 len;
303 
304 static char seed[128];
305 
306 int main()
307 {
308  unsigned int pos;
309  char header[12];
310  char qtype[2];
311  char qclass[2];
312  const char *x;
313 
314  droproot(WHO);
315  dns_random_init(seed);
316 
317  axfr = env_get("AXFR");
318 
319  x = env_get("TCP6REMOTEIP");
320  if (!x) x = env_get("TCPREMOTEIP");
321  if (x && ip6_scan(x,ip))
322  ;
323  else
324  byte_zero(ip,16);
325 
326  x = env_get("TCP6REMOTEPORT");
327  if (!x)
328  x = env_get("TCPREMOTEPORT");
329  if (!x) x = "0";
330  scan_ulong(x,&port);
331 
332  for (;;) {
333  netread(tcpheader,2);
334  uint16_unpack_big(tcpheader,&len);
335  if (len > MSGSIZE) logmsg(WHO,111,FATAL,"excessively large request");
336  netread(buf,len);
337 
338  pos = dns_packet_copy(buf,len,0,header,12); if (!pos) die_truncated();
339  if (header[2] & 254) logmsg(WHO,111,FATAL,"bogus query");
340  if (header[4] || (header[5] != 1)) logmsg(WHO,111,FATAL,"bogus query");
341 
342  pos = dns_packet_getname(buf,len,pos,&zone); if (!pos) die_truncated();
343  zonelen = dns_domain_length(zone);
344  pos = dns_packet_copy(buf,len,pos,qtype,2); if (!pos) die_truncated();
345  pos = dns_packet_copy(buf,len,pos,qclass,2); if (!pos) die_truncated();
346 
347  if (byte_diff(qclass,2,DNS_C_IN) && byte_diff(qclass,2,DNS_C_ANY))
348  logmsg(WHO,111,FATAL,"bogus query: bad class");
349 
350  qlog(ip,port,header,zone,qtype," ");
351 
352  if (byte_equal(qtype,2,DNS_T_AXFR)) {
353  case_lowerb(zone,zonelen);
354  fdcdb = open_read("data.cdb");
355  if (fdcdb == -1) die_cdbread();
356  doaxfr(header);
357  close(fdcdb);
358  }
359  else {
360  if (!response_query(zone,qtype,qclass)) nomem();
361  response[2] |= 4;
362  case_lowerb(zone,zonelen);
363  response_id(header);
364  response[3] &= ~128;
365  if (!(header[2] & 1)) response[2] &= ~1;
366  if (!respond(zone,qtype,ip)) die_outside();
368  }
369  }
370 }
int fd
Definition: axfr-get.c:103
char data[32767]
Definition: axfrdns.c:131
void die_cdbread()
Definition: axfrdns.c:49
void get(char *buf, unsigned int len)
Definition: axfrdns.c:113
void die_truncated()
Definition: axfrdns.c:33
int fdcdb
Definition: axfrdns.c:109
buffer bcdb
Definition: axfrdns.c:110
unsigned long port
Definition: axfrdns.c:127
void netread(char *buf, unsigned int len)
Definition: axfrdns.c:288
void die_cdbformat()
Definition: axfrdns.c:53
char netwritespace[1024]
Definition: axfrdns.c:67
void die_outside()
Definition: axfrdns.c:45
int respond(char *, char *, char *)
int safewrite(int fd, char *buf, unsigned int len)
Definition: axfrdns.c:58
char bcdbspace[1024]
Definition: axfrdns.c:111
void die_netread()
Definition: axfrdns.c:41
unsigned int zonelen
Definition: axfrdns.c:106
void nomem()
Definition: axfrdns.c:29
struct tai now
Definition: axfrdns.c:130
int build(stralloc *sa, char *q, int flagsoa, char id[2])
Definition: axfrdns.c:149
void die_netwrite()
Definition: axfrdns.c:37
char clientloc[2]
Definition: axfrdns.c:128
void axfrcheck(char *q)
Definition: axfrdns.c:82
char ip[16]
Definition: axfrdns.c:126
uint16 len
Definition: axfrdns.c:302
char typeclass[4]
Definition: axfrdns.c:107
void print(char *buf, unsigned int len)
Definition: axfrdns.c:70
char * axfr
Definition: axfrdns.c:79
char buf[MSGSIZE]
Definition: axfrdns.c:301
void copy(char *buf, unsigned int len)
Definition: axfrdns.c:135
buffer netwrite
Definition: axfrdns.c:68
#define WHO
Definition: axfrdns.c:27
uint32 dpos
Definition: axfrdns.c:133
int main()
Definition: axfrdns.c:306
void doname(stralloc *sa)
Definition: axfrdns.c:141
void doaxfr(char id[2])
Definition: axfrdns.c:223
uint32 dlen
Definition: axfrdns.c:132
char tcpheader[2]
Definition: axfrdns.c:300
int find_client_loc(char loc[2], const char ip[16])
Definition: clientloc.c:8
unsigned int dns_packet_copy(const char *, unsigned int, unsigned int, char *, unsigned int)
Definition: dns_packet.c:8
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
#define DNS_C_IN
Definition: dns.h:34
#define MSGSIZE
Definition: dns.h:26
int dns_domain_suffix(const char *, const char *)
Definition: dns_domain.c:50
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_C_ANY
Definition: dns.h:35
unsigned int dns_packet_getname(const char *, unsigned int, unsigned int, char **)
Definition: dns_packet.c:35
void dns_random_init(const char *)
#define DNS_T_MX
Definition: dns.h:43
struct line * x
char type[2]
Definition: dnsq.c:56
void droproot(const char *fatal)
Definition: droproot.c:8
void d(const char *home, const char *subdir, int uid, int gid, int mode)
void qlog(const char ip[16], uint16 port, const char id[2], const char *q, const char qtype[2], const char *result)
Definition: qlog.c:51
struct cdb_make cdb
Definition: rbldns-data.c:36
void response_id(const char id[2])
Definition: response.c:114
char response[65535]
Definition: response.c:6
unsigned int response_len
Definition: response.c:7
int response_query(const char *q, const char qtype[2], const char qclass[2])
Definition: response.c:54