release
[hcoop/zz_old/debian/djbdns.git] / tdlookup.c
1 #include <unistd.h>
2 #include "uint16.h"
3 #include "open.h"
4 #include "tai.h"
5 #include "cdb.h"
6 #include "byte.h"
7 #include "case.h"
8 #include "dns.h"
9 #include "seek.h"
10 #include "response.h"
11
12 static int want(const char *owner,const char type[2])
13 {
14 unsigned int pos;
15 static char *d;
16 char x[10];
17 uint16 datalen;
18
19 pos = dns_packet_skipname(response,response_len,12); if (!pos) return 0;
20 pos += 4;
21
22 while (pos < response_len) {
23 pos = dns_packet_getname(response,response_len,pos,&d); if (!pos) return 0;
24 pos = dns_packet_copy(response,response_len,pos,x,10); if (!pos) return 0;
25 if (dns_domain_equal(d,owner))
26 if (byte_equal(type,2,x))
27 return 0;
28 uint16_unpack_big(x + 8,&datalen);
29 pos += datalen;
30 }
31 return 1;
32 }
33
34 static char *d1;
35
36 static char clientloc[2];
37 static struct tai now;
38 static struct cdb c;
39
40 static char data[32767];
41 static uint32 dlen;
42 static unsigned int dpos;
43 static char type[2];
44 static uint32 ttl;
45
46 static int find(char *d,int flagwild)
47 {
48 int r;
49 char ch;
50 struct tai cutoff;
51 char ttd[8];
52 char ttlstr[4];
53 char recordloc[2];
54 double newttl;
55
56 for (;;) {
57 r = cdb_findnext(&c,d,dns_domain_length(d));
58 if (r <= 0) return r;
59 dlen = cdb_datalen(&c);
60 if (dlen > sizeof data) return -1;
61 if (cdb_read(&c,data,dlen,cdb_datapos(&c)) == -1) return -1;
62 dpos = dns_packet_copy(data,dlen,0,type,2); if (!dpos) return -1;
63 dpos = dns_packet_copy(data,dlen,dpos,&ch,1); if (!dpos) return -1;
64 if ((ch == '=' + 1) || (ch == '*' + 1)) {
65 --ch;
66 dpos = dns_packet_copy(data,dlen,dpos,recordloc,2); if (!dpos) return -1;
67 if (byte_diff(recordloc,2,clientloc)) continue;
68 }
69 if (flagwild != (ch == '*')) continue;
70 dpos = dns_packet_copy(data,dlen,dpos,ttlstr,4); if (!dpos) return -1;
71 uint32_unpack_big(ttlstr,&ttl);
72 dpos = dns_packet_copy(data,dlen,dpos,ttd,8); if (!dpos) return -1;
73 if (byte_diff(ttd,8,"\0\0\0\0\0\0\0\0")) {
74 tai_unpack(ttd,&cutoff);
75 if (ttl == 0) {
76 if (tai_less(&cutoff,&now)) continue;
77 tai_sub(&cutoff,&cutoff,&now);
78 newttl = tai_approx(&cutoff);
79 if (newttl <= 2.0) newttl = 2.0;
80 if (newttl >= 3600.0) newttl = 3600.0;
81 ttl = newttl;
82 }
83 else
84 if (!tai_less(&cutoff,&now)) continue;
85 }
86 return 1;
87 }
88 }
89
90 static int dobytes(unsigned int len)
91 {
92 char buf[20];
93 if (len > 20) return 0;
94 dpos = dns_packet_copy(data,dlen,dpos,buf,len);
95 if (!dpos) return 0;
96 return response_addbytes(buf,len);
97 }
98
99 static int doname(void)
100 {
101 dpos = dns_packet_getname(data,dlen,dpos,&d1);
102 if (!dpos) return 0;
103 return response_addname(d1);
104 }
105
106 static int doit(char *q,char qtype[2])
107 {
108 unsigned int bpos;
109 unsigned int anpos;
110 unsigned int aupos;
111 unsigned int arpos;
112 char *control;
113 char *wild;
114 int flaggavesoa;
115 int flagfound;
116 int r;
117 int flagns;
118 int flagauthoritative;
119 char x[20];
120 uint16 u16;
121 char addr[8][4];
122 int addrnum;
123 uint32 addrttl;
124 int i;
125
126 anpos = response_len;
127
128 control = q;
129 for (;;) {
130 flagns = 0;
131 flagauthoritative = 0;
132 cdb_findstart(&c);
133 while (r = find(control,0)) {
134 if (r == -1) return 0;
135 if (byte_equal(type,2,DNS_T_SOA)) flagauthoritative = 1;
136 if (byte_equal(type,2,DNS_T_NS)) flagns = 1;
137 }
138 if (flagns) break;
139 if (!*control) return 0; /* q is not within our bailiwick */
140 control += *control;
141 control += 1;
142 }
143
144 if (!flagauthoritative) {
145 response[2] &= ~4;
146 goto AUTHORITY; /* q is in a child zone */
147 }
148
149
150 flaggavesoa = 0;
151 flagfound = 0;
152 wild = q;
153
154 for (;;) {
155 addrnum = 0;
156 addrttl = 0;
157 cdb_findstart(&c);
158 while (r = find(wild,wild != q)) {
159 if (r == -1) return 0;
160 flagfound = 1;
161 if (flaggavesoa && byte_equal(type,2,DNS_T_SOA)) continue;
162 if (byte_diff(type,2,qtype) && byte_diff(qtype,2,DNS_T_ANY) && byte_diff(type,2,DNS_T_CNAME)) continue;
163 if (byte_equal(type,2,DNS_T_A) && (dlen - dpos == 4)) {
164 addrttl = ttl;
165 i = dns_random(addrnum + 1);
166 if (i < 8) {
167 if ((i < addrnum) && (addrnum < 8))
168 byte_copy(addr[addrnum],4,addr[i]);
169 byte_copy(addr[i],4,data + dpos);
170 }
171 if (addrnum < 1000000) ++addrnum;
172 continue;
173 }
174 if (!response_rstart(q,type,ttl)) return 0;
175 if (byte_equal(type,2,DNS_T_NS) || byte_equal(type,2,DNS_T_CNAME) || byte_equal(type,2,DNS_T_PTR)) {
176 if (!doname()) return 0;
177 }
178 else if (byte_equal(type,2,DNS_T_MX)) {
179 if (!dobytes(2)) return 0;
180 if (!doname()) return 0;
181 }
182 else if (byte_equal(type,2,DNS_T_SOA)) {
183 if (!doname()) return 0;
184 if (!doname()) return 0;
185 if (!dobytes(20)) return 0;
186 flaggavesoa = 1;
187 }
188 else
189 if (!response_addbytes(data + dpos,dlen - dpos)) return 0;
190 response_rfinish(RESPONSE_ANSWER);
191 }
192 for (i = 0;i < addrnum;++i)
193 if (i < 8) {
194 if (!response_rstart(q,DNS_T_A,addrttl)) return 0;
195 if (!response_addbytes(addr[i],4)) return 0;
196 response_rfinish(RESPONSE_ANSWER);
197 }
198
199 if (flagfound) break;
200 if (wild == control) break;
201 if (!*wild) break; /* impossible */
202 wild += *wild;
203 wild += 1;
204 }
205
206 if (!flagfound)
207 response_nxdomain();
208
209
210 AUTHORITY:
211 aupos = response_len;
212
213 if (flagauthoritative && (aupos == anpos)) {
214 cdb_findstart(&c);
215 while (r = find(control,0)) {
216 if (r == -1) return 0;
217 if (byte_equal(type,2,DNS_T_SOA)) {
218 if (!response_rstart(control,DNS_T_SOA,ttl)) return 0;
219 if (!doname()) return 0;
220 if (!doname()) return 0;
221 if (!dobytes(20)) return 0;
222 response_rfinish(RESPONSE_AUTHORITY);
223 break;
224 }
225 }
226 }
227 else
228 if (want(control,DNS_T_NS)) {
229 cdb_findstart(&c);
230 while (r = find(control,0)) {
231 if (r == -1) return 0;
232 if (byte_equal(type,2,DNS_T_NS)) {
233 if (!response_rstart(control,DNS_T_NS,ttl)) return 0;
234 if (!doname()) return 0;
235 response_rfinish(RESPONSE_AUTHORITY);
236 }
237 }
238 }
239
240 arpos = response_len;
241
242 bpos = anpos;
243 while (bpos < arpos) {
244 bpos = dns_packet_skipname(response,arpos,bpos); if (!bpos) return 0;
245 bpos = dns_packet_copy(response,arpos,bpos,x,10); if (!bpos) return 0;
246 if (byte_equal(x,2,DNS_T_NS) || byte_equal(x,2,DNS_T_MX)) {
247 if (byte_equal(x,2,DNS_T_NS)) {
248 if (!dns_packet_getname(response,arpos,bpos,&d1)) return 0;
249 }
250 else
251 if (!dns_packet_getname(response,arpos,bpos + 2,&d1)) return 0;
252 case_lowerb(d1,dns_domain_length(d1));
253 if (want(d1,DNS_T_A)) {
254 cdb_findstart(&c);
255 while (r = find(d1,0)) {
256 if (r == -1) return 0;
257 if (byte_equal(type,2,DNS_T_A)) {
258 if (!response_rstart(d1,DNS_T_A,ttl)) return 0;
259 if (!dobytes(4)) return 0;
260 response_rfinish(RESPONSE_ADDITIONAL);
261 }
262 }
263 }
264 }
265 uint16_unpack_big(x + 8,&u16);
266 bpos += u16;
267 }
268
269 if (flagauthoritative && (response_len > 512)) {
270 byte_zero(response + RESPONSE_ADDITIONAL,2);
271 response_len = arpos;
272 if (response_len > 512) {
273 byte_zero(response + RESPONSE_AUTHORITY,2);
274 response_len = aupos;
275 }
276 }
277
278 return 1;
279 }
280
281 int respond(char *q,char qtype[2],char ip[4])
282 {
283 int fd;
284 int r;
285 char key[6];
286
287 tai_now(&now);
288 fd = open_read("data.cdb");
289 if (fd == -1) return 0;
290 cdb_init(&c,fd);
291
292 byte_zero(clientloc,2);
293 key[0] = 0;
294 key[1] = '%';
295 byte_copy(key + 2,4,ip);
296 r = cdb_find(&c,key,6);
297 if (!r) r = cdb_find(&c,key,5);
298 if (!r) r = cdb_find(&c,key,4);
299 if (!r) r = cdb_find(&c,key,3);
300 if (!r) r = cdb_find(&c,key,2);
301 if (r == -1) return 0;
302 if (r && (cdb_datalen(&c) == 2))
303 if (cdb_read(&c,clientloc,2,cdb_datapos(&c)) == -1) return 0;
304
305 r = doit(q,qtype);
306
307 cdb_free(&c);
308 close(fd);
309 return r;
310 }