blob: 7093e8288db610277d3e07b2ca6128664be7d8b6 [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 Kelleyf61afcf2021-04-07 20:54:36 +010024static void query_full(time_t now);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000025
Simon Kelley824af852008-02-12 20:43:05 +000026/* Send a UDP packet with its source address set as "source"
Simon Kelley44a2a312004-03-10 20:04:35 +000027 unless nowild is true, when we just send it with the kernel default */
Simon Kelley29689cf2012-03-22 14:01:00 +000028int send_from(int fd, int nowild, char *packet, size_t len,
Simon Kelleycc921df2019-01-02 22:48:59 +000029 union mysockaddr *to, union all_addr *source,
Simon Kelley50303b12012-04-04 22:13:17 +010030 unsigned int iface)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000031{
Simon Kelley44a2a312004-03-10 20:04:35 +000032 struct msghdr msg;
33 struct iovec iov[1];
Simon Kelley44a2a312004-03-10 20:04:35 +000034 union {
35 struct cmsghdr align; /* this ensures alignment */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010036#if defined(HAVE_LINUX_NETWORK)
Simon Kelley44a2a312004-03-10 20:04:35 +000037 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
38#elif defined(IP_SENDSRCADDR)
39 char control[CMSG_SPACE(sizeof(struct in_addr))];
40#endif
Simon Kelley44a2a312004-03-10 20:04:35 +000041 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
Simon Kelley44a2a312004-03-10 20:04:35 +000042 } control_u;
Simon Kelleyfeba5c12004-07-27 20:28:58 +010043
Simon Kelley44a2a312004-03-10 20:04:35 +000044 iov[0].iov_base = packet;
45 iov[0].iov_len = len;
46
Simon Kelleyfeba5c12004-07-27 20:28:58 +010047 msg.msg_control = NULL;
48 msg.msg_controllen = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +000049 msg.msg_flags = 0;
50 msg.msg_name = to;
51 msg.msg_namelen = sa_len(to);
52 msg.msg_iov = iov;
53 msg.msg_iovlen = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +010054
Simon Kelley26128d22004-11-14 16:43:54 +000055 if (!nowild)
Simon Kelleyfeba5c12004-07-27 20:28:58 +010056 {
Simon Kelley26128d22004-11-14 16:43:54 +000057 struct cmsghdr *cmptr;
Simon Kelleyfeba5c12004-07-27 20:28:58 +010058 msg.msg_control = &control_u;
59 msg.msg_controllen = sizeof(control_u);
Simon Kelley26128d22004-11-14 16:43:54 +000060 cmptr = CMSG_FIRSTHDR(&msg);
Simon Kelley44a2a312004-03-10 20:04:35 +000061
Simon Kelley26128d22004-11-14 16:43:54 +000062 if (to->sa.sa_family == AF_INET)
63 {
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010064#if defined(HAVE_LINUX_NETWORK)
Simon Kelley8ef5ada2010-06-03 19:42:45 +010065 struct in_pktinfo p;
66 p.ipi_ifindex = 0;
Simon Kelleycc921df2019-01-02 22:48:59 +000067 p.ipi_spec_dst = source->addr4;
Jérémie Courrèges-Anglasc6cc4552019-03-22 10:56:13 +010068 msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
Simon Kelley8ef5ada2010-06-03 19:42:45 +010069 memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
Jérémie Courrèges-Anglasc6cc4552019-03-22 10:56:13 +010070 cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
Simon Kelleyc72daea2012-01-05 21:33:27 +000071 cmptr->cmsg_level = IPPROTO_IP;
Simon Kelley26128d22004-11-14 16:43:54 +000072 cmptr->cmsg_type = IP_PKTINFO;
73#elif defined(IP_SENDSRCADDR)
Jérémie Courrèges-Anglasc6cc4552019-03-22 10:56:13 +010074 msg.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
Simon Kelleycc921df2019-01-02 22:48:59 +000075 memcpy(CMSG_DATA(cmptr), &(source->addr4), sizeof(source->addr4));
Jérémie Courrèges-Anglasc6cc4552019-03-22 10:56:13 +010076 cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
Simon Kelley26128d22004-11-14 16:43:54 +000077 cmptr->cmsg_level = IPPROTO_IP;
78 cmptr->cmsg_type = IP_SENDSRCADDR;
Simon Kelley44a2a312004-03-10 20:04:35 +000079#endif
Simon Kelley26128d22004-11-14 16:43:54 +000080 }
Simon Kelley26128d22004-11-14 16:43:54 +000081 else
82 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +010083 struct in6_pktinfo p;
84 p.ipi6_ifindex = iface; /* Need iface for IPv6 to handle link-local addrs */
Simon Kelleycc921df2019-01-02 22:48:59 +000085 p.ipi6_addr = source->addr6;
Jérémie Courrèges-Anglasc6cc4552019-03-22 10:56:13 +010086 msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
Simon Kelley8ef5ada2010-06-03 19:42:45 +010087 memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
Jérémie Courrèges-Anglasc6cc4552019-03-22 10:56:13 +010088 cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
Simon Kelley316e2732010-01-22 20:16:09 +000089 cmptr->cmsg_type = daemon->v6pktinfo;
Simon Kelleyc72daea2012-01-05 21:33:27 +000090 cmptr->cmsg_level = IPPROTO_IPV6;
Simon Kelley26128d22004-11-14 16:43:54 +000091 }
Simon Kelley26128d22004-11-14 16:43:54 +000092 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +010093
Simon Kelleyff841eb2015-03-11 21:36:30 +000094 while (retry_send(sendmsg(fd, &msg, 0)));
95
Brad Smithea3c60a2020-03-08 14:53:59 +000096 if (errno != 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +010097 {
Brad Smithea3c60a2020-03-08 14:53:59 +000098#ifdef HAVE_LINUX_NETWORK
99 /* If interface is still in DAD, EINVAL results - ignore that. */
100 if (errno != EINVAL)
101 my_syslog(LOG_ERR, _("failed to send packet: %s"), strerror(errno));
102#endif
Simon Kelley29689cf2012-03-22 14:01:00 +0000103 return 0;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100104 }
Simon Kelley29d28dd2012-12-03 14:05:59 +0000105
Simon Kelley29689cf2012-03-22 14:01:00 +0000106 return 1;
Simon Kelley44a2a312004-03-10 20:04:35 +0000107}
108
Simon Kelleycc921df2019-01-02 22:48:59 +0000109static unsigned int search_servers(time_t now, union all_addr **addrpp, unsigned int qtype,
Simon Kelley367341f2016-01-12 15:58:23 +0000110 char *qdomain, int *type, char **domain, int *norebind)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100111
112{
113 /* If the query ends in the domain in one of our servers, set
114 domain to point to that name. We find the largest match to allow both
115 domain.org and sub.domain.org to exist. */
116
117 unsigned int namelen = strlen(qdomain);
118 unsigned int matchlen = 0;
119 struct server *serv;
Simon Kelley28866e92011-02-14 20:19:14 +0000120 unsigned int flags = 0;
Simon Kelleycc921df2019-01-02 22:48:59 +0000121 static union all_addr zero;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100122
Simon Kelley3be34542004-09-11 19:12:13 +0100123 for (serv = daemon->servers; serv; serv=serv->next)
Simon Kelley09f3b2c2017-05-09 01:34:02 +0100124 if (qtype == F_DNSSECOK && !(serv->flags & SERV_DO_DNSSEC))
125 continue;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100126 /* domain matches take priority over NODOTS matches */
Simon Kelley09f3b2c2017-05-09 01:34:02 +0100127 else if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.') && namelen != 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100128 {
Simon Kelley28866e92011-02-14 20:19:14 +0000129 unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100130 *type = SERV_FOR_NODOTS;
Sung Paea914d0a2019-12-30 17:07:37 -0600131 if ((serv->flags & SERV_NO_REBIND) && norebind)
132 *norebind = 1;
133 else if (serv->flags & SERV_NO_ADDR)
Simon Kelley36717ee2004-09-20 19:20:58 +0100134 flags = F_NXDOMAIN;
Simon Kelleyda8b6512018-09-03 23:18:36 +0100135 else if (serv->flags & SERV_LITERAL_ADDRESS)
Simon Kelley36717ee2004-09-20 19:20:58 +0100136 {
Simon Kelleyda8b6512018-09-03 23:18:36 +0100137 /* literal address = '#' -> return all-zero address for IPv4 and IPv6 */
138 if ((serv->flags & SERV_USE_RESOLV) && (qtype & (F_IPV6 | F_IPV4)))
139 {
140 memset(&zero, 0, sizeof(zero));
141 flags = qtype;
142 *addrpp = &zero;
143 }
144 else if (sflag & qtype)
Simon Kelley36717ee2004-09-20 19:20:58 +0100145 {
146 flags = sflag;
147 if (serv->addr.sa.sa_family == AF_INET)
Simon Kelleycc921df2019-01-02 22:48:59 +0000148 *addrpp = (union all_addr *)&serv->addr.in.sin_addr;
Simon Kelley36717ee2004-09-20 19:20:58 +0100149 else
Simon Kelleycc921df2019-01-02 22:48:59 +0000150 *addrpp = (union all_addr *)&serv->addr.in6.sin6_addr;
Simon Kelley36717ee2004-09-20 19:20:58 +0100151 }
Simon Kelley824af852008-02-12 20:43:05 +0000152 else if (!flags || (flags & F_NXDOMAIN))
Simon Kelley36717ee2004-09-20 19:20:58 +0100153 flags = F_NOERR;
154 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100155 }
156 else if (serv->flags & SERV_HAS_DOMAIN)
157 {
158 unsigned int domainlen = strlen(serv->domain);
Simon Kelleyb8187c82005-11-26 21:46:27 +0000159 char *matchstart = qdomain + namelen - domainlen;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100160 if (namelen >= domainlen &&
Simon Kelleyb8187c82005-11-26 21:46:27 +0000161 hostname_isequal(matchstart, serv->domain) &&
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100162 (domainlen == 0 || namelen == domainlen || *(matchstart-1) == '.' ))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100163 {
Simon Kelley92be34a2016-01-16 18:39:54 +0000164 if ((serv->flags & SERV_NO_REBIND) && norebind)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100165 *norebind = 1;
Simon Kelley28866e92011-02-14 20:19:14 +0000166 else
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100167 {
Simon Kelley28866e92011-02-14 20:19:14 +0000168 unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
169 /* implement priority rules for --address and --server for same domain.
170 --address wins if the address is for the correct AF
171 --server wins otherwise. */
172 if (domainlen != 0 && domainlen == matchlen)
Simon Kelley36717ee2004-09-20 19:20:58 +0100173 {
Simon Kelley28866e92011-02-14 20:19:14 +0000174 if ((serv->flags & SERV_LITERAL_ADDRESS))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100175 {
Simon Kelley28866e92011-02-14 20:19:14 +0000176 if (!(sflag & qtype) && flags == 0)
177 continue;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100178 }
Simon Kelley28866e92011-02-14 20:19:14 +0000179 else
180 {
181 if (flags & (F_IPV4 | F_IPV6))
182 continue;
183 }
Simon Kelley36717ee2004-09-20 19:20:58 +0100184 }
Simon Kelley28866e92011-02-14 20:19:14 +0000185
186 if (domainlen >= matchlen)
187 {
Simon Kelley367341f2016-01-12 15:58:23 +0000188 *type = serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_DO_DNSSEC);
Simon Kelley28866e92011-02-14 20:19:14 +0000189 *domain = serv->domain;
190 matchlen = domainlen;
191 if (serv->flags & SERV_NO_ADDR)
192 flags = F_NXDOMAIN;
193 else if (serv->flags & SERV_LITERAL_ADDRESS)
194 {
Simon Kelleyda8b6512018-09-03 23:18:36 +0100195 /* literal address = '#' -> return all-zero address for IPv4 and IPv6 */
196 if ((serv->flags & SERV_USE_RESOLV) && (qtype & (F_IPV6 | F_IPV4)))
197 {
198 memset(&zero, 0, sizeof(zero));
199 flags = qtype;
200 *addrpp = &zero;
201 }
202 else if (sflag & qtype)
Simon Kelley28866e92011-02-14 20:19:14 +0000203 {
204 flags = sflag;
205 if (serv->addr.sa.sa_family == AF_INET)
Simon Kelleycc921df2019-01-02 22:48:59 +0000206 *addrpp = (union all_addr *)&serv->addr.in.sin_addr;
Simon Kelley28866e92011-02-14 20:19:14 +0000207 else
Simon Kelleycc921df2019-01-02 22:48:59 +0000208 *addrpp = (union all_addr *)&serv->addr.in6.sin6_addr;
Simon Kelley28866e92011-02-14 20:19:14 +0000209 }
210 else if (!flags || (flags & F_NXDOMAIN))
211 flags = F_NOERR;
212 }
213 else
214 flags = 0;
215 }
216 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100217 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100218 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100219
Simon Kelleybf05f8f2017-05-09 22:37:46 +0100220 if (flags == 0 && !(qtype & (F_QUERY | F_DNSSECOK)) &&
Simon Kelley28866e92011-02-14 20:19:14 +0000221 option_bool(OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
Simon Kelley7de060b2011-08-26 17:24:52 +0100222 /* don't forward A or AAAA queries for simple names, except the empty name */
223 flags = F_NOERR;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100224
Simon Kelley5aabfc72007-08-29 11:24:47 +0100225 if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now))
Simon Kelleyc1bb8502004-08-11 18:40:17 +0100226 flags = F_NOERR;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100227
Simon Kelley824af852008-02-12 20:43:05 +0000228 if (flags)
229 {
Simon Kelleyc346f612018-09-04 21:14:18 +0100230 if (flags == F_NXDOMAIN || flags == F_NOERR)
231 log_query(flags | qtype | F_NEG | F_CONFIG | F_FORWARD, qdomain, NULL, NULL);
232 else
233 {
234 /* handle F_IPV4 and F_IPV6 set on ANY query to 0.0.0.0/:: domain. */
235 if (flags & F_IPV4)
236 log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV6, qdomain, *addrpp, NULL);
Simon Kelleyc346f612018-09-04 21:14:18 +0100237 if (flags & F_IPV6)
238 log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV4, qdomain, *addrpp, NULL);
Simon Kelleyc346f612018-09-04 21:14:18 +0100239 }
Simon Kelley824af852008-02-12 20:43:05 +0000240 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100241 else if ((*type) & SERV_USE_RESOLV)
242 {
243 *type = 0; /* use normal servers for this domain */
244 *domain = NULL;
245 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100246 return flags;
247}
Simon Kelley44a2a312004-03-10 20:04:35 +0000248
Petr Menšík6c0bf792021-03-18 00:07:45 +0100249#ifdef HAVE_CONNTRACK
250static void set_outgoing_mark(struct frec *forward, int fd)
251{
252 /* Copy connection mark of incoming query to outgoing connection. */
253 unsigned int mark;
254 if (get_incoming_mark(&forward->frec_src.source, &forward->frec_src.dest, 0, &mark))
255 setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
256}
257#endif
258
259static void log_query_mysockaddr(unsigned int flags, char *name, union mysockaddr *addr, char *arg)
260{
261 if (addr->sa.sa_family == AF_INET)
262 log_query(flags | F_IPV4, name, (union all_addr *)&addr->in.sin_addr, arg);
263 else
264 log_query(flags | F_IPV6, name, (union all_addr *)&addr->in6.sin6_addr, arg);
265}
266
Petr Menšík51f7bc92021-03-18 01:05:43 +0100267static void server_send(struct server *server, int fd,
268 const void *header, size_t plen, int flags)
269{
270 while (retry_send(sendto(fd, header, plen, flags,
271 &server->addr.sa,
272 sa_len(&server->addr))));
273}
274
275#ifdef HAVE_DNSSEC
276static void server_send_log(struct server *server, int fd,
277 const void *header, size_t plen, int dumpflags,
278 unsigned int logflags, char *name, char *arg)
279{
280#ifdef HAVE_DUMPFILE
281 dump_packet(dumpflags, (void *)header, (size_t)plen, NULL, &server->addr);
282#endif
283 log_query_mysockaddr(logflags, name, &server->addr, arg);
284 server_send(server, fd, header, plen, 0);
285}
286#endif
287
Petr Menšíke10a9232021-03-15 11:20:49 +0100288static int server_test_type(const struct server *server,
289 const char *domain, int type, int extratype)
290{
291 return (type == (server->flags & (SERV_TYPE | extratype)) &&
292 (type != SERV_HAS_DOMAIN || hostname_isequal(domain, server->domain)) &&
293 !(server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)));
294}
295
Simon Kelley824af852008-02-12 20:43:05 +0000296static int forward_query(int udpfd, union mysockaddr *udpaddr,
Simon Kelleycc921df2019-01-02 22:48:59 +0000297 union all_addr *dst_addr, unsigned int dst_iface,
Simon Kelley83349b82014-02-10 21:02:01 +0000298 struct dns_header *header, size_t plen, time_t now,
Simon Kelley613ad152014-02-25 23:02:28 +0000299 struct frec *forward, int ad_reqd, int do_bit)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000300{
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000301 char *domain = NULL;
Simon Kelley367341f2016-01-12 15:58:23 +0000302 int type = SERV_DO_DNSSEC, norebind = 0;
Simon Kelleycc921df2019-01-02 22:48:59 +0000303 union all_addr *addrp = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +0000304 unsigned int flags = 0;
Simon Kelley15b60dd2020-11-18 18:34:55 +0000305 unsigned int fwd_flags = 0;
Simon Kelleyde379512004-06-22 20:23:33 +0100306 struct server *start = NULL;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000307 void *hash = hash_questions(header, plen, daemon->namebuff);
Simon Kelley2d765862020-11-12 22:06:07 +0000308#ifdef HAVE_DNSSEC
Simon Kelley367341f2016-01-12 15:58:23 +0000309 int do_dnssec = 0;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000310#endif
Simon Kelley1682d152018-08-03 20:38:18 +0100311 unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
312 unsigned char *oph = find_pseudoheader(header, plen, NULL, NULL, NULL, NULL);
Simon Kelleyea6b0b22021-04-05 21:01:09 +0100313 int old_src = 0;
314
Simon Kelley1682d152018-08-03 20:38:18 +0100315 (void)do_bit;
Simon Kelley15b60dd2020-11-18 18:34:55 +0000316
317 if (header->hb4 & HB4_CD)
318 fwd_flags |= FREC_CHECKING_DISABLED;
319 if (ad_reqd)
320 fwd_flags |= FREC_AD_QUESTION;
321 if (oph)
322 fwd_flags |= FREC_HAS_PHEADER;
323#ifdef HAVE_DNSSEC
324 if (do_bit)
325 fwd_flags |= FREC_DO_QUESTION;
326#endif
327
Simon Kelley305cb792021-02-18 21:35:09 +0000328 /* Check for retry on existing query */
Simon Kelleyea6b0b22021-04-05 21:01:09 +0100329 if (forward)
330 old_src = 1;
331 else if ((forward = lookup_frec_by_query(hash, fwd_flags)))
Simon Kelley141a26f2021-02-17 23:56:32 +0000332 {
Simon Kelley305cb792021-02-18 21:35:09 +0000333 struct frec_src *src;
Simon Kelleyea6b0b22021-04-05 21:01:09 +0100334
Simon Kelley305cb792021-02-18 21:35:09 +0000335 for (src = &forward->frec_src; src; src = src->next)
336 if (src->orig_id == ntohs(header->id) &&
337 sockaddr_isequal(&src->source, udpaddr))
338 break;
Simon Kelleyea6b0b22021-04-05 21:01:09 +0100339
340 if (src)
341 old_src = 1;
342 else
Simon Kelley305cb792021-02-18 21:35:09 +0000343 {
Simon Kelleyea6b0b22021-04-05 21:01:09 +0100344 /* Existing query, but from new source, just add this
345 client to the list that will get the reply.*/
346
Simon Kelley141a26f2021-02-17 23:56:32 +0000347 /* Note whine_malloc() zeros memory. */
348 if (!daemon->free_frec_src &&
349 daemon->frec_src_count < daemon->ftabsize &&
350 (daemon->free_frec_src = whine_malloc(sizeof(struct frec_src))))
351 {
352 daemon->frec_src_count++;
353 daemon->free_frec_src->next = NULL;
354 }
355
Simon Kelley961daf82021-04-06 23:52:09 +0100356 /* If we've been spammed with many duplicates, return REFUSED. */
Simon Kelley141a26f2021-02-17 23:56:32 +0000357 if (!daemon->free_frec_src)
Simon Kelley961daf82021-04-06 23:52:09 +0100358 {
Simon Kelleyf61afcf2021-04-07 20:54:36 +0100359 query_full(now);
Simon Kelley961daf82021-04-06 23:52:09 +0100360 goto frec_err;
361 }
Simon Kelley141a26f2021-02-17 23:56:32 +0000362
Simon Kelley305cb792021-02-18 21:35:09 +0000363 src = daemon->free_frec_src;
364 daemon->free_frec_src = src->next;
365 src->next = forward->frec_src.next;
366 forward->frec_src.next = src;
367 src->orig_id = ntohs(header->id);
368 src->source = *udpaddr;
369 src->dest = *dst_addr;
370 src->log_id = daemon->log_id;
371 src->iface = dst_iface;
372 src->fd = udpfd;
Simon Kelley64a16cb2021-04-06 23:29:46 +0100373
374 /* closely spaced identical queries cannot be a try and a retry, so
375 it's safe to wait for the reply from the first without
376 forwarding the second. */
377 if (difftime(now, forward->time) < 2)
378 return 0;
Simon Kelley141a26f2021-02-17 23:56:32 +0000379 }
380 }
381
382 /* retry existing query */
383 if (forward)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000384 {
Simon Kelleya77cec82015-05-08 16:25:38 +0100385 /* If we didn't get an answer advertising a maximal packet in EDNS,
386 fall back to 1280, which should work everywhere on IPv6.
387 If that generates an answer, it will become the new default
388 for this server */
389 forward->flags |= FREC_TEST_PKTSZ;
390
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000391#ifdef HAVE_DNSSEC
Simon Kelleydac74312014-02-13 16:43:49 +0000392 /* If we've already got an answer to this query, but we're awaiting keys for validation,
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000393 there's no point retrying the query, retry the key query instead...... */
394 if (forward->blocking_query)
395 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000396 int fd, is_sign;
397 unsigned char *pheader;
Simon Kelleya77cec82015-05-08 16:25:38 +0100398
399 forward->flags &= ~FREC_TEST_PKTSZ;
400
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000401 while (forward->blocking_query)
402 forward = forward->blocking_query;
Simon Kelleya77cec82015-05-08 16:25:38 +0100403
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000404 blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
405 plen = forward->stash_len;
406
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000407 forward->flags |= FREC_TEST_PKTSZ;
Simon Kelley5bb88f02015-12-21 16:23:47 +0000408 if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000409 PUTSHORT(SAFE_PKTSZ, pheader);
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000410
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000411 if ((fd = allocate_rfd(&forward->rfds, forward->sentto)) != -1)
Petr Menšík51f7bc92021-03-18 01:05:43 +0100412 server_send_log(forward->sentto, fd, header, plen,
413 DUMP_SEC_QUERY,
414 F_NOEXTRA | F_DNSSEC, "retry", "dnssec");
415
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000416 return 1;
417 }
418#endif
419
Simon Kelleyea6b0b22021-04-05 21:01:09 +0100420 /* retry on existing query, from original source. Send to all available servers */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000421 domain = forward->sentto->domain;
Simon Kelley824af852008-02-12 20:43:05 +0000422 forward->sentto->failed_queries++;
Simon Kelleyea6b0b22021-04-05 21:01:09 +0100423 if (!option_bool(OPT_ORDER) && old_src)
Simon Kelleyde379512004-06-22 20:23:33 +0100424 {
Simon Kelley0a852542005-03-23 20:28:59 +0000425 forward->forwardall = 1;
Simon Kelley3be34542004-09-11 19:12:13 +0100426 daemon->last_server = NULL;
Simon Kelleyde379512004-06-22 20:23:33 +0100427 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000428 type = forward->sentto->flags & SERV_TYPE;
Simon Kelley367341f2016-01-12 15:58:23 +0000429#ifdef HAVE_DNSSEC
430 do_dnssec = forward->sentto->flags & SERV_DO_DNSSEC;
431#endif
432
Simon Kelleyde379512004-06-22 20:23:33 +0100433 if (!(start = forward->sentto->next))
Simon Kelley3be34542004-09-11 19:12:13 +0100434 start = daemon->servers; /* at end of list, recycle */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000435 header->id = htons(forward->new_id);
436 }
437 else
438 {
Simon Kelley141a26f2021-02-17 23:56:32 +0000439 /* new query */
440
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000441 if (gotname)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100442 flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000443
Simon Kelley367341f2016-01-12 15:58:23 +0000444#ifdef HAVE_DNSSEC
445 do_dnssec = type & SERV_DO_DNSSEC;
Simon Kelleyf7443d72016-01-19 20:29:57 +0000446#endif
447 type &= ~SERV_DO_DNSSEC;
Simon Kelley15b60dd2020-11-18 18:34:55 +0000448
Simon Kelley141a26f2021-02-17 23:56:32 +0000449 /* may be no servers available. */
Simon Kelleyd05dd582016-01-19 21:23:30 +0000450 if (daemon->servers && !flags)
Simon Kelley8caf3d72020-04-04 17:00:32 +0100451 forward = get_new_frec(now, NULL, NULL);
Simon Kelleyd05dd582016-01-19 21:23:30 +0000452 /* table full - flags == 0, return REFUSED */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000453
454 if (forward)
455 {
Simon Kelley15b60dd2020-11-18 18:34:55 +0000456 forward->frec_src.source = *udpaddr;
457 forward->frec_src.orig_id = ntohs(header->id);
458 forward->frec_src.dest = *dst_addr;
459 forward->frec_src.iface = dst_iface;
Simon Kelley6a6e06f2020-12-04 18:35:11 +0000460 forward->frec_src.next = NULL;
Simon Kelley04490bf2021-01-22 16:49:12 +0000461 forward->frec_src.fd = udpfd;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000462 forward->new_id = get_id();
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000463 memcpy(forward->hash, hash, HASH_SIZE);
Simon Kelley0a852542005-03-23 20:28:59 +0000464 forward->forwardall = 0;
Simon Kelley15b60dd2020-11-18 18:34:55 +0000465 forward->flags = fwd_flags;
Simon Kelley28866e92011-02-14 20:19:14 +0000466 if (norebind)
467 forward->flags |= FREC_NOREBIND;
Simon Kelley572b41e2011-02-18 18:11:18 +0000468 if (header->hb4 & HB4_CD)
Simon Kelley28866e92011-02-14 20:19:14 +0000469 forward->flags |= FREC_CHECKING_DISABLED;
Simon Kelley83349b82014-02-10 21:02:01 +0000470 if (ad_reqd)
471 forward->flags |= FREC_AD_QUESTION;
Simon Kelley7fa836e2014-02-10 20:11:24 +0000472#ifdef HAVE_DNSSEC
473 forward->work_counter = DNSSEC_WORK;
Simon Kelley613ad152014-02-25 23:02:28 +0000474 if (do_bit)
475 forward->flags |= FREC_DO_QUESTION;
Simon Kelley7fa836e2014-02-10 20:11:24 +0000476#endif
Simon Kelley613ad152014-02-25 23:02:28 +0000477
Simon Kelley28866e92011-02-14 20:19:14 +0000478 header->id = htons(forward->new_id);
479
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100480 /* In strict_order mode, always try servers in the order
481 specified in resolv.conf, if a domain is given
482 always try all the available servers,
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000483 otherwise, use the one last known to work. */
484
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100485 if (type == 0)
486 {
Simon Kelley28866e92011-02-14 20:19:14 +0000487 if (option_bool(OPT_ORDER))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100488 start = daemon->servers;
489 else if (!(start = daemon->last_server) ||
490 daemon->forwardcount++ > FORWARD_TEST ||
491 difftime(now, daemon->forwardtime) > FORWARD_TIME)
492 {
493 start = daemon->servers;
494 forward->forwardall = 1;
495 daemon->forwardcount = 0;
496 daemon->forwardtime = now;
497 }
498 }
499 else
Simon Kelleyde379512004-06-22 20:23:33 +0100500 {
Simon Kelley3be34542004-09-11 19:12:13 +0100501 start = daemon->servers;
Simon Kelley28866e92011-02-14 20:19:14 +0000502 if (!option_bool(OPT_ORDER))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100503 forward->forwardall = 1;
Simon Kelleyde379512004-06-22 20:23:33 +0100504 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000505 }
506 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100507
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000508 /* check for send errors here (no route to host)
509 if we fail to send to all nameservers, send back an error
510 packet straight away (helps modem users when offline) */
511
512 if (!flags && forward)
513 {
Simon Kelleyde379512004-06-22 20:23:33 +0100514 struct server *firstsentto = start;
Simon Kelley25e63f12020-11-25 21:17:52 +0000515 int subnet, cacheable, forwarded = 0;
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000516 size_t edns0_len;
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000517 unsigned char *pheader;
518
Simon Kelley25cf5e32015-01-09 15:53:03 +0000519 /* If a query is retried, use the log_id for the retry when logging the answer. */
Simon Kelley15b60dd2020-11-18 18:34:55 +0000520 forward->frec_src.log_id = daemon->log_id;
Simon Kelley25cf5e32015-01-09 15:53:03 +0000521
Kyle Swensonba77fe82021-11-19 09:33:46 -0700522 if(!option_bool(OPT_EDNS_RESTRICT) || (option_bool(OPT_EDNS_RESTRICT) && !domain))
Simon Kelley25e63f12020-11-25 21:17:52 +0000523 plen = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->frec_src.source, now, &subnet, &cacheable);
Simon Kelley33702ab2015-12-28 23:17:15 +0000524
Simon Kelley6fd5d792017-10-13 22:26:40 +0100525 if (subnet)
526 forward->flags |= FREC_HAS_SUBNET;
Simon Kelley25e63f12020-11-25 21:17:52 +0000527
528 if (!cacheable)
529 forward->flags |= FREC_NO_CACHE;
530
Simon Kelley3a237152013-12-12 12:15:50 +0000531#ifdef HAVE_DNSSEC
Simon Kelley367341f2016-01-12 15:58:23 +0000532 if (option_bool(OPT_DNSSEC_VALID) && do_dnssec)
Simon Kelley0fc2f312014-01-08 10:26:58 +0000533 {
Simon Kelley6fd5d792017-10-13 22:26:40 +0100534 plen = add_do_bit(header, plen, ((unsigned char *) header) + PACKETSZ);
535
Simon Kelley5b3bf922014-01-25 17:03:07 +0000536 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
537 this allows it to select auth servers when one is returning bad data. */
538 if (option_bool(OPT_DNSSEC_DEBUG))
539 header->hb4 |= HB4_CD;
Simon Kelley613ad152014-02-25 23:02:28 +0000540
Simon Kelley0fc2f312014-01-08 10:26:58 +0000541 }
Simon Kelley3a237152013-12-12 12:15:50 +0000542#endif
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000543
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000544 if (find_pseudoheader(header, plen, &edns0_len, &pheader, NULL, NULL))
Simon Kelley6fd5d792017-10-13 22:26:40 +0100545 {
546 /* If there wasn't a PH before, and there is now, we added it. */
547 if (!oph)
548 forward->flags |= FREC_ADDED_PHEADER;
549
550 /* If we're sending an EDNS0 with any options, we can't recreate the query from a reply. */
551 if (edns0_len > 11)
552 forward->flags |= FREC_HAS_EXTRADATA;
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000553
554 /* Reduce udp size on retransmits. */
555 if (forward->flags & FREC_TEST_PKTSZ)
556 PUTSHORT(SAFE_PKTSZ, pheader);
Simon Kelley6fd5d792017-10-13 22:26:40 +0100557 }
Simon Kelleya77cec82015-05-08 16:25:38 +0100558
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000559 while (1)
560 {
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000561 int fd;
562
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000563 /* only send to servers dealing with our domain.
564 domain may be NULL, in which case server->domain
565 must be NULL also. */
566
Petr Menšíke10a9232021-03-15 11:20:49 +0100567 if (server_test_type(start, domain, type, 0) &&
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000568 ((fd = allocate_rfd(&forward->rfds, start)) != -1))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000569 {
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000570
Simon Kelley7de060b2011-08-26 17:24:52 +0100571#ifdef HAVE_CONNTRACK
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000572 /* Copy connection mark of incoming query to outgoing connection. */
573 if (option_bool(OPT_CONNTRACK))
Petr Menšík6c0bf792021-03-18 00:07:45 +0100574 set_outgoing_mark(forward, fd);
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000575#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +0100576
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000577#ifdef HAVE_DNSSEC
Simon Kelley5bb88f02015-12-21 16:23:47 +0000578 if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER))
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000579 {
580 /* Difficult one here. If our client didn't send EDNS0, we will have set the UDP
581 packet size to 512. But that won't provide space for the RRSIGS in many cases.
582 The RRSIGS will be stripped out before the answer goes back, so the packet should
583 shrink again. So, if we added a do-bit, bump the udp packet size to the value
Simon Kelley5aa5f0f2015-12-21 17:20:35 +0000584 known to be OK for this server. We check returned size after stripping and set
585 the truncated bit if it's still too big. */
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000586 unsigned char *pheader;
587 int is_sign;
Simon Kelley5bb88f02015-12-21 16:23:47 +0000588 if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000589 PUTSHORT(start->edns_pktsz, pheader);
590 }
591#endif
592
tarun.kundu519669e2023-01-04 09:21:28 -0800593 if (udpaddr &&
594 (start->addr.in.sin_addr.s_addr != udpaddr->in.sin_addr.s_addr) &&
595 (retry_send(sendto(fd, (char *)header, plen, 0,
Simon Kelleyff841eb2015-03-11 21:36:30 +0000596 &start->addr.sa,
tarun.kundu519669e2023-01-04 09:21:28 -0800597 sa_len(&start->addr)))))
Simon Kelleyff841eb2015-03-11 21:36:30 +0000598 continue;
599
600 if (errno == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000601 {
Simon Kelley6b173352018-05-08 18:32:14 +0100602#ifdef HAVE_DUMPFILE
603 dump_packet(DUMP_UP_QUERY, (void *)header, plen, NULL, &start->addr);
604#endif
605
Simon Kelleycdeda282006-03-16 20:16:06 +0000606 /* Keep info in case we want to re-send this packet */
607 daemon->srv_save = start;
608 daemon->packet_len = plen;
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000609 daemon->fd_save = fd;
Simon Kelleycdeda282006-03-16 20:16:06 +0000610
Simon Kelleyde379512004-06-22 20:23:33 +0100611 if (!gotname)
Simon Kelley3be34542004-09-11 19:12:13 +0100612 strcpy(daemon->namebuff, "query");
Petr Menšík6c0bf792021-03-18 00:07:45 +0100613 log_query_mysockaddr(F_SERVER | F_FORWARD, daemon->namebuff,
614 &start->addr, NULL);
Simon Kelley824af852008-02-12 20:43:05 +0000615 start->queries++;
Simon Kelleyde379512004-06-22 20:23:33 +0100616 forwarded = 1;
617 forward->sentto = start;
Simon Kelley0a852542005-03-23 20:28:59 +0000618 if (!forward->forwardall)
Simon Kelleyde379512004-06-22 20:23:33 +0100619 break;
Simon Kelley0a852542005-03-23 20:28:59 +0000620 forward->forwardall++;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000621 }
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000622 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000623
Simon Kelleyde379512004-06-22 20:23:33 +0100624 if (!(start = start->next))
Simon Kelley3be34542004-09-11 19:12:13 +0100625 start = daemon->servers;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000626
Simon Kelleyde379512004-06-22 20:23:33 +0100627 if (start == firstsentto)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000628 break;
629 }
630
Simon Kelleyde379512004-06-22 20:23:33 +0100631 if (forwarded)
Simon Kelley824af852008-02-12 20:43:05 +0000632 return 1;
Simon Kelleyde379512004-06-22 20:23:33 +0100633
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000634 /* could not send on, prepare to return */
Simon Kelley15b60dd2020-11-18 18:34:55 +0000635 header->id = htons(forward->frec_src.orig_id);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100636 free_frec(forward); /* cancel */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000637 }
638
639 /* could not send on, return empty answer or address if known for whole domain */
Simon Kelley961daf82021-04-06 23:52:09 +0100640 frec_err:
Simon Kelleyb8187c82005-11-26 21:46:27 +0000641 if (udpfd != -1)
642 {
Simon Kelleycdeda282006-03-16 20:16:06 +0000643 plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl);
Simon Kelley1682d152018-08-03 20:38:18 +0100644 if (oph)
645 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 +0100646 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 +0000647 }
648
Simon Kelley824af852008-02-12 20:43:05 +0000649 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000650}
651
Simon Kelleyed4c0762013-10-08 20:46:34 +0100652static 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 +0100653 int no_cache, int cache_secure, int bogusanswer, int ad_reqd, int do_bit, int added_pheader,
654 int check_subnet, union mysockaddr *query_source)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100655{
Simon Kelley36717ee2004-09-20 19:20:58 +0100656 unsigned char *pheader, *sizep;
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000657 char **sets = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +0000658 int munged = 0, is_sign;
Simon Kelley07ed5852018-05-04 21:52:22 +0100659 unsigned int rcode = RCODE(header);
Simon Kelleycdeda282006-03-16 20:16:06 +0000660 size_t plen;
Simon Kelleya6004d72017-10-25 17:48:19 +0100661
Simon Kelley83349b82014-02-10 21:02:01 +0000662 (void)ad_reqd;
Simon Kelley982faf42015-04-03 21:42:30 +0100663 (void)do_bit;
664 (void)bogusanswer;
Simon Kelley83349b82014-02-10 21:02:01 +0000665
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000666#ifdef HAVE_IPSET
Tarun Kunduf37019e2022-08-08 07:45:13 -0700667 if (extract_request(header, n, daemon->namebuff, NULL))
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000668 {
Tarun Kunduf37019e2022-08-08 07:45:13 -0700669 if (header && (ntohs(header->arcount)))
670 n = process_appid_catid(header, n);
Simon Kelley82a14af2014-04-13 20:48:57 +0100671 /* Similar algorithm to search_servers. */
672 struct ipsets *ipset_pos;
673 unsigned int namelen = strlen(daemon->namebuff);
674 unsigned int matchlen = 0;
Tarun Kunduf37019e2022-08-08 07:45:13 -0700675 if (daemon->ipsets)
676 for (ipset_pos = daemon->ipsets; ipset_pos; ipset_pos = ipset_pos->next)
Simon Kelley6c0cb852014-01-17 14:40:46 +0000677 {
Simon Kelley82a14af2014-04-13 20:48:57 +0100678 unsigned int domainlen = strlen(ipset_pos->domain);
679 char *matchstart = daemon->namebuff + namelen - domainlen;
680 if (namelen >= domainlen && hostname_isequal(matchstart, ipset_pos->domain) &&
681 (domainlen == 0 || namelen == domainlen || *(matchstart - 1) == '.' ) &&
682 domainlen >= matchlen)
683 {
684 matchlen = domainlen;
685 sets = ipset_pos->sets;
686 }
Simon Kelley6c0cb852014-01-17 14:40:46 +0000687 }
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000688 }
689#endif
Simon Kelley25e63f12020-11-25 21:17:52 +0000690
Simon Kelley5bb88f02015-12-21 16:23:47 +0000691 if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign, NULL)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100692 {
Simon Kelley07ed5852018-05-04 21:52:22 +0100693 /* Get extended RCODE. */
694 rcode |= sizep[2] << 4;
695
Simon Kelleyed4c0762013-10-08 20:46:34 +0100696 if (check_subnet && !check_source(header, plen, pheader, query_source))
697 {
698 my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch"));
699 return 0;
700 }
Simon Kelley613ad152014-02-25 23:02:28 +0000701
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000702 if (!is_sign)
Simon Kelley613ad152014-02-25 23:02:28 +0000703 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000704 if (added_pheader)
705 {
706 /* client didn't send EDNS0, we added one, strip it off before returning answer. */
707 n = rrfilter(header, n, 0);
708 pheader = NULL;
709 }
710 else
711 {
Simon Kelley33702ab2015-12-28 23:17:15 +0000712 unsigned short udpsz;
713
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000714 /* If upstream is advertising a larger UDP packet size
715 than we allow, trim it so that we don't get overlarge
716 requests for the client. We can't do this for signed packets. */
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000717 GETSHORT(udpsz, sizep);
718 if (udpsz > daemon->edns_pktsz)
Simon Kelley33702ab2015-12-28 23:17:15 +0000719 {
720 sizep -= 2;
721 PUTSHORT(daemon->edns_pktsz, sizep);
722 }
723
724#ifdef HAVE_DNSSEC
725 /* If the client didn't set the do bit, but we did, reset it. */
726 if (option_bool(OPT_DNSSEC_VALID) && !do_bit)
727 {
728 unsigned short flags;
729 sizep += 2; /* skip RCODE */
730 GETSHORT(flags, sizep);
731 flags &= ~0x8000;
732 sizep -= 2;
733 PUTSHORT(flags, sizep);
734 }
735#endif
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000736 }
Simon Kelley613ad152014-02-25 23:02:28 +0000737 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100738 }
Simon Kelley83349b82014-02-10 21:02:01 +0000739
Simon Kelley28866e92011-02-14 20:19:14 +0000740 /* RFC 4035 sect 4.6 para 3 */
Giovanni Bajo237724c2012-04-05 02:46:52 +0200741 if (!is_sign && !option_bool(OPT_DNSSEC_PROXY))
Simon Kelley795501b2014-01-08 18:11:55 +0000742 header->hb4 &= ~HB4_AD;
Simon Kelley3a237152013-12-12 12:15:50 +0000743
Simon Kelley07ed5852018-05-04 21:52:22 +0100744 if (OPCODE(header) != QUERY)
Simon Kelley8938ae02014-05-01 17:46:25 +0100745 return resize_packet(header, n, pheader, plen);
Simon Kelley07ed5852018-05-04 21:52:22 +0100746
747 if (rcode != NOERROR && rcode != NXDOMAIN)
748 {
Simon Kelleycc921df2019-01-02 22:48:59 +0000749 union all_addr a;
750 a.log.rcode = rcode;
Simon Kelley07ed5852018-05-04 21:52:22 +0100751 log_query(F_UPSTREAM | F_RCODE, "error", &a, NULL);
752
753 return resize_packet(header, n, pheader, plen);
754 }
Simon Kelley36717ee2004-09-20 19:20:58 +0100755
Simon Kelley0a852542005-03-23 20:28:59 +0000756 /* Complain loudly if the upstream server is non-recursive. */
Simon Kelley07ed5852018-05-04 21:52:22 +0100757 if (!(header->hb4 & HB4_RA) && rcode == NOERROR &&
Simon Kelley0a852542005-03-23 20:28:59 +0000758 server && !(server->flags & SERV_WARNED_RECURSIVE))
759 {
Petr Mensik51cdd1a2019-07-04 20:28:08 +0200760 (void)prettyprint_addr(&server->addr, daemon->namebuff);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100761 my_syslog(LOG_WARNING, _("nameserver %s refused to do a recursive query"), daemon->namebuff);
Simon Kelley28866e92011-02-14 20:19:14 +0000762 if (!option_bool(OPT_LOG))
Simon Kelley0a852542005-03-23 20:28:59 +0000763 server->flags |= SERV_WARNED_RECURSIVE;
764 }
Giovanni Bajoe292e932012-04-22 14:32:02 +0200765
Simon Kelley07ed5852018-05-04 21:52:22 +0100766 if (daemon->bogus_addr && rcode != NXDOMAIN &&
Simon Kelley9eaa91b2021-03-17 20:31:06 +0000767 check_for_bogus_wildcard(header, n, daemon->namebuff, now))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100768 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100769 munged = 1;
Simon Kelley572b41e2011-02-18 18:11:18 +0000770 SET_RCODE(header, NXDOMAIN);
771 header->hb3 &= ~HB3_AA;
Simon Kelley6938f342014-01-26 22:47:39 +0000772 cache_secure = 0;
Simon Kelley36717ee2004-09-20 19:20:58 +0100773 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100774 else
Simon Kelley36717ee2004-09-20 19:20:58 +0100775 {
Simon Kelley6938f342014-01-26 22:47:39 +0000776 int doctored = 0;
777
Simon Kelley07ed5852018-05-04 21:52:22 +0100778 if (rcode == NXDOMAIN &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100779 extract_request(header, n, daemon->namebuff, NULL) &&
Simon Kelley5aabfc72007-08-29 11:24:47 +0100780 check_for_local_domain(daemon->namebuff, now))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100781 {
Simon Kelley36717ee2004-09-20 19:20:58 +0100782 /* if we forwarded a query for a locally known name (because it was for
783 an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
784 since we know that the domain exists, even if upstream doesn't */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100785 munged = 1;
Simon Kelley572b41e2011-02-18 18:11:18 +0000786 header->hb3 |= HB3_AA;
787 SET_RCODE(header, NOERROR);
Simon Kelley6938f342014-01-26 22:47:39 +0000788 cache_secure = 0;
Simon Kelley36717ee2004-09-20 19:20:58 +0100789 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000790
Simon Kelley373e9172017-12-01 22:40:56 +0000791 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 +0000792 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100793 my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
Simon Kelley824af852008-02-12 20:43:05 +0000794 munged = 1;
Simon Kelley6938f342014-01-26 22:47:39 +0000795 cache_secure = 0;
Simon Kelley824af852008-02-12 20:43:05 +0000796 }
Simon Kelley6938f342014-01-26 22:47:39 +0000797
798 if (doctored)
799 cache_secure = 0;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100800 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100801
Simon Kelleya25720a2014-01-14 23:13:55 +0000802#ifdef HAVE_DNSSEC
Simon Kelley33702ab2015-12-28 23:17:15 +0000803 if (bogusanswer && !(header->hb4 & HB4_CD) && !option_bool(OPT_DNSSEC_DEBUG))
Simon Kelleya25720a2014-01-14 23:13:55 +0000804 {
Simon Kelley33702ab2015-12-28 23:17:15 +0000805 /* Bogus reply, turn into SERVFAIL */
806 SET_RCODE(header, SERVFAIL);
807 munged = 1;
Simon Kelleya25720a2014-01-14 23:13:55 +0000808 }
Simon Kelley6938f342014-01-26 22:47:39 +0000809
810 if (option_bool(OPT_DNSSEC_VALID))
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000811 {
812 header->hb4 &= ~HB4_AD;
813
814 if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure)
815 header->hb4 |= HB4_AD;
816
817 /* If the requestor didn't set the DO bit, don't return DNSSEC info. */
818 if (!do_bit)
819 n = rrfilter(header, n, 1);
820 }
Simon Kelleya25720a2014-01-14 23:13:55 +0000821#endif
822
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100823 /* do this after extract_addresses. Ensure NODATA reply and remove
824 nameserver info. */
825
826 if (munged)
827 {
828 header->ancount = htons(0);
829 header->nscount = htons(0);
830 header->arcount = htons(0);
Simon Kelley150162b2015-03-27 09:58:26 +0000831 header->hb3 &= ~HB3_TC;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100832 }
833
Simon Kelley36717ee2004-09-20 19:20:58 +0100834 /* the bogus-nxdomain stuff, doctor and NXDOMAIN->NODATA munging can all elide
835 sections of the packet. Find the new length here and put back pseudoheader
836 if it was removed. */
837 return resize_packet(header, n, pheader, plen);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100838}
839
Simon Kelley3be34542004-09-11 19:12:13 +0100840/* sets new last_server */
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000841void reply_query(int fd, time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000842{
843 /* packet from peer server, extract data for cache, and send to
844 original requester */
Simon Kelley572b41e2011-02-18 18:11:18 +0000845 struct dns_header *header;
Simon Kelleyde379512004-06-22 20:23:33 +0100846 union mysockaddr serveraddr;
Simon Kelley832af0b2007-01-21 20:01:28 +0000847 struct frec *forward;
Simon Kelleyde379512004-06-22 20:23:33 +0100848 socklen_t addrlen = sizeof(serveraddr);
Simon Kelley60b68062014-01-08 12:10:28 +0000849 ssize_t n = recvfrom(fd, daemon->packet, daemon->packet_buff_sz, 0, &serveraddr.sa, &addrlen);
Simon Kelleycdeda282006-03-16 20:16:06 +0000850 size_t nn;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100851 struct server *server;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000852 void *hash;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000853
Simon Kelleycdeda282006-03-16 20:16:06 +0000854 /* packet buffer overwritten */
855 daemon->srv_save = NULL;
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000856
Simon Kelleyde379512004-06-22 20:23:33 +0100857 /* Determine the address of the server replying so that we can mark that as good */
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000858 if (serveraddr.sa.sa_family == AF_INET6)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100859 serveraddr.in6.sin6_flowinfo = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000860
Simon Kelley490f9072014-03-24 22:04:42 +0000861 header = (struct dns_header *)daemon->packet;
Simon Kelley6b173352018-05-08 18:32:14 +0100862
Simon Kelley490f9072014-03-24 22:04:42 +0000863 if (n < (int)sizeof(struct dns_header) || !(header->hb3 & HB3_QR))
864 return;
865
Simon Kelley1a6bca82008-07-11 11:11:42 +0100866 /* spoof check: answer must come from known server, */
867 for (server = daemon->servers; server; server = server->next)
868 if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) &&
869 sockaddr_isequal(&server->addr, &serveraddr))
870 break;
Simon Kelley490f9072014-03-24 22:04:42 +0000871
872 if (!server)
873 return;
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000874
875 /* If sufficient time has elapsed, try and expand UDP buffer size again. */
876 if (difftime(now, server->pktsz_reduced) > UDP_TEST_TIME)
877 server->edns_pktsz = daemon->edns_pktsz;
878
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000879 hash = hash_questions(header, n, daemon->namebuff);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100880
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000881 if (!(forward = lookup_frec(ntohs(header->id), fd, hash)))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100882 return;
Simon Kelley490f9072014-03-24 22:04:42 +0000883
Simon Kelley6b173352018-05-08 18:32:14 +0100884#ifdef HAVE_DUMPFILE
885 dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_REPLY : DUMP_UP_REPLY,
886 (void *)header, n, &serveraddr, NULL);
887#endif
Simon Kelleya0088e82018-05-10 21:43:14 +0100888
Simon Kelley25cf5e32015-01-09 15:53:03 +0000889 /* log_query gets called indirectly all over the place, so
890 pass these in global variables - sorry. */
Simon Kelley15b60dd2020-11-18 18:34:55 +0000891 daemon->log_display_id = forward->frec_src.log_id;
892 daemon->log_source_addr = &forward->frec_src.source;
Simon Kelley25cf5e32015-01-09 15:53:03 +0000893
Glen Huang32fc6db2014-12-27 15:28:12 +0000894 if (daemon->ignore_addr && RCODE(header) == NOERROR &&
Simon Kelley9eaa91b2021-03-17 20:31:06 +0000895 check_for_ignored_address(header, n))
Glen Huang32fc6db2014-12-27 15:28:12 +0000896 return;
897
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000898 /* Note: if we send extra options in the EDNS0 header, we can't recreate
899 the query from the reply. */
Simon Kelley34e26e12018-05-10 20:54:57 +0100900 if ((RCODE(header) == REFUSED || RCODE(header) == SERVFAIL) &&
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000901 forward->forwardall == 0 &&
902 !(forward->flags & FREC_HAS_EXTRADATA))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100903 /* for broken servers, attempt to send to another one. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000904 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100905 unsigned char *pheader;
906 size_t plen;
907 int is_sign;
Simon Kelleyef3d1372017-12-05 22:37:29 +0000908
Simon Kelley1f60a182018-05-11 16:44:16 +0100909#ifdef HAVE_DNSSEC
Simon Kelleya0088e82018-05-10 21:43:14 +0100910 if (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY))
911 {
Simon Kelley1f60a182018-05-11 16:44:16 +0100912 struct server *start;
913
Simon Kelleya0088e82018-05-10 21:43:14 +0100914 blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
915 plen = forward->stash_len;
916
917 forward->forwardall = 2; /* only retry once */
Simon Kelley1f60a182018-05-11 16:44:16 +0100918 start = forward->sentto;
919
920 /* for non-domain specific servers, see if we can find another to try. */
921 if ((forward->sentto->flags & SERV_TYPE) == 0)
922 while (1)
923 {
924 if (!(start = start->next))
925 start = daemon->servers;
926 if (start == forward->sentto)
927 break;
928
929 if ((start->flags & SERV_TYPE) == 0 &&
930 (start->flags & SERV_DO_DNSSEC))
931 break;
932 }
933
934
Petr Menšík51f7bc92021-03-18 01:05:43 +0100935 if ((fd = allocate_rfd(&forward->rfds, start)) != -1)
936 server_send_log(start, fd, header, plen,
937 DUMP_SEC_QUERY,
938 F_NOEXTRA | F_DNSSEC, "retry", "dnssec");
Simon Kelleya0088e82018-05-10 21:43:14 +0100939 return;
940 }
Simon Kelley1f60a182018-05-11 16:44:16 +0100941#endif
942
Simon Kelleyef3d1372017-12-05 22:37:29 +0000943 /* In strict order mode, there must be a server later in the chain
944 left to send to, otherwise without the forwardall mechanism,
945 code further on will cycle around the list forwever if they
946 all return REFUSED. Note that server is always non-NULL before
947 this executes. */
948 if (option_bool(OPT_ORDER))
949 for (server = forward->sentto->next; server; server = server->next)
950 if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR | SERV_LOOP)))
951 break;
952
Simon Kelley1a6bca82008-07-11 11:11:42 +0100953 /* recreate query from reply */
Simon Kelley5bb88f02015-12-21 16:23:47 +0000954 pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign, NULL);
Simon Kelleyef3d1372017-12-05 22:37:29 +0000955 if (!is_sign && server)
Simon Kelley832af0b2007-01-21 20:01:28 +0000956 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100957 header->ancount = htons(0);
958 header->nscount = htons(0);
959 header->arcount = htons(0);
960 if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
961 {
swiggerbd7bfa22015-06-01 20:54:59 +0100962 header->hb3 &= ~(HB3_QR | HB3_AA | HB3_TC);
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000963 header->hb4 &= ~(HB4_RA | HB4_RCODE | HB4_CD | HB4_AD);
Simon Kelley1801a292016-01-17 21:53:57 +0000964 if (forward->flags & FREC_CHECKING_DISABLED)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000965 header->hb4 |= HB4_CD;
Simon Kelley1801a292016-01-17 21:53:57 +0000966 if (forward->flags & FREC_AD_QUESTION)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000967 header->hb4 |= HB4_AD;
968 if (forward->flags & FREC_DO_QUESTION)
Simon Kelley33702ab2015-12-28 23:17:15 +0000969 add_do_bit(header, nn, (unsigned char *)pheader + plen);
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000970 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 +0100971 return;
972 }
973 }
974 }
Simon Kelley3a237152013-12-12 12:15:50 +0000975
976 server = forward->sentto;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100977 if ((forward->sentto->flags & SERV_TYPE) == 0)
978 {
Simon Kelley51967f92014-03-25 21:07:00 +0000979 if (RCODE(header) == REFUSED)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100980 server = NULL;
981 else
982 {
983 struct server *last_server;
Simon Kelley832af0b2007-01-21 20:01:28 +0000984
Simon Kelley1a6bca82008-07-11 11:11:42 +0100985 /* find good server by address if possible, otherwise assume the last one we sent to */
986 for (last_server = daemon->servers; last_server; last_server = last_server->next)
987 if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) &&
988 sockaddr_isequal(&last_server->addr, &serveraddr))
989 {
990 server = last_server;
991 break;
992 }
993 }
Simon Kelley28866e92011-02-14 20:19:14 +0000994 if (!option_bool(OPT_ALL_SERVERS))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100995 daemon->last_server = server;
996 }
Simon Kelleya77cec82015-05-08 16:25:38 +0100997
998 /* We tried resending to this server with a smaller maximum size and got an answer.
Ville Skyttäfaaf3062018-01-14 17:32:52 +0000999 Make that permanent. To avoid reduxing the packet size for a single dropped packet,
Simon Kelley86fa1042015-05-10 13:50:59 +01001000 only do this when we get a truncated answer, or one larger than the safe size. */
Simon Kelley04db1482019-10-11 23:22:17 +01001001 if (forward->sentto->edns_pktsz > SAFE_PKTSZ && (forward->flags & FREC_TEST_PKTSZ) &&
Simon Kelley86fa1042015-05-10 13:50:59 +01001002 ((header->hb3 & HB3_TC) || n >= SAFE_PKTSZ))
Simon Kelley22dee512017-10-13 22:54:00 +01001003 {
Simon Kelley04db1482019-10-11 23:22:17 +01001004 forward->sentto->edns_pktsz = SAFE_PKTSZ;
1005 forward->sentto->pktsz_reduced = now;
Petr Mensik51cdd1a2019-07-04 20:28:08 +02001006 (void)prettyprint_addr(&forward->sentto->addr, daemon->addrbuff);
Simon Kelleyebedcba2017-10-29 20:54:17 +00001007 my_syslog(LOG_WARNING, _("reducing DNS packet size for nameserver %s to %d"), daemon->addrbuff, SAFE_PKTSZ);
Simon Kelley22dee512017-10-13 22:54:00 +01001008 }
Simon Kelleyc1a4e252018-01-19 22:00:05 +00001009
1010
Simon Kelley1a6bca82008-07-11 11:11:42 +01001011 /* If the answer is an error, keep the forward record in place in case
1012 we get a good reply from another server. Kill it when we've
1013 had replies from all to avoid filling the forwarding table when
1014 everything is broken */
Simon Kelley122392e2018-10-31 22:24:02 +00001015 if (forward->forwardall == 0 || --forward->forwardall == 1 || RCODE(header) != REFUSED)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001016 {
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001017 int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
Simon Kelleya6004d72017-10-25 17:48:19 +01001018
Simon Kelley3a237152013-12-12 12:15:50 +00001019 if (option_bool(OPT_NO_REBIND))
1020 check_rebind = !(forward->flags & FREC_NOREBIND);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001021
Simon Kelley3a237152013-12-12 12:15:50 +00001022 /* Don't cache replies where DNSSEC validation was turned off, either
1023 the upstream server told us so, or the original query specified it. */
1024 if ((header->hb4 & HB4_CD) || (forward->flags & FREC_CHECKING_DISABLED))
1025 no_cache_dnssec = 1;
1026
1027#ifdef HAVE_DNSSEC
Simon Kelley04db1482019-10-11 23:22:17 +01001028 if ((forward->sentto->flags & SERV_DO_DNSSEC) &&
Simon Kelley57573712016-01-11 22:50:00 +00001029 option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED))
Simon Kelley3a237152013-12-12 12:15:50 +00001030 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001031 int status = 0;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001032
1033 /* We've had a reply already, which we're validating. Ignore this duplicate */
Simon Kelleye0c0ad32014-01-16 22:42:07 +00001034 if (forward->blocking_query)
Simon Kelley0fc2f312014-01-08 10:26:58 +00001035 return;
Simon Kelley9a31b682015-12-15 10:20:39 +00001036
1037 /* Truncated answer can't be validated.
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001038 If this is an answer to a DNSSEC-generated query, we still
1039 need to get the client to retry over TCP, so return
1040 an answer with the TC bit set, even if the actual answer fits.
1041 */
Simon Kelley9a31b682015-12-15 10:20:39 +00001042 if (header->hb3 & HB3_TC)
1043 status = STAT_TRUNCATED;
1044
1045 while (1)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001046 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001047 /* As soon as anything returns BOGUS, we stop and unwind, to do otherwise
1048 would invite infinite loops, since the answers to DNSKEY and DS queries
1049 will not be cached, so they'll be repeated. */
1050 if (status != STAT_BOGUS && status != STAT_TRUNCATED && status != STAT_ABANDONED)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001051 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001052 if (forward->flags & FREC_DNSKEY_QUERY)
1053 status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
1054 else if (forward->flags & FREC_DS_QUERY)
1055 status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001056 else
Simon Kelley9a31b682015-12-15 10:20:39 +00001057 status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class,
Simon Kelley203ce0a2019-10-12 21:41:20 +01001058 !option_bool(OPT_DNSSEC_IGN_NS) && (forward->sentto->flags & SERV_DO_DNSSEC),
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001059 NULL, NULL, NULL);
Simon Kelley6b173352018-05-08 18:32:14 +01001060#ifdef HAVE_DUMPFILE
1061 if (status == STAT_BOGUS)
1062 dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_BOGUS : DUMP_BOGUS,
1063 header, (size_t)n, &serveraddr, NULL);
1064#endif
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001065 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001066
Simon Kelley9a31b682015-12-15 10:20:39 +00001067 /* Can't validate, as we're missing key data. Put this
1068 answer aside, whilst we get that. */
1069 if (status == STAT_NEED_DS || status == STAT_NEED_KEY)
Simon Kelley3a237152013-12-12 12:15:50 +00001070 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001071 struct frec *new, *orig;
Simon Kelley9d633042013-12-13 15:36:55 +00001072
Simon Kelley9a31b682015-12-15 10:20:39 +00001073 /* Free any saved query */
1074 if (forward->stash)
1075 blockdata_free(forward->stash);
1076
1077 /* Now save reply pending receipt of key data */
1078 if (!(forward->stash = blockdata_alloc((char *)header, n)))
Simon Kelley97e618a2015-01-07 21:55:43 +00001079 return;
Simon Kelley9a31b682015-12-15 10:20:39 +00001080 forward->stash_len = n;
Simon Kelleye0c0ad32014-01-16 22:42:07 +00001081
Simon Kelley9a31b682015-12-15 10:20:39 +00001082 /* Find the original query that started it all.... */
1083 for (orig = forward; orig->dependent; orig = orig->dependent);
Simon Kelley7fa836e2014-02-10 20:11:24 +00001084
Simon Kelley8caf3d72020-04-04 17:00:32 +01001085 /* Make sure we don't expire and free the orig frec during the
1086 allocation of a new one. */
1087 if (--orig->work_counter == 0 || !(new = get_new_frec(now, NULL, orig)))
Simon Kelley9a31b682015-12-15 10:20:39 +00001088 status = STAT_ABANDONED;
Simon Kelleye0c0ad32014-01-16 22:42:07 +00001089 else
Simon Kelley3a237152013-12-12 12:15:50 +00001090 {
Simon Kelleye1791f32018-10-06 23:23:23 +01001091 int querytype, fd, type = SERV_DO_DNSSEC;
Simon Kelley9a31b682015-12-15 10:20:39 +00001092 struct frec *next = new->next;
Simon Kelley92be34a2016-01-16 18:39:54 +00001093 char *domain;
1094
Simon Kelley9a31b682015-12-15 10:20:39 +00001095 *new = *forward; /* copy everything, then overwrite */
1096 new->next = next;
1097 new->blocking_query = NULL;
Simon Kelley92be34a2016-01-16 18:39:54 +00001098
1099 /* Find server to forward to. This will normally be the
1100 same as for the original query, but may be another if
1101 servers for domains are involved. */
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001102 if (search_servers(now, NULL, F_DNSSECOK, daemon->keyname, &type, &domain, NULL) == 0)
Simon Kelley92be34a2016-01-16 18:39:54 +00001103 {
Simon Kelley203ce0a2019-10-12 21:41:20 +01001104 struct server *start, *new_server = NULL;
1105 start = server = forward->sentto;
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001106
1107 while (1)
1108 {
Petr Menšík8f9bd612021-03-27 23:16:09 +00001109 if (server_test_type(start, domain, type, SERV_DO_DNSSEC))
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001110 {
1111 new_server = start;
1112 if (server == start)
1113 {
1114 new_server = NULL;
1115 break;
1116 }
1117 }
1118
1119 if (!(start = start->next))
1120 start = daemon->servers;
1121 if (start == server)
1122 break;
1123 }
1124
1125 if (new_server)
1126 server = new_server;
Simon Kelley92be34a2016-01-16 18:39:54 +00001127 }
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001128
Simon Kelley9a31b682015-12-15 10:20:39 +00001129 new->sentto = server;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00001130 new->rfds = NULL;
Simon Kelley15b60dd2020-11-18 18:34:55 +00001131 new->frec_src.next = NULL;
Simon Kelleya0088e82018-05-10 21:43:14 +01001132 new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_HAS_EXTRADATA);
1133 new->forwardall = 0;
Simon Kelley9a31b682015-12-15 10:20:39 +00001134
1135 new->dependent = forward; /* to find query awaiting new one. */
1136 forward->blocking_query = new; /* for garbage cleaning */
1137 /* validate routines leave name of required record in daemon->keyname */
1138 if (status == STAT_NEED_KEY)
Simon Kelley7fa836e2014-02-10 20:11:24 +00001139 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001140 new->flags |= FREC_DNSKEY_QUERY;
Simon Kelleye1791f32018-10-06 23:23:23 +01001141 querytype = T_DNSKEY;
Simon Kelleyf1668d22014-01-08 16:53:27 +00001142 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001143 else
1144 {
1145 new->flags |= FREC_DS_QUERY;
Simon Kelleye1791f32018-10-06 23:23:23 +01001146 querytype = T_DS;
Simon Kelley9a31b682015-12-15 10:20:39 +00001147 }
Simon Kelleye1791f32018-10-06 23:23:23 +01001148
1149 nn = dnssec_generate_query(header,((unsigned char *) header) + server->edns_pktsz,
1150 daemon->keyname, forward->class, querytype, server->edns_pktsz);
1151
Simon Kelley2d765862020-11-12 22:06:07 +00001152 memcpy(new->hash, hash_questions(header, nn, daemon->namebuff), HASH_SIZE);
Simon Kelley9a31b682015-12-15 10:20:39 +00001153 new->new_id = get_id();
1154 header->id = htons(new->new_id);
1155 /* Save query for retransmission */
1156 new->stash = blockdata_alloc((char *)header, nn);
1157 new->stash_len = nn;
1158
1159 /* Don't resend this. */
1160 daemon->srv_save = NULL;
1161
Simon Kelley74d4fcd2021-03-15 21:59:51 +00001162 if ((fd = allocate_rfd(&new->rfds, server)) != -1)
Simon Kelley9a31b682015-12-15 10:20:39 +00001163 {
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001164#ifdef HAVE_CONNTRACK
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001165 if (option_bool(OPT_CONNTRACK))
Petr Menšík6c0bf792021-03-18 00:07:45 +01001166 set_outgoing_mark(orig, fd);
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001167#endif
Petr Menšík51f7bc92021-03-18 01:05:43 +01001168 server_send_log(server, fd, header, nn, DUMP_SEC_QUERY,
1169 F_NOEXTRA | F_DNSSEC, daemon->keyname,
1170 querystr("dnssec-query", querytype));
Simon Kelley9a31b682015-12-15 10:20:39 +00001171 server->queries++;
1172 }
1173 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00001174 return;
Simon Kelley3a237152013-12-12 12:15:50 +00001175 }
Simon Kelley3a237152013-12-12 12:15:50 +00001176
Simon Kelley9a31b682015-12-15 10:20:39 +00001177 /* Validated original answer, all done. */
1178 if (!forward->dependent)
1179 break;
1180
Josh Soref730c6742017-02-06 16:14:04 +00001181 /* validated subsidiary query, (and cached result)
Simon Kelley9a31b682015-12-15 10:20:39 +00001182 pop that and return to the previous query we were working on. */
Simon Kelley0744ca62014-01-25 16:40:15 +00001183 struct frec *prev = forward->dependent;
1184 free_frec(forward);
1185 forward = prev;
1186 forward->blocking_query = NULL; /* already gone */
1187 blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
1188 n = forward->stash_len;
Simon Kelley3a237152013-12-12 12:15:50 +00001189 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001190
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001191
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001192 no_cache_dnssec = 0;
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001193
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001194 if (status == STAT_TRUNCATED)
Simon Kelley0744ca62014-01-25 16:40:15 +00001195 header->hb3 |= HB3_TC;
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001196 else
Simon Kelley7fa836e2014-02-10 20:11:24 +00001197 {
Simon Kelley554b5802015-04-17 22:50:20 +01001198 char *result, *domain = "result";
Simon Kelley7fa836e2014-02-10 20:11:24 +00001199
Simon Kelley9a31b682015-12-15 10:20:39 +00001200 if (status == STAT_ABANDONED)
Simon Kelley150162b2015-03-27 09:58:26 +00001201 {
1202 result = "ABANDONED";
1203 status = STAT_BOGUS;
1204 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00001205 else
1206 result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
1207
Simon Kelley554b5802015-04-17 22:50:20 +01001208 if (status == STAT_BOGUS && extract_request(header, n, daemon->namebuff, NULL))
1209 domain = daemon->namebuff;
Simon Kelley9a31b682015-12-15 10:20:39 +00001210
Simon Kelley07ed5852018-05-04 21:52:22 +01001211 log_query(F_SECSTAT, domain, NULL, result);
Simon Kelley7fa836e2014-02-10 20:11:24 +00001212 }
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001213
Simon Kelley3a237152013-12-12 12:15:50 +00001214 if (status == STAT_SECURE)
1215 cache_secure = 1;
Simon Kelley3a237152013-12-12 12:15:50 +00001216 else if (status == STAT_BOGUS)
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001217 {
1218 no_cache_dnssec = 1;
1219 bogusanswer = 1;
1220 }
Simon Kelley3a237152013-12-12 12:15:50 +00001221 }
Simon Kelley04db1482019-10-11 23:22:17 +01001222
Simon Kelley6b173352018-05-08 18:32:14 +01001223#endif
1224
Simon Kelley83349b82014-02-10 21:02:01 +00001225 /* restore CD bit to the value in the query */
1226 if (forward->flags & FREC_CHECKING_DISABLED)
1227 header->hb4 |= HB4_CD;
1228 else
1229 header->hb4 &= ~HB4_CD;
Simon Kelley25e63f12020-11-25 21:17:52 +00001230
1231 /* Never cache answers which are contingent on the source or MAC address EDSN0 option,
1232 since the cache is ignorant of such things. */
1233 if (forward->flags & FREC_NO_CACHE)
1234 no_cache_dnssec = 1;
Simon Kelley3a237152013-12-12 12:15:50 +00001235
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001236 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 +00001237 forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION,
Simon Kelley15b60dd2020-11-18 18:34:55 +00001238 forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->frec_src.source)))
Simon Kelley832af0b2007-01-21 20:01:28 +00001239 {
Simon Kelley15b60dd2020-11-18 18:34:55 +00001240 struct frec_src *src;
1241
1242 header->id = htons(forward->frec_src.orig_id);
Simon Kelley572b41e2011-02-18 18:11:18 +00001243 header->hb4 |= HB4_RA; /* recursion if available */
Simon Kelley5aa5f0f2015-12-21 17:20:35 +00001244#ifdef HAVE_DNSSEC
1245 /* 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 +01001246 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 +00001247 header, the answer is still bigger than 512, truncate it and mark it so. The client then retries with TCP. */
1248 if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER) && (nn > PACKETSZ))
1249 {
1250 header->ancount = htons(0);
1251 header->nscount = htons(0);
1252 header->arcount = htons(0);
1253 header->hb3 |= HB3_TC;
1254 nn = resize_packet(header, nn, NULL, 0);
1255 }
1256#endif
Simon Kelley6b173352018-05-08 18:32:14 +01001257
Simon Kelley15b60dd2020-11-18 18:34:55 +00001258 for (src = &forward->frec_src; src; src = src->next)
1259 {
1260 header->id = htons(src->orig_id);
1261
Simon Kelley6b173352018-05-08 18:32:14 +01001262#ifdef HAVE_DUMPFILE
Simon Kelley15b60dd2020-11-18 18:34:55 +00001263 dump_packet(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &src->source);
Simon Kelley6b173352018-05-08 18:32:14 +01001264#endif
Simon Kelley15b60dd2020-11-18 18:34:55 +00001265
Simon Kelley04490bf2021-01-22 16:49:12 +00001266 send_from(src->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
Simon Kelley15b60dd2020-11-18 18:34:55 +00001267 &src->source, &src->dest, src->iface);
1268
1269 if (option_bool(OPT_EXTRALOG) && src != &forward->frec_src)
1270 {
1271 daemon->log_display_id = src->log_id;
1272 daemon->log_source_addr = &src->source;
1273 log_query(F_UPSTREAM, "query", NULL, "duplicate");
1274 }
1275 }
Simon Kelley832af0b2007-01-21 20:01:28 +00001276 }
Simon Kelley15b60dd2020-11-18 18:34:55 +00001277
Simon Kelley1a6bca82008-07-11 11:11:42 +01001278 free_frec(forward); /* cancel */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001279 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001280}
Simon Kelley44a2a312004-03-10 20:04:35 +00001281
Simon Kelley1a6bca82008-07-11 11:11:42 +01001282
Simon Kelley5aabfc72007-08-29 11:24:47 +01001283void receive_query(struct listener *listen, time_t now)
Simon Kelley44a2a312004-03-10 20:04:35 +00001284{
Simon Kelley572b41e2011-02-18 18:11:18 +00001285 struct dns_header *header = (struct dns_header *)daemon->packet;
Simon Kelley44a2a312004-03-10 20:04:35 +00001286 union mysockaddr source_addr;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001287 unsigned char *pheader;
1288 unsigned short type, udp_size = PACKETSZ; /* default if no EDNS0 */
Simon Kelleycc921df2019-01-02 22:48:59 +00001289 union all_addr dst_addr;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001290 struct in_addr netmask, dst_addr_4;
Simon Kelleycdeda282006-03-16 20:16:06 +00001291 size_t m;
1292 ssize_t n;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001293 int if_index = 0, auth_dns = 0, do_bit = 0, have_pseudoheader = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001294#ifdef HAVE_AUTH
1295 int local_auth = 0;
1296#endif
Simon Kelley44a2a312004-03-10 20:04:35 +00001297 struct iovec iov[1];
1298 struct msghdr msg;
1299 struct cmsghdr *cmptr;
Simon Kelley44a2a312004-03-10 20:04:35 +00001300 union {
1301 struct cmsghdr align; /* this ensures alignment */
Simon Kelley44a2a312004-03-10 20:04:35 +00001302 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001303#if defined(HAVE_LINUX_NETWORK)
Simon Kelley44a2a312004-03-10 20:04:35 +00001304 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
Simon Kelley824af852008-02-12 20:43:05 +00001305#elif defined(IP_RECVDSTADDR) && defined(HAVE_SOLARIS_NETWORK)
1306 char control[CMSG_SPACE(sizeof(struct in_addr)) +
1307 CMSG_SPACE(sizeof(unsigned int))];
Simon Kelley44a2a312004-03-10 20:04:35 +00001308#elif defined(IP_RECVDSTADDR)
1309 char control[CMSG_SPACE(sizeof(struct in_addr)) +
1310 CMSG_SPACE(sizeof(struct sockaddr_dl))];
1311#endif
1312 } control_u;
Petr Menšík1c1b9252019-07-15 17:16:44 +02001313 int family = listen->addr.sa.sa_family;
Simon Kelley2329bef2013-12-03 13:41:16 +00001314 /* Can always get recvd interface for IPv6 */
Petr Menšík1c1b9252019-07-15 17:16:44 +02001315 int check_dst = !option_bool(OPT_NOWILD) || family == AF_INET6;
Simon Kelley2329bef2013-12-03 13:41:16 +00001316
Simon Kelleycdeda282006-03-16 20:16:06 +00001317 /* packet buffer overwritten */
1318 daemon->srv_save = NULL;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00001319
Simon Kelleycc921df2019-01-02 22:48:59 +00001320 dst_addr_4.s_addr = dst_addr.addr4.s_addr = 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001321 netmask.s_addr = 0;
1322
Simon Kelley7e5664b2013-04-05 16:57:41 +01001323 if (option_bool(OPT_NOWILD) && listen->iface)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001324 {
Simon Kelley4f7b3042012-11-28 21:27:02 +00001325 auth_dns = listen->iface->dns_auth;
1326
Petr Menšík1c1b9252019-07-15 17:16:44 +02001327 if (family == AF_INET)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001328 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001329 dst_addr_4 = dst_addr.addr4 = listen->iface->addr.in.sin_addr;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001330 netmask = listen->iface->netmask;
1331 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001332 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00001333
Simon Kelley3be34542004-09-11 19:12:13 +01001334 iov[0].iov_base = daemon->packet;
1335 iov[0].iov_len = daemon->edns_pktsz;
Simon Kelley44a2a312004-03-10 20:04:35 +00001336
1337 msg.msg_control = control_u.control;
1338 msg.msg_controllen = sizeof(control_u);
1339 msg.msg_flags = 0;
1340 msg.msg_name = &source_addr;
1341 msg.msg_namelen = sizeof(source_addr);
1342 msg.msg_iov = iov;
1343 msg.msg_iovlen = 1;
1344
Simon Kelleyde379512004-06-22 20:23:33 +01001345 if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
Simon Kelley3be34542004-09-11 19:12:13 +01001346 return;
Simon Kelley44a2a312004-03-10 20:04:35 +00001347
Simon Kelley572b41e2011-02-18 18:11:18 +00001348 if (n < (int)sizeof(struct dns_header) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001349 (msg.msg_flags & MSG_TRUNC) ||
Simon Kelley572b41e2011-02-18 18:11:18 +00001350 (header->hb3 & HB3_QR))
Simon Kelley3be34542004-09-11 19:12:13 +01001351 return;
Simon Kelley63437ff2017-09-06 22:34:21 +01001352
1353 /* Clear buffer beyond request to avoid risk of
1354 information disclosure. */
1355 memset(daemon->packet + n, 0, daemon->edns_pktsz - n);
Simon Kelley44a2a312004-03-10 20:04:35 +00001356
Petr Menšík1c1b9252019-07-15 17:16:44 +02001357 source_addr.sa.sa_family = family;
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001358
Petr Menšík1c1b9252019-07-15 17:16:44 +02001359 if (family == AF_INET)
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001360 {
1361 /* Source-port == 0 is an error, we can't send back to that.
1362 http://www.ietf.org/mail-archive/web/dnsop/current/msg11441.html */
1363 if (source_addr.in.sin_port == 0)
1364 return;
1365 }
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001366 else
1367 {
1368 /* Source-port == 0 is an error, we can't send back to that. */
1369 if (source_addr.in6.sin6_port == 0)
1370 return;
1371 source_addr.in6.sin6_flowinfo = 0;
1372 }
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001373
Simon Kelleyc8a80482014-03-05 14:29:54 +00001374 /* We can be configured to only accept queries from at-most-one-hop-away addresses. */
1375 if (option_bool(OPT_LOCAL_SERVICE))
1376 {
1377 struct addrlist *addr;
Simon Kelleyee875042018-10-23 22:10:17 +01001378
Petr Menšík1c1b9252019-07-15 17:16:44 +02001379 if (family == AF_INET6)
Simon Kelleyc8a80482014-03-05 14:29:54 +00001380 {
1381 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1382 if ((addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001383 is_same_net6(&addr->addr.addr6, &source_addr.in6.sin6_addr, addr->prefixlen))
Simon Kelleyc8a80482014-03-05 14:29:54 +00001384 break;
1385 }
1386 else
Simon Kelleyc8a80482014-03-05 14:29:54 +00001387 {
1388 struct in_addr netmask;
1389 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1390 {
Richard Genoud15b1b7e2014-09-17 21:12:00 +01001391 netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
Simon Kelleyc8a80482014-03-05 14:29:54 +00001392 if (!(addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001393 is_same_net(addr->addr.addr4, source_addr.in.sin_addr, netmask))
Simon Kelleyc8a80482014-03-05 14:29:54 +00001394 break;
1395 }
1396 }
1397 if (!addr)
1398 {
Simon Kelley0c8584e2014-03-12 20:12:56 +00001399 static int warned = 0;
1400 if (!warned)
1401 {
1402 my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
1403 warned = 1;
1404 }
Simon Kelleyc8a80482014-03-05 14:29:54 +00001405 return;
1406 }
1407 }
1408
Simon Kelley2329bef2013-12-03 13:41:16 +00001409 if (check_dst)
Simon Kelley44a2a312004-03-10 20:04:35 +00001410 {
Simon Kelley8a911cc2004-03-16 18:35:52 +00001411 struct ifreq ifr;
1412
Simon Kelley26128d22004-11-14 16:43:54 +00001413 if (msg.msg_controllen < sizeof(struct cmsghdr))
1414 return;
1415
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001416#if defined(HAVE_LINUX_NETWORK)
Petr Menšík1c1b9252019-07-15 17:16:44 +02001417 if (family == AF_INET)
Simon Kelley26128d22004-11-14 16:43:54 +00001418 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelleyc72daea2012-01-05 21:33:27 +00001419 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
Simon Kelley26128d22004-11-14 16:43:54 +00001420 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001421 union {
1422 unsigned char *c;
1423 struct in_pktinfo *p;
1424 } p;
1425 p.c = CMSG_DATA(cmptr);
Simon Kelleycc921df2019-01-02 22:48:59 +00001426 dst_addr_4 = dst_addr.addr4 = p.p->ipi_spec_dst;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001427 if_index = p.p->ipi_ifindex;
Simon Kelley26128d22004-11-14 16:43:54 +00001428 }
1429#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
Petr Menšík1c1b9252019-07-15 17:16:44 +02001430 if (family == AF_INET)
Simon Kelley26128d22004-11-14 16:43:54 +00001431 {
1432 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001433 {
1434 union {
1435 unsigned char *c;
1436 unsigned int *i;
1437 struct in_addr *a;
1438#ifndef HAVE_SOLARIS_NETWORK
1439 struct sockaddr_dl *s;
Simon Kelley824af852008-02-12 20:43:05 +00001440#endif
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001441 } p;
1442 p.c = CMSG_DATA(cmptr);
1443 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
Simon Kelleycc921df2019-01-02 22:48:59 +00001444 dst_addr_4 = dst_addr.addr4 = *(p.a);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001445 else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
1446#ifdef HAVE_SOLARIS_NETWORK
1447 if_index = *(p.i);
1448#else
1449 if_index = p.s->sdl_index;
1450#endif
1451 }
Simon Kelley26128d22004-11-14 16:43:54 +00001452 }
1453#endif
1454
Petr Menšík1c1b9252019-07-15 17:16:44 +02001455 if (family == AF_INET6)
Simon Kelley26128d22004-11-14 16:43:54 +00001456 {
1457 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelleyc72daea2012-01-05 21:33:27 +00001458 if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
Simon Kelley26128d22004-11-14 16:43:54 +00001459 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001460 union {
1461 unsigned char *c;
1462 struct in6_pktinfo *p;
1463 } p;
1464 p.c = CMSG_DATA(cmptr);
1465
Simon Kelleycc921df2019-01-02 22:48:59 +00001466 dst_addr.addr6 = p.p->ipi6_addr;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001467 if_index = p.p->ipi6_ifindex;
Simon Kelley26128d22004-11-14 16:43:54 +00001468 }
1469 }
Simon Kelley26128d22004-11-14 16:43:54 +00001470
1471 /* enforce available interface configuration */
1472
Simon Kelleye25db1f2013-01-29 22:10:26 +00001473 if (!indextoname(listen->fd, if_index, ifr.ifr_name))
Simon Kelley832af0b2007-01-21 20:01:28 +00001474 return;
1475
Petr Menšík1c1b9252019-07-15 17:16:44 +02001476 if (!iface_check(family, &dst_addr, ifr.ifr_name, &auth_dns))
Simon Kelleye25db1f2013-01-29 22:10:26 +00001477 {
1478 if (!option_bool(OPT_CLEVERBIND))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001479 enumerate_interfaces(0);
Petr Menšík1c1b9252019-07-15 17:16:44 +02001480 if (!loopback_exception(listen->fd, family, &dst_addr, ifr.ifr_name) &&
1481 !label_exception(if_index, family, &dst_addr))
Simon Kelleye25db1f2013-01-29 22:10:26 +00001482 return;
1483 }
1484
Petr Menšík1c1b9252019-07-15 17:16:44 +02001485 if (family == AF_INET && option_bool(OPT_LOCALISE))
Simon Kelley552af8b2012-02-29 20:10:31 +00001486 {
1487 struct irec *iface;
1488
Josh Soref730c6742017-02-06 16:14:04 +00001489 /* get the netmask of the interface which has the address we were sent to.
klemens43517fc2017-02-19 15:53:37 +00001490 This is no necessarily the interface we arrived on. */
Simon Kelley552af8b2012-02-29 20:10:31 +00001491
1492 for (iface = daemon->interfaces; iface; iface = iface->next)
1493 if (iface->addr.sa.sa_family == AF_INET &&
1494 iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
1495 break;
1496
1497 /* interface may be new */
Simon Kelleye25db1f2013-01-29 22:10:26 +00001498 if (!iface && !option_bool(OPT_CLEVERBIND))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001499 enumerate_interfaces(0);
Simon Kelley552af8b2012-02-29 20:10:31 +00001500
1501 for (iface = daemon->interfaces; iface; iface = iface->next)
1502 if (iface->addr.sa.sa_family == AF_INET &&
1503 iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
1504 break;
1505
1506 /* If we failed, abandon localisation */
1507 if (iface)
1508 netmask = iface->netmask;
1509 else
1510 dst_addr_4.s_addr = 0;
1511 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001512 }
Simon Kelley25cf5e32015-01-09 15:53:03 +00001513
1514 /* log_query gets called indirectly all over the place, so
1515 pass these in global variables - sorry. */
1516 daemon->log_display_id = ++daemon->log_id;
1517 daemon->log_source_addr = &source_addr;
Simon Kelley6b173352018-05-08 18:32:14 +01001518
1519#ifdef HAVE_DUMPFILE
1520 dump_packet(DUMP_QUERY, daemon->packet, (size_t)n, &source_addr, NULL);
1521#endif
1522
Simon Kelleycdeda282006-03-16 20:16:06 +00001523 if (extract_request(header, (size_t)n, daemon->namebuff, &type))
Simon Kelley44a2a312004-03-10 20:04:35 +00001524 {
Simon Kelleyb485ed92013-10-18 22:00:39 +01001525#ifdef HAVE_AUTH
1526 struct auth_zone *zone;
1527#endif
Simon Kelley610e7822014-02-06 14:45:17 +00001528 char *types = querystr(auth_dns ? "auth" : "query", type);
Petr Menšík6c0bf792021-03-18 00:07:45 +01001529
1530 log_query_mysockaddr(F_QUERY | F_FORWARD, daemon->namebuff,
1531 &source_addr, types);
Simon Kelley44a2a312004-03-10 20:04:35 +00001532
Simon Kelley4820dce2012-12-18 18:30:30 +00001533#ifdef HAVE_AUTH
Simon Kelleyb485ed92013-10-18 22:00:39 +01001534 /* find queries for zones we're authoritative for, and answer them directly */
Simon Kelley3a3965a2015-08-09 17:45:06 +01001535 if (!auth_dns && !option_bool(OPT_LOCALISE))
Simon Kelley6008bdb2013-10-21 21:47:03 +01001536 for (zone = daemon->auth_zones; zone; zone = zone->next)
1537 if (in_zone(zone, daemon->namebuff, NULL))
1538 {
1539 auth_dns = 1;
1540 local_auth = 1;
1541 break;
1542 }
Simon Kelleyb485ed92013-10-18 22:00:39 +01001543#endif
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01001544
1545#ifdef HAVE_LOOP
1546 /* Check for forwarding loop */
1547 if (detect_loop(daemon->namebuff, type))
1548 return;
1549#endif
Simon Kelleyb485ed92013-10-18 22:00:39 +01001550 }
1551
Simon Kelley5bb88f02015-12-21 16:23:47 +00001552 if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL, NULL))
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001553 {
1554 unsigned short flags;
1555
1556 have_pseudoheader = 1;
1557 GETSHORT(udp_size, pheader);
1558 pheader += 2; /* ext_rcode */
1559 GETSHORT(flags, pheader);
1560
1561 if (flags & 0x8000)
1562 do_bit = 1;/* do bit */
1563
1564 /* If the client provides an EDNS0 UDP size, use that to limit our reply.
1565 (bounded by the maximum configured). If no EDNS0, then it
1566 defaults to 512 */
1567 if (udp_size > daemon->edns_pktsz)
1568 udp_size = daemon->edns_pktsz;
Simon Kelleya3303e12017-09-07 20:45:00 +01001569 else if (udp_size < PACKETSZ)
1570 udp_size = PACKETSZ; /* Sanity check - can't reduce below default. RFC 6891 6.2.3 */
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001571 }
1572
Simon Kelleyb485ed92013-10-18 22:00:39 +01001573#ifdef HAVE_AUTH
Simon Kelley4f7b3042012-11-28 21:27:02 +00001574 if (auth_dns)
Simon Kelley824af852008-02-12 20:43:05 +00001575 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001576 m = answer_auth(header, ((char *) header) + udp_size, (size_t)n, now, &source_addr,
1577 local_auth, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001578 if (m >= 1)
Simon Kelleyb485ed92013-10-18 22:00:39 +01001579 {
1580 send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
1581 (char *)header, m, &source_addr, &dst_addr, if_index);
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001582 daemon->metrics[METRIC_DNS_AUTH_ANSWERED]++;
Simon Kelleyb485ed92013-10-18 22:00:39 +01001583 }
Simon Kelley824af852008-02-12 20:43:05 +00001584 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001585 else
Simon Kelley4820dce2012-12-18 18:30:30 +00001586#endif
Simon Kelley4f7b3042012-11-28 21:27:02 +00001587 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001588 int ad_reqd = do_bit;
1589 /* RFC 6840 5.7 */
1590 if (header->hb4 & HB4_AD)
1591 ad_reqd = 1;
1592
1593 m = answer_request(header, ((char *) header) + udp_size, (size_t)n,
1594 dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001595
1596 if (m >= 1)
1597 {
1598 send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
1599 (char *)header, m, &source_addr, &dst_addr, if_index);
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001600 daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001601 }
1602 else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
Simon Kelley613ad152014-02-25 23:02:28 +00001603 header, (size_t)n, now, NULL, ad_reqd, do_bit))
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001604 daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]++;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001605 else
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001606 daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001607 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001608}
1609
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001610#ifdef HAVE_DNSSEC
Josh Soref730c6742017-02-06 16:14:04 +00001611/* Recurse up the key hierarchy */
Simon Kelley7fa836e2014-02-10 20:11:24 +00001612static int tcp_key_recurse(time_t now, int status, struct dns_header *header, size_t n,
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001613 int class, char *name, char *keyname, struct server *server,
1614 int have_mark, unsigned int mark, int *keycount)
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001615{
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001616 int new_status;
Simon Kelley9a31b682015-12-15 10:20:39 +00001617 unsigned char *packet = NULL;
Simon Kelley9a31b682015-12-15 10:20:39 +00001618 unsigned char *payload = NULL;
1619 struct dns_header *new_header = NULL;
1620 u16 *length = NULL;
Simon Kelley361dfe52017-02-10 21:12:30 +00001621
Simon Kelley9a31b682015-12-15 10:20:39 +00001622 while (1)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001623 {
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001624 int type = SERV_DO_DNSSEC;
1625 char *domain;
1626 size_t m;
1627 unsigned char c1, c2;
Simon Kelley361dfe52017-02-10 21:12:30 +00001628 struct server *firstsendto = NULL;
1629
Simon Kelley9a31b682015-12-15 10:20:39 +00001630 /* limit the amount of work we do, to avoid cycling forever on loops in the DNS */
1631 if (--(*keycount) == 0)
1632 new_status = STAT_ABANDONED;
1633 else if (status == STAT_NEED_KEY)
1634 new_status = dnssec_validate_by_ds(now, header, n, name, keyname, class);
1635 else if (status == STAT_NEED_DS)
1636 new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
1637 else
James Bottomleye33b4872017-03-17 21:44:10 +00001638 new_status = dnssec_validate_reply(now, header, n, name, keyname, &class,
Simon Kelleya6918532018-04-15 16:20:52 +01001639 !option_bool(OPT_DNSSEC_IGN_NS) && (server->flags & SERV_DO_DNSSEC),
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001640 NULL, NULL, NULL);
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001641
Simon Kelley9a31b682015-12-15 10:20:39 +00001642 if (new_status != STAT_NEED_DS && new_status != STAT_NEED_KEY)
1643 break;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001644
Simon Kelley9a31b682015-12-15 10:20:39 +00001645 /* Can't validate because we need a key/DS whose name now in keyname.
1646 Make query for same, and recurse to validate */
Simon Kelley7fa836e2014-02-10 20:11:24 +00001647 if (!packet)
Simon Kelley9a31b682015-12-15 10:20:39 +00001648 {
1649 packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
1650 payload = &packet[2];
1651 new_header = (struct dns_header *)payload;
1652 length = (u16 *)packet;
1653 }
1654
1655 if (!packet)
1656 {
1657 new_status = STAT_ABANDONED;
1658 break;
1659 }
Simon Kelleye1791f32018-10-06 23:23:23 +01001660
Simon Kelley33702ab2015-12-28 23:17:15 +00001661 m = dnssec_generate_query(new_header, ((unsigned char *) new_header) + 65536, keyname, class,
Simon Kelleye1791f32018-10-06 23:23:23 +01001662 new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS, server->edns_pktsz);
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001663
Simon Kelley7fa836e2014-02-10 20:11:24 +00001664 *length = htons(m);
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001665
1666 /* Find server to forward to. This will normally be the
1667 same as for the original query, but may be another if
1668 servers for domains are involved. */
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001669 if (search_servers(now, NULL, F_DNSSECOK, keyname, &type, &domain, NULL) != 0)
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001670 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001671 new_status = STAT_ABANDONED;
1672 break;
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001673 }
Simon Kelley361dfe52017-02-10 21:12:30 +00001674
Simon Kelley361dfe52017-02-10 21:12:30 +00001675 while (1)
1676 {
Simon Kelley608aa9f2019-03-10 22:44:15 +00001677 int data_sent = 0;
1678
Simon Kelley361dfe52017-02-10 21:12:30 +00001679 if (!firstsendto)
1680 firstsendto = server;
1681 else
1682 {
1683 if (!(server = server->next))
1684 server = daemon->servers;
1685 if (server == firstsendto)
1686 {
1687 /* can't find server to accept our query. */
1688 new_status = STAT_ABANDONED;
1689 break;
1690 }
1691 }
1692
Petr Menšíke10a9232021-03-15 11:20:49 +01001693 if (!server_test_type(server, domain, type, SERV_DO_DNSSEC))
Simon Kelley361dfe52017-02-10 21:12:30 +00001694 continue;
Simon Kelleye1791f32018-10-06 23:23:23 +01001695
1696 retry:
1697 /* may need to make new connection. */
1698 if (server->tcpfd == -1)
1699 {
1700 if ((server->tcpfd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
1701 continue; /* No good, next server */
1702
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001703#ifdef HAVE_CONNTRACK
Simon Kelleye1791f32018-10-06 23:23:23 +01001704 /* Copy connection mark of incoming query to outgoing connection. */
1705 if (have_mark)
1706 setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001707#endif
Simon Kelleye1791f32018-10-06 23:23:23 +01001708
Simon Kelley608aa9f2019-03-10 22:44:15 +00001709 if (!local_bind(server->tcpfd, &server->source_addr, server->interface, 0, 1))
1710 {
1711 close(server->tcpfd);
1712 server->tcpfd = -1;
1713 continue; /* No good, next server */
1714 }
1715
1716#ifdef MSG_FASTOPEN
Petr Menšík51f7bc92021-03-18 01:05:43 +01001717 server_send(server, server->tcpfd, packet, m + sizeof(u16), MSG_FASTOPEN);
1718
Simon Kelley608aa9f2019-03-10 22:44:15 +00001719 if (errno == 0)
1720 data_sent = 1;
1721#endif
1722
1723 if (!data_sent && connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) == -1)
Simon Kelleye1791f32018-10-06 23:23:23 +01001724 {
1725 close(server->tcpfd);
1726 server->tcpfd = -1;
1727 continue; /* No good, next server */
1728 }
1729
1730 server->flags &= ~SERV_GOT_TCP;
1731 }
Simon Kelley361dfe52017-02-10 21:12:30 +00001732
Simon Kelley608aa9f2019-03-10 22:44:15 +00001733 if ((!data_sent && !read_write(server->tcpfd, packet, m + sizeof(u16), 0)) ||
Simon Kelley361dfe52017-02-10 21:12:30 +00001734 !read_write(server->tcpfd, &c1, 1, 1) ||
1735 !read_write(server->tcpfd, &c2, 1, 1) ||
1736 !read_write(server->tcpfd, payload, (c1 << 8) | c2, 1))
1737 {
1738 close(server->tcpfd);
1739 server->tcpfd = -1;
1740 /* We get data then EOF, reopen connection to same server,
1741 else try next. This avoids DoS from a server which accepts
1742 connections and then closes them. */
1743 if (server->flags & SERV_GOT_TCP)
1744 goto retry;
1745 else
1746 continue;
1747 }
Simon Kelleye1791f32018-10-06 23:23:23 +01001748
Petr Menšík6c0bf792021-03-18 00:07:45 +01001749 log_query_mysockaddr(F_NOEXTRA | F_DNSSEC, keyname, &server->addr,
1750 querystr("dnssec-query", new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS));
Simon Kelleye1791f32018-10-06 23:23:23 +01001751
Simon Kelley361dfe52017-02-10 21:12:30 +00001752 server->flags |= SERV_GOT_TCP;
1753
1754 m = (c1 << 8) | c2;
1755 new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, have_mark, mark, keycount);
1756 break;
1757 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001758
1759 if (new_status != STAT_OK)
1760 break;
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001761 }
Simon Kelley361dfe52017-02-10 21:12:30 +00001762
Simon Kelley9a31b682015-12-15 10:20:39 +00001763 if (packet)
1764 free(packet);
1765
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001766 return new_status;
1767}
1768#endif
1769
1770
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001771/* The daemon forks before calling this: it should deal with one connection,
Josh Soref730c6742017-02-06 16:14:04 +00001772 blocking as necessary, and then return. Note, need to be a bit careful
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001773 about resources for debug mode, when the fork is suppressed: that's
1774 done by the caller. */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001775unsigned char *tcp_request(int confd, time_t now,
Simon Kelley4f7b3042012-11-28 21:27:02 +00001776 union mysockaddr *local_addr, struct in_addr netmask, int auth_dns)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001777{
Simon Kelley28866e92011-02-14 20:19:14 +00001778 size_t size = 0;
1779 int norebind = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001780#ifdef HAVE_AUTH
Simon Kelley19b16892013-10-20 10:19:39 +01001781 int local_auth = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001782#endif
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001783 int checking_disabled, do_bit, added_pheader = 0, have_pseudoheader = 0;
Simon Kelley25e63f12020-11-25 21:17:52 +00001784 int check_subnet, cacheable, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
Simon Kelleycdeda282006-03-16 20:16:06 +00001785 size_t m;
Simon Kelleyee86ce62012-12-07 11:54:46 +00001786 unsigned short qtype;
1787 unsigned int gotname;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001788 unsigned char c1, c2;
Simon Kelley4b5ea122013-04-22 10:18:26 +01001789 /* Max TCP packet + slop + size */
1790 unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
1791 unsigned char *payload = &packet[2];
1792 /* largest field in header is 16-bits, so this is still sufficiently aligned */
1793 struct dns_header *header = (struct dns_header *)payload;
1794 u16 *length = (u16 *)packet;
Simon Kelley3be34542004-09-11 19:12:13 +01001795 struct server *last_server;
Simon Kelley7de060b2011-08-26 17:24:52 +01001796 struct in_addr dst_addr_4;
1797 union mysockaddr peer_addr;
1798 socklen_t peer_len = sizeof(union mysockaddr);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001799 int query_count = 0;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001800 unsigned char *pheader;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001801 unsigned int mark = 0;
1802 int have_mark = 0;
Simon Kelley25cf5e32015-01-09 15:53:03 +00001803
Simon Kelleyd05dd582016-01-19 21:23:30 +00001804 (void)mark;
1805 (void)have_mark;
1806
Simon Kelley7de060b2011-08-26 17:24:52 +01001807 if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
1808 return packet;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001809
1810#ifdef HAVE_CONNTRACK
1811 /* Get connection mark of incoming query to set on outgoing connections. */
1812 if (option_bool(OPT_CONNTRACK))
1813 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001814 union all_addr local;
Simon Kelleyee875042018-10-23 22:10:17 +01001815
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001816 if (local_addr->sa.sa_family == AF_INET6)
Simon Kelleycc921df2019-01-02 22:48:59 +00001817 local.addr6 = local_addr->in6.sin6_addr;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001818 else
Simon Kelleycc921df2019-01-02 22:48:59 +00001819 local.addr4 = local_addr->in.sin_addr;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001820
1821 have_mark = get_incoming_mark(&peer_addr, &local, 1, &mark);
1822 }
1823#endif
1824
Simon Kelleyc8a80482014-03-05 14:29:54 +00001825 /* We can be configured to only accept queries from at-most-one-hop-away addresses. */
1826 if (option_bool(OPT_LOCAL_SERVICE))
1827 {
1828 struct addrlist *addr;
Simon Kelleyee875042018-10-23 22:10:17 +01001829
Simon Kelleyc8a80482014-03-05 14:29:54 +00001830 if (peer_addr.sa.sa_family == AF_INET6)
1831 {
1832 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1833 if ((addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001834 is_same_net6(&addr->addr.addr6, &peer_addr.in6.sin6_addr, addr->prefixlen))
Simon Kelleyc8a80482014-03-05 14:29:54 +00001835 break;
1836 }
1837 else
Simon Kelleyc8a80482014-03-05 14:29:54 +00001838 {
1839 struct in_addr netmask;
1840 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1841 {
Richard Genoud15b1b7e2014-09-17 21:12:00 +01001842 netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
Simon Kelleyc8a80482014-03-05 14:29:54 +00001843 if (!(addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001844 is_same_net(addr->addr.addr4, peer_addr.in.sin_addr, netmask))
Simon Kelleyc8a80482014-03-05 14:29:54 +00001845 break;
1846 }
1847 }
1848 if (!addr)
1849 {
1850 my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
1851 return packet;
1852 }
1853 }
Simon Kelley7de060b2011-08-26 17:24:52 +01001854
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001855 while (1)
1856 {
Simon Kelley25cf5e32015-01-09 15:53:03 +00001857 if (query_count == TCP_MAX_QUERIES ||
1858 !packet ||
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001859 !read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
1860 !(size = c1 << 8 | c2) ||
Simon Kelley4b5ea122013-04-22 10:18:26 +01001861 !read_write(confd, payload, size, 1))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001862 return packet;
1863
Simon Kelley572b41e2011-02-18 18:11:18 +00001864 if (size < (int)sizeof(struct dns_header))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001865 continue;
Simon Kelley63437ff2017-09-06 22:34:21 +01001866
1867 /* Clear buffer beyond request to avoid risk of
1868 information disclosure. */
1869 memset(payload + size, 0, 65536 - size);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001870
Simon Kelley25cf5e32015-01-09 15:53:03 +00001871 query_count++;
1872
1873 /* log_query gets called indirectly all over the place, so
1874 pass these in global variables - sorry. */
1875 daemon->log_display_id = ++daemon->log_id;
1876 daemon->log_source_addr = &peer_addr;
1877
Simon Kelley28866e92011-02-14 20:19:14 +00001878 /* save state of "cd" flag in query */
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001879 if ((checking_disabled = header->hb4 & HB4_CD))
1880 no_cache_dnssec = 1;
Simon Kelley28866e92011-02-14 20:19:14 +00001881
Simon Kelley3be34542004-09-11 19:12:13 +01001882 if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001883 {
Simon Kelleyb485ed92013-10-18 22:00:39 +01001884#ifdef HAVE_AUTH
1885 struct auth_zone *zone;
1886#endif
Simon Kelley610e7822014-02-06 14:45:17 +00001887 char *types = querystr(auth_dns ? "auth" : "query", qtype);
Simon Kelley7de060b2011-08-26 17:24:52 +01001888
Petr Menšík6c0bf792021-03-18 00:07:45 +01001889 log_query_mysockaddr(F_QUERY | F_FORWARD, daemon->namebuff,
1890 &peer_addr, types);
Simon Kelleyb485ed92013-10-18 22:00:39 +01001891
1892#ifdef HAVE_AUTH
1893 /* find queries for zones we're authoritative for, and answer them directly */
Simon Kelley3a3965a2015-08-09 17:45:06 +01001894 if (!auth_dns && !option_bool(OPT_LOCALISE))
Simon Kelley6008bdb2013-10-21 21:47:03 +01001895 for (zone = daemon->auth_zones; zone; zone = zone->next)
1896 if (in_zone(zone, daemon->namebuff, NULL))
1897 {
1898 auth_dns = 1;
1899 local_auth = 1;
1900 break;
1901 }
Simon Kelleyb485ed92013-10-18 22:00:39 +01001902#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001903 }
1904
Simon Kelley7de060b2011-08-26 17:24:52 +01001905 if (local_addr->sa.sa_family == AF_INET)
1906 dst_addr_4 = local_addr->in.sin_addr;
1907 else
1908 dst_addr_4.s_addr = 0;
1909
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001910 do_bit = 0;
1911
Simon Kelley5bb88f02015-12-21 16:23:47 +00001912 if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL, NULL))
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001913 {
1914 unsigned short flags;
1915
1916 have_pseudoheader = 1;
1917 pheader += 4; /* udp_size, ext_rcode */
1918 GETSHORT(flags, pheader);
1919
1920 if (flags & 0x8000)
Simon Kelley5bb88f02015-12-21 16:23:47 +00001921 do_bit = 1; /* do bit */
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001922 }
1923
Simon Kelley4820dce2012-12-18 18:30:30 +00001924#ifdef HAVE_AUTH
Simon Kelley4f7b3042012-11-28 21:27:02 +00001925 if (auth_dns)
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001926 m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr,
1927 local_auth, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001928 else
Simon Kelley4820dce2012-12-18 18:30:30 +00001929#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001930 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001931 int ad_reqd = do_bit;
1932 /* RFC 6840 5.7 */
1933 if (header->hb4 & HB4_AD)
1934 ad_reqd = 1;
1935
1936 /* m > 0 if answered from cache */
1937 m = answer_request(header, ((char *) header) + 65536, (size_t)size,
1938 dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001939
Simon Kelley4f7b3042012-11-28 21:27:02 +00001940 /* Do this by steam now we're not in the select() loop */
Simon Kelleyb842bc92015-07-12 21:09:11 +01001941 check_log_writer(1);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001942
1943 if (m == 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001944 {
Simon Kelley4f7b3042012-11-28 21:27:02 +00001945 unsigned int flags = 0;
Simon Kelleycc921df2019-01-02 22:48:59 +00001946 union all_addr *addrp = NULL;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001947 int type = SERV_DO_DNSSEC;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001948 char *domain = NULL;
Simon Kelley6fd5d792017-10-13 22:26:40 +01001949 unsigned char *oph = find_pseudoheader(header, size, NULL, NULL, NULL, NULL);
Simon Kelleyed4c0762013-10-08 20:46:34 +01001950
Simon Kelley4f7b3042012-11-28 21:27:02 +00001951 if (gotname)
1952 flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
Simon Kelley6fd5d792017-10-13 22:26:40 +01001953
Kyle Swensonba77fe82021-11-19 09:33:46 -07001954 if(!option_bool(OPT_EDNS_RESTRICT) || (option_bool(OPT_EDNS_RESTRICT) && !domain))
1955 size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet, &cacheable);
1956
Simon Kelley6fd5d792017-10-13 22:26:40 +01001957#ifdef HAVE_DNSSEC
1958 if (option_bool(OPT_DNSSEC_VALID) && (type & SERV_DO_DNSSEC))
1959 {
1960 size = add_do_bit(header, size, ((unsigned char *) header) + 65536);
1961
1962 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
1963 this allows it to select auth servers when one is returning bad data. */
1964 if (option_bool(OPT_DNSSEC_DEBUG))
1965 header->hb4 |= HB4_CD;
1966 }
1967#endif
1968
1969 /* Check if we added a pheader on forwarding - may need to
1970 strip it from the reply. */
1971 if (!oph && find_pseudoheader(header, size, NULL, NULL, NULL, NULL))
1972 added_pheader = 1;
1973
Simon Kelley367341f2016-01-12 15:58:23 +00001974 type &= ~SERV_DO_DNSSEC;
Simon Kelley367341f2016-01-12 15:58:23 +00001975
Simon Kelley4f7b3042012-11-28 21:27:02 +00001976 if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server)
1977 last_server = daemon->servers;
1978 else
1979 last_server = daemon->last_server;
1980
1981 if (!flags && last_server)
1982 {
1983 struct server *firstsendto = NULL;
Simon Kelley2d765862020-11-12 22:06:07 +00001984 unsigned char hash[HASH_SIZE];
1985 memcpy(hash, hash_questions(header, (unsigned int)size, daemon->namebuff), HASH_SIZE);
1986
Simon Kelley4f7b3042012-11-28 21:27:02 +00001987 /* Loop round available servers until we succeed in connecting to one.
Josh Soref730c6742017-02-06 16:14:04 +00001988 Note that this code subtly ensures that consecutive queries on this connection
Simon Kelley4f7b3042012-11-28 21:27:02 +00001989 which can go to the same server, do so. */
1990 while (1)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001991 {
Simon Kelley608aa9f2019-03-10 22:44:15 +00001992 int data_sent = 0;
1993
Simon Kelley4f7b3042012-11-28 21:27:02 +00001994 if (!firstsendto)
1995 firstsendto = last_server;
1996 else
1997 {
1998 if (!(last_server = last_server->next))
1999 last_server = daemon->servers;
2000
2001 if (last_server == firstsendto)
2002 break;
2003 }
2004
2005 /* server for wrong domain */
Petr Menšíke10a9232021-03-15 11:20:49 +01002006 if (!server_test_type(last_server, domain, type, 0))
Simon Kelley7de060b2011-08-26 17:24:52 +01002007 continue;
Simon Kelley361dfe52017-02-10 21:12:30 +00002008
2009 retry:
Simon Kelley608aa9f2019-03-10 22:44:15 +00002010 *length = htons(size);
2011
Simon Kelley4f7b3042012-11-28 21:27:02 +00002012 if (last_server->tcpfd == -1)
2013 {
2014 if ((last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
2015 continue;
2016
Karl Vogele9828b62014-10-03 21:45:15 +01002017#ifdef HAVE_CONNTRACK
2018 /* Copy connection mark of incoming query to outgoing connection. */
Simon Kelleyf344dbc2016-01-18 18:04:17 +00002019 if (have_mark)
2020 setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
Simon Kelley608aa9f2019-03-10 22:44:15 +00002021#endif
Karl Vogele9828b62014-10-03 21:45:15 +01002022
Simon Kelley608aa9f2019-03-10 22:44:15 +00002023 if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 0, 1)))
2024 {
2025 close(last_server->tcpfd);
2026 last_server->tcpfd = -1;
2027 continue;
2028 }
2029
2030#ifdef MSG_FASTOPEN
黎醒聪ffa46282021-03-22 22:00:26 +00002031 server_send(last_server, last_server->tcpfd, packet, size + sizeof(u16), MSG_FASTOPEN);
Petr Menšík51f7bc92021-03-18 01:05:43 +01002032
Simon Kelley608aa9f2019-03-10 22:44:15 +00002033 if (errno == 0)
2034 data_sent = 1;
2035#endif
2036
2037 if (!data_sent && connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1)
Simon Kelley4f7b3042012-11-28 21:27:02 +00002038 {
2039 close(last_server->tcpfd);
2040 last_server->tcpfd = -1;
2041 continue;
2042 }
2043
Simon Kelley361dfe52017-02-10 21:12:30 +00002044 last_server->flags &= ~SERV_GOT_TCP;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002045 }
2046
Simon Kelley1fc02682014-04-29 12:30:18 +01002047 /* get query name again for logging - may have been overwritten */
2048 if (!(gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
2049 strcpy(daemon->namebuff, "query");
Simon Kelley4f7b3042012-11-28 21:27:02 +00002050
Simon Kelley608aa9f2019-03-10 22:44:15 +00002051 if ((!data_sent && !read_write(last_server->tcpfd, packet, size + sizeof(u16), 0)) ||
Simon Kelley4f7b3042012-11-28 21:27:02 +00002052 !read_write(last_server->tcpfd, &c1, 1, 1) ||
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002053 !read_write(last_server->tcpfd, &c2, 1, 1) ||
2054 !read_write(last_server->tcpfd, payload, (c1 << 8) | c2, 1))
Simon Kelley7de060b2011-08-26 17:24:52 +01002055 {
2056 close(last_server->tcpfd);
2057 last_server->tcpfd = -1;
Simon Kelley361dfe52017-02-10 21:12:30 +00002058 /* We get data then EOF, reopen connection to same server,
2059 else try next. This avoids DoS from a server which accepts
2060 connections and then closes them. */
2061 if (last_server->flags & SERV_GOT_TCP)
2062 goto retry;
2063 else
2064 continue;
2065 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00002066
Simon Kelley361dfe52017-02-10 21:12:30 +00002067 last_server->flags |= SERV_GOT_TCP;
2068
Simon Kelley4f7b3042012-11-28 21:27:02 +00002069 m = (c1 << 8) | c2;
Petr Menšík6c0bf792021-03-18 00:07:45 +01002070
2071 log_query_mysockaddr(F_SERVER | F_FORWARD, daemon->namebuff,
2072 &last_server->addr, NULL);
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002073
2074#ifdef HAVE_DNSSEC
Simon Kelley367341f2016-01-12 15:58:23 +00002075 if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled && (last_server->flags & SERV_DO_DNSSEC))
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002076 {
Simon Kelley7fa836e2014-02-10 20:11:24 +00002077 int keycount = DNSSEC_WORK; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
Simon Kelleyf344dbc2016-01-18 18:04:17 +00002078 int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname,
2079 last_server, have_mark, mark, &keycount);
Simon Kelley554b5802015-04-17 22:50:20 +01002080 char *result, *domain = "result";
Simon Kelleyfe3992f2015-04-03 21:25:05 +01002081
Simon Kelley9a31b682015-12-15 10:20:39 +00002082 if (status == STAT_ABANDONED)
Simon Kelley150162b2015-03-27 09:58:26 +00002083 {
2084 result = "ABANDONED";
2085 status = STAT_BOGUS;
2086 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00002087 else
2088 result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
Simon Kelleye66b4df2015-04-28 20:45:57 +01002089
2090 if (status == STAT_BOGUS && extract_request(header, m, daemon->namebuff, NULL))
2091 domain = daemon->namebuff;
Simon Kelley554b5802015-04-17 22:50:20 +01002092
Simon Kelley07ed5852018-05-04 21:52:22 +01002093 log_query(F_SECSTAT, domain, NULL, result);
Simon Kelley7fa836e2014-02-10 20:11:24 +00002094
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002095 if (status == STAT_BOGUS)
Simon Kelleyfe3992f2015-04-03 21:25:05 +01002096 {
2097 no_cache_dnssec = 1;
2098 bogusanswer = 1;
2099 }
2100
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002101 if (status == STAT_SECURE)
2102 cache_secure = 1;
2103 }
2104#endif
2105
2106 /* restore CD bit to the value in the query */
2107 if (checking_disabled)
2108 header->hb4 |= HB4_CD;
2109 else
2110 header->hb4 &= ~HB4_CD;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002111
2112 /* There's no point in updating the cache, since this process will exit and
2113 lose the information after a few queries. We make this call for the alias and
2114 bogus-nxdomain side-effects. */
2115 /* If the crc of the question section doesn't match the crc we sent, then
2116 someone might be attempting to insert bogus values into the cache by
2117 sending replies containing questions and bogus answers. */
Simon Kelley2d765862020-11-12 22:06:07 +00002118 if (memcmp(hash, hash_questions(header, (unsigned int)m, daemon->namebuff), HASH_SIZE) != 0)
Simon Kelley703c7ff2014-01-25 23:46:23 +00002119 {
2120 m = 0;
2121 break;
2122 }
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002123
Simon Kelley25e63f12020-11-25 21:17:52 +00002124 /* Never cache answers which are contingent on the source or MAC address EDSN0 option,
2125 since the cache is ignorant of such things. */
2126 if (!cacheable)
2127 no_cache_dnssec = 1;
2128
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002129 m = process_reply(header, now, last_server, (unsigned int)m,
Simon Kelleye66b4df2015-04-28 20:45:57 +01002130 option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
Simon Kelleyfa14bec2015-12-20 17:12:16 +00002131 ad_reqd, do_bit, added_pheader, check_subnet, &peer_addr);
Simon Kelley4f7b3042012-11-28 21:27:02 +00002132
2133 break;
2134 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002135 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00002136
2137 /* In case of local answer or no connections made. */
2138 if (m == 0)
Simon Kelley1682d152018-08-03 20:38:18 +01002139 {
2140 m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl);
2141 if (have_pseudoheader)
2142 m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
2143 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002144 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002145 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00002146
Simon Kelleyb842bc92015-07-12 21:09:11 +01002147 check_log_writer(1);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002148
Simon Kelley4b5ea122013-04-22 10:18:26 +01002149 *length = htons(m);
2150
2151 if (m == 0 || !read_write(confd, packet, m + sizeof(u16), 0))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002152 return packet;
2153 }
2154}
2155
Simon Kelley16972692006-10-16 20:04:18 +01002156static struct frec *allocate_frec(time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002157{
Simon Kelley16972692006-10-16 20:04:18 +01002158 struct frec *f;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002159
Simon Kelley5aabfc72007-08-29 11:24:47 +01002160 if ((f = (struct frec *)whine_malloc(sizeof(struct frec))))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002161 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01002162 f->next = daemon->frec_list;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002163 f->time = now;
Simon Kelley832af0b2007-01-21 20:01:28 +00002164 f->sentto = NULL;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002165 f->rfds = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +00002166 f->flags = 0;
Simon Kelley3a237152013-12-12 12:15:50 +00002167#ifdef HAVE_DNSSEC
Simon Kelley97bc7982014-01-31 10:19:52 +00002168 f->dependent = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002169 f->blocking_query = NULL;
Simon Kelley4619d942014-01-16 19:53:06 +00002170 f->stash = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002171#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +01002172 daemon->frec_list = f;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002173 }
Simon Kelley16972692006-10-16 20:04:18 +01002174
2175 return f;
2176}
2177
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002178/* return a UDP socket bound to a random port, have to cope with straying into
2179 occupied port nos and reserved ones. */
2180static int random_sock(struct server *s)
2181{
2182 int fd;
2183
2184 if ((fd = socket(s->source_addr.sa.sa_family, SOCK_DGRAM, 0)) != -1)
2185 {
2186 if (local_bind(fd, &s->source_addr, s->interface, s->ifindex, 0))
2187 return fd;
2188
2189 if (s->interface[0] == 0)
2190 (void)prettyprint_addr(&s->source_addr, daemon->namebuff);
2191 else
2192 strcpy(daemon->namebuff, s->interface);
2193
2194 my_syslog(LOG_ERR, _("failed to bind server socket to %s: %s"),
2195 daemon->namebuff, strerror(errno));
2196 close(fd);
2197 }
2198
2199 return -1;
2200}
2201
2202/* compare source addresses and interface, serv2 can be null. */
2203static int server_isequal(const struct server *serv1,
2204 const struct server *serv2)
2205{
2206 return (serv2 &&
2207 serv2->ifindex == serv1->ifindex &&
2208 sockaddr_isequal(&serv2->source_addr, &serv1->source_addr) &&
2209 strncmp(serv2->interface, serv1->interface, IF_NAMESIZE) == 0);
2210}
2211
2212/* fdlp points to chain of randomfds already in use by transaction.
2213 If there's already a suitable one, return it, else allocate a
2214 new one and add it to the list.
2215
2216 Not leaking any resources in the face of allocation failures
2217 is rather convoluted here.
2218
2219 Note that rfd->serv may be NULL, when a server goes away.
2220*/
2221int allocate_rfd(struct randfd_list **fdlp, struct server *serv)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002222{
2223 static int finger = 0;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002224 int i, j = 0;
2225 struct randfd_list *rfl;
2226 struct randfd *rfd = NULL;
2227 int fd = 0;
2228
2229 /* If server has a pre-allocated fd, use that. */
2230 if (serv->sfd)
2231 return serv->sfd->fd;
2232
2233 /* existing suitable random port socket linked to this transaction? */
2234 for (rfl = *fdlp; rfl; rfl = rfl->next)
2235 if (server_isequal(serv, rfl->rfd->serv))
2236 return rfl->rfd->fd;
Simon Kelley1a6bca82008-07-11 11:11:42 +01002237
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002238 /* No. need new link. */
2239 if ((rfl = daemon->rfl_spare))
2240 daemon->rfl_spare = rfl->next;
2241 else if (!(rfl = whine_malloc(sizeof(struct randfd_list))))
2242 return -1;
2243
Simon Kelley1a6bca82008-07-11 11:11:42 +01002244 /* limit the number of sockets we have open to avoid starvation of
2245 (eg) TFTP. Once we have a reasonable number, randomness should be OK */
Simon Kelleyea28d0e2021-03-26 22:02:04 +00002246 for (i = 0; i < daemon->numrrand; i++)
Simon Kelley9009d742008-11-14 20:04:27 +00002247 if (daemon->randomsocks[i].refcount == 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002248 {
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002249 if ((fd = random_sock(serv)) != -1)
2250 {
2251 rfd = &daemon->randomsocks[i];
2252 rfd->serv = serv;
2253 rfd->fd = fd;
2254 rfd->refcount = 1;
2255 }
2256 break;
2257 }
2258
2259 /* No free ones or cannot get new socket, grab an existing one */
2260 if (!rfd)
Simon Kelleyea28d0e2021-03-26 22:02:04 +00002261 for (j = 0; j < daemon->numrrand; j++)
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002262 {
Simon Kelleyea28d0e2021-03-26 22:02:04 +00002263 i = (j + finger) % daemon->numrrand;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002264 if (daemon->randomsocks[i].refcount != 0 &&
2265 server_isequal(serv, daemon->randomsocks[i].serv) &&
2266 daemon->randomsocks[i].refcount != 0xfffe)
2267 {
2268 finger = i + 1;
2269 rfd = &daemon->randomsocks[i];
2270 rfd->refcount++;
2271 break;
2272 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01002273 }
2274
Simon Kelleyea28d0e2021-03-26 22:02:04 +00002275 if (j == daemon->numrrand)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002276 {
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002277 struct randfd_list *rfl_poll;
Simon Kelley1a6bca82008-07-11 11:11:42 +01002278
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002279 /* there are no free slots, and non with the same parameters we can piggy-back on.
2280 We're going to have to allocate a new temporary record, distinguished by
2281 refcount == 0xffff. This will exist in the frec randfd list, never be shared,
2282 and be freed when no longer in use. It will also be held on
2283 the daemon->rfl_poll list so the poll system can find it. */
2284
2285 if ((rfl_poll = daemon->rfl_spare))
2286 daemon->rfl_spare = rfl_poll->next;
2287 else
2288 rfl_poll = whine_malloc(sizeof(struct randfd_list));
2289
2290 if (!rfl_poll ||
2291 !(rfd = whine_malloc(sizeof(struct randfd))) ||
2292 (fd = random_sock(serv)) == -1)
2293 {
2294
2295 /* Don't leak anything we may already have */
2296 rfl->next = daemon->rfl_spare;
2297 daemon->rfl_spare = rfl;
2298
2299 if (rfl_poll)
2300 {
2301 rfl_poll->next = daemon->rfl_spare;
2302 daemon->rfl_spare = rfl_poll;
2303 }
2304
2305 if (rfd)
2306 free(rfd);
2307
2308 return -1; /* doom */
2309 }
2310
2311 /* Note rfd->serv not set here, since it's not reused */
2312 rfd->fd = fd;
2313 rfd->refcount = 0xffff; /* marker for temp record */
2314
2315 rfl_poll->rfd = rfd;
2316 rfl_poll->next = daemon->rfl_poll;
2317 daemon->rfl_poll = rfl_poll;
2318 }
2319
2320 rfl->rfd = rfd;
2321 rfl->next = *fdlp;
2322 *fdlp = rfl;
2323
2324 return rfl->rfd->fd;
Simon Kelley1a6bca82008-07-11 11:11:42 +01002325}
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002326
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002327void free_rfds(struct randfd_list **fdlp)
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002328{
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002329 struct randfd_list *tmp, *rfl, *poll, *next, **up;
2330
2331 for (rfl = *fdlp; rfl; rfl = tmp)
2332 {
2333 if (rfl->rfd->refcount == 0xffff || --(rfl->rfd->refcount) == 0)
2334 close(rfl->rfd->fd);
2335
2336 /* temporary overflow record */
2337 if (rfl->rfd->refcount == 0xffff)
2338 {
2339 free(rfl->rfd);
2340
2341 /* go through the link of all these by steam to delete.
2342 This list is expected to be almost always empty. */
2343 for (poll = daemon->rfl_poll, up = &daemon->rfl_poll; poll; poll = next)
2344 {
2345 next = poll->next;
2346
2347 if (poll->rfd == rfl->rfd)
2348 {
2349 *up = poll->next;
2350 poll->next = daemon->rfl_spare;
2351 daemon->rfl_spare = poll;
2352 }
2353 else
2354 up = &poll->next;
2355 }
2356 }
2357
2358 tmp = rfl->next;
2359 rfl->next = daemon->rfl_spare;
2360 daemon->rfl_spare = rfl;
2361 }
2362
2363 *fdlp = NULL;
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002364}
2365
Simon Kelley1a6bca82008-07-11 11:11:42 +01002366static void free_frec(struct frec *f)
2367{
Simon Kelley6a6e06f2020-12-04 18:35:11 +00002368 struct frec_src *last;
Simon Kelley15b60dd2020-11-18 18:34:55 +00002369
Simon Kelley6a6e06f2020-12-04 18:35:11 +00002370 /* add back to freelist if not the record builtin to every frec. */
2371 for (last = f->frec_src.next; last && last->next; last = last->next) ;
2372 if (last)
2373 {
2374 last->next = daemon->free_frec_src;
2375 daemon->free_frec_src = f->frec_src.next;
2376 }
2377
Simon Kelley15b60dd2020-11-18 18:34:55 +00002378 f->frec_src.next = NULL;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002379 free_rfds(&f->rfds);
Simon Kelley1a6bca82008-07-11 11:11:42 +01002380 f->sentto = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +00002381 f->flags = 0;
Simon Kelley3a237152013-12-12 12:15:50 +00002382
2383#ifdef HAVE_DNSSEC
2384 if (f->stash)
Simon Kelley0fc2f312014-01-08 10:26:58 +00002385 {
2386 blockdata_free(f->stash);
2387 f->stash = NULL;
2388 }
Simon Kelley3a237152013-12-12 12:15:50 +00002389
2390 /* Anything we're waiting on is pointless now, too */
2391 if (f->blocking_query)
2392 free_frec(f->blocking_query);
2393 f->blocking_query = NULL;
Simon Kelley39048ad2014-01-21 17:33:58 +00002394 f->dependent = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002395#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +01002396}
2397
Simon Kelley09f3b2c2017-05-09 01:34:02 +01002398
2399
Simon Kelley16972692006-10-16 20:04:18 +01002400/* if wait==NULL return a free or older than TIMEOUT record.
2401 else return *wait zero if one available, or *wait is delay to
Simon Kelley1a6bca82008-07-11 11:11:42 +01002402 when the oldest in-use record will expire. Impose an absolute
Simon Kelley3a237152013-12-12 12:15:50 +00002403 limit of 4*TIMEOUT before we wipe things (for random sockets).
Simon Kelley8caf3d72020-04-04 17:00:32 +01002404 If force is non-NULL, always return a result, even if we have
2405 to allocate above the limit, and never free the record pointed
2406 to by the force argument. */
2407struct frec *get_new_frec(time_t now, int *wait, struct frec *force)
Simon Kelley16972692006-10-16 20:04:18 +01002408{
Simon Kelley1a6bca82008-07-11 11:11:42 +01002409 struct frec *f, *oldest, *target;
Simon Kelley16972692006-10-16 20:04:18 +01002410 int count;
2411
2412 if (wait)
2413 *wait = 0;
2414
Simon Kelley1a6bca82008-07-11 11:11:42 +01002415 for (f = daemon->frec_list, oldest = NULL, target = NULL, count = 0; f; f = f->next, count++)
Simon Kelley832af0b2007-01-21 20:01:28 +00002416 if (!f->sentto)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002417 target = f;
2418 else
Simon Kelley16972692006-10-16 20:04:18 +01002419 {
Simon Kelley9a31b682015-12-15 10:20:39 +00002420#ifdef HAVE_DNSSEC
2421 /* Don't free DNSSEC sub-queries here, as we may end up with
2422 dangling references to them. They'll go when their "real" query
2423 is freed. */
Simon Kelley8caf3d72020-04-04 17:00:32 +01002424 if (!f->dependent && f != force)
Simon Kelley9a31b682015-12-15 10:20:39 +00002425#endif
2426 {
2427 if (difftime(now, f->time) >= 4*TIMEOUT)
2428 {
2429 free_frec(f);
2430 target = f;
2431 }
2432
2433
2434 if (!oldest || difftime(f->time, oldest->time) <= 0)
2435 oldest = f;
2436 }
Simon Kelley16972692006-10-16 20:04:18 +01002437 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01002438
2439 if (target)
2440 {
2441 target->time = now;
2442 return target;
2443 }
Simon Kelley16972692006-10-16 20:04:18 +01002444
2445 /* can't find empty one, use oldest if there is one
2446 and it's older than timeout */
Simon Kelley09f3b2c2017-05-09 01:34:02 +01002447 if (!force && oldest && ((int)difftime(now, oldest->time)) >= TIMEOUT)
Simon Kelley16972692006-10-16 20:04:18 +01002448 {
2449 /* keep stuff for twice timeout if we can by allocating a new
2450 record instead */
2451 if (difftime(now, oldest->time) < 2*TIMEOUT &&
2452 count <= daemon->ftabsize &&
2453 (f = allocate_frec(now)))
2454 return f;
2455
2456 if (!wait)
2457 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01002458 free_frec(oldest);
Simon Kelley16972692006-10-16 20:04:18 +01002459 oldest->time = now;
2460 }
2461 return oldest;
2462 }
2463
2464 /* none available, calculate time 'till oldest record expires */
Simon Kelley3a237152013-12-12 12:15:50 +00002465 if (!force && count > daemon->ftabsize)
Simon Kelley16972692006-10-16 20:04:18 +01002466 {
2467 if (oldest && wait)
2468 *wait = oldest->time + (time_t)TIMEOUT - now;
Marcelo Salhab Brogliato0da5e892013-05-31 11:49:06 +01002469
Simon Kelleyf61afcf2021-04-07 20:54:36 +01002470 query_full(now);
2471
Simon Kelley16972692006-10-16 20:04:18 +01002472 return NULL;
2473 }
2474
2475 if (!(f = allocate_frec(now)) && wait)
2476 /* wait one second on malloc failure */
2477 *wait = 1;
2478
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002479 return f; /* OK if malloc fails and this is NULL */
2480}
Simon Kelley09f3b2c2017-05-09 01:34:02 +01002481
Simon Kelleyf61afcf2021-04-07 20:54:36 +01002482static void query_full(time_t now)
2483{
2484 static time_t last_log = 0;
2485
2486 if ((int)difftime(now, last_log) > 5)
2487 {
2488 last_log = now;
2489 my_syslog(LOG_WARNING, _("Maximum number of concurrent DNS queries reached (max: %d)"), daemon->ftabsize);
2490 }
2491}
2492
2493
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002494static struct frec *lookup_frec(unsigned short id, int fd, void *hash)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002495{
2496 struct frec *f;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002497 struct server *s;
2498 int type;
2499 struct randfd_list *fdl;
2500
Simon Kelley1a6bca82008-07-11 11:11:42 +01002501 for(f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00002502 if (f->sentto && f->new_id == id &&
Simon Kelley2d765862020-11-12 22:06:07 +00002503 (memcmp(hash, f->hash, HASH_SIZE) == 0))
Simon Kelley257ac0c2020-11-12 18:49:23 +00002504 {
2505 /* sent from random port */
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002506 for (fdl = f->rfds; fdl; fdl = fdl->next)
2507 if (fdl->rfd->fd == fd)
Simon Kelley257ac0c2020-11-12 18:49:23 +00002508 return f;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002509
2510 /* Sent to upstream from socket associated with a server.
2511 Note we have to iterate over all the possible servers, since they may
2512 have different bound sockets. */
2513 type = f->sentto->flags & SERV_TYPE;
2514 s = f->sentto;
2515 do {
Petr Menšík8f9bd612021-03-27 23:16:09 +00002516 if (server_test_type(s, f->sentto->domain, type, 0) &&
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002517 s->sfd && s->sfd->fd == fd)
2518 return f;
2519
2520 s = s->next ? s->next : daemon->servers;
2521 } while (s != f->sentto);
Simon Kelley257ac0c2020-11-12 18:49:23 +00002522 }
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002523
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002524 return NULL;
2525}
2526
Simon Kelley15b60dd2020-11-18 18:34:55 +00002527static struct frec *lookup_frec_by_query(void *hash, unsigned int flags)
2528{
2529 struct frec *f;
2530
2531 /* FREC_DNSKEY and FREC_DS_QUERY are never set in flags, so the test below
Simon Kelley25e63f12020-11-25 21:17:52 +00002532 ensures that no frec created for internal DNSSEC query can be returned here.
2533
2534 Similarly FREC_NO_CACHE is never set in flags, so a query which is
2535 contigent on a particular source address EDNS0 option will never be matched. */
Simon Kelley15b60dd2020-11-18 18:34:55 +00002536
2537#define FLAGMASK (FREC_CHECKING_DISABLED | FREC_AD_QUESTION | FREC_DO_QUESTION \
Simon Kelley25e63f12020-11-25 21:17:52 +00002538 | FREC_HAS_PHEADER | FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_NO_CACHE)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002539
Simon Kelley1a6bca82008-07-11 11:11:42 +01002540 for(f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00002541 if (f->sentto &&
Simon Kelley15b60dd2020-11-18 18:34:55 +00002542 (f->flags & FLAGMASK) == flags &&
2543 memcmp(hash, f->hash, HASH_SIZE) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002544 return f;
Simon Kelley15b60dd2020-11-18 18:34:55 +00002545
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002546 return NULL;
2547}
Simon Kelley15b60dd2020-11-18 18:34:55 +00002548
Simon Kelley47a95162014-07-08 22:22:02 +01002549/* Send query packet again, if we can. */
2550void resend_query()
2551{
2552 if (daemon->srv_save)
Petr Menšík51f7bc92021-03-18 01:05:43 +01002553 server_send(daemon->srv_save, daemon->fd_save,
2554 daemon->packet, daemon->packet_len, 0);
Simon Kelley47a95162014-07-08 22:22:02 +01002555}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002556
Simon Kelley849a8352006-06-09 21:02:31 +01002557/* A server record is going away, remove references to it */
Simon Kelley5aabfc72007-08-29 11:24:47 +01002558void server_gone(struct server *server)
Simon Kelley849a8352006-06-09 21:02:31 +01002559{
2560 struct frec *f;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002561 int i;
Simon Kelley849a8352006-06-09 21:02:31 +01002562
Simon Kelley1a6bca82008-07-11 11:11:42 +01002563 for (f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00002564 if (f->sentto && f->sentto == server)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002565 free_frec(f);
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002566
2567 /* If any random socket refers to this server, NULL the reference.
2568 No more references to the socket will be created in the future. */
Simon Kelleyea28d0e2021-03-26 22:02:04 +00002569 for (i = 0; i < daemon->numrrand; i++)
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002570 if (daemon->randomsocks[i].refcount != 0 && daemon->randomsocks[i].serv == server)
2571 daemon->randomsocks[i].serv = NULL;
Simon Kelley849a8352006-06-09 21:02:31 +01002572
2573 if (daemon->last_server == server)
2574 daemon->last_server = NULL;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002575
Simon Kelley849a8352006-06-09 21:02:31 +01002576 if (daemon->srv_save == server)
2577 daemon->srv_save = NULL;
2578}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002579
Simon Kelley316e2732010-01-22 20:16:09 +00002580/* return unique random ids. */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002581static unsigned short get_id(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002582{
2583 unsigned short ret = 0;
Simon Kelley257ac0c2020-11-12 18:49:23 +00002584 struct frec *f;
Simon Kelley832af0b2007-01-21 20:01:28 +00002585
Simon Kelley257ac0c2020-11-12 18:49:23 +00002586 while (1)
2587 {
2588 ret = rand16();
2589
2590 /* ensure id is unique. */
2591 for (f = daemon->frec_list; f; f = f->next)
2592 if (f->sentto && f->new_id == ret)
2593 break;
2594
2595 if (!f)
2596 return ret;
2597 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002598}
2599
2600
2601
2602
2603