blob: 2d13de5d1068185ec3ba101bd14ae6d280ca7294 [file] [log] [blame]
Simon Kelleyc8e8f5c2021-01-24 21:59:37 +00001/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
Simon Kelley824af852008-02-12 20:43:05 +00005 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
Simon Kelley9e4abcb2004-01-22 19:47:41 +00008 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
Simon Kelley824af852008-02-12 20:43:05 +000012
Simon Kelley73a08a22009-02-05 20:28:08 +000013 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
Simon Kelley9e4abcb2004-01-22 19:47:41 +000015*/
16
Simon Kelley9e4abcb2004-01-22 19:47:41 +000017#include "dnsmasq.h"
18
Simon Kelley74d4fcd2021-03-15 21:59:51 +000019static struct frec *lookup_frec(unsigned short id, int fd, void *hash);
Simon Kelley15b60dd2020-11-18 18:34:55 +000020static struct frec *lookup_frec_by_query(void *hash, unsigned int flags);
21
Simon Kelley8a9be9e2014-01-25 23:17:21 +000022static unsigned short get_id(void);
Simon Kelley1a6bca82008-07-11 11:11:42 +010023static void free_frec(struct frec *f);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000024
Simon Kelley824af852008-02-12 20:43:05 +000025/* Send a UDP packet with its source address set as "source"
Simon Kelley44a2a312004-03-10 20:04:35 +000026 unless nowild is true, when we just send it with the kernel default */
Simon Kelley29689cf2012-03-22 14:01:00 +000027int send_from(int fd, int nowild, char *packet, size_t len,
Simon Kelleycc921df2019-01-02 22:48:59 +000028 union mysockaddr *to, union all_addr *source,
Simon Kelley50303b12012-04-04 22:13:17 +010029 unsigned int iface)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000030{
Simon Kelley44a2a312004-03-10 20:04:35 +000031 struct msghdr msg;
32 struct iovec iov[1];
Simon Kelley44a2a312004-03-10 20:04:35 +000033 union {
34 struct cmsghdr align; /* this ensures alignment */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010035#if defined(HAVE_LINUX_NETWORK)
Simon Kelley44a2a312004-03-10 20:04:35 +000036 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
37#elif defined(IP_SENDSRCADDR)
38 char control[CMSG_SPACE(sizeof(struct in_addr))];
39#endif
Simon Kelley44a2a312004-03-10 20:04:35 +000040 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
Simon Kelley44a2a312004-03-10 20:04:35 +000041 } control_u;
Simon Kelleyfeba5c12004-07-27 20:28:58 +010042
Simon Kelley44a2a312004-03-10 20:04:35 +000043 iov[0].iov_base = packet;
44 iov[0].iov_len = len;
45
Simon Kelleyfeba5c12004-07-27 20:28:58 +010046 msg.msg_control = NULL;
47 msg.msg_controllen = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +000048 msg.msg_flags = 0;
49 msg.msg_name = to;
50 msg.msg_namelen = sa_len(to);
51 msg.msg_iov = iov;
52 msg.msg_iovlen = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +010053
Simon Kelley26128d22004-11-14 16:43:54 +000054 if (!nowild)
Simon Kelleyfeba5c12004-07-27 20:28:58 +010055 {
Simon Kelley26128d22004-11-14 16:43:54 +000056 struct cmsghdr *cmptr;
Simon Kelleyfeba5c12004-07-27 20:28:58 +010057 msg.msg_control = &control_u;
58 msg.msg_controllen = sizeof(control_u);
Simon Kelley26128d22004-11-14 16:43:54 +000059 cmptr = CMSG_FIRSTHDR(&msg);
Simon Kelley44a2a312004-03-10 20:04:35 +000060
Simon Kelley26128d22004-11-14 16:43:54 +000061 if (to->sa.sa_family == AF_INET)
62 {
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010063#if defined(HAVE_LINUX_NETWORK)
Simon Kelley8ef5ada2010-06-03 19:42:45 +010064 struct in_pktinfo p;
65 p.ipi_ifindex = 0;
Simon Kelleycc921df2019-01-02 22:48:59 +000066 p.ipi_spec_dst = source->addr4;
Jérémie Courrèges-Anglasc6cc4552019-03-22 10:56:13 +010067 msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
Simon Kelley8ef5ada2010-06-03 19:42:45 +010068 memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
Jérémie Courrèges-Anglasc6cc4552019-03-22 10:56:13 +010069 cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
Simon Kelleyc72daea2012-01-05 21:33:27 +000070 cmptr->cmsg_level = IPPROTO_IP;
Simon Kelley26128d22004-11-14 16:43:54 +000071 cmptr->cmsg_type = IP_PKTINFO;
72#elif defined(IP_SENDSRCADDR)
Jérémie Courrèges-Anglasc6cc4552019-03-22 10:56:13 +010073 msg.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
Simon Kelleycc921df2019-01-02 22:48:59 +000074 memcpy(CMSG_DATA(cmptr), &(source->addr4), sizeof(source->addr4));
Jérémie Courrèges-Anglasc6cc4552019-03-22 10:56:13 +010075 cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
Simon Kelley26128d22004-11-14 16:43:54 +000076 cmptr->cmsg_level = IPPROTO_IP;
77 cmptr->cmsg_type = IP_SENDSRCADDR;
Simon Kelley44a2a312004-03-10 20:04:35 +000078#endif
Simon Kelley26128d22004-11-14 16:43:54 +000079 }
Simon Kelley26128d22004-11-14 16:43:54 +000080 else
81 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +010082 struct in6_pktinfo p;
83 p.ipi6_ifindex = iface; /* Need iface for IPv6 to handle link-local addrs */
Simon Kelleycc921df2019-01-02 22:48:59 +000084 p.ipi6_addr = source->addr6;
Jérémie Courrèges-Anglasc6cc4552019-03-22 10:56:13 +010085 msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
Simon Kelley8ef5ada2010-06-03 19:42:45 +010086 memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
Jérémie Courrèges-Anglasc6cc4552019-03-22 10:56:13 +010087 cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
Simon Kelley316e2732010-01-22 20:16:09 +000088 cmptr->cmsg_type = daemon->v6pktinfo;
Simon Kelleyc72daea2012-01-05 21:33:27 +000089 cmptr->cmsg_level = IPPROTO_IPV6;
Simon Kelley26128d22004-11-14 16:43:54 +000090 }
Simon Kelley26128d22004-11-14 16:43:54 +000091 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +010092
Simon Kelleyff841eb2015-03-11 21:36:30 +000093 while (retry_send(sendmsg(fd, &msg, 0)));
94
Brad Smithea3c60a2020-03-08 14:53:59 +000095 if (errno != 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +010096 {
Brad Smithea3c60a2020-03-08 14:53:59 +000097#ifdef HAVE_LINUX_NETWORK
98 /* If interface is still in DAD, EINVAL results - ignore that. */
99 if (errno != EINVAL)
100 my_syslog(LOG_ERR, _("failed to send packet: %s"), strerror(errno));
101#endif
Simon Kelley29689cf2012-03-22 14:01:00 +0000102 return 0;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100103 }
Simon Kelley29d28dd2012-12-03 14:05:59 +0000104
Simon Kelley29689cf2012-03-22 14:01:00 +0000105 return 1;
Simon Kelley44a2a312004-03-10 20:04:35 +0000106}
107
Simon Kelleycc921df2019-01-02 22:48:59 +0000108static unsigned int search_servers(time_t now, union all_addr **addrpp, unsigned int qtype,
Simon Kelley367341f2016-01-12 15:58:23 +0000109 char *qdomain, int *type, char **domain, int *norebind)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100110
111{
112 /* If the query ends in the domain in one of our servers, set
113 domain to point to that name. We find the largest match to allow both
114 domain.org and sub.domain.org to exist. */
115
116 unsigned int namelen = strlen(qdomain);
117 unsigned int matchlen = 0;
118 struct server *serv;
Simon Kelley28866e92011-02-14 20:19:14 +0000119 unsigned int flags = 0;
Simon Kelleycc921df2019-01-02 22:48:59 +0000120 static union all_addr zero;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100121
Simon Kelley3be34542004-09-11 19:12:13 +0100122 for (serv = daemon->servers; serv; serv=serv->next)
Simon Kelley09f3b2c2017-05-09 01:34:02 +0100123 if (qtype == F_DNSSECOK && !(serv->flags & SERV_DO_DNSSEC))
124 continue;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100125 /* domain matches take priority over NODOTS matches */
Simon Kelley09f3b2c2017-05-09 01:34:02 +0100126 else if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.') && namelen != 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100127 {
Simon Kelley28866e92011-02-14 20:19:14 +0000128 unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100129 *type = SERV_FOR_NODOTS;
Sung Paea914d0a2019-12-30 17:07:37 -0600130 if ((serv->flags & SERV_NO_REBIND) && norebind)
131 *norebind = 1;
132 else if (serv->flags & SERV_NO_ADDR)
Simon Kelley36717ee2004-09-20 19:20:58 +0100133 flags = F_NXDOMAIN;
Simon Kelleyda8b6512018-09-03 23:18:36 +0100134 else if (serv->flags & SERV_LITERAL_ADDRESS)
Simon Kelley36717ee2004-09-20 19:20:58 +0100135 {
Simon Kelleyda8b6512018-09-03 23:18:36 +0100136 /* literal address = '#' -> return all-zero address for IPv4 and IPv6 */
137 if ((serv->flags & SERV_USE_RESOLV) && (qtype & (F_IPV6 | F_IPV4)))
138 {
139 memset(&zero, 0, sizeof(zero));
140 flags = qtype;
141 *addrpp = &zero;
142 }
143 else if (sflag & qtype)
Simon Kelley36717ee2004-09-20 19:20:58 +0100144 {
145 flags = sflag;
146 if (serv->addr.sa.sa_family == AF_INET)
Simon Kelleycc921df2019-01-02 22:48:59 +0000147 *addrpp = (union all_addr *)&serv->addr.in.sin_addr;
Simon Kelley36717ee2004-09-20 19:20:58 +0100148 else
Simon Kelleycc921df2019-01-02 22:48:59 +0000149 *addrpp = (union all_addr *)&serv->addr.in6.sin6_addr;
Simon Kelley36717ee2004-09-20 19:20:58 +0100150 }
Simon Kelley824af852008-02-12 20:43:05 +0000151 else if (!flags || (flags & F_NXDOMAIN))
Simon Kelley36717ee2004-09-20 19:20:58 +0100152 flags = F_NOERR;
153 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100154 }
155 else if (serv->flags & SERV_HAS_DOMAIN)
156 {
157 unsigned int domainlen = strlen(serv->domain);
Simon Kelleyb8187c82005-11-26 21:46:27 +0000158 char *matchstart = qdomain + namelen - domainlen;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100159 if (namelen >= domainlen &&
Simon Kelleyb8187c82005-11-26 21:46:27 +0000160 hostname_isequal(matchstart, serv->domain) &&
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100161 (domainlen == 0 || namelen == domainlen || *(matchstart-1) == '.' ))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100162 {
Simon Kelley92be34a2016-01-16 18:39:54 +0000163 if ((serv->flags & SERV_NO_REBIND) && norebind)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100164 *norebind = 1;
Simon Kelley28866e92011-02-14 20:19:14 +0000165 else
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100166 {
Simon Kelley28866e92011-02-14 20:19:14 +0000167 unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
168 /* implement priority rules for --address and --server for same domain.
169 --address wins if the address is for the correct AF
170 --server wins otherwise. */
171 if (domainlen != 0 && domainlen == matchlen)
Simon Kelley36717ee2004-09-20 19:20:58 +0100172 {
Simon Kelley28866e92011-02-14 20:19:14 +0000173 if ((serv->flags & SERV_LITERAL_ADDRESS))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100174 {
Simon Kelley28866e92011-02-14 20:19:14 +0000175 if (!(sflag & qtype) && flags == 0)
176 continue;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100177 }
Simon Kelley28866e92011-02-14 20:19:14 +0000178 else
179 {
180 if (flags & (F_IPV4 | F_IPV6))
181 continue;
182 }
Simon Kelley36717ee2004-09-20 19:20:58 +0100183 }
Simon Kelley28866e92011-02-14 20:19:14 +0000184
185 if (domainlen >= matchlen)
186 {
Simon Kelley367341f2016-01-12 15:58:23 +0000187 *type = serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_DO_DNSSEC);
Simon Kelley28866e92011-02-14 20:19:14 +0000188 *domain = serv->domain;
189 matchlen = domainlen;
190 if (serv->flags & SERV_NO_ADDR)
191 flags = F_NXDOMAIN;
192 else if (serv->flags & SERV_LITERAL_ADDRESS)
193 {
Simon Kelleyda8b6512018-09-03 23:18:36 +0100194 /* literal address = '#' -> return all-zero address for IPv4 and IPv6 */
195 if ((serv->flags & SERV_USE_RESOLV) && (qtype & (F_IPV6 | F_IPV4)))
196 {
197 memset(&zero, 0, sizeof(zero));
198 flags = qtype;
199 *addrpp = &zero;
200 }
201 else if (sflag & qtype)
Simon Kelley28866e92011-02-14 20:19:14 +0000202 {
203 flags = sflag;
204 if (serv->addr.sa.sa_family == AF_INET)
Simon Kelleycc921df2019-01-02 22:48:59 +0000205 *addrpp = (union all_addr *)&serv->addr.in.sin_addr;
Simon Kelley28866e92011-02-14 20:19:14 +0000206 else
Simon Kelleycc921df2019-01-02 22:48:59 +0000207 *addrpp = (union all_addr *)&serv->addr.in6.sin6_addr;
Simon Kelley28866e92011-02-14 20:19:14 +0000208 }
209 else if (!flags || (flags & F_NXDOMAIN))
210 flags = F_NOERR;
211 }
212 else
213 flags = 0;
214 }
215 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100216 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100217 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100218
Simon Kelleybf05f8f2017-05-09 22:37:46 +0100219 if (flags == 0 && !(qtype & (F_QUERY | F_DNSSECOK)) &&
Simon Kelley28866e92011-02-14 20:19:14 +0000220 option_bool(OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
Simon Kelley7de060b2011-08-26 17:24:52 +0100221 /* don't forward A or AAAA queries for simple names, except the empty name */
222 flags = F_NOERR;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100223
Simon Kelley5aabfc72007-08-29 11:24:47 +0100224 if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now))
Simon Kelleyc1bb8502004-08-11 18:40:17 +0100225 flags = F_NOERR;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100226
Simon Kelley824af852008-02-12 20:43:05 +0000227 if (flags)
228 {
Simon Kelleyc346f612018-09-04 21:14:18 +0100229 if (flags == F_NXDOMAIN || flags == F_NOERR)
230 log_query(flags | qtype | F_NEG | F_CONFIG | F_FORWARD, qdomain, NULL, NULL);
231 else
232 {
233 /* handle F_IPV4 and F_IPV6 set on ANY query to 0.0.0.0/:: domain. */
234 if (flags & F_IPV4)
235 log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV6, qdomain, *addrpp, NULL);
Simon Kelleyc346f612018-09-04 21:14:18 +0100236 if (flags & F_IPV6)
237 log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV4, qdomain, *addrpp, NULL);
Simon Kelleyc346f612018-09-04 21:14:18 +0100238 }
Simon Kelley824af852008-02-12 20:43:05 +0000239 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100240 else if ((*type) & SERV_USE_RESOLV)
241 {
242 *type = 0; /* use normal servers for this domain */
243 *domain = NULL;
244 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100245 return flags;
246}
Simon Kelley44a2a312004-03-10 20:04:35 +0000247
Petr Menšík6c0bf792021-03-18 00:07:45 +0100248#ifdef HAVE_CONNTRACK
249static void set_outgoing_mark(struct frec *forward, int fd)
250{
251 /* Copy connection mark of incoming query to outgoing connection. */
252 unsigned int mark;
253 if (get_incoming_mark(&forward->frec_src.source, &forward->frec_src.dest, 0, &mark))
254 setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
255}
256#endif
257
258static void log_query_mysockaddr(unsigned int flags, char *name, union mysockaddr *addr, char *arg)
259{
260 if (addr->sa.sa_family == AF_INET)
261 log_query(flags | F_IPV4, name, (union all_addr *)&addr->in.sin_addr, arg);
262 else
263 log_query(flags | F_IPV6, name, (union all_addr *)&addr->in6.sin6_addr, arg);
264}
265
Petr Menšík51f7bc92021-03-18 01:05:43 +0100266static void server_send(struct server *server, int fd,
267 const void *header, size_t plen, int flags)
268{
269 while (retry_send(sendto(fd, header, plen, flags,
270 &server->addr.sa,
271 sa_len(&server->addr))));
272}
273
274#ifdef HAVE_DNSSEC
275static void server_send_log(struct server *server, int fd,
276 const void *header, size_t plen, int dumpflags,
277 unsigned int logflags, char *name, char *arg)
278{
279#ifdef HAVE_DUMPFILE
280 dump_packet(dumpflags, (void *)header, (size_t)plen, NULL, &server->addr);
281#endif
282 log_query_mysockaddr(logflags, name, &server->addr, arg);
283 server_send(server, fd, header, plen, 0);
284}
285#endif
286
Petr Menšíke10a9232021-03-15 11:20:49 +0100287static int server_test_type(const struct server *server,
288 const char *domain, int type, int extratype)
289{
290 return (type == (server->flags & (SERV_TYPE | extratype)) &&
291 (type != SERV_HAS_DOMAIN || hostname_isequal(domain, server->domain)) &&
292 !(server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)));
293}
294
Simon Kelley824af852008-02-12 20:43:05 +0000295static int forward_query(int udpfd, union mysockaddr *udpaddr,
Simon Kelleycc921df2019-01-02 22:48:59 +0000296 union all_addr *dst_addr, unsigned int dst_iface,
Simon Kelley83349b82014-02-10 21:02:01 +0000297 struct dns_header *header, size_t plen, time_t now,
Simon Kelley613ad152014-02-25 23:02:28 +0000298 struct frec *forward, int ad_reqd, int do_bit)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000299{
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000300 char *domain = NULL;
Simon Kelley367341f2016-01-12 15:58:23 +0000301 int type = SERV_DO_DNSSEC, norebind = 0;
Simon Kelleycc921df2019-01-02 22:48:59 +0000302 union all_addr *addrp = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +0000303 unsigned int flags = 0;
Simon Kelley15b60dd2020-11-18 18:34:55 +0000304 unsigned int fwd_flags = 0;
Simon Kelleyde379512004-06-22 20:23:33 +0100305 struct server *start = NULL;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000306 void *hash = hash_questions(header, plen, daemon->namebuff);
Simon Kelley2d765862020-11-12 22:06:07 +0000307#ifdef HAVE_DNSSEC
Simon Kelley367341f2016-01-12 15:58:23 +0000308 int do_dnssec = 0;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000309#endif
Simon Kelley1682d152018-08-03 20:38:18 +0100310 unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
311 unsigned char *oph = find_pseudoheader(header, plen, NULL, NULL, NULL, NULL);
Simon Kelleyea6b0b22021-04-05 21:01:09 +0100312 int old_src = 0;
313
Simon Kelley1682d152018-08-03 20:38:18 +0100314 (void)do_bit;
Simon Kelley15b60dd2020-11-18 18:34:55 +0000315
316 if (header->hb4 & HB4_CD)
317 fwd_flags |= FREC_CHECKING_DISABLED;
318 if (ad_reqd)
319 fwd_flags |= FREC_AD_QUESTION;
320 if (oph)
321 fwd_flags |= FREC_HAS_PHEADER;
322#ifdef HAVE_DNSSEC
323 if (do_bit)
324 fwd_flags |= FREC_DO_QUESTION;
325#endif
326
Simon Kelley305cb792021-02-18 21:35:09 +0000327 /* Check for retry on existing query */
Simon Kelleyea6b0b22021-04-05 21:01:09 +0100328 if (forward)
329 old_src = 1;
330 else if ((forward = lookup_frec_by_query(hash, fwd_flags)))
Simon Kelley141a26f2021-02-17 23:56:32 +0000331 {
Simon Kelley305cb792021-02-18 21:35:09 +0000332 struct frec_src *src;
Simon Kelleyea6b0b22021-04-05 21:01:09 +0100333
Simon Kelley305cb792021-02-18 21:35:09 +0000334 for (src = &forward->frec_src; src; src = src->next)
335 if (src->orig_id == ntohs(header->id) &&
336 sockaddr_isequal(&src->source, udpaddr))
337 break;
Simon Kelleyea6b0b22021-04-05 21:01:09 +0100338
339 if (src)
340 old_src = 1;
341 else
Simon Kelley305cb792021-02-18 21:35:09 +0000342 {
Simon Kelleyea6b0b22021-04-05 21:01:09 +0100343 /* Existing query, but from new source, just add this
344 client to the list that will get the reply.*/
345
Simon Kelley141a26f2021-02-17 23:56:32 +0000346 /* Note whine_malloc() zeros memory. */
347 if (!daemon->free_frec_src &&
348 daemon->frec_src_count < daemon->ftabsize &&
349 (daemon->free_frec_src = whine_malloc(sizeof(struct frec_src))))
350 {
351 daemon->frec_src_count++;
352 daemon->free_frec_src->next = NULL;
353 }
354
Simon Kelley961daf82021-04-06 23:52:09 +0100355 /* If we've been spammed with many duplicates, return REFUSED. */
Simon Kelley141a26f2021-02-17 23:56:32 +0000356 if (!daemon->free_frec_src)
Simon Kelley961daf82021-04-06 23:52:09 +0100357 {
358 static time_t last_log = 0;
359
360 if ((int)difftime(now, last_log) > 5)
361 {
362 last_log = now;
363 my_syslog(LOG_WARNING, _("Maximum number of concurrent DNS queries reached (max: %d)"), daemon->ftabsize);
364 }
365
366 goto frec_err;
367 }
Simon Kelley141a26f2021-02-17 23:56:32 +0000368
Simon Kelley305cb792021-02-18 21:35:09 +0000369 src = daemon->free_frec_src;
370 daemon->free_frec_src = src->next;
371 src->next = forward->frec_src.next;
372 forward->frec_src.next = src;
373 src->orig_id = ntohs(header->id);
374 src->source = *udpaddr;
375 src->dest = *dst_addr;
376 src->log_id = daemon->log_id;
377 src->iface = dst_iface;
378 src->fd = udpfd;
Simon Kelley64a16cb2021-04-06 23:29:46 +0100379
380 /* closely spaced identical queries cannot be a try and a retry, so
381 it's safe to wait for the reply from the first without
382 forwarding the second. */
383 if (difftime(now, forward->time) < 2)
384 return 0;
Simon Kelley141a26f2021-02-17 23:56:32 +0000385 }
386 }
387
388 /* retry existing query */
389 if (forward)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000390 {
Simon Kelleya77cec82015-05-08 16:25:38 +0100391 /* If we didn't get an answer advertising a maximal packet in EDNS,
392 fall back to 1280, which should work everywhere on IPv6.
393 If that generates an answer, it will become the new default
394 for this server */
395 forward->flags |= FREC_TEST_PKTSZ;
396
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000397#ifdef HAVE_DNSSEC
Simon Kelleydac74312014-02-13 16:43:49 +0000398 /* If we've already got an answer to this query, but we're awaiting keys for validation,
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000399 there's no point retrying the query, retry the key query instead...... */
400 if (forward->blocking_query)
401 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000402 int fd, is_sign;
403 unsigned char *pheader;
Simon Kelleya77cec82015-05-08 16:25:38 +0100404
405 forward->flags &= ~FREC_TEST_PKTSZ;
406
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000407 while (forward->blocking_query)
408 forward = forward->blocking_query;
Simon Kelleya77cec82015-05-08 16:25:38 +0100409
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000410 blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
411 plen = forward->stash_len;
412
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000413 forward->flags |= FREC_TEST_PKTSZ;
Simon Kelley5bb88f02015-12-21 16:23:47 +0000414 if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000415 PUTSHORT(SAFE_PKTSZ, pheader);
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000416
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000417 if ((fd = allocate_rfd(&forward->rfds, forward->sentto)) != -1)
Petr Menšík51f7bc92021-03-18 01:05:43 +0100418 server_send_log(forward->sentto, fd, header, plen,
419 DUMP_SEC_QUERY,
420 F_NOEXTRA | F_DNSSEC, "retry", "dnssec");
421
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000422 return 1;
423 }
424#endif
425
Simon Kelleyea6b0b22021-04-05 21:01:09 +0100426 /* retry on existing query, from original source. Send to all available servers */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000427 domain = forward->sentto->domain;
Simon Kelley824af852008-02-12 20:43:05 +0000428 forward->sentto->failed_queries++;
Simon Kelleyea6b0b22021-04-05 21:01:09 +0100429 if (!option_bool(OPT_ORDER) && old_src)
Simon Kelleyde379512004-06-22 20:23:33 +0100430 {
Simon Kelley0a852542005-03-23 20:28:59 +0000431 forward->forwardall = 1;
Simon Kelley3be34542004-09-11 19:12:13 +0100432 daemon->last_server = NULL;
Simon Kelleyde379512004-06-22 20:23:33 +0100433 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000434 type = forward->sentto->flags & SERV_TYPE;
Simon Kelley367341f2016-01-12 15:58:23 +0000435#ifdef HAVE_DNSSEC
436 do_dnssec = forward->sentto->flags & SERV_DO_DNSSEC;
437#endif
438
Simon Kelleyde379512004-06-22 20:23:33 +0100439 if (!(start = forward->sentto->next))
Simon Kelley3be34542004-09-11 19:12:13 +0100440 start = daemon->servers; /* at end of list, recycle */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000441 header->id = htons(forward->new_id);
442 }
443 else
444 {
Simon Kelley141a26f2021-02-17 23:56:32 +0000445 /* new query */
446
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000447 if (gotname)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100448 flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000449
Simon Kelley367341f2016-01-12 15:58:23 +0000450#ifdef HAVE_DNSSEC
451 do_dnssec = type & SERV_DO_DNSSEC;
Simon Kelleyf7443d72016-01-19 20:29:57 +0000452#endif
453 type &= ~SERV_DO_DNSSEC;
Simon Kelley15b60dd2020-11-18 18:34:55 +0000454
Simon Kelley141a26f2021-02-17 23:56:32 +0000455 /* may be no servers available. */
Simon Kelleyd05dd582016-01-19 21:23:30 +0000456 if (daemon->servers && !flags)
Simon Kelley8caf3d72020-04-04 17:00:32 +0100457 forward = get_new_frec(now, NULL, NULL);
Simon Kelleyd05dd582016-01-19 21:23:30 +0000458 /* table full - flags == 0, return REFUSED */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000459
460 if (forward)
461 {
Simon Kelley15b60dd2020-11-18 18:34:55 +0000462 forward->frec_src.source = *udpaddr;
463 forward->frec_src.orig_id = ntohs(header->id);
464 forward->frec_src.dest = *dst_addr;
465 forward->frec_src.iface = dst_iface;
Simon Kelley6a6e06f2020-12-04 18:35:11 +0000466 forward->frec_src.next = NULL;
Simon Kelley04490bf2021-01-22 16:49:12 +0000467 forward->frec_src.fd = udpfd;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000468 forward->new_id = get_id();
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000469 memcpy(forward->hash, hash, HASH_SIZE);
Simon Kelley0a852542005-03-23 20:28:59 +0000470 forward->forwardall = 0;
Simon Kelley15b60dd2020-11-18 18:34:55 +0000471 forward->flags = fwd_flags;
Simon Kelley28866e92011-02-14 20:19:14 +0000472 if (norebind)
473 forward->flags |= FREC_NOREBIND;
Simon Kelley572b41e2011-02-18 18:11:18 +0000474 if (header->hb4 & HB4_CD)
Simon Kelley28866e92011-02-14 20:19:14 +0000475 forward->flags |= FREC_CHECKING_DISABLED;
Simon Kelley83349b82014-02-10 21:02:01 +0000476 if (ad_reqd)
477 forward->flags |= FREC_AD_QUESTION;
Simon Kelley7fa836e2014-02-10 20:11:24 +0000478#ifdef HAVE_DNSSEC
479 forward->work_counter = DNSSEC_WORK;
Simon Kelley613ad152014-02-25 23:02:28 +0000480 if (do_bit)
481 forward->flags |= FREC_DO_QUESTION;
Simon Kelley7fa836e2014-02-10 20:11:24 +0000482#endif
Simon Kelley613ad152014-02-25 23:02:28 +0000483
Simon Kelley28866e92011-02-14 20:19:14 +0000484 header->id = htons(forward->new_id);
485
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100486 /* In strict_order mode, always try servers in the order
487 specified in resolv.conf, if a domain is given
488 always try all the available servers,
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000489 otherwise, use the one last known to work. */
490
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100491 if (type == 0)
492 {
Simon Kelley28866e92011-02-14 20:19:14 +0000493 if (option_bool(OPT_ORDER))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100494 start = daemon->servers;
495 else if (!(start = daemon->last_server) ||
496 daemon->forwardcount++ > FORWARD_TEST ||
497 difftime(now, daemon->forwardtime) > FORWARD_TIME)
498 {
499 start = daemon->servers;
500 forward->forwardall = 1;
501 daemon->forwardcount = 0;
502 daemon->forwardtime = now;
503 }
504 }
505 else
Simon Kelleyde379512004-06-22 20:23:33 +0100506 {
Simon Kelley3be34542004-09-11 19:12:13 +0100507 start = daemon->servers;
Simon Kelley28866e92011-02-14 20:19:14 +0000508 if (!option_bool(OPT_ORDER))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100509 forward->forwardall = 1;
Simon Kelleyde379512004-06-22 20:23:33 +0100510 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000511 }
512 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100513
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000514 /* check for send errors here (no route to host)
515 if we fail to send to all nameservers, send back an error
516 packet straight away (helps modem users when offline) */
517
518 if (!flags && forward)
519 {
Simon Kelleyde379512004-06-22 20:23:33 +0100520 struct server *firstsentto = start;
Simon Kelley25e63f12020-11-25 21:17:52 +0000521 int subnet, cacheable, forwarded = 0;
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000522 size_t edns0_len;
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000523 unsigned char *pheader;
524
Simon Kelley25cf5e32015-01-09 15:53:03 +0000525 /* If a query is retried, use the log_id for the retry when logging the answer. */
Simon Kelley15b60dd2020-11-18 18:34:55 +0000526 forward->frec_src.log_id = daemon->log_id;
Simon Kelley25cf5e32015-01-09 15:53:03 +0000527
Simon Kelley25e63f12020-11-25 21:17:52 +0000528 plen = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->frec_src.source, now, &subnet, &cacheable);
Simon Kelley33702ab2015-12-28 23:17:15 +0000529
Simon Kelley6fd5d792017-10-13 22:26:40 +0100530 if (subnet)
531 forward->flags |= FREC_HAS_SUBNET;
Simon Kelley25e63f12020-11-25 21:17:52 +0000532
533 if (!cacheable)
534 forward->flags |= FREC_NO_CACHE;
535
Simon Kelley3a237152013-12-12 12:15:50 +0000536#ifdef HAVE_DNSSEC
Simon Kelley367341f2016-01-12 15:58:23 +0000537 if (option_bool(OPT_DNSSEC_VALID) && do_dnssec)
Simon Kelley0fc2f312014-01-08 10:26:58 +0000538 {
Simon Kelley6fd5d792017-10-13 22:26:40 +0100539 plen = add_do_bit(header, plen, ((unsigned char *) header) + PACKETSZ);
540
Simon Kelley5b3bf922014-01-25 17:03:07 +0000541 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
542 this allows it to select auth servers when one is returning bad data. */
543 if (option_bool(OPT_DNSSEC_DEBUG))
544 header->hb4 |= HB4_CD;
Simon Kelley613ad152014-02-25 23:02:28 +0000545
Simon Kelley0fc2f312014-01-08 10:26:58 +0000546 }
Simon Kelley3a237152013-12-12 12:15:50 +0000547#endif
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000548
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000549 if (find_pseudoheader(header, plen, &edns0_len, &pheader, NULL, NULL))
Simon Kelley6fd5d792017-10-13 22:26:40 +0100550 {
551 /* If there wasn't a PH before, and there is now, we added it. */
552 if (!oph)
553 forward->flags |= FREC_ADDED_PHEADER;
554
555 /* If we're sending an EDNS0 with any options, we can't recreate the query from a reply. */
556 if (edns0_len > 11)
557 forward->flags |= FREC_HAS_EXTRADATA;
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000558
559 /* Reduce udp size on retransmits. */
560 if (forward->flags & FREC_TEST_PKTSZ)
561 PUTSHORT(SAFE_PKTSZ, pheader);
Simon Kelley6fd5d792017-10-13 22:26:40 +0100562 }
Simon Kelleya77cec82015-05-08 16:25:38 +0100563
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000564 while (1)
565 {
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000566 int fd;
567
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000568 /* only send to servers dealing with our domain.
569 domain may be NULL, in which case server->domain
570 must be NULL also. */
571
Petr Menšíke10a9232021-03-15 11:20:49 +0100572 if (server_test_type(start, domain, type, 0) &&
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000573 ((fd = allocate_rfd(&forward->rfds, start)) != -1))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000574 {
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000575
Simon Kelley7de060b2011-08-26 17:24:52 +0100576#ifdef HAVE_CONNTRACK
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000577 /* Copy connection mark of incoming query to outgoing connection. */
578 if (option_bool(OPT_CONNTRACK))
Petr Menšík6c0bf792021-03-18 00:07:45 +0100579 set_outgoing_mark(forward, fd);
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000580#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +0100581
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000582#ifdef HAVE_DNSSEC
Simon Kelley5bb88f02015-12-21 16:23:47 +0000583 if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER))
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000584 {
585 /* Difficult one here. If our client didn't send EDNS0, we will have set the UDP
586 packet size to 512. But that won't provide space for the RRSIGS in many cases.
587 The RRSIGS will be stripped out before the answer goes back, so the packet should
588 shrink again. So, if we added a do-bit, bump the udp packet size to the value
Simon Kelley5aa5f0f2015-12-21 17:20:35 +0000589 known to be OK for this server. We check returned size after stripping and set
590 the truncated bit if it's still too big. */
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000591 unsigned char *pheader;
592 int is_sign;
Simon Kelley5bb88f02015-12-21 16:23:47 +0000593 if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000594 PUTSHORT(start->edns_pktsz, pheader);
595 }
596#endif
597
Simon Kelleyff841eb2015-03-11 21:36:30 +0000598 if (retry_send(sendto(fd, (char *)header, plen, 0,
599 &start->addr.sa,
600 sa_len(&start->addr))))
601 continue;
602
603 if (errno == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000604 {
Simon Kelley6b173352018-05-08 18:32:14 +0100605#ifdef HAVE_DUMPFILE
606 dump_packet(DUMP_UP_QUERY, (void *)header, plen, NULL, &start->addr);
607#endif
608
Simon Kelleycdeda282006-03-16 20:16:06 +0000609 /* Keep info in case we want to re-send this packet */
610 daemon->srv_save = start;
611 daemon->packet_len = plen;
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000612 daemon->fd_save = fd;
Simon Kelleycdeda282006-03-16 20:16:06 +0000613
Simon Kelleyde379512004-06-22 20:23:33 +0100614 if (!gotname)
Simon Kelley3be34542004-09-11 19:12:13 +0100615 strcpy(daemon->namebuff, "query");
Petr Menšík6c0bf792021-03-18 00:07:45 +0100616 log_query_mysockaddr(F_SERVER | F_FORWARD, daemon->namebuff,
617 &start->addr, NULL);
Simon Kelley824af852008-02-12 20:43:05 +0000618 start->queries++;
Simon Kelleyde379512004-06-22 20:23:33 +0100619 forwarded = 1;
620 forward->sentto = start;
Simon Kelley0a852542005-03-23 20:28:59 +0000621 if (!forward->forwardall)
Simon Kelleyde379512004-06-22 20:23:33 +0100622 break;
Simon Kelley0a852542005-03-23 20:28:59 +0000623 forward->forwardall++;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000624 }
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000625 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000626
Simon Kelleyde379512004-06-22 20:23:33 +0100627 if (!(start = start->next))
Simon Kelley3be34542004-09-11 19:12:13 +0100628 start = daemon->servers;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000629
Simon Kelleyde379512004-06-22 20:23:33 +0100630 if (start == firstsentto)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000631 break;
632 }
633
Simon Kelleyde379512004-06-22 20:23:33 +0100634 if (forwarded)
Simon Kelley824af852008-02-12 20:43:05 +0000635 return 1;
Simon Kelleyde379512004-06-22 20:23:33 +0100636
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000637 /* could not send on, prepare to return */
Simon Kelley15b60dd2020-11-18 18:34:55 +0000638 header->id = htons(forward->frec_src.orig_id);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100639 free_frec(forward); /* cancel */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000640 }
641
642 /* could not send on, return empty answer or address if known for whole domain */
Simon Kelley961daf82021-04-06 23:52:09 +0100643 frec_err:
Simon Kelleyb8187c82005-11-26 21:46:27 +0000644 if (udpfd != -1)
645 {
Simon Kelleycdeda282006-03-16 20:16:06 +0000646 plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl);
Simon Kelley1682d152018-08-03 20:38:18 +0100647 if (oph)
648 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 +0100649 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 +0000650 }
651
Simon Kelley824af852008-02-12 20:43:05 +0000652 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000653}
654
Simon Kelleyed4c0762013-10-08 20:46:34 +0100655static 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 +0100656 int no_cache, int cache_secure, int bogusanswer, int ad_reqd, int do_bit, int added_pheader,
657 int check_subnet, union mysockaddr *query_source)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100658{
Simon Kelley36717ee2004-09-20 19:20:58 +0100659 unsigned char *pheader, *sizep;
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000660 char **sets = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +0000661 int munged = 0, is_sign;
Simon Kelley07ed5852018-05-04 21:52:22 +0100662 unsigned int rcode = RCODE(header);
Simon Kelleycdeda282006-03-16 20:16:06 +0000663 size_t plen;
Simon Kelleya6004d72017-10-25 17:48:19 +0100664
Simon Kelley83349b82014-02-10 21:02:01 +0000665 (void)ad_reqd;
Simon Kelley982faf42015-04-03 21:42:30 +0100666 (void)do_bit;
667 (void)bogusanswer;
Simon Kelley83349b82014-02-10 21:02:01 +0000668
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000669#ifdef HAVE_IPSET
Simon Kelley82a14af2014-04-13 20:48:57 +0100670 if (daemon->ipsets && extract_request(header, n, daemon->namebuff, NULL))
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000671 {
Simon Kelley82a14af2014-04-13 20:48:57 +0100672 /* Similar algorithm to search_servers. */
673 struct ipsets *ipset_pos;
674 unsigned int namelen = strlen(daemon->namebuff);
675 unsigned int matchlen = 0;
676 for (ipset_pos = daemon->ipsets; ipset_pos; ipset_pos = ipset_pos->next)
Simon Kelley6c0cb852014-01-17 14:40:46 +0000677 {
Simon Kelley82a14af2014-04-13 20:48:57 +0100678 unsigned int domainlen = strlen(ipset_pos->domain);
679 char *matchstart = daemon->namebuff + namelen - domainlen;
680 if (namelen >= domainlen && hostname_isequal(matchstart, ipset_pos->domain) &&
681 (domainlen == 0 || namelen == domainlen || *(matchstart - 1) == '.' ) &&
682 domainlen >= matchlen)
683 {
684 matchlen = domainlen;
685 sets = ipset_pos->sets;
686 }
Simon Kelley6c0cb852014-01-17 14:40:46 +0000687 }
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000688 }
689#endif
Simon Kelley25e63f12020-11-25 21:17:52 +0000690
Simon Kelley5bb88f02015-12-21 16:23:47 +0000691 if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign, NULL)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100692 {
Simon Kelley07ed5852018-05-04 21:52:22 +0100693 /* Get extended RCODE. */
694 rcode |= sizep[2] << 4;
695
Simon Kelleyed4c0762013-10-08 20:46:34 +0100696 if (check_subnet && !check_source(header, plen, pheader, query_source))
697 {
698 my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch"));
699 return 0;
700 }
Simon Kelley613ad152014-02-25 23:02:28 +0000701
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000702 if (!is_sign)
Simon Kelley613ad152014-02-25 23:02:28 +0000703 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000704 if (added_pheader)
705 {
706 /* client didn't send EDNS0, we added one, strip it off before returning answer. */
707 n = rrfilter(header, n, 0);
708 pheader = NULL;
709 }
710 else
711 {
Simon Kelley33702ab2015-12-28 23:17:15 +0000712 unsigned short udpsz;
713
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000714 /* If upstream is advertising a larger UDP packet size
715 than we allow, trim it so that we don't get overlarge
716 requests for the client. We can't do this for signed packets. */
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000717 GETSHORT(udpsz, sizep);
718 if (udpsz > daemon->edns_pktsz)
Simon Kelley33702ab2015-12-28 23:17:15 +0000719 {
720 sizep -= 2;
721 PUTSHORT(daemon->edns_pktsz, sizep);
722 }
723
724#ifdef HAVE_DNSSEC
725 /* If the client didn't set the do bit, but we did, reset it. */
726 if (option_bool(OPT_DNSSEC_VALID) && !do_bit)
727 {
728 unsigned short flags;
729 sizep += 2; /* skip RCODE */
730 GETSHORT(flags, sizep);
731 flags &= ~0x8000;
732 sizep -= 2;
733 PUTSHORT(flags, sizep);
734 }
735#endif
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000736 }
Simon Kelley613ad152014-02-25 23:02:28 +0000737 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100738 }
Simon Kelley83349b82014-02-10 21:02:01 +0000739
Simon Kelley28866e92011-02-14 20:19:14 +0000740 /* RFC 4035 sect 4.6 para 3 */
Giovanni Bajo237724c2012-04-05 02:46:52 +0200741 if (!is_sign && !option_bool(OPT_DNSSEC_PROXY))
Simon Kelley795501b2014-01-08 18:11:55 +0000742 header->hb4 &= ~HB4_AD;
Simon Kelley3a237152013-12-12 12:15:50 +0000743
Simon Kelley07ed5852018-05-04 21:52:22 +0100744 if (OPCODE(header) != QUERY)
Simon Kelley8938ae02014-05-01 17:46:25 +0100745 return resize_packet(header, n, pheader, plen);
Simon Kelley07ed5852018-05-04 21:52:22 +0100746
747 if (rcode != NOERROR && rcode != NXDOMAIN)
748 {
Simon Kelleycc921df2019-01-02 22:48:59 +0000749 union all_addr a;
750 a.log.rcode = rcode;
Simon Kelley07ed5852018-05-04 21:52:22 +0100751 log_query(F_UPSTREAM | F_RCODE, "error", &a, NULL);
752
753 return resize_packet(header, n, pheader, plen);
754 }
Simon Kelley36717ee2004-09-20 19:20:58 +0100755
Simon Kelley0a852542005-03-23 20:28:59 +0000756 /* Complain loudly if the upstream server is non-recursive. */
Simon Kelley07ed5852018-05-04 21:52:22 +0100757 if (!(header->hb4 & HB4_RA) && rcode == NOERROR &&
Simon Kelley0a852542005-03-23 20:28:59 +0000758 server && !(server->flags & SERV_WARNED_RECURSIVE))
759 {
Petr Mensik51cdd1a2019-07-04 20:28:08 +0200760 (void)prettyprint_addr(&server->addr, daemon->namebuff);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100761 my_syslog(LOG_WARNING, _("nameserver %s refused to do a recursive query"), daemon->namebuff);
Simon Kelley28866e92011-02-14 20:19:14 +0000762 if (!option_bool(OPT_LOG))
Simon Kelley0a852542005-03-23 20:28:59 +0000763 server->flags |= SERV_WARNED_RECURSIVE;
764 }
Giovanni Bajoe292e932012-04-22 14:32:02 +0200765
Simon Kelley07ed5852018-05-04 21:52:22 +0100766 if (daemon->bogus_addr && rcode != NXDOMAIN &&
Simon Kelley9eaa91b2021-03-17 20:31:06 +0000767 check_for_bogus_wildcard(header, n, daemon->namebuff, now))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100768 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100769 munged = 1;
Simon Kelley572b41e2011-02-18 18:11:18 +0000770 SET_RCODE(header, NXDOMAIN);
771 header->hb3 &= ~HB3_AA;
Simon Kelley6938f342014-01-26 22:47:39 +0000772 cache_secure = 0;
Simon Kelley36717ee2004-09-20 19:20:58 +0100773 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100774 else
Simon Kelley36717ee2004-09-20 19:20:58 +0100775 {
Simon Kelley6938f342014-01-26 22:47:39 +0000776 int doctored = 0;
777
Simon Kelley07ed5852018-05-04 21:52:22 +0100778 if (rcode == NXDOMAIN &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100779 extract_request(header, n, daemon->namebuff, NULL) &&
Simon Kelley5aabfc72007-08-29 11:24:47 +0100780 check_for_local_domain(daemon->namebuff, now))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100781 {
Simon Kelley36717ee2004-09-20 19:20:58 +0100782 /* if we forwarded a query for a locally known name (because it was for
783 an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
784 since we know that the domain exists, even if upstream doesn't */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100785 munged = 1;
Simon Kelley572b41e2011-02-18 18:11:18 +0000786 header->hb3 |= HB3_AA;
787 SET_RCODE(header, NOERROR);
Simon Kelley6938f342014-01-26 22:47:39 +0000788 cache_secure = 0;
Simon Kelley36717ee2004-09-20 19:20:58 +0100789 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000790
Simon Kelley373e9172017-12-01 22:40:56 +0000791 if (extract_addresses(header, n, daemon->namebuff, now, sets, is_sign, check_rebind, no_cache, cache_secure, &doctored))
Simon Kelley824af852008-02-12 20:43:05 +0000792 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100793 my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
Simon Kelley824af852008-02-12 20:43:05 +0000794 munged = 1;
Simon Kelley6938f342014-01-26 22:47:39 +0000795 cache_secure = 0;
Simon Kelley824af852008-02-12 20:43:05 +0000796 }
Simon Kelley6938f342014-01-26 22:47:39 +0000797
798 if (doctored)
799 cache_secure = 0;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100800 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100801
Simon Kelleya25720a2014-01-14 23:13:55 +0000802#ifdef HAVE_DNSSEC
Simon Kelley33702ab2015-12-28 23:17:15 +0000803 if (bogusanswer && !(header->hb4 & HB4_CD) && !option_bool(OPT_DNSSEC_DEBUG))
Simon Kelleya25720a2014-01-14 23:13:55 +0000804 {
Simon Kelley33702ab2015-12-28 23:17:15 +0000805 /* Bogus reply, turn into SERVFAIL */
806 SET_RCODE(header, SERVFAIL);
807 munged = 1;
Simon Kelleya25720a2014-01-14 23:13:55 +0000808 }
Simon Kelley6938f342014-01-26 22:47:39 +0000809
810 if (option_bool(OPT_DNSSEC_VALID))
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000811 {
812 header->hb4 &= ~HB4_AD;
813
814 if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure)
815 header->hb4 |= HB4_AD;
816
817 /* If the requestor didn't set the DO bit, don't return DNSSEC info. */
818 if (!do_bit)
819 n = rrfilter(header, n, 1);
820 }
Simon Kelleya25720a2014-01-14 23:13:55 +0000821#endif
822
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100823 /* do this after extract_addresses. Ensure NODATA reply and remove
824 nameserver info. */
825
826 if (munged)
827 {
828 header->ancount = htons(0);
829 header->nscount = htons(0);
830 header->arcount = htons(0);
Simon Kelley150162b2015-03-27 09:58:26 +0000831 header->hb3 &= ~HB3_TC;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100832 }
833
Simon Kelley36717ee2004-09-20 19:20:58 +0100834 /* the bogus-nxdomain stuff, doctor and NXDOMAIN->NODATA munging can all elide
835 sections of the packet. Find the new length here and put back pseudoheader
836 if it was removed. */
837 return resize_packet(header, n, pheader, plen);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100838}
839
Simon Kelley3be34542004-09-11 19:12:13 +0100840/* sets new last_server */
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000841void reply_query(int fd, time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000842{
843 /* packet from peer server, extract data for cache, and send to
844 original requester */
Simon Kelley572b41e2011-02-18 18:11:18 +0000845 struct dns_header *header;
Simon Kelleyde379512004-06-22 20:23:33 +0100846 union mysockaddr serveraddr;
Simon Kelley832af0b2007-01-21 20:01:28 +0000847 struct frec *forward;
Simon Kelleyde379512004-06-22 20:23:33 +0100848 socklen_t addrlen = sizeof(serveraddr);
Simon Kelley60b68062014-01-08 12:10:28 +0000849 ssize_t n = recvfrom(fd, daemon->packet, daemon->packet_buff_sz, 0, &serveraddr.sa, &addrlen);
Simon Kelleycdeda282006-03-16 20:16:06 +0000850 size_t nn;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100851 struct server *server;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000852 void *hash;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000853
Simon Kelleycdeda282006-03-16 20:16:06 +0000854 /* packet buffer overwritten */
855 daemon->srv_save = NULL;
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000856
Simon Kelleyde379512004-06-22 20:23:33 +0100857 /* Determine the address of the server replying so that we can mark that as good */
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000858 if (serveraddr.sa.sa_family == AF_INET6)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100859 serveraddr.in6.sin6_flowinfo = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000860
Simon Kelley490f9072014-03-24 22:04:42 +0000861 header = (struct dns_header *)daemon->packet;
Simon Kelley6b173352018-05-08 18:32:14 +0100862
Simon Kelley490f9072014-03-24 22:04:42 +0000863 if (n < (int)sizeof(struct dns_header) || !(header->hb3 & HB3_QR))
864 return;
865
Simon Kelley1a6bca82008-07-11 11:11:42 +0100866 /* spoof check: answer must come from known server, */
867 for (server = daemon->servers; server; server = server->next)
868 if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) &&
869 sockaddr_isequal(&server->addr, &serveraddr))
870 break;
Simon Kelley490f9072014-03-24 22:04:42 +0000871
872 if (!server)
873 return;
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000874
875 /* If sufficient time has elapsed, try and expand UDP buffer size again. */
876 if (difftime(now, server->pktsz_reduced) > UDP_TEST_TIME)
877 server->edns_pktsz = daemon->edns_pktsz;
878
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000879 hash = hash_questions(header, n, daemon->namebuff);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100880
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000881 if (!(forward = lookup_frec(ntohs(header->id), fd, hash)))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100882 return;
Simon Kelley490f9072014-03-24 22:04:42 +0000883
Simon Kelley6b173352018-05-08 18:32:14 +0100884#ifdef HAVE_DUMPFILE
885 dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_REPLY : DUMP_UP_REPLY,
886 (void *)header, n, &serveraddr, NULL);
887#endif
Simon Kelleya0088e82018-05-10 21:43:14 +0100888
Simon Kelley25cf5e32015-01-09 15:53:03 +0000889 /* log_query gets called indirectly all over the place, so
890 pass these in global variables - sorry. */
Simon Kelley15b60dd2020-11-18 18:34:55 +0000891 daemon->log_display_id = forward->frec_src.log_id;
892 daemon->log_source_addr = &forward->frec_src.source;
Simon Kelley25cf5e32015-01-09 15:53:03 +0000893
Glen Huang32fc6db2014-12-27 15:28:12 +0000894 if (daemon->ignore_addr && RCODE(header) == NOERROR &&
Simon Kelley9eaa91b2021-03-17 20:31:06 +0000895 check_for_ignored_address(header, n))
Glen Huang32fc6db2014-12-27 15:28:12 +0000896 return;
897
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000898 /* Note: if we send extra options in the EDNS0 header, we can't recreate
899 the query from the reply. */
Simon Kelley34e26e12018-05-10 20:54:57 +0100900 if ((RCODE(header) == REFUSED || RCODE(header) == SERVFAIL) &&
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000901 forward->forwardall == 0 &&
902 !(forward->flags & FREC_HAS_EXTRADATA))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100903 /* for broken servers, attempt to send to another one. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000904 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100905 unsigned char *pheader;
906 size_t plen;
907 int is_sign;
Simon Kelleyef3d1372017-12-05 22:37:29 +0000908
Simon Kelley1f60a182018-05-11 16:44:16 +0100909#ifdef HAVE_DNSSEC
Simon Kelleya0088e82018-05-10 21:43:14 +0100910 if (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY))
911 {
Simon Kelley1f60a182018-05-11 16:44:16 +0100912 struct server *start;
913
Simon Kelleya0088e82018-05-10 21:43:14 +0100914 blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
915 plen = forward->stash_len;
916
917 forward->forwardall = 2; /* only retry once */
Simon Kelley1f60a182018-05-11 16:44:16 +0100918 start = forward->sentto;
919
920 /* for non-domain specific servers, see if we can find another to try. */
921 if ((forward->sentto->flags & SERV_TYPE) == 0)
922 while (1)
923 {
924 if (!(start = start->next))
925 start = daemon->servers;
926 if (start == forward->sentto)
927 break;
928
929 if ((start->flags & SERV_TYPE) == 0 &&
930 (start->flags & SERV_DO_DNSSEC))
931 break;
932 }
933
934
Petr Menšík51f7bc92021-03-18 01:05:43 +0100935 if ((fd = allocate_rfd(&forward->rfds, start)) != -1)
936 server_send_log(start, fd, header, plen,
937 DUMP_SEC_QUERY,
938 F_NOEXTRA | F_DNSSEC, "retry", "dnssec");
Simon Kelleya0088e82018-05-10 21:43:14 +0100939 return;
940 }
Simon Kelley1f60a182018-05-11 16:44:16 +0100941#endif
942
Simon Kelleyef3d1372017-12-05 22:37:29 +0000943 /* In strict order mode, there must be a server later in the chain
944 left to send to, otherwise without the forwardall mechanism,
945 code further on will cycle around the list forwever if they
946 all return REFUSED. Note that server is always non-NULL before
947 this executes. */
948 if (option_bool(OPT_ORDER))
949 for (server = forward->sentto->next; server; server = server->next)
950 if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR | SERV_LOOP)))
951 break;
952
Simon Kelley1a6bca82008-07-11 11:11:42 +0100953 /* recreate query from reply */
Simon Kelley5bb88f02015-12-21 16:23:47 +0000954 pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign, NULL);
Simon Kelleyef3d1372017-12-05 22:37:29 +0000955 if (!is_sign && server)
Simon Kelley832af0b2007-01-21 20:01:28 +0000956 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100957 header->ancount = htons(0);
958 header->nscount = htons(0);
959 header->arcount = htons(0);
960 if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
961 {
swiggerbd7bfa22015-06-01 20:54:59 +0100962 header->hb3 &= ~(HB3_QR | HB3_AA | HB3_TC);
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000963 header->hb4 &= ~(HB4_RA | HB4_RCODE | HB4_CD | HB4_AD);
Simon Kelley1801a292016-01-17 21:53:57 +0000964 if (forward->flags & FREC_CHECKING_DISABLED)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000965 header->hb4 |= HB4_CD;
Simon Kelley1801a292016-01-17 21:53:57 +0000966 if (forward->flags & FREC_AD_QUESTION)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000967 header->hb4 |= HB4_AD;
968 if (forward->flags & FREC_DO_QUESTION)
Simon Kelley33702ab2015-12-28 23:17:15 +0000969 add_do_bit(header, nn, (unsigned char *)pheader + plen);
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000970 forward_query(-1, NULL, NULL, 0, header, nn, now, forward, forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100971 return;
972 }
973 }
974 }
Simon Kelley3a237152013-12-12 12:15:50 +0000975
976 server = forward->sentto;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100977 if ((forward->sentto->flags & SERV_TYPE) == 0)
978 {
Simon Kelley51967f92014-03-25 21:07:00 +0000979 if (RCODE(header) == REFUSED)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100980 server = NULL;
981 else
982 {
983 struct server *last_server;
Simon Kelley832af0b2007-01-21 20:01:28 +0000984
Simon Kelley1a6bca82008-07-11 11:11:42 +0100985 /* find good server by address if possible, otherwise assume the last one we sent to */
986 for (last_server = daemon->servers; last_server; last_server = last_server->next)
987 if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) &&
988 sockaddr_isequal(&last_server->addr, &serveraddr))
989 {
990 server = last_server;
991 break;
992 }
993 }
Simon Kelley28866e92011-02-14 20:19:14 +0000994 if (!option_bool(OPT_ALL_SERVERS))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100995 daemon->last_server = server;
996 }
Simon Kelleya77cec82015-05-08 16:25:38 +0100997
998 /* We tried resending to this server with a smaller maximum size and got an answer.
Ville Skyttäfaaf3062018-01-14 17:32:52 +0000999 Make that permanent. To avoid reduxing the packet size for a single dropped packet,
Simon Kelley86fa1042015-05-10 13:50:59 +01001000 only do this when we get a truncated answer, or one larger than the safe size. */
Simon Kelley04db1482019-10-11 23:22:17 +01001001 if (forward->sentto->edns_pktsz > SAFE_PKTSZ && (forward->flags & FREC_TEST_PKTSZ) &&
Simon Kelley86fa1042015-05-10 13:50:59 +01001002 ((header->hb3 & HB3_TC) || n >= SAFE_PKTSZ))
Simon Kelley22dee512017-10-13 22:54:00 +01001003 {
Simon Kelley04db1482019-10-11 23:22:17 +01001004 forward->sentto->edns_pktsz = SAFE_PKTSZ;
1005 forward->sentto->pktsz_reduced = now;
Petr Mensik51cdd1a2019-07-04 20:28:08 +02001006 (void)prettyprint_addr(&forward->sentto->addr, daemon->addrbuff);
Simon Kelleyebedcba2017-10-29 20:54:17 +00001007 my_syslog(LOG_WARNING, _("reducing DNS packet size for nameserver %s to %d"), daemon->addrbuff, SAFE_PKTSZ);
Simon Kelley22dee512017-10-13 22:54:00 +01001008 }
Simon Kelleyc1a4e252018-01-19 22:00:05 +00001009
1010
Simon Kelley1a6bca82008-07-11 11:11:42 +01001011 /* If the answer is an error, keep the forward record in place in case
1012 we get a good reply from another server. Kill it when we've
1013 had replies from all to avoid filling the forwarding table when
1014 everything is broken */
Simon Kelley122392e2018-10-31 22:24:02 +00001015 if (forward->forwardall == 0 || --forward->forwardall == 1 || RCODE(header) != REFUSED)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001016 {
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001017 int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
Simon Kelleya6004d72017-10-25 17:48:19 +01001018
Simon Kelley3a237152013-12-12 12:15:50 +00001019 if (option_bool(OPT_NO_REBIND))
1020 check_rebind = !(forward->flags & FREC_NOREBIND);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001021
Simon Kelley3a237152013-12-12 12:15:50 +00001022 /* Don't cache replies where DNSSEC validation was turned off, either
1023 the upstream server told us so, or the original query specified it. */
1024 if ((header->hb4 & HB4_CD) || (forward->flags & FREC_CHECKING_DISABLED))
1025 no_cache_dnssec = 1;
1026
1027#ifdef HAVE_DNSSEC
Simon Kelley04db1482019-10-11 23:22:17 +01001028 if ((forward->sentto->flags & SERV_DO_DNSSEC) &&
Simon Kelley57573712016-01-11 22:50:00 +00001029 option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED))
Simon Kelley3a237152013-12-12 12:15:50 +00001030 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001031 int status = 0;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001032
1033 /* We've had a reply already, which we're validating. Ignore this duplicate */
Simon Kelleye0c0ad32014-01-16 22:42:07 +00001034 if (forward->blocking_query)
Simon Kelley0fc2f312014-01-08 10:26:58 +00001035 return;
Simon Kelley9a31b682015-12-15 10:20:39 +00001036
1037 /* Truncated answer can't be validated.
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001038 If this is an answer to a DNSSEC-generated query, we still
1039 need to get the client to retry over TCP, so return
1040 an answer with the TC bit set, even if the actual answer fits.
1041 */
Simon Kelley9a31b682015-12-15 10:20:39 +00001042 if (header->hb3 & HB3_TC)
1043 status = STAT_TRUNCATED;
1044
1045 while (1)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001046 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001047 /* As soon as anything returns BOGUS, we stop and unwind, to do otherwise
1048 would invite infinite loops, since the answers to DNSKEY and DS queries
1049 will not be cached, so they'll be repeated. */
1050 if (status != STAT_BOGUS && status != STAT_TRUNCATED && status != STAT_ABANDONED)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001051 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001052 if (forward->flags & FREC_DNSKEY_QUERY)
1053 status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
1054 else if (forward->flags & FREC_DS_QUERY)
1055 status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001056 else
Simon Kelley9a31b682015-12-15 10:20:39 +00001057 status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class,
Simon Kelley203ce0a2019-10-12 21:41:20 +01001058 !option_bool(OPT_DNSSEC_IGN_NS) && (forward->sentto->flags & SERV_DO_DNSSEC),
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001059 NULL, NULL, NULL);
Simon Kelley6b173352018-05-08 18:32:14 +01001060#ifdef HAVE_DUMPFILE
1061 if (status == STAT_BOGUS)
1062 dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_BOGUS : DUMP_BOGUS,
1063 header, (size_t)n, &serveraddr, NULL);
1064#endif
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001065 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001066
Simon Kelley9a31b682015-12-15 10:20:39 +00001067 /* Can't validate, as we're missing key data. Put this
1068 answer aside, whilst we get that. */
1069 if (status == STAT_NEED_DS || status == STAT_NEED_KEY)
Simon Kelley3a237152013-12-12 12:15:50 +00001070 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001071 struct frec *new, *orig;
Simon Kelley9d633042013-12-13 15:36:55 +00001072
Simon Kelley9a31b682015-12-15 10:20:39 +00001073 /* Free any saved query */
1074 if (forward->stash)
1075 blockdata_free(forward->stash);
1076
1077 /* Now save reply pending receipt of key data */
1078 if (!(forward->stash = blockdata_alloc((char *)header, n)))
Simon Kelley97e618a2015-01-07 21:55:43 +00001079 return;
Simon Kelley9a31b682015-12-15 10:20:39 +00001080 forward->stash_len = n;
Simon Kelleye0c0ad32014-01-16 22:42:07 +00001081
Simon Kelley9a31b682015-12-15 10:20:39 +00001082 /* Find the original query that started it all.... */
1083 for (orig = forward; orig->dependent; orig = orig->dependent);
Simon Kelley7fa836e2014-02-10 20:11:24 +00001084
Simon Kelley8caf3d72020-04-04 17:00:32 +01001085 /* Make sure we don't expire and free the orig frec during the
1086 allocation of a new one. */
1087 if (--orig->work_counter == 0 || !(new = get_new_frec(now, NULL, orig)))
Simon Kelley9a31b682015-12-15 10:20:39 +00001088 status = STAT_ABANDONED;
Simon Kelleye0c0ad32014-01-16 22:42:07 +00001089 else
Simon Kelley3a237152013-12-12 12:15:50 +00001090 {
Simon Kelleye1791f32018-10-06 23:23:23 +01001091 int querytype, fd, type = SERV_DO_DNSSEC;
Simon Kelley9a31b682015-12-15 10:20:39 +00001092 struct frec *next = new->next;
Simon Kelley92be34a2016-01-16 18:39:54 +00001093 char *domain;
1094
Simon Kelley9a31b682015-12-15 10:20:39 +00001095 *new = *forward; /* copy everything, then overwrite */
1096 new->next = next;
1097 new->blocking_query = NULL;
Simon Kelley92be34a2016-01-16 18:39:54 +00001098
1099 /* Find server to forward to. This will normally be the
1100 same as for the original query, but may be another if
1101 servers for domains are involved. */
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001102 if (search_servers(now, NULL, F_DNSSECOK, daemon->keyname, &type, &domain, NULL) == 0)
Simon Kelley92be34a2016-01-16 18:39:54 +00001103 {
Simon Kelley203ce0a2019-10-12 21:41:20 +01001104 struct server *start, *new_server = NULL;
1105 start = server = forward->sentto;
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001106
1107 while (1)
1108 {
Petr Menšík8f9bd612021-03-27 23:16:09 +00001109 if (server_test_type(start, domain, type, SERV_DO_DNSSEC))
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001110 {
1111 new_server = start;
1112 if (server == start)
1113 {
1114 new_server = NULL;
1115 break;
1116 }
1117 }
1118
1119 if (!(start = start->next))
1120 start = daemon->servers;
1121 if (start == server)
1122 break;
1123 }
1124
1125 if (new_server)
1126 server = new_server;
Simon Kelley92be34a2016-01-16 18:39:54 +00001127 }
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001128
Simon Kelley9a31b682015-12-15 10:20:39 +00001129 new->sentto = server;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00001130 new->rfds = NULL;
Simon Kelley15b60dd2020-11-18 18:34:55 +00001131 new->frec_src.next = NULL;
Simon Kelleya0088e82018-05-10 21:43:14 +01001132 new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_HAS_EXTRADATA);
1133 new->forwardall = 0;
Simon Kelley9a31b682015-12-15 10:20:39 +00001134
1135 new->dependent = forward; /* to find query awaiting new one. */
1136 forward->blocking_query = new; /* for garbage cleaning */
1137 /* validate routines leave name of required record in daemon->keyname */
1138 if (status == STAT_NEED_KEY)
Simon Kelley7fa836e2014-02-10 20:11:24 +00001139 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001140 new->flags |= FREC_DNSKEY_QUERY;
Simon Kelleye1791f32018-10-06 23:23:23 +01001141 querytype = T_DNSKEY;
Simon Kelleyf1668d22014-01-08 16:53:27 +00001142 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001143 else
1144 {
1145 new->flags |= FREC_DS_QUERY;
Simon Kelleye1791f32018-10-06 23:23:23 +01001146 querytype = T_DS;
Simon Kelley9a31b682015-12-15 10:20:39 +00001147 }
Simon Kelleye1791f32018-10-06 23:23:23 +01001148
1149 nn = dnssec_generate_query(header,((unsigned char *) header) + server->edns_pktsz,
1150 daemon->keyname, forward->class, querytype, server->edns_pktsz);
1151
Simon Kelley2d765862020-11-12 22:06:07 +00001152 memcpy(new->hash, hash_questions(header, nn, daemon->namebuff), HASH_SIZE);
Simon Kelley9a31b682015-12-15 10:20:39 +00001153 new->new_id = get_id();
1154 header->id = htons(new->new_id);
1155 /* Save query for retransmission */
1156 new->stash = blockdata_alloc((char *)header, nn);
1157 new->stash_len = nn;
1158
1159 /* Don't resend this. */
1160 daemon->srv_save = NULL;
1161
Simon Kelley74d4fcd2021-03-15 21:59:51 +00001162 if ((fd = allocate_rfd(&new->rfds, server)) != -1)
Simon Kelley9a31b682015-12-15 10:20:39 +00001163 {
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001164#ifdef HAVE_CONNTRACK
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001165 if (option_bool(OPT_CONNTRACK))
Petr Menšík6c0bf792021-03-18 00:07:45 +01001166 set_outgoing_mark(orig, fd);
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001167#endif
Petr Menšík51f7bc92021-03-18 01:05:43 +01001168 server_send_log(server, fd, header, nn, DUMP_SEC_QUERY,
1169 F_NOEXTRA | F_DNSSEC, daemon->keyname,
1170 querystr("dnssec-query", querytype));
Simon Kelley9a31b682015-12-15 10:20:39 +00001171 server->queries++;
1172 }
1173 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00001174 return;
Simon Kelley3a237152013-12-12 12:15:50 +00001175 }
Simon Kelley3a237152013-12-12 12:15:50 +00001176
Simon Kelley9a31b682015-12-15 10:20:39 +00001177 /* Validated original answer, all done. */
1178 if (!forward->dependent)
1179 break;
1180
Josh Soref730c6742017-02-06 16:14:04 +00001181 /* validated subsidiary query, (and cached result)
Simon Kelley9a31b682015-12-15 10:20:39 +00001182 pop that and return to the previous query we were working on. */
Simon Kelley0744ca62014-01-25 16:40:15 +00001183 struct frec *prev = forward->dependent;
1184 free_frec(forward);
1185 forward = prev;
1186 forward->blocking_query = NULL; /* already gone */
1187 blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
1188 n = forward->stash_len;
Simon Kelley3a237152013-12-12 12:15:50 +00001189 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001190
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001191
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001192 no_cache_dnssec = 0;
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001193
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001194 if (status == STAT_TRUNCATED)
Simon Kelley0744ca62014-01-25 16:40:15 +00001195 header->hb3 |= HB3_TC;
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001196 else
Simon Kelley7fa836e2014-02-10 20:11:24 +00001197 {
Simon Kelley554b5802015-04-17 22:50:20 +01001198 char *result, *domain = "result";
Simon Kelley7fa836e2014-02-10 20:11:24 +00001199
Simon Kelley9a31b682015-12-15 10:20:39 +00001200 if (status == STAT_ABANDONED)
Simon Kelley150162b2015-03-27 09:58:26 +00001201 {
1202 result = "ABANDONED";
1203 status = STAT_BOGUS;
1204 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00001205 else
1206 result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
1207
Simon Kelley554b5802015-04-17 22:50:20 +01001208 if (status == STAT_BOGUS && extract_request(header, n, daemon->namebuff, NULL))
1209 domain = daemon->namebuff;
Simon Kelley9a31b682015-12-15 10:20:39 +00001210
Simon Kelley07ed5852018-05-04 21:52:22 +01001211 log_query(F_SECSTAT, domain, NULL, result);
Simon Kelley7fa836e2014-02-10 20:11:24 +00001212 }
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001213
Simon Kelley3a237152013-12-12 12:15:50 +00001214 if (status == STAT_SECURE)
1215 cache_secure = 1;
Simon Kelley3a237152013-12-12 12:15:50 +00001216 else if (status == STAT_BOGUS)
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001217 {
1218 no_cache_dnssec = 1;
1219 bogusanswer = 1;
1220 }
Simon Kelley3a237152013-12-12 12:15:50 +00001221 }
Simon Kelley04db1482019-10-11 23:22:17 +01001222
Simon Kelley6b173352018-05-08 18:32:14 +01001223#endif
1224
Simon Kelley83349b82014-02-10 21:02:01 +00001225 /* restore CD bit to the value in the query */
1226 if (forward->flags & FREC_CHECKING_DISABLED)
1227 header->hb4 |= HB4_CD;
1228 else
1229 header->hb4 &= ~HB4_CD;
Simon Kelley25e63f12020-11-25 21:17:52 +00001230
1231 /* Never cache answers which are contingent on the source or MAC address EDSN0 option,
1232 since the cache is ignorant of such things. */
1233 if (forward->flags & FREC_NO_CACHE)
1234 no_cache_dnssec = 1;
Simon Kelley3a237152013-12-12 12:15:50 +00001235
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001236 if ((nn = process_reply(header, now, forward->sentto, (size_t)n, check_rebind, no_cache_dnssec, cache_secure, bogusanswer,
Simon Kelley613ad152014-02-25 23:02:28 +00001237 forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION,
Simon Kelley15b60dd2020-11-18 18:34:55 +00001238 forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->frec_src.source)))
Simon Kelley832af0b2007-01-21 20:01:28 +00001239 {
Simon Kelley15b60dd2020-11-18 18:34:55 +00001240 struct frec_src *src;
1241
1242 header->id = htons(forward->frec_src.orig_id);
Simon Kelley572b41e2011-02-18 18:11:18 +00001243 header->hb4 |= HB4_RA; /* recursion if available */
Simon Kelley5aa5f0f2015-12-21 17:20:35 +00001244#ifdef HAVE_DNSSEC
1245 /* We added an EDNSO header for the purpose of getting DNSSEC RRs, and set the value of the UDP payload size
Simon Kelley6fd5d792017-10-13 22:26:40 +01001246 greater than the no-EDNS0-implied 512 to have space for the RRSIGS. If, having stripped them and the EDNS0
Simon Kelley5aa5f0f2015-12-21 17:20:35 +00001247 header, the answer is still bigger than 512, truncate it and mark it so. The client then retries with TCP. */
1248 if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER) && (nn > PACKETSZ))
1249 {
1250 header->ancount = htons(0);
1251 header->nscount = htons(0);
1252 header->arcount = htons(0);
1253 header->hb3 |= HB3_TC;
1254 nn = resize_packet(header, nn, NULL, 0);
1255 }
1256#endif
Simon Kelley6b173352018-05-08 18:32:14 +01001257
Simon Kelley15b60dd2020-11-18 18:34:55 +00001258 for (src = &forward->frec_src; src; src = src->next)
1259 {
1260 header->id = htons(src->orig_id);
1261
Simon Kelley6b173352018-05-08 18:32:14 +01001262#ifdef HAVE_DUMPFILE
Simon Kelley15b60dd2020-11-18 18:34:55 +00001263 dump_packet(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &src->source);
Simon Kelley6b173352018-05-08 18:32:14 +01001264#endif
Simon Kelley15b60dd2020-11-18 18:34:55 +00001265
Simon Kelley04490bf2021-01-22 16:49:12 +00001266 send_from(src->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
Simon Kelley15b60dd2020-11-18 18:34:55 +00001267 &src->source, &src->dest, src->iface);
1268
1269 if (option_bool(OPT_EXTRALOG) && src != &forward->frec_src)
1270 {
1271 daemon->log_display_id = src->log_id;
1272 daemon->log_source_addr = &src->source;
1273 log_query(F_UPSTREAM, "query", NULL, "duplicate");
1274 }
1275 }
Simon Kelley832af0b2007-01-21 20:01:28 +00001276 }
Simon Kelley15b60dd2020-11-18 18:34:55 +00001277
Simon Kelley1a6bca82008-07-11 11:11:42 +01001278 free_frec(forward); /* cancel */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001279 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001280}
Simon Kelley44a2a312004-03-10 20:04:35 +00001281
Simon Kelley1a6bca82008-07-11 11:11:42 +01001282
Simon Kelley5aabfc72007-08-29 11:24:47 +01001283void receive_query(struct listener *listen, time_t now)
Simon Kelley44a2a312004-03-10 20:04:35 +00001284{
Simon Kelley572b41e2011-02-18 18:11:18 +00001285 struct dns_header *header = (struct dns_header *)daemon->packet;
Simon Kelley44a2a312004-03-10 20:04:35 +00001286 union mysockaddr source_addr;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001287 unsigned char *pheader;
1288 unsigned short type, udp_size = PACKETSZ; /* default if no EDNS0 */
Simon Kelleycc921df2019-01-02 22:48:59 +00001289 union all_addr dst_addr;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001290 struct in_addr netmask, dst_addr_4;
Simon Kelleycdeda282006-03-16 20:16:06 +00001291 size_t m;
1292 ssize_t n;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001293 int if_index = 0, auth_dns = 0, do_bit = 0, have_pseudoheader = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001294#ifdef HAVE_AUTH
1295 int local_auth = 0;
1296#endif
Simon Kelley44a2a312004-03-10 20:04:35 +00001297 struct iovec iov[1];
1298 struct msghdr msg;
1299 struct cmsghdr *cmptr;
Simon Kelley44a2a312004-03-10 20:04:35 +00001300 union {
1301 struct cmsghdr align; /* this ensures alignment */
Simon Kelley44a2a312004-03-10 20:04:35 +00001302 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001303#if defined(HAVE_LINUX_NETWORK)
Simon Kelley44a2a312004-03-10 20:04:35 +00001304 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
Simon Kelley824af852008-02-12 20:43:05 +00001305#elif defined(IP_RECVDSTADDR) && defined(HAVE_SOLARIS_NETWORK)
1306 char control[CMSG_SPACE(sizeof(struct in_addr)) +
1307 CMSG_SPACE(sizeof(unsigned int))];
Simon Kelley44a2a312004-03-10 20:04:35 +00001308#elif defined(IP_RECVDSTADDR)
1309 char control[CMSG_SPACE(sizeof(struct in_addr)) +
1310 CMSG_SPACE(sizeof(struct sockaddr_dl))];
1311#endif
1312 } control_u;
Petr Menšík1c1b9252019-07-15 17:16:44 +02001313 int family = listen->addr.sa.sa_family;
Simon Kelley2329bef2013-12-03 13:41:16 +00001314 /* Can always get recvd interface for IPv6 */
Petr Menšík1c1b9252019-07-15 17:16:44 +02001315 int check_dst = !option_bool(OPT_NOWILD) || family == AF_INET6;
Simon Kelley2329bef2013-12-03 13:41:16 +00001316
Simon Kelleycdeda282006-03-16 20:16:06 +00001317 /* packet buffer overwritten */
1318 daemon->srv_save = NULL;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00001319
Simon Kelleycc921df2019-01-02 22:48:59 +00001320 dst_addr_4.s_addr = dst_addr.addr4.s_addr = 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001321 netmask.s_addr = 0;
1322
Simon Kelley7e5664b2013-04-05 16:57:41 +01001323 if (option_bool(OPT_NOWILD) && listen->iface)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001324 {
Simon Kelley4f7b3042012-11-28 21:27:02 +00001325 auth_dns = listen->iface->dns_auth;
1326
Petr Menšík1c1b9252019-07-15 17:16:44 +02001327 if (family == AF_INET)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001328 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001329 dst_addr_4 = dst_addr.addr4 = listen->iface->addr.in.sin_addr;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001330 netmask = listen->iface->netmask;
1331 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001332 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00001333
Simon Kelley3be34542004-09-11 19:12:13 +01001334 iov[0].iov_base = daemon->packet;
1335 iov[0].iov_len = daemon->edns_pktsz;
Simon Kelley44a2a312004-03-10 20:04:35 +00001336
1337 msg.msg_control = control_u.control;
1338 msg.msg_controllen = sizeof(control_u);
1339 msg.msg_flags = 0;
1340 msg.msg_name = &source_addr;
1341 msg.msg_namelen = sizeof(source_addr);
1342 msg.msg_iov = iov;
1343 msg.msg_iovlen = 1;
1344
Simon Kelleyde379512004-06-22 20:23:33 +01001345 if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
Simon Kelley3be34542004-09-11 19:12:13 +01001346 return;
Simon Kelley44a2a312004-03-10 20:04:35 +00001347
Simon Kelley572b41e2011-02-18 18:11:18 +00001348 if (n < (int)sizeof(struct dns_header) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001349 (msg.msg_flags & MSG_TRUNC) ||
Simon Kelley572b41e2011-02-18 18:11:18 +00001350 (header->hb3 & HB3_QR))
Simon Kelley3be34542004-09-11 19:12:13 +01001351 return;
Simon Kelley63437ff2017-09-06 22:34:21 +01001352
1353 /* Clear buffer beyond request to avoid risk of
1354 information disclosure. */
1355 memset(daemon->packet + n, 0, daemon->edns_pktsz - n);
Simon Kelley44a2a312004-03-10 20:04:35 +00001356
Petr Menšík1c1b9252019-07-15 17:16:44 +02001357 source_addr.sa.sa_family = family;
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001358
Petr Menšík1c1b9252019-07-15 17:16:44 +02001359 if (family == AF_INET)
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001360 {
1361 /* Source-port == 0 is an error, we can't send back to that.
1362 http://www.ietf.org/mail-archive/web/dnsop/current/msg11441.html */
1363 if (source_addr.in.sin_port == 0)
1364 return;
1365 }
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001366 else
1367 {
1368 /* Source-port == 0 is an error, we can't send back to that. */
1369 if (source_addr.in6.sin6_port == 0)
1370 return;
1371 source_addr.in6.sin6_flowinfo = 0;
1372 }
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001373
Simon Kelleyc8a80482014-03-05 14:29:54 +00001374 /* We can be configured to only accept queries from at-most-one-hop-away addresses. */
1375 if (option_bool(OPT_LOCAL_SERVICE))
1376 {
1377 struct addrlist *addr;
Simon Kelleyee875042018-10-23 22:10:17 +01001378
Petr Menšík1c1b9252019-07-15 17:16:44 +02001379 if (family == AF_INET6)
Simon Kelleyc8a80482014-03-05 14:29:54 +00001380 {
1381 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1382 if ((addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001383 is_same_net6(&addr->addr.addr6, &source_addr.in6.sin6_addr, addr->prefixlen))
Simon Kelleyc8a80482014-03-05 14:29:54 +00001384 break;
1385 }
1386 else
Simon Kelleyc8a80482014-03-05 14:29:54 +00001387 {
1388 struct in_addr netmask;
1389 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1390 {
Richard Genoud15b1b7e2014-09-17 21:12:00 +01001391 netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
Simon Kelleyc8a80482014-03-05 14:29:54 +00001392 if (!(addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001393 is_same_net(addr->addr.addr4, source_addr.in.sin_addr, netmask))
Simon Kelleyc8a80482014-03-05 14:29:54 +00001394 break;
1395 }
1396 }
1397 if (!addr)
1398 {
Simon Kelley0c8584e2014-03-12 20:12:56 +00001399 static int warned = 0;
1400 if (!warned)
1401 {
1402 my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
1403 warned = 1;
1404 }
Simon Kelleyc8a80482014-03-05 14:29:54 +00001405 return;
1406 }
1407 }
1408
Simon Kelley2329bef2013-12-03 13:41:16 +00001409 if (check_dst)
Simon Kelley44a2a312004-03-10 20:04:35 +00001410 {
Simon Kelley8a911cc2004-03-16 18:35:52 +00001411 struct ifreq ifr;
1412
Simon Kelley26128d22004-11-14 16:43:54 +00001413 if (msg.msg_controllen < sizeof(struct cmsghdr))
1414 return;
1415
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001416#if defined(HAVE_LINUX_NETWORK)
Petr Menšík1c1b9252019-07-15 17:16:44 +02001417 if (family == AF_INET)
Simon Kelley26128d22004-11-14 16:43:54 +00001418 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelleyc72daea2012-01-05 21:33:27 +00001419 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
Simon Kelley26128d22004-11-14 16:43:54 +00001420 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001421 union {
1422 unsigned char *c;
1423 struct in_pktinfo *p;
1424 } p;
1425 p.c = CMSG_DATA(cmptr);
Simon Kelleycc921df2019-01-02 22:48:59 +00001426 dst_addr_4 = dst_addr.addr4 = p.p->ipi_spec_dst;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001427 if_index = p.p->ipi_ifindex;
Simon Kelley26128d22004-11-14 16:43:54 +00001428 }
1429#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
Petr Menšík1c1b9252019-07-15 17:16:44 +02001430 if (family == AF_INET)
Simon Kelley26128d22004-11-14 16:43:54 +00001431 {
1432 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001433 {
1434 union {
1435 unsigned char *c;
1436 unsigned int *i;
1437 struct in_addr *a;
1438#ifndef HAVE_SOLARIS_NETWORK
1439 struct sockaddr_dl *s;
Simon Kelley824af852008-02-12 20:43:05 +00001440#endif
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001441 } p;
1442 p.c = CMSG_DATA(cmptr);
1443 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
Simon Kelleycc921df2019-01-02 22:48:59 +00001444 dst_addr_4 = dst_addr.addr4 = *(p.a);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001445 else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
1446#ifdef HAVE_SOLARIS_NETWORK
1447 if_index = *(p.i);
1448#else
1449 if_index = p.s->sdl_index;
1450#endif
1451 }
Simon Kelley26128d22004-11-14 16:43:54 +00001452 }
1453#endif
1454
Petr Menšík1c1b9252019-07-15 17:16:44 +02001455 if (family == AF_INET6)
Simon Kelley26128d22004-11-14 16:43:54 +00001456 {
1457 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelleyc72daea2012-01-05 21:33:27 +00001458 if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
Simon Kelley26128d22004-11-14 16:43:54 +00001459 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001460 union {
1461 unsigned char *c;
1462 struct in6_pktinfo *p;
1463 } p;
1464 p.c = CMSG_DATA(cmptr);
1465
Simon Kelleycc921df2019-01-02 22:48:59 +00001466 dst_addr.addr6 = p.p->ipi6_addr;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001467 if_index = p.p->ipi6_ifindex;
Simon Kelley26128d22004-11-14 16:43:54 +00001468 }
1469 }
Simon Kelley26128d22004-11-14 16:43:54 +00001470
1471 /* enforce available interface configuration */
1472
Simon Kelleye25db1f2013-01-29 22:10:26 +00001473 if (!indextoname(listen->fd, if_index, ifr.ifr_name))
Simon Kelley832af0b2007-01-21 20:01:28 +00001474 return;
1475
Petr Menšík1c1b9252019-07-15 17:16:44 +02001476 if (!iface_check(family, &dst_addr, ifr.ifr_name, &auth_dns))
Simon Kelleye25db1f2013-01-29 22:10:26 +00001477 {
1478 if (!option_bool(OPT_CLEVERBIND))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001479 enumerate_interfaces(0);
Petr Menšík1c1b9252019-07-15 17:16:44 +02001480 if (!loopback_exception(listen->fd, family, &dst_addr, ifr.ifr_name) &&
1481 !label_exception(if_index, family, &dst_addr))
Simon Kelleye25db1f2013-01-29 22:10:26 +00001482 return;
1483 }
1484
Petr Menšík1c1b9252019-07-15 17:16:44 +02001485 if (family == AF_INET && option_bool(OPT_LOCALISE))
Simon Kelley552af8b2012-02-29 20:10:31 +00001486 {
1487 struct irec *iface;
1488
Josh Soref730c6742017-02-06 16:14:04 +00001489 /* get the netmask of the interface which has the address we were sent to.
klemens43517fc2017-02-19 15:53:37 +00001490 This is no necessarily the interface we arrived on. */
Simon Kelley552af8b2012-02-29 20:10:31 +00001491
1492 for (iface = daemon->interfaces; iface; iface = iface->next)
1493 if (iface->addr.sa.sa_family == AF_INET &&
1494 iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
1495 break;
1496
1497 /* interface may be new */
Simon Kelleye25db1f2013-01-29 22:10:26 +00001498 if (!iface && !option_bool(OPT_CLEVERBIND))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001499 enumerate_interfaces(0);
Simon Kelley552af8b2012-02-29 20:10:31 +00001500
1501 for (iface = daemon->interfaces; iface; iface = iface->next)
1502 if (iface->addr.sa.sa_family == AF_INET &&
1503 iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
1504 break;
1505
1506 /* If we failed, abandon localisation */
1507 if (iface)
1508 netmask = iface->netmask;
1509 else
1510 dst_addr_4.s_addr = 0;
1511 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001512 }
Simon Kelley25cf5e32015-01-09 15:53:03 +00001513
1514 /* log_query gets called indirectly all over the place, so
1515 pass these in global variables - sorry. */
1516 daemon->log_display_id = ++daemon->log_id;
1517 daemon->log_source_addr = &source_addr;
Simon Kelley6b173352018-05-08 18:32:14 +01001518
1519#ifdef HAVE_DUMPFILE
1520 dump_packet(DUMP_QUERY, daemon->packet, (size_t)n, &source_addr, NULL);
1521#endif
1522
Simon Kelleycdeda282006-03-16 20:16:06 +00001523 if (extract_request(header, (size_t)n, daemon->namebuff, &type))
Simon Kelley44a2a312004-03-10 20:04:35 +00001524 {
Simon Kelleyb485ed92013-10-18 22:00:39 +01001525#ifdef HAVE_AUTH
1526 struct auth_zone *zone;
1527#endif
Simon Kelley610e7822014-02-06 14:45:17 +00001528 char *types = querystr(auth_dns ? "auth" : "query", type);
Petr Menšík6c0bf792021-03-18 00:07:45 +01001529
1530 log_query_mysockaddr(F_QUERY | F_FORWARD, daemon->namebuff,
1531 &source_addr, types);
Simon Kelley44a2a312004-03-10 20:04:35 +00001532
Simon Kelley4820dce2012-12-18 18:30:30 +00001533#ifdef HAVE_AUTH
Simon Kelleyb485ed92013-10-18 22:00:39 +01001534 /* find queries for zones we're authoritative for, and answer them directly */
Simon Kelley3a3965a2015-08-09 17:45:06 +01001535 if (!auth_dns && !option_bool(OPT_LOCALISE))
Simon Kelley6008bdb2013-10-21 21:47:03 +01001536 for (zone = daemon->auth_zones; zone; zone = zone->next)
1537 if (in_zone(zone, daemon->namebuff, NULL))
1538 {
1539 auth_dns = 1;
1540 local_auth = 1;
1541 break;
1542 }
Simon Kelleyb485ed92013-10-18 22:00:39 +01001543#endif
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01001544
1545#ifdef HAVE_LOOP
1546 /* Check for forwarding loop */
1547 if (detect_loop(daemon->namebuff, type))
1548 return;
1549#endif
Simon Kelleyb485ed92013-10-18 22:00:39 +01001550 }
1551
Simon Kelley5bb88f02015-12-21 16:23:47 +00001552 if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL, NULL))
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001553 {
1554 unsigned short flags;
1555
1556 have_pseudoheader = 1;
1557 GETSHORT(udp_size, pheader);
1558 pheader += 2; /* ext_rcode */
1559 GETSHORT(flags, pheader);
1560
1561 if (flags & 0x8000)
1562 do_bit = 1;/* do bit */
1563
1564 /* If the client provides an EDNS0 UDP size, use that to limit our reply.
1565 (bounded by the maximum configured). If no EDNS0, then it
1566 defaults to 512 */
1567 if (udp_size > daemon->edns_pktsz)
1568 udp_size = daemon->edns_pktsz;
Simon Kelleya3303e12017-09-07 20:45:00 +01001569 else if (udp_size < PACKETSZ)
1570 udp_size = PACKETSZ; /* Sanity check - can't reduce below default. RFC 6891 6.2.3 */
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001571 }
1572
Simon Kelleyb485ed92013-10-18 22:00:39 +01001573#ifdef HAVE_AUTH
Simon Kelley4f7b3042012-11-28 21:27:02 +00001574 if (auth_dns)
Simon Kelley824af852008-02-12 20:43:05 +00001575 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001576 m = answer_auth(header, ((char *) header) + udp_size, (size_t)n, now, &source_addr,
1577 local_auth, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001578 if (m >= 1)
Simon Kelleyb485ed92013-10-18 22:00:39 +01001579 {
1580 send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
1581 (char *)header, m, &source_addr, &dst_addr, if_index);
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001582 daemon->metrics[METRIC_DNS_AUTH_ANSWERED]++;
Simon Kelleyb485ed92013-10-18 22:00:39 +01001583 }
Simon Kelley824af852008-02-12 20:43:05 +00001584 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001585 else
Simon Kelley4820dce2012-12-18 18:30:30 +00001586#endif
Simon Kelley4f7b3042012-11-28 21:27:02 +00001587 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001588 int ad_reqd = do_bit;
1589 /* RFC 6840 5.7 */
1590 if (header->hb4 & HB4_AD)
1591 ad_reqd = 1;
1592
1593 m = answer_request(header, ((char *) header) + udp_size, (size_t)n,
1594 dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001595
1596 if (m >= 1)
1597 {
1598 send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
1599 (char *)header, m, &source_addr, &dst_addr, if_index);
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001600 daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001601 }
1602 else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
Simon Kelley613ad152014-02-25 23:02:28 +00001603 header, (size_t)n, now, NULL, ad_reqd, do_bit))
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001604 daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]++;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001605 else
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001606 daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001607 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001608}
1609
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001610#ifdef HAVE_DNSSEC
Josh Soref730c6742017-02-06 16:14:04 +00001611/* Recurse up the key hierarchy */
Simon Kelley7fa836e2014-02-10 20:11:24 +00001612static int tcp_key_recurse(time_t now, int status, struct dns_header *header, size_t n,
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001613 int class, char *name, char *keyname, struct server *server,
1614 int have_mark, unsigned int mark, int *keycount)
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001615{
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001616 int new_status;
Simon Kelley9a31b682015-12-15 10:20:39 +00001617 unsigned char *packet = NULL;
Simon Kelley9a31b682015-12-15 10:20:39 +00001618 unsigned char *payload = NULL;
1619 struct dns_header *new_header = NULL;
1620 u16 *length = NULL;
Simon Kelley361dfe52017-02-10 21:12:30 +00001621
Simon Kelley9a31b682015-12-15 10:20:39 +00001622 while (1)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001623 {
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001624 int type = SERV_DO_DNSSEC;
1625 char *domain;
1626 size_t m;
1627 unsigned char c1, c2;
Simon Kelley361dfe52017-02-10 21:12:30 +00001628 struct server *firstsendto = NULL;
1629
Simon Kelley9a31b682015-12-15 10:20:39 +00001630 /* limit the amount of work we do, to avoid cycling forever on loops in the DNS */
1631 if (--(*keycount) == 0)
1632 new_status = STAT_ABANDONED;
1633 else if (status == STAT_NEED_KEY)
1634 new_status = dnssec_validate_by_ds(now, header, n, name, keyname, class);
1635 else if (status == STAT_NEED_DS)
1636 new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
1637 else
James Bottomleye33b4872017-03-17 21:44:10 +00001638 new_status = dnssec_validate_reply(now, header, n, name, keyname, &class,
Simon Kelleya6918532018-04-15 16:20:52 +01001639 !option_bool(OPT_DNSSEC_IGN_NS) && (server->flags & SERV_DO_DNSSEC),
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001640 NULL, NULL, NULL);
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001641
Simon Kelley9a31b682015-12-15 10:20:39 +00001642 if (new_status != STAT_NEED_DS && new_status != STAT_NEED_KEY)
1643 break;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001644
Simon Kelley9a31b682015-12-15 10:20:39 +00001645 /* Can't validate because we need a key/DS whose name now in keyname.
1646 Make query for same, and recurse to validate */
Simon Kelley7fa836e2014-02-10 20:11:24 +00001647 if (!packet)
Simon Kelley9a31b682015-12-15 10:20:39 +00001648 {
1649 packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
1650 payload = &packet[2];
1651 new_header = (struct dns_header *)payload;
1652 length = (u16 *)packet;
1653 }
1654
1655 if (!packet)
1656 {
1657 new_status = STAT_ABANDONED;
1658 break;
1659 }
Simon Kelleye1791f32018-10-06 23:23:23 +01001660
Simon Kelley33702ab2015-12-28 23:17:15 +00001661 m = dnssec_generate_query(new_header, ((unsigned char *) new_header) + 65536, keyname, class,
Simon Kelleye1791f32018-10-06 23:23:23 +01001662 new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS, server->edns_pktsz);
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001663
Simon Kelley7fa836e2014-02-10 20:11:24 +00001664 *length = htons(m);
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001665
1666 /* Find server to forward to. This will normally be the
1667 same as for the original query, but may be another if
1668 servers for domains are involved. */
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001669 if (search_servers(now, NULL, F_DNSSECOK, keyname, &type, &domain, NULL) != 0)
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001670 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001671 new_status = STAT_ABANDONED;
1672 break;
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001673 }
Simon Kelley361dfe52017-02-10 21:12:30 +00001674
Simon Kelley361dfe52017-02-10 21:12:30 +00001675 while (1)
1676 {
Simon Kelley608aa9f2019-03-10 22:44:15 +00001677 int data_sent = 0;
1678
Simon Kelley361dfe52017-02-10 21:12:30 +00001679 if (!firstsendto)
1680 firstsendto = server;
1681 else
1682 {
1683 if (!(server = server->next))
1684 server = daemon->servers;
1685 if (server == firstsendto)
1686 {
1687 /* can't find server to accept our query. */
1688 new_status = STAT_ABANDONED;
1689 break;
1690 }
1691 }
1692
Petr Menšíke10a9232021-03-15 11:20:49 +01001693 if (!server_test_type(server, domain, type, SERV_DO_DNSSEC))
Simon Kelley361dfe52017-02-10 21:12:30 +00001694 continue;
Simon Kelleye1791f32018-10-06 23:23:23 +01001695
1696 retry:
1697 /* may need to make new connection. */
1698 if (server->tcpfd == -1)
1699 {
1700 if ((server->tcpfd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
1701 continue; /* No good, next server */
1702
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001703#ifdef HAVE_CONNTRACK
Simon Kelleye1791f32018-10-06 23:23:23 +01001704 /* Copy connection mark of incoming query to outgoing connection. */
1705 if (have_mark)
1706 setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001707#endif
Simon Kelleye1791f32018-10-06 23:23:23 +01001708
Simon Kelley608aa9f2019-03-10 22:44:15 +00001709 if (!local_bind(server->tcpfd, &server->source_addr, server->interface, 0, 1))
1710 {
1711 close(server->tcpfd);
1712 server->tcpfd = -1;
1713 continue; /* No good, next server */
1714 }
1715
1716#ifdef MSG_FASTOPEN
Petr Menšík51f7bc92021-03-18 01:05:43 +01001717 server_send(server, server->tcpfd, packet, m + sizeof(u16), MSG_FASTOPEN);
1718
Simon Kelley608aa9f2019-03-10 22:44:15 +00001719 if (errno == 0)
1720 data_sent = 1;
1721#endif
1722
1723 if (!data_sent && connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) == -1)
Simon Kelleye1791f32018-10-06 23:23:23 +01001724 {
1725 close(server->tcpfd);
1726 server->tcpfd = -1;
1727 continue; /* No good, next server */
1728 }
1729
1730 server->flags &= ~SERV_GOT_TCP;
1731 }
Simon Kelley361dfe52017-02-10 21:12:30 +00001732
Simon Kelley608aa9f2019-03-10 22:44:15 +00001733 if ((!data_sent && !read_write(server->tcpfd, packet, m + sizeof(u16), 0)) ||
Simon Kelley361dfe52017-02-10 21:12:30 +00001734 !read_write(server->tcpfd, &c1, 1, 1) ||
1735 !read_write(server->tcpfd, &c2, 1, 1) ||
1736 !read_write(server->tcpfd, payload, (c1 << 8) | c2, 1))
1737 {
1738 close(server->tcpfd);
1739 server->tcpfd = -1;
1740 /* We get data then EOF, reopen connection to same server,
1741 else try next. This avoids DoS from a server which accepts
1742 connections and then closes them. */
1743 if (server->flags & SERV_GOT_TCP)
1744 goto retry;
1745 else
1746 continue;
1747 }
Simon Kelleye1791f32018-10-06 23:23:23 +01001748
Petr Menšík6c0bf792021-03-18 00:07:45 +01001749 log_query_mysockaddr(F_NOEXTRA | F_DNSSEC, keyname, &server->addr,
1750 querystr("dnssec-query", new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS));
Simon Kelleye1791f32018-10-06 23:23:23 +01001751
Simon Kelley361dfe52017-02-10 21:12:30 +00001752 server->flags |= SERV_GOT_TCP;
1753
1754 m = (c1 << 8) | c2;
1755 new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, have_mark, mark, keycount);
1756 break;
1757 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001758
1759 if (new_status != STAT_OK)
1760 break;
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001761 }
Simon Kelley361dfe52017-02-10 21:12:30 +00001762
Simon Kelley9a31b682015-12-15 10:20:39 +00001763 if (packet)
1764 free(packet);
1765
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001766 return new_status;
1767}
1768#endif
1769
1770
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001771/* The daemon forks before calling this: it should deal with one connection,
Josh Soref730c6742017-02-06 16:14:04 +00001772 blocking as necessary, and then return. Note, need to be a bit careful
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001773 about resources for debug mode, when the fork is suppressed: that's
1774 done by the caller. */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001775unsigned char *tcp_request(int confd, time_t now,
Simon Kelley4f7b3042012-11-28 21:27:02 +00001776 union mysockaddr *local_addr, struct in_addr netmask, int auth_dns)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001777{
Simon Kelley28866e92011-02-14 20:19:14 +00001778 size_t size = 0;
1779 int norebind = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001780#ifdef HAVE_AUTH
Simon Kelley19b16892013-10-20 10:19:39 +01001781 int local_auth = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001782#endif
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001783 int checking_disabled, do_bit, added_pheader = 0, have_pseudoheader = 0;
Simon Kelley25e63f12020-11-25 21:17:52 +00001784 int check_subnet, cacheable, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
Simon Kelleycdeda282006-03-16 20:16:06 +00001785 size_t m;
Simon Kelleyee86ce62012-12-07 11:54:46 +00001786 unsigned short qtype;
1787 unsigned int gotname;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001788 unsigned char c1, c2;
Simon Kelley4b5ea122013-04-22 10:18:26 +01001789 /* Max TCP packet + slop + size */
1790 unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
1791 unsigned char *payload = &packet[2];
1792 /* largest field in header is 16-bits, so this is still sufficiently aligned */
1793 struct dns_header *header = (struct dns_header *)payload;
1794 u16 *length = (u16 *)packet;
Simon Kelley3be34542004-09-11 19:12:13 +01001795 struct server *last_server;
Simon Kelley7de060b2011-08-26 17:24:52 +01001796 struct in_addr dst_addr_4;
1797 union mysockaddr peer_addr;
1798 socklen_t peer_len = sizeof(union mysockaddr);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001799 int query_count = 0;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001800 unsigned char *pheader;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001801 unsigned int mark = 0;
1802 int have_mark = 0;
Simon Kelley25cf5e32015-01-09 15:53:03 +00001803
Simon Kelleyd05dd582016-01-19 21:23:30 +00001804 (void)mark;
1805 (void)have_mark;
1806
Simon Kelley7de060b2011-08-26 17:24:52 +01001807 if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
1808 return packet;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001809
1810#ifdef HAVE_CONNTRACK
1811 /* Get connection mark of incoming query to set on outgoing connections. */
1812 if (option_bool(OPT_CONNTRACK))
1813 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001814 union all_addr local;
Simon Kelleyee875042018-10-23 22:10:17 +01001815
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001816 if (local_addr->sa.sa_family == AF_INET6)
Simon Kelleycc921df2019-01-02 22:48:59 +00001817 local.addr6 = local_addr->in6.sin6_addr;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001818 else
Simon Kelleycc921df2019-01-02 22:48:59 +00001819 local.addr4 = local_addr->in.sin_addr;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001820
1821 have_mark = get_incoming_mark(&peer_addr, &local, 1, &mark);
1822 }
1823#endif
1824
Simon Kelleyc8a80482014-03-05 14:29:54 +00001825 /* We can be configured to only accept queries from at-most-one-hop-away addresses. */
1826 if (option_bool(OPT_LOCAL_SERVICE))
1827 {
1828 struct addrlist *addr;
Simon Kelleyee875042018-10-23 22:10:17 +01001829
Simon Kelleyc8a80482014-03-05 14:29:54 +00001830 if (peer_addr.sa.sa_family == AF_INET6)
1831 {
1832 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1833 if ((addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001834 is_same_net6(&addr->addr.addr6, &peer_addr.in6.sin6_addr, addr->prefixlen))
Simon Kelleyc8a80482014-03-05 14:29:54 +00001835 break;
1836 }
1837 else
Simon Kelleyc8a80482014-03-05 14:29:54 +00001838 {
1839 struct in_addr netmask;
1840 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1841 {
Richard Genoud15b1b7e2014-09-17 21:12:00 +01001842 netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
Simon Kelleyc8a80482014-03-05 14:29:54 +00001843 if (!(addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001844 is_same_net(addr->addr.addr4, peer_addr.in.sin_addr, netmask))
Simon Kelleyc8a80482014-03-05 14:29:54 +00001845 break;
1846 }
1847 }
1848 if (!addr)
1849 {
1850 my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
1851 return packet;
1852 }
1853 }
Simon Kelley7de060b2011-08-26 17:24:52 +01001854
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001855 while (1)
1856 {
Simon Kelley25cf5e32015-01-09 15:53:03 +00001857 if (query_count == TCP_MAX_QUERIES ||
1858 !packet ||
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001859 !read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
1860 !(size = c1 << 8 | c2) ||
Simon Kelley4b5ea122013-04-22 10:18:26 +01001861 !read_write(confd, payload, size, 1))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001862 return packet;
1863
Simon Kelley572b41e2011-02-18 18:11:18 +00001864 if (size < (int)sizeof(struct dns_header))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001865 continue;
Simon Kelley63437ff2017-09-06 22:34:21 +01001866
1867 /* Clear buffer beyond request to avoid risk of
1868 information disclosure. */
1869 memset(payload + size, 0, 65536 - size);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001870
Simon Kelley25cf5e32015-01-09 15:53:03 +00001871 query_count++;
1872
1873 /* log_query gets called indirectly all over the place, so
1874 pass these in global variables - sorry. */
1875 daemon->log_display_id = ++daemon->log_id;
1876 daemon->log_source_addr = &peer_addr;
1877
Simon Kelley28866e92011-02-14 20:19:14 +00001878 /* save state of "cd" flag in query */
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001879 if ((checking_disabled = header->hb4 & HB4_CD))
1880 no_cache_dnssec = 1;
Simon Kelley28866e92011-02-14 20:19:14 +00001881
Simon Kelley3be34542004-09-11 19:12:13 +01001882 if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001883 {
Simon Kelleyb485ed92013-10-18 22:00:39 +01001884#ifdef HAVE_AUTH
1885 struct auth_zone *zone;
1886#endif
Simon Kelley610e7822014-02-06 14:45:17 +00001887 char *types = querystr(auth_dns ? "auth" : "query", qtype);
Simon Kelley7de060b2011-08-26 17:24:52 +01001888
Petr Menšík6c0bf792021-03-18 00:07:45 +01001889 log_query_mysockaddr(F_QUERY | F_FORWARD, daemon->namebuff,
1890 &peer_addr, types);
Simon Kelleyb485ed92013-10-18 22:00:39 +01001891
1892#ifdef HAVE_AUTH
1893 /* find queries for zones we're authoritative for, and answer them directly */
Simon Kelley3a3965a2015-08-09 17:45:06 +01001894 if (!auth_dns && !option_bool(OPT_LOCALISE))
Simon Kelley6008bdb2013-10-21 21:47:03 +01001895 for (zone = daemon->auth_zones; zone; zone = zone->next)
1896 if (in_zone(zone, daemon->namebuff, NULL))
1897 {
1898 auth_dns = 1;
1899 local_auth = 1;
1900 break;
1901 }
Simon Kelleyb485ed92013-10-18 22:00:39 +01001902#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001903 }
1904
Simon Kelley7de060b2011-08-26 17:24:52 +01001905 if (local_addr->sa.sa_family == AF_INET)
1906 dst_addr_4 = local_addr->in.sin_addr;
1907 else
1908 dst_addr_4.s_addr = 0;
1909
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001910 do_bit = 0;
1911
Simon Kelley5bb88f02015-12-21 16:23:47 +00001912 if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL, NULL))
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001913 {
1914 unsigned short flags;
1915
1916 have_pseudoheader = 1;
1917 pheader += 4; /* udp_size, ext_rcode */
1918 GETSHORT(flags, pheader);
1919
1920 if (flags & 0x8000)
Simon Kelley5bb88f02015-12-21 16:23:47 +00001921 do_bit = 1; /* do bit */
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001922 }
1923
Simon Kelley4820dce2012-12-18 18:30:30 +00001924#ifdef HAVE_AUTH
Simon Kelley4f7b3042012-11-28 21:27:02 +00001925 if (auth_dns)
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001926 m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr,
1927 local_auth, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001928 else
Simon Kelley4820dce2012-12-18 18:30:30 +00001929#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001930 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001931 int ad_reqd = do_bit;
1932 /* RFC 6840 5.7 */
1933 if (header->hb4 & HB4_AD)
1934 ad_reqd = 1;
1935
1936 /* m > 0 if answered from cache */
1937 m = answer_request(header, ((char *) header) + 65536, (size_t)size,
1938 dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001939
Simon Kelley4f7b3042012-11-28 21:27:02 +00001940 /* Do this by steam now we're not in the select() loop */
Simon Kelleyb842bc92015-07-12 21:09:11 +01001941 check_log_writer(1);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001942
1943 if (m == 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001944 {
Simon Kelley4f7b3042012-11-28 21:27:02 +00001945 unsigned int flags = 0;
Simon Kelleycc921df2019-01-02 22:48:59 +00001946 union all_addr *addrp = NULL;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001947 int type = SERV_DO_DNSSEC;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001948 char *domain = NULL;
Simon Kelley6fd5d792017-10-13 22:26:40 +01001949 unsigned char *oph = find_pseudoheader(header, size, NULL, NULL, NULL, NULL);
Simon Kelleyed4c0762013-10-08 20:46:34 +01001950
Simon Kelley25e63f12020-11-25 21:17:52 +00001951 size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet, &cacheable);
Simon Kelley6fd5d792017-10-13 22:26:40 +01001952
Simon Kelley4f7b3042012-11-28 21:27:02 +00001953 if (gotname)
1954 flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
Simon Kelley6fd5d792017-10-13 22:26:40 +01001955
1956#ifdef HAVE_DNSSEC
1957 if (option_bool(OPT_DNSSEC_VALID) && (type & SERV_DO_DNSSEC))
1958 {
1959 size = add_do_bit(header, size, ((unsigned char *) header) + 65536);
1960
1961 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
1962 this allows it to select auth servers when one is returning bad data. */
1963 if (option_bool(OPT_DNSSEC_DEBUG))
1964 header->hb4 |= HB4_CD;
1965 }
1966#endif
1967
1968 /* Check if we added a pheader on forwarding - may need to
1969 strip it from the reply. */
1970 if (!oph && find_pseudoheader(header, size, NULL, NULL, NULL, NULL))
1971 added_pheader = 1;
1972
Simon Kelley367341f2016-01-12 15:58:23 +00001973 type &= ~SERV_DO_DNSSEC;
Simon Kelley367341f2016-01-12 15:58:23 +00001974
Simon Kelley4f7b3042012-11-28 21:27:02 +00001975 if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server)
1976 last_server = daemon->servers;
1977 else
1978 last_server = daemon->last_server;
1979
1980 if (!flags && last_server)
1981 {
1982 struct server *firstsendto = NULL;
Simon Kelley2d765862020-11-12 22:06:07 +00001983 unsigned char hash[HASH_SIZE];
1984 memcpy(hash, hash_questions(header, (unsigned int)size, daemon->namebuff), HASH_SIZE);
1985
Simon Kelley4f7b3042012-11-28 21:27:02 +00001986 /* Loop round available servers until we succeed in connecting to one.
Josh Soref730c6742017-02-06 16:14:04 +00001987 Note that this code subtly ensures that consecutive queries on this connection
Simon Kelley4f7b3042012-11-28 21:27:02 +00001988 which can go to the same server, do so. */
1989 while (1)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001990 {
Simon Kelley608aa9f2019-03-10 22:44:15 +00001991 int data_sent = 0;
1992
Simon Kelley4f7b3042012-11-28 21:27:02 +00001993 if (!firstsendto)
1994 firstsendto = last_server;
1995 else
1996 {
1997 if (!(last_server = last_server->next))
1998 last_server = daemon->servers;
1999
2000 if (last_server == firstsendto)
2001 break;
2002 }
2003
2004 /* server for wrong domain */
Petr Menšíke10a9232021-03-15 11:20:49 +01002005 if (!server_test_type(last_server, domain, type, 0))
Simon Kelley7de060b2011-08-26 17:24:52 +01002006 continue;
Simon Kelley361dfe52017-02-10 21:12:30 +00002007
2008 retry:
Simon Kelley608aa9f2019-03-10 22:44:15 +00002009 *length = htons(size);
2010
Simon Kelley4f7b3042012-11-28 21:27:02 +00002011 if (last_server->tcpfd == -1)
2012 {
2013 if ((last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
2014 continue;
2015
Karl Vogele9828b62014-10-03 21:45:15 +01002016#ifdef HAVE_CONNTRACK
2017 /* Copy connection mark of incoming query to outgoing connection. */
Simon Kelleyf344dbc2016-01-18 18:04:17 +00002018 if (have_mark)
2019 setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
Simon Kelley608aa9f2019-03-10 22:44:15 +00002020#endif
Karl Vogele9828b62014-10-03 21:45:15 +01002021
Simon Kelley608aa9f2019-03-10 22:44:15 +00002022 if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 0, 1)))
2023 {
2024 close(last_server->tcpfd);
2025 last_server->tcpfd = -1;
2026 continue;
2027 }
2028
2029#ifdef MSG_FASTOPEN
黎醒聪ffa46282021-03-22 22:00:26 +00002030 server_send(last_server, last_server->tcpfd, packet, size + sizeof(u16), MSG_FASTOPEN);
Petr Menšík51f7bc92021-03-18 01:05:43 +01002031
Simon Kelley608aa9f2019-03-10 22:44:15 +00002032 if (errno == 0)
2033 data_sent = 1;
2034#endif
2035
2036 if (!data_sent && connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1)
Simon Kelley4f7b3042012-11-28 21:27:02 +00002037 {
2038 close(last_server->tcpfd);
2039 last_server->tcpfd = -1;
2040 continue;
2041 }
2042
Simon Kelley361dfe52017-02-10 21:12:30 +00002043 last_server->flags &= ~SERV_GOT_TCP;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002044 }
2045
Simon Kelley1fc02682014-04-29 12:30:18 +01002046 /* get query name again for logging - may have been overwritten */
2047 if (!(gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
2048 strcpy(daemon->namebuff, "query");
Simon Kelley4f7b3042012-11-28 21:27:02 +00002049
Simon Kelley608aa9f2019-03-10 22:44:15 +00002050 if ((!data_sent && !read_write(last_server->tcpfd, packet, size + sizeof(u16), 0)) ||
Simon Kelley4f7b3042012-11-28 21:27:02 +00002051 !read_write(last_server->tcpfd, &c1, 1, 1) ||
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002052 !read_write(last_server->tcpfd, &c2, 1, 1) ||
2053 !read_write(last_server->tcpfd, payload, (c1 << 8) | c2, 1))
Simon Kelley7de060b2011-08-26 17:24:52 +01002054 {
2055 close(last_server->tcpfd);
2056 last_server->tcpfd = -1;
Simon Kelley361dfe52017-02-10 21:12:30 +00002057 /* We get data then EOF, reopen connection to same server,
2058 else try next. This avoids DoS from a server which accepts
2059 connections and then closes them. */
2060 if (last_server->flags & SERV_GOT_TCP)
2061 goto retry;
2062 else
2063 continue;
2064 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00002065
Simon Kelley361dfe52017-02-10 21:12:30 +00002066 last_server->flags |= SERV_GOT_TCP;
2067
Simon Kelley4f7b3042012-11-28 21:27:02 +00002068 m = (c1 << 8) | c2;
Petr Menšík6c0bf792021-03-18 00:07:45 +01002069
2070 log_query_mysockaddr(F_SERVER | F_FORWARD, daemon->namebuff,
2071 &last_server->addr, NULL);
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002072
2073#ifdef HAVE_DNSSEC
Simon Kelley367341f2016-01-12 15:58:23 +00002074 if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled && (last_server->flags & SERV_DO_DNSSEC))
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002075 {
Simon Kelley7fa836e2014-02-10 20:11:24 +00002076 int keycount = DNSSEC_WORK; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
Simon Kelleyf344dbc2016-01-18 18:04:17 +00002077 int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname,
2078 last_server, have_mark, mark, &keycount);
Simon Kelley554b5802015-04-17 22:50:20 +01002079 char *result, *domain = "result";
Simon Kelleyfe3992f2015-04-03 21:25:05 +01002080
Simon Kelley9a31b682015-12-15 10:20:39 +00002081 if (status == STAT_ABANDONED)
Simon Kelley150162b2015-03-27 09:58:26 +00002082 {
2083 result = "ABANDONED";
2084 status = STAT_BOGUS;
2085 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00002086 else
2087 result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
Simon Kelleye66b4df2015-04-28 20:45:57 +01002088
2089 if (status == STAT_BOGUS && extract_request(header, m, daemon->namebuff, NULL))
2090 domain = daemon->namebuff;
Simon Kelley554b5802015-04-17 22:50:20 +01002091
Simon Kelley07ed5852018-05-04 21:52:22 +01002092 log_query(F_SECSTAT, domain, NULL, result);
Simon Kelley7fa836e2014-02-10 20:11:24 +00002093
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002094 if (status == STAT_BOGUS)
Simon Kelleyfe3992f2015-04-03 21:25:05 +01002095 {
2096 no_cache_dnssec = 1;
2097 bogusanswer = 1;
2098 }
2099
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002100 if (status == STAT_SECURE)
2101 cache_secure = 1;
2102 }
2103#endif
2104
2105 /* restore CD bit to the value in the query */
2106 if (checking_disabled)
2107 header->hb4 |= HB4_CD;
2108 else
2109 header->hb4 &= ~HB4_CD;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002110
2111 /* There's no point in updating the cache, since this process will exit and
2112 lose the information after a few queries. We make this call for the alias and
2113 bogus-nxdomain side-effects. */
2114 /* If the crc of the question section doesn't match the crc we sent, then
2115 someone might be attempting to insert bogus values into the cache by
2116 sending replies containing questions and bogus answers. */
Simon Kelley2d765862020-11-12 22:06:07 +00002117 if (memcmp(hash, hash_questions(header, (unsigned int)m, daemon->namebuff), HASH_SIZE) != 0)
Simon Kelley703c7ff2014-01-25 23:46:23 +00002118 {
2119 m = 0;
2120 break;
2121 }
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002122
Simon Kelley25e63f12020-11-25 21:17:52 +00002123 /* Never cache answers which are contingent on the source or MAC address EDSN0 option,
2124 since the cache is ignorant of such things. */
2125 if (!cacheable)
2126 no_cache_dnssec = 1;
2127
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002128 m = process_reply(header, now, last_server, (unsigned int)m,
Simon Kelleye66b4df2015-04-28 20:45:57 +01002129 option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
Simon Kelleyfa14bec2015-12-20 17:12:16 +00002130 ad_reqd, do_bit, added_pheader, check_subnet, &peer_addr);
Simon Kelley4f7b3042012-11-28 21:27:02 +00002131
2132 break;
2133 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002134 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00002135
2136 /* In case of local answer or no connections made. */
2137 if (m == 0)
Simon Kelley1682d152018-08-03 20:38:18 +01002138 {
2139 m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl);
2140 if (have_pseudoheader)
2141 m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
2142 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002143 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002144 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00002145
Simon Kelleyb842bc92015-07-12 21:09:11 +01002146 check_log_writer(1);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002147
Simon Kelley4b5ea122013-04-22 10:18:26 +01002148 *length = htons(m);
2149
2150 if (m == 0 || !read_write(confd, packet, m + sizeof(u16), 0))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002151 return packet;
2152 }
2153}
2154
Simon Kelley16972692006-10-16 20:04:18 +01002155static struct frec *allocate_frec(time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002156{
Simon Kelley16972692006-10-16 20:04:18 +01002157 struct frec *f;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002158
Simon Kelley5aabfc72007-08-29 11:24:47 +01002159 if ((f = (struct frec *)whine_malloc(sizeof(struct frec))))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002160 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01002161 f->next = daemon->frec_list;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002162 f->time = now;
Simon Kelley832af0b2007-01-21 20:01:28 +00002163 f->sentto = NULL;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002164 f->rfds = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +00002165 f->flags = 0;
Simon Kelley3a237152013-12-12 12:15:50 +00002166#ifdef HAVE_DNSSEC
Simon Kelley97bc7982014-01-31 10:19:52 +00002167 f->dependent = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002168 f->blocking_query = NULL;
Simon Kelley4619d942014-01-16 19:53:06 +00002169 f->stash = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002170#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +01002171 daemon->frec_list = f;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002172 }
Simon Kelley16972692006-10-16 20:04:18 +01002173
2174 return f;
2175}
2176
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002177/* return a UDP socket bound to a random port, have to cope with straying into
2178 occupied port nos and reserved ones. */
2179static int random_sock(struct server *s)
2180{
2181 int fd;
2182
2183 if ((fd = socket(s->source_addr.sa.sa_family, SOCK_DGRAM, 0)) != -1)
2184 {
2185 if (local_bind(fd, &s->source_addr, s->interface, s->ifindex, 0))
2186 return fd;
2187
2188 if (s->interface[0] == 0)
2189 (void)prettyprint_addr(&s->source_addr, daemon->namebuff);
2190 else
2191 strcpy(daemon->namebuff, s->interface);
2192
2193 my_syslog(LOG_ERR, _("failed to bind server socket to %s: %s"),
2194 daemon->namebuff, strerror(errno));
2195 close(fd);
2196 }
2197
2198 return -1;
2199}
2200
2201/* compare source addresses and interface, serv2 can be null. */
2202static int server_isequal(const struct server *serv1,
2203 const struct server *serv2)
2204{
2205 return (serv2 &&
2206 serv2->ifindex == serv1->ifindex &&
2207 sockaddr_isequal(&serv2->source_addr, &serv1->source_addr) &&
2208 strncmp(serv2->interface, serv1->interface, IF_NAMESIZE) == 0);
2209}
2210
2211/* fdlp points to chain of randomfds already in use by transaction.
2212 If there's already a suitable one, return it, else allocate a
2213 new one and add it to the list.
2214
2215 Not leaking any resources in the face of allocation failures
2216 is rather convoluted here.
2217
2218 Note that rfd->serv may be NULL, when a server goes away.
2219*/
2220int allocate_rfd(struct randfd_list **fdlp, struct server *serv)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002221{
2222 static int finger = 0;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002223 int i, j = 0;
2224 struct randfd_list *rfl;
2225 struct randfd *rfd = NULL;
2226 int fd = 0;
2227
2228 /* If server has a pre-allocated fd, use that. */
2229 if (serv->sfd)
2230 return serv->sfd->fd;
2231
2232 /* existing suitable random port socket linked to this transaction? */
2233 for (rfl = *fdlp; rfl; rfl = rfl->next)
2234 if (server_isequal(serv, rfl->rfd->serv))
2235 return rfl->rfd->fd;
Simon Kelley1a6bca82008-07-11 11:11:42 +01002236
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002237 /* No. need new link. */
2238 if ((rfl = daemon->rfl_spare))
2239 daemon->rfl_spare = rfl->next;
2240 else if (!(rfl = whine_malloc(sizeof(struct randfd_list))))
2241 return -1;
2242
Simon Kelley1a6bca82008-07-11 11:11:42 +01002243 /* limit the number of sockets we have open to avoid starvation of
2244 (eg) TFTP. Once we have a reasonable number, randomness should be OK */
Simon Kelleyea28d0e2021-03-26 22:02:04 +00002245 for (i = 0; i < daemon->numrrand; i++)
Simon Kelley9009d742008-11-14 20:04:27 +00002246 if (daemon->randomsocks[i].refcount == 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002247 {
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002248 if ((fd = random_sock(serv)) != -1)
2249 {
2250 rfd = &daemon->randomsocks[i];
2251 rfd->serv = serv;
2252 rfd->fd = fd;
2253 rfd->refcount = 1;
2254 }
2255 break;
2256 }
2257
2258 /* No free ones or cannot get new socket, grab an existing one */
2259 if (!rfd)
Simon Kelleyea28d0e2021-03-26 22:02:04 +00002260 for (j = 0; j < daemon->numrrand; j++)
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002261 {
Simon Kelleyea28d0e2021-03-26 22:02:04 +00002262 i = (j + finger) % daemon->numrrand;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002263 if (daemon->randomsocks[i].refcount != 0 &&
2264 server_isequal(serv, daemon->randomsocks[i].serv) &&
2265 daemon->randomsocks[i].refcount != 0xfffe)
2266 {
2267 finger = i + 1;
2268 rfd = &daemon->randomsocks[i];
2269 rfd->refcount++;
2270 break;
2271 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01002272 }
2273
Simon Kelleyea28d0e2021-03-26 22:02:04 +00002274 if (j == daemon->numrrand)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002275 {
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002276 struct randfd_list *rfl_poll;
Simon Kelley1a6bca82008-07-11 11:11:42 +01002277
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002278 /* there are no free slots, and non with the same parameters we can piggy-back on.
2279 We're going to have to allocate a new temporary record, distinguished by
2280 refcount == 0xffff. This will exist in the frec randfd list, never be shared,
2281 and be freed when no longer in use. It will also be held on
2282 the daemon->rfl_poll list so the poll system can find it. */
2283
2284 if ((rfl_poll = daemon->rfl_spare))
2285 daemon->rfl_spare = rfl_poll->next;
2286 else
2287 rfl_poll = whine_malloc(sizeof(struct randfd_list));
2288
2289 if (!rfl_poll ||
2290 !(rfd = whine_malloc(sizeof(struct randfd))) ||
2291 (fd = random_sock(serv)) == -1)
2292 {
2293
2294 /* Don't leak anything we may already have */
2295 rfl->next = daemon->rfl_spare;
2296 daemon->rfl_spare = rfl;
2297
2298 if (rfl_poll)
2299 {
2300 rfl_poll->next = daemon->rfl_spare;
2301 daemon->rfl_spare = rfl_poll;
2302 }
2303
2304 if (rfd)
2305 free(rfd);
2306
2307 return -1; /* doom */
2308 }
2309
2310 /* Note rfd->serv not set here, since it's not reused */
2311 rfd->fd = fd;
2312 rfd->refcount = 0xffff; /* marker for temp record */
2313
2314 rfl_poll->rfd = rfd;
2315 rfl_poll->next = daemon->rfl_poll;
2316 daemon->rfl_poll = rfl_poll;
2317 }
2318
2319 rfl->rfd = rfd;
2320 rfl->next = *fdlp;
2321 *fdlp = rfl;
2322
2323 return rfl->rfd->fd;
Simon Kelley1a6bca82008-07-11 11:11:42 +01002324}
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002325
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002326void free_rfds(struct randfd_list **fdlp)
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002327{
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002328 struct randfd_list *tmp, *rfl, *poll, *next, **up;
2329
2330 for (rfl = *fdlp; rfl; rfl = tmp)
2331 {
2332 if (rfl->rfd->refcount == 0xffff || --(rfl->rfd->refcount) == 0)
2333 close(rfl->rfd->fd);
2334
2335 /* temporary overflow record */
2336 if (rfl->rfd->refcount == 0xffff)
2337 {
2338 free(rfl->rfd);
2339
2340 /* go through the link of all these by steam to delete.
2341 This list is expected to be almost always empty. */
2342 for (poll = daemon->rfl_poll, up = &daemon->rfl_poll; poll; poll = next)
2343 {
2344 next = poll->next;
2345
2346 if (poll->rfd == rfl->rfd)
2347 {
2348 *up = poll->next;
2349 poll->next = daemon->rfl_spare;
2350 daemon->rfl_spare = poll;
2351 }
2352 else
2353 up = &poll->next;
2354 }
2355 }
2356
2357 tmp = rfl->next;
2358 rfl->next = daemon->rfl_spare;
2359 daemon->rfl_spare = rfl;
2360 }
2361
2362 *fdlp = NULL;
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002363}
2364
Simon Kelley1a6bca82008-07-11 11:11:42 +01002365static void free_frec(struct frec *f)
2366{
Simon Kelley6a6e06f2020-12-04 18:35:11 +00002367 struct frec_src *last;
Simon Kelley15b60dd2020-11-18 18:34:55 +00002368
Simon Kelley6a6e06f2020-12-04 18:35:11 +00002369 /* add back to freelist if not the record builtin to every frec. */
2370 for (last = f->frec_src.next; last && last->next; last = last->next) ;
2371 if (last)
2372 {
2373 last->next = daemon->free_frec_src;
2374 daemon->free_frec_src = f->frec_src.next;
2375 }
2376
Simon Kelley15b60dd2020-11-18 18:34:55 +00002377 f->frec_src.next = NULL;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002378 free_rfds(&f->rfds);
Simon Kelley1a6bca82008-07-11 11:11:42 +01002379 f->sentto = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +00002380 f->flags = 0;
Simon Kelley3a237152013-12-12 12:15:50 +00002381
2382#ifdef HAVE_DNSSEC
2383 if (f->stash)
Simon Kelley0fc2f312014-01-08 10:26:58 +00002384 {
2385 blockdata_free(f->stash);
2386 f->stash = NULL;
2387 }
Simon Kelley3a237152013-12-12 12:15:50 +00002388
2389 /* Anything we're waiting on is pointless now, too */
2390 if (f->blocking_query)
2391 free_frec(f->blocking_query);
2392 f->blocking_query = NULL;
Simon Kelley39048ad2014-01-21 17:33:58 +00002393 f->dependent = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002394#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +01002395}
2396
Simon Kelley09f3b2c2017-05-09 01:34:02 +01002397
2398
Simon Kelley16972692006-10-16 20:04:18 +01002399/* if wait==NULL return a free or older than TIMEOUT record.
2400 else return *wait zero if one available, or *wait is delay to
Simon Kelley1a6bca82008-07-11 11:11:42 +01002401 when the oldest in-use record will expire. Impose an absolute
Simon Kelley3a237152013-12-12 12:15:50 +00002402 limit of 4*TIMEOUT before we wipe things (for random sockets).
Simon Kelley8caf3d72020-04-04 17:00:32 +01002403 If force is non-NULL, always return a result, even if we have
2404 to allocate above the limit, and never free the record pointed
2405 to by the force argument. */
2406struct frec *get_new_frec(time_t now, int *wait, struct frec *force)
Simon Kelley16972692006-10-16 20:04:18 +01002407{
Simon Kelley1a6bca82008-07-11 11:11:42 +01002408 struct frec *f, *oldest, *target;
Simon Kelley16972692006-10-16 20:04:18 +01002409 int count;
2410
2411 if (wait)
2412 *wait = 0;
2413
Simon Kelley1a6bca82008-07-11 11:11:42 +01002414 for (f = daemon->frec_list, oldest = NULL, target = NULL, count = 0; f; f = f->next, count++)
Simon Kelley832af0b2007-01-21 20:01:28 +00002415 if (!f->sentto)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002416 target = f;
2417 else
Simon Kelley16972692006-10-16 20:04:18 +01002418 {
Simon Kelley9a31b682015-12-15 10:20:39 +00002419#ifdef HAVE_DNSSEC
2420 /* Don't free DNSSEC sub-queries here, as we may end up with
2421 dangling references to them. They'll go when their "real" query
2422 is freed. */
Simon Kelley8caf3d72020-04-04 17:00:32 +01002423 if (!f->dependent && f != force)
Simon Kelley9a31b682015-12-15 10:20:39 +00002424#endif
2425 {
2426 if (difftime(now, f->time) >= 4*TIMEOUT)
2427 {
2428 free_frec(f);
2429 target = f;
2430 }
2431
2432
2433 if (!oldest || difftime(f->time, oldest->time) <= 0)
2434 oldest = f;
2435 }
Simon Kelley16972692006-10-16 20:04:18 +01002436 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01002437
2438 if (target)
2439 {
2440 target->time = now;
2441 return target;
2442 }
Simon Kelley16972692006-10-16 20:04:18 +01002443
2444 /* can't find empty one, use oldest if there is one
2445 and it's older than timeout */
Simon Kelley09f3b2c2017-05-09 01:34:02 +01002446 if (!force && oldest && ((int)difftime(now, oldest->time)) >= TIMEOUT)
Simon Kelley16972692006-10-16 20:04:18 +01002447 {
2448 /* keep stuff for twice timeout if we can by allocating a new
2449 record instead */
2450 if (difftime(now, oldest->time) < 2*TIMEOUT &&
2451 count <= daemon->ftabsize &&
2452 (f = allocate_frec(now)))
2453 return f;
2454
2455 if (!wait)
2456 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01002457 free_frec(oldest);
Simon Kelley16972692006-10-16 20:04:18 +01002458 oldest->time = now;
2459 }
2460 return oldest;
2461 }
2462
2463 /* none available, calculate time 'till oldest record expires */
Simon Kelley3a237152013-12-12 12:15:50 +00002464 if (!force && count > daemon->ftabsize)
Simon Kelley16972692006-10-16 20:04:18 +01002465 {
Marcelo Salhab Brogliato0da5e892013-05-31 11:49:06 +01002466 static time_t last_log = 0;
2467
Simon Kelley16972692006-10-16 20:04:18 +01002468 if (oldest && wait)
2469 *wait = oldest->time + (time_t)TIMEOUT - now;
Marcelo Salhab Brogliato0da5e892013-05-31 11:49:06 +01002470
2471 if ((int)difftime(now, last_log) > 5)
2472 {
2473 last_log = now;
2474 my_syslog(LOG_WARNING, _("Maximum number of concurrent DNS queries reached (max: %d)"), daemon->ftabsize);
2475 }
2476
Simon Kelley16972692006-10-16 20:04:18 +01002477 return NULL;
2478 }
2479
2480 if (!(f = allocate_frec(now)) && wait)
2481 /* wait one second on malloc failure */
2482 *wait = 1;
2483
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002484 return f; /* OK if malloc fails and this is NULL */
2485}
Simon Kelley09f3b2c2017-05-09 01:34:02 +01002486
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