blob: 2c0ef7f9da2f840855e711daf9ab7d3ec15798d6 [file] [log] [blame]
Simon Kelleyc8e8f5c2021-01-24 21:59:37 +00001/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
Simon Kelley9e4abcb2004-01-22 19:47:41 +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
Simon Kelley824af852008-02-12 20:43:05 +00005 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
Simon Kelley9e4abcb2004-01-22 19:47:41 +00008 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.
Simon Kelley824af852008-02-12 20:43:05 +000012
Simon Kelley73a08a22009-02-05 20:28:08 +000013 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/>.
Simon Kelley9e4abcb2004-01-22 19:47:41 +000015*/
16
Simon Kelley9e4abcb2004-01-22 19:47:41 +000017#include "dnsmasq.h"
18
Simon Kelley74d4fcd2021-03-15 21:59:51 +000019static struct frec *lookup_frec(unsigned short id, int fd, void *hash);
Simon Kelley15b60dd2020-11-18 18:34:55 +000020static struct frec *lookup_frec_by_query(void *hash, unsigned int flags);
21
Simon Kelley8a9be9e2014-01-25 23:17:21 +000022static unsigned short get_id(void);
Simon Kelley1a6bca82008-07-11 11:11:42 +010023static void free_frec(struct frec *f);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000024
Simon Kelley824af852008-02-12 20:43:05 +000025/* Send a UDP packet with its source address set as "source"
Simon Kelley44a2a312004-03-10 20:04:35 +000026 unless nowild is true, when we just send it with the kernel default */
Simon Kelley29689cf2012-03-22 14:01:00 +000027int send_from(int fd, int nowild, char *packet, size_t len,
Simon Kelleycc921df2019-01-02 22:48:59 +000028 union mysockaddr *to, union all_addr *source,
Simon Kelley50303b12012-04-04 22:13:17 +010029 unsigned int iface)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000030{
Simon Kelley44a2a312004-03-10 20:04:35 +000031 struct msghdr msg;
32 struct iovec iov[1];
Simon Kelley44a2a312004-03-10 20:04:35 +000033 union {
34 struct cmsghdr align; /* this ensures alignment */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010035#if defined(HAVE_LINUX_NETWORK)
Simon Kelley44a2a312004-03-10 20:04:35 +000036 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
37#elif defined(IP_SENDSRCADDR)
38 char control[CMSG_SPACE(sizeof(struct in_addr))];
39#endif
Simon Kelley44a2a312004-03-10 20:04:35 +000040 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
Simon Kelley44a2a312004-03-10 20:04:35 +000041 } control_u;
Simon Kelleyfeba5c12004-07-27 20:28:58 +010042
Simon Kelley44a2a312004-03-10 20:04:35 +000043 iov[0].iov_base = packet;
44 iov[0].iov_len = len;
45
Simon Kelleyfeba5c12004-07-27 20:28:58 +010046 msg.msg_control = NULL;
47 msg.msg_controllen = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +000048 msg.msg_flags = 0;
49 msg.msg_name = to;
50 msg.msg_namelen = sa_len(to);
51 msg.msg_iov = iov;
52 msg.msg_iovlen = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +010053
Simon Kelley26128d22004-11-14 16:43:54 +000054 if (!nowild)
Simon Kelleyfeba5c12004-07-27 20:28:58 +010055 {
Simon Kelley26128d22004-11-14 16:43:54 +000056 struct cmsghdr *cmptr;
Simon Kelleyfeba5c12004-07-27 20:28:58 +010057 msg.msg_control = &control_u;
58 msg.msg_controllen = sizeof(control_u);
Simon Kelley26128d22004-11-14 16:43:54 +000059 cmptr = CMSG_FIRSTHDR(&msg);
Simon Kelley44a2a312004-03-10 20:04:35 +000060
Simon Kelley26128d22004-11-14 16:43:54 +000061 if (to->sa.sa_family == AF_INET)
62 {
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010063#if defined(HAVE_LINUX_NETWORK)
Simon Kelley8ef5ada2010-06-03 19:42:45 +010064 struct in_pktinfo p;
65 p.ipi_ifindex = 0;
Simon Kelleycc921df2019-01-02 22:48:59 +000066 p.ipi_spec_dst = source->addr4;
Jérémie Courrèges-Anglasc6cc4552019-03-22 10:56:13 +010067 msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
Simon Kelley8ef5ada2010-06-03 19:42:45 +010068 memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
Jérémie Courrèges-Anglasc6cc4552019-03-22 10:56:13 +010069 cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
Simon Kelleyc72daea2012-01-05 21:33:27 +000070 cmptr->cmsg_level = IPPROTO_IP;
Simon Kelley26128d22004-11-14 16:43:54 +000071 cmptr->cmsg_type = IP_PKTINFO;
72#elif defined(IP_SENDSRCADDR)
Jérémie Courrèges-Anglasc6cc4552019-03-22 10:56:13 +010073 msg.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
Simon Kelleycc921df2019-01-02 22:48:59 +000074 memcpy(CMSG_DATA(cmptr), &(source->addr4), sizeof(source->addr4));
Jérémie Courrèges-Anglasc6cc4552019-03-22 10:56:13 +010075 cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
Simon Kelley26128d22004-11-14 16:43:54 +000076 cmptr->cmsg_level = IPPROTO_IP;
77 cmptr->cmsg_type = IP_SENDSRCADDR;
Simon Kelley44a2a312004-03-10 20:04:35 +000078#endif
Simon Kelley26128d22004-11-14 16:43:54 +000079 }
Simon Kelley26128d22004-11-14 16:43:54 +000080 else
81 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +010082 struct in6_pktinfo p;
83 p.ipi6_ifindex = iface; /* Need iface for IPv6 to handle link-local addrs */
Simon Kelleycc921df2019-01-02 22:48:59 +000084 p.ipi6_addr = source->addr6;
Jérémie Courrèges-Anglasc6cc4552019-03-22 10:56:13 +010085 msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
Simon Kelley8ef5ada2010-06-03 19:42:45 +010086 memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
Jérémie Courrèges-Anglasc6cc4552019-03-22 10:56:13 +010087 cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
Simon Kelley316e2732010-01-22 20:16:09 +000088 cmptr->cmsg_type = daemon->v6pktinfo;
Simon Kelleyc72daea2012-01-05 21:33:27 +000089 cmptr->cmsg_level = IPPROTO_IPV6;
Simon Kelley26128d22004-11-14 16:43:54 +000090 }
Simon Kelley26128d22004-11-14 16:43:54 +000091 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +010092
Simon Kelleyff841eb2015-03-11 21:36:30 +000093 while (retry_send(sendmsg(fd, &msg, 0)));
94
Brad Smithea3c60a2020-03-08 14:53:59 +000095 if (errno != 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +010096 {
Brad Smithea3c60a2020-03-08 14:53:59 +000097#ifdef HAVE_LINUX_NETWORK
98 /* If interface is still in DAD, EINVAL results - ignore that. */
99 if (errno != EINVAL)
100 my_syslog(LOG_ERR, _("failed to send packet: %s"), strerror(errno));
101#endif
Simon Kelley29689cf2012-03-22 14:01:00 +0000102 return 0;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100103 }
Simon Kelley29d28dd2012-12-03 14:05:59 +0000104
Simon Kelley29689cf2012-03-22 14:01:00 +0000105 return 1;
Simon Kelley44a2a312004-03-10 20:04:35 +0000106}
107
Simon Kelleycc921df2019-01-02 22:48:59 +0000108static unsigned int search_servers(time_t now, union all_addr **addrpp, unsigned int qtype,
Simon Kelley367341f2016-01-12 15:58:23 +0000109 char *qdomain, int *type, char **domain, int *norebind)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100110
111{
112 /* If the query ends in the domain in one of our servers, set
113 domain to point to that name. We find the largest match to allow both
114 domain.org and sub.domain.org to exist. */
115
116 unsigned int namelen = strlen(qdomain);
117 unsigned int matchlen = 0;
118 struct server *serv;
Simon Kelley28866e92011-02-14 20:19:14 +0000119 unsigned int flags = 0;
Simon Kelleycc921df2019-01-02 22:48:59 +0000120 static union all_addr zero;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100121
Simon Kelley3be34542004-09-11 19:12:13 +0100122 for (serv = daemon->servers; serv; serv=serv->next)
Simon Kelley09f3b2c2017-05-09 01:34:02 +0100123 if (qtype == F_DNSSECOK && !(serv->flags & SERV_DO_DNSSEC))
124 continue;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100125 /* domain matches take priority over NODOTS matches */
Simon Kelley09f3b2c2017-05-09 01:34:02 +0100126 else if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.') && namelen != 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100127 {
Simon Kelley28866e92011-02-14 20:19:14 +0000128 unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100129 *type = SERV_FOR_NODOTS;
Sung Paea914d0a2019-12-30 17:07:37 -0600130 if ((serv->flags & SERV_NO_REBIND) && norebind)
131 *norebind = 1;
132 else if (serv->flags & SERV_NO_ADDR)
Simon Kelley36717ee2004-09-20 19:20:58 +0100133 flags = F_NXDOMAIN;
Simon Kelleyda8b6512018-09-03 23:18:36 +0100134 else if (serv->flags & SERV_LITERAL_ADDRESS)
Simon Kelley36717ee2004-09-20 19:20:58 +0100135 {
Simon Kelleyda8b6512018-09-03 23:18:36 +0100136 /* literal address = '#' -> return all-zero address for IPv4 and IPv6 */
137 if ((serv->flags & SERV_USE_RESOLV) && (qtype & (F_IPV6 | F_IPV4)))
138 {
139 memset(&zero, 0, sizeof(zero));
140 flags = qtype;
141 *addrpp = &zero;
142 }
143 else if (sflag & qtype)
Simon Kelley36717ee2004-09-20 19:20:58 +0100144 {
145 flags = sflag;
146 if (serv->addr.sa.sa_family == AF_INET)
Simon Kelleycc921df2019-01-02 22:48:59 +0000147 *addrpp = (union all_addr *)&serv->addr.in.sin_addr;
Simon Kelley36717ee2004-09-20 19:20:58 +0100148 else
Simon Kelleycc921df2019-01-02 22:48:59 +0000149 *addrpp = (union all_addr *)&serv->addr.in6.sin6_addr;
Simon Kelley36717ee2004-09-20 19:20:58 +0100150 }
Simon Kelley824af852008-02-12 20:43:05 +0000151 else if (!flags || (flags & F_NXDOMAIN))
Simon Kelley36717ee2004-09-20 19:20:58 +0100152 flags = F_NOERR;
153 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100154 }
155 else if (serv->flags & SERV_HAS_DOMAIN)
156 {
157 unsigned int domainlen = strlen(serv->domain);
Simon Kelleyb8187c82005-11-26 21:46:27 +0000158 char *matchstart = qdomain + namelen - domainlen;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100159 if (namelen >= domainlen &&
Simon Kelleyb8187c82005-11-26 21:46:27 +0000160 hostname_isequal(matchstart, serv->domain) &&
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100161 (domainlen == 0 || namelen == domainlen || *(matchstart-1) == '.' ))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100162 {
Simon Kelley92be34a2016-01-16 18:39:54 +0000163 if ((serv->flags & SERV_NO_REBIND) && norebind)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100164 *norebind = 1;
Simon Kelley28866e92011-02-14 20:19:14 +0000165 else
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100166 {
Simon Kelley28866e92011-02-14 20:19:14 +0000167 unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
168 /* implement priority rules for --address and --server for same domain.
169 --address wins if the address is for the correct AF
170 --server wins otherwise. */
171 if (domainlen != 0 && domainlen == matchlen)
Simon Kelley36717ee2004-09-20 19:20:58 +0100172 {
Simon Kelley28866e92011-02-14 20:19:14 +0000173 if ((serv->flags & SERV_LITERAL_ADDRESS))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100174 {
Simon Kelley28866e92011-02-14 20:19:14 +0000175 if (!(sflag & qtype) && flags == 0)
176 continue;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100177 }
Simon Kelley28866e92011-02-14 20:19:14 +0000178 else
179 {
180 if (flags & (F_IPV4 | F_IPV6))
181 continue;
182 }
Simon Kelley36717ee2004-09-20 19:20:58 +0100183 }
Simon Kelley28866e92011-02-14 20:19:14 +0000184
185 if (domainlen >= matchlen)
186 {
Simon Kelley367341f2016-01-12 15:58:23 +0000187 *type = serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_DO_DNSSEC);
Simon Kelley28866e92011-02-14 20:19:14 +0000188 *domain = serv->domain;
189 matchlen = domainlen;
190 if (serv->flags & SERV_NO_ADDR)
191 flags = F_NXDOMAIN;
192 else if (serv->flags & SERV_LITERAL_ADDRESS)
193 {
Simon Kelleyda8b6512018-09-03 23:18:36 +0100194 /* literal address = '#' -> return all-zero address for IPv4 and IPv6 */
195 if ((serv->flags & SERV_USE_RESOLV) && (qtype & (F_IPV6 | F_IPV4)))
196 {
197 memset(&zero, 0, sizeof(zero));
198 flags = qtype;
199 *addrpp = &zero;
200 }
201 else if (sflag & qtype)
Simon Kelley28866e92011-02-14 20:19:14 +0000202 {
203 flags = sflag;
204 if (serv->addr.sa.sa_family == AF_INET)
Simon Kelleycc921df2019-01-02 22:48:59 +0000205 *addrpp = (union all_addr *)&serv->addr.in.sin_addr;
Simon Kelley28866e92011-02-14 20:19:14 +0000206 else
Simon Kelleycc921df2019-01-02 22:48:59 +0000207 *addrpp = (union all_addr *)&serv->addr.in6.sin6_addr;
Simon Kelley28866e92011-02-14 20:19:14 +0000208 }
209 else if (!flags || (flags & F_NXDOMAIN))
210 flags = F_NOERR;
211 }
212 else
213 flags = 0;
214 }
215 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100216 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100217 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100218
Simon Kelleybf05f8f2017-05-09 22:37:46 +0100219 if (flags == 0 && !(qtype & (F_QUERY | F_DNSSECOK)) &&
Simon Kelley28866e92011-02-14 20:19:14 +0000220 option_bool(OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
Simon Kelley7de060b2011-08-26 17:24:52 +0100221 /* don't forward A or AAAA queries for simple names, except the empty name */
222 flags = F_NOERR;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100223
Simon Kelley5aabfc72007-08-29 11:24:47 +0100224 if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now))
Simon Kelleyc1bb8502004-08-11 18:40:17 +0100225 flags = F_NOERR;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100226
Simon Kelley824af852008-02-12 20:43:05 +0000227 if (flags)
228 {
Simon Kelleyc346f612018-09-04 21:14:18 +0100229 if (flags == F_NXDOMAIN || flags == F_NOERR)
230 log_query(flags | qtype | F_NEG | F_CONFIG | F_FORWARD, qdomain, NULL, NULL);
231 else
232 {
233 /* handle F_IPV4 and F_IPV6 set on ANY query to 0.0.0.0/:: domain. */
234 if (flags & F_IPV4)
235 log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV6, qdomain, *addrpp, NULL);
Simon Kelleyc346f612018-09-04 21:14:18 +0100236 if (flags & F_IPV6)
237 log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV4, qdomain, *addrpp, NULL);
Simon Kelleyc346f612018-09-04 21:14:18 +0100238 }
Simon Kelley824af852008-02-12 20:43:05 +0000239 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100240 else if ((*type) & SERV_USE_RESOLV)
241 {
242 *type = 0; /* use normal servers for this domain */
243 *domain = NULL;
244 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100245 return flags;
246}
Simon Kelley44a2a312004-03-10 20:04:35 +0000247
Petr Menšík6c0bf792021-03-18 00:07:45 +0100248#ifdef HAVE_CONNTRACK
249static void set_outgoing_mark(struct frec *forward, int fd)
250{
251 /* Copy connection mark of incoming query to outgoing connection. */
252 unsigned int mark;
253 if (get_incoming_mark(&forward->frec_src.source, &forward->frec_src.dest, 0, &mark))
254 setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
255}
256#endif
257
258static void log_query_mysockaddr(unsigned int flags, char *name, union mysockaddr *addr, char *arg)
259{
260 if (addr->sa.sa_family == AF_INET)
261 log_query(flags | F_IPV4, name, (union all_addr *)&addr->in.sin_addr, arg);
262 else
263 log_query(flags | F_IPV6, name, (union all_addr *)&addr->in6.sin6_addr, arg);
264}
265
Petr Menšík51f7bc92021-03-18 01:05:43 +0100266static void server_send(struct server *server, int fd,
267 const void *header, size_t plen, int flags)
268{
269 while (retry_send(sendto(fd, header, plen, flags,
270 &server->addr.sa,
271 sa_len(&server->addr))));
272}
273
274#ifdef HAVE_DNSSEC
275static void server_send_log(struct server *server, int fd,
276 const void *header, size_t plen, int dumpflags,
277 unsigned int logflags, char *name, char *arg)
278{
279#ifdef HAVE_DUMPFILE
280 dump_packet(dumpflags, (void *)header, (size_t)plen, NULL, &server->addr);
281#endif
282 log_query_mysockaddr(logflags, name, &server->addr, arg);
283 server_send(server, fd, header, plen, 0);
284}
285#endif
286
Petr Menšíke10a9232021-03-15 11:20:49 +0100287static int server_test_type(const struct server *server,
288 const char *domain, int type, int extratype)
289{
290 return (type == (server->flags & (SERV_TYPE | extratype)) &&
291 (type != SERV_HAS_DOMAIN || hostname_isequal(domain, server->domain)) &&
292 !(server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)));
293}
294
Simon Kelley824af852008-02-12 20:43:05 +0000295static int forward_query(int udpfd, union mysockaddr *udpaddr,
Simon Kelleycc921df2019-01-02 22:48:59 +0000296 union all_addr *dst_addr, unsigned int dst_iface,
Simon Kelley83349b82014-02-10 21:02:01 +0000297 struct dns_header *header, size_t plen, time_t now,
Simon Kelley613ad152014-02-25 23:02:28 +0000298 struct frec *forward, int ad_reqd, int do_bit)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000299{
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000300 char *domain = NULL;
Simon Kelley367341f2016-01-12 15:58:23 +0000301 int type = SERV_DO_DNSSEC, norebind = 0;
Simon Kelleycc921df2019-01-02 22:48:59 +0000302 union all_addr *addrp = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +0000303 unsigned int flags = 0;
Simon Kelley15b60dd2020-11-18 18:34:55 +0000304 unsigned int fwd_flags = 0;
Simon Kelleyde379512004-06-22 20:23:33 +0100305 struct server *start = NULL;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000306 void *hash = hash_questions(header, plen, daemon->namebuff);
Simon Kelley2d765862020-11-12 22:06:07 +0000307#ifdef HAVE_DNSSEC
Simon Kelley367341f2016-01-12 15:58:23 +0000308 int do_dnssec = 0;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000309#endif
Simon Kelley1682d152018-08-03 20:38:18 +0100310 unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
311 unsigned char *oph = find_pseudoheader(header, plen, NULL, NULL, NULL, NULL);
312 (void)do_bit;
Simon Kelley15b60dd2020-11-18 18:34:55 +0000313
314 if (header->hb4 & HB4_CD)
315 fwd_flags |= FREC_CHECKING_DISABLED;
316 if (ad_reqd)
317 fwd_flags |= FREC_AD_QUESTION;
318 if (oph)
319 fwd_flags |= FREC_HAS_PHEADER;
320#ifdef HAVE_DNSSEC
321 if (do_bit)
322 fwd_flags |= FREC_DO_QUESTION;
323#endif
324
Simon Kelley305cb792021-02-18 21:35:09 +0000325 /* Check for retry on existing query */
326 if (!forward && (forward = lookup_frec_by_query(hash, fwd_flags)))
Simon Kelley141a26f2021-02-17 23:56:32 +0000327 {
Simon Kelley305cb792021-02-18 21:35:09 +0000328 struct frec_src *src;
Simon Kelley141a26f2021-02-17 23:56:32 +0000329
Simon Kelley305cb792021-02-18 21:35:09 +0000330 for (src = &forward->frec_src; src; src = src->next)
331 if (src->orig_id == ntohs(header->id) &&
332 sockaddr_isequal(&src->source, udpaddr))
333 break;
334
335 /* Existing query, but from new source, just add this
336 client to the list that will get the reply.*/
337 if (!src)
338 {
Simon Kelley141a26f2021-02-17 23:56:32 +0000339 /* Note whine_malloc() zeros memory. */
340 if (!daemon->free_frec_src &&
341 daemon->frec_src_count < daemon->ftabsize &&
342 (daemon->free_frec_src = whine_malloc(sizeof(struct frec_src))))
343 {
344 daemon->frec_src_count++;
345 daemon->free_frec_src->next = NULL;
346 }
347
348 /* If we've been spammed with many duplicates, just drop the query. */
349 if (!daemon->free_frec_src)
350 return 0;
351
Simon Kelley305cb792021-02-18 21:35:09 +0000352 src = daemon->free_frec_src;
353 daemon->free_frec_src = src->next;
354 src->next = forward->frec_src.next;
355 forward->frec_src.next = src;
356 src->orig_id = ntohs(header->id);
357 src->source = *udpaddr;
358 src->dest = *dst_addr;
359 src->log_id = daemon->log_id;
360 src->iface = dst_iface;
361 src->fd = udpfd;
Simon Kelley141a26f2021-02-17 23:56:32 +0000362 }
363 }
364
365 /* retry existing query */
366 if (forward)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000367 {
Simon Kelleya77cec82015-05-08 16:25:38 +0100368 /* If we didn't get an answer advertising a maximal packet in EDNS,
369 fall back to 1280, which should work everywhere on IPv6.
370 If that generates an answer, it will become the new default
371 for this server */
372 forward->flags |= FREC_TEST_PKTSZ;
373
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000374#ifdef HAVE_DNSSEC
Simon Kelleydac74312014-02-13 16:43:49 +0000375 /* If we've already got an answer to this query, but we're awaiting keys for validation,
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000376 there's no point retrying the query, retry the key query instead...... */
377 if (forward->blocking_query)
378 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000379 int fd, is_sign;
380 unsigned char *pheader;
Simon Kelleya77cec82015-05-08 16:25:38 +0100381
382 forward->flags &= ~FREC_TEST_PKTSZ;
383
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000384 while (forward->blocking_query)
385 forward = forward->blocking_query;
Simon Kelleya77cec82015-05-08 16:25:38 +0100386
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000387 blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
388 plen = forward->stash_len;
389
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000390 forward->flags |= FREC_TEST_PKTSZ;
Simon Kelley5bb88f02015-12-21 16:23:47 +0000391 if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000392 PUTSHORT(SAFE_PKTSZ, pheader);
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000393
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000394 if ((fd = allocate_rfd(&forward->rfds, forward->sentto)) != -1)
Petr Menšík51f7bc92021-03-18 01:05:43 +0100395 server_send_log(forward->sentto, fd, header, plen,
396 DUMP_SEC_QUERY,
397 F_NOEXTRA | F_DNSSEC, "retry", "dnssec");
398
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000399 return 1;
400 }
401#endif
402
Simon Kelleyde379512004-06-22 20:23:33 +0100403 /* retry on existing query, send to all available servers */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000404 domain = forward->sentto->domain;
Simon Kelley824af852008-02-12 20:43:05 +0000405 forward->sentto->failed_queries++;
Simon Kelley28866e92011-02-14 20:19:14 +0000406 if (!option_bool(OPT_ORDER))
Simon Kelleyde379512004-06-22 20:23:33 +0100407 {
Simon Kelley0a852542005-03-23 20:28:59 +0000408 forward->forwardall = 1;
Simon Kelley3be34542004-09-11 19:12:13 +0100409 daemon->last_server = NULL;
Simon Kelleyde379512004-06-22 20:23:33 +0100410 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000411 type = forward->sentto->flags & SERV_TYPE;
Simon Kelley367341f2016-01-12 15:58:23 +0000412#ifdef HAVE_DNSSEC
413 do_dnssec = forward->sentto->flags & SERV_DO_DNSSEC;
414#endif
415
Simon Kelleyde379512004-06-22 20:23:33 +0100416 if (!(start = forward->sentto->next))
Simon Kelley3be34542004-09-11 19:12:13 +0100417 start = daemon->servers; /* at end of list, recycle */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000418 header->id = htons(forward->new_id);
419 }
420 else
421 {
Simon Kelley141a26f2021-02-17 23:56:32 +0000422 /* new query */
423
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000424 if (gotname)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100425 flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000426
Simon Kelley367341f2016-01-12 15:58:23 +0000427#ifdef HAVE_DNSSEC
428 do_dnssec = type & SERV_DO_DNSSEC;
Simon Kelleyf7443d72016-01-19 20:29:57 +0000429#endif
430 type &= ~SERV_DO_DNSSEC;
Simon Kelley15b60dd2020-11-18 18:34:55 +0000431
Simon Kelley141a26f2021-02-17 23:56:32 +0000432 /* may be no servers available. */
Simon Kelleyd05dd582016-01-19 21:23:30 +0000433 if (daemon->servers && !flags)
Simon Kelley8caf3d72020-04-04 17:00:32 +0100434 forward = get_new_frec(now, NULL, NULL);
Simon Kelleyd05dd582016-01-19 21:23:30 +0000435 /* table full - flags == 0, return REFUSED */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000436
437 if (forward)
438 {
Simon Kelley15b60dd2020-11-18 18:34:55 +0000439 forward->frec_src.source = *udpaddr;
440 forward->frec_src.orig_id = ntohs(header->id);
441 forward->frec_src.dest = *dst_addr;
442 forward->frec_src.iface = dst_iface;
Simon Kelley6a6e06f2020-12-04 18:35:11 +0000443 forward->frec_src.next = NULL;
Simon Kelley04490bf2021-01-22 16:49:12 +0000444 forward->frec_src.fd = udpfd;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000445 forward->new_id = get_id();
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000446 memcpy(forward->hash, hash, HASH_SIZE);
Simon Kelley0a852542005-03-23 20:28:59 +0000447 forward->forwardall = 0;
Simon Kelley15b60dd2020-11-18 18:34:55 +0000448 forward->flags = fwd_flags;
Simon Kelley28866e92011-02-14 20:19:14 +0000449 if (norebind)
450 forward->flags |= FREC_NOREBIND;
Simon Kelley572b41e2011-02-18 18:11:18 +0000451 if (header->hb4 & HB4_CD)
Simon Kelley28866e92011-02-14 20:19:14 +0000452 forward->flags |= FREC_CHECKING_DISABLED;
Simon Kelley83349b82014-02-10 21:02:01 +0000453 if (ad_reqd)
454 forward->flags |= FREC_AD_QUESTION;
Simon Kelley7fa836e2014-02-10 20:11:24 +0000455#ifdef HAVE_DNSSEC
456 forward->work_counter = DNSSEC_WORK;
Simon Kelley613ad152014-02-25 23:02:28 +0000457 if (do_bit)
458 forward->flags |= FREC_DO_QUESTION;
Simon Kelley7fa836e2014-02-10 20:11:24 +0000459#endif
Simon Kelley613ad152014-02-25 23:02:28 +0000460
Simon Kelley28866e92011-02-14 20:19:14 +0000461 header->id = htons(forward->new_id);
462
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100463 /* In strict_order mode, always try servers in the order
464 specified in resolv.conf, if a domain is given
465 always try all the available servers,
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000466 otherwise, use the one last known to work. */
467
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100468 if (type == 0)
469 {
Simon Kelley28866e92011-02-14 20:19:14 +0000470 if (option_bool(OPT_ORDER))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100471 start = daemon->servers;
472 else if (!(start = daemon->last_server) ||
473 daemon->forwardcount++ > FORWARD_TEST ||
474 difftime(now, daemon->forwardtime) > FORWARD_TIME)
475 {
476 start = daemon->servers;
477 forward->forwardall = 1;
478 daemon->forwardcount = 0;
479 daemon->forwardtime = now;
480 }
481 }
482 else
Simon Kelleyde379512004-06-22 20:23:33 +0100483 {
Simon Kelley3be34542004-09-11 19:12:13 +0100484 start = daemon->servers;
Simon Kelley28866e92011-02-14 20:19:14 +0000485 if (!option_bool(OPT_ORDER))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100486 forward->forwardall = 1;
Simon Kelleyde379512004-06-22 20:23:33 +0100487 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000488 }
489 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100490
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000491 /* check for send errors here (no route to host)
492 if we fail to send to all nameservers, send back an error
493 packet straight away (helps modem users when offline) */
494
495 if (!flags && forward)
496 {
Simon Kelleyde379512004-06-22 20:23:33 +0100497 struct server *firstsentto = start;
Simon Kelley25e63f12020-11-25 21:17:52 +0000498 int subnet, cacheable, forwarded = 0;
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000499 size_t edns0_len;
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000500 unsigned char *pheader;
501
Simon Kelley25cf5e32015-01-09 15:53:03 +0000502 /* If a query is retried, use the log_id for the retry when logging the answer. */
Simon Kelley15b60dd2020-11-18 18:34:55 +0000503 forward->frec_src.log_id = daemon->log_id;
Simon Kelley25cf5e32015-01-09 15:53:03 +0000504
Simon Kelley25e63f12020-11-25 21:17:52 +0000505 plen = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->frec_src.source, now, &subnet, &cacheable);
Simon Kelley33702ab2015-12-28 23:17:15 +0000506
Simon Kelley6fd5d792017-10-13 22:26:40 +0100507 if (subnet)
508 forward->flags |= FREC_HAS_SUBNET;
Simon Kelley25e63f12020-11-25 21:17:52 +0000509
510 if (!cacheable)
511 forward->flags |= FREC_NO_CACHE;
512
Simon Kelley3a237152013-12-12 12:15:50 +0000513#ifdef HAVE_DNSSEC
Simon Kelley367341f2016-01-12 15:58:23 +0000514 if (option_bool(OPT_DNSSEC_VALID) && do_dnssec)
Simon Kelley0fc2f312014-01-08 10:26:58 +0000515 {
Simon Kelley6fd5d792017-10-13 22:26:40 +0100516 plen = add_do_bit(header, plen, ((unsigned char *) header) + PACKETSZ);
517
Simon Kelley5b3bf922014-01-25 17:03:07 +0000518 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
519 this allows it to select auth servers when one is returning bad data. */
520 if (option_bool(OPT_DNSSEC_DEBUG))
521 header->hb4 |= HB4_CD;
Simon Kelley613ad152014-02-25 23:02:28 +0000522
Simon Kelley0fc2f312014-01-08 10:26:58 +0000523 }
Simon Kelley3a237152013-12-12 12:15:50 +0000524#endif
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000525
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000526 if (find_pseudoheader(header, plen, &edns0_len, &pheader, NULL, NULL))
Simon Kelley6fd5d792017-10-13 22:26:40 +0100527 {
528 /* If there wasn't a PH before, and there is now, we added it. */
529 if (!oph)
530 forward->flags |= FREC_ADDED_PHEADER;
531
532 /* If we're sending an EDNS0 with any options, we can't recreate the query from a reply. */
533 if (edns0_len > 11)
534 forward->flags |= FREC_HAS_EXTRADATA;
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000535
536 /* Reduce udp size on retransmits. */
537 if (forward->flags & FREC_TEST_PKTSZ)
538 PUTSHORT(SAFE_PKTSZ, pheader);
Simon Kelley6fd5d792017-10-13 22:26:40 +0100539 }
Simon Kelleya77cec82015-05-08 16:25:38 +0100540
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000541 while (1)
542 {
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000543 int fd;
544
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000545 /* only send to servers dealing with our domain.
546 domain may be NULL, in which case server->domain
547 must be NULL also. */
548
Petr Menšíke10a9232021-03-15 11:20:49 +0100549 if (server_test_type(start, domain, type, 0) &&
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000550 ((fd = allocate_rfd(&forward->rfds, start)) != -1))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000551 {
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000552
Simon Kelley7de060b2011-08-26 17:24:52 +0100553#ifdef HAVE_CONNTRACK
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000554 /* Copy connection mark of incoming query to outgoing connection. */
555 if (option_bool(OPT_CONNTRACK))
Petr Menšík6c0bf792021-03-18 00:07:45 +0100556 set_outgoing_mark(forward, fd);
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000557#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +0100558
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000559#ifdef HAVE_DNSSEC
Simon Kelley5bb88f02015-12-21 16:23:47 +0000560 if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER))
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000561 {
562 /* Difficult one here. If our client didn't send EDNS0, we will have set the UDP
563 packet size to 512. But that won't provide space for the RRSIGS in many cases.
564 The RRSIGS will be stripped out before the answer goes back, so the packet should
565 shrink again. So, if we added a do-bit, bump the udp packet size to the value
Simon Kelley5aa5f0f2015-12-21 17:20:35 +0000566 known to be OK for this server. We check returned size after stripping and set
567 the truncated bit if it's still too big. */
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000568 unsigned char *pheader;
569 int is_sign;
Simon Kelley5bb88f02015-12-21 16:23:47 +0000570 if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000571 PUTSHORT(start->edns_pktsz, pheader);
572 }
573#endif
574
Simon Kelleyff841eb2015-03-11 21:36:30 +0000575 if (retry_send(sendto(fd, (char *)header, plen, 0,
576 &start->addr.sa,
577 sa_len(&start->addr))))
578 continue;
579
580 if (errno == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000581 {
Simon Kelley6b173352018-05-08 18:32:14 +0100582#ifdef HAVE_DUMPFILE
583 dump_packet(DUMP_UP_QUERY, (void *)header, plen, NULL, &start->addr);
584#endif
585
Simon Kelleycdeda282006-03-16 20:16:06 +0000586 /* Keep info in case we want to re-send this packet */
587 daemon->srv_save = start;
588 daemon->packet_len = plen;
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000589 daemon->fd_save = fd;
Simon Kelleycdeda282006-03-16 20:16:06 +0000590
Simon Kelleyde379512004-06-22 20:23:33 +0100591 if (!gotname)
Simon Kelley3be34542004-09-11 19:12:13 +0100592 strcpy(daemon->namebuff, "query");
Petr Menšík6c0bf792021-03-18 00:07:45 +0100593 log_query_mysockaddr(F_SERVER | F_FORWARD, daemon->namebuff,
594 &start->addr, NULL);
Simon Kelley824af852008-02-12 20:43:05 +0000595 start->queries++;
Simon Kelleyde379512004-06-22 20:23:33 +0100596 forwarded = 1;
597 forward->sentto = start;
Simon Kelley0a852542005-03-23 20:28:59 +0000598 if (!forward->forwardall)
Simon Kelleyde379512004-06-22 20:23:33 +0100599 break;
Simon Kelley0a852542005-03-23 20:28:59 +0000600 forward->forwardall++;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000601 }
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000602 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000603
Simon Kelleyde379512004-06-22 20:23:33 +0100604 if (!(start = start->next))
Simon Kelley3be34542004-09-11 19:12:13 +0100605 start = daemon->servers;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000606
Simon Kelleyde379512004-06-22 20:23:33 +0100607 if (start == firstsentto)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000608 break;
609 }
610
Simon Kelleyde379512004-06-22 20:23:33 +0100611 if (forwarded)
Simon Kelley824af852008-02-12 20:43:05 +0000612 return 1;
Simon Kelleyde379512004-06-22 20:23:33 +0100613
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000614 /* could not send on, prepare to return */
Simon Kelley15b60dd2020-11-18 18:34:55 +0000615 header->id = htons(forward->frec_src.orig_id);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100616 free_frec(forward); /* cancel */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000617 }
618
619 /* could not send on, return empty answer or address if known for whole domain */
Simon Kelleyb8187c82005-11-26 21:46:27 +0000620 if (udpfd != -1)
621 {
Simon Kelleycdeda282006-03-16 20:16:06 +0000622 plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl);
Simon Kelley1682d152018-08-03 20:38:18 +0100623 if (oph)
624 plen = add_pseudoheader(header, plen, ((unsigned char *) header) + PACKETSZ, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
Simon Kelley54dd3932012-06-20 11:23:38 +0100625 send_from(udpfd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND), (char *)header, plen, udpaddr, dst_addr, dst_iface);
Simon Kelleyb8187c82005-11-26 21:46:27 +0000626 }
627
Simon Kelley824af852008-02-12 20:43:05 +0000628 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000629}
630
Simon Kelleyed4c0762013-10-08 20:46:34 +0100631static size_t process_reply(struct dns_header *header, time_t now, struct server *server, size_t n, int check_rebind,
Simon Kelleyfe3992f2015-04-03 21:25:05 +0100632 int no_cache, int cache_secure, int bogusanswer, int ad_reqd, int do_bit, int added_pheader,
633 int check_subnet, union mysockaddr *query_source)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100634{
Simon Kelley36717ee2004-09-20 19:20:58 +0100635 unsigned char *pheader, *sizep;
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000636 char **sets = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +0000637 int munged = 0, is_sign;
Simon Kelley07ed5852018-05-04 21:52:22 +0100638 unsigned int rcode = RCODE(header);
Simon Kelleycdeda282006-03-16 20:16:06 +0000639 size_t plen;
Simon Kelleya6004d72017-10-25 17:48:19 +0100640
Simon Kelley83349b82014-02-10 21:02:01 +0000641 (void)ad_reqd;
Simon Kelley982faf42015-04-03 21:42:30 +0100642 (void)do_bit;
643 (void)bogusanswer;
Simon Kelley83349b82014-02-10 21:02:01 +0000644
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000645#ifdef HAVE_IPSET
Simon Kelley82a14af2014-04-13 20:48:57 +0100646 if (daemon->ipsets && extract_request(header, n, daemon->namebuff, NULL))
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000647 {
Simon Kelley82a14af2014-04-13 20:48:57 +0100648 /* Similar algorithm to search_servers. */
649 struct ipsets *ipset_pos;
650 unsigned int namelen = strlen(daemon->namebuff);
651 unsigned int matchlen = 0;
652 for (ipset_pos = daemon->ipsets; ipset_pos; ipset_pos = ipset_pos->next)
Simon Kelley6c0cb852014-01-17 14:40:46 +0000653 {
Simon Kelley82a14af2014-04-13 20:48:57 +0100654 unsigned int domainlen = strlen(ipset_pos->domain);
655 char *matchstart = daemon->namebuff + namelen - domainlen;
656 if (namelen >= domainlen && hostname_isequal(matchstart, ipset_pos->domain) &&
657 (domainlen == 0 || namelen == domainlen || *(matchstart - 1) == '.' ) &&
658 domainlen >= matchlen)
659 {
660 matchlen = domainlen;
661 sets = ipset_pos->sets;
662 }
Simon Kelley6c0cb852014-01-17 14:40:46 +0000663 }
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000664 }
665#endif
Simon Kelley25e63f12020-11-25 21:17:52 +0000666
Simon Kelley5bb88f02015-12-21 16:23:47 +0000667 if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign, NULL)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100668 {
Simon Kelley07ed5852018-05-04 21:52:22 +0100669 /* Get extended RCODE. */
670 rcode |= sizep[2] << 4;
671
Simon Kelleyed4c0762013-10-08 20:46:34 +0100672 if (check_subnet && !check_source(header, plen, pheader, query_source))
673 {
674 my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch"));
675 return 0;
676 }
Simon Kelley613ad152014-02-25 23:02:28 +0000677
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000678 if (!is_sign)
Simon Kelley613ad152014-02-25 23:02:28 +0000679 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000680 if (added_pheader)
681 {
682 /* client didn't send EDNS0, we added one, strip it off before returning answer. */
683 n = rrfilter(header, n, 0);
684 pheader = NULL;
685 }
686 else
687 {
Simon Kelley33702ab2015-12-28 23:17:15 +0000688 unsigned short udpsz;
689
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000690 /* If upstream is advertising a larger UDP packet size
691 than we allow, trim it so that we don't get overlarge
692 requests for the client. We can't do this for signed packets. */
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000693 GETSHORT(udpsz, sizep);
694 if (udpsz > daemon->edns_pktsz)
Simon Kelley33702ab2015-12-28 23:17:15 +0000695 {
696 sizep -= 2;
697 PUTSHORT(daemon->edns_pktsz, sizep);
698 }
699
700#ifdef HAVE_DNSSEC
701 /* If the client didn't set the do bit, but we did, reset it. */
702 if (option_bool(OPT_DNSSEC_VALID) && !do_bit)
703 {
704 unsigned short flags;
705 sizep += 2; /* skip RCODE */
706 GETSHORT(flags, sizep);
707 flags &= ~0x8000;
708 sizep -= 2;
709 PUTSHORT(flags, sizep);
710 }
711#endif
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000712 }
Simon Kelley613ad152014-02-25 23:02:28 +0000713 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100714 }
Simon Kelley83349b82014-02-10 21:02:01 +0000715
Simon Kelley28866e92011-02-14 20:19:14 +0000716 /* RFC 4035 sect 4.6 para 3 */
Giovanni Bajo237724c2012-04-05 02:46:52 +0200717 if (!is_sign && !option_bool(OPT_DNSSEC_PROXY))
Simon Kelley795501b2014-01-08 18:11:55 +0000718 header->hb4 &= ~HB4_AD;
Simon Kelley3a237152013-12-12 12:15:50 +0000719
Simon Kelley07ed5852018-05-04 21:52:22 +0100720 if (OPCODE(header) != QUERY)
Simon Kelley8938ae02014-05-01 17:46:25 +0100721 return resize_packet(header, n, pheader, plen);
Simon Kelley07ed5852018-05-04 21:52:22 +0100722
723 if (rcode != NOERROR && rcode != NXDOMAIN)
724 {
Simon Kelleycc921df2019-01-02 22:48:59 +0000725 union all_addr a;
726 a.log.rcode = rcode;
Simon Kelley07ed5852018-05-04 21:52:22 +0100727 log_query(F_UPSTREAM | F_RCODE, "error", &a, NULL);
728
729 return resize_packet(header, n, pheader, plen);
730 }
Simon Kelley36717ee2004-09-20 19:20:58 +0100731
Simon Kelley0a852542005-03-23 20:28:59 +0000732 /* Complain loudly if the upstream server is non-recursive. */
Simon Kelley07ed5852018-05-04 21:52:22 +0100733 if (!(header->hb4 & HB4_RA) && rcode == NOERROR &&
Simon Kelley0a852542005-03-23 20:28:59 +0000734 server && !(server->flags & SERV_WARNED_RECURSIVE))
735 {
Petr Mensik51cdd1a2019-07-04 20:28:08 +0200736 (void)prettyprint_addr(&server->addr, daemon->namebuff);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100737 my_syslog(LOG_WARNING, _("nameserver %s refused to do a recursive query"), daemon->namebuff);
Simon Kelley28866e92011-02-14 20:19:14 +0000738 if (!option_bool(OPT_LOG))
Simon Kelley0a852542005-03-23 20:28:59 +0000739 server->flags |= SERV_WARNED_RECURSIVE;
740 }
Giovanni Bajoe292e932012-04-22 14:32:02 +0200741
Simon Kelley07ed5852018-05-04 21:52:22 +0100742 if (daemon->bogus_addr && rcode != NXDOMAIN &&
Simon Kelley9eaa91b2021-03-17 20:31:06 +0000743 check_for_bogus_wildcard(header, n, daemon->namebuff, now))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100744 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100745 munged = 1;
Simon Kelley572b41e2011-02-18 18:11:18 +0000746 SET_RCODE(header, NXDOMAIN);
747 header->hb3 &= ~HB3_AA;
Simon Kelley6938f342014-01-26 22:47:39 +0000748 cache_secure = 0;
Simon Kelley36717ee2004-09-20 19:20:58 +0100749 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100750 else
Simon Kelley36717ee2004-09-20 19:20:58 +0100751 {
Simon Kelley6938f342014-01-26 22:47:39 +0000752 int doctored = 0;
753
Simon Kelley07ed5852018-05-04 21:52:22 +0100754 if (rcode == NXDOMAIN &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100755 extract_request(header, n, daemon->namebuff, NULL) &&
Simon Kelley5aabfc72007-08-29 11:24:47 +0100756 check_for_local_domain(daemon->namebuff, now))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100757 {
Simon Kelley36717ee2004-09-20 19:20:58 +0100758 /* if we forwarded a query for a locally known name (because it was for
759 an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
760 since we know that the domain exists, even if upstream doesn't */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100761 munged = 1;
Simon Kelley572b41e2011-02-18 18:11:18 +0000762 header->hb3 |= HB3_AA;
763 SET_RCODE(header, NOERROR);
Simon Kelley6938f342014-01-26 22:47:39 +0000764 cache_secure = 0;
Simon Kelley36717ee2004-09-20 19:20:58 +0100765 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000766
Simon Kelley373e9172017-12-01 22:40:56 +0000767 if (extract_addresses(header, n, daemon->namebuff, now, sets, is_sign, check_rebind, no_cache, cache_secure, &doctored))
Simon Kelley824af852008-02-12 20:43:05 +0000768 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100769 my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
Simon Kelley824af852008-02-12 20:43:05 +0000770 munged = 1;
Simon Kelley6938f342014-01-26 22:47:39 +0000771 cache_secure = 0;
Simon Kelley824af852008-02-12 20:43:05 +0000772 }
Simon Kelley6938f342014-01-26 22:47:39 +0000773
774 if (doctored)
775 cache_secure = 0;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100776 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100777
Simon Kelleya25720a2014-01-14 23:13:55 +0000778#ifdef HAVE_DNSSEC
Simon Kelley33702ab2015-12-28 23:17:15 +0000779 if (bogusanswer && !(header->hb4 & HB4_CD) && !option_bool(OPT_DNSSEC_DEBUG))
Simon Kelleya25720a2014-01-14 23:13:55 +0000780 {
Simon Kelley33702ab2015-12-28 23:17:15 +0000781 /* Bogus reply, turn into SERVFAIL */
782 SET_RCODE(header, SERVFAIL);
783 munged = 1;
Simon Kelleya25720a2014-01-14 23:13:55 +0000784 }
Simon Kelley6938f342014-01-26 22:47:39 +0000785
786 if (option_bool(OPT_DNSSEC_VALID))
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000787 {
788 header->hb4 &= ~HB4_AD;
789
790 if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure)
791 header->hb4 |= HB4_AD;
792
793 /* If the requestor didn't set the DO bit, don't return DNSSEC info. */
794 if (!do_bit)
795 n = rrfilter(header, n, 1);
796 }
Simon Kelleya25720a2014-01-14 23:13:55 +0000797#endif
798
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100799 /* do this after extract_addresses. Ensure NODATA reply and remove
800 nameserver info. */
801
802 if (munged)
803 {
804 header->ancount = htons(0);
805 header->nscount = htons(0);
806 header->arcount = htons(0);
Simon Kelley150162b2015-03-27 09:58:26 +0000807 header->hb3 &= ~HB3_TC;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100808 }
809
Simon Kelley36717ee2004-09-20 19:20:58 +0100810 /* the bogus-nxdomain stuff, doctor and NXDOMAIN->NODATA munging can all elide
811 sections of the packet. Find the new length here and put back pseudoheader
812 if it was removed. */
813 return resize_packet(header, n, pheader, plen);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100814}
815
Simon Kelley3be34542004-09-11 19:12:13 +0100816/* sets new last_server */
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000817void reply_query(int fd, time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000818{
819 /* packet from peer server, extract data for cache, and send to
820 original requester */
Simon Kelley572b41e2011-02-18 18:11:18 +0000821 struct dns_header *header;
Simon Kelleyde379512004-06-22 20:23:33 +0100822 union mysockaddr serveraddr;
Simon Kelley832af0b2007-01-21 20:01:28 +0000823 struct frec *forward;
Simon Kelleyde379512004-06-22 20:23:33 +0100824 socklen_t addrlen = sizeof(serveraddr);
Simon Kelley60b68062014-01-08 12:10:28 +0000825 ssize_t n = recvfrom(fd, daemon->packet, daemon->packet_buff_sz, 0, &serveraddr.sa, &addrlen);
Simon Kelleycdeda282006-03-16 20:16:06 +0000826 size_t nn;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100827 struct server *server;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000828 void *hash;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000829
Simon Kelleycdeda282006-03-16 20:16:06 +0000830 /* packet buffer overwritten */
831 daemon->srv_save = NULL;
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000832
Simon Kelleyde379512004-06-22 20:23:33 +0100833 /* Determine the address of the server replying so that we can mark that as good */
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000834 if (serveraddr.sa.sa_family == AF_INET6)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100835 serveraddr.in6.sin6_flowinfo = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000836
Simon Kelley490f9072014-03-24 22:04:42 +0000837 header = (struct dns_header *)daemon->packet;
Simon Kelley6b173352018-05-08 18:32:14 +0100838
Simon Kelley490f9072014-03-24 22:04:42 +0000839 if (n < (int)sizeof(struct dns_header) || !(header->hb3 & HB3_QR))
840 return;
841
Simon Kelley1a6bca82008-07-11 11:11:42 +0100842 /* spoof check: answer must come from known server, */
843 for (server = daemon->servers; server; server = server->next)
844 if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) &&
845 sockaddr_isequal(&server->addr, &serveraddr))
846 break;
Simon Kelley490f9072014-03-24 22:04:42 +0000847
848 if (!server)
849 return;
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000850
851 /* If sufficient time has elapsed, try and expand UDP buffer size again. */
852 if (difftime(now, server->pktsz_reduced) > UDP_TEST_TIME)
853 server->edns_pktsz = daemon->edns_pktsz;
854
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000855 hash = hash_questions(header, n, daemon->namebuff);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100856
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000857 if (!(forward = lookup_frec(ntohs(header->id), fd, hash)))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100858 return;
Simon Kelley490f9072014-03-24 22:04:42 +0000859
Simon Kelley6b173352018-05-08 18:32:14 +0100860#ifdef HAVE_DUMPFILE
861 dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_REPLY : DUMP_UP_REPLY,
862 (void *)header, n, &serveraddr, NULL);
863#endif
Simon Kelleya0088e82018-05-10 21:43:14 +0100864
Simon Kelley25cf5e32015-01-09 15:53:03 +0000865 /* log_query gets called indirectly all over the place, so
866 pass these in global variables - sorry. */
Simon Kelley15b60dd2020-11-18 18:34:55 +0000867 daemon->log_display_id = forward->frec_src.log_id;
868 daemon->log_source_addr = &forward->frec_src.source;
Simon Kelley25cf5e32015-01-09 15:53:03 +0000869
Glen Huang32fc6db2014-12-27 15:28:12 +0000870 if (daemon->ignore_addr && RCODE(header) == NOERROR &&
Simon Kelley9eaa91b2021-03-17 20:31:06 +0000871 check_for_ignored_address(header, n))
Glen Huang32fc6db2014-12-27 15:28:12 +0000872 return;
873
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000874 /* Note: if we send extra options in the EDNS0 header, we can't recreate
875 the query from the reply. */
Simon Kelley34e26e12018-05-10 20:54:57 +0100876 if ((RCODE(header) == REFUSED || RCODE(header) == SERVFAIL) &&
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000877 forward->forwardall == 0 &&
878 !(forward->flags & FREC_HAS_EXTRADATA))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100879 /* for broken servers, attempt to send to another one. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000880 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100881 unsigned char *pheader;
882 size_t plen;
883 int is_sign;
Simon Kelleyef3d1372017-12-05 22:37:29 +0000884
Simon Kelley1f60a182018-05-11 16:44:16 +0100885#ifdef HAVE_DNSSEC
Simon Kelleya0088e82018-05-10 21:43:14 +0100886 if (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY))
887 {
Simon Kelley1f60a182018-05-11 16:44:16 +0100888 struct server *start;
889
Simon Kelleya0088e82018-05-10 21:43:14 +0100890 blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
891 plen = forward->stash_len;
892
893 forward->forwardall = 2; /* only retry once */
Simon Kelley1f60a182018-05-11 16:44:16 +0100894 start = forward->sentto;
895
896 /* for non-domain specific servers, see if we can find another to try. */
897 if ((forward->sentto->flags & SERV_TYPE) == 0)
898 while (1)
899 {
900 if (!(start = start->next))
901 start = daemon->servers;
902 if (start == forward->sentto)
903 break;
904
905 if ((start->flags & SERV_TYPE) == 0 &&
906 (start->flags & SERV_DO_DNSSEC))
907 break;
908 }
909
910
Petr Menšík51f7bc92021-03-18 01:05:43 +0100911 if ((fd = allocate_rfd(&forward->rfds, start)) != -1)
912 server_send_log(start, fd, header, plen,
913 DUMP_SEC_QUERY,
914 F_NOEXTRA | F_DNSSEC, "retry", "dnssec");
Simon Kelleya0088e82018-05-10 21:43:14 +0100915 return;
916 }
Simon Kelley1f60a182018-05-11 16:44:16 +0100917#endif
918
Simon Kelleyef3d1372017-12-05 22:37:29 +0000919 /* In strict order mode, there must be a server later in the chain
920 left to send to, otherwise without the forwardall mechanism,
921 code further on will cycle around the list forwever if they
922 all return REFUSED. Note that server is always non-NULL before
923 this executes. */
924 if (option_bool(OPT_ORDER))
925 for (server = forward->sentto->next; server; server = server->next)
926 if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR | SERV_LOOP)))
927 break;
928
Simon Kelley1a6bca82008-07-11 11:11:42 +0100929 /* recreate query from reply */
Simon Kelley5bb88f02015-12-21 16:23:47 +0000930 pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign, NULL);
Simon Kelleyef3d1372017-12-05 22:37:29 +0000931 if (!is_sign && server)
Simon Kelley832af0b2007-01-21 20:01:28 +0000932 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100933 header->ancount = htons(0);
934 header->nscount = htons(0);
935 header->arcount = htons(0);
936 if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
937 {
swiggerbd7bfa22015-06-01 20:54:59 +0100938 header->hb3 &= ~(HB3_QR | HB3_AA | HB3_TC);
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000939 header->hb4 &= ~(HB4_RA | HB4_RCODE | HB4_CD | HB4_AD);
Simon Kelley1801a292016-01-17 21:53:57 +0000940 if (forward->flags & FREC_CHECKING_DISABLED)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000941 header->hb4 |= HB4_CD;
Simon Kelley1801a292016-01-17 21:53:57 +0000942 if (forward->flags & FREC_AD_QUESTION)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000943 header->hb4 |= HB4_AD;
944 if (forward->flags & FREC_DO_QUESTION)
Simon Kelley33702ab2015-12-28 23:17:15 +0000945 add_do_bit(header, nn, (unsigned char *)pheader + plen);
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000946 forward_query(-1, NULL, NULL, 0, header, nn, now, forward, forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100947 return;
948 }
949 }
950 }
Simon Kelley3a237152013-12-12 12:15:50 +0000951
952 server = forward->sentto;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100953 if ((forward->sentto->flags & SERV_TYPE) == 0)
954 {
Simon Kelley51967f92014-03-25 21:07:00 +0000955 if (RCODE(header) == REFUSED)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100956 server = NULL;
957 else
958 {
959 struct server *last_server;
Simon Kelley832af0b2007-01-21 20:01:28 +0000960
Simon Kelley1a6bca82008-07-11 11:11:42 +0100961 /* find good server by address if possible, otherwise assume the last one we sent to */
962 for (last_server = daemon->servers; last_server; last_server = last_server->next)
963 if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) &&
964 sockaddr_isequal(&last_server->addr, &serveraddr))
965 {
966 server = last_server;
967 break;
968 }
969 }
Simon Kelley28866e92011-02-14 20:19:14 +0000970 if (!option_bool(OPT_ALL_SERVERS))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100971 daemon->last_server = server;
972 }
Simon Kelleya77cec82015-05-08 16:25:38 +0100973
974 /* We tried resending to this server with a smaller maximum size and got an answer.
Ville Skyttäfaaf3062018-01-14 17:32:52 +0000975 Make that permanent. To avoid reduxing the packet size for a single dropped packet,
Simon Kelley86fa1042015-05-10 13:50:59 +0100976 only do this when we get a truncated answer, or one larger than the safe size. */
Simon Kelley04db1482019-10-11 23:22:17 +0100977 if (forward->sentto->edns_pktsz > SAFE_PKTSZ && (forward->flags & FREC_TEST_PKTSZ) &&
Simon Kelley86fa1042015-05-10 13:50:59 +0100978 ((header->hb3 & HB3_TC) || n >= SAFE_PKTSZ))
Simon Kelley22dee512017-10-13 22:54:00 +0100979 {
Simon Kelley04db1482019-10-11 23:22:17 +0100980 forward->sentto->edns_pktsz = SAFE_PKTSZ;
981 forward->sentto->pktsz_reduced = now;
Petr Mensik51cdd1a2019-07-04 20:28:08 +0200982 (void)prettyprint_addr(&forward->sentto->addr, daemon->addrbuff);
Simon Kelleyebedcba2017-10-29 20:54:17 +0000983 my_syslog(LOG_WARNING, _("reducing DNS packet size for nameserver %s to %d"), daemon->addrbuff, SAFE_PKTSZ);
Simon Kelley22dee512017-10-13 22:54:00 +0100984 }
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000985
986
Simon Kelley1a6bca82008-07-11 11:11:42 +0100987 /* If the answer is an error, keep the forward record in place in case
988 we get a good reply from another server. Kill it when we've
989 had replies from all to avoid filling the forwarding table when
990 everything is broken */
Simon Kelley122392e2018-10-31 22:24:02 +0000991 if (forward->forwardall == 0 || --forward->forwardall == 1 || RCODE(header) != REFUSED)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100992 {
Simon Kelleyfe3992f2015-04-03 21:25:05 +0100993 int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
Simon Kelleya6004d72017-10-25 17:48:19 +0100994
Simon Kelley3a237152013-12-12 12:15:50 +0000995 if (option_bool(OPT_NO_REBIND))
996 check_rebind = !(forward->flags & FREC_NOREBIND);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100997
Simon Kelley3a237152013-12-12 12:15:50 +0000998 /* Don't cache replies where DNSSEC validation was turned off, either
999 the upstream server told us so, or the original query specified it. */
1000 if ((header->hb4 & HB4_CD) || (forward->flags & FREC_CHECKING_DISABLED))
1001 no_cache_dnssec = 1;
1002
1003#ifdef HAVE_DNSSEC
Simon Kelley04db1482019-10-11 23:22:17 +01001004 if ((forward->sentto->flags & SERV_DO_DNSSEC) &&
Simon Kelley57573712016-01-11 22:50:00 +00001005 option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED))
Simon Kelley3a237152013-12-12 12:15:50 +00001006 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001007 int status = 0;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001008
1009 /* We've had a reply already, which we're validating. Ignore this duplicate */
Simon Kelleye0c0ad32014-01-16 22:42:07 +00001010 if (forward->blocking_query)
Simon Kelley0fc2f312014-01-08 10:26:58 +00001011 return;
Simon Kelley9a31b682015-12-15 10:20:39 +00001012
1013 /* Truncated answer can't be validated.
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001014 If this is an answer to a DNSSEC-generated query, we still
1015 need to get the client to retry over TCP, so return
1016 an answer with the TC bit set, even if the actual answer fits.
1017 */
Simon Kelley9a31b682015-12-15 10:20:39 +00001018 if (header->hb3 & HB3_TC)
1019 status = STAT_TRUNCATED;
1020
1021 while (1)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001022 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001023 /* As soon as anything returns BOGUS, we stop and unwind, to do otherwise
1024 would invite infinite loops, since the answers to DNSKEY and DS queries
1025 will not be cached, so they'll be repeated. */
1026 if (status != STAT_BOGUS && status != STAT_TRUNCATED && status != STAT_ABANDONED)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001027 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001028 if (forward->flags & FREC_DNSKEY_QUERY)
1029 status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
1030 else if (forward->flags & FREC_DS_QUERY)
1031 status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001032 else
Simon Kelley9a31b682015-12-15 10:20:39 +00001033 status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class,
Simon Kelley203ce0a2019-10-12 21:41:20 +01001034 !option_bool(OPT_DNSSEC_IGN_NS) && (forward->sentto->flags & SERV_DO_DNSSEC),
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001035 NULL, NULL, NULL);
Simon Kelley6b173352018-05-08 18:32:14 +01001036#ifdef HAVE_DUMPFILE
1037 if (status == STAT_BOGUS)
1038 dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_BOGUS : DUMP_BOGUS,
1039 header, (size_t)n, &serveraddr, NULL);
1040#endif
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001041 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001042
Simon Kelley9a31b682015-12-15 10:20:39 +00001043 /* Can't validate, as we're missing key data. Put this
1044 answer aside, whilst we get that. */
1045 if (status == STAT_NEED_DS || status == STAT_NEED_KEY)
Simon Kelley3a237152013-12-12 12:15:50 +00001046 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001047 struct frec *new, *orig;
Simon Kelley9d633042013-12-13 15:36:55 +00001048
Simon Kelley9a31b682015-12-15 10:20:39 +00001049 /* Free any saved query */
1050 if (forward->stash)
1051 blockdata_free(forward->stash);
1052
1053 /* Now save reply pending receipt of key data */
1054 if (!(forward->stash = blockdata_alloc((char *)header, n)))
Simon Kelley97e618a2015-01-07 21:55:43 +00001055 return;
Simon Kelley9a31b682015-12-15 10:20:39 +00001056 forward->stash_len = n;
Simon Kelleye0c0ad32014-01-16 22:42:07 +00001057
Simon Kelley9a31b682015-12-15 10:20:39 +00001058 /* Find the original query that started it all.... */
1059 for (orig = forward; orig->dependent; orig = orig->dependent);
Simon Kelley7fa836e2014-02-10 20:11:24 +00001060
Simon Kelley8caf3d72020-04-04 17:00:32 +01001061 /* Make sure we don't expire and free the orig frec during the
1062 allocation of a new one. */
1063 if (--orig->work_counter == 0 || !(new = get_new_frec(now, NULL, orig)))
Simon Kelley9a31b682015-12-15 10:20:39 +00001064 status = STAT_ABANDONED;
Simon Kelleye0c0ad32014-01-16 22:42:07 +00001065 else
Simon Kelley3a237152013-12-12 12:15:50 +00001066 {
Simon Kelleye1791f32018-10-06 23:23:23 +01001067 int querytype, fd, type = SERV_DO_DNSSEC;
Simon Kelley9a31b682015-12-15 10:20:39 +00001068 struct frec *next = new->next;
Simon Kelley92be34a2016-01-16 18:39:54 +00001069 char *domain;
1070
Simon Kelley9a31b682015-12-15 10:20:39 +00001071 *new = *forward; /* copy everything, then overwrite */
1072 new->next = next;
1073 new->blocking_query = NULL;
Simon Kelley92be34a2016-01-16 18:39:54 +00001074
1075 /* Find server to forward to. This will normally be the
1076 same as for the original query, but may be another if
1077 servers for domains are involved. */
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001078 if (search_servers(now, NULL, F_DNSSECOK, daemon->keyname, &type, &domain, NULL) == 0)
Simon Kelley92be34a2016-01-16 18:39:54 +00001079 {
Simon Kelley203ce0a2019-10-12 21:41:20 +01001080 struct server *start, *new_server = NULL;
1081 start = server = forward->sentto;
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001082
1083 while (1)
1084 {
Petr Menšík8f9bd612021-03-27 23:16:09 +00001085 if (server_test_type(start, domain, type, SERV_DO_DNSSEC))
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001086 {
1087 new_server = start;
1088 if (server == start)
1089 {
1090 new_server = NULL;
1091 break;
1092 }
1093 }
1094
1095 if (!(start = start->next))
1096 start = daemon->servers;
1097 if (start == server)
1098 break;
1099 }
1100
1101 if (new_server)
1102 server = new_server;
Simon Kelley92be34a2016-01-16 18:39:54 +00001103 }
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001104
Simon Kelley9a31b682015-12-15 10:20:39 +00001105 new->sentto = server;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00001106 new->rfds = NULL;
Simon Kelley15b60dd2020-11-18 18:34:55 +00001107 new->frec_src.next = NULL;
Simon Kelleya0088e82018-05-10 21:43:14 +01001108 new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_HAS_EXTRADATA);
1109 new->forwardall = 0;
Simon Kelley9a31b682015-12-15 10:20:39 +00001110
1111 new->dependent = forward; /* to find query awaiting new one. */
1112 forward->blocking_query = new; /* for garbage cleaning */
1113 /* validate routines leave name of required record in daemon->keyname */
1114 if (status == STAT_NEED_KEY)
Simon Kelley7fa836e2014-02-10 20:11:24 +00001115 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001116 new->flags |= FREC_DNSKEY_QUERY;
Simon Kelleye1791f32018-10-06 23:23:23 +01001117 querytype = T_DNSKEY;
Simon Kelleyf1668d22014-01-08 16:53:27 +00001118 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001119 else
1120 {
1121 new->flags |= FREC_DS_QUERY;
Simon Kelleye1791f32018-10-06 23:23:23 +01001122 querytype = T_DS;
Simon Kelley9a31b682015-12-15 10:20:39 +00001123 }
Simon Kelleye1791f32018-10-06 23:23:23 +01001124
1125 nn = dnssec_generate_query(header,((unsigned char *) header) + server->edns_pktsz,
1126 daemon->keyname, forward->class, querytype, server->edns_pktsz);
1127
Simon Kelley2d765862020-11-12 22:06:07 +00001128 memcpy(new->hash, hash_questions(header, nn, daemon->namebuff), HASH_SIZE);
Simon Kelley9a31b682015-12-15 10:20:39 +00001129 new->new_id = get_id();
1130 header->id = htons(new->new_id);
1131 /* Save query for retransmission */
1132 new->stash = blockdata_alloc((char *)header, nn);
1133 new->stash_len = nn;
1134
1135 /* Don't resend this. */
1136 daemon->srv_save = NULL;
1137
Simon Kelley74d4fcd2021-03-15 21:59:51 +00001138 if ((fd = allocate_rfd(&new->rfds, server)) != -1)
Simon Kelley9a31b682015-12-15 10:20:39 +00001139 {
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001140#ifdef HAVE_CONNTRACK
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001141 if (option_bool(OPT_CONNTRACK))
Petr Menšík6c0bf792021-03-18 00:07:45 +01001142 set_outgoing_mark(orig, fd);
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001143#endif
Petr Menšík51f7bc92021-03-18 01:05:43 +01001144 server_send_log(server, fd, header, nn, DUMP_SEC_QUERY,
1145 F_NOEXTRA | F_DNSSEC, daemon->keyname,
1146 querystr("dnssec-query", querytype));
Simon Kelley9a31b682015-12-15 10:20:39 +00001147 server->queries++;
1148 }
1149 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00001150 return;
Simon Kelley3a237152013-12-12 12:15:50 +00001151 }
Simon Kelley3a237152013-12-12 12:15:50 +00001152
Simon Kelley9a31b682015-12-15 10:20:39 +00001153 /* Validated original answer, all done. */
1154 if (!forward->dependent)
1155 break;
1156
Josh Soref730c6742017-02-06 16:14:04 +00001157 /* validated subsidiary query, (and cached result)
Simon Kelley9a31b682015-12-15 10:20:39 +00001158 pop that and return to the previous query we were working on. */
Simon Kelley0744ca62014-01-25 16:40:15 +00001159 struct frec *prev = forward->dependent;
1160 free_frec(forward);
1161 forward = prev;
1162 forward->blocking_query = NULL; /* already gone */
1163 blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
1164 n = forward->stash_len;
Simon Kelley3a237152013-12-12 12:15:50 +00001165 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001166
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001167
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001168 no_cache_dnssec = 0;
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001169
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001170 if (status == STAT_TRUNCATED)
Simon Kelley0744ca62014-01-25 16:40:15 +00001171 header->hb3 |= HB3_TC;
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001172 else
Simon Kelley7fa836e2014-02-10 20:11:24 +00001173 {
Simon Kelley554b5802015-04-17 22:50:20 +01001174 char *result, *domain = "result";
Simon Kelley7fa836e2014-02-10 20:11:24 +00001175
Simon Kelley9a31b682015-12-15 10:20:39 +00001176 if (status == STAT_ABANDONED)
Simon Kelley150162b2015-03-27 09:58:26 +00001177 {
1178 result = "ABANDONED";
1179 status = STAT_BOGUS;
1180 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00001181 else
1182 result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
1183
Simon Kelley554b5802015-04-17 22:50:20 +01001184 if (status == STAT_BOGUS && extract_request(header, n, daemon->namebuff, NULL))
1185 domain = daemon->namebuff;
Simon Kelley9a31b682015-12-15 10:20:39 +00001186
Simon Kelley07ed5852018-05-04 21:52:22 +01001187 log_query(F_SECSTAT, domain, NULL, result);
Simon Kelley7fa836e2014-02-10 20:11:24 +00001188 }
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001189
Simon Kelley3a237152013-12-12 12:15:50 +00001190 if (status == STAT_SECURE)
1191 cache_secure = 1;
Simon Kelley3a237152013-12-12 12:15:50 +00001192 else if (status == STAT_BOGUS)
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001193 {
1194 no_cache_dnssec = 1;
1195 bogusanswer = 1;
1196 }
Simon Kelley3a237152013-12-12 12:15:50 +00001197 }
Simon Kelley04db1482019-10-11 23:22:17 +01001198
Simon Kelley6b173352018-05-08 18:32:14 +01001199#endif
1200
Simon Kelley83349b82014-02-10 21:02:01 +00001201 /* restore CD bit to the value in the query */
1202 if (forward->flags & FREC_CHECKING_DISABLED)
1203 header->hb4 |= HB4_CD;
1204 else
1205 header->hb4 &= ~HB4_CD;
Simon Kelley25e63f12020-11-25 21:17:52 +00001206
1207 /* Never cache answers which are contingent on the source or MAC address EDSN0 option,
1208 since the cache is ignorant of such things. */
1209 if (forward->flags & FREC_NO_CACHE)
1210 no_cache_dnssec = 1;
Simon Kelley3a237152013-12-12 12:15:50 +00001211
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001212 if ((nn = process_reply(header, now, forward->sentto, (size_t)n, check_rebind, no_cache_dnssec, cache_secure, bogusanswer,
Simon Kelley613ad152014-02-25 23:02:28 +00001213 forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION,
Simon Kelley15b60dd2020-11-18 18:34:55 +00001214 forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->frec_src.source)))
Simon Kelley832af0b2007-01-21 20:01:28 +00001215 {
Simon Kelley15b60dd2020-11-18 18:34:55 +00001216 struct frec_src *src;
1217
1218 header->id = htons(forward->frec_src.orig_id);
Simon Kelley572b41e2011-02-18 18:11:18 +00001219 header->hb4 |= HB4_RA; /* recursion if available */
Simon Kelley5aa5f0f2015-12-21 17:20:35 +00001220#ifdef HAVE_DNSSEC
1221 /* We added an EDNSO header for the purpose of getting DNSSEC RRs, and set the value of the UDP payload size
Simon Kelley6fd5d792017-10-13 22:26:40 +01001222 greater than the no-EDNS0-implied 512 to have space for the RRSIGS. If, having stripped them and the EDNS0
Simon Kelley5aa5f0f2015-12-21 17:20:35 +00001223 header, the answer is still bigger than 512, truncate it and mark it so. The client then retries with TCP. */
1224 if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER) && (nn > PACKETSZ))
1225 {
1226 header->ancount = htons(0);
1227 header->nscount = htons(0);
1228 header->arcount = htons(0);
1229 header->hb3 |= HB3_TC;
1230 nn = resize_packet(header, nn, NULL, 0);
1231 }
1232#endif
Simon Kelley6b173352018-05-08 18:32:14 +01001233
Simon Kelley15b60dd2020-11-18 18:34:55 +00001234 for (src = &forward->frec_src; src; src = src->next)
1235 {
1236 header->id = htons(src->orig_id);
1237
Simon Kelley6b173352018-05-08 18:32:14 +01001238#ifdef HAVE_DUMPFILE
Simon Kelley15b60dd2020-11-18 18:34:55 +00001239 dump_packet(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &src->source);
Simon Kelley6b173352018-05-08 18:32:14 +01001240#endif
Simon Kelley15b60dd2020-11-18 18:34:55 +00001241
Simon Kelley04490bf2021-01-22 16:49:12 +00001242 send_from(src->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
Simon Kelley15b60dd2020-11-18 18:34:55 +00001243 &src->source, &src->dest, src->iface);
1244
1245 if (option_bool(OPT_EXTRALOG) && src != &forward->frec_src)
1246 {
1247 daemon->log_display_id = src->log_id;
1248 daemon->log_source_addr = &src->source;
1249 log_query(F_UPSTREAM, "query", NULL, "duplicate");
1250 }
1251 }
Simon Kelley832af0b2007-01-21 20:01:28 +00001252 }
Simon Kelley15b60dd2020-11-18 18:34:55 +00001253
Simon Kelley1a6bca82008-07-11 11:11:42 +01001254 free_frec(forward); /* cancel */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001255 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001256}
Simon Kelley44a2a312004-03-10 20:04:35 +00001257
Simon Kelley1a6bca82008-07-11 11:11:42 +01001258
Simon Kelley5aabfc72007-08-29 11:24:47 +01001259void receive_query(struct listener *listen, time_t now)
Simon Kelley44a2a312004-03-10 20:04:35 +00001260{
Simon Kelley572b41e2011-02-18 18:11:18 +00001261 struct dns_header *header = (struct dns_header *)daemon->packet;
Simon Kelley44a2a312004-03-10 20:04:35 +00001262 union mysockaddr source_addr;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001263 unsigned char *pheader;
1264 unsigned short type, udp_size = PACKETSZ; /* default if no EDNS0 */
Simon Kelleycc921df2019-01-02 22:48:59 +00001265 union all_addr dst_addr;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001266 struct in_addr netmask, dst_addr_4;
Simon Kelleycdeda282006-03-16 20:16:06 +00001267 size_t m;
1268 ssize_t n;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001269 int if_index = 0, auth_dns = 0, do_bit = 0, have_pseudoheader = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001270#ifdef HAVE_AUTH
1271 int local_auth = 0;
1272#endif
Simon Kelley44a2a312004-03-10 20:04:35 +00001273 struct iovec iov[1];
1274 struct msghdr msg;
1275 struct cmsghdr *cmptr;
Simon Kelley44a2a312004-03-10 20:04:35 +00001276 union {
1277 struct cmsghdr align; /* this ensures alignment */
Simon Kelley44a2a312004-03-10 20:04:35 +00001278 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001279#if defined(HAVE_LINUX_NETWORK)
Simon Kelley44a2a312004-03-10 20:04:35 +00001280 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
Simon Kelley824af852008-02-12 20:43:05 +00001281#elif defined(IP_RECVDSTADDR) && defined(HAVE_SOLARIS_NETWORK)
1282 char control[CMSG_SPACE(sizeof(struct in_addr)) +
1283 CMSG_SPACE(sizeof(unsigned int))];
Simon Kelley44a2a312004-03-10 20:04:35 +00001284#elif defined(IP_RECVDSTADDR)
1285 char control[CMSG_SPACE(sizeof(struct in_addr)) +
1286 CMSG_SPACE(sizeof(struct sockaddr_dl))];
1287#endif
1288 } control_u;
Petr Menšík1c1b9252019-07-15 17:16:44 +02001289 int family = listen->addr.sa.sa_family;
Simon Kelley2329bef2013-12-03 13:41:16 +00001290 /* Can always get recvd interface for IPv6 */
Petr Menšík1c1b9252019-07-15 17:16:44 +02001291 int check_dst = !option_bool(OPT_NOWILD) || family == AF_INET6;
Simon Kelley2329bef2013-12-03 13:41:16 +00001292
Simon Kelleycdeda282006-03-16 20:16:06 +00001293 /* packet buffer overwritten */
1294 daemon->srv_save = NULL;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00001295
Simon Kelleycc921df2019-01-02 22:48:59 +00001296 dst_addr_4.s_addr = dst_addr.addr4.s_addr = 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001297 netmask.s_addr = 0;
1298
Simon Kelley7e5664b2013-04-05 16:57:41 +01001299 if (option_bool(OPT_NOWILD) && listen->iface)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001300 {
Simon Kelley4f7b3042012-11-28 21:27:02 +00001301 auth_dns = listen->iface->dns_auth;
1302
Petr Menšík1c1b9252019-07-15 17:16:44 +02001303 if (family == AF_INET)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001304 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001305 dst_addr_4 = dst_addr.addr4 = listen->iface->addr.in.sin_addr;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001306 netmask = listen->iface->netmask;
1307 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001308 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00001309
Simon Kelley3be34542004-09-11 19:12:13 +01001310 iov[0].iov_base = daemon->packet;
1311 iov[0].iov_len = daemon->edns_pktsz;
Simon Kelley44a2a312004-03-10 20:04:35 +00001312
1313 msg.msg_control = control_u.control;
1314 msg.msg_controllen = sizeof(control_u);
1315 msg.msg_flags = 0;
1316 msg.msg_name = &source_addr;
1317 msg.msg_namelen = sizeof(source_addr);
1318 msg.msg_iov = iov;
1319 msg.msg_iovlen = 1;
1320
Simon Kelleyde379512004-06-22 20:23:33 +01001321 if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
Simon Kelley3be34542004-09-11 19:12:13 +01001322 return;
Simon Kelley44a2a312004-03-10 20:04:35 +00001323
Simon Kelley572b41e2011-02-18 18:11:18 +00001324 if (n < (int)sizeof(struct dns_header) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001325 (msg.msg_flags & MSG_TRUNC) ||
Simon Kelley572b41e2011-02-18 18:11:18 +00001326 (header->hb3 & HB3_QR))
Simon Kelley3be34542004-09-11 19:12:13 +01001327 return;
Simon Kelley63437ff2017-09-06 22:34:21 +01001328
1329 /* Clear buffer beyond request to avoid risk of
1330 information disclosure. */
1331 memset(daemon->packet + n, 0, daemon->edns_pktsz - n);
Simon Kelley44a2a312004-03-10 20:04:35 +00001332
Petr Menšík1c1b9252019-07-15 17:16:44 +02001333 source_addr.sa.sa_family = family;
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001334
Petr Menšík1c1b9252019-07-15 17:16:44 +02001335 if (family == AF_INET)
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001336 {
1337 /* Source-port == 0 is an error, we can't send back to that.
1338 http://www.ietf.org/mail-archive/web/dnsop/current/msg11441.html */
1339 if (source_addr.in.sin_port == 0)
1340 return;
1341 }
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001342 else
1343 {
1344 /* Source-port == 0 is an error, we can't send back to that. */
1345 if (source_addr.in6.sin6_port == 0)
1346 return;
1347 source_addr.in6.sin6_flowinfo = 0;
1348 }
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001349
Simon Kelleyc8a80482014-03-05 14:29:54 +00001350 /* We can be configured to only accept queries from at-most-one-hop-away addresses. */
1351 if (option_bool(OPT_LOCAL_SERVICE))
1352 {
1353 struct addrlist *addr;
Simon Kelleyee875042018-10-23 22:10:17 +01001354
Petr Menšík1c1b9252019-07-15 17:16:44 +02001355 if (family == AF_INET6)
Simon Kelleyc8a80482014-03-05 14:29:54 +00001356 {
1357 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1358 if ((addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001359 is_same_net6(&addr->addr.addr6, &source_addr.in6.sin6_addr, addr->prefixlen))
Simon Kelleyc8a80482014-03-05 14:29:54 +00001360 break;
1361 }
1362 else
Simon Kelleyc8a80482014-03-05 14:29:54 +00001363 {
1364 struct in_addr netmask;
1365 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1366 {
Richard Genoud15b1b7e2014-09-17 21:12:00 +01001367 netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
Simon Kelleyc8a80482014-03-05 14:29:54 +00001368 if (!(addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001369 is_same_net(addr->addr.addr4, source_addr.in.sin_addr, netmask))
Simon Kelleyc8a80482014-03-05 14:29:54 +00001370 break;
1371 }
1372 }
1373 if (!addr)
1374 {
Simon Kelley0c8584e2014-03-12 20:12:56 +00001375 static int warned = 0;
1376 if (!warned)
1377 {
1378 my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
1379 warned = 1;
1380 }
Simon Kelleyc8a80482014-03-05 14:29:54 +00001381 return;
1382 }
1383 }
1384
Simon Kelley2329bef2013-12-03 13:41:16 +00001385 if (check_dst)
Simon Kelley44a2a312004-03-10 20:04:35 +00001386 {
Simon Kelley8a911cc2004-03-16 18:35:52 +00001387 struct ifreq ifr;
1388
Simon Kelley26128d22004-11-14 16:43:54 +00001389 if (msg.msg_controllen < sizeof(struct cmsghdr))
1390 return;
1391
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001392#if defined(HAVE_LINUX_NETWORK)
Petr Menšík1c1b9252019-07-15 17:16:44 +02001393 if (family == AF_INET)
Simon Kelley26128d22004-11-14 16:43:54 +00001394 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelleyc72daea2012-01-05 21:33:27 +00001395 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
Simon Kelley26128d22004-11-14 16:43:54 +00001396 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001397 union {
1398 unsigned char *c;
1399 struct in_pktinfo *p;
1400 } p;
1401 p.c = CMSG_DATA(cmptr);
Simon Kelleycc921df2019-01-02 22:48:59 +00001402 dst_addr_4 = dst_addr.addr4 = p.p->ipi_spec_dst;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001403 if_index = p.p->ipi_ifindex;
Simon Kelley26128d22004-11-14 16:43:54 +00001404 }
1405#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
Petr Menšík1c1b9252019-07-15 17:16:44 +02001406 if (family == AF_INET)
Simon Kelley26128d22004-11-14 16:43:54 +00001407 {
1408 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001409 {
1410 union {
1411 unsigned char *c;
1412 unsigned int *i;
1413 struct in_addr *a;
1414#ifndef HAVE_SOLARIS_NETWORK
1415 struct sockaddr_dl *s;
Simon Kelley824af852008-02-12 20:43:05 +00001416#endif
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001417 } p;
1418 p.c = CMSG_DATA(cmptr);
1419 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
Simon Kelleycc921df2019-01-02 22:48:59 +00001420 dst_addr_4 = dst_addr.addr4 = *(p.a);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001421 else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
1422#ifdef HAVE_SOLARIS_NETWORK
1423 if_index = *(p.i);
1424#else
1425 if_index = p.s->sdl_index;
1426#endif
1427 }
Simon Kelley26128d22004-11-14 16:43:54 +00001428 }
1429#endif
1430
Petr Menšík1c1b9252019-07-15 17:16:44 +02001431 if (family == AF_INET6)
Simon Kelley26128d22004-11-14 16:43:54 +00001432 {
1433 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelleyc72daea2012-01-05 21:33:27 +00001434 if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
Simon Kelley26128d22004-11-14 16:43:54 +00001435 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001436 union {
1437 unsigned char *c;
1438 struct in6_pktinfo *p;
1439 } p;
1440 p.c = CMSG_DATA(cmptr);
1441
Simon Kelleycc921df2019-01-02 22:48:59 +00001442 dst_addr.addr6 = p.p->ipi6_addr;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001443 if_index = p.p->ipi6_ifindex;
Simon Kelley26128d22004-11-14 16:43:54 +00001444 }
1445 }
Simon Kelley26128d22004-11-14 16:43:54 +00001446
1447 /* enforce available interface configuration */
1448
Simon Kelleye25db1f2013-01-29 22:10:26 +00001449 if (!indextoname(listen->fd, if_index, ifr.ifr_name))
Simon Kelley832af0b2007-01-21 20:01:28 +00001450 return;
1451
Petr Menšík1c1b9252019-07-15 17:16:44 +02001452 if (!iface_check(family, &dst_addr, ifr.ifr_name, &auth_dns))
Simon Kelleye25db1f2013-01-29 22:10:26 +00001453 {
1454 if (!option_bool(OPT_CLEVERBIND))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001455 enumerate_interfaces(0);
Petr Menšík1c1b9252019-07-15 17:16:44 +02001456 if (!loopback_exception(listen->fd, family, &dst_addr, ifr.ifr_name) &&
1457 !label_exception(if_index, family, &dst_addr))
Simon Kelleye25db1f2013-01-29 22:10:26 +00001458 return;
1459 }
1460
Petr Menšík1c1b9252019-07-15 17:16:44 +02001461 if (family == AF_INET && option_bool(OPT_LOCALISE))
Simon Kelley552af8b2012-02-29 20:10:31 +00001462 {
1463 struct irec *iface;
1464
Josh Soref730c6742017-02-06 16:14:04 +00001465 /* get the netmask of the interface which has the address we were sent to.
klemens43517fc2017-02-19 15:53:37 +00001466 This is no necessarily the interface we arrived on. */
Simon Kelley552af8b2012-02-29 20:10:31 +00001467
1468 for (iface = daemon->interfaces; iface; iface = iface->next)
1469 if (iface->addr.sa.sa_family == AF_INET &&
1470 iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
1471 break;
1472
1473 /* interface may be new */
Simon Kelleye25db1f2013-01-29 22:10:26 +00001474 if (!iface && !option_bool(OPT_CLEVERBIND))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001475 enumerate_interfaces(0);
Simon Kelley552af8b2012-02-29 20:10:31 +00001476
1477 for (iface = daemon->interfaces; iface; iface = iface->next)
1478 if (iface->addr.sa.sa_family == AF_INET &&
1479 iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
1480 break;
1481
1482 /* If we failed, abandon localisation */
1483 if (iface)
1484 netmask = iface->netmask;
1485 else
1486 dst_addr_4.s_addr = 0;
1487 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001488 }
Simon Kelley25cf5e32015-01-09 15:53:03 +00001489
1490 /* log_query gets called indirectly all over the place, so
1491 pass these in global variables - sorry. */
1492 daemon->log_display_id = ++daemon->log_id;
1493 daemon->log_source_addr = &source_addr;
Simon Kelley6b173352018-05-08 18:32:14 +01001494
1495#ifdef HAVE_DUMPFILE
1496 dump_packet(DUMP_QUERY, daemon->packet, (size_t)n, &source_addr, NULL);
1497#endif
1498
Simon Kelleycdeda282006-03-16 20:16:06 +00001499 if (extract_request(header, (size_t)n, daemon->namebuff, &type))
Simon Kelley44a2a312004-03-10 20:04:35 +00001500 {
Simon Kelleyb485ed92013-10-18 22:00:39 +01001501#ifdef HAVE_AUTH
1502 struct auth_zone *zone;
1503#endif
Simon Kelley610e7822014-02-06 14:45:17 +00001504 char *types = querystr(auth_dns ? "auth" : "query", type);
Petr Menšík6c0bf792021-03-18 00:07:45 +01001505
1506 log_query_mysockaddr(F_QUERY | F_FORWARD, daemon->namebuff,
1507 &source_addr, types);
Simon Kelley44a2a312004-03-10 20:04:35 +00001508
Simon Kelley4820dce2012-12-18 18:30:30 +00001509#ifdef HAVE_AUTH
Simon Kelleyb485ed92013-10-18 22:00:39 +01001510 /* find queries for zones we're authoritative for, and answer them directly */
Simon Kelley3a3965a2015-08-09 17:45:06 +01001511 if (!auth_dns && !option_bool(OPT_LOCALISE))
Simon Kelley6008bdb2013-10-21 21:47:03 +01001512 for (zone = daemon->auth_zones; zone; zone = zone->next)
1513 if (in_zone(zone, daemon->namebuff, NULL))
1514 {
1515 auth_dns = 1;
1516 local_auth = 1;
1517 break;
1518 }
Simon Kelleyb485ed92013-10-18 22:00:39 +01001519#endif
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01001520
1521#ifdef HAVE_LOOP
1522 /* Check for forwarding loop */
1523 if (detect_loop(daemon->namebuff, type))
1524 return;
1525#endif
Simon Kelleyb485ed92013-10-18 22:00:39 +01001526 }
1527
Simon Kelley5bb88f02015-12-21 16:23:47 +00001528 if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL, NULL))
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001529 {
1530 unsigned short flags;
1531
1532 have_pseudoheader = 1;
1533 GETSHORT(udp_size, pheader);
1534 pheader += 2; /* ext_rcode */
1535 GETSHORT(flags, pheader);
1536
1537 if (flags & 0x8000)
1538 do_bit = 1;/* do bit */
1539
1540 /* If the client provides an EDNS0 UDP size, use that to limit our reply.
1541 (bounded by the maximum configured). If no EDNS0, then it
1542 defaults to 512 */
1543 if (udp_size > daemon->edns_pktsz)
1544 udp_size = daemon->edns_pktsz;
Simon Kelleya3303e12017-09-07 20:45:00 +01001545 else if (udp_size < PACKETSZ)
1546 udp_size = PACKETSZ; /* Sanity check - can't reduce below default. RFC 6891 6.2.3 */
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001547 }
1548
Simon Kelleyb485ed92013-10-18 22:00:39 +01001549#ifdef HAVE_AUTH
Simon Kelley4f7b3042012-11-28 21:27:02 +00001550 if (auth_dns)
Simon Kelley824af852008-02-12 20:43:05 +00001551 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001552 m = answer_auth(header, ((char *) header) + udp_size, (size_t)n, now, &source_addr,
1553 local_auth, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001554 if (m >= 1)
Simon Kelleyb485ed92013-10-18 22:00:39 +01001555 {
1556 send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
1557 (char *)header, m, &source_addr, &dst_addr, if_index);
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001558 daemon->metrics[METRIC_DNS_AUTH_ANSWERED]++;
Simon Kelleyb485ed92013-10-18 22:00:39 +01001559 }
Simon Kelley824af852008-02-12 20:43:05 +00001560 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001561 else
Simon Kelley4820dce2012-12-18 18:30:30 +00001562#endif
Simon Kelley4f7b3042012-11-28 21:27:02 +00001563 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001564 int ad_reqd = do_bit;
1565 /* RFC 6840 5.7 */
1566 if (header->hb4 & HB4_AD)
1567 ad_reqd = 1;
1568
1569 m = answer_request(header, ((char *) header) + udp_size, (size_t)n,
1570 dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001571
1572 if (m >= 1)
1573 {
1574 send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
1575 (char *)header, m, &source_addr, &dst_addr, if_index);
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001576 daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001577 }
1578 else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
Simon Kelley613ad152014-02-25 23:02:28 +00001579 header, (size_t)n, now, NULL, ad_reqd, do_bit))
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001580 daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]++;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001581 else
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001582 daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001583 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001584}
1585
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001586#ifdef HAVE_DNSSEC
Josh Soref730c6742017-02-06 16:14:04 +00001587/* Recurse up the key hierarchy */
Simon Kelley7fa836e2014-02-10 20:11:24 +00001588static int tcp_key_recurse(time_t now, int status, struct dns_header *header, size_t n,
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001589 int class, char *name, char *keyname, struct server *server,
1590 int have_mark, unsigned int mark, int *keycount)
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001591{
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001592 int new_status;
Simon Kelley9a31b682015-12-15 10:20:39 +00001593 unsigned char *packet = NULL;
Simon Kelley9a31b682015-12-15 10:20:39 +00001594 unsigned char *payload = NULL;
1595 struct dns_header *new_header = NULL;
1596 u16 *length = NULL;
Simon Kelley361dfe52017-02-10 21:12:30 +00001597
Simon Kelley9a31b682015-12-15 10:20:39 +00001598 while (1)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001599 {
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001600 int type = SERV_DO_DNSSEC;
1601 char *domain;
1602 size_t m;
1603 unsigned char c1, c2;
Simon Kelley361dfe52017-02-10 21:12:30 +00001604 struct server *firstsendto = NULL;
1605
Simon Kelley9a31b682015-12-15 10:20:39 +00001606 /* limit the amount of work we do, to avoid cycling forever on loops in the DNS */
1607 if (--(*keycount) == 0)
1608 new_status = STAT_ABANDONED;
1609 else if (status == STAT_NEED_KEY)
1610 new_status = dnssec_validate_by_ds(now, header, n, name, keyname, class);
1611 else if (status == STAT_NEED_DS)
1612 new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
1613 else
James Bottomleye33b4872017-03-17 21:44:10 +00001614 new_status = dnssec_validate_reply(now, header, n, name, keyname, &class,
Simon Kelleya6918532018-04-15 16:20:52 +01001615 !option_bool(OPT_DNSSEC_IGN_NS) && (server->flags & SERV_DO_DNSSEC),
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001616 NULL, NULL, NULL);
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001617
Simon Kelley9a31b682015-12-15 10:20:39 +00001618 if (new_status != STAT_NEED_DS && new_status != STAT_NEED_KEY)
1619 break;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001620
Simon Kelley9a31b682015-12-15 10:20:39 +00001621 /* Can't validate because we need a key/DS whose name now in keyname.
1622 Make query for same, and recurse to validate */
Simon Kelley7fa836e2014-02-10 20:11:24 +00001623 if (!packet)
Simon Kelley9a31b682015-12-15 10:20:39 +00001624 {
1625 packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
1626 payload = &packet[2];
1627 new_header = (struct dns_header *)payload;
1628 length = (u16 *)packet;
1629 }
1630
1631 if (!packet)
1632 {
1633 new_status = STAT_ABANDONED;
1634 break;
1635 }
Simon Kelleye1791f32018-10-06 23:23:23 +01001636
Simon Kelley33702ab2015-12-28 23:17:15 +00001637 m = dnssec_generate_query(new_header, ((unsigned char *) new_header) + 65536, keyname, class,
Simon Kelleye1791f32018-10-06 23:23:23 +01001638 new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS, server->edns_pktsz);
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001639
Simon Kelley7fa836e2014-02-10 20:11:24 +00001640 *length = htons(m);
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001641
1642 /* Find server to forward to. This will normally be the
1643 same as for the original query, but may be another if
1644 servers for domains are involved. */
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001645 if (search_servers(now, NULL, F_DNSSECOK, keyname, &type, &domain, NULL) != 0)
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001646 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001647 new_status = STAT_ABANDONED;
1648 break;
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001649 }
Simon Kelley361dfe52017-02-10 21:12:30 +00001650
Simon Kelley361dfe52017-02-10 21:12:30 +00001651 while (1)
1652 {
Simon Kelley608aa9f2019-03-10 22:44:15 +00001653 int data_sent = 0;
1654
Simon Kelley361dfe52017-02-10 21:12:30 +00001655 if (!firstsendto)
1656 firstsendto = server;
1657 else
1658 {
1659 if (!(server = server->next))
1660 server = daemon->servers;
1661 if (server == firstsendto)
1662 {
1663 /* can't find server to accept our query. */
1664 new_status = STAT_ABANDONED;
1665 break;
1666 }
1667 }
1668
Petr Menšíke10a9232021-03-15 11:20:49 +01001669 if (!server_test_type(server, domain, type, SERV_DO_DNSSEC))
Simon Kelley361dfe52017-02-10 21:12:30 +00001670 continue;
Simon Kelleye1791f32018-10-06 23:23:23 +01001671
1672 retry:
1673 /* may need to make new connection. */
1674 if (server->tcpfd == -1)
1675 {
1676 if ((server->tcpfd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
1677 continue; /* No good, next server */
1678
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001679#ifdef HAVE_CONNTRACK
Simon Kelleye1791f32018-10-06 23:23:23 +01001680 /* Copy connection mark of incoming query to outgoing connection. */
1681 if (have_mark)
1682 setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001683#endif
Simon Kelleye1791f32018-10-06 23:23:23 +01001684
Simon Kelley608aa9f2019-03-10 22:44:15 +00001685 if (!local_bind(server->tcpfd, &server->source_addr, server->interface, 0, 1))
1686 {
1687 close(server->tcpfd);
1688 server->tcpfd = -1;
1689 continue; /* No good, next server */
1690 }
1691
1692#ifdef MSG_FASTOPEN
Petr Menšík51f7bc92021-03-18 01:05:43 +01001693 server_send(server, server->tcpfd, packet, m + sizeof(u16), MSG_FASTOPEN);
1694
Simon Kelley608aa9f2019-03-10 22:44:15 +00001695 if (errno == 0)
1696 data_sent = 1;
1697#endif
1698
1699 if (!data_sent && connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) == -1)
Simon Kelleye1791f32018-10-06 23:23:23 +01001700 {
1701 close(server->tcpfd);
1702 server->tcpfd = -1;
1703 continue; /* No good, next server */
1704 }
1705
1706 server->flags &= ~SERV_GOT_TCP;
1707 }
Simon Kelley361dfe52017-02-10 21:12:30 +00001708
Simon Kelley608aa9f2019-03-10 22:44:15 +00001709 if ((!data_sent && !read_write(server->tcpfd, packet, m + sizeof(u16), 0)) ||
Simon Kelley361dfe52017-02-10 21:12:30 +00001710 !read_write(server->tcpfd, &c1, 1, 1) ||
1711 !read_write(server->tcpfd, &c2, 1, 1) ||
1712 !read_write(server->tcpfd, payload, (c1 << 8) | c2, 1))
1713 {
1714 close(server->tcpfd);
1715 server->tcpfd = -1;
1716 /* We get data then EOF, reopen connection to same server,
1717 else try next. This avoids DoS from a server which accepts
1718 connections and then closes them. */
1719 if (server->flags & SERV_GOT_TCP)
1720 goto retry;
1721 else
1722 continue;
1723 }
Simon Kelleye1791f32018-10-06 23:23:23 +01001724
Petr Menšík6c0bf792021-03-18 00:07:45 +01001725 log_query_mysockaddr(F_NOEXTRA | F_DNSSEC, keyname, &server->addr,
1726 querystr("dnssec-query", new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS));
Simon Kelleye1791f32018-10-06 23:23:23 +01001727
Simon Kelley361dfe52017-02-10 21:12:30 +00001728 server->flags |= SERV_GOT_TCP;
1729
1730 m = (c1 << 8) | c2;
1731 new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, have_mark, mark, keycount);
1732 break;
1733 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001734
1735 if (new_status != STAT_OK)
1736 break;
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001737 }
Simon Kelley361dfe52017-02-10 21:12:30 +00001738
Simon Kelley9a31b682015-12-15 10:20:39 +00001739 if (packet)
1740 free(packet);
1741
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001742 return new_status;
1743}
1744#endif
1745
1746
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001747/* The daemon forks before calling this: it should deal with one connection,
Josh Soref730c6742017-02-06 16:14:04 +00001748 blocking as necessary, and then return. Note, need to be a bit careful
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001749 about resources for debug mode, when the fork is suppressed: that's
1750 done by the caller. */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001751unsigned char *tcp_request(int confd, time_t now,
Simon Kelley4f7b3042012-11-28 21:27:02 +00001752 union mysockaddr *local_addr, struct in_addr netmask, int auth_dns)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001753{
Simon Kelley28866e92011-02-14 20:19:14 +00001754 size_t size = 0;
1755 int norebind = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001756#ifdef HAVE_AUTH
Simon Kelley19b16892013-10-20 10:19:39 +01001757 int local_auth = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001758#endif
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001759 int checking_disabled, do_bit, added_pheader = 0, have_pseudoheader = 0;
Simon Kelley25e63f12020-11-25 21:17:52 +00001760 int check_subnet, cacheable, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
Simon Kelleycdeda282006-03-16 20:16:06 +00001761 size_t m;
Simon Kelleyee86ce62012-12-07 11:54:46 +00001762 unsigned short qtype;
1763 unsigned int gotname;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001764 unsigned char c1, c2;
Simon Kelley4b5ea122013-04-22 10:18:26 +01001765 /* Max TCP packet + slop + size */
1766 unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
1767 unsigned char *payload = &packet[2];
1768 /* largest field in header is 16-bits, so this is still sufficiently aligned */
1769 struct dns_header *header = (struct dns_header *)payload;
1770 u16 *length = (u16 *)packet;
Simon Kelley3be34542004-09-11 19:12:13 +01001771 struct server *last_server;
Simon Kelley7de060b2011-08-26 17:24:52 +01001772 struct in_addr dst_addr_4;
1773 union mysockaddr peer_addr;
1774 socklen_t peer_len = sizeof(union mysockaddr);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001775 int query_count = 0;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001776 unsigned char *pheader;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001777 unsigned int mark = 0;
1778 int have_mark = 0;
Simon Kelley25cf5e32015-01-09 15:53:03 +00001779
Simon Kelleyd05dd582016-01-19 21:23:30 +00001780 (void)mark;
1781 (void)have_mark;
1782
Simon Kelley7de060b2011-08-26 17:24:52 +01001783 if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
1784 return packet;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001785
1786#ifdef HAVE_CONNTRACK
1787 /* Get connection mark of incoming query to set on outgoing connections. */
1788 if (option_bool(OPT_CONNTRACK))
1789 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001790 union all_addr local;
Simon Kelleyee875042018-10-23 22:10:17 +01001791
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001792 if (local_addr->sa.sa_family == AF_INET6)
Simon Kelleycc921df2019-01-02 22:48:59 +00001793 local.addr6 = local_addr->in6.sin6_addr;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001794 else
Simon Kelleycc921df2019-01-02 22:48:59 +00001795 local.addr4 = local_addr->in.sin_addr;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001796
1797 have_mark = get_incoming_mark(&peer_addr, &local, 1, &mark);
1798 }
1799#endif
1800
Simon Kelleyc8a80482014-03-05 14:29:54 +00001801 /* We can be configured to only accept queries from at-most-one-hop-away addresses. */
1802 if (option_bool(OPT_LOCAL_SERVICE))
1803 {
1804 struct addrlist *addr;
Simon Kelleyee875042018-10-23 22:10:17 +01001805
Simon Kelleyc8a80482014-03-05 14:29:54 +00001806 if (peer_addr.sa.sa_family == AF_INET6)
1807 {
1808 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1809 if ((addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001810 is_same_net6(&addr->addr.addr6, &peer_addr.in6.sin6_addr, addr->prefixlen))
Simon Kelleyc8a80482014-03-05 14:29:54 +00001811 break;
1812 }
1813 else
Simon Kelleyc8a80482014-03-05 14:29:54 +00001814 {
1815 struct in_addr netmask;
1816 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1817 {
Richard Genoud15b1b7e2014-09-17 21:12:00 +01001818 netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
Simon Kelleyc8a80482014-03-05 14:29:54 +00001819 if (!(addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001820 is_same_net(addr->addr.addr4, peer_addr.in.sin_addr, netmask))
Simon Kelleyc8a80482014-03-05 14:29:54 +00001821 break;
1822 }
1823 }
1824 if (!addr)
1825 {
1826 my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
1827 return packet;
1828 }
1829 }
Simon Kelley7de060b2011-08-26 17:24:52 +01001830
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001831 while (1)
1832 {
Simon Kelley25cf5e32015-01-09 15:53:03 +00001833 if (query_count == TCP_MAX_QUERIES ||
1834 !packet ||
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001835 !read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
1836 !(size = c1 << 8 | c2) ||
Simon Kelley4b5ea122013-04-22 10:18:26 +01001837 !read_write(confd, payload, size, 1))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001838 return packet;
1839
Simon Kelley572b41e2011-02-18 18:11:18 +00001840 if (size < (int)sizeof(struct dns_header))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001841 continue;
Simon Kelley63437ff2017-09-06 22:34:21 +01001842
1843 /* Clear buffer beyond request to avoid risk of
1844 information disclosure. */
1845 memset(payload + size, 0, 65536 - size);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001846
Simon Kelley25cf5e32015-01-09 15:53:03 +00001847 query_count++;
1848
1849 /* log_query gets called indirectly all over the place, so
1850 pass these in global variables - sorry. */
1851 daemon->log_display_id = ++daemon->log_id;
1852 daemon->log_source_addr = &peer_addr;
1853
Simon Kelley28866e92011-02-14 20:19:14 +00001854 /* save state of "cd" flag in query */
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001855 if ((checking_disabled = header->hb4 & HB4_CD))
1856 no_cache_dnssec = 1;
Simon Kelley28866e92011-02-14 20:19:14 +00001857
Simon Kelley3be34542004-09-11 19:12:13 +01001858 if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001859 {
Simon Kelleyb485ed92013-10-18 22:00:39 +01001860#ifdef HAVE_AUTH
1861 struct auth_zone *zone;
1862#endif
Simon Kelley610e7822014-02-06 14:45:17 +00001863 char *types = querystr(auth_dns ? "auth" : "query", qtype);
Simon Kelley7de060b2011-08-26 17:24:52 +01001864
Petr Menšík6c0bf792021-03-18 00:07:45 +01001865 log_query_mysockaddr(F_QUERY | F_FORWARD, daemon->namebuff,
1866 &peer_addr, types);
Simon Kelleyb485ed92013-10-18 22:00:39 +01001867
1868#ifdef HAVE_AUTH
1869 /* find queries for zones we're authoritative for, and answer them directly */
Simon Kelley3a3965a2015-08-09 17:45:06 +01001870 if (!auth_dns && !option_bool(OPT_LOCALISE))
Simon Kelley6008bdb2013-10-21 21:47:03 +01001871 for (zone = daemon->auth_zones; zone; zone = zone->next)
1872 if (in_zone(zone, daemon->namebuff, NULL))
1873 {
1874 auth_dns = 1;
1875 local_auth = 1;
1876 break;
1877 }
Simon Kelleyb485ed92013-10-18 22:00:39 +01001878#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001879 }
1880
Simon Kelley7de060b2011-08-26 17:24:52 +01001881 if (local_addr->sa.sa_family == AF_INET)
1882 dst_addr_4 = local_addr->in.sin_addr;
1883 else
1884 dst_addr_4.s_addr = 0;
1885
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001886 do_bit = 0;
1887
Simon Kelley5bb88f02015-12-21 16:23:47 +00001888 if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL, NULL))
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001889 {
1890 unsigned short flags;
1891
1892 have_pseudoheader = 1;
1893 pheader += 4; /* udp_size, ext_rcode */
1894 GETSHORT(flags, pheader);
1895
1896 if (flags & 0x8000)
Simon Kelley5bb88f02015-12-21 16:23:47 +00001897 do_bit = 1; /* do bit */
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001898 }
1899
Simon Kelley4820dce2012-12-18 18:30:30 +00001900#ifdef HAVE_AUTH
Simon Kelley4f7b3042012-11-28 21:27:02 +00001901 if (auth_dns)
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001902 m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr,
1903 local_auth, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001904 else
Simon Kelley4820dce2012-12-18 18:30:30 +00001905#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001906 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001907 int ad_reqd = do_bit;
1908 /* RFC 6840 5.7 */
1909 if (header->hb4 & HB4_AD)
1910 ad_reqd = 1;
1911
1912 /* m > 0 if answered from cache */
1913 m = answer_request(header, ((char *) header) + 65536, (size_t)size,
1914 dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001915
Simon Kelley4f7b3042012-11-28 21:27:02 +00001916 /* Do this by steam now we're not in the select() loop */
Simon Kelleyb842bc92015-07-12 21:09:11 +01001917 check_log_writer(1);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001918
1919 if (m == 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001920 {
Simon Kelley4f7b3042012-11-28 21:27:02 +00001921 unsigned int flags = 0;
Simon Kelleycc921df2019-01-02 22:48:59 +00001922 union all_addr *addrp = NULL;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001923 int type = SERV_DO_DNSSEC;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001924 char *domain = NULL;
Simon Kelley6fd5d792017-10-13 22:26:40 +01001925 unsigned char *oph = find_pseudoheader(header, size, NULL, NULL, NULL, NULL);
Simon Kelleyed4c0762013-10-08 20:46:34 +01001926
Simon Kelley25e63f12020-11-25 21:17:52 +00001927 size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet, &cacheable);
Simon Kelley6fd5d792017-10-13 22:26:40 +01001928
Simon Kelley4f7b3042012-11-28 21:27:02 +00001929 if (gotname)
1930 flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
Simon Kelley6fd5d792017-10-13 22:26:40 +01001931
1932#ifdef HAVE_DNSSEC
1933 if (option_bool(OPT_DNSSEC_VALID) && (type & SERV_DO_DNSSEC))
1934 {
1935 size = add_do_bit(header, size, ((unsigned char *) header) + 65536);
1936
1937 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
1938 this allows it to select auth servers when one is returning bad data. */
1939 if (option_bool(OPT_DNSSEC_DEBUG))
1940 header->hb4 |= HB4_CD;
1941 }
1942#endif
1943
1944 /* Check if we added a pheader on forwarding - may need to
1945 strip it from the reply. */
1946 if (!oph && find_pseudoheader(header, size, NULL, NULL, NULL, NULL))
1947 added_pheader = 1;
1948
Simon Kelley367341f2016-01-12 15:58:23 +00001949 type &= ~SERV_DO_DNSSEC;
Simon Kelley367341f2016-01-12 15:58:23 +00001950
Simon Kelley4f7b3042012-11-28 21:27:02 +00001951 if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server)
1952 last_server = daemon->servers;
1953 else
1954 last_server = daemon->last_server;
1955
1956 if (!flags && last_server)
1957 {
1958 struct server *firstsendto = NULL;
Simon Kelley2d765862020-11-12 22:06:07 +00001959 unsigned char hash[HASH_SIZE];
1960 memcpy(hash, hash_questions(header, (unsigned int)size, daemon->namebuff), HASH_SIZE);
1961
Simon Kelley4f7b3042012-11-28 21:27:02 +00001962 /* Loop round available servers until we succeed in connecting to one.
Josh Soref730c6742017-02-06 16:14:04 +00001963 Note that this code subtly ensures that consecutive queries on this connection
Simon Kelley4f7b3042012-11-28 21:27:02 +00001964 which can go to the same server, do so. */
1965 while (1)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001966 {
Simon Kelley608aa9f2019-03-10 22:44:15 +00001967 int data_sent = 0;
1968
Simon Kelley4f7b3042012-11-28 21:27:02 +00001969 if (!firstsendto)
1970 firstsendto = last_server;
1971 else
1972 {
1973 if (!(last_server = last_server->next))
1974 last_server = daemon->servers;
1975
1976 if (last_server == firstsendto)
1977 break;
1978 }
1979
1980 /* server for wrong domain */
Petr Menšíke10a9232021-03-15 11:20:49 +01001981 if (!server_test_type(last_server, domain, type, 0))
Simon Kelley7de060b2011-08-26 17:24:52 +01001982 continue;
Simon Kelley361dfe52017-02-10 21:12:30 +00001983
1984 retry:
Simon Kelley608aa9f2019-03-10 22:44:15 +00001985 *length = htons(size);
1986
Simon Kelley4f7b3042012-11-28 21:27:02 +00001987 if (last_server->tcpfd == -1)
1988 {
1989 if ((last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
1990 continue;
1991
Karl Vogele9828b62014-10-03 21:45:15 +01001992#ifdef HAVE_CONNTRACK
1993 /* Copy connection mark of incoming query to outgoing connection. */
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001994 if (have_mark)
1995 setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
Simon Kelley608aa9f2019-03-10 22:44:15 +00001996#endif
Karl Vogele9828b62014-10-03 21:45:15 +01001997
Simon Kelley608aa9f2019-03-10 22:44:15 +00001998 if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 0, 1)))
1999 {
2000 close(last_server->tcpfd);
2001 last_server->tcpfd = -1;
2002 continue;
2003 }
2004
2005#ifdef MSG_FASTOPEN
黎醒聪ffa46282021-03-22 22:00:26 +00002006 server_send(last_server, last_server->tcpfd, packet, size + sizeof(u16), MSG_FASTOPEN);
Petr Menšík51f7bc92021-03-18 01:05:43 +01002007
Simon Kelley608aa9f2019-03-10 22:44:15 +00002008 if (errno == 0)
2009 data_sent = 1;
2010#endif
2011
2012 if (!data_sent && connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1)
Simon Kelley4f7b3042012-11-28 21:27:02 +00002013 {
2014 close(last_server->tcpfd);
2015 last_server->tcpfd = -1;
2016 continue;
2017 }
2018
Simon Kelley361dfe52017-02-10 21:12:30 +00002019 last_server->flags &= ~SERV_GOT_TCP;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002020 }
2021
Simon Kelley1fc02682014-04-29 12:30:18 +01002022 /* get query name again for logging - may have been overwritten */
2023 if (!(gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
2024 strcpy(daemon->namebuff, "query");
Simon Kelley4f7b3042012-11-28 21:27:02 +00002025
Simon Kelley608aa9f2019-03-10 22:44:15 +00002026 if ((!data_sent && !read_write(last_server->tcpfd, packet, size + sizeof(u16), 0)) ||
Simon Kelley4f7b3042012-11-28 21:27:02 +00002027 !read_write(last_server->tcpfd, &c1, 1, 1) ||
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002028 !read_write(last_server->tcpfd, &c2, 1, 1) ||
2029 !read_write(last_server->tcpfd, payload, (c1 << 8) | c2, 1))
Simon Kelley7de060b2011-08-26 17:24:52 +01002030 {
2031 close(last_server->tcpfd);
2032 last_server->tcpfd = -1;
Simon Kelley361dfe52017-02-10 21:12:30 +00002033 /* We get data then EOF, reopen connection to same server,
2034 else try next. This avoids DoS from a server which accepts
2035 connections and then closes them. */
2036 if (last_server->flags & SERV_GOT_TCP)
2037 goto retry;
2038 else
2039 continue;
2040 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00002041
Simon Kelley361dfe52017-02-10 21:12:30 +00002042 last_server->flags |= SERV_GOT_TCP;
2043
Simon Kelley4f7b3042012-11-28 21:27:02 +00002044 m = (c1 << 8) | c2;
Petr Menšík6c0bf792021-03-18 00:07:45 +01002045
2046 log_query_mysockaddr(F_SERVER | F_FORWARD, daemon->namebuff,
2047 &last_server->addr, NULL);
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002048
2049#ifdef HAVE_DNSSEC
Simon Kelley367341f2016-01-12 15:58:23 +00002050 if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled && (last_server->flags & SERV_DO_DNSSEC))
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002051 {
Simon Kelley7fa836e2014-02-10 20:11:24 +00002052 int keycount = DNSSEC_WORK; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
Simon Kelleyf344dbc2016-01-18 18:04:17 +00002053 int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname,
2054 last_server, have_mark, mark, &keycount);
Simon Kelley554b5802015-04-17 22:50:20 +01002055 char *result, *domain = "result";
Simon Kelleyfe3992f2015-04-03 21:25:05 +01002056
Simon Kelley9a31b682015-12-15 10:20:39 +00002057 if (status == STAT_ABANDONED)
Simon Kelley150162b2015-03-27 09:58:26 +00002058 {
2059 result = "ABANDONED";
2060 status = STAT_BOGUS;
2061 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00002062 else
2063 result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
Simon Kelleye66b4df2015-04-28 20:45:57 +01002064
2065 if (status == STAT_BOGUS && extract_request(header, m, daemon->namebuff, NULL))
2066 domain = daemon->namebuff;
Simon Kelley554b5802015-04-17 22:50:20 +01002067
Simon Kelley07ed5852018-05-04 21:52:22 +01002068 log_query(F_SECSTAT, domain, NULL, result);
Simon Kelley7fa836e2014-02-10 20:11:24 +00002069
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002070 if (status == STAT_BOGUS)
Simon Kelleyfe3992f2015-04-03 21:25:05 +01002071 {
2072 no_cache_dnssec = 1;
2073 bogusanswer = 1;
2074 }
2075
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002076 if (status == STAT_SECURE)
2077 cache_secure = 1;
2078 }
2079#endif
2080
2081 /* restore CD bit to the value in the query */
2082 if (checking_disabled)
2083 header->hb4 |= HB4_CD;
2084 else
2085 header->hb4 &= ~HB4_CD;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002086
2087 /* There's no point in updating the cache, since this process will exit and
2088 lose the information after a few queries. We make this call for the alias and
2089 bogus-nxdomain side-effects. */
2090 /* If the crc of the question section doesn't match the crc we sent, then
2091 someone might be attempting to insert bogus values into the cache by
2092 sending replies containing questions and bogus answers. */
Simon Kelley2d765862020-11-12 22:06:07 +00002093 if (memcmp(hash, hash_questions(header, (unsigned int)m, daemon->namebuff), HASH_SIZE) != 0)
Simon Kelley703c7ff2014-01-25 23:46:23 +00002094 {
2095 m = 0;
2096 break;
2097 }
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002098
Simon Kelley25e63f12020-11-25 21:17:52 +00002099 /* Never cache answers which are contingent on the source or MAC address EDSN0 option,
2100 since the cache is ignorant of such things. */
2101 if (!cacheable)
2102 no_cache_dnssec = 1;
2103
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002104 m = process_reply(header, now, last_server, (unsigned int)m,
Simon Kelleye66b4df2015-04-28 20:45:57 +01002105 option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
Simon Kelleyfa14bec2015-12-20 17:12:16 +00002106 ad_reqd, do_bit, added_pheader, check_subnet, &peer_addr);
Simon Kelley4f7b3042012-11-28 21:27:02 +00002107
2108 break;
2109 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002110 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00002111
2112 /* In case of local answer or no connections made. */
2113 if (m == 0)
Simon Kelley1682d152018-08-03 20:38:18 +01002114 {
2115 m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl);
2116 if (have_pseudoheader)
2117 m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
2118 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002119 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002120 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00002121
Simon Kelleyb842bc92015-07-12 21:09:11 +01002122 check_log_writer(1);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002123
Simon Kelley4b5ea122013-04-22 10:18:26 +01002124 *length = htons(m);
2125
2126 if (m == 0 || !read_write(confd, packet, m + sizeof(u16), 0))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002127 return packet;
2128 }
2129}
2130
Simon Kelley16972692006-10-16 20:04:18 +01002131static struct frec *allocate_frec(time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002132{
Simon Kelley16972692006-10-16 20:04:18 +01002133 struct frec *f;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002134
Simon Kelley5aabfc72007-08-29 11:24:47 +01002135 if ((f = (struct frec *)whine_malloc(sizeof(struct frec))))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002136 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01002137 f->next = daemon->frec_list;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002138 f->time = now;
Simon Kelley832af0b2007-01-21 20:01:28 +00002139 f->sentto = NULL;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002140 f->rfds = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +00002141 f->flags = 0;
Simon Kelley3a237152013-12-12 12:15:50 +00002142#ifdef HAVE_DNSSEC
Simon Kelley97bc7982014-01-31 10:19:52 +00002143 f->dependent = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002144 f->blocking_query = NULL;
Simon Kelley4619d942014-01-16 19:53:06 +00002145 f->stash = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002146#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +01002147 daemon->frec_list = f;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002148 }
Simon Kelley16972692006-10-16 20:04:18 +01002149
2150 return f;
2151}
2152
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002153/* return a UDP socket bound to a random port, have to cope with straying into
2154 occupied port nos and reserved ones. */
2155static int random_sock(struct server *s)
2156{
2157 int fd;
2158
2159 if ((fd = socket(s->source_addr.sa.sa_family, SOCK_DGRAM, 0)) != -1)
2160 {
2161 if (local_bind(fd, &s->source_addr, s->interface, s->ifindex, 0))
2162 return fd;
2163
2164 if (s->interface[0] == 0)
2165 (void)prettyprint_addr(&s->source_addr, daemon->namebuff);
2166 else
2167 strcpy(daemon->namebuff, s->interface);
2168
2169 my_syslog(LOG_ERR, _("failed to bind server socket to %s: %s"),
2170 daemon->namebuff, strerror(errno));
2171 close(fd);
2172 }
2173
2174 return -1;
2175}
2176
2177/* compare source addresses and interface, serv2 can be null. */
2178static int server_isequal(const struct server *serv1,
2179 const struct server *serv2)
2180{
2181 return (serv2 &&
2182 serv2->ifindex == serv1->ifindex &&
2183 sockaddr_isequal(&serv2->source_addr, &serv1->source_addr) &&
2184 strncmp(serv2->interface, serv1->interface, IF_NAMESIZE) == 0);
2185}
2186
2187/* fdlp points to chain of randomfds already in use by transaction.
2188 If there's already a suitable one, return it, else allocate a
2189 new one and add it to the list.
2190
2191 Not leaking any resources in the face of allocation failures
2192 is rather convoluted here.
2193
2194 Note that rfd->serv may be NULL, when a server goes away.
2195*/
2196int allocate_rfd(struct randfd_list **fdlp, struct server *serv)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002197{
2198 static int finger = 0;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002199 int i, j = 0;
2200 struct randfd_list *rfl;
2201 struct randfd *rfd = NULL;
2202 int fd = 0;
2203
2204 /* If server has a pre-allocated fd, use that. */
2205 if (serv->sfd)
2206 return serv->sfd->fd;
2207
2208 /* existing suitable random port socket linked to this transaction? */
2209 for (rfl = *fdlp; rfl; rfl = rfl->next)
2210 if (server_isequal(serv, rfl->rfd->serv))
2211 return rfl->rfd->fd;
Simon Kelley1a6bca82008-07-11 11:11:42 +01002212
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002213 /* No. need new link. */
2214 if ((rfl = daemon->rfl_spare))
2215 daemon->rfl_spare = rfl->next;
2216 else if (!(rfl = whine_malloc(sizeof(struct randfd_list))))
2217 return -1;
2218
Simon Kelley1a6bca82008-07-11 11:11:42 +01002219 /* limit the number of sockets we have open to avoid starvation of
2220 (eg) TFTP. Once we have a reasonable number, randomness should be OK */
Simon Kelleyea28d0e2021-03-26 22:02:04 +00002221 for (i = 0; i < daemon->numrrand; i++)
Simon Kelley9009d742008-11-14 20:04:27 +00002222 if (daemon->randomsocks[i].refcount == 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002223 {
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002224 if ((fd = random_sock(serv)) != -1)
2225 {
2226 rfd = &daemon->randomsocks[i];
2227 rfd->serv = serv;
2228 rfd->fd = fd;
2229 rfd->refcount = 1;
2230 }
2231 break;
2232 }
2233
2234 /* No free ones or cannot get new socket, grab an existing one */
2235 if (!rfd)
Simon Kelleyea28d0e2021-03-26 22:02:04 +00002236 for (j = 0; j < daemon->numrrand; j++)
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002237 {
Simon Kelleyea28d0e2021-03-26 22:02:04 +00002238 i = (j + finger) % daemon->numrrand;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002239 if (daemon->randomsocks[i].refcount != 0 &&
2240 server_isequal(serv, daemon->randomsocks[i].serv) &&
2241 daemon->randomsocks[i].refcount != 0xfffe)
2242 {
2243 finger = i + 1;
2244 rfd = &daemon->randomsocks[i];
2245 rfd->refcount++;
2246 break;
2247 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01002248 }
2249
Simon Kelleyea28d0e2021-03-26 22:02:04 +00002250 if (j == daemon->numrrand)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002251 {
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002252 struct randfd_list *rfl_poll;
Simon Kelley1a6bca82008-07-11 11:11:42 +01002253
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002254 /* there are no free slots, and non with the same parameters we can piggy-back on.
2255 We're going to have to allocate a new temporary record, distinguished by
2256 refcount == 0xffff. This will exist in the frec randfd list, never be shared,
2257 and be freed when no longer in use. It will also be held on
2258 the daemon->rfl_poll list so the poll system can find it. */
2259
2260 if ((rfl_poll = daemon->rfl_spare))
2261 daemon->rfl_spare = rfl_poll->next;
2262 else
2263 rfl_poll = whine_malloc(sizeof(struct randfd_list));
2264
2265 if (!rfl_poll ||
2266 !(rfd = whine_malloc(sizeof(struct randfd))) ||
2267 (fd = random_sock(serv)) == -1)
2268 {
2269
2270 /* Don't leak anything we may already have */
2271 rfl->next = daemon->rfl_spare;
2272 daemon->rfl_spare = rfl;
2273
2274 if (rfl_poll)
2275 {
2276 rfl_poll->next = daemon->rfl_spare;
2277 daemon->rfl_spare = rfl_poll;
2278 }
2279
2280 if (rfd)
2281 free(rfd);
2282
2283 return -1; /* doom */
2284 }
2285
2286 /* Note rfd->serv not set here, since it's not reused */
2287 rfd->fd = fd;
2288 rfd->refcount = 0xffff; /* marker for temp record */
2289
2290 rfl_poll->rfd = rfd;
2291 rfl_poll->next = daemon->rfl_poll;
2292 daemon->rfl_poll = rfl_poll;
2293 }
2294
2295 rfl->rfd = rfd;
2296 rfl->next = *fdlp;
2297 *fdlp = rfl;
2298
2299 return rfl->rfd->fd;
Simon Kelley1a6bca82008-07-11 11:11:42 +01002300}
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002301
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002302void free_rfds(struct randfd_list **fdlp)
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002303{
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002304 struct randfd_list *tmp, *rfl, *poll, *next, **up;
2305
2306 for (rfl = *fdlp; rfl; rfl = tmp)
2307 {
2308 if (rfl->rfd->refcount == 0xffff || --(rfl->rfd->refcount) == 0)
2309 close(rfl->rfd->fd);
2310
2311 /* temporary overflow record */
2312 if (rfl->rfd->refcount == 0xffff)
2313 {
2314 free(rfl->rfd);
2315
2316 /* go through the link of all these by steam to delete.
2317 This list is expected to be almost always empty. */
2318 for (poll = daemon->rfl_poll, up = &daemon->rfl_poll; poll; poll = next)
2319 {
2320 next = poll->next;
2321
2322 if (poll->rfd == rfl->rfd)
2323 {
2324 *up = poll->next;
2325 poll->next = daemon->rfl_spare;
2326 daemon->rfl_spare = poll;
2327 }
2328 else
2329 up = &poll->next;
2330 }
2331 }
2332
2333 tmp = rfl->next;
2334 rfl->next = daemon->rfl_spare;
2335 daemon->rfl_spare = rfl;
2336 }
2337
2338 *fdlp = NULL;
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002339}
2340
Simon Kelley1a6bca82008-07-11 11:11:42 +01002341static void free_frec(struct frec *f)
2342{
Simon Kelley6a6e06f2020-12-04 18:35:11 +00002343 struct frec_src *last;
Simon Kelley15b60dd2020-11-18 18:34:55 +00002344
Simon Kelley6a6e06f2020-12-04 18:35:11 +00002345 /* add back to freelist if not the record builtin to every frec. */
2346 for (last = f->frec_src.next; last && last->next; last = last->next) ;
2347 if (last)
2348 {
2349 last->next = daemon->free_frec_src;
2350 daemon->free_frec_src = f->frec_src.next;
2351 }
2352
Simon Kelley15b60dd2020-11-18 18:34:55 +00002353 f->frec_src.next = NULL;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002354 free_rfds(&f->rfds);
Simon Kelley1a6bca82008-07-11 11:11:42 +01002355 f->sentto = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +00002356 f->flags = 0;
Simon Kelley3a237152013-12-12 12:15:50 +00002357
2358#ifdef HAVE_DNSSEC
2359 if (f->stash)
Simon Kelley0fc2f312014-01-08 10:26:58 +00002360 {
2361 blockdata_free(f->stash);
2362 f->stash = NULL;
2363 }
Simon Kelley3a237152013-12-12 12:15:50 +00002364
2365 /* Anything we're waiting on is pointless now, too */
2366 if (f->blocking_query)
2367 free_frec(f->blocking_query);
2368 f->blocking_query = NULL;
Simon Kelley39048ad2014-01-21 17:33:58 +00002369 f->dependent = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002370#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +01002371}
2372
Simon Kelley09f3b2c2017-05-09 01:34:02 +01002373
2374
Simon Kelley16972692006-10-16 20:04:18 +01002375/* if wait==NULL return a free or older than TIMEOUT record.
2376 else return *wait zero if one available, or *wait is delay to
Simon Kelley1a6bca82008-07-11 11:11:42 +01002377 when the oldest in-use record will expire. Impose an absolute
Simon Kelley3a237152013-12-12 12:15:50 +00002378 limit of 4*TIMEOUT before we wipe things (for random sockets).
Simon Kelley8caf3d72020-04-04 17:00:32 +01002379 If force is non-NULL, always return a result, even if we have
2380 to allocate above the limit, and never free the record pointed
2381 to by the force argument. */
2382struct frec *get_new_frec(time_t now, int *wait, struct frec *force)
Simon Kelley16972692006-10-16 20:04:18 +01002383{
Simon Kelley1a6bca82008-07-11 11:11:42 +01002384 struct frec *f, *oldest, *target;
Simon Kelley16972692006-10-16 20:04:18 +01002385 int count;
2386
2387 if (wait)
2388 *wait = 0;
2389
Simon Kelley1a6bca82008-07-11 11:11:42 +01002390 for (f = daemon->frec_list, oldest = NULL, target = NULL, count = 0; f; f = f->next, count++)
Simon Kelley832af0b2007-01-21 20:01:28 +00002391 if (!f->sentto)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002392 target = f;
2393 else
Simon Kelley16972692006-10-16 20:04:18 +01002394 {
Simon Kelley9a31b682015-12-15 10:20:39 +00002395#ifdef HAVE_DNSSEC
2396 /* Don't free DNSSEC sub-queries here, as we may end up with
2397 dangling references to them. They'll go when their "real" query
2398 is freed. */
Simon Kelley8caf3d72020-04-04 17:00:32 +01002399 if (!f->dependent && f != force)
Simon Kelley9a31b682015-12-15 10:20:39 +00002400#endif
2401 {
2402 if (difftime(now, f->time) >= 4*TIMEOUT)
2403 {
2404 free_frec(f);
2405 target = f;
2406 }
2407
2408
2409 if (!oldest || difftime(f->time, oldest->time) <= 0)
2410 oldest = f;
2411 }
Simon Kelley16972692006-10-16 20:04:18 +01002412 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01002413
2414 if (target)
2415 {
2416 target->time = now;
2417 return target;
2418 }
Simon Kelley16972692006-10-16 20:04:18 +01002419
2420 /* can't find empty one, use oldest if there is one
2421 and it's older than timeout */
Simon Kelley09f3b2c2017-05-09 01:34:02 +01002422 if (!force && oldest && ((int)difftime(now, oldest->time)) >= TIMEOUT)
Simon Kelley16972692006-10-16 20:04:18 +01002423 {
2424 /* keep stuff for twice timeout if we can by allocating a new
2425 record instead */
2426 if (difftime(now, oldest->time) < 2*TIMEOUT &&
2427 count <= daemon->ftabsize &&
2428 (f = allocate_frec(now)))
2429 return f;
2430
2431 if (!wait)
2432 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01002433 free_frec(oldest);
Simon Kelley16972692006-10-16 20:04:18 +01002434 oldest->time = now;
2435 }
2436 return oldest;
2437 }
2438
2439 /* none available, calculate time 'till oldest record expires */
Simon Kelley3a237152013-12-12 12:15:50 +00002440 if (!force && count > daemon->ftabsize)
Simon Kelley16972692006-10-16 20:04:18 +01002441 {
Marcelo Salhab Brogliato0da5e892013-05-31 11:49:06 +01002442 static time_t last_log = 0;
2443
Simon Kelley16972692006-10-16 20:04:18 +01002444 if (oldest && wait)
2445 *wait = oldest->time + (time_t)TIMEOUT - now;
Marcelo Salhab Brogliato0da5e892013-05-31 11:49:06 +01002446
2447 if ((int)difftime(now, last_log) > 5)
2448 {
2449 last_log = now;
2450 my_syslog(LOG_WARNING, _("Maximum number of concurrent DNS queries reached (max: %d)"), daemon->ftabsize);
2451 }
2452
Simon Kelley16972692006-10-16 20:04:18 +01002453 return NULL;
2454 }
2455
2456 if (!(f = allocate_frec(now)) && wait)
2457 /* wait one second on malloc failure */
2458 *wait = 1;
2459
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002460 return f; /* OK if malloc fails and this is NULL */
2461}
Simon Kelley09f3b2c2017-05-09 01:34:02 +01002462
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002463static struct frec *lookup_frec(unsigned short id, int fd, void *hash)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002464{
2465 struct frec *f;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002466 struct server *s;
2467 int type;
2468 struct randfd_list *fdl;
2469
Simon Kelley1a6bca82008-07-11 11:11:42 +01002470 for(f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00002471 if (f->sentto && f->new_id == id &&
Simon Kelley2d765862020-11-12 22:06:07 +00002472 (memcmp(hash, f->hash, HASH_SIZE) == 0))
Simon Kelley257ac0c2020-11-12 18:49:23 +00002473 {
2474 /* sent from random port */
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002475 for (fdl = f->rfds; fdl; fdl = fdl->next)
2476 if (fdl->rfd->fd == fd)
Simon Kelley257ac0c2020-11-12 18:49:23 +00002477 return f;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002478
2479 /* Sent to upstream from socket associated with a server.
2480 Note we have to iterate over all the possible servers, since they may
2481 have different bound sockets. */
2482 type = f->sentto->flags & SERV_TYPE;
2483 s = f->sentto;
2484 do {
Petr Menšík8f9bd612021-03-27 23:16:09 +00002485 if (server_test_type(s, f->sentto->domain, type, 0) &&
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002486 s->sfd && s->sfd->fd == fd)
2487 return f;
2488
2489 s = s->next ? s->next : daemon->servers;
2490 } while (s != f->sentto);
Simon Kelley257ac0c2020-11-12 18:49:23 +00002491 }
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002492
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002493 return NULL;
2494}
2495
Simon Kelley15b60dd2020-11-18 18:34:55 +00002496static struct frec *lookup_frec_by_query(void *hash, unsigned int flags)
2497{
2498 struct frec *f;
2499
2500 /* FREC_DNSKEY and FREC_DS_QUERY are never set in flags, so the test below
Simon Kelley25e63f12020-11-25 21:17:52 +00002501 ensures that no frec created for internal DNSSEC query can be returned here.
2502
2503 Similarly FREC_NO_CACHE is never set in flags, so a query which is
2504 contigent on a particular source address EDNS0 option will never be matched. */
Simon Kelley15b60dd2020-11-18 18:34:55 +00002505
2506#define FLAGMASK (FREC_CHECKING_DISABLED | FREC_AD_QUESTION | FREC_DO_QUESTION \
Simon Kelley25e63f12020-11-25 21:17:52 +00002507 | FREC_HAS_PHEADER | FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_NO_CACHE)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002508
Simon Kelley1a6bca82008-07-11 11:11:42 +01002509 for(f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00002510 if (f->sentto &&
Simon Kelley15b60dd2020-11-18 18:34:55 +00002511 (f->flags & FLAGMASK) == flags &&
2512 memcmp(hash, f->hash, HASH_SIZE) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002513 return f;
Simon Kelley15b60dd2020-11-18 18:34:55 +00002514
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002515 return NULL;
2516}
Simon Kelley15b60dd2020-11-18 18:34:55 +00002517
Simon Kelley47a95162014-07-08 22:22:02 +01002518/* Send query packet again, if we can. */
2519void resend_query()
2520{
2521 if (daemon->srv_save)
Petr Menšík51f7bc92021-03-18 01:05:43 +01002522 server_send(daemon->srv_save, daemon->fd_save,
2523 daemon->packet, daemon->packet_len, 0);
Simon Kelley47a95162014-07-08 22:22:02 +01002524}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002525
Simon Kelley849a8352006-06-09 21:02:31 +01002526/* A server record is going away, remove references to it */
Simon Kelley5aabfc72007-08-29 11:24:47 +01002527void server_gone(struct server *server)
Simon Kelley849a8352006-06-09 21:02:31 +01002528{
2529 struct frec *f;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002530 int i;
Simon Kelley849a8352006-06-09 21:02:31 +01002531
Simon Kelley1a6bca82008-07-11 11:11:42 +01002532 for (f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00002533 if (f->sentto && f->sentto == server)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002534 free_frec(f);
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002535
2536 /* If any random socket refers to this server, NULL the reference.
2537 No more references to the socket will be created in the future. */
Simon Kelleyea28d0e2021-03-26 22:02:04 +00002538 for (i = 0; i < daemon->numrrand; i++)
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002539 if (daemon->randomsocks[i].refcount != 0 && daemon->randomsocks[i].serv == server)
2540 daemon->randomsocks[i].serv = NULL;
Simon Kelley849a8352006-06-09 21:02:31 +01002541
2542 if (daemon->last_server == server)
2543 daemon->last_server = NULL;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002544
Simon Kelley849a8352006-06-09 21:02:31 +01002545 if (daemon->srv_save == server)
2546 daemon->srv_save = NULL;
2547}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002548
Simon Kelley316e2732010-01-22 20:16:09 +00002549/* return unique random ids. */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002550static unsigned short get_id(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002551{
2552 unsigned short ret = 0;
Simon Kelley257ac0c2020-11-12 18:49:23 +00002553 struct frec *f;
Simon Kelley832af0b2007-01-21 20:01:28 +00002554
Simon Kelley257ac0c2020-11-12 18:49:23 +00002555 while (1)
2556 {
2557 ret = rand16();
2558
2559 /* ensure id is unique. */
2560 for (f = daemon->frec_list; f; f = f->next)
2561 if (f->sentto && f->new_id == ret)
2562 break;
2563
2564 if (!f)
2565 return ret;
2566 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002567}
2568
2569
2570
2571
2572