blob: e6adc37978211079f82109da40b5d158ef3bbdbe [file] [log] [blame]
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001/* dnsmasq is Copyright (c) 2000-2024 Simon Kelley
Simon Kelley4f7b3042012-11-28 21:27:02 +00002
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
Simon Kelley4820dce2012-12-18 18:30:30 +000019#ifdef HAVE_AUTH
Simon Kelleyb75e9362012-12-07 11:50:41 +000020
Simon Kelleycc921df2019-01-02 22:48:59 +000021static struct addrlist *find_addrlist(struct addrlist *list, int flag, union all_addr *addr_u)
Mathias Kresin094bfae2016-07-24 14:15:22 +010022{
23 do {
24 if (!(list->flags & ADDRLIST_IPV6))
25 {
Simon Kelleycc921df2019-01-02 22:48:59 +000026 struct in_addr netmask, addr = addr_u->addr4;
Mathias Kresin094bfae2016-07-24 14:15:22 +010027
28 if (!(flag & F_IPV4))
29 continue;
30
31 netmask.s_addr = htonl(~(in_addr_t)0 << (32 - list->prefixlen));
32
Simon Kelleycc921df2019-01-02 22:48:59 +000033 if (is_same_net(addr, list->addr.addr4, netmask))
Mathias Kresin094bfae2016-07-24 14:15:22 +010034 return list;
35 }
Simon Kelleycc921df2019-01-02 22:48:59 +000036 else if (is_same_net6(&(addr_u->addr6), &list->addr.addr6, list->prefixlen))
Mathias Kresin094bfae2016-07-24 14:15:22 +010037 return list;
Mathias Kresin094bfae2016-07-24 14:15:22 +010038
39 } while ((list = list->next));
40
41 return NULL;
42}
43
Simon Kelleycc921df2019-01-02 22:48:59 +000044static struct addrlist *find_subnet(struct auth_zone *zone, int flag, union all_addr *addr_u)
Simon Kelley4f7b3042012-11-28 21:27:02 +000045{
Mathias Kresin094bfae2016-07-24 14:15:22 +010046 if (!zone->subnet)
47 return NULL;
48
49 return find_addrlist(zone->subnet, flag, addr_u);
50}
Simon Kelley4f7b3042012-11-28 21:27:02 +000051
Simon Kelleycc921df2019-01-02 22:48:59 +000052static struct addrlist *find_exclude(struct auth_zone *zone, int flag, union all_addr *addr_u)
Mathias Kresin094bfae2016-07-24 14:15:22 +010053{
54 if (!zone->exclude)
55 return NULL;
56
57 return find_addrlist(zone->exclude, flag, addr_u);
Simon Kelley4f7b3042012-11-28 21:27:02 +000058}
59
Simon Kelleycc921df2019-01-02 22:48:59 +000060static int filter_zone(struct auth_zone *zone, int flag, union all_addr *addr_u)
Simon Kelleyc50f25a2013-11-21 11:29:27 +000061{
Mathias Kresin094bfae2016-07-24 14:15:22 +010062 if (find_exclude(zone, flag, addr_u))
63 return 0;
64
65 /* No subnets specified, no filter */
Simon Kelleyc50f25a2013-11-21 11:29:27 +000066 if (!zone->subnet)
67 return 1;
68
69 return find_subnet(zone, flag, addr_u) != NULL;
70}
71
Simon Kelleyb485ed92013-10-18 22:00:39 +010072int in_zone(struct auth_zone *zone, char *name, char **cut)
Simon Kelleyb75e9362012-12-07 11:50:41 +000073{
74 size_t namelen = strlen(name);
75 size_t domainlen = strlen(zone->domain);
76
77 if (cut)
78 *cut = NULL;
79
80 if (namelen >= domainlen &&
81 hostname_isequal(zone->domain, &name[namelen - domainlen]))
82 {
83
84 if (namelen == domainlen)
85 return 1;
86
87 if (name[namelen - domainlen - 1] == '.')
88 {
89 if (cut)
90 *cut = &name[namelen - domainlen - 1];
91 return 1;
92 }
93 }
94
95 return 0;
96}
Simon Kelley4f7b3042012-11-28 21:27:02 +000097
98
Simon Kelleyfa14bec2015-12-20 17:12:16 +000099size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr,
100 int local_query, int do_bit, int have_pseudoheader)
Simon Kelley4f7b3042012-11-28 21:27:02 +0000101{
102 char *name = daemon->namebuff;
103 unsigned char *p, *ansp;
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100104 int qtype, qclass, rc;
Simon Kelleyb75e9362012-12-07 11:50:41 +0000105 int nameoffset, axfroffset = 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +0000106 int q, anscount = 0, authcount = 0;
107 struct crec *crecp;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700108 int auth = !local_query, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0, out_of_zone = 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +0000109 struct auth_zone *zone = NULL;
Simon Kelley376d48c2013-11-13 13:04:30 +0000110 struct addrlist *subnet = NULL;
Simon Kelleyb75e9362012-12-07 11:50:41 +0000111 char *cut;
Simon Kelleye1ff4192012-12-09 17:08:47 +0000112 struct mx_srv_record *rec, *move, **up;
113 struct txt_record *txt;
114 struct interface_name *intr;
115 struct naptr *na;
Simon Kelleycc921df2019-01-02 22:48:59 +0000116 union all_addr addr;
Simon Kelleyb637d782016-12-13 16:44:11 +0000117 struct cname *a, *candidate;
118 unsigned int wclen;
Simon Kelleye1ff4192012-12-09 17:08:47 +0000119
Simon Kelley4f7b3042012-11-28 21:27:02 +0000120 if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
121 return 0;
Simon Kelley6008bdb2013-10-21 21:47:03 +0100122
Simon Kelley4f7b3042012-11-28 21:27:02 +0000123 /* determine end of question section (we put answers there) */
124 if (!(ansp = skip_questions(header, qlen)))
125 return 0; /* bad packet */
126
127 /* now process each question, answers go in RRs after the question */
128 p = (unsigned char *)(header+1);
129
130 for (q = ntohs(header->qdcount); q != 0; q--)
131 {
Simon Kelley5b99eae2019-01-06 23:09:50 +0000132 unsigned int flag = 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +0000133 int found = 0;
Simon Kelleyb637d782016-12-13 16:44:11 +0000134 int cname_wildcard = 0;
Simon Kelleye1ff4192012-12-09 17:08:47 +0000135
Simon Kelley4f7b3042012-11-28 21:27:02 +0000136 /* save pointer to name for copying into answers */
137 nameoffset = p - (unsigned char *)header;
138
139 /* now extract name as .-concatenated string into name */
140 if (!extract_name(header, qlen, &p, name, 1, 4))
141 return 0; /* bad packet */
142
143 GETSHORT(qtype, p);
144 GETSHORT(qclass, p);
145
146 if (qclass != C_IN)
Simon Kelleyf8abe0c2012-12-15 11:59:25 +0000147 {
148 auth = 0;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700149 out_of_zone = 1;
Simon Kelleyf8abe0c2012-12-15 11:59:25 +0000150 continue;
151 }
Simon Kelleyb75e9362012-12-07 11:50:41 +0000152
Simon Kelley78c61842015-04-16 15:05:30 +0100153 if ((qtype == T_PTR || qtype == T_SOA || qtype == T_NS) &&
154 (flag = in_arpa_name_2_addr(name, &addr)) &&
155 !local_query)
Simon Kelley4f7b3042012-11-28 21:27:02 +0000156 {
Simon Kelley78c61842015-04-16 15:05:30 +0100157 for (zone = daemon->auth_zones; zone; zone = zone->next)
158 if ((subnet = find_subnet(zone, flag, &addr)))
159 break;
160
161 if (!zone)
Simon Kelley4f7b3042012-11-28 21:27:02 +0000162 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700163 out_of_zone = 1;
Simon Kelley78c61842015-04-16 15:05:30 +0100164 auth = 0;
165 continue;
Simon Kelley4f7b3042012-11-28 21:27:02 +0000166 }
Simon Kelley78c61842015-04-16 15:05:30 +0100167 else if (qtype == T_SOA)
168 soa = 1, found = 1;
169 else if (qtype == T_NS)
170 ns = 1, found = 1;
171 }
Simon Kelley19b16892013-10-20 10:19:39 +0100172
Simon Kelley78c61842015-04-16 15:05:30 +0100173 if (qtype == T_PTR && flag)
174 {
Simon Kelley115ac3e2013-05-20 11:28:32 +0100175 intr = NULL;
Simon Kelley86e3b9a2012-11-30 13:46:48 +0000176
Simon Kelley115ac3e2013-05-20 11:28:32 +0100177 if (flag == F_IPV4)
178 for (intr = daemon->int_names; intr; intr = intr->next)
179 {
180 struct addrlist *addrlist;
181
Simon Kelley376d48c2013-11-13 13:04:30 +0000182 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
Simon Kelleycc921df2019-01-02 22:48:59 +0000183 if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr4.s_addr == addrlist->addr.addr4.s_addr)
Simon Kelley115ac3e2013-05-20 11:28:32 +0100184 break;
185
186 if (addrlist)
187 break;
188 else
189 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
190 intr = intr->next;
191 }
Simon Kelley115ac3e2013-05-20 11:28:32 +0100192 else if (flag == F_IPV6)
193 for (intr = daemon->int_names; intr; intr = intr->next)
194 {
195 struct addrlist *addrlist;
196
Simon Kelley376d48c2013-11-13 13:04:30 +0000197 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
Simon Kelleycc921df2019-01-02 22:48:59 +0000198 if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr6, &addrlist->addr.addr6))
Simon Kelley115ac3e2013-05-20 11:28:32 +0100199 break;
200
201 if (addrlist)
202 break;
203 else
204 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
205 intr = intr->next;
206 }
Simon Kelley115ac3e2013-05-20 11:28:32 +0100207
208 if (intr)
209 {
Simon Kelley38440b22015-04-12 21:52:47 +0100210 if (local_query || in_zone(zone, intr->name, NULL))
Simon Kelley115ac3e2013-05-20 11:28:32 +0100211 {
212 found = 1;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700213 log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL, 0);
Simon Kelley115ac3e2013-05-20 11:28:32 +0100214 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
215 daemon->auth_ttl, NULL,
216 T_PTR, C_IN, "d", intr->name))
217 anscount++;
Simon Kelley86e3b9a2012-11-30 13:46:48 +0000218 }
219 }
Simon Kelley115ac3e2013-05-20 11:28:32 +0100220
Simon Kelley4f7b3042012-11-28 21:27:02 +0000221 if ((crecp = cache_find_by_addr(NULL, &addr, now, flag)))
222 do {
223 strcpy(name, cache_get_name(crecp));
224
225 if (crecp->flags & F_DHCP && !option_bool(OPT_DHCP_FQDN))
226 {
227 char *p = strchr(name, '.');
228 if (p)
229 *p = 0; /* must be bare name */
230
231 /* add external domain */
Simon Kelley38440b22015-04-12 21:52:47 +0100232 if (zone)
233 {
234 strcat(name, ".");
235 strcat(name, zone->domain);
236 }
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700237 log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid), 0);
Simon Kelley8273ea52012-11-29 21:12:33 +0000238 found = 1;
Simon Kelley4f7b3042012-11-28 21:27:02 +0000239 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
240 daemon->auth_ttl, NULL,
241 T_PTR, C_IN, "d", name))
Simon Kelley8273ea52012-11-29 21:12:33 +0000242 anscount++;
Simon Kelley4f7b3042012-11-28 21:27:02 +0000243 }
Simon Kelley38440b22015-04-12 21:52:47 +0100244 else if (crecp->flags & (F_DHCP | F_HOSTS) && (local_query || in_zone(zone, name, NULL)))
Simon Kelley4f7b3042012-11-28 21:27:02 +0000245 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700246 log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid), 0);
Simon Kelley8273ea52012-11-29 21:12:33 +0000247 found = 1;
Simon Kelley4f7b3042012-11-28 21:27:02 +0000248 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
249 daemon->auth_ttl, NULL,
250 T_PTR, C_IN, "d", name))
Simon Kelley8273ea52012-11-29 21:12:33 +0000251 anscount++;
Simon Kelley4f7b3042012-11-28 21:27:02 +0000252 }
253 else
254 continue;
255
256 } while ((crecp = cache_find_by_addr(crecp, &addr, now, flag)));
Simon Kelley86e3b9a2012-11-30 13:46:48 +0000257
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700258 if (!found && is_rev_synth(flag, &addr, name) && (local_query || in_zone(zone, name, NULL)))
259 {
260 log_query(F_CONFIG | F_REVERSE | flag, name, &addr, NULL, 0);
261 found = 1;
262
263 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
264 daemon->auth_ttl, NULL,
265 T_PTR, C_IN, "d", name))
266 anscount++;
267 }
268
Simon Kelley10068602014-04-03 21:16:40 +0100269 if (found)
270 nxdomain = 0;
271 else
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700272 log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL, 0);
Simon Kelley4f7b3042012-11-28 21:27:02 +0000273
274 continue;
275 }
276
Simon Kelley5c0bd5b2012-12-01 16:42:47 +0000277 cname_restart:
Simon Kelley78c61842015-04-16 15:05:30 +0100278 if (found)
279 /* NS and SOA .arpa requests have set found above. */
280 cut = NULL;
281 else
Simon Kelley4f7b3042012-11-28 21:27:02 +0000282 {
Simon Kelley78c61842015-04-16 15:05:30 +0100283 for (zone = daemon->auth_zones; zone; zone = zone->next)
284 if (in_zone(zone, name, &cut))
285 break;
286
287 if (!zone)
288 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700289 out_of_zone = 1;
Simon Kelley78c61842015-04-16 15:05:30 +0100290 auth = 0;
291 continue;
292 }
Simon Kelley4f7b3042012-11-28 21:27:02 +0000293 }
294
Simon Kelley8273ea52012-11-29 21:12:33 +0000295 for (rec = daemon->mxnames; rec; rec = rec->next)
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100296 if (!rec->issrv && (rc = hostname_issubdomain(name, rec->name)))
Simon Kelley86e3b9a2012-11-30 13:46:48 +0000297 {
298 nxdomain = 0;
299
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100300 if (rc == 2 && qtype == T_MX)
Simon Kelley86e3b9a2012-11-30 13:46:48 +0000301 {
302 found = 1;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700303 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>", 0);
Simon Kelley86e3b9a2012-11-30 13:46:48 +0000304 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
305 NULL, T_MX, C_IN, "sd", rec->weight, rec->target))
306 anscount++;
307 }
308 }
Simon Kelley8273ea52012-11-29 21:12:33 +0000309
Simon Kelley86e3b9a2012-11-30 13:46:48 +0000310 for (move = NULL, up = &daemon->mxnames, rec = daemon->mxnames; rec; rec = rec->next)
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100311 if (rec->issrv && (rc = hostname_issubdomain(name, rec->name)))
Simon Kelley86e3b9a2012-11-30 13:46:48 +0000312 {
313 nxdomain = 0;
314
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100315 if (rc == 2 && qtype == T_SRV)
Simon Kelley86e3b9a2012-11-30 13:46:48 +0000316 {
317 found = 1;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700318 log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>", 0);
Simon Kelley86e3b9a2012-11-30 13:46:48 +0000319 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
320 NULL, T_SRV, C_IN, "sssd",
321 rec->priority, rec->weight, rec->srvport, rec->target))
322
323 anscount++;
324 }
325
326 /* unlink first SRV record found */
327 if (!move)
328 {
329 move = rec;
330 *up = rec->next;
331 }
332 else
333 up = &rec->next;
334 }
335 else
336 up = &rec->next;
337
338 /* put first SRV record back at the end. */
339 if (move)
340 {
341 *up = move;
342 move->next = NULL;
343 }
344
345 for (txt = daemon->rr; txt; txt = txt->next)
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100346 if ((rc = hostname_issubdomain(name, txt->name)))
Simon Kelley86e3b9a2012-11-30 13:46:48 +0000347 {
348 nxdomain = 0;
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100349 if (rc == 2 && txt->class == qtype)
Simon Kelley86e3b9a2012-11-30 13:46:48 +0000350 {
351 found = 1;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700352 log_query(F_CONFIG | F_RRNAME, name, NULL, NULL, txt->class);
Simon Kelley86e3b9a2012-11-30 13:46:48 +0000353 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
354 NULL, txt->class, C_IN, "t", txt->len, txt->txt))
355 anscount++;
356 }
357 }
358
359 for (txt = daemon->txt; txt; txt = txt->next)
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100360 if (txt->class == C_IN && (rc = hostname_issubdomain(name, txt->name)))
Simon Kelley86e3b9a2012-11-30 13:46:48 +0000361 {
362 nxdomain = 0;
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100363 if (rc == 2 && qtype == T_TXT)
Simon Kelley86e3b9a2012-11-30 13:46:48 +0000364 {
365 found = 1;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700366 log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>", 0);
Simon Kelley86e3b9a2012-11-30 13:46:48 +0000367 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
368 NULL, T_TXT, C_IN, "t", txt->len, txt->txt))
369 anscount++;
370 }
371 }
372
373 for (na = daemon->naptr; na; na = na->next)
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100374 if ((rc = hostname_issubdomain(name, na->name)))
Simon Kelley86e3b9a2012-11-30 13:46:48 +0000375 {
376 nxdomain = 0;
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100377 if (rc == 2 && qtype == T_NAPTR)
Simon Kelley86e3b9a2012-11-30 13:46:48 +0000378 {
379 found = 1;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700380 log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>", 0);
Simon Kelley86e3b9a2012-11-30 13:46:48 +0000381 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
382 NULL, T_NAPTR, C_IN, "sszzzd",
383 na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
384 anscount++;
385 }
386 }
Simon Kelley115ac3e2013-05-20 11:28:32 +0100387
388 if (qtype == T_A)
389 flag = F_IPV4;
390
Simon Kelley115ac3e2013-05-20 11:28:32 +0100391 if (qtype == T_AAAA)
392 flag = F_IPV6;
Simon Kelley115ac3e2013-05-20 11:28:32 +0100393
Simon Kelley8ab91e92013-10-21 20:50:04 +0100394 for (intr = daemon->int_names; intr; intr = intr->next)
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100395 if ((rc = hostname_issubdomain(name, intr->name)))
Simon Kelley8ab91e92013-10-21 20:50:04 +0100396 {
397 struct addrlist *addrlist;
398
Simon Kelley8ab91e92013-10-21 20:50:04 +0100399 nxdomain = 0;
400
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100401 if (rc == 2 && flag)
Simon Kelley376d48c2013-11-13 13:04:30 +0000402 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
403 if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == qtype &&
404 (local_query || filter_zone(zone, flag, &addrlist->addr)))
Simon Kelleyfb63dd12013-10-21 18:19:35 +0100405 {
Simon Kelley47669362014-12-17 12:41:56 +0000406 if (addrlist->flags & ADDRLIST_REVONLY)
407 continue;
Simon Kelleyee875042018-10-23 22:10:17 +0100408
Simon Kelleyfb63dd12013-10-21 18:19:35 +0100409 found = 1;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700410 log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL, 0);
Simon Kelleyfb63dd12013-10-21 18:19:35 +0100411 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
412 daemon->auth_ttl, NULL, qtype, C_IN,
413 qtype == T_A ? "4" : "6", &addrlist->addr))
414 anscount++;
415 }
416 }
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700417
418 if (!found && is_name_synthetic(flag, name, &addr) )
419 {
420 nxdomain = 0;
421
422 log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL, 0);
423 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
424 daemon->auth_ttl, NULL, qtype, C_IN, qtype == T_A ? "4" : "6", &addr))
425 anscount++;
426 }
Simon Kelley5c0bd5b2012-12-01 16:42:47 +0000427
Simon Kelleye1ff4192012-12-09 17:08:47 +0000428 if (!cut)
Simon Kelley4f7b3042012-11-28 21:27:02 +0000429 {
Simon Kelleye1ff4192012-12-09 17:08:47 +0000430 nxdomain = 0;
431
432 if (qtype == T_SOA)
433 {
Simon Kelley5f8002f2013-10-21 17:40:18 +0100434 auth = soa = 1; /* inhibits auth section */
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700435 log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>", 0);
Simon Kelleye1ff4192012-12-09 17:08:47 +0000436 }
437 else if (qtype == T_AXFR)
438 {
Simon Kelleyc6cb7402013-01-07 21:55:54 +0000439 struct iname *peers;
440
441 if (peer_addr->sa.sa_family == AF_INET)
442 peer_addr->in.sin_port = 0;
Simon Kelleyc6cb7402013-01-07 21:55:54 +0000443 else
Simon Kelley39341552015-01-18 22:11:10 +0000444 {
445 peer_addr->in6.sin6_port = 0;
446 peer_addr->in6.sin6_scope_id = 0;
447 }
Simon Kelleyc6cb7402013-01-07 21:55:54 +0000448
449 for (peers = daemon->auth_peers; peers; peers = peers->next)
450 if (sockaddr_isequal(peer_addr, &peers->addr))
451 break;
452
Simon Kelley090856c2018-06-02 18:37:07 +0100453 /* Refuse all AXFR unless --auth-sec-servers or auth-peers is set */
454 if ((!daemon->secondary_forward_server && !daemon->auth_peers) ||
455 (daemon->auth_peers && !peers))
Simon Kelley49678762012-12-09 18:24:58 +0000456 {
Simon Kelley49678762012-12-09 18:24:58 +0000457 if (peer_addr->sa.sa_family == AF_INET)
Simon Kelleyc6cb7402013-01-07 21:55:54 +0000458 inet_ntop(AF_INET, &peer_addr->in.sin_addr, daemon->addrbuff, ADDRSTRLEN);
Simon Kelley49678762012-12-09 18:24:58 +0000459 else
Simon Kelleyc6cb7402013-01-07 21:55:54 +0000460 inet_ntop(AF_INET6, &peer_addr->in6.sin6_addr, daemon->addrbuff, ADDRSTRLEN);
Simon Kelley49678762012-12-09 18:24:58 +0000461
Simon Kelleyc6cb7402013-01-07 21:55:54 +0000462 my_syslog(LOG_WARNING, _("ignoring zone transfer request from %s"), daemon->addrbuff);
463 return 0;
Simon Kelley49678762012-12-09 18:24:58 +0000464 }
Simon Kelleyc6cb7402013-01-07 21:55:54 +0000465
Simon Kelley5f8002f2013-10-21 17:40:18 +0100466 auth = 1;
Simon Kelleye1ff4192012-12-09 17:08:47 +0000467 soa = 1; /* inhibits auth section */
468 ns = 1; /* ensure we include NS records! */
469 axfr = 1;
Simon Kelleye1ff4192012-12-09 17:08:47 +0000470 axfroffset = nameoffset;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700471 log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>", 0);
Simon Kelleye1ff4192012-12-09 17:08:47 +0000472 }
473 else if (qtype == T_NS)
474 {
Simon Kelley5f8002f2013-10-21 17:40:18 +0100475 auth = 1;
Simon Kelleye1ff4192012-12-09 17:08:47 +0000476 ns = 1; /* inhibits auth section */
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700477 log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>", 0);
Simon Kelleye1ff4192012-12-09 17:08:47 +0000478 }
Simon Kelley4f7b3042012-11-28 21:27:02 +0000479 }
Simon Kelley8273ea52012-11-29 21:12:33 +0000480
Simon Kelleyb75e9362012-12-07 11:50:41 +0000481 if (!option_bool(OPT_DHCP_FQDN) && cut)
Simon Kelley4f7b3042012-11-28 21:27:02 +0000482 {
Simon Kelleyb75e9362012-12-07 11:50:41 +0000483 *cut = 0; /* remove domain part */
Simon Kelley4f7b3042012-11-28 21:27:02 +0000484
Simon Kelley5c0bd5b2012-12-01 16:42:47 +0000485 if (!strchr(name, '.') && (crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
Simon Kelley4f7b3042012-11-28 21:27:02 +0000486 {
487 if (crecp->flags & F_DHCP)
488 do
489 {
490 nxdomain = 0;
Simon Kelley60225f42012-12-28 11:29:01 +0000491 if ((crecp->flags & flag) &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000492 (local_query || filter_zone(zone, flag, &(crecp->addr))))
Simon Kelley4f7b3042012-11-28 21:27:02 +0000493 {
Simon Kelleyb75e9362012-12-07 11:50:41 +0000494 *cut = '.'; /* restore domain part */
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700495 log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid), 0);
Simon Kelleyb75e9362012-12-07 11:50:41 +0000496 *cut = 0; /* remove domain part */
Simon Kelley4f7b3042012-11-28 21:27:02 +0000497 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
498 daemon->auth_ttl, NULL, qtype, C_IN,
499 qtype == T_A ? "4" : "6", &crecp->addr))
Simon Kelley8273ea52012-11-29 21:12:33 +0000500 anscount++;
Simon Kelley4f7b3042012-11-28 21:27:02 +0000501 }
502 } while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
503 }
504
Simon Kelleyb75e9362012-12-07 11:50:41 +0000505 *cut = '.'; /* restore domain part */
Simon Kelley4f7b3042012-11-28 21:27:02 +0000506 }
507
Simon Kelley86e3b9a2012-11-30 13:46:48 +0000508 if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
Simon Kelley4f7b3042012-11-28 21:27:02 +0000509 {
510 if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
511 do
512 {
513 nxdomain = 0;
Simon Kelleycc921df2019-01-02 22:48:59 +0000514 if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr))))
Simon Kelley4f7b3042012-11-28 21:27:02 +0000515 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700516 log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid), 0);
Simon Kelley4f7b3042012-11-28 21:27:02 +0000517 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
518 daemon->auth_ttl, NULL, qtype, C_IN,
519 qtype == T_A ? "4" : "6", &crecp->addr))
Simon Kelley8273ea52012-11-29 21:12:33 +0000520 anscount++;
Simon Kelley4f7b3042012-11-28 21:27:02 +0000521 }
522 } while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
523 }
Simon Kelley8273ea52012-11-29 21:12:33 +0000524
Simon Kelley62f9c0d2017-02-19 23:07:01 +0000525 /* Only supply CNAME if no record for any type is known. */
526 if (nxdomain)
Simon Kelleyb637d782016-12-13 16:44:11 +0000527 {
528 /* Check for possible wildcard match against *.domain
529 return length of match, to get longest.
530 Note that if return length of wildcard section, so
531 we match b.simon to _both_ *.simon and b.simon
532 but return a longer (better) match to b.simon.
533 */
534 for (wclen = 0, candidate = NULL, a = daemon->cnames; a; a = a->next)
535 if (a->alias[0] == '*')
536 {
537 char *test = name;
538
539 while ((test = strchr(test+1, '.')))
540 {
541 if (hostname_isequal(test, &(a->alias[1])))
542 {
543 if (strlen(test) > wclen && !cname_wildcard)
544 {
545 wclen = strlen(test);
546 candidate = a;
547 cname_wildcard = 1;
548 }
549 break;
550 }
551 }
552
553 }
554 else if (hostname_isequal(a->alias, name) && strlen(a->alias) > wclen)
555 {
556 /* Simple case, no wildcard */
557 wclen = strlen(a->alias);
558 candidate = a;
559 }
560
561 if (candidate)
562 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700563 log_query(F_CONFIG | F_CNAME, name, NULL, NULL, 0);
Simon Kelleyb637d782016-12-13 16:44:11 +0000564 strcpy(name, candidate->target);
565 if (!strchr(name, '.'))
566 {
567 strcat(name, ".");
568 strcat(name, zone->domain);
569 }
570 found = 1;
571 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
572 daemon->auth_ttl, &nameoffset,
573 T_CNAME, C_IN, "d", name))
574 anscount++;
575
576 goto cname_restart;
577 }
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100578 else if (cache_find_non_terminal(name, now))
579 nxdomain = 0;
Simon Kelleyb637d782016-12-13 16:44:11 +0000580
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700581 log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL, 0);
Simon Kelleyb637d782016-12-13 16:44:11 +0000582 }
Simon Kelley8273ea52012-11-29 21:12:33 +0000583
Simon Kelley4f7b3042012-11-28 21:27:02 +0000584 }
Simon Kelley45dd1fe2012-12-04 20:49:24 +0000585
Simon Kelley4f7b3042012-11-28 21:27:02 +0000586 /* Add auth section */
Simon Kelleyaa67fe72013-02-04 21:32:34 +0000587 if (auth && zone)
Simon Kelley4f7b3042012-11-28 21:27:02 +0000588 {
Simon Kelleyb75e9362012-12-07 11:50:41 +0000589 char *authname;
Simon Kelleye1ff4192012-12-09 17:08:47 +0000590 int newoffset, offset = 0;
591
Simon Kelley45dd1fe2012-12-04 20:49:24 +0000592 if (!subnet)
Simon Kelleyb75e9362012-12-07 11:50:41 +0000593 authname = zone->domain;
Simon Kelley45dd1fe2012-12-04 20:49:24 +0000594 else
595 {
596 /* handle NS and SOA for PTR records */
Simon Kelleyb75e9362012-12-07 11:50:41 +0000597
598 authname = name;
599
Simon Kelley376d48c2013-11-13 13:04:30 +0000600 if (!(subnet->flags & ADDRLIST_IPV6))
Simon Kelley45dd1fe2012-12-04 20:49:24 +0000601 {
Simon Kelleycc921df2019-01-02 22:48:59 +0000602 in_addr_t a = ntohl(subnet->addr.addr4.s_addr) >> 8;
Simon Kelley45dd1fe2012-12-04 20:49:24 +0000603 char *p = name;
604
Simon Kelleybaa80ae2013-05-29 16:32:07 +0100605 if (subnet->prefixlen >= 24)
Rosen Penevcbd29e52017-06-27 22:29:51 +0100606 p += sprintf(p, "%u.", a & 0xff);
Simon Kelley45dd1fe2012-12-04 20:49:24 +0000607 a = a >> 8;
Simon Kelleybaa80ae2013-05-29 16:32:07 +0100608 if (subnet->prefixlen >= 16 )
Rosen Penevcbd29e52017-06-27 22:29:51 +0100609 p += sprintf(p, "%u.", a & 0xff);
Simon Kelley45dd1fe2012-12-04 20:49:24 +0000610 a = a >> 8;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700611 sprintf(p, "%u.in-addr.arpa", a & 0xff);
Simon Kelley45dd1fe2012-12-04 20:49:24 +0000612
613 }
Simon Kelley45dd1fe2012-12-04 20:49:24 +0000614 else
615 {
616 char *p = name;
617 int i;
618
619 for (i = subnet->prefixlen-1; i >= 0; i -= 4)
620 {
Simon Kelleycc921df2019-01-02 22:48:59 +0000621 int dig = ((unsigned char *)&subnet->addr.addr6)[i>>3];
Simon Kelley45dd1fe2012-12-04 20:49:24 +0000622 p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
623 }
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700624 sprintf(p, "ip6.arpa");
Simon Kelley45dd1fe2012-12-04 20:49:24 +0000625
626 }
Simon Kelley45dd1fe2012-12-04 20:49:24 +0000627 }
628
629 /* handle NS and SOA in auth section or for explicit queries */
Simon Kelleye1ff4192012-12-09 17:08:47 +0000630 newoffset = ansp - (unsigned char *)header;
631 if (((anscount == 0 && !ns) || soa) &&
Simon Kelley45dd1fe2012-12-04 20:49:24 +0000632 add_resource_record(header, limit, &trunc, 0, &ansp,
633 daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
Simon Kelleyb75e9362012-12-07 11:50:41 +0000634 authname, daemon->authserver, daemon->hostmaster,
Simon Kelley45dd1fe2012-12-04 20:49:24 +0000635 daemon->soa_sn, daemon->soa_refresh,
636 daemon->soa_retry, daemon->soa_expiry,
637 daemon->auth_ttl))
638 {
Simon Kelleye1ff4192012-12-09 17:08:47 +0000639 offset = newoffset;
Simon Kelley45dd1fe2012-12-04 20:49:24 +0000640 if (soa)
641 anscount++;
642 else
643 authcount++;
644 }
Simon Kelleye1ff4192012-12-09 17:08:47 +0000645
646 if (anscount != 0 || ns)
647 {
648 struct name_list *secondary;
649
Simon Kelleyb43585c2020-03-28 17:41:06 +0000650 /* Only include the machine running dnsmasq if it's acting as an auth server */
651 if (daemon->authinterface)
Simon Kelleye1ff4192012-12-09 17:08:47 +0000652 {
Simon Kelleyb43585c2020-03-28 17:41:06 +0000653 newoffset = ansp - (unsigned char *)header;
654 if (add_resource_record(header, limit, &trunc, -offset, &ansp,
655 daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, daemon->authserver))
656 {
657 if (offset == 0)
658 offset = newoffset;
659 if (ns)
660 anscount++;
661 else
662 authcount++;
663 }
Simon Kelleye1ff4192012-12-09 17:08:47 +0000664 }
Simon Kelleyb75e9362012-12-07 11:50:41 +0000665
Simon Kelleye1ff4192012-12-09 17:08:47 +0000666 if (!subnet)
667 for (secondary = daemon->secondary_forward_server; secondary; secondary = secondary->next)
668 if (add_resource_record(header, limit, &trunc, offset, &ansp,
669 daemon->auth_ttl, NULL, T_NS, C_IN, "d", secondary->name))
670 {
671 if (ns)
672 anscount++;
673 else
674 authcount++;
675 }
676 }
677
Simon Kelleyb75e9362012-12-07 11:50:41 +0000678 if (axfr)
679 {
Simon Kelleye1ff4192012-12-09 17:08:47 +0000680 for (rec = daemon->mxnames; rec; rec = rec->next)
681 if (in_zone(zone, rec->name, &cut))
682 {
683 if (cut)
684 *cut = 0;
685
686 if (rec->issrv)
687 {
688 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
689 NULL, T_SRV, C_IN, "sssd", cut ? rec->name : NULL,
690 rec->priority, rec->weight, rec->srvport, rec->target))
691
692 anscount++;
693 }
694 else
695 {
696 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
697 NULL, T_MX, C_IN, "sd", cut ? rec->name : NULL, rec->weight, rec->target))
698 anscount++;
699 }
700
701 /* restore config data */
702 if (cut)
703 *cut = '.';
704 }
705
706 for (txt = daemon->rr; txt; txt = txt->next)
707 if (in_zone(zone, txt->name, &cut))
708 {
709 if (cut)
710 *cut = 0;
711
712 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
713 NULL, txt->class, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
714 anscount++;
715
716 /* restore config data */
717 if (cut)
718 *cut = '.';
719 }
720
721 for (txt = daemon->txt; txt; txt = txt->next)
722 if (txt->class == C_IN && in_zone(zone, txt->name, &cut))
723 {
724 if (cut)
725 *cut = 0;
726
727 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
728 NULL, T_TXT, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
729 anscount++;
730
731 /* restore config data */
732 if (cut)
733 *cut = '.';
734 }
735
736 for (na = daemon->naptr; na; na = na->next)
737 if (in_zone(zone, na->name, &cut))
738 {
739 if (cut)
740 *cut = 0;
741
742 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
743 NULL, T_NAPTR, C_IN, "sszzzd", cut ? na->name : NULL,
744 na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
745 anscount++;
746
747 /* restore config data */
748 if (cut)
749 *cut = '.';
750 }
751
752 for (intr = daemon->int_names; intr; intr = intr->next)
Simon Kelley115ac3e2013-05-20 11:28:32 +0100753 if (in_zone(zone, intr->name, &cut))
Simon Kelleye1ff4192012-12-09 17:08:47 +0000754 {
Simon Kelley115ac3e2013-05-20 11:28:32 +0100755 struct addrlist *addrlist;
756
Simon Kelleye1ff4192012-12-09 17:08:47 +0000757 if (cut)
758 *cut = 0;
759
Simon Kelley376d48c2013-11-13 13:04:30 +0000760 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
Simon Kelley587ad4f2013-11-15 15:47:51 +0000761 if (!(addrlist->flags & ADDRLIST_IPV6) &&
762 (local_query || filter_zone(zone, F_IPV4, &addrlist->addr)) &&
Simon Kelley115ac3e2013-05-20 11:28:32 +0100763 add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
764 daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addrlist->addr))
765 anscount++;
766
Simon Kelley376d48c2013-11-13 13:04:30 +0000767 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
Simon Kelley587ad4f2013-11-15 15:47:51 +0000768 if ((addrlist->flags & ADDRLIST_IPV6) &&
769 (local_query || filter_zone(zone, F_IPV6, &addrlist->addr)) &&
Simon Kelley115ac3e2013-05-20 11:28:32 +0100770 add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
771 daemon->auth_ttl, NULL, T_AAAA, C_IN, "6", cut ? intr->name : NULL, &addrlist->addr))
772 anscount++;
Simon Kelleye1ff4192012-12-09 17:08:47 +0000773
774 /* restore config data */
775 if (cut)
776 *cut = '.';
777 }
Simon Kelley115ac3e2013-05-20 11:28:32 +0100778
Simon Kelleye1ff4192012-12-09 17:08:47 +0000779 for (a = daemon->cnames; a; a = a->next)
780 if (in_zone(zone, a->alias, &cut))
781 {
782 strcpy(name, a->target);
783 if (!strchr(name, '.'))
784 {
785 strcat(name, ".");
786 strcat(name, zone->domain);
787 }
788
789 if (cut)
790 *cut = 0;
791
792 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
793 daemon->auth_ttl, NULL,
794 T_CNAME, C_IN, "d", cut ? a->alias : NULL, name))
795 anscount++;
796 }
797
Simon Kelleyb75e9362012-12-07 11:50:41 +0000798 cache_enumerate(1);
799 while ((crecp = cache_enumerate(0)))
800 {
801 if ((crecp->flags & (F_IPV4 | F_IPV6)) &&
802 !(crecp->flags & (F_NEG | F_NXDOMAIN)) &&
803 (crecp->flags & F_FORWARD))
804 {
805 if ((crecp->flags & F_DHCP) && !option_bool(OPT_DHCP_FQDN))
806 {
807 char *cache_name = cache_get_name(crecp);
Simon Kelley19b16892013-10-20 10:19:39 +0100808 if (!strchr(cache_name, '.') &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000809 (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr))) &&
Simon Kelleyee875042018-10-23 22:10:17 +0100810 add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
811 daemon->auth_ttl, NULL, (crecp->flags & F_IPV6) ? T_AAAA : T_A, C_IN,
812 (crecp->flags & F_IPV4) ? "4" : "6", cache_name, &crecp->addr))
813 anscount++;
Simon Kelleyb75e9362012-12-07 11:50:41 +0000814 }
815
816 if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
817 {
818 strcpy(name, cache_get_name(crecp));
Simon Kelley19b16892013-10-20 10:19:39 +0100819 if (in_zone(zone, name, &cut) &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000820 (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr))))
Simon Kelleyb75e9362012-12-07 11:50:41 +0000821 {
Simon Kelleyee875042018-10-23 22:10:17 +0100822 if (cut)
823 *cut = 0;
Simon Kelleye1ff4192012-12-09 17:08:47 +0000824
Simon Kelleyee875042018-10-23 22:10:17 +0100825 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
826 daemon->auth_ttl, NULL, (crecp->flags & F_IPV6) ? T_AAAA : T_A, C_IN,
827 (crecp->flags & F_IPV4) ? "4" : "6", cut ? name : NULL, &crecp->addr))
828 anscount++;
Simon Kelleyb75e9362012-12-07 11:50:41 +0000829 }
830 }
831 }
832 }
833
834 /* repeat SOA as last record */
835 if (add_resource_record(header, limit, &trunc, axfroffset, &ansp,
836 daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
837 daemon->authserver, daemon->hostmaster,
838 daemon->soa_sn, daemon->soa_refresh,
839 daemon->soa_retry, daemon->soa_expiry,
840 daemon->auth_ttl))
841 anscount++;
Simon Kelley4c985da2013-03-22 14:07:38 +0000842
Simon Kelleyb75e9362012-12-07 11:50:41 +0000843 }
Simon Kelley4c985da2013-03-22 14:07:38 +0000844
845 }
Simon Kelley45dd1fe2012-12-04 20:49:24 +0000846
Simon Kelley4f7b3042012-11-28 21:27:02 +0000847 /* done all questions, set up header and return length of result */
848 /* clear authoritative and truncated flags, set QR flag */
849 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
Simon Kelley93bafe62013-10-21 21:19:34 +0100850
851 if (local_query)
852 {
853 /* set RA flag */
854 header->hb4 |= HB4_RA;
855 }
856 else
857 {
858 /* clear RA flag */
859 header->hb4 &= ~HB4_RA;
860 }
Simon Kelley4f7b3042012-11-28 21:27:02 +0000861
Simon Kelleydc6a57f2019-08-20 23:17:27 +0100862 /* data is never DNSSEC signed. */
863 header->hb4 &= ~HB4_AD;
864
Josh Soref730c6742017-02-06 16:14:04 +0000865 /* authoritative */
Simon Kelley4f7b3042012-11-28 21:27:02 +0000866 if (auth)
867 header->hb3 |= HB3_AA;
868
869 /* truncation */
870 if (trunc)
871 header->hb3 |= HB3_TC;
872
Simon Kelley57310502013-10-21 18:26:20 +0100873 if ((auth || local_query) && nxdomain)
Simon Kelley4f7b3042012-11-28 21:27:02 +0000874 SET_RCODE(header, NXDOMAIN);
875 else
876 SET_RCODE(header, NOERROR); /* no error */
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700877
Simon Kelley4f7b3042012-11-28 21:27:02 +0000878 header->ancount = htons(anscount);
879 header->nscount = htons(authcount);
Simon Kelleyaa792352012-12-06 19:41:35 +0000880 header->arcount = htons(0);
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000881
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700882 if (!local_query && out_of_zone)
883 {
884 SET_RCODE(header, REFUSED);
885 header->ancount = htons(0);
886 header->nscount = htons(0);
887 addr.log.rcode = REFUSED;
888 addr.log.ede = EDE_NOT_AUTH;
889 log_query(F_UPSTREAM | F_RCODE, "error", &addr, NULL, 0);
890 return resize_packet(header, ansp - (unsigned char *)header, NULL, 0);
891 }
892
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000893 /* Advertise our packet size limit in our reply */
894 if (have_pseudoheader)
Simon Kelleyc7f3bd22016-02-28 21:48:34 +0000895 return add_pseudoheader(header, ansp - (unsigned char *)header, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000896
Simon Kelley4f7b3042012-11-28 21:27:02 +0000897 return ansp - (unsigned char *)header;
898}
899
Simon Kelley4820dce2012-12-18 18:30:30 +0000900#endif