10 #include "timeoutread.h"
11 #include "timeoutwrite.h"
25 extern int respond(char *,char *,char *);
27 #define FATAL "axfrdns: fatal: "
31 strerr_die2x(111,FATAL
,"out of memory");
35 strerr_die2x(111,FATAL
,"truncated request");
39 strerr_die2sys(111,FATAL
,"unable to write to network: ");
43 strerr_die2sys(111,FATAL
,"unable to read from network: ");
47 strerr_die2x(111,FATAL
,"unable to locate information in data.cdb");
51 strerr_die2sys(111,FATAL
,"unable to read data.cdb: ");
55 strerr_die3x(111,FATAL
,"unable to read data.cdb: ","format error");
58 int safewrite(int fd
,char *buf
,unsigned int len
)
62 w
= timeoutwrite(60,fd
,buf
,len
);
63 if (w
<= 0) die_netwrite();
67 char netwritespace
[1024];
68 buffer netwrite
= BUFFER_INIT(safewrite
,1,netwritespace
,sizeof netwritespace
);
70 void print(char *buf
,unsigned int len
)
73 uint16_pack_big(tcpheader
,len
);
74 buffer_put(&netwrite
,tcpheader
,2);
75 buffer_put(&netwrite
,buf
,len
);
76 buffer_flush(&netwrite
);
82 void axfrcheck(char *q
)
91 if (!axfr
[i
] || (axfr
[i
] == '/')) {
93 if (!dns_domain_fromdot(&axfrok
,axfr
+ j
,i
- j
)) nomem();
94 if (dns_domain_equal(q
,axfrok
)) return;
102 strerr_die2x(111,FATAL
,"disallowed zone transfer request");
106 unsigned int zonelen
;
111 char bcdbspace
[1024];
113 void get(char *buf
,unsigned int len
)
118 r
= buffer_get(&bcdb
,buf
,len
);
119 if (r
< 0) die_cdbread();
120 if (!r
) die_cdbformat();
135 void copy(char *buf
,unsigned int len
)
137 dpos
= dns_packet_copy(data
,dlen
,dpos
,buf
,len
);
138 if (!dpos
) die_cdbread();
141 void doname(stralloc
*sa
)
144 dpos
= dns_packet_getname(data
,dlen
,dpos
,&d
);
145 if (!dpos
) die_cdbread();
146 if (!stralloc_catb(sa
,d
,dns_domain_length(d
))) nomem();
149 int build(stralloc
*sa
,char *q
,int flagsoa
,char id
[2])
151 unsigned int rdatapos
;
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;
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();
167 if ((misc
[0] == '=' + 1) || (misc
[0] == '*' + 1)) {
170 if (byte_diff(recordloc
,2,clientloc
)) return 0;
172 if (misc
[0] == '*') {
173 if (flagsoa
) return 0;
174 if (!stralloc_catb(sa
,"\1*",2)) nomem();
176 if (!stralloc_catb(sa
,q
,dns_domain_length(q
))) nomem();
177 if (!stralloc_catb(sa
,type
,2)) nomem();
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);
188 if (!tai_less(&cutoff
,&now
)) return 0;
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();
196 if (byte_equal(type
,2,DNS_T_SOA
)) {
200 if (!stralloc_catb(sa
,misc
,20)) nomem();
202 else if (byte_equal(type
,2,DNS_T_NS
) || byte_equal(type
,2,DNS_T_PTR
) || byte_equal(type
,2,DNS_T_CNAME
)) {
205 else if (byte_equal(type
,2,DNS_T_MX
)) {
207 if (!stralloc_catb(sa
,misc
,2)) nomem();
211 if (!stralloc_catb(sa
,data
+ dpos
,dlen
- dpos
)) nomem();
213 if (sa
->len
> 65535) die_cdbformat();
214 uint16_pack_big(sa
->s
+ rdatapos
- 2,sa
->len
- rdatapos
);
221 static stralloc message
;
223 void doaxfr(char id
[2])
237 byte_zero(clientloc
,2);
240 byte_copy(key
+ 2,4,ip
);
241 r
= cdb_find(&c
,key
,6);
242 if (!r
) r
= cdb_find(&c
,key
,5);
243 if (!r
) r
= cdb_find(&c
,key
,4);
244 if (!r
) r
= cdb_find(&c
,key
,3);
245 if (!r
) r
= cdb_find(&c
,key
,2);
246 if (r
== -1) die_cdbread();
247 if (r
&& (cdb_datalen(&c
) == 2))
248 if (cdb_read(&c
,clientloc
,2,cdb_datapos(&c
)) == -1) die_cdbread();
252 r
= cdb_findnext(&c
,zone
,zonelen
);
253 if (r
== -1) die_cdbread();
254 if (!r
) die_outside();
255 dlen
= cdb_datalen(&c
);
256 if (dlen
> sizeof data
) die_cdbformat();
257 if (cdb_read(&c
,data
,dlen
,cdb_datapos(&c
)) == -1) die_cdbformat();
258 if (build(&soa
,zone
,1,id
)) break;
262 print(soa
.s
,soa
.len
);
265 buffer_init(&bcdb
,buffer_unixread
,fdcdb
,bcdbspace
,sizeof bcdbspace
);
268 get(num
,4); pos
+= 4;
269 uint32_unpack(num
,&eod
);
270 while (pos
< 2048) { get(num
,4); pos
+= 4; }
273 if (eod
- pos
< 8) die_cdbformat();
274 get(num
,4); pos
+= 4;
275 uint32_unpack(num
,&klen
);
276 get(num
,4); pos
+= 4;
277 uint32_unpack(num
,&dlen
);
278 if (eod
- pos
< klen
) die_cdbformat();
280 if (eod
- pos
< dlen
) die_cdbformat();
283 if (klen
> sizeof key
) die_cdbformat();
285 if (dlen
> sizeof data
) die_cdbformat();
288 if ((klen
> 1) && (key
[0] == 0)) continue; /* location */
289 if (klen
< 1) die_cdbformat();
290 if (dns_packet_getname(key
,klen
,0,&q
) != klen
) die_cdbformat();
291 if (!dns_domain_suffix(q
,zone
)) continue;
292 if (!build(&message
,q
,0,id
)) continue;
293 print(message
.s
,message
.len
);
296 print(soa
.s
,soa
.len
);
299 void netread(char *buf
,unsigned int len
)
304 r
= timeoutread(60,0,buf
,len
);
305 if (r
== 0) _exit(0);
306 if (r
< 0) die_netread();
315 static char seed
[128];
326 dns_random_init(seed
);
328 axfr
= env_get("AXFR");
330 x
= env_get("TCPREMOTEIP");
331 if (x
&& ip4_scan(x
,ip
))
336 x
= env_get("TCPREMOTEPORT");
341 netread(tcpheader
,2);
342 uint16_unpack_big(tcpheader
,&len
);
343 if (len
> 512) strerr_die2x(111,FATAL
,"excessively large request");
346 pos
= dns_packet_copy(buf
,len
,0,header
,12); if (!pos
) die_truncated();
347 if (header
[2] & 254) strerr_die2x(111,FATAL
,"bogus query");
348 if (header
[4] || (header
[5] != 1)) strerr_die2x(111,FATAL
,"bogus query");
350 pos
= dns_packet_getname(buf
,len
,pos
,&zone
); if (!pos
) die_truncated();
351 zonelen
= dns_domain_length(zone
);
352 pos
= dns_packet_copy(buf
,len
,pos
,qtype
,2); if (!pos
) die_truncated();
353 pos
= dns_packet_copy(buf
,len
,pos
,qclass
,2); if (!pos
) die_truncated();
355 if (byte_diff(qclass
,2,DNS_C_IN
) && byte_diff(qclass
,2,DNS_C_ANY
))
356 strerr_die2x(111,FATAL
,"bogus query: bad class");
358 qlog(ip
,port
,header
,zone
,qtype
," ");
360 if (byte_equal(qtype
,2,DNS_T_AXFR
)) {
361 case_lowerb(zone
,zonelen
);
362 fdcdb
= open_read("data.cdb");
363 if (fdcdb
== -1) die_cdbread();
368 if (!response_query(zone
,qtype
,qclass
)) nomem();
370 case_lowerb(zone
,zonelen
);
373 if (!(header
[2] & 1)) response
[2] &= ~1;
374 if (!respond(zone
,qtype
,ip
)) die_outside();
375 print(response
,response_len
);