djbdnscurve6 53
djbdnscurve6
Loading...
Searching...
No Matches
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
24extern int respond(char *,char *,char *);
25
26#define WHO "axfrdns"
27
28unsigned int flagedns0 = 0;
29unsigned int msgsize = MSGSIZE;
30
31void nomem()
32{
33 logmsg(WHO,111,FATAL,"out of memory");
34}
36{
37 logmsg(WHO,111,FATAL,"truncated request");
38}
40{
41 logmsg(WHO,111,FATAL,"unable to write to network");
42}
44{
45 logmsg(WHO,111,FATAL,"unable to read from network");
46}
48{
49 logmsg(WHO,111,FATAL,"unable to locate information in data.cdb");
50}
52{
53 logmsg(WHO,111,FATAL,"unable to read data.cdb");
54}
56{
57 logmsg(WHO,111,FATAL,B("unable to read data.cdb: ","format error"));
58}
59
60ssize_t safewrite(int fd,char *buf,size_t len)
61{
62 int r;
63
64 r = timeoutwrite(60,fd,buf,len);
65 if (r <= 0) die_netwrite();
66 return r;
67}
68
69char netwritespace[1024];
70buffer netwrite = BUFFER_INIT(safewrite,1,netwritespace,sizeof(netwritespace));
71
72void print(char *buf,unsigned int len)
73{
74 char tcpheader[2];
75 uint16_pack_big(tcpheader,len);
76 buffer_put(&netwrite,tcpheader,2);
77 buffer_put(&netwrite,buf,len);
78 buffer_flush(&netwrite);
79}
80
81char *axfr;
82static char *axfrok;
83
84void axfrcheck(char *q)
85{
86 int i;
87 int j;
88
89 if (!axfr) return;
90
91 i = j = 0;
92 for (;;) {
93 if (!axfr[i] || (axfr[i] == '/')) {
94 if (i > j) {
95 if (dns_domain_fromdot(&axfrok,axfr + j,i - j) <= 0) nomem();
96 if (dns_domain_equal(q,axfrok)) return;
97 }
98 j = i + 1;
99 }
100 if (!axfr[i]) break;
101 ++i;
102 }
103
104 logmsg(WHO,111,FATAL,"disallowed zone transfer request");
105}
106
107static char *zone;
108unsigned int zonelen;
109char typeclass[4];
110
112buffer bcdb;
113char bcdbspace[1024];
114
115void get_cdb(char *buf,unsigned int len)
116{
117 int r;
118
119 while (len > 0) {
120 r = buffer_get(&bcdb,buf,len);
121 if (r < 0) die_cdbread();
122 if (!r) die_cdbformat();
123 buf += r;
124 len -= r;
125 }
126}
127
128char ip[16];
129unsigned long port;
130char clientloc[2];
131
132struct tai now;
133char data[32767];
134uint32 dlen;
135uint32 dpos;
136
137void dns_copy(char *buf,unsigned int len)
138{
140 if (!dpos) die_cdbread();
141}
142
143void doname(stralloc *sa)
144{
145 static char *d;
147 if (!dpos) die_cdbread();
148 if (!stralloc_catb(sa,d,dns_domain_length(d))) nomem();
149}
150
151int build(stralloc *sa,char *q,int flagsoa,char id[2])
152{
153 unsigned int rdatapos;
154 char misc[20];
155 char type[2];
156 char recordloc[2];
157 char ttl[4];
158 char ttd[8];
159 struct tai cutoff;
160
161 dpos = 0;
162 dns_copy(type,2);
163 if (flagsoa) if (byte_diff(type,2,DNS_T_SOA)) return 0;
164 if (!flagsoa) if (byte_equal(type,2,DNS_T_SOA)) return 0;
165
166/*
167 Byte \204 (meaning: response, opcode 0, authoritative, not truncated, recursion not desired), or, optionally,
168 QR OPCODE AA TC RD
169 \205 if the client used byte \001. named-xfer rejects responses that do not have at least bits \204.
170 Byte \000 (meaning: recursion not available, no Z bits, RCODE 0), or, optionally, \200.
171 RA Z+AD+CD RCODE
172 Bytes \000\000 (meaning no questions), or \000\001 (meaning one question).
173 QDCOUNT=0 QDCOUNT=1
1742 bytes, nly \000\001, indicating the number of answer records below.
175 ANCOUNT
176 Bytes \000\000 (meaning no authority records).
177 NSCOUNT
178 Bytes \000\000 (meaning no additional records).
179 ARCOUNT
180 NOTE: \000 = \00 = \0
181*/
182
183 if (!stralloc_copyb(sa,id,2)) nomem(); // ID
184 if (!stralloc_catb(sa,"\204\000\0\0\0\1\0\0\0\0",10)) nomem(); // following header
185
186 dns_copy(misc,1);
187 if ((misc[0] == '=' + 1) || (misc[0] == '*' + 1)) { // '*'+1 = 43; '='+1 = 62; bug fix?
188 --misc[0];
189 dns_copy(recordloc,2);
190 if (byte_diff(recordloc,2,clientloc)) return 0;
191 }
192 if (misc[0] == '*') {
193 if (flagsoa) return 0;
194 if (!stralloc_catb(sa,"\1*",2)) nomem();
195 }
196 if (!stralloc_catb(sa,q,dns_domain_length(q))) nomem();
197 if (!stralloc_catb(sa,type,2)) nomem();
198
199 dns_copy(ttl,4);
200 dns_copy(ttd,8);
201 if (byte_diff(ttd,8,"\0\0\0\0\0\0\0\0")) {
202 tai_unpack(ttd,&cutoff);
203 if (byte_equal(ttl,4,"\0\0\0\0")) {
204 if (tai_less(&cutoff,&now)) return 0;
205 uint32_pack_big(ttl,2);
206 }
207 else
208 if (!tai_less(&cutoff,&now)) return 0;
209 }
210
211 if (!stralloc_catb(sa,DNS_C_IN,2)) nomem();
212 if (!stralloc_catb(sa,ttl,4)) nomem();
213 if (!stralloc_catb(sa,"\0\0",2)) nomem();
214 rdatapos = sa->len;
215
216 if (byte_equal(type,2,DNS_T_SOA)) {
217 doname(sa);
218 doname(sa);
219 dns_copy(misc,20);
220 if (!stralloc_catb(sa,misc,20)) nomem();
221 }
222 else if (byte_equal(type,2,DNS_T_NS) || byte_equal(type,2,DNS_T_PTR) || byte_equal(type,2,DNS_T_CNAME)) {
223 doname(sa);
224 }
225 else if (byte_equal(type,2,DNS_T_MX)) {
226 dns_copy(misc,2);
227 if (!stralloc_catb(sa,misc,2)) nomem();
228 doname(sa);
229 }
230 else
231 if (!stralloc_catb(sa,data + dpos,dlen - dpos)) nomem();
232
233 if (sa->len > 65535) die_cdbformat();
234 uint16_pack_big(sa->s + rdatapos - 2,sa->len - rdatapos);
235 return 1;
236}
237
238static struct cdb c;
239static char *q;
240static stralloc soa;
241static stralloc message;
242
243void doaxfr(char id[2])
244{
245 char key[MSGSIZE];
246 uint32 klen;
247 char num[4];
248 uint32 eod;
249 uint32 pos;
250 int r;
251
252 axfrcheck(zone);
253
255
256 tai_now(&now);
257 cdb_init(&c,fdcdb);
258
259 cdb_findstart(&c);
260 for (;;) {
261 r = cdb_findnext(&c,zone,zonelen);
262 if (r == -1) die_cdbread();
263 if (!r) die_outside();
264 dlen = cdb_datalen(&c);
265 if (dlen > sizeof(data)) die_cdbformat();
266 if (cdb_read(&c,data,dlen,cdb_datapos(&c)) == -1) die_cdbformat();
267 if (build(&soa,zone,1,id)) break;
268 }
269
270 cdb_free(&c);
271 print(soa.s,soa.len);
272
273 seek_begin(fdcdb);
274 buffer_init(&bcdb,buffer_unixread,fdcdb,bcdbspace,sizeof(bcdbspace));
275
276 pos = 0;
277 get_cdb(num,4); pos += 4;
278 uint32_unpack(num,&eod);
279 while (pos < 2048) { get_cdb(num,4); pos += 4; }
280
281 while (pos < eod) {
282 if (eod - pos < 8) die_cdbformat();
283 get_cdb(num,4); pos += 4;
284 uint32_unpack(num,&klen);
285 get_cdb(num,4); pos += 4;
286 uint32_unpack(num,&dlen);
287 if (eod - pos < klen) die_cdbformat();
288 pos += klen;
289 if (eod - pos < dlen) die_cdbformat();
290 pos += dlen;
291
292 if (klen > sizeof(key)) die_cdbformat();
293 get_cdb(key,klen);
294 if (dlen > sizeof(data)) die_cdbformat();
296
297 if ((klen > 1) && (key[0] == 0)) continue; /* location */
298 if (klen < 1) die_cdbformat();
299 if (dns_packet_getname(key,klen,0,&q) != klen) die_cdbformat();
300 if (!dns_domain_suffix(q,zone)) continue;
301 if (!build(&message,q,0,id)) continue;
302 print(message.s,message.len);
303 }
304
305 print(soa.s,soa.len);
306}
307
308void netread(char *buf,unsigned int len)
309{
310 int r;
311
312 while (len > 0) {
313 r = timeoutread(60,0,buf,len);
314 if (r == 0) _exit(0);
315 if (r < 0) die_netread();
316 buf += r; len -= r;
317 }
318}
319
320char tcpheader[2];
322uint16 len;
323
324static char seed[128];
325
326int main()
327{
328 unsigned int pos;
329 char header[12];
330 char qtype[2];
331 char qclass[2];
332 const char *x;
333
334 droproot(WHO);
335 dns_random_init(seed);
336
337 axfr = env_get("AXFR");
338
339 x = env_get("TCP6REMOTEIP");
340 if (!x) x = env_get("TCPREMOTEIP");
341 if (x && ip6_scan(x,ip))
342 ;
343 else
344 byte_zero(ip,16);
345
346 x = env_get("TCP6REMOTEPORT");
347 if (!x)
348 x = env_get("TCPREMOTEPORT");
349 if (!x) x = "0";
350 scan_dnum(x,&port);
351
352 for (;;) {
354 uint16_unpack_big(tcpheader,&len);
355 if (len > MSGSIZE) logmsg(WHO,111,FATAL,"excessively large request");
356 netread(buf,len);
357
358 pos = dns_packet_copy(buf,len,0,header,12); if (!pos) die_truncated();
359 if (header[2] & 254) logmsg(WHO,111,FATAL,"bogus query");
360 if (header[4] || (header[5] != 1)) logmsg(WHO,111,FATAL,"bogus query");
361
362 pos = dns_packet_getname(buf,len,pos,&zone); if (!pos) die_truncated();
364 pos = dns_packet_copy(buf,len,pos,qtype,2); if (!pos) die_truncated();
365 pos = dns_packet_copy(buf,len,pos,qclass,2); if (!pos) die_truncated();
366
367 if (byte_diff(qclass,2,DNS_C_IN) && byte_diff(qclass,2,DNS_C_ANY))
368 logmsg(WHO,111,FATAL,"bogus query: bad class");
369
370 qlog(ip,port,header,zone,qtype," ");
371
372 if (byte_equal(qtype,2,DNS_T_AXFR)) {
373 case_lowerb(zone,zonelen);
374 fdcdb = open_read("data.cdb");
375 if (fdcdb == -1) die_cdbread();
376 doaxfr(header);
377 close(fdcdb);
378 }
379 else {
380 if (!response_query(zone,qtype,qclass)) nomem();
381 response[2] |= 4;
382 case_lowerb(zone,zonelen);
383 response_id(header);
384 response[3] &= ~128;
385 if (!(header[2] & 1)) response[2] &= ~1;
386 if (!respond(zone,qtype,ip)) die_outside();
388 }
389 }
390}
int fd
Definition: axfr-get.c:103
buffer netread
Definition: axfr-get.c:89
ssize_t safewrite(int fd, char *buf, size_t len)
Definition: axfrdns.c:60
char data[32767]
Definition: axfrdns.c:133
void die_cdbread()
Definition: axfrdns.c:51
void dns_copy(char *buf, unsigned int len)
Definition: axfrdns.c:137
void die_truncated()
Definition: axfrdns.c:35
int fdcdb
Definition: axfrdns.c:111
buffer bcdb
Definition: axfrdns.c:112
unsigned long port
Definition: axfrdns.c:129
void die_cdbformat()
Definition: axfrdns.c:55
char netwritespace[1024]
Definition: axfrdns.c:69
void die_outside()
Definition: axfrdns.c:47
int respond(char *, char *, char *)
void get_cdb(char *buf, unsigned int len)
Definition: axfrdns.c:115
char bcdbspace[1024]
Definition: axfrdns.c:113
void die_netread()
Definition: axfrdns.c:43
unsigned int zonelen
Definition: axfrdns.c:108
void nomem()
Definition: axfrdns.c:31
struct tai now
Definition: axfrdns.c:132
int build(stralloc *sa, char *q, int flagsoa, char id[2])
Definition: axfrdns.c:151
void die_netwrite()
Definition: axfrdns.c:39
char clientloc[2]
Definition: axfrdns.c:130
unsigned int flagedns0
Definition: axfrdns.c:28
void axfrcheck(char *q)
Definition: axfrdns.c:84
char ip[16]
Definition: axfrdns.c:128
uint16 len
Definition: axfrdns.c:322
char typeclass[4]
Definition: axfrdns.c:109
void print(char *buf, unsigned int len)
Definition: axfrdns.c:72
char * axfr
Definition: axfrdns.c:81
char buf[MSGSIZE]
Definition: axfrdns.c:321
unsigned int msgsize
Definition: axfrdns.c:29
buffer netwrite
Definition: axfrdns.c:70
#define WHO
Definition: axfrdns.c:26
uint32 dpos
Definition: axfrdns.c:135
int main()
Definition: axfrdns.c:326
void doname(stralloc *sa)
Definition: axfrdns.c:143
void doaxfr(char id[2])
Definition: axfrdns.c:243
uint32 dlen
Definition: axfrdns.c:134
char tcpheader[2]
Definition: axfrdns.c:320
int find_clientloc(char clientloc[2], const char ip[16])
Definition: clientloc.c:8
#define DNS_T_AXFR
Definition: dns.h:95
#define DNS_C_IN
Definition: dns.h:62
#define MSGSIZE
Definition: dns.h:47
#define DNS_T_PTR
Definition: dns.h:69
#define DNS_T_SOA
Definition: dns.h:68
#define DNS_T_NS
Definition: dns.h:66
#define DNS_T_CNAME
Definition: dns.h:67
#define DNS_C_ANY
Definition: dns.h:63
#define DNS_T_MX
Definition: dns.h:71
int dns_domain_fromdot(char **out, const char *buf, unsigned int n)
Definition: dns_dfd.c:6
int dns_domain_equal(const char *dn1, const char *dn2)
Definition: dns_domain.c:39
unsigned int dns_domain_length(const char *dn)
Definition: dns_domain.c:6
int dns_domain_suffix(const char *big, const char *little)
Definition: dns_domain.c:50
unsigned int dns_packet_getname(const char *buf, unsigned int len, unsigned int pos, char **d)
Definition: dns_packet.c:35
unsigned int dns_packet_copy(const char *buf, unsigned int len, unsigned int pos, char *out, unsigned int outlen)
Definition: dns_packet.c:8
void dns_random_init(const char data[128])
Definition: dns_random.c:36
struct line * x
char type[2]
Definition: dnsq.c:60
void droproot(const char *server)
Definition: droproot.c:7
void d(const char *home, const char *subdir, int uid, int gid, int mode)
void qlog(const char[16], uint16, const char[2], const char *, const char[2], const char *)
Definition: qlog.c:51
struct cdb_make cdb
Definition: rbldns-data.c:36
void response_id(const char[2])
Definition: response.c:114
char response[]
Definition: response.c:6
unsigned int response_len
Definition: response.c:7
int response_query(const char *, const char[2], const char[2])
Definition: response.c:54