blob: 40c97233a38018dc22d33f0e2e5e94934bc9d784 [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
Simon Kelley25e63f12020-11-25 21:17:52 +0000522 plen = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->frec_src.source, now, &subnet, &cacheable);
Simon Kelley33702ab2015-12-28 23:17:15 +0000523
Simon Kelley6fd5d792017-10-13 22:26:40 +0100524 if (subnet)
525 forward->flags |= FREC_HAS_SUBNET;
Simon Kelley25e63f12020-11-25 21:17:52 +0000526
527 if (!cacheable)
528 forward->flags |= FREC_NO_CACHE;
529
Simon Kelley3a237152013-12-12 12:15:50 +0000530#ifdef HAVE_DNSSEC
Simon Kelley367341f2016-01-12 15:58:23 +0000531 if (option_bool(OPT_DNSSEC_VALID) && do_dnssec)
Simon Kelley0fc2f312014-01-08 10:26:58 +0000532 {
Simon Kelley6fd5d792017-10-13 22:26:40 +0100533 plen = add_do_bit(header, plen, ((unsigned char *) header) + PACKETSZ);
534
Simon Kelley5b3bf922014-01-25 17:03:07 +0000535 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
536 this allows it to select auth servers when one is returning bad data. */
537 if (option_bool(OPT_DNSSEC_DEBUG))
538 header->hb4 |= HB4_CD;
Simon Kelley613ad152014-02-25 23:02:28 +0000539
Simon Kelley0fc2f312014-01-08 10:26:58 +0000540 }
Simon Kelley3a237152013-12-12 12:15:50 +0000541#endif
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000542
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000543 if (find_pseudoheader(header, plen, &edns0_len, &pheader, NULL, NULL))
Simon Kelley6fd5d792017-10-13 22:26:40 +0100544 {
545 /* If there wasn't a PH before, and there is now, we added it. */
546 if (!oph)
547 forward->flags |= FREC_ADDED_PHEADER;
548
549 /* If we're sending an EDNS0 with any options, we can't recreate the query from a reply. */
550 if (edns0_len > 11)
551 forward->flags |= FREC_HAS_EXTRADATA;
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000552
553 /* Reduce udp size on retransmits. */
554 if (forward->flags & FREC_TEST_PKTSZ)
555 PUTSHORT(SAFE_PKTSZ, pheader);
Simon Kelley6fd5d792017-10-13 22:26:40 +0100556 }
Simon Kelleya77cec82015-05-08 16:25:38 +0100557
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000558 while (1)
559 {
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000560 int fd;
561
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000562 /* only send to servers dealing with our domain.
563 domain may be NULL, in which case server->domain
564 must be NULL also. */
565
Petr Menšíke10a9232021-03-15 11:20:49 +0100566 if (server_test_type(start, domain, type, 0) &&
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000567 ((fd = allocate_rfd(&forward->rfds, start)) != -1))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000568 {
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000569
Simon Kelley7de060b2011-08-26 17:24:52 +0100570#ifdef HAVE_CONNTRACK
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000571 /* Copy connection mark of incoming query to outgoing connection. */
572 if (option_bool(OPT_CONNTRACK))
Petr Menšík6c0bf792021-03-18 00:07:45 +0100573 set_outgoing_mark(forward, fd);
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000574#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +0100575
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000576#ifdef HAVE_DNSSEC
Simon Kelley5bb88f02015-12-21 16:23:47 +0000577 if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER))
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000578 {
579 /* Difficult one here. If our client didn't send EDNS0, we will have set the UDP
580 packet size to 512. But that won't provide space for the RRSIGS in many cases.
581 The RRSIGS will be stripped out before the answer goes back, so the packet should
582 shrink again. So, if we added a do-bit, bump the udp packet size to the value
Simon Kelley5aa5f0f2015-12-21 17:20:35 +0000583 known to be OK for this server. We check returned size after stripping and set
584 the truncated bit if it's still too big. */
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000585 unsigned char *pheader;
586 int is_sign;
Simon Kelley5bb88f02015-12-21 16:23:47 +0000587 if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000588 PUTSHORT(start->edns_pktsz, pheader);
589 }
590#endif
591
Simon Kelleyff841eb2015-03-11 21:36:30 +0000592 if (retry_send(sendto(fd, (char *)header, plen, 0,
593 &start->addr.sa,
594 sa_len(&start->addr))))
595 continue;
596
597 if (errno == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000598 {
Simon Kelley6b173352018-05-08 18:32:14 +0100599#ifdef HAVE_DUMPFILE
600 dump_packet(DUMP_UP_QUERY, (void *)header, plen, NULL, &start->addr);
601#endif
602
Simon Kelleycdeda282006-03-16 20:16:06 +0000603 /* Keep info in case we want to re-send this packet */
604 daemon->srv_save = start;
605 daemon->packet_len = plen;
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000606 daemon->fd_save = fd;
Simon Kelleycdeda282006-03-16 20:16:06 +0000607
Simon Kelleyde379512004-06-22 20:23:33 +0100608 if (!gotname)
Simon Kelley3be34542004-09-11 19:12:13 +0100609 strcpy(daemon->namebuff, "query");
Petr Menšík6c0bf792021-03-18 00:07:45 +0100610 log_query_mysockaddr(F_SERVER | F_FORWARD, daemon->namebuff,
611 &start->addr, NULL);
Simon Kelley824af852008-02-12 20:43:05 +0000612 start->queries++;
Simon Kelleyde379512004-06-22 20:23:33 +0100613 forwarded = 1;
614 forward->sentto = start;
Simon Kelley0a852542005-03-23 20:28:59 +0000615 if (!forward->forwardall)
Simon Kelleyde379512004-06-22 20:23:33 +0100616 break;
Simon Kelley0a852542005-03-23 20:28:59 +0000617 forward->forwardall++;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000618 }
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000619 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000620
Simon Kelleyde379512004-06-22 20:23:33 +0100621 if (!(start = start->next))
Simon Kelley3be34542004-09-11 19:12:13 +0100622 start = daemon->servers;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000623
Simon Kelleyde379512004-06-22 20:23:33 +0100624 if (start == firstsentto)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000625 break;
626 }
627
Simon Kelleyde379512004-06-22 20:23:33 +0100628 if (forwarded)
Simon Kelley824af852008-02-12 20:43:05 +0000629 return 1;
Simon Kelleyde379512004-06-22 20:23:33 +0100630
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000631 /* could not send on, prepare to return */
Simon Kelley15b60dd2020-11-18 18:34:55 +0000632 header->id = htons(forward->frec_src.orig_id);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100633 free_frec(forward); /* cancel */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000634 }
635
636 /* could not send on, return empty answer or address if known for whole domain */
Simon Kelley961daf82021-04-06 23:52:09 +0100637 frec_err:
Simon Kelleyb8187c82005-11-26 21:46:27 +0000638 if (udpfd != -1)
639 {
Simon Kelleycdeda282006-03-16 20:16:06 +0000640 plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl);
Simon Kelley1682d152018-08-03 20:38:18 +0100641 if (oph)
642 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 +0100643 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 +0000644 }
645
Simon Kelley824af852008-02-12 20:43:05 +0000646 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000647}
648
Simon Kelleyed4c0762013-10-08 20:46:34 +0100649static 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 +0100650 int no_cache, int cache_secure, int bogusanswer, int ad_reqd, int do_bit, int added_pheader,
651 int check_subnet, union mysockaddr *query_source)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100652{
Simon Kelley36717ee2004-09-20 19:20:58 +0100653 unsigned char *pheader, *sizep;
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000654 char **sets = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +0000655 int munged = 0, is_sign;
Simon Kelley07ed5852018-05-04 21:52:22 +0100656 unsigned int rcode = RCODE(header);
Simon Kelleycdeda282006-03-16 20:16:06 +0000657 size_t plen;
Simon Kelleya6004d72017-10-25 17:48:19 +0100658
Simon Kelley83349b82014-02-10 21:02:01 +0000659 (void)ad_reqd;
Simon Kelley982faf42015-04-03 21:42:30 +0100660 (void)do_bit;
661 (void)bogusanswer;
Simon Kelley83349b82014-02-10 21:02:01 +0000662
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000663#ifdef HAVE_IPSET
Simon Kelley82a14af2014-04-13 20:48:57 +0100664 if (daemon->ipsets && extract_request(header, n, daemon->namebuff, NULL))
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000665 {
Simon Kelley82a14af2014-04-13 20:48:57 +0100666 /* Similar algorithm to search_servers. */
667 struct ipsets *ipset_pos;
668 unsigned int namelen = strlen(daemon->namebuff);
669 unsigned int matchlen = 0;
670 for (ipset_pos = daemon->ipsets; ipset_pos; ipset_pos = ipset_pos->next)
Simon Kelley6c0cb852014-01-17 14:40:46 +0000671 {
Simon Kelley82a14af2014-04-13 20:48:57 +0100672 unsigned int domainlen = strlen(ipset_pos->domain);
673 char *matchstart = daemon->namebuff + namelen - domainlen;
674 if (namelen >= domainlen && hostname_isequal(matchstart, ipset_pos->domain) &&
675 (domainlen == 0 || namelen == domainlen || *(matchstart - 1) == '.' ) &&
676 domainlen >= matchlen)
677 {
678 matchlen = domainlen;
679 sets = ipset_pos->sets;
680 }
Simon Kelley6c0cb852014-01-17 14:40:46 +0000681 }
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000682 }
683#endif
Simon Kelley25e63f12020-11-25 21:17:52 +0000684
Simon Kelley5bb88f02015-12-21 16:23:47 +0000685 if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign, NULL)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100686 {
Simon Kelley07ed5852018-05-04 21:52:22 +0100687 /* Get extended RCODE. */
688 rcode |= sizep[2] << 4;
689
Simon Kelleyed4c0762013-10-08 20:46:34 +0100690 if (check_subnet && !check_source(header, plen, pheader, query_source))
691 {
692 my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch"));
693 return 0;
694 }
Simon Kelley613ad152014-02-25 23:02:28 +0000695
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000696 if (!is_sign)
Simon Kelley613ad152014-02-25 23:02:28 +0000697 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000698 if (added_pheader)
699 {
700 /* client didn't send EDNS0, we added one, strip it off before returning answer. */
701 n = rrfilter(header, n, 0);
702 pheader = NULL;
703 }
704 else
705 {
Simon Kelley33702ab2015-12-28 23:17:15 +0000706 unsigned short udpsz;
707
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000708 /* If upstream is advertising a larger UDP packet size
709 than we allow, trim it so that we don't get overlarge
710 requests for the client. We can't do this for signed packets. */
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000711 GETSHORT(udpsz, sizep);
712 if (udpsz > daemon->edns_pktsz)
Simon Kelley33702ab2015-12-28 23:17:15 +0000713 {
714 sizep -= 2;
715 PUTSHORT(daemon->edns_pktsz, sizep);
716 }
717
718#ifdef HAVE_DNSSEC
719 /* If the client didn't set the do bit, but we did, reset it. */
720 if (option_bool(OPT_DNSSEC_VALID) && !do_bit)
721 {
722 unsigned short flags;
723 sizep += 2; /* skip RCODE */
724 GETSHORT(flags, sizep);
725 flags &= ~0x8000;
726 sizep -= 2;
727 PUTSHORT(flags, sizep);
728 }
729#endif
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000730 }
Simon Kelley613ad152014-02-25 23:02:28 +0000731 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100732 }
Simon Kelley83349b82014-02-10 21:02:01 +0000733
Simon Kelley28866e92011-02-14 20:19:14 +0000734 /* RFC 4035 sect 4.6 para 3 */
Giovanni Bajo237724c2012-04-05 02:46:52 +0200735 if (!is_sign && !option_bool(OPT_DNSSEC_PROXY))
Simon Kelley795501b2014-01-08 18:11:55 +0000736 header->hb4 &= ~HB4_AD;
Simon Kelley3a237152013-12-12 12:15:50 +0000737
Simon Kelley07ed5852018-05-04 21:52:22 +0100738 if (OPCODE(header) != QUERY)
Simon Kelley8938ae02014-05-01 17:46:25 +0100739 return resize_packet(header, n, pheader, plen);
Simon Kelley07ed5852018-05-04 21:52:22 +0100740
741 if (rcode != NOERROR && rcode != NXDOMAIN)
742 {
Simon Kelleycc921df2019-01-02 22:48:59 +0000743 union all_addr a;
744 a.log.rcode = rcode;
Simon Kelley07ed5852018-05-04 21:52:22 +0100745 log_query(F_UPSTREAM | F_RCODE, "error", &a, NULL);
746
747 return resize_packet(header, n, pheader, plen);
748 }
Simon Kelley36717ee2004-09-20 19:20:58 +0100749
Simon Kelley0a852542005-03-23 20:28:59 +0000750 /* Complain loudly if the upstream server is non-recursive. */
Simon Kelley07ed5852018-05-04 21:52:22 +0100751 if (!(header->hb4 & HB4_RA) && rcode == NOERROR &&
Simon Kelley0a852542005-03-23 20:28:59 +0000752 server && !(server->flags & SERV_WARNED_RECURSIVE))
753 {
Petr Mensik51cdd1a2019-07-04 20:28:08 +0200754 (void)prettyprint_addr(&server->addr, daemon->namebuff);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100755 my_syslog(LOG_WARNING, _("nameserver %s refused to do a recursive query"), daemon->namebuff);
Simon Kelley28866e92011-02-14 20:19:14 +0000756 if (!option_bool(OPT_LOG))
Simon Kelley0a852542005-03-23 20:28:59 +0000757 server->flags |= SERV_WARNED_RECURSIVE;
758 }
Giovanni Bajoe292e932012-04-22 14:32:02 +0200759
Simon Kelley07ed5852018-05-04 21:52:22 +0100760 if (daemon->bogus_addr && rcode != NXDOMAIN &&
Simon Kelley9eaa91b2021-03-17 20:31:06 +0000761 check_for_bogus_wildcard(header, n, daemon->namebuff, now))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100762 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100763 munged = 1;
Simon Kelley572b41e2011-02-18 18:11:18 +0000764 SET_RCODE(header, NXDOMAIN);
765 header->hb3 &= ~HB3_AA;
Simon Kelley6938f342014-01-26 22:47:39 +0000766 cache_secure = 0;
Simon Kelley36717ee2004-09-20 19:20:58 +0100767 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100768 else
Simon Kelley36717ee2004-09-20 19:20:58 +0100769 {
Simon Kelley6938f342014-01-26 22:47:39 +0000770 int doctored = 0;
771
Simon Kelley07ed5852018-05-04 21:52:22 +0100772 if (rcode == NXDOMAIN &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100773 extract_request(header, n, daemon->namebuff, NULL) &&
Simon Kelley5aabfc72007-08-29 11:24:47 +0100774 check_for_local_domain(daemon->namebuff, now))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100775 {
Simon Kelley36717ee2004-09-20 19:20:58 +0100776 /* if we forwarded a query for a locally known name (because it was for
777 an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
778 since we know that the domain exists, even if upstream doesn't */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100779 munged = 1;
Simon Kelley572b41e2011-02-18 18:11:18 +0000780 header->hb3 |= HB3_AA;
781 SET_RCODE(header, NOERROR);
Simon Kelley6938f342014-01-26 22:47:39 +0000782 cache_secure = 0;
Simon Kelley36717ee2004-09-20 19:20:58 +0100783 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000784
Simon Kelley373e9172017-12-01 22:40:56 +0000785 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 +0000786 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100787 my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
Simon Kelley824af852008-02-12 20:43:05 +0000788 munged = 1;
Simon Kelley6938f342014-01-26 22:47:39 +0000789 cache_secure = 0;
Simon Kelley824af852008-02-12 20:43:05 +0000790 }
Simon Kelley6938f342014-01-26 22:47:39 +0000791
792 if (doctored)
793 cache_secure = 0;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100794 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100795
Simon Kelleya25720a2014-01-14 23:13:55 +0000796#ifdef HAVE_DNSSEC
Simon Kelley33702ab2015-12-28 23:17:15 +0000797 if (bogusanswer && !(header->hb4 & HB4_CD) && !option_bool(OPT_DNSSEC_DEBUG))
Simon Kelleya25720a2014-01-14 23:13:55 +0000798 {
Simon Kelley33702ab2015-12-28 23:17:15 +0000799 /* Bogus reply, turn into SERVFAIL */
800 SET_RCODE(header, SERVFAIL);
801 munged = 1;
Simon Kelleya25720a2014-01-14 23:13:55 +0000802 }
Simon Kelley6938f342014-01-26 22:47:39 +0000803
804 if (option_bool(OPT_DNSSEC_VALID))
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000805 {
806 header->hb4 &= ~HB4_AD;
807
808 if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure)
809 header->hb4 |= HB4_AD;
810
811 /* If the requestor didn't set the DO bit, don't return DNSSEC info. */
812 if (!do_bit)
813 n = rrfilter(header, n, 1);
814 }
Simon Kelleya25720a2014-01-14 23:13:55 +0000815#endif
816
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100817 /* do this after extract_addresses. Ensure NODATA reply and remove
818 nameserver info. */
819
820 if (munged)
821 {
822 header->ancount = htons(0);
823 header->nscount = htons(0);
824 header->arcount = htons(0);
Simon Kelley150162b2015-03-27 09:58:26 +0000825 header->hb3 &= ~HB3_TC;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100826 }
827
Simon Kelley36717ee2004-09-20 19:20:58 +0100828 /* the bogus-nxdomain stuff, doctor and NXDOMAIN->NODATA munging can all elide
829 sections of the packet. Find the new length here and put back pseudoheader
830 if it was removed. */
831 return resize_packet(header, n, pheader, plen);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100832}
833
Simon Kelley3be34542004-09-11 19:12:13 +0100834/* sets new last_server */
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000835void reply_query(int fd, time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000836{
837 /* packet from peer server, extract data for cache, and send to
838 original requester */
Simon Kelley572b41e2011-02-18 18:11:18 +0000839 struct dns_header *header;
Simon Kelleyde379512004-06-22 20:23:33 +0100840 union mysockaddr serveraddr;
Simon Kelley832af0b2007-01-21 20:01:28 +0000841 struct frec *forward;
Simon Kelleyde379512004-06-22 20:23:33 +0100842 socklen_t addrlen = sizeof(serveraddr);
Simon Kelley60b68062014-01-08 12:10:28 +0000843 ssize_t n = recvfrom(fd, daemon->packet, daemon->packet_buff_sz, 0, &serveraddr.sa, &addrlen);
Simon Kelleycdeda282006-03-16 20:16:06 +0000844 size_t nn;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100845 struct server *server;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000846 void *hash;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000847
Simon Kelleycdeda282006-03-16 20:16:06 +0000848 /* packet buffer overwritten */
849 daemon->srv_save = NULL;
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000850
Simon Kelleyde379512004-06-22 20:23:33 +0100851 /* Determine the address of the server replying so that we can mark that as good */
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000852 if (serveraddr.sa.sa_family == AF_INET6)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100853 serveraddr.in6.sin6_flowinfo = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000854
Simon Kelley490f9072014-03-24 22:04:42 +0000855 header = (struct dns_header *)daemon->packet;
Simon Kelley6b173352018-05-08 18:32:14 +0100856
Simon Kelley490f9072014-03-24 22:04:42 +0000857 if (n < (int)sizeof(struct dns_header) || !(header->hb3 & HB3_QR))
858 return;
859
Simon Kelley1a6bca82008-07-11 11:11:42 +0100860 /* spoof check: answer must come from known server, */
861 for (server = daemon->servers; server; server = server->next)
862 if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) &&
863 sockaddr_isequal(&server->addr, &serveraddr))
864 break;
Simon Kelley490f9072014-03-24 22:04:42 +0000865
866 if (!server)
867 return;
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000868
869 /* If sufficient time has elapsed, try and expand UDP buffer size again. */
870 if (difftime(now, server->pktsz_reduced) > UDP_TEST_TIME)
871 server->edns_pktsz = daemon->edns_pktsz;
872
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000873 hash = hash_questions(header, n, daemon->namebuff);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100874
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000875 if (!(forward = lookup_frec(ntohs(header->id), fd, hash)))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100876 return;
Simon Kelley490f9072014-03-24 22:04:42 +0000877
Simon Kelley6b173352018-05-08 18:32:14 +0100878#ifdef HAVE_DUMPFILE
879 dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_REPLY : DUMP_UP_REPLY,
880 (void *)header, n, &serveraddr, NULL);
881#endif
Simon Kelleya0088e82018-05-10 21:43:14 +0100882
Simon Kelley25cf5e32015-01-09 15:53:03 +0000883 /* log_query gets called indirectly all over the place, so
884 pass these in global variables - sorry. */
Simon Kelley15b60dd2020-11-18 18:34:55 +0000885 daemon->log_display_id = forward->frec_src.log_id;
886 daemon->log_source_addr = &forward->frec_src.source;
Simon Kelley25cf5e32015-01-09 15:53:03 +0000887
Glen Huang32fc6db2014-12-27 15:28:12 +0000888 if (daemon->ignore_addr && RCODE(header) == NOERROR &&
Simon Kelley9eaa91b2021-03-17 20:31:06 +0000889 check_for_ignored_address(header, n))
Glen Huang32fc6db2014-12-27 15:28:12 +0000890 return;
891
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000892 /* Note: if we send extra options in the EDNS0 header, we can't recreate
893 the query from the reply. */
Simon Kelley34e26e12018-05-10 20:54:57 +0100894 if ((RCODE(header) == REFUSED || RCODE(header) == SERVFAIL) &&
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000895 forward->forwardall == 0 &&
896 !(forward->flags & FREC_HAS_EXTRADATA))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100897 /* for broken servers, attempt to send to another one. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000898 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100899 unsigned char *pheader;
900 size_t plen;
901 int is_sign;
Simon Kelleyef3d1372017-12-05 22:37:29 +0000902
Simon Kelley1f60a182018-05-11 16:44:16 +0100903#ifdef HAVE_DNSSEC
Simon Kelleya0088e82018-05-10 21:43:14 +0100904 if (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY))
905 {
Simon Kelley1f60a182018-05-11 16:44:16 +0100906 struct server *start;
907
Simon Kelleya0088e82018-05-10 21:43:14 +0100908 blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
909 plen = forward->stash_len;
910
911 forward->forwardall = 2; /* only retry once */
Simon Kelley1f60a182018-05-11 16:44:16 +0100912 start = forward->sentto;
913
914 /* for non-domain specific servers, see if we can find another to try. */
915 if ((forward->sentto->flags & SERV_TYPE) == 0)
916 while (1)
917 {
918 if (!(start = start->next))
919 start = daemon->servers;
920 if (start == forward->sentto)
921 break;
922
923 if ((start->flags & SERV_TYPE) == 0 &&
924 (start->flags & SERV_DO_DNSSEC))
925 break;
926 }
927
928
Petr Menšík51f7bc92021-03-18 01:05:43 +0100929 if ((fd = allocate_rfd(&forward->rfds, start)) != -1)
930 server_send_log(start, fd, header, plen,
931 DUMP_SEC_QUERY,
932 F_NOEXTRA | F_DNSSEC, "retry", "dnssec");
Simon Kelleya0088e82018-05-10 21:43:14 +0100933 return;
934 }
Simon Kelley1f60a182018-05-11 16:44:16 +0100935#endif
936
Simon Kelleyef3d1372017-12-05 22:37:29 +0000937 /* In strict order mode, there must be a server later in the chain
938 left to send to, otherwise without the forwardall mechanism,
939 code further on will cycle around the list forwever if they
940 all return REFUSED. Note that server is always non-NULL before
941 this executes. */
942 if (option_bool(OPT_ORDER))
943 for (server = forward->sentto->next; server; server = server->next)
944 if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR | SERV_LOOP)))
945 break;
946
Simon Kelley1a6bca82008-07-11 11:11:42 +0100947 /* recreate query from reply */
Simon Kelley5bb88f02015-12-21 16:23:47 +0000948 pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign, NULL);
Simon Kelleyef3d1372017-12-05 22:37:29 +0000949 if (!is_sign && server)
Simon Kelley832af0b2007-01-21 20:01:28 +0000950 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100951 header->ancount = htons(0);
952 header->nscount = htons(0);
953 header->arcount = htons(0);
954 if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
955 {
swiggerbd7bfa22015-06-01 20:54:59 +0100956 header->hb3 &= ~(HB3_QR | HB3_AA | HB3_TC);
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000957 header->hb4 &= ~(HB4_RA | HB4_RCODE | HB4_CD | HB4_AD);
Simon Kelley1801a292016-01-17 21:53:57 +0000958 if (forward->flags & FREC_CHECKING_DISABLED)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000959 header->hb4 |= HB4_CD;
Simon Kelley1801a292016-01-17 21:53:57 +0000960 if (forward->flags & FREC_AD_QUESTION)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000961 header->hb4 |= HB4_AD;
962 if (forward->flags & FREC_DO_QUESTION)
Simon Kelley33702ab2015-12-28 23:17:15 +0000963 add_do_bit(header, nn, (unsigned char *)pheader + plen);
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000964 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 +0100965 return;
966 }
967 }
968 }
Simon Kelley3a237152013-12-12 12:15:50 +0000969
970 server = forward->sentto;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100971 if ((forward->sentto->flags & SERV_TYPE) == 0)
972 {
Simon Kelley51967f92014-03-25 21:07:00 +0000973 if (RCODE(header) == REFUSED)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100974 server = NULL;
975 else
976 {
977 struct server *last_server;
Simon Kelley832af0b2007-01-21 20:01:28 +0000978
Simon Kelley1a6bca82008-07-11 11:11:42 +0100979 /* find good server by address if possible, otherwise assume the last one we sent to */
980 for (last_server = daemon->servers; last_server; last_server = last_server->next)
981 if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) &&
982 sockaddr_isequal(&last_server->addr, &serveraddr))
983 {
984 server = last_server;
985 break;
986 }
987 }
Simon Kelley28866e92011-02-14 20:19:14 +0000988 if (!option_bool(OPT_ALL_SERVERS))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100989 daemon->last_server = server;
990 }
Simon Kelleya77cec82015-05-08 16:25:38 +0100991
992 /* We tried resending to this server with a smaller maximum size and got an answer.
Ville Skyttäfaaf3062018-01-14 17:32:52 +0000993 Make that permanent. To avoid reduxing the packet size for a single dropped packet,
Simon Kelley86fa1042015-05-10 13:50:59 +0100994 only do this when we get a truncated answer, or one larger than the safe size. */
Simon Kelley04db1482019-10-11 23:22:17 +0100995 if (forward->sentto->edns_pktsz > SAFE_PKTSZ && (forward->flags & FREC_TEST_PKTSZ) &&
Simon Kelley86fa1042015-05-10 13:50:59 +0100996 ((header->hb3 & HB3_TC) || n >= SAFE_PKTSZ))
Simon Kelley22dee512017-10-13 22:54:00 +0100997 {
Simon Kelley04db1482019-10-11 23:22:17 +0100998 forward->sentto->edns_pktsz = SAFE_PKTSZ;
999 forward->sentto->pktsz_reduced = now;
Petr Mensik51cdd1a2019-07-04 20:28:08 +02001000 (void)prettyprint_addr(&forward->sentto->addr, daemon->addrbuff);
Simon Kelleyebedcba2017-10-29 20:54:17 +00001001 my_syslog(LOG_WARNING, _("reducing DNS packet size for nameserver %s to %d"), daemon->addrbuff, SAFE_PKTSZ);
Simon Kelley22dee512017-10-13 22:54:00 +01001002 }
Simon Kelleyc1a4e252018-01-19 22:00:05 +00001003
1004
Simon Kelley1a6bca82008-07-11 11:11:42 +01001005 /* If the answer is an error, keep the forward record in place in case
1006 we get a good reply from another server. Kill it when we've
1007 had replies from all to avoid filling the forwarding table when
1008 everything is broken */
Simon Kelley122392e2018-10-31 22:24:02 +00001009 if (forward->forwardall == 0 || --forward->forwardall == 1 || RCODE(header) != REFUSED)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001010 {
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001011 int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
Simon Kelleya6004d72017-10-25 17:48:19 +01001012
Simon Kelley3a237152013-12-12 12:15:50 +00001013 if (option_bool(OPT_NO_REBIND))
1014 check_rebind = !(forward->flags & FREC_NOREBIND);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001015
Simon Kelley3a237152013-12-12 12:15:50 +00001016 /* Don't cache replies where DNSSEC validation was turned off, either
1017 the upstream server told us so, or the original query specified it. */
1018 if ((header->hb4 & HB4_CD) || (forward->flags & FREC_CHECKING_DISABLED))
1019 no_cache_dnssec = 1;
1020
1021#ifdef HAVE_DNSSEC
Simon Kelley04db1482019-10-11 23:22:17 +01001022 if ((forward->sentto->flags & SERV_DO_DNSSEC) &&
Simon Kelley57573712016-01-11 22:50:00 +00001023 option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED))
Simon Kelley3a237152013-12-12 12:15:50 +00001024 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001025 int status = 0;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001026
1027 /* We've had a reply already, which we're validating. Ignore this duplicate */
Simon Kelleye0c0ad32014-01-16 22:42:07 +00001028 if (forward->blocking_query)
Simon Kelley0fc2f312014-01-08 10:26:58 +00001029 return;
Simon Kelley9a31b682015-12-15 10:20:39 +00001030
1031 /* Truncated answer can't be validated.
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001032 If this is an answer to a DNSSEC-generated query, we still
1033 need to get the client to retry over TCP, so return
1034 an answer with the TC bit set, even if the actual answer fits.
1035 */
Simon Kelley9a31b682015-12-15 10:20:39 +00001036 if (header->hb3 & HB3_TC)
1037 status = STAT_TRUNCATED;
1038
1039 while (1)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001040 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001041 /* As soon as anything returns BOGUS, we stop and unwind, to do otherwise
1042 would invite infinite loops, since the answers to DNSKEY and DS queries
1043 will not be cached, so they'll be repeated. */
1044 if (status != STAT_BOGUS && status != STAT_TRUNCATED && status != STAT_ABANDONED)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001045 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001046 if (forward->flags & FREC_DNSKEY_QUERY)
1047 status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
1048 else if (forward->flags & FREC_DS_QUERY)
1049 status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001050 else
Simon Kelley9a31b682015-12-15 10:20:39 +00001051 status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class,
Simon Kelley203ce0a2019-10-12 21:41:20 +01001052 !option_bool(OPT_DNSSEC_IGN_NS) && (forward->sentto->flags & SERV_DO_DNSSEC),
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001053 NULL, NULL, NULL);
Simon Kelley6b173352018-05-08 18:32:14 +01001054#ifdef HAVE_DUMPFILE
1055 if (status == STAT_BOGUS)
1056 dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_BOGUS : DUMP_BOGUS,
1057 header, (size_t)n, &serveraddr, NULL);
1058#endif
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001059 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001060
Simon Kelley9a31b682015-12-15 10:20:39 +00001061 /* Can't validate, as we're missing key data. Put this
1062 answer aside, whilst we get that. */
1063 if (status == STAT_NEED_DS || status == STAT_NEED_KEY)
Simon Kelley3a237152013-12-12 12:15:50 +00001064 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001065 struct frec *new, *orig;
Simon Kelley9d633042013-12-13 15:36:55 +00001066
Simon Kelley9a31b682015-12-15 10:20:39 +00001067 /* Free any saved query */
1068 if (forward->stash)
1069 blockdata_free(forward->stash);
1070
1071 /* Now save reply pending receipt of key data */
1072 if (!(forward->stash = blockdata_alloc((char *)header, n)))
Simon Kelley97e618a2015-01-07 21:55:43 +00001073 return;
Simon Kelley9a31b682015-12-15 10:20:39 +00001074 forward->stash_len = n;
Simon Kelleye0c0ad32014-01-16 22:42:07 +00001075
Simon Kelley9a31b682015-12-15 10:20:39 +00001076 /* Find the original query that started it all.... */
1077 for (orig = forward; orig->dependent; orig = orig->dependent);
Simon Kelley7fa836e2014-02-10 20:11:24 +00001078
Simon Kelley8caf3d72020-04-04 17:00:32 +01001079 /* Make sure we don't expire and free the orig frec during the
1080 allocation of a new one. */
1081 if (--orig->work_counter == 0 || !(new = get_new_frec(now, NULL, orig)))
Simon Kelley9a31b682015-12-15 10:20:39 +00001082 status = STAT_ABANDONED;
Simon Kelleye0c0ad32014-01-16 22:42:07 +00001083 else
Simon Kelley3a237152013-12-12 12:15:50 +00001084 {
Simon Kelleye1791f32018-10-06 23:23:23 +01001085 int querytype, fd, type = SERV_DO_DNSSEC;
Simon Kelley9a31b682015-12-15 10:20:39 +00001086 struct frec *next = new->next;
Simon Kelley92be34a2016-01-16 18:39:54 +00001087 char *domain;
1088
Simon Kelley9a31b682015-12-15 10:20:39 +00001089 *new = *forward; /* copy everything, then overwrite */
1090 new->next = next;
1091 new->blocking_query = NULL;
Simon Kelley92be34a2016-01-16 18:39:54 +00001092
1093 /* Find server to forward to. This will normally be the
1094 same as for the original query, but may be another if
1095 servers for domains are involved. */
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001096 if (search_servers(now, NULL, F_DNSSECOK, daemon->keyname, &type, &domain, NULL) == 0)
Simon Kelley92be34a2016-01-16 18:39:54 +00001097 {
Simon Kelley203ce0a2019-10-12 21:41:20 +01001098 struct server *start, *new_server = NULL;
1099 start = server = forward->sentto;
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001100
1101 while (1)
1102 {
Petr Menšík8f9bd612021-03-27 23:16:09 +00001103 if (server_test_type(start, domain, type, SERV_DO_DNSSEC))
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001104 {
1105 new_server = start;
1106 if (server == start)
1107 {
1108 new_server = NULL;
1109 break;
1110 }
1111 }
1112
1113 if (!(start = start->next))
1114 start = daemon->servers;
1115 if (start == server)
1116 break;
1117 }
1118
1119 if (new_server)
1120 server = new_server;
Simon Kelley92be34a2016-01-16 18:39:54 +00001121 }
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001122
Simon Kelley9a31b682015-12-15 10:20:39 +00001123 new->sentto = server;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00001124 new->rfds = NULL;
Simon Kelley15b60dd2020-11-18 18:34:55 +00001125 new->frec_src.next = NULL;
Simon Kelleya0088e82018-05-10 21:43:14 +01001126 new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_HAS_EXTRADATA);
1127 new->forwardall = 0;
Simon Kelley9a31b682015-12-15 10:20:39 +00001128
1129 new->dependent = forward; /* to find query awaiting new one. */
1130 forward->blocking_query = new; /* for garbage cleaning */
1131 /* validate routines leave name of required record in daemon->keyname */
1132 if (status == STAT_NEED_KEY)
Simon Kelley7fa836e2014-02-10 20:11:24 +00001133 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001134 new->flags |= FREC_DNSKEY_QUERY;
Simon Kelleye1791f32018-10-06 23:23:23 +01001135 querytype = T_DNSKEY;
Simon Kelleyf1668d22014-01-08 16:53:27 +00001136 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001137 else
1138 {
1139 new->flags |= FREC_DS_QUERY;
Simon Kelleye1791f32018-10-06 23:23:23 +01001140 querytype = T_DS;
Simon Kelley9a31b682015-12-15 10:20:39 +00001141 }
Simon Kelleye1791f32018-10-06 23:23:23 +01001142
1143 nn = dnssec_generate_query(header,((unsigned char *) header) + server->edns_pktsz,
1144 daemon->keyname, forward->class, querytype, server->edns_pktsz);
1145
Simon Kelley2d765862020-11-12 22:06:07 +00001146 memcpy(new->hash, hash_questions(header, nn, daemon->namebuff), HASH_SIZE);
Simon Kelley9a31b682015-12-15 10:20:39 +00001147 new->new_id = get_id();
1148 header->id = htons(new->new_id);
1149 /* Save query for retransmission */
1150 new->stash = blockdata_alloc((char *)header, nn);
1151 new->stash_len = nn;
1152
1153 /* Don't resend this. */
1154 daemon->srv_save = NULL;
1155
Simon Kelley74d4fcd2021-03-15 21:59:51 +00001156 if ((fd = allocate_rfd(&new->rfds, server)) != -1)
Simon Kelley9a31b682015-12-15 10:20:39 +00001157 {
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001158#ifdef HAVE_CONNTRACK
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001159 if (option_bool(OPT_CONNTRACK))
Petr Menšík6c0bf792021-03-18 00:07:45 +01001160 set_outgoing_mark(orig, fd);
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001161#endif
Petr Menšík51f7bc92021-03-18 01:05:43 +01001162 server_send_log(server, fd, header, nn, DUMP_SEC_QUERY,
1163 F_NOEXTRA | F_DNSSEC, daemon->keyname,
1164 querystr("dnssec-query", querytype));
Simon Kelley9a31b682015-12-15 10:20:39 +00001165 server->queries++;
1166 }
1167 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00001168 return;
Simon Kelley3a237152013-12-12 12:15:50 +00001169 }
Simon Kelley3a237152013-12-12 12:15:50 +00001170
Simon Kelley9a31b682015-12-15 10:20:39 +00001171 /* Validated original answer, all done. */
1172 if (!forward->dependent)
1173 break;
1174
Josh Soref730c6742017-02-06 16:14:04 +00001175 /* validated subsidiary query, (and cached result)
Simon Kelley9a31b682015-12-15 10:20:39 +00001176 pop that and return to the previous query we were working on. */
Simon Kelley0744ca62014-01-25 16:40:15 +00001177 struct frec *prev = forward->dependent;
1178 free_frec(forward);
1179 forward = prev;
1180 forward->blocking_query = NULL; /* already gone */
1181 blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
1182 n = forward->stash_len;
Simon Kelley3a237152013-12-12 12:15:50 +00001183 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001184
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001185
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001186 no_cache_dnssec = 0;
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001187
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001188 if (status == STAT_TRUNCATED)
Simon Kelley0744ca62014-01-25 16:40:15 +00001189 header->hb3 |= HB3_TC;
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001190 else
Simon Kelley7fa836e2014-02-10 20:11:24 +00001191 {
Simon Kelley554b5802015-04-17 22:50:20 +01001192 char *result, *domain = "result";
Simon Kelley7fa836e2014-02-10 20:11:24 +00001193
Simon Kelley9a31b682015-12-15 10:20:39 +00001194 if (status == STAT_ABANDONED)
Simon Kelley150162b2015-03-27 09:58:26 +00001195 {
1196 result = "ABANDONED";
1197 status = STAT_BOGUS;
1198 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00001199 else
1200 result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
1201
Simon Kelley554b5802015-04-17 22:50:20 +01001202 if (status == STAT_BOGUS && extract_request(header, n, daemon->namebuff, NULL))
1203 domain = daemon->namebuff;
Simon Kelley9a31b682015-12-15 10:20:39 +00001204
Simon Kelley07ed5852018-05-04 21:52:22 +01001205 log_query(F_SECSTAT, domain, NULL, result);
Simon Kelley7fa836e2014-02-10 20:11:24 +00001206 }
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001207
Simon Kelley3a237152013-12-12 12:15:50 +00001208 if (status == STAT_SECURE)
1209 cache_secure = 1;
Simon Kelley3a237152013-12-12 12:15:50 +00001210 else if (status == STAT_BOGUS)
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001211 {
1212 no_cache_dnssec = 1;
1213 bogusanswer = 1;
1214 }
Simon Kelley3a237152013-12-12 12:15:50 +00001215 }
Simon Kelley04db1482019-10-11 23:22:17 +01001216
Simon Kelley6b173352018-05-08 18:32:14 +01001217#endif
1218
Simon Kelley83349b82014-02-10 21:02:01 +00001219 /* restore CD bit to the value in the query */
1220 if (forward->flags & FREC_CHECKING_DISABLED)
1221 header->hb4 |= HB4_CD;
1222 else
1223 header->hb4 &= ~HB4_CD;
Simon Kelley25e63f12020-11-25 21:17:52 +00001224
1225 /* Never cache answers which are contingent on the source or MAC address EDSN0 option,
1226 since the cache is ignorant of such things. */
1227 if (forward->flags & FREC_NO_CACHE)
1228 no_cache_dnssec = 1;
Simon Kelley3a237152013-12-12 12:15:50 +00001229
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001230 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 +00001231 forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION,
Simon Kelley15b60dd2020-11-18 18:34:55 +00001232 forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->frec_src.source)))
Simon Kelley832af0b2007-01-21 20:01:28 +00001233 {
Simon Kelley15b60dd2020-11-18 18:34:55 +00001234 struct frec_src *src;
1235
1236 header->id = htons(forward->frec_src.orig_id);
Simon Kelley572b41e2011-02-18 18:11:18 +00001237 header->hb4 |= HB4_RA; /* recursion if available */
Simon Kelley5aa5f0f2015-12-21 17:20:35 +00001238#ifdef HAVE_DNSSEC
1239 /* 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 +01001240 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 +00001241 header, the answer is still bigger than 512, truncate it and mark it so. The client then retries with TCP. */
1242 if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER) && (nn > PACKETSZ))
1243 {
1244 header->ancount = htons(0);
1245 header->nscount = htons(0);
1246 header->arcount = htons(0);
1247 header->hb3 |= HB3_TC;
1248 nn = resize_packet(header, nn, NULL, 0);
1249 }
1250#endif
Simon Kelley6b173352018-05-08 18:32:14 +01001251
Simon Kelley15b60dd2020-11-18 18:34:55 +00001252 for (src = &forward->frec_src; src; src = src->next)
1253 {
1254 header->id = htons(src->orig_id);
1255
Simon Kelley6b173352018-05-08 18:32:14 +01001256#ifdef HAVE_DUMPFILE
Simon Kelley15b60dd2020-11-18 18:34:55 +00001257 dump_packet(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &src->source);
Simon Kelley6b173352018-05-08 18:32:14 +01001258#endif
Simon Kelley15b60dd2020-11-18 18:34:55 +00001259
Simon Kelley04490bf2021-01-22 16:49:12 +00001260 send_from(src->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
Simon Kelley15b60dd2020-11-18 18:34:55 +00001261 &src->source, &src->dest, src->iface);
1262
1263 if (option_bool(OPT_EXTRALOG) && src != &forward->frec_src)
1264 {
1265 daemon->log_display_id = src->log_id;
1266 daemon->log_source_addr = &src->source;
1267 log_query(F_UPSTREAM, "query", NULL, "duplicate");
1268 }
1269 }
Simon Kelley832af0b2007-01-21 20:01:28 +00001270 }
Simon Kelley15b60dd2020-11-18 18:34:55 +00001271
Simon Kelley1a6bca82008-07-11 11:11:42 +01001272 free_frec(forward); /* cancel */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001273 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001274}
Simon Kelley44a2a312004-03-10 20:04:35 +00001275
Simon Kelley1a6bca82008-07-11 11:11:42 +01001276
Simon Kelley5aabfc72007-08-29 11:24:47 +01001277void receive_query(struct listener *listen, time_t now)
Simon Kelley44a2a312004-03-10 20:04:35 +00001278{
Simon Kelley572b41e2011-02-18 18:11:18 +00001279 struct dns_header *header = (struct dns_header *)daemon->packet;
Simon Kelley44a2a312004-03-10 20:04:35 +00001280 union mysockaddr source_addr;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001281 unsigned char *pheader;
1282 unsigned short type, udp_size = PACKETSZ; /* default if no EDNS0 */
Simon Kelleycc921df2019-01-02 22:48:59 +00001283 union all_addr dst_addr;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001284 struct in_addr netmask, dst_addr_4;
Simon Kelleycdeda282006-03-16 20:16:06 +00001285 size_t m;
1286 ssize_t n;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001287 int if_index = 0, auth_dns = 0, do_bit = 0, have_pseudoheader = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001288#ifdef HAVE_AUTH
1289 int local_auth = 0;
1290#endif
Simon Kelley44a2a312004-03-10 20:04:35 +00001291 struct iovec iov[1];
1292 struct msghdr msg;
1293 struct cmsghdr *cmptr;
Simon Kelley44a2a312004-03-10 20:04:35 +00001294 union {
1295 struct cmsghdr align; /* this ensures alignment */
Simon Kelley44a2a312004-03-10 20:04:35 +00001296 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001297#if defined(HAVE_LINUX_NETWORK)
Simon Kelley44a2a312004-03-10 20:04:35 +00001298 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
Simon Kelley824af852008-02-12 20:43:05 +00001299#elif defined(IP_RECVDSTADDR) && defined(HAVE_SOLARIS_NETWORK)
1300 char control[CMSG_SPACE(sizeof(struct in_addr)) +
1301 CMSG_SPACE(sizeof(unsigned int))];
Simon Kelley44a2a312004-03-10 20:04:35 +00001302#elif defined(IP_RECVDSTADDR)
1303 char control[CMSG_SPACE(sizeof(struct in_addr)) +
1304 CMSG_SPACE(sizeof(struct sockaddr_dl))];
1305#endif
1306 } control_u;
Petr Menšík1c1b9252019-07-15 17:16:44 +02001307 int family = listen->addr.sa.sa_family;
Simon Kelley2329bef2013-12-03 13:41:16 +00001308 /* Can always get recvd interface for IPv6 */
Petr Menšík1c1b9252019-07-15 17:16:44 +02001309 int check_dst = !option_bool(OPT_NOWILD) || family == AF_INET6;
Simon Kelley2329bef2013-12-03 13:41:16 +00001310
Simon Kelleycdeda282006-03-16 20:16:06 +00001311 /* packet buffer overwritten */
1312 daemon->srv_save = NULL;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00001313
Simon Kelleycc921df2019-01-02 22:48:59 +00001314 dst_addr_4.s_addr = dst_addr.addr4.s_addr = 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001315 netmask.s_addr = 0;
1316
Simon Kelley7e5664b2013-04-05 16:57:41 +01001317 if (option_bool(OPT_NOWILD) && listen->iface)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001318 {
Simon Kelley4f7b3042012-11-28 21:27:02 +00001319 auth_dns = listen->iface->dns_auth;
1320
Petr Menšík1c1b9252019-07-15 17:16:44 +02001321 if (family == AF_INET)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001322 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001323 dst_addr_4 = dst_addr.addr4 = listen->iface->addr.in.sin_addr;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001324 netmask = listen->iface->netmask;
1325 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001326 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00001327
Simon Kelley3be34542004-09-11 19:12:13 +01001328 iov[0].iov_base = daemon->packet;
1329 iov[0].iov_len = daemon->edns_pktsz;
Simon Kelley44a2a312004-03-10 20:04:35 +00001330
1331 msg.msg_control = control_u.control;
1332 msg.msg_controllen = sizeof(control_u);
1333 msg.msg_flags = 0;
1334 msg.msg_name = &source_addr;
1335 msg.msg_namelen = sizeof(source_addr);
1336 msg.msg_iov = iov;
1337 msg.msg_iovlen = 1;
1338
Simon Kelleyde379512004-06-22 20:23:33 +01001339 if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
Simon Kelley3be34542004-09-11 19:12:13 +01001340 return;
Simon Kelley44a2a312004-03-10 20:04:35 +00001341
Simon Kelley572b41e2011-02-18 18:11:18 +00001342 if (n < (int)sizeof(struct dns_header) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001343 (msg.msg_flags & MSG_TRUNC) ||
Simon Kelley572b41e2011-02-18 18:11:18 +00001344 (header->hb3 & HB3_QR))
Simon Kelley3be34542004-09-11 19:12:13 +01001345 return;
Simon Kelley63437ff2017-09-06 22:34:21 +01001346
1347 /* Clear buffer beyond request to avoid risk of
1348 information disclosure. */
1349 memset(daemon->packet + n, 0, daemon->edns_pktsz - n);
Simon Kelley44a2a312004-03-10 20:04:35 +00001350
Petr Menšík1c1b9252019-07-15 17:16:44 +02001351 source_addr.sa.sa_family = family;
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001352
Petr Menšík1c1b9252019-07-15 17:16:44 +02001353 if (family == AF_INET)
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001354 {
1355 /* Source-port == 0 is an error, we can't send back to that.
1356 http://www.ietf.org/mail-archive/web/dnsop/current/msg11441.html */
1357 if (source_addr.in.sin_port == 0)
1358 return;
1359 }
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001360 else
1361 {
1362 /* Source-port == 0 is an error, we can't send back to that. */
1363 if (source_addr.in6.sin6_port == 0)
1364 return;
1365 source_addr.in6.sin6_flowinfo = 0;
1366 }
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001367
Simon Kelleyc8a80482014-03-05 14:29:54 +00001368 /* We can be configured to only accept queries from at-most-one-hop-away addresses. */
1369 if (option_bool(OPT_LOCAL_SERVICE))
1370 {
1371 struct addrlist *addr;
Simon Kelleyee875042018-10-23 22:10:17 +01001372
Petr Menšík1c1b9252019-07-15 17:16:44 +02001373 if (family == AF_INET6)
Simon Kelleyc8a80482014-03-05 14:29:54 +00001374 {
1375 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1376 if ((addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001377 is_same_net6(&addr->addr.addr6, &source_addr.in6.sin6_addr, addr->prefixlen))
Simon Kelleyc8a80482014-03-05 14:29:54 +00001378 break;
1379 }
1380 else
Simon Kelleyc8a80482014-03-05 14:29:54 +00001381 {
1382 struct in_addr netmask;
1383 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1384 {
Richard Genoud15b1b7e2014-09-17 21:12:00 +01001385 netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
Simon Kelleyc8a80482014-03-05 14:29:54 +00001386 if (!(addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001387 is_same_net(addr->addr.addr4, source_addr.in.sin_addr, netmask))
Simon Kelleyc8a80482014-03-05 14:29:54 +00001388 break;
1389 }
1390 }
1391 if (!addr)
1392 {
Simon Kelley0c8584e2014-03-12 20:12:56 +00001393 static int warned = 0;
1394 if (!warned)
1395 {
1396 my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
1397 warned = 1;
1398 }
Simon Kelleyc8a80482014-03-05 14:29:54 +00001399 return;
1400 }
1401 }
1402
Simon Kelley2329bef2013-12-03 13:41:16 +00001403 if (check_dst)
Simon Kelley44a2a312004-03-10 20:04:35 +00001404 {
Simon Kelley8a911cc2004-03-16 18:35:52 +00001405 struct ifreq ifr;
1406
Simon Kelley26128d22004-11-14 16:43:54 +00001407 if (msg.msg_controllen < sizeof(struct cmsghdr))
1408 return;
1409
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001410#if defined(HAVE_LINUX_NETWORK)
Petr Menšík1c1b9252019-07-15 17:16:44 +02001411 if (family == AF_INET)
Simon Kelley26128d22004-11-14 16:43:54 +00001412 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelleyc72daea2012-01-05 21:33:27 +00001413 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
Simon Kelley26128d22004-11-14 16:43:54 +00001414 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001415 union {
1416 unsigned char *c;
1417 struct in_pktinfo *p;
1418 } p;
1419 p.c = CMSG_DATA(cmptr);
Simon Kelleycc921df2019-01-02 22:48:59 +00001420 dst_addr_4 = dst_addr.addr4 = p.p->ipi_spec_dst;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001421 if_index = p.p->ipi_ifindex;
Simon Kelley26128d22004-11-14 16:43:54 +00001422 }
1423#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
Petr Menšík1c1b9252019-07-15 17:16:44 +02001424 if (family == AF_INET)
Simon Kelley26128d22004-11-14 16:43:54 +00001425 {
1426 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001427 {
1428 union {
1429 unsigned char *c;
1430 unsigned int *i;
1431 struct in_addr *a;
1432#ifndef HAVE_SOLARIS_NETWORK
1433 struct sockaddr_dl *s;
Simon Kelley824af852008-02-12 20:43:05 +00001434#endif
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001435 } p;
1436 p.c = CMSG_DATA(cmptr);
1437 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
Simon Kelleycc921df2019-01-02 22:48:59 +00001438 dst_addr_4 = dst_addr.addr4 = *(p.a);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001439 else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
1440#ifdef HAVE_SOLARIS_NETWORK
1441 if_index = *(p.i);
1442#else
1443 if_index = p.s->sdl_index;
1444#endif
1445 }
Simon Kelley26128d22004-11-14 16:43:54 +00001446 }
1447#endif
1448
Petr Menšík1c1b9252019-07-15 17:16:44 +02001449 if (family == AF_INET6)
Simon Kelley26128d22004-11-14 16:43:54 +00001450 {
1451 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelleyc72daea2012-01-05 21:33:27 +00001452 if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
Simon Kelley26128d22004-11-14 16:43:54 +00001453 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001454 union {
1455 unsigned char *c;
1456 struct in6_pktinfo *p;
1457 } p;
1458 p.c = CMSG_DATA(cmptr);
1459
Simon Kelleycc921df2019-01-02 22:48:59 +00001460 dst_addr.addr6 = p.p->ipi6_addr;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001461 if_index = p.p->ipi6_ifindex;
Simon Kelley26128d22004-11-14 16:43:54 +00001462 }
1463 }
Simon Kelley26128d22004-11-14 16:43:54 +00001464
1465 /* enforce available interface configuration */
1466
Simon Kelleye25db1f2013-01-29 22:10:26 +00001467 if (!indextoname(listen->fd, if_index, ifr.ifr_name))
Simon Kelley832af0b2007-01-21 20:01:28 +00001468 return;
1469
Petr Menšík1c1b9252019-07-15 17:16:44 +02001470 if (!iface_check(family, &dst_addr, ifr.ifr_name, &auth_dns))
Simon Kelleye25db1f2013-01-29 22:10:26 +00001471 {
1472 if (!option_bool(OPT_CLEVERBIND))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001473 enumerate_interfaces(0);
Petr Menšík1c1b9252019-07-15 17:16:44 +02001474 if (!loopback_exception(listen->fd, family, &dst_addr, ifr.ifr_name) &&
1475 !label_exception(if_index, family, &dst_addr))
Simon Kelleye25db1f2013-01-29 22:10:26 +00001476 return;
1477 }
1478
Petr Menšík1c1b9252019-07-15 17:16:44 +02001479 if (family == AF_INET && option_bool(OPT_LOCALISE))
Simon Kelley552af8b2012-02-29 20:10:31 +00001480 {
1481 struct irec *iface;
1482
Josh Soref730c6742017-02-06 16:14:04 +00001483 /* get the netmask of the interface which has the address we were sent to.
klemens43517fc2017-02-19 15:53:37 +00001484 This is no necessarily the interface we arrived on. */
Simon Kelley552af8b2012-02-29 20:10:31 +00001485
1486 for (iface = daemon->interfaces; iface; iface = iface->next)
1487 if (iface->addr.sa.sa_family == AF_INET &&
1488 iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
1489 break;
1490
1491 /* interface may be new */
Simon Kelleye25db1f2013-01-29 22:10:26 +00001492 if (!iface && !option_bool(OPT_CLEVERBIND))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001493 enumerate_interfaces(0);
Simon Kelley552af8b2012-02-29 20:10:31 +00001494
1495 for (iface = daemon->interfaces; iface; iface = iface->next)
1496 if (iface->addr.sa.sa_family == AF_INET &&
1497 iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
1498 break;
1499
1500 /* If we failed, abandon localisation */
1501 if (iface)
1502 netmask = iface->netmask;
1503 else
1504 dst_addr_4.s_addr = 0;
1505 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001506 }
Simon Kelley25cf5e32015-01-09 15:53:03 +00001507
1508 /* log_query gets called indirectly all over the place, so
1509 pass these in global variables - sorry. */
1510 daemon->log_display_id = ++daemon->log_id;
1511 daemon->log_source_addr = &source_addr;
Simon Kelley6b173352018-05-08 18:32:14 +01001512
1513#ifdef HAVE_DUMPFILE
1514 dump_packet(DUMP_QUERY, daemon->packet, (size_t)n, &source_addr, NULL);
1515#endif
1516
Simon Kelleycdeda282006-03-16 20:16:06 +00001517 if (extract_request(header, (size_t)n, daemon->namebuff, &type))
Simon Kelley44a2a312004-03-10 20:04:35 +00001518 {
Simon Kelleyb485ed92013-10-18 22:00:39 +01001519#ifdef HAVE_AUTH
1520 struct auth_zone *zone;
1521#endif
Simon Kelley610e7822014-02-06 14:45:17 +00001522 char *types = querystr(auth_dns ? "auth" : "query", type);
Petr Menšík6c0bf792021-03-18 00:07:45 +01001523
1524 log_query_mysockaddr(F_QUERY | F_FORWARD, daemon->namebuff,
1525 &source_addr, types);
Simon Kelley44a2a312004-03-10 20:04:35 +00001526
Simon Kelley4820dce2012-12-18 18:30:30 +00001527#ifdef HAVE_AUTH
Simon Kelleyb485ed92013-10-18 22:00:39 +01001528 /* find queries for zones we're authoritative for, and answer them directly */
Simon Kelley3a3965a2015-08-09 17:45:06 +01001529 if (!auth_dns && !option_bool(OPT_LOCALISE))
Simon Kelley6008bdb2013-10-21 21:47:03 +01001530 for (zone = daemon->auth_zones; zone; zone = zone->next)
1531 if (in_zone(zone, daemon->namebuff, NULL))
1532 {
1533 auth_dns = 1;
1534 local_auth = 1;
1535 break;
1536 }
Simon Kelleyb485ed92013-10-18 22:00:39 +01001537#endif
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01001538
1539#ifdef HAVE_LOOP
1540 /* Check for forwarding loop */
1541 if (detect_loop(daemon->namebuff, type))
1542 return;
1543#endif
Simon Kelleyb485ed92013-10-18 22:00:39 +01001544 }
1545
Simon Kelley5bb88f02015-12-21 16:23:47 +00001546 if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL, NULL))
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001547 {
1548 unsigned short flags;
1549
1550 have_pseudoheader = 1;
1551 GETSHORT(udp_size, pheader);
1552 pheader += 2; /* ext_rcode */
1553 GETSHORT(flags, pheader);
1554
1555 if (flags & 0x8000)
1556 do_bit = 1;/* do bit */
1557
1558 /* If the client provides an EDNS0 UDP size, use that to limit our reply.
1559 (bounded by the maximum configured). If no EDNS0, then it
1560 defaults to 512 */
1561 if (udp_size > daemon->edns_pktsz)
1562 udp_size = daemon->edns_pktsz;
Simon Kelleya3303e12017-09-07 20:45:00 +01001563 else if (udp_size < PACKETSZ)
1564 udp_size = PACKETSZ; /* Sanity check - can't reduce below default. RFC 6891 6.2.3 */
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001565 }
1566
Simon Kelleyb485ed92013-10-18 22:00:39 +01001567#ifdef HAVE_AUTH
Simon Kelley4f7b3042012-11-28 21:27:02 +00001568 if (auth_dns)
Simon Kelley824af852008-02-12 20:43:05 +00001569 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001570 m = answer_auth(header, ((char *) header) + udp_size, (size_t)n, now, &source_addr,
1571 local_auth, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001572 if (m >= 1)
Simon Kelleyb485ed92013-10-18 22:00:39 +01001573 {
1574 send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
1575 (char *)header, m, &source_addr, &dst_addr, if_index);
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001576 daemon->metrics[METRIC_DNS_AUTH_ANSWERED]++;
Simon Kelleyb485ed92013-10-18 22:00:39 +01001577 }
Simon Kelley824af852008-02-12 20:43:05 +00001578 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001579 else
Simon Kelley4820dce2012-12-18 18:30:30 +00001580#endif
Simon Kelley4f7b3042012-11-28 21:27:02 +00001581 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001582 int ad_reqd = do_bit;
1583 /* RFC 6840 5.7 */
1584 if (header->hb4 & HB4_AD)
1585 ad_reqd = 1;
1586
1587 m = answer_request(header, ((char *) header) + udp_size, (size_t)n,
1588 dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001589
1590 if (m >= 1)
1591 {
1592 send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
1593 (char *)header, m, &source_addr, &dst_addr, if_index);
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001594 daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001595 }
1596 else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
Simon Kelley613ad152014-02-25 23:02:28 +00001597 header, (size_t)n, now, NULL, ad_reqd, do_bit))
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001598 daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]++;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001599 else
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001600 daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001601 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001602}
1603
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001604#ifdef HAVE_DNSSEC
Josh Soref730c6742017-02-06 16:14:04 +00001605/* Recurse up the key hierarchy */
Simon Kelley7fa836e2014-02-10 20:11:24 +00001606static int tcp_key_recurse(time_t now, int status, struct dns_header *header, size_t n,
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001607 int class, char *name, char *keyname, struct server *server,
1608 int have_mark, unsigned int mark, int *keycount)
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001609{
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001610 int new_status;
Simon Kelley9a31b682015-12-15 10:20:39 +00001611 unsigned char *packet = NULL;
Simon Kelley9a31b682015-12-15 10:20:39 +00001612 unsigned char *payload = NULL;
1613 struct dns_header *new_header = NULL;
1614 u16 *length = NULL;
Simon Kelley361dfe52017-02-10 21:12:30 +00001615
Simon Kelley9a31b682015-12-15 10:20:39 +00001616 while (1)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001617 {
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001618 int type = SERV_DO_DNSSEC;
1619 char *domain;
1620 size_t m;
1621 unsigned char c1, c2;
Simon Kelley361dfe52017-02-10 21:12:30 +00001622 struct server *firstsendto = NULL;
1623
Simon Kelley9a31b682015-12-15 10:20:39 +00001624 /* limit the amount of work we do, to avoid cycling forever on loops in the DNS */
1625 if (--(*keycount) == 0)
1626 new_status = STAT_ABANDONED;
1627 else if (status == STAT_NEED_KEY)
1628 new_status = dnssec_validate_by_ds(now, header, n, name, keyname, class);
1629 else if (status == STAT_NEED_DS)
1630 new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
1631 else
James Bottomleye33b4872017-03-17 21:44:10 +00001632 new_status = dnssec_validate_reply(now, header, n, name, keyname, &class,
Simon Kelleya6918532018-04-15 16:20:52 +01001633 !option_bool(OPT_DNSSEC_IGN_NS) && (server->flags & SERV_DO_DNSSEC),
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001634 NULL, NULL, NULL);
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001635
Simon Kelley9a31b682015-12-15 10:20:39 +00001636 if (new_status != STAT_NEED_DS && new_status != STAT_NEED_KEY)
1637 break;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001638
Simon Kelley9a31b682015-12-15 10:20:39 +00001639 /* Can't validate because we need a key/DS whose name now in keyname.
1640 Make query for same, and recurse to validate */
Simon Kelley7fa836e2014-02-10 20:11:24 +00001641 if (!packet)
Simon Kelley9a31b682015-12-15 10:20:39 +00001642 {
1643 packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
1644 payload = &packet[2];
1645 new_header = (struct dns_header *)payload;
1646 length = (u16 *)packet;
1647 }
1648
1649 if (!packet)
1650 {
1651 new_status = STAT_ABANDONED;
1652 break;
1653 }
Simon Kelleye1791f32018-10-06 23:23:23 +01001654
Simon Kelley33702ab2015-12-28 23:17:15 +00001655 m = dnssec_generate_query(new_header, ((unsigned char *) new_header) + 65536, keyname, class,
Simon Kelleye1791f32018-10-06 23:23:23 +01001656 new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS, server->edns_pktsz);
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001657
Simon Kelley7fa836e2014-02-10 20:11:24 +00001658 *length = htons(m);
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001659
1660 /* Find server to forward to. This will normally be the
1661 same as for the original query, but may be another if
1662 servers for domains are involved. */
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001663 if (search_servers(now, NULL, F_DNSSECOK, keyname, &type, &domain, NULL) != 0)
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001664 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001665 new_status = STAT_ABANDONED;
1666 break;
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001667 }
Simon Kelley361dfe52017-02-10 21:12:30 +00001668
Simon Kelley361dfe52017-02-10 21:12:30 +00001669 while (1)
1670 {
Simon Kelley608aa9f2019-03-10 22:44:15 +00001671 int data_sent = 0;
1672
Simon Kelley361dfe52017-02-10 21:12:30 +00001673 if (!firstsendto)
1674 firstsendto = server;
1675 else
1676 {
1677 if (!(server = server->next))
1678 server = daemon->servers;
1679 if (server == firstsendto)
1680 {
1681 /* can't find server to accept our query. */
1682 new_status = STAT_ABANDONED;
1683 break;
1684 }
1685 }
1686
Petr Menšíke10a9232021-03-15 11:20:49 +01001687 if (!server_test_type(server, domain, type, SERV_DO_DNSSEC))
Simon Kelley361dfe52017-02-10 21:12:30 +00001688 continue;
Simon Kelleye1791f32018-10-06 23:23:23 +01001689
1690 retry:
1691 /* may need to make new connection. */
1692 if (server->tcpfd == -1)
1693 {
1694 if ((server->tcpfd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
1695 continue; /* No good, next server */
1696
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001697#ifdef HAVE_CONNTRACK
Simon Kelleye1791f32018-10-06 23:23:23 +01001698 /* Copy connection mark of incoming query to outgoing connection. */
1699 if (have_mark)
1700 setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001701#endif
Simon Kelleye1791f32018-10-06 23:23:23 +01001702
Simon Kelley608aa9f2019-03-10 22:44:15 +00001703 if (!local_bind(server->tcpfd, &server->source_addr, server->interface, 0, 1))
1704 {
1705 close(server->tcpfd);
1706 server->tcpfd = -1;
1707 continue; /* No good, next server */
1708 }
1709
1710#ifdef MSG_FASTOPEN
Petr Menšík51f7bc92021-03-18 01:05:43 +01001711 server_send(server, server->tcpfd, packet, m + sizeof(u16), MSG_FASTOPEN);
1712
Simon Kelley608aa9f2019-03-10 22:44:15 +00001713 if (errno == 0)
1714 data_sent = 1;
1715#endif
1716
1717 if (!data_sent && connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) == -1)
Simon Kelleye1791f32018-10-06 23:23:23 +01001718 {
1719 close(server->tcpfd);
1720 server->tcpfd = -1;
1721 continue; /* No good, next server */
1722 }
1723
1724 server->flags &= ~SERV_GOT_TCP;
1725 }
Simon Kelley361dfe52017-02-10 21:12:30 +00001726
Simon Kelley608aa9f2019-03-10 22:44:15 +00001727 if ((!data_sent && !read_write(server->tcpfd, packet, m + sizeof(u16), 0)) ||
Simon Kelley361dfe52017-02-10 21:12:30 +00001728 !read_write(server->tcpfd, &c1, 1, 1) ||
1729 !read_write(server->tcpfd, &c2, 1, 1) ||
1730 !read_write(server->tcpfd, payload, (c1 << 8) | c2, 1))
1731 {
1732 close(server->tcpfd);
1733 server->tcpfd = -1;
1734 /* We get data then EOF, reopen connection to same server,
1735 else try next. This avoids DoS from a server which accepts
1736 connections and then closes them. */
1737 if (server->flags & SERV_GOT_TCP)
1738 goto retry;
1739 else
1740 continue;
1741 }
Simon Kelleye1791f32018-10-06 23:23:23 +01001742
Petr Menšík6c0bf792021-03-18 00:07:45 +01001743 log_query_mysockaddr(F_NOEXTRA | F_DNSSEC, keyname, &server->addr,
1744 querystr("dnssec-query", new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS));
Simon Kelleye1791f32018-10-06 23:23:23 +01001745
Simon Kelley361dfe52017-02-10 21:12:30 +00001746 server->flags |= SERV_GOT_TCP;
1747
1748 m = (c1 << 8) | c2;
1749 new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, have_mark, mark, keycount);
1750 break;
1751 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001752
1753 if (new_status != STAT_OK)
1754 break;
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001755 }
Simon Kelley361dfe52017-02-10 21:12:30 +00001756
Simon Kelley9a31b682015-12-15 10:20:39 +00001757 if (packet)
1758 free(packet);
1759
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001760 return new_status;
1761}
1762#endif
1763
1764
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001765/* The daemon forks before calling this: it should deal with one connection,
Josh Soref730c6742017-02-06 16:14:04 +00001766 blocking as necessary, and then return. Note, need to be a bit careful
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001767 about resources for debug mode, when the fork is suppressed: that's
1768 done by the caller. */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001769unsigned char *tcp_request(int confd, time_t now,
Simon Kelley4f7b3042012-11-28 21:27:02 +00001770 union mysockaddr *local_addr, struct in_addr netmask, int auth_dns)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001771{
Simon Kelley28866e92011-02-14 20:19:14 +00001772 size_t size = 0;
1773 int norebind = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001774#ifdef HAVE_AUTH
Simon Kelley19b16892013-10-20 10:19:39 +01001775 int local_auth = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001776#endif
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001777 int checking_disabled, do_bit, added_pheader = 0, have_pseudoheader = 0;
Simon Kelley25e63f12020-11-25 21:17:52 +00001778 int check_subnet, cacheable, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
Simon Kelleycdeda282006-03-16 20:16:06 +00001779 size_t m;
Simon Kelleyee86ce62012-12-07 11:54:46 +00001780 unsigned short qtype;
1781 unsigned int gotname;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001782 unsigned char c1, c2;
Simon Kelley4b5ea122013-04-22 10:18:26 +01001783 /* Max TCP packet + slop + size */
1784 unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
1785 unsigned char *payload = &packet[2];
1786 /* largest field in header is 16-bits, so this is still sufficiently aligned */
1787 struct dns_header *header = (struct dns_header *)payload;
1788 u16 *length = (u16 *)packet;
Simon Kelley3be34542004-09-11 19:12:13 +01001789 struct server *last_server;
Simon Kelley7de060b2011-08-26 17:24:52 +01001790 struct in_addr dst_addr_4;
1791 union mysockaddr peer_addr;
1792 socklen_t peer_len = sizeof(union mysockaddr);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001793 int query_count = 0;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001794 unsigned char *pheader;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001795 unsigned int mark = 0;
1796 int have_mark = 0;
Simon Kelley25cf5e32015-01-09 15:53:03 +00001797
Simon Kelleyd05dd582016-01-19 21:23:30 +00001798 (void)mark;
1799 (void)have_mark;
1800
Simon Kelley7de060b2011-08-26 17:24:52 +01001801 if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
1802 return packet;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001803
1804#ifdef HAVE_CONNTRACK
1805 /* Get connection mark of incoming query to set on outgoing connections. */
1806 if (option_bool(OPT_CONNTRACK))
1807 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001808 union all_addr local;
Simon Kelleyee875042018-10-23 22:10:17 +01001809
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001810 if (local_addr->sa.sa_family == AF_INET6)
Simon Kelleycc921df2019-01-02 22:48:59 +00001811 local.addr6 = local_addr->in6.sin6_addr;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001812 else
Simon Kelleycc921df2019-01-02 22:48:59 +00001813 local.addr4 = local_addr->in.sin_addr;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001814
1815 have_mark = get_incoming_mark(&peer_addr, &local, 1, &mark);
1816 }
1817#endif
1818
Simon Kelleyc8a80482014-03-05 14:29:54 +00001819 /* We can be configured to only accept queries from at-most-one-hop-away addresses. */
1820 if (option_bool(OPT_LOCAL_SERVICE))
1821 {
1822 struct addrlist *addr;
Simon Kelleyee875042018-10-23 22:10:17 +01001823
Simon Kelleyc8a80482014-03-05 14:29:54 +00001824 if (peer_addr.sa.sa_family == AF_INET6)
1825 {
1826 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1827 if ((addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001828 is_same_net6(&addr->addr.addr6, &peer_addr.in6.sin6_addr, addr->prefixlen))
Simon Kelleyc8a80482014-03-05 14:29:54 +00001829 break;
1830 }
1831 else
Simon Kelleyc8a80482014-03-05 14:29:54 +00001832 {
1833 struct in_addr netmask;
1834 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1835 {
Richard Genoud15b1b7e2014-09-17 21:12:00 +01001836 netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
Simon Kelleyc8a80482014-03-05 14:29:54 +00001837 if (!(addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001838 is_same_net(addr->addr.addr4, peer_addr.in.sin_addr, netmask))
Simon Kelleyc8a80482014-03-05 14:29:54 +00001839 break;
1840 }
1841 }
1842 if (!addr)
1843 {
1844 my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
1845 return packet;
1846 }
1847 }
Simon Kelley7de060b2011-08-26 17:24:52 +01001848
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001849 while (1)
1850 {
Simon Kelley25cf5e32015-01-09 15:53:03 +00001851 if (query_count == TCP_MAX_QUERIES ||
1852 !packet ||
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001853 !read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
1854 !(size = c1 << 8 | c2) ||
Simon Kelley4b5ea122013-04-22 10:18:26 +01001855 !read_write(confd, payload, size, 1))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001856 return packet;
1857
Simon Kelley572b41e2011-02-18 18:11:18 +00001858 if (size < (int)sizeof(struct dns_header))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001859 continue;
Simon Kelley63437ff2017-09-06 22:34:21 +01001860
1861 /* Clear buffer beyond request to avoid risk of
1862 information disclosure. */
1863 memset(payload + size, 0, 65536 - size);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001864
Simon Kelley25cf5e32015-01-09 15:53:03 +00001865 query_count++;
1866
1867 /* log_query gets called indirectly all over the place, so
1868 pass these in global variables - sorry. */
1869 daemon->log_display_id = ++daemon->log_id;
1870 daemon->log_source_addr = &peer_addr;
1871
Simon Kelley28866e92011-02-14 20:19:14 +00001872 /* save state of "cd" flag in query */
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001873 if ((checking_disabled = header->hb4 & HB4_CD))
1874 no_cache_dnssec = 1;
Simon Kelley28866e92011-02-14 20:19:14 +00001875
Simon Kelley3be34542004-09-11 19:12:13 +01001876 if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001877 {
Simon Kelleyb485ed92013-10-18 22:00:39 +01001878#ifdef HAVE_AUTH
1879 struct auth_zone *zone;
1880#endif
Simon Kelley610e7822014-02-06 14:45:17 +00001881 char *types = querystr(auth_dns ? "auth" : "query", qtype);
Simon Kelley7de060b2011-08-26 17:24:52 +01001882
Petr Menšík6c0bf792021-03-18 00:07:45 +01001883 log_query_mysockaddr(F_QUERY | F_FORWARD, daemon->namebuff,
1884 &peer_addr, types);
Simon Kelleyb485ed92013-10-18 22:00:39 +01001885
1886#ifdef HAVE_AUTH
1887 /* find queries for zones we're authoritative for, and answer them directly */
Simon Kelley3a3965a2015-08-09 17:45:06 +01001888 if (!auth_dns && !option_bool(OPT_LOCALISE))
Simon Kelley6008bdb2013-10-21 21:47:03 +01001889 for (zone = daemon->auth_zones; zone; zone = zone->next)
1890 if (in_zone(zone, daemon->namebuff, NULL))
1891 {
1892 auth_dns = 1;
1893 local_auth = 1;
1894 break;
1895 }
Simon Kelleyb485ed92013-10-18 22:00:39 +01001896#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001897 }
1898
Simon Kelley7de060b2011-08-26 17:24:52 +01001899 if (local_addr->sa.sa_family == AF_INET)
1900 dst_addr_4 = local_addr->in.sin_addr;
1901 else
1902 dst_addr_4.s_addr = 0;
1903
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001904 do_bit = 0;
1905
Simon Kelley5bb88f02015-12-21 16:23:47 +00001906 if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL, NULL))
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001907 {
1908 unsigned short flags;
1909
1910 have_pseudoheader = 1;
1911 pheader += 4; /* udp_size, ext_rcode */
1912 GETSHORT(flags, pheader);
1913
1914 if (flags & 0x8000)
Simon Kelley5bb88f02015-12-21 16:23:47 +00001915 do_bit = 1; /* do bit */
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001916 }
1917
Simon Kelley4820dce2012-12-18 18:30:30 +00001918#ifdef HAVE_AUTH
Simon Kelley4f7b3042012-11-28 21:27:02 +00001919 if (auth_dns)
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001920 m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr,
1921 local_auth, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001922 else
Simon Kelley4820dce2012-12-18 18:30:30 +00001923#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001924 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001925 int ad_reqd = do_bit;
1926 /* RFC 6840 5.7 */
1927 if (header->hb4 & HB4_AD)
1928 ad_reqd = 1;
1929
1930 /* m > 0 if answered from cache */
1931 m = answer_request(header, ((char *) header) + 65536, (size_t)size,
1932 dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001933
Simon Kelley4f7b3042012-11-28 21:27:02 +00001934 /* Do this by steam now we're not in the select() loop */
Simon Kelleyb842bc92015-07-12 21:09:11 +01001935 check_log_writer(1);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001936
1937 if (m == 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001938 {
Simon Kelley4f7b3042012-11-28 21:27:02 +00001939 unsigned int flags = 0;
Simon Kelleycc921df2019-01-02 22:48:59 +00001940 union all_addr *addrp = NULL;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001941 int type = SERV_DO_DNSSEC;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001942 char *domain = NULL;
Simon Kelley6fd5d792017-10-13 22:26:40 +01001943 unsigned char *oph = find_pseudoheader(header, size, NULL, NULL, NULL, NULL);
Simon Kelleyed4c0762013-10-08 20:46:34 +01001944
Simon Kelley25e63f12020-11-25 21:17:52 +00001945 size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet, &cacheable);
Simon Kelley6fd5d792017-10-13 22:26:40 +01001946
Simon Kelley4f7b3042012-11-28 21:27:02 +00001947 if (gotname)
1948 flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
Simon Kelley6fd5d792017-10-13 22:26:40 +01001949
1950#ifdef HAVE_DNSSEC
1951 if (option_bool(OPT_DNSSEC_VALID) && (type & SERV_DO_DNSSEC))
1952 {
1953 size = add_do_bit(header, size, ((unsigned char *) header) + 65536);
1954
1955 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
1956 this allows it to select auth servers when one is returning bad data. */
1957 if (option_bool(OPT_DNSSEC_DEBUG))
1958 header->hb4 |= HB4_CD;
1959 }
1960#endif
1961
1962 /* Check if we added a pheader on forwarding - may need to
1963 strip it from the reply. */
1964 if (!oph && find_pseudoheader(header, size, NULL, NULL, NULL, NULL))
1965 added_pheader = 1;
1966
Simon Kelley367341f2016-01-12 15:58:23 +00001967 type &= ~SERV_DO_DNSSEC;
Simon Kelley367341f2016-01-12 15:58:23 +00001968
Simon Kelley4f7b3042012-11-28 21:27:02 +00001969 if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server)
1970 last_server = daemon->servers;
1971 else
1972 last_server = daemon->last_server;
1973
1974 if (!flags && last_server)
1975 {
1976 struct server *firstsendto = NULL;
Simon Kelley2d765862020-11-12 22:06:07 +00001977 unsigned char hash[HASH_SIZE];
1978 memcpy(hash, hash_questions(header, (unsigned int)size, daemon->namebuff), HASH_SIZE);
1979
Simon Kelley4f7b3042012-11-28 21:27:02 +00001980 /* Loop round available servers until we succeed in connecting to one.
Josh Soref730c6742017-02-06 16:14:04 +00001981 Note that this code subtly ensures that consecutive queries on this connection
Simon Kelley4f7b3042012-11-28 21:27:02 +00001982 which can go to the same server, do so. */
1983 while (1)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001984 {
Simon Kelley608aa9f2019-03-10 22:44:15 +00001985 int data_sent = 0;
1986
Simon Kelley4f7b3042012-11-28 21:27:02 +00001987 if (!firstsendto)
1988 firstsendto = last_server;
1989 else
1990 {
1991 if (!(last_server = last_server->next))
1992 last_server = daemon->servers;
1993
1994 if (last_server == firstsendto)
1995 break;
1996 }
1997
1998 /* server for wrong domain */
Petr Menšíke10a9232021-03-15 11:20:49 +01001999 if (!server_test_type(last_server, domain, type, 0))
Simon Kelley7de060b2011-08-26 17:24:52 +01002000 continue;
Simon Kelley361dfe52017-02-10 21:12:30 +00002001
2002 retry:
Simon Kelley608aa9f2019-03-10 22:44:15 +00002003 *length = htons(size);
2004
Simon Kelley4f7b3042012-11-28 21:27:02 +00002005 if (last_server->tcpfd == -1)
2006 {
2007 if ((last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
2008 continue;
2009
Karl Vogele9828b62014-10-03 21:45:15 +01002010#ifdef HAVE_CONNTRACK
2011 /* Copy connection mark of incoming query to outgoing connection. */
Simon Kelleyf344dbc2016-01-18 18:04:17 +00002012 if (have_mark)
2013 setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
Simon Kelley608aa9f2019-03-10 22:44:15 +00002014#endif
Karl Vogele9828b62014-10-03 21:45:15 +01002015
Simon Kelley608aa9f2019-03-10 22:44:15 +00002016 if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 0, 1)))
2017 {
2018 close(last_server->tcpfd);
2019 last_server->tcpfd = -1;
2020 continue;
2021 }
2022
2023#ifdef MSG_FASTOPEN
黎醒聪ffa46282021-03-22 22:00:26 +00002024 server_send(last_server, last_server->tcpfd, packet, size + sizeof(u16), MSG_FASTOPEN);
Petr Menšík51f7bc92021-03-18 01:05:43 +01002025
Simon Kelley608aa9f2019-03-10 22:44:15 +00002026 if (errno == 0)
2027 data_sent = 1;
2028#endif
2029
2030 if (!data_sent && connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1)
Simon Kelley4f7b3042012-11-28 21:27:02 +00002031 {
2032 close(last_server->tcpfd);
2033 last_server->tcpfd = -1;
2034 continue;
2035 }
2036
Simon Kelley361dfe52017-02-10 21:12:30 +00002037 last_server->flags &= ~SERV_GOT_TCP;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002038 }
2039
Simon Kelley1fc02682014-04-29 12:30:18 +01002040 /* get query name again for logging - may have been overwritten */
2041 if (!(gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
2042 strcpy(daemon->namebuff, "query");
Simon Kelley4f7b3042012-11-28 21:27:02 +00002043
Simon Kelley608aa9f2019-03-10 22:44:15 +00002044 if ((!data_sent && !read_write(last_server->tcpfd, packet, size + sizeof(u16), 0)) ||
Simon Kelley4f7b3042012-11-28 21:27:02 +00002045 !read_write(last_server->tcpfd, &c1, 1, 1) ||
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002046 !read_write(last_server->tcpfd, &c2, 1, 1) ||
2047 !read_write(last_server->tcpfd, payload, (c1 << 8) | c2, 1))
Simon Kelley7de060b2011-08-26 17:24:52 +01002048 {
2049 close(last_server->tcpfd);
2050 last_server->tcpfd = -1;
Simon Kelley361dfe52017-02-10 21:12:30 +00002051 /* We get data then EOF, reopen connection to same server,
2052 else try next. This avoids DoS from a server which accepts
2053 connections and then closes them. */
2054 if (last_server->flags & SERV_GOT_TCP)
2055 goto retry;
2056 else
2057 continue;
2058 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00002059
Simon Kelley361dfe52017-02-10 21:12:30 +00002060 last_server->flags |= SERV_GOT_TCP;
2061
Simon Kelley4f7b3042012-11-28 21:27:02 +00002062 m = (c1 << 8) | c2;
Petr Menšík6c0bf792021-03-18 00:07:45 +01002063
2064 log_query_mysockaddr(F_SERVER | F_FORWARD, daemon->namebuff,
2065 &last_server->addr, NULL);
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002066
2067#ifdef HAVE_DNSSEC
Simon Kelley367341f2016-01-12 15:58:23 +00002068 if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled && (last_server->flags & SERV_DO_DNSSEC))
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002069 {
Simon Kelley7fa836e2014-02-10 20:11:24 +00002070 int keycount = DNSSEC_WORK; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
Simon Kelleyf344dbc2016-01-18 18:04:17 +00002071 int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname,
2072 last_server, have_mark, mark, &keycount);
Simon Kelley554b5802015-04-17 22:50:20 +01002073 char *result, *domain = "result";
Simon Kelleyfe3992f2015-04-03 21:25:05 +01002074
Simon Kelley9a31b682015-12-15 10:20:39 +00002075 if (status == STAT_ABANDONED)
Simon Kelley150162b2015-03-27 09:58:26 +00002076 {
2077 result = "ABANDONED";
2078 status = STAT_BOGUS;
2079 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00002080 else
2081 result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
Simon Kelleye66b4df2015-04-28 20:45:57 +01002082
2083 if (status == STAT_BOGUS && extract_request(header, m, daemon->namebuff, NULL))
2084 domain = daemon->namebuff;
Simon Kelley554b5802015-04-17 22:50:20 +01002085
Simon Kelley07ed5852018-05-04 21:52:22 +01002086 log_query(F_SECSTAT, domain, NULL, result);
Simon Kelley7fa836e2014-02-10 20:11:24 +00002087
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002088 if (status == STAT_BOGUS)
Simon Kelleyfe3992f2015-04-03 21:25:05 +01002089 {
2090 no_cache_dnssec = 1;
2091 bogusanswer = 1;
2092 }
2093
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002094 if (status == STAT_SECURE)
2095 cache_secure = 1;
2096 }
2097#endif
2098
2099 /* restore CD bit to the value in the query */
2100 if (checking_disabled)
2101 header->hb4 |= HB4_CD;
2102 else
2103 header->hb4 &= ~HB4_CD;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002104
2105 /* There's no point in updating the cache, since this process will exit and
2106 lose the information after a few queries. We make this call for the alias and
2107 bogus-nxdomain side-effects. */
2108 /* If the crc of the question section doesn't match the crc we sent, then
2109 someone might be attempting to insert bogus values into the cache by
2110 sending replies containing questions and bogus answers. */
Simon Kelley2d765862020-11-12 22:06:07 +00002111 if (memcmp(hash, hash_questions(header, (unsigned int)m, daemon->namebuff), HASH_SIZE) != 0)
Simon Kelley703c7ff2014-01-25 23:46:23 +00002112 {
2113 m = 0;
2114 break;
2115 }
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002116
Simon Kelley25e63f12020-11-25 21:17:52 +00002117 /* Never cache answers which are contingent on the source or MAC address EDSN0 option,
2118 since the cache is ignorant of such things. */
2119 if (!cacheable)
2120 no_cache_dnssec = 1;
2121
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002122 m = process_reply(header, now, last_server, (unsigned int)m,
Simon Kelleye66b4df2015-04-28 20:45:57 +01002123 option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
Simon Kelleyfa14bec2015-12-20 17:12:16 +00002124 ad_reqd, do_bit, added_pheader, check_subnet, &peer_addr);
Simon Kelley4f7b3042012-11-28 21:27:02 +00002125
2126 break;
2127 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002128 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00002129
2130 /* In case of local answer or no connections made. */
2131 if (m == 0)
Simon Kelley1682d152018-08-03 20:38:18 +01002132 {
2133 m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl);
2134 if (have_pseudoheader)
2135 m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
2136 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002137 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002138 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00002139
Simon Kelleyb842bc92015-07-12 21:09:11 +01002140 check_log_writer(1);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002141
Simon Kelley4b5ea122013-04-22 10:18:26 +01002142 *length = htons(m);
2143
2144 if (m == 0 || !read_write(confd, packet, m + sizeof(u16), 0))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002145 return packet;
2146 }
2147}
2148
Simon Kelley16972692006-10-16 20:04:18 +01002149static struct frec *allocate_frec(time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002150{
Simon Kelley16972692006-10-16 20:04:18 +01002151 struct frec *f;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002152
Simon Kelley5aabfc72007-08-29 11:24:47 +01002153 if ((f = (struct frec *)whine_malloc(sizeof(struct frec))))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002154 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01002155 f->next = daemon->frec_list;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002156 f->time = now;
Simon Kelley832af0b2007-01-21 20:01:28 +00002157 f->sentto = NULL;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002158 f->rfds = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +00002159 f->flags = 0;
Simon Kelley3a237152013-12-12 12:15:50 +00002160#ifdef HAVE_DNSSEC
Simon Kelley97bc7982014-01-31 10:19:52 +00002161 f->dependent = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002162 f->blocking_query = NULL;
Simon Kelley4619d942014-01-16 19:53:06 +00002163 f->stash = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002164#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +01002165 daemon->frec_list = f;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002166 }
Simon Kelley16972692006-10-16 20:04:18 +01002167
2168 return f;
2169}
2170
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002171/* return a UDP socket bound to a random port, have to cope with straying into
2172 occupied port nos and reserved ones. */
2173static int random_sock(struct server *s)
2174{
2175 int fd;
2176
2177 if ((fd = socket(s->source_addr.sa.sa_family, SOCK_DGRAM, 0)) != -1)
2178 {
2179 if (local_bind(fd, &s->source_addr, s->interface, s->ifindex, 0))
2180 return fd;
2181
2182 if (s->interface[0] == 0)
2183 (void)prettyprint_addr(&s->source_addr, daemon->namebuff);
2184 else
2185 strcpy(daemon->namebuff, s->interface);
2186
2187 my_syslog(LOG_ERR, _("failed to bind server socket to %s: %s"),
2188 daemon->namebuff, strerror(errno));
2189 close(fd);
2190 }
2191
2192 return -1;
2193}
2194
2195/* compare source addresses and interface, serv2 can be null. */
2196static int server_isequal(const struct server *serv1,
2197 const struct server *serv2)
2198{
2199 return (serv2 &&
2200 serv2->ifindex == serv1->ifindex &&
2201 sockaddr_isequal(&serv2->source_addr, &serv1->source_addr) &&
2202 strncmp(serv2->interface, serv1->interface, IF_NAMESIZE) == 0);
2203}
2204
2205/* fdlp points to chain of randomfds already in use by transaction.
2206 If there's already a suitable one, return it, else allocate a
2207 new one and add it to the list.
2208
2209 Not leaking any resources in the face of allocation failures
2210 is rather convoluted here.
2211
2212 Note that rfd->serv may be NULL, when a server goes away.
2213*/
2214int allocate_rfd(struct randfd_list **fdlp, struct server *serv)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002215{
2216 static int finger = 0;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002217 int i, j = 0;
2218 struct randfd_list *rfl;
2219 struct randfd *rfd = NULL;
2220 int fd = 0;
2221
2222 /* If server has a pre-allocated fd, use that. */
2223 if (serv->sfd)
2224 return serv->sfd->fd;
2225
2226 /* existing suitable random port socket linked to this transaction? */
2227 for (rfl = *fdlp; rfl; rfl = rfl->next)
2228 if (server_isequal(serv, rfl->rfd->serv))
2229 return rfl->rfd->fd;
Simon Kelley1a6bca82008-07-11 11:11:42 +01002230
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002231 /* No. need new link. */
2232 if ((rfl = daemon->rfl_spare))
2233 daemon->rfl_spare = rfl->next;
2234 else if (!(rfl = whine_malloc(sizeof(struct randfd_list))))
2235 return -1;
2236
Simon Kelley1a6bca82008-07-11 11:11:42 +01002237 /* limit the number of sockets we have open to avoid starvation of
2238 (eg) TFTP. Once we have a reasonable number, randomness should be OK */
Simon Kelleyea28d0e2021-03-26 22:02:04 +00002239 for (i = 0; i < daemon->numrrand; i++)
Simon Kelley9009d742008-11-14 20:04:27 +00002240 if (daemon->randomsocks[i].refcount == 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002241 {
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002242 if ((fd = random_sock(serv)) != -1)
2243 {
2244 rfd = &daemon->randomsocks[i];
2245 rfd->serv = serv;
2246 rfd->fd = fd;
2247 rfd->refcount = 1;
2248 }
2249 break;
2250 }
2251
2252 /* No free ones or cannot get new socket, grab an existing one */
2253 if (!rfd)
Simon Kelleyea28d0e2021-03-26 22:02:04 +00002254 for (j = 0; j < daemon->numrrand; j++)
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002255 {
Simon Kelleyea28d0e2021-03-26 22:02:04 +00002256 i = (j + finger) % daemon->numrrand;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002257 if (daemon->randomsocks[i].refcount != 0 &&
2258 server_isequal(serv, daemon->randomsocks[i].serv) &&
2259 daemon->randomsocks[i].refcount != 0xfffe)
2260 {
2261 finger = i + 1;
2262 rfd = &daemon->randomsocks[i];
2263 rfd->refcount++;
2264 break;
2265 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01002266 }
2267
Simon Kelleyea28d0e2021-03-26 22:02:04 +00002268 if (j == daemon->numrrand)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002269 {
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002270 struct randfd_list *rfl_poll;
Simon Kelley1a6bca82008-07-11 11:11:42 +01002271
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002272 /* there are no free slots, and non with the same parameters we can piggy-back on.
2273 We're going to have to allocate a new temporary record, distinguished by
2274 refcount == 0xffff. This will exist in the frec randfd list, never be shared,
2275 and be freed when no longer in use. It will also be held on
2276 the daemon->rfl_poll list so the poll system can find it. */
2277
2278 if ((rfl_poll = daemon->rfl_spare))
2279 daemon->rfl_spare = rfl_poll->next;
2280 else
2281 rfl_poll = whine_malloc(sizeof(struct randfd_list));
2282
2283 if (!rfl_poll ||
2284 !(rfd = whine_malloc(sizeof(struct randfd))) ||
2285 (fd = random_sock(serv)) == -1)
2286 {
2287
2288 /* Don't leak anything we may already have */
2289 rfl->next = daemon->rfl_spare;
2290 daemon->rfl_spare = rfl;
2291
2292 if (rfl_poll)
2293 {
2294 rfl_poll->next = daemon->rfl_spare;
2295 daemon->rfl_spare = rfl_poll;
2296 }
2297
2298 if (rfd)
2299 free(rfd);
2300
2301 return -1; /* doom */
2302 }
2303
2304 /* Note rfd->serv not set here, since it's not reused */
2305 rfd->fd = fd;
2306 rfd->refcount = 0xffff; /* marker for temp record */
2307
2308 rfl_poll->rfd = rfd;
2309 rfl_poll->next = daemon->rfl_poll;
2310 daemon->rfl_poll = rfl_poll;
2311 }
2312
2313 rfl->rfd = rfd;
2314 rfl->next = *fdlp;
2315 *fdlp = rfl;
2316
2317 return rfl->rfd->fd;
Simon Kelley1a6bca82008-07-11 11:11:42 +01002318}
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002319
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002320void free_rfds(struct randfd_list **fdlp)
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002321{
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002322 struct randfd_list *tmp, *rfl, *poll, *next, **up;
2323
2324 for (rfl = *fdlp; rfl; rfl = tmp)
2325 {
2326 if (rfl->rfd->refcount == 0xffff || --(rfl->rfd->refcount) == 0)
2327 close(rfl->rfd->fd);
2328
2329 /* temporary overflow record */
2330 if (rfl->rfd->refcount == 0xffff)
2331 {
2332 free(rfl->rfd);
2333
2334 /* go through the link of all these by steam to delete.
2335 This list is expected to be almost always empty. */
2336 for (poll = daemon->rfl_poll, up = &daemon->rfl_poll; poll; poll = next)
2337 {
2338 next = poll->next;
2339
2340 if (poll->rfd == rfl->rfd)
2341 {
2342 *up = poll->next;
2343 poll->next = daemon->rfl_spare;
2344 daemon->rfl_spare = poll;
2345 }
2346 else
2347 up = &poll->next;
2348 }
2349 }
2350
2351 tmp = rfl->next;
2352 rfl->next = daemon->rfl_spare;
2353 daemon->rfl_spare = rfl;
2354 }
2355
2356 *fdlp = NULL;
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002357}
2358
Simon Kelley1a6bca82008-07-11 11:11:42 +01002359static void free_frec(struct frec *f)
2360{
Simon Kelley6a6e06f2020-12-04 18:35:11 +00002361 struct frec_src *last;
Simon Kelley15b60dd2020-11-18 18:34:55 +00002362
Simon Kelley6a6e06f2020-12-04 18:35:11 +00002363 /* add back to freelist if not the record builtin to every frec. */
2364 for (last = f->frec_src.next; last && last->next; last = last->next) ;
2365 if (last)
2366 {
2367 last->next = daemon->free_frec_src;
2368 daemon->free_frec_src = f->frec_src.next;
2369 }
2370
Simon Kelley15b60dd2020-11-18 18:34:55 +00002371 f->frec_src.next = NULL;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002372 free_rfds(&f->rfds);
Simon Kelley1a6bca82008-07-11 11:11:42 +01002373 f->sentto = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +00002374 f->flags = 0;
Simon Kelley3a237152013-12-12 12:15:50 +00002375
2376#ifdef HAVE_DNSSEC
2377 if (f->stash)
Simon Kelley0fc2f312014-01-08 10:26:58 +00002378 {
2379 blockdata_free(f->stash);
2380 f->stash = NULL;
2381 }
Simon Kelley3a237152013-12-12 12:15:50 +00002382
2383 /* Anything we're waiting on is pointless now, too */
2384 if (f->blocking_query)
2385 free_frec(f->blocking_query);
2386 f->blocking_query = NULL;
Simon Kelley39048ad2014-01-21 17:33:58 +00002387 f->dependent = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002388#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +01002389}
2390
Simon Kelley09f3b2c2017-05-09 01:34:02 +01002391
2392
Simon Kelley16972692006-10-16 20:04:18 +01002393/* if wait==NULL return a free or older than TIMEOUT record.
2394 else return *wait zero if one available, or *wait is delay to
Simon Kelley1a6bca82008-07-11 11:11:42 +01002395 when the oldest in-use record will expire. Impose an absolute
Simon Kelley3a237152013-12-12 12:15:50 +00002396 limit of 4*TIMEOUT before we wipe things (for random sockets).
Simon Kelley8caf3d72020-04-04 17:00:32 +01002397 If force is non-NULL, always return a result, even if we have
2398 to allocate above the limit, and never free the record pointed
2399 to by the force argument. */
2400struct frec *get_new_frec(time_t now, int *wait, struct frec *force)
Simon Kelley16972692006-10-16 20:04:18 +01002401{
Simon Kelley1a6bca82008-07-11 11:11:42 +01002402 struct frec *f, *oldest, *target;
Simon Kelley16972692006-10-16 20:04:18 +01002403 int count;
2404
2405 if (wait)
2406 *wait = 0;
2407
Simon Kelley1a6bca82008-07-11 11:11:42 +01002408 for (f = daemon->frec_list, oldest = NULL, target = NULL, count = 0; f; f = f->next, count++)
Simon Kelley832af0b2007-01-21 20:01:28 +00002409 if (!f->sentto)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002410 target = f;
2411 else
Simon Kelley16972692006-10-16 20:04:18 +01002412 {
Simon Kelley9a31b682015-12-15 10:20:39 +00002413#ifdef HAVE_DNSSEC
2414 /* Don't free DNSSEC sub-queries here, as we may end up with
2415 dangling references to them. They'll go when their "real" query
2416 is freed. */
Simon Kelley8caf3d72020-04-04 17:00:32 +01002417 if (!f->dependent && f != force)
Simon Kelley9a31b682015-12-15 10:20:39 +00002418#endif
2419 {
2420 if (difftime(now, f->time) >= 4*TIMEOUT)
2421 {
2422 free_frec(f);
2423 target = f;
2424 }
2425
2426
2427 if (!oldest || difftime(f->time, oldest->time) <= 0)
2428 oldest = f;
2429 }
Simon Kelley16972692006-10-16 20:04:18 +01002430 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01002431
2432 if (target)
2433 {
2434 target->time = now;
2435 return target;
2436 }
Simon Kelley16972692006-10-16 20:04:18 +01002437
2438 /* can't find empty one, use oldest if there is one
2439 and it's older than timeout */
Simon Kelley09f3b2c2017-05-09 01:34:02 +01002440 if (!force && oldest && ((int)difftime(now, oldest->time)) >= TIMEOUT)
Simon Kelley16972692006-10-16 20:04:18 +01002441 {
2442 /* keep stuff for twice timeout if we can by allocating a new
2443 record instead */
2444 if (difftime(now, oldest->time) < 2*TIMEOUT &&
2445 count <= daemon->ftabsize &&
2446 (f = allocate_frec(now)))
2447 return f;
2448
2449 if (!wait)
2450 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01002451 free_frec(oldest);
Simon Kelley16972692006-10-16 20:04:18 +01002452 oldest->time = now;
2453 }
2454 return oldest;
2455 }
2456
2457 /* none available, calculate time 'till oldest record expires */
Simon Kelley3a237152013-12-12 12:15:50 +00002458 if (!force && count > daemon->ftabsize)
Simon Kelley16972692006-10-16 20:04:18 +01002459 {
2460 if (oldest && wait)
2461 *wait = oldest->time + (time_t)TIMEOUT - now;
Marcelo Salhab Brogliato0da5e892013-05-31 11:49:06 +01002462
Simon Kelleyf61afcf2021-04-07 20:54:36 +01002463 query_full(now);
2464
Simon Kelley16972692006-10-16 20:04:18 +01002465 return NULL;
2466 }
2467
2468 if (!(f = allocate_frec(now)) && wait)
2469 /* wait one second on malloc failure */
2470 *wait = 1;
2471
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002472 return f; /* OK if malloc fails and this is NULL */
2473}
Simon Kelley09f3b2c2017-05-09 01:34:02 +01002474
Simon Kelleyf61afcf2021-04-07 20:54:36 +01002475static void query_full(time_t now)
2476{
2477 static time_t last_log = 0;
2478
2479 if ((int)difftime(now, last_log) > 5)
2480 {
2481 last_log = now;
2482 my_syslog(LOG_WARNING, _("Maximum number of concurrent DNS queries reached (max: %d)"), daemon->ftabsize);
2483 }
2484}
2485
2486
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002487static struct frec *lookup_frec(unsigned short id, int fd, void *hash)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002488{
2489 struct frec *f;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002490 struct server *s;
2491 int type;
2492 struct randfd_list *fdl;
2493
Simon Kelley1a6bca82008-07-11 11:11:42 +01002494 for(f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00002495 if (f->sentto && f->new_id == id &&
Simon Kelley2d765862020-11-12 22:06:07 +00002496 (memcmp(hash, f->hash, HASH_SIZE) == 0))
Simon Kelley257ac0c2020-11-12 18:49:23 +00002497 {
2498 /* sent from random port */
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002499 for (fdl = f->rfds; fdl; fdl = fdl->next)
2500 if (fdl->rfd->fd == fd)
Simon Kelley257ac0c2020-11-12 18:49:23 +00002501 return f;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002502
2503 /* Sent to upstream from socket associated with a server.
2504 Note we have to iterate over all the possible servers, since they may
2505 have different bound sockets. */
2506 type = f->sentto->flags & SERV_TYPE;
2507 s = f->sentto;
2508 do {
Petr Menšík8f9bd612021-03-27 23:16:09 +00002509 if (server_test_type(s, f->sentto->domain, type, 0) &&
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002510 s->sfd && s->sfd->fd == fd)
2511 return f;
2512
2513 s = s->next ? s->next : daemon->servers;
2514 } while (s != f->sentto);
Simon Kelley257ac0c2020-11-12 18:49:23 +00002515 }
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002516
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002517 return NULL;
2518}
2519
Simon Kelley15b60dd2020-11-18 18:34:55 +00002520static struct frec *lookup_frec_by_query(void *hash, unsigned int flags)
2521{
2522 struct frec *f;
2523
2524 /* FREC_DNSKEY and FREC_DS_QUERY are never set in flags, so the test below
Simon Kelley25e63f12020-11-25 21:17:52 +00002525 ensures that no frec created for internal DNSSEC query can be returned here.
2526
2527 Similarly FREC_NO_CACHE is never set in flags, so a query which is
2528 contigent on a particular source address EDNS0 option will never be matched. */
Simon Kelley15b60dd2020-11-18 18:34:55 +00002529
2530#define FLAGMASK (FREC_CHECKING_DISABLED | FREC_AD_QUESTION | FREC_DO_QUESTION \
Simon Kelley25e63f12020-11-25 21:17:52 +00002531 | FREC_HAS_PHEADER | FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_NO_CACHE)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002532
Simon Kelley1a6bca82008-07-11 11:11:42 +01002533 for(f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00002534 if (f->sentto &&
Simon Kelley15b60dd2020-11-18 18:34:55 +00002535 (f->flags & FLAGMASK) == flags &&
2536 memcmp(hash, f->hash, HASH_SIZE) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002537 return f;
Simon Kelley15b60dd2020-11-18 18:34:55 +00002538
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002539 return NULL;
2540}
Simon Kelley15b60dd2020-11-18 18:34:55 +00002541
Simon Kelley47a95162014-07-08 22:22:02 +01002542/* Send query packet again, if we can. */
2543void resend_query()
2544{
2545 if (daemon->srv_save)
Petr Menšík51f7bc92021-03-18 01:05:43 +01002546 server_send(daemon->srv_save, daemon->fd_save,
2547 daemon->packet, daemon->packet_len, 0);
Simon Kelley47a95162014-07-08 22:22:02 +01002548}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002549
Simon Kelley849a8352006-06-09 21:02:31 +01002550/* A server record is going away, remove references to it */
Simon Kelley5aabfc72007-08-29 11:24:47 +01002551void server_gone(struct server *server)
Simon Kelley849a8352006-06-09 21:02:31 +01002552{
2553 struct frec *f;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002554 int i;
Simon Kelley849a8352006-06-09 21:02:31 +01002555
Simon Kelley1a6bca82008-07-11 11:11:42 +01002556 for (f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00002557 if (f->sentto && f->sentto == server)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002558 free_frec(f);
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002559
2560 /* If any random socket refers to this server, NULL the reference.
2561 No more references to the socket will be created in the future. */
Simon Kelleyea28d0e2021-03-26 22:02:04 +00002562 for (i = 0; i < daemon->numrrand; i++)
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002563 if (daemon->randomsocks[i].refcount != 0 && daemon->randomsocks[i].serv == server)
2564 daemon->randomsocks[i].serv = NULL;
Simon Kelley849a8352006-06-09 21:02:31 +01002565
2566 if (daemon->last_server == server)
2567 daemon->last_server = NULL;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002568
Simon Kelley849a8352006-06-09 21:02:31 +01002569 if (daemon->srv_save == server)
2570 daemon->srv_save = NULL;
2571}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002572
Simon Kelley316e2732010-01-22 20:16:09 +00002573/* return unique random ids. */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002574static unsigned short get_id(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002575{
2576 unsigned short ret = 0;
Simon Kelley257ac0c2020-11-12 18:49:23 +00002577 struct frec *f;
Simon Kelley832af0b2007-01-21 20:01:28 +00002578
Simon Kelley257ac0c2020-11-12 18:49:23 +00002579 while (1)
2580 {
2581 ret = rand16();
2582
2583 /* ensure id is unique. */
2584 for (f = daemon->frec_list; f; f = f->next)
2585 if (f->sentto && f->new_id == ret)
2586 break;
2587
2588 if (!f)
2589 return ret;
2590 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002591}
2592
2593
2594
2595
2596