]>
Commit | Line | Data |
---|---|---|
aff33962 | 1 | /* dnsmasq is Copyright (c) 2000-2015 Simon Kelley |
4f7b304f SK |
2 | |
3 | This program is free software; you can redistribute it and/or modify | |
4 | it under the terms of the GNU General Public License as published by | |
5 | the Free Software Foundation; version 2 dated June, 1991, or | |
6 | (at your option) version 3 dated 29 June, 2007. | |
7 | ||
8 | This program is distributed in the hope that it will be useful, | |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | GNU General Public License for more details. | |
12 | ||
13 | You should have received a copy of the GNU General Public License | |
14 | along with this program. If not, see <http://www.gnu.org/licenses/>. | |
15 | */ | |
16 | ||
17 | #include "dnsmasq.h" | |
18 | ||
4820dce9 | 19 | #ifdef HAVE_AUTH |
b75e9363 | 20 | |
c50f25a3 | 21 | static struct addrlist *find_subnet(struct auth_zone *zone, int flag, struct all_addr *addr_u) |
4f7b304f | 22 | { |
376d48c7 | 23 | struct addrlist *subnet; |
4f7b304f SK |
24 | |
25 | for (subnet = zone->subnet; subnet; subnet = subnet->next) | |
26 | { | |
376d48c7 | 27 | if (!(subnet->flags & ADDRLIST_IPV6)) |
4f7b304f | 28 | { |
376d48c7 SK |
29 | struct in_addr netmask, addr = addr_u->addr.addr4; |
30 | ||
31 | if (!(flag & F_IPV4)) | |
32 | continue; | |
4f7b304f | 33 | |
10cfc0dd | 34 | netmask.s_addr = htonl(~(in_addr_t)0 << (32 - subnet->prefixlen)); |
4f7b304f | 35 | |
376d48c7 | 36 | if (is_same_net(addr, subnet->addr.addr.addr4, netmask)) |
45dd1fec | 37 | return subnet; |
4f7b304f SK |
38 | } |
39 | #ifdef HAVE_IPV6 | |
376d48c7 | 40 | else if (is_same_net6(&(addr_u->addr.addr6), &subnet->addr.addr.addr6, subnet->prefixlen)) |
45dd1fec | 41 | return subnet; |
4f7b304f SK |
42 | #endif |
43 | ||
44 | } | |
45dd1fec | 45 | return NULL; |
4f7b304f SK |
46 | } |
47 | ||
c50f25a3 SK |
48 | static int filter_zone(struct auth_zone *zone, int flag, struct all_addr *addr_u) |
49 | { | |
50 | /* No zones specified, no filter */ | |
51 | if (!zone->subnet) | |
52 | return 1; | |
53 | ||
54 | return find_subnet(zone, flag, addr_u) != NULL; | |
55 | } | |
56 | ||
b485ed97 | 57 | int in_zone(struct auth_zone *zone, char *name, char **cut) |
b75e9363 SK |
58 | { |
59 | size_t namelen = strlen(name); | |
60 | size_t domainlen = strlen(zone->domain); | |
61 | ||
62 | if (cut) | |
63 | *cut = NULL; | |
64 | ||
65 | if (namelen >= domainlen && | |
66 | hostname_isequal(zone->domain, &name[namelen - domainlen])) | |
67 | { | |
68 | ||
69 | if (namelen == domainlen) | |
70 | return 1; | |
71 | ||
72 | if (name[namelen - domainlen - 1] == '.') | |
73 | { | |
74 | if (cut) | |
75 | *cut = &name[namelen - domainlen - 1]; | |
76 | return 1; | |
77 | } | |
78 | } | |
79 | ||
80 | return 0; | |
81 | } | |
4f7b304f SK |
82 | |
83 | ||
19b16891 | 84 | size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr, int local_query) |
4f7b304f SK |
85 | { |
86 | char *name = daemon->namebuff; | |
87 | unsigned char *p, *ansp; | |
88 | int qtype, qclass; | |
b75e9363 | 89 | int nameoffset, axfroffset = 0; |
4f7b304f SK |
90 | int q, anscount = 0, authcount = 0; |
91 | struct crec *crecp; | |
19b16891 | 92 | int auth = !local_query, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0; |
4f7b304f | 93 | struct auth_zone *zone = NULL; |
376d48c7 | 94 | struct addrlist *subnet = NULL; |
b75e9363 | 95 | char *cut; |
e1ff419c SK |
96 | struct mx_srv_record *rec, *move, **up; |
97 | struct txt_record *txt; | |
98 | struct interface_name *intr; | |
99 | struct naptr *na; | |
100 | struct all_addr addr; | |
101 | struct cname *a; | |
102 | ||
4f7b304f SK |
103 | if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY ) |
104 | return 0; | |
6008bdbb | 105 | |
4f7b304f SK |
106 | /* determine end of question section (we put answers there) */ |
107 | if (!(ansp = skip_questions(header, qlen))) | |
108 | return 0; /* bad packet */ | |
109 | ||
110 | /* now process each question, answers go in RRs after the question */ | |
111 | p = (unsigned char *)(header+1); | |
112 | ||
113 | for (q = ntohs(header->qdcount); q != 0; q--) | |
114 | { | |
8273ea5a | 115 | unsigned short flag = 0; |
4f7b304f | 116 | int found = 0; |
e1ff419c | 117 | |
4f7b304f SK |
118 | /* save pointer to name for copying into answers */ |
119 | nameoffset = p - (unsigned char *)header; | |
120 | ||
121 | /* now extract name as .-concatenated string into name */ | |
122 | if (!extract_name(header, qlen, &p, name, 1, 4)) | |
123 | return 0; /* bad packet */ | |
124 | ||
125 | GETSHORT(qtype, p); | |
126 | GETSHORT(qclass, p); | |
127 | ||
128 | if (qclass != C_IN) | |
f8abe0c5 SK |
129 | { |
130 | auth = 0; | |
131 | continue; | |
132 | } | |
b75e9363 | 133 | |
4f7b304f SK |
134 | if (qtype == T_PTR) |
135 | { | |
4f7b304f SK |
136 | if (!(flag = in_arpa_name_2_addr(name, &addr))) |
137 | continue; | |
138 | ||
19b16891 | 139 | if (!local_query) |
4f7b304f | 140 | { |
19b16891 | 141 | for (zone = daemon->auth_zones; zone; zone = zone->next) |
c50f25a3 | 142 | if ((subnet = find_subnet(zone, flag, &addr))) |
19b16891 | 143 | break; |
38440b20 | 144 | |
19b16891 SK |
145 | if (!zone) |
146 | { | |
147 | auth = 0; | |
148 | continue; | |
149 | } | |
4f7b304f | 150 | } |
19b16891 | 151 | |
115ac3e4 SK |
152 | intr = NULL; |
153 | ||
86e3b9a0 | 154 | if (flag == F_IPV4) |
115ac3e4 SK |
155 | for (intr = daemon->int_names; intr; intr = intr->next) |
156 | { | |
157 | struct addrlist *addrlist; | |
158 | ||
376d48c7 SK |
159 | for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) |
160 | if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr.addr4.s_addr == addrlist->addr.addr.addr4.s_addr) | |
86e3b9a0 | 161 | break; |
115ac3e4 SK |
162 | |
163 | if (addrlist) | |
164 | break; | |
165 | else | |
166 | while (intr->next && strcmp(intr->intr, intr->next->intr) == 0) | |
167 | intr = intr->next; | |
168 | } | |
169 | #ifdef HAVE_IPV6 | |
170 | else if (flag == F_IPV6) | |
171 | for (intr = daemon->int_names; intr; intr = intr->next) | |
172 | { | |
173 | struct addrlist *addrlist; | |
174 | ||
376d48c7 SK |
175 | for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) |
176 | if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr.addr6, &addrlist->addr.addr.addr6)) | |
115ac3e4 SK |
177 | break; |
178 | ||
179 | if (addrlist) | |
180 | break; | |
181 | else | |
182 | while (intr->next && strcmp(intr->intr, intr->next->intr) == 0) | |
183 | intr = intr->next; | |
184 | } | |
185 | #endif | |
186 | ||
187 | if (intr) | |
188 | { | |
38440b20 | 189 | if (local_query || in_zone(zone, intr->name, NULL)) |
115ac3e4 SK |
190 | { |
191 | found = 1; | |
8ab91e9f | 192 | log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL); |
115ac3e4 SK |
193 | if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, |
194 | daemon->auth_ttl, NULL, | |
195 | T_PTR, C_IN, "d", intr->name)) | |
196 | anscount++; | |
86e3b9a0 SK |
197 | } |
198 | } | |
115ac3e4 | 199 | |
4f7b304f SK |
200 | if ((crecp = cache_find_by_addr(NULL, &addr, now, flag))) |
201 | do { | |
202 | strcpy(name, cache_get_name(crecp)); | |
203 | ||
204 | if (crecp->flags & F_DHCP && !option_bool(OPT_DHCP_FQDN)) | |
205 | { | |
206 | char *p = strchr(name, '.'); | |
207 | if (p) | |
208 | *p = 0; /* must be bare name */ | |
209 | ||
210 | /* add external domain */ | |
38440b20 SK |
211 | if (zone) |
212 | { | |
213 | strcat(name, "."); | |
214 | strcat(name, zone->domain); | |
215 | } | |
4f7b304f | 216 | log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid)); |
8273ea5a | 217 | found = 1; |
4f7b304f SK |
218 | if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, |
219 | daemon->auth_ttl, NULL, | |
220 | T_PTR, C_IN, "d", name)) | |
8273ea5a | 221 | anscount++; |
4f7b304f | 222 | } |
38440b20 | 223 | else if (crecp->flags & (F_DHCP | F_HOSTS) && (local_query || in_zone(zone, name, NULL))) |
4f7b304f | 224 | { |
4f7b304f | 225 | log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid)); |
8273ea5a | 226 | found = 1; |
4f7b304f SK |
227 | if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, |
228 | daemon->auth_ttl, NULL, | |
229 | T_PTR, C_IN, "d", name)) | |
8273ea5a | 230 | anscount++; |
4f7b304f SK |
231 | } |
232 | else | |
233 | continue; | |
234 | ||
235 | } while ((crecp = cache_find_by_addr(crecp, &addr, now, flag))); | |
86e3b9a0 | 236 | |
10068600 SK |
237 | if (found) |
238 | nxdomain = 0; | |
239 | else | |
240 | log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL); | |
4f7b304f SK |
241 | |
242 | continue; | |
243 | } | |
244 | ||
5c0bd5b1 | 245 | cname_restart: |
4f7b304f | 246 | for (zone = daemon->auth_zones; zone; zone = zone->next) |
b75e9363 SK |
247 | if (in_zone(zone, name, &cut)) |
248 | break; | |
86e3b9a0 SK |
249 | |
250 | if (!zone) | |
4f7b304f SK |
251 | { |
252 | auth = 0; | |
253 | continue; | |
254 | } | |
255 | ||
8273ea5a SK |
256 | for (rec = daemon->mxnames; rec; rec = rec->next) |
257 | if (!rec->issrv && hostname_isequal(name, rec->name)) | |
86e3b9a0 SK |
258 | { |
259 | nxdomain = 0; | |
260 | ||
261 | if (qtype == T_MX) | |
262 | { | |
263 | found = 1; | |
264 | log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>"); | |
265 | if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, | |
266 | NULL, T_MX, C_IN, "sd", rec->weight, rec->target)) | |
267 | anscount++; | |
268 | } | |
269 | } | |
270 | ||
271 | for (move = NULL, up = &daemon->mxnames, rec = daemon->mxnames; rec; rec = rec->next) | |
272 | if (rec->issrv && hostname_isequal(name, rec->name)) | |
273 | { | |
274 | nxdomain = 0; | |
275 | ||
276 | if (qtype == T_SRV) | |
277 | { | |
278 | found = 1; | |
279 | log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>"); | |
280 | if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, | |
281 | NULL, T_SRV, C_IN, "sssd", | |
282 | rec->priority, rec->weight, rec->srvport, rec->target)) | |
4f7b304f | 283 | |
86e3b9a0 SK |
284 | anscount++; |
285 | } | |
286 | ||
287 | /* unlink first SRV record found */ | |
288 | if (!move) | |
289 | { | |
290 | move = rec; | |
291 | *up = rec->next; | |
292 | } | |
293 | else | |
294 | up = &rec->next; | |
295 | } | |
296 | else | |
297 | up = &rec->next; | |
298 | ||
299 | /* put first SRV record back at the end. */ | |
300 | if (move) | |
4f7b304f | 301 | { |
86e3b9a0 SK |
302 | *up = move; |
303 | move->next = NULL; | |
8273ea5a | 304 | } |
86e3b9a0 SK |
305 | |
306 | for (txt = daemon->rr; txt; txt = txt->next) | |
307 | if (hostname_isequal(name, txt->name)) | |
308 | { | |
309 | nxdomain = 0; | |
310 | if (txt->class == qtype) | |
311 | { | |
312 | found = 1; | |
313 | log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>"); | |
314 | if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, | |
315 | NULL, txt->class, C_IN, "t", txt->len, txt->txt)) | |
316 | anscount++; | |
317 | } | |
318 | } | |
8273ea5a | 319 | |
86e3b9a0 SK |
320 | for (txt = daemon->txt; txt; txt = txt->next) |
321 | if (txt->class == C_IN && hostname_isequal(name, txt->name)) | |
322 | { | |
323 | nxdomain = 0; | |
324 | if (qtype == T_TXT) | |
325 | { | |
326 | found = 1; | |
327 | log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>"); | |
328 | if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, | |
329 | NULL, T_TXT, C_IN, "t", txt->len, txt->txt)) | |
330 | anscount++; | |
331 | } | |
332 | } | |
333 | ||
334 | for (na = daemon->naptr; na; na = na->next) | |
335 | if (hostname_isequal(name, na->name)) | |
336 | { | |
337 | nxdomain = 0; | |
338 | if (qtype == T_NAPTR) | |
339 | { | |
340 | found = 1; | |
341 | log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>"); | |
342 | if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, | |
343 | NULL, T_NAPTR, C_IN, "sszzzd", | |
344 | na->order, na->pref, na->flags, na->services, na->regexp, na->replace)) | |
345 | anscount++; | |
346 | } | |
347 | } | |
115ac3e4 SK |
348 | |
349 | if (qtype == T_A) | |
350 | flag = F_IPV4; | |
351 | ||
352 | #ifdef HAVE_IPV6 | |
353 | if (qtype == T_AAAA) | |
354 | flag = F_IPV6; | |
355 | #endif | |
356 | ||
8ab91e9f SK |
357 | for (intr = daemon->int_names; intr; intr = intr->next) |
358 | if (hostname_isequal(name, intr->name)) | |
359 | { | |
360 | struct addrlist *addrlist; | |
361 | ||
8ab91e9f SK |
362 | nxdomain = 0; |
363 | ||
364 | if (flag) | |
376d48c7 SK |
365 | for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) |
366 | if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == qtype && | |
367 | (local_query || filter_zone(zone, flag, &addrlist->addr))) | |
fb63dd13 | 368 | { |
47669367 SK |
369 | #ifdef HAVE_IPV6 |
370 | if (addrlist->flags & ADDRLIST_REVONLY) | |
371 | continue; | |
372 | #endif | |
fb63dd13 SK |
373 | found = 1; |
374 | log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL); | |
375 | if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, | |
376 | daemon->auth_ttl, NULL, qtype, C_IN, | |
377 | qtype == T_A ? "4" : "6", &addrlist->addr)) | |
378 | anscount++; | |
379 | } | |
380 | } | |
5c0bd5b1 SK |
381 | |
382 | for (a = daemon->cnames; a; a = a->next) | |
383 | if (hostname_isequal(name, a->alias) ) | |
384 | { | |
385 | log_query(F_CONFIG | F_CNAME, name, NULL, NULL); | |
386 | strcpy(name, a->target); | |
387 | if (!strchr(name, '.')) | |
388 | { | |
389 | strcat(name, "."); | |
390 | strcat(name, zone->domain); | |
391 | } | |
392 | found = 1; | |
393 | if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, | |
93bafe61 | 394 | daemon->auth_ttl, &nameoffset, |
5c0bd5b1 SK |
395 | T_CNAME, C_IN, "d", name)) |
396 | anscount++; | |
397 | ||
398 | goto cname_restart; | |
399 | } | |
86e3b9a0 | 400 | |
e1ff419c | 401 | if (!cut) |
8273ea5a | 402 | { |
e1ff419c SK |
403 | nxdomain = 0; |
404 | ||
405 | if (qtype == T_SOA) | |
406 | { | |
5f8002fc | 407 | auth = soa = 1; /* inhibits auth section */ |
e1ff419c SK |
408 | found = 1; |
409 | log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>"); | |
410 | } | |
411 | else if (qtype == T_AXFR) | |
412 | { | |
c6cb7407 SK |
413 | struct iname *peers; |
414 | ||
415 | if (peer_addr->sa.sa_family == AF_INET) | |
416 | peer_addr->in.sin_port = 0; | |
417 | #ifdef HAVE_IPV6 | |
418 | else | |
39341559 SK |
419 | { |
420 | peer_addr->in6.sin6_port = 0; | |
421 | peer_addr->in6.sin6_scope_id = 0; | |
422 | } | |
c6cb7407 SK |
423 | #endif |
424 | ||
425 | for (peers = daemon->auth_peers; peers; peers = peers->next) | |
426 | if (sockaddr_isequal(peer_addr, &peers->addr)) | |
427 | break; | |
428 | ||
429 | /* Refuse all AXFR unless --auth-sec-servers is set */ | |
430 | if ((!peers && daemon->auth_peers) || !daemon->secondary_forward_server) | |
49678767 | 431 | { |
49678767 | 432 | if (peer_addr->sa.sa_family == AF_INET) |
c6cb7407 | 433 | inet_ntop(AF_INET, &peer_addr->in.sin_addr, daemon->addrbuff, ADDRSTRLEN); |
49678767 SK |
434 | #ifdef HAVE_IPV6 |
435 | else | |
c6cb7407 | 436 | inet_ntop(AF_INET6, &peer_addr->in6.sin6_addr, daemon->addrbuff, ADDRSTRLEN); |
49678767 SK |
437 | #endif |
438 | ||
c6cb7407 SK |
439 | my_syslog(LOG_WARNING, _("ignoring zone transfer request from %s"), daemon->addrbuff); |
440 | return 0; | |
49678767 | 441 | } |
c6cb7407 | 442 | |
5f8002fc | 443 | auth = 1; |
e1ff419c SK |
444 | soa = 1; /* inhibits auth section */ |
445 | ns = 1; /* ensure we include NS records! */ | |
446 | axfr = 1; | |
447 | found = 1; | |
448 | axfroffset = nameoffset; | |
449 | log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>"); | |
450 | } | |
451 | else if (qtype == T_NS) | |
452 | { | |
5f8002fc | 453 | auth = 1; |
e1ff419c SK |
454 | ns = 1; /* inhibits auth section */ |
455 | found = 1; | |
456 | log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>"); | |
457 | } | |
4f7b304f | 458 | } |
8273ea5a | 459 | |
b75e9363 | 460 | if (!option_bool(OPT_DHCP_FQDN) && cut) |
4f7b304f | 461 | { |
b75e9363 | 462 | *cut = 0; /* remove domain part */ |
4f7b304f | 463 | |
5c0bd5b1 | 464 | if (!strchr(name, '.') && (crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6))) |
4f7b304f SK |
465 | { |
466 | if (crecp->flags & F_DHCP) | |
467 | do | |
468 | { | |
469 | nxdomain = 0; | |
60225f4e | 470 | if ((crecp->flags & flag) && |
376d48c7 | 471 | (local_query || filter_zone(zone, flag, &(crecp->addr.addr)))) |
4f7b304f | 472 | { |
b75e9363 | 473 | *cut = '.'; /* restore domain part */ |
4f7b304f | 474 | log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid)); |
b75e9363 | 475 | *cut = 0; /* remove domain part */ |
8273ea5a | 476 | found = 1; |
4f7b304f SK |
477 | if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, |
478 | daemon->auth_ttl, NULL, qtype, C_IN, | |
479 | qtype == T_A ? "4" : "6", &crecp->addr)) | |
8273ea5a | 480 | anscount++; |
4f7b304f SK |
481 | } |
482 | } while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6))); | |
483 | } | |
484 | ||
b75e9363 | 485 | *cut = '.'; /* restore domain part */ |
4f7b304f SK |
486 | } |
487 | ||
86e3b9a0 | 488 | if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6))) |
4f7b304f SK |
489 | { |
490 | if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN)))) | |
491 | do | |
492 | { | |
493 | nxdomain = 0; | |
376d48c7 | 494 | if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr.addr)))) |
4f7b304f SK |
495 | { |
496 | log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid)); | |
8273ea5a | 497 | found = 1; |
4f7b304f SK |
498 | if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, |
499 | daemon->auth_ttl, NULL, qtype, C_IN, | |
500 | qtype == T_A ? "4" : "6", &crecp->addr)) | |
8273ea5a | 501 | anscount++; |
4f7b304f SK |
502 | } |
503 | } while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6))); | |
504 | } | |
8273ea5a | 505 | |
4f7b304f SK |
506 | if (!found) |
507 | log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL); | |
8273ea5a | 508 | |
4f7b304f | 509 | } |
45dd1fec | 510 | |
4f7b304f | 511 | /* Add auth section */ |
aa67fe7a | 512 | if (auth && zone) |
4f7b304f | 513 | { |
b75e9363 | 514 | char *authname; |
e1ff419c SK |
515 | int newoffset, offset = 0; |
516 | ||
45dd1fec | 517 | if (!subnet) |
b75e9363 | 518 | authname = zone->domain; |
45dd1fec SK |
519 | else |
520 | { | |
521 | /* handle NS and SOA for PTR records */ | |
b75e9363 SK |
522 | |
523 | authname = name; | |
524 | ||
376d48c7 | 525 | if (!(subnet->flags & ADDRLIST_IPV6)) |
45dd1fec | 526 | { |
376d48c7 | 527 | in_addr_t a = ntohl(subnet->addr.addr.addr4.s_addr) >> 8; |
45dd1fec SK |
528 | char *p = name; |
529 | ||
baa80ae5 | 530 | if (subnet->prefixlen >= 24) |
45dd1fec SK |
531 | p += sprintf(p, "%d.", a & 0xff); |
532 | a = a >> 8; | |
baa80ae5 | 533 | if (subnet->prefixlen >= 16 ) |
45dd1fec SK |
534 | p += sprintf(p, "%d.", a & 0xff); |
535 | a = a >> 8; | |
536 | p += sprintf(p, "%d.in-addr.arpa", a & 0xff); | |
537 | ||
538 | } | |
539 | #ifdef HAVE_IPV6 | |
540 | else | |
541 | { | |
542 | char *p = name; | |
543 | int i; | |
544 | ||
545 | for (i = subnet->prefixlen-1; i >= 0; i -= 4) | |
546 | { | |
376d48c7 | 547 | int dig = ((unsigned char *)&subnet->addr.addr.addr6)[i>>3]; |
45dd1fec SK |
548 | p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4); |
549 | } | |
550 | p += sprintf(p, "ip6.arpa"); | |
551 | ||
552 | } | |
553 | #endif | |
554 | } | |
555 | ||
556 | /* handle NS and SOA in auth section or for explicit queries */ | |
e1ff419c SK |
557 | newoffset = ansp - (unsigned char *)header; |
558 | if (((anscount == 0 && !ns) || soa) && | |
45dd1fec SK |
559 | add_resource_record(header, limit, &trunc, 0, &ansp, |
560 | daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll", | |
b75e9363 | 561 | authname, daemon->authserver, daemon->hostmaster, |
45dd1fec SK |
562 | daemon->soa_sn, daemon->soa_refresh, |
563 | daemon->soa_retry, daemon->soa_expiry, | |
564 | daemon->auth_ttl)) | |
565 | { | |
e1ff419c | 566 | offset = newoffset; |
45dd1fec SK |
567 | if (soa) |
568 | anscount++; | |
569 | else | |
570 | authcount++; | |
571 | } | |
e1ff419c SK |
572 | |
573 | if (anscount != 0 || ns) | |
574 | { | |
575 | struct name_list *secondary; | |
576 | ||
577 | newoffset = ansp - (unsigned char *)header; | |
578 | if (add_resource_record(header, limit, &trunc, -offset, &ansp, | |
579 | daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, daemon->authserver)) | |
580 | { | |
581 | if (offset == 0) | |
582 | offset = newoffset; | |
583 | if (ns) | |
584 | anscount++; | |
585 | else | |
586 | authcount++; | |
587 | } | |
b75e9363 | 588 | |
e1ff419c SK |
589 | if (!subnet) |
590 | for (secondary = daemon->secondary_forward_server; secondary; secondary = secondary->next) | |
591 | if (add_resource_record(header, limit, &trunc, offset, &ansp, | |
592 | daemon->auth_ttl, NULL, T_NS, C_IN, "d", secondary->name)) | |
593 | { | |
594 | if (ns) | |
595 | anscount++; | |
596 | else | |
597 | authcount++; | |
598 | } | |
599 | } | |
600 | ||
b75e9363 SK |
601 | if (axfr) |
602 | { | |
e1ff419c SK |
603 | for (rec = daemon->mxnames; rec; rec = rec->next) |
604 | if (in_zone(zone, rec->name, &cut)) | |
605 | { | |
606 | if (cut) | |
607 | *cut = 0; | |
608 | ||
609 | if (rec->issrv) | |
610 | { | |
611 | if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl, | |
612 | NULL, T_SRV, C_IN, "sssd", cut ? rec->name : NULL, | |
613 | rec->priority, rec->weight, rec->srvport, rec->target)) | |
614 | ||
615 | anscount++; | |
616 | } | |
617 | else | |
618 | { | |
619 | if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl, | |
620 | NULL, T_MX, C_IN, "sd", cut ? rec->name : NULL, rec->weight, rec->target)) | |
621 | anscount++; | |
622 | } | |
623 | ||
624 | /* restore config data */ | |
625 | if (cut) | |
626 | *cut = '.'; | |
627 | } | |
628 | ||
629 | for (txt = daemon->rr; txt; txt = txt->next) | |
630 | if (in_zone(zone, txt->name, &cut)) | |
631 | { | |
632 | if (cut) | |
633 | *cut = 0; | |
634 | ||
635 | if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl, | |
636 | NULL, txt->class, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt)) | |
637 | anscount++; | |
638 | ||
639 | /* restore config data */ | |
640 | if (cut) | |
641 | *cut = '.'; | |
642 | } | |
643 | ||
644 | for (txt = daemon->txt; txt; txt = txt->next) | |
645 | if (txt->class == C_IN && in_zone(zone, txt->name, &cut)) | |
646 | { | |
647 | if (cut) | |
648 | *cut = 0; | |
649 | ||
650 | if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl, | |
651 | NULL, T_TXT, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt)) | |
652 | anscount++; | |
653 | ||
654 | /* restore config data */ | |
655 | if (cut) | |
656 | *cut = '.'; | |
657 | } | |
658 | ||
659 | for (na = daemon->naptr; na; na = na->next) | |
660 | if (in_zone(zone, na->name, &cut)) | |
661 | { | |
662 | if (cut) | |
663 | *cut = 0; | |
664 | ||
665 | if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl, | |
666 | NULL, T_NAPTR, C_IN, "sszzzd", cut ? na->name : NULL, | |
667 | na->order, na->pref, na->flags, na->services, na->regexp, na->replace)) | |
668 | anscount++; | |
669 | ||
670 | /* restore config data */ | |
671 | if (cut) | |
672 | *cut = '.'; | |
673 | } | |
674 | ||
675 | for (intr = daemon->int_names; intr; intr = intr->next) | |
115ac3e4 | 676 | if (in_zone(zone, intr->name, &cut)) |
e1ff419c | 677 | { |
115ac3e4 SK |
678 | struct addrlist *addrlist; |
679 | ||
e1ff419c SK |
680 | if (cut) |
681 | *cut = 0; | |
682 | ||
376d48c7 | 683 | for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) |
587ad4f2 SK |
684 | if (!(addrlist->flags & ADDRLIST_IPV6) && |
685 | (local_query || filter_zone(zone, F_IPV4, &addrlist->addr)) && | |
115ac3e4 SK |
686 | add_resource_record(header, limit, &trunc, -axfroffset, &ansp, |
687 | daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addrlist->addr)) | |
688 | anscount++; | |
689 | ||
690 | #ifdef HAVE_IPV6 | |
376d48c7 | 691 | for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) |
587ad4f2 SK |
692 | if ((addrlist->flags & ADDRLIST_IPV6) && |
693 | (local_query || filter_zone(zone, F_IPV6, &addrlist->addr)) && | |
115ac3e4 SK |
694 | add_resource_record(header, limit, &trunc, -axfroffset, &ansp, |
695 | daemon->auth_ttl, NULL, T_AAAA, C_IN, "6", cut ? intr->name : NULL, &addrlist->addr)) | |
696 | anscount++; | |
697 | #endif | |
e1ff419c SK |
698 | |
699 | /* restore config data */ | |
700 | if (cut) | |
701 | *cut = '.'; | |
702 | } | |
115ac3e4 | 703 | |
e1ff419c SK |
704 | for (a = daemon->cnames; a; a = a->next) |
705 | if (in_zone(zone, a->alias, &cut)) | |
706 | { | |
707 | strcpy(name, a->target); | |
708 | if (!strchr(name, '.')) | |
709 | { | |
710 | strcat(name, "."); | |
711 | strcat(name, zone->domain); | |
712 | } | |
713 | ||
714 | if (cut) | |
715 | *cut = 0; | |
716 | ||
717 | if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, | |
718 | daemon->auth_ttl, NULL, | |
719 | T_CNAME, C_IN, "d", cut ? a->alias : NULL, name)) | |
720 | anscount++; | |
721 | } | |
722 | ||
b75e9363 SK |
723 | cache_enumerate(1); |
724 | while ((crecp = cache_enumerate(0))) | |
725 | { | |
726 | if ((crecp->flags & (F_IPV4 | F_IPV6)) && | |
727 | !(crecp->flags & (F_NEG | F_NXDOMAIN)) && | |
728 | (crecp->flags & F_FORWARD)) | |
729 | { | |
730 | if ((crecp->flags & F_DHCP) && !option_bool(OPT_DHCP_FQDN)) | |
731 | { | |
732 | char *cache_name = cache_get_name(crecp); | |
19b16891 | 733 | if (!strchr(cache_name, '.') && |
376d48c7 | 734 | (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr)))) |
b75e9363 SK |
735 | { |
736 | qtype = T_A; | |
737 | #ifdef HAVE_IPV6 | |
738 | if (crecp->flags & F_IPV6) | |
739 | qtype = T_AAAA; | |
740 | #endif | |
741 | if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, | |
742 | daemon->auth_ttl, NULL, qtype, C_IN, | |
743 | (crecp->flags & F_IPV4) ? "4" : "6", cache_name, &crecp->addr)) | |
744 | anscount++; | |
745 | } | |
746 | } | |
747 | ||
748 | if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN)))) | |
749 | { | |
750 | strcpy(name, cache_get_name(crecp)); | |
19b16891 | 751 | if (in_zone(zone, name, &cut) && |
376d48c7 | 752 | (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr)))) |
b75e9363 SK |
753 | { |
754 | qtype = T_A; | |
755 | #ifdef HAVE_IPV6 | |
756 | if (crecp->flags & F_IPV6) | |
757 | qtype = T_AAAA; | |
758 | #endif | |
759 | if (cut) | |
e1ff419c SK |
760 | *cut = 0; |
761 | ||
762 | if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, | |
763 | daemon->auth_ttl, NULL, qtype, C_IN, | |
764 | (crecp->flags & F_IPV4) ? "4" : "6", cut ? name : NULL, &crecp->addr)) | |
765 | anscount++; | |
b75e9363 SK |
766 | } |
767 | } | |
768 | } | |
769 | } | |
770 | ||
771 | /* repeat SOA as last record */ | |
772 | if (add_resource_record(header, limit, &trunc, axfroffset, &ansp, | |
773 | daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll", | |
774 | daemon->authserver, daemon->hostmaster, | |
775 | daemon->soa_sn, daemon->soa_refresh, | |
776 | daemon->soa_retry, daemon->soa_expiry, | |
777 | daemon->auth_ttl)) | |
778 | anscount++; | |
4c985dac | 779 | |
b75e9363 | 780 | } |
4c985dac SK |
781 | |
782 | } | |
45dd1fec | 783 | |
4f7b304f SK |
784 | /* done all questions, set up header and return length of result */ |
785 | /* clear authoritative and truncated flags, set QR flag */ | |
786 | header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR; | |
93bafe61 SK |
787 | |
788 | if (local_query) | |
789 | { | |
790 | /* set RA flag */ | |
791 | header->hb4 |= HB4_RA; | |
792 | } | |
793 | else | |
794 | { | |
795 | /* clear RA flag */ | |
796 | header->hb4 &= ~HB4_RA; | |
797 | } | |
4f7b304f SK |
798 | |
799 | /* authoritive */ | |
800 | if (auth) | |
801 | header->hb3 |= HB3_AA; | |
802 | ||
803 | /* truncation */ | |
804 | if (trunc) | |
805 | header->hb3 |= HB3_TC; | |
806 | ||
57310500 | 807 | if ((auth || local_query) && nxdomain) |
4f7b304f SK |
808 | SET_RCODE(header, NXDOMAIN); |
809 | else | |
810 | SET_RCODE(header, NOERROR); /* no error */ | |
811 | header->ancount = htons(anscount); | |
812 | header->nscount = htons(authcount); | |
aa792351 | 813 | header->arcount = htons(0); |
4f7b304f SK |
814 | return ansp - (unsigned char *)header; |
815 | } | |
816 | ||
4820dce9 | 817 | #endif |
b75e9363 | 818 | |
4f7b304f SK |
819 | |
820 |