blob: 7bb962893451659c4e9652938e6b0f2d36140cd8 [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
Simon Kelley824af852008-02-12 20:43:05 +0000266static int forward_query(int udpfd, union mysockaddr *udpaddr,
Simon Kelleycc921df2019-01-02 22:48:59 +0000267 union all_addr *dst_addr, unsigned int dst_iface,
Simon Kelley83349b82014-02-10 21:02:01 +0000268 struct dns_header *header, size_t plen, time_t now,
Simon Kelley613ad152014-02-25 23:02:28 +0000269 struct frec *forward, int ad_reqd, int do_bit)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000270{
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000271 char *domain = NULL;
Simon Kelley367341f2016-01-12 15:58:23 +0000272 int type = SERV_DO_DNSSEC, norebind = 0;
Simon Kelleycc921df2019-01-02 22:48:59 +0000273 union all_addr *addrp = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +0000274 unsigned int flags = 0;
Simon Kelley15b60dd2020-11-18 18:34:55 +0000275 unsigned int fwd_flags = 0;
Simon Kelleyde379512004-06-22 20:23:33 +0100276 struct server *start = NULL;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000277 void *hash = hash_questions(header, plen, daemon->namebuff);
Simon Kelley2d765862020-11-12 22:06:07 +0000278#ifdef HAVE_DNSSEC
Simon Kelley367341f2016-01-12 15:58:23 +0000279 int do_dnssec = 0;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000280#endif
Simon Kelley1682d152018-08-03 20:38:18 +0100281 unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
282 unsigned char *oph = find_pseudoheader(header, plen, NULL, NULL, NULL, NULL);
283 (void)do_bit;
Simon Kelley15b60dd2020-11-18 18:34:55 +0000284
285 if (header->hb4 & HB4_CD)
286 fwd_flags |= FREC_CHECKING_DISABLED;
287 if (ad_reqd)
288 fwd_flags |= FREC_AD_QUESTION;
289 if (oph)
290 fwd_flags |= FREC_HAS_PHEADER;
291#ifdef HAVE_DNSSEC
292 if (do_bit)
293 fwd_flags |= FREC_DO_QUESTION;
294#endif
295
Simon Kelley305cb792021-02-18 21:35:09 +0000296 /* Check for retry on existing query */
297 if (!forward && (forward = lookup_frec_by_query(hash, fwd_flags)))
Simon Kelley141a26f2021-02-17 23:56:32 +0000298 {
Simon Kelley305cb792021-02-18 21:35:09 +0000299 struct frec_src *src;
Simon Kelley141a26f2021-02-17 23:56:32 +0000300
Simon Kelley305cb792021-02-18 21:35:09 +0000301 for (src = &forward->frec_src; src; src = src->next)
302 if (src->orig_id == ntohs(header->id) &&
303 sockaddr_isequal(&src->source, udpaddr))
304 break;
305
306 /* Existing query, but from new source, just add this
307 client to the list that will get the reply.*/
308 if (!src)
309 {
Simon Kelley141a26f2021-02-17 23:56:32 +0000310 /* Note whine_malloc() zeros memory. */
311 if (!daemon->free_frec_src &&
312 daemon->frec_src_count < daemon->ftabsize &&
313 (daemon->free_frec_src = whine_malloc(sizeof(struct frec_src))))
314 {
315 daemon->frec_src_count++;
316 daemon->free_frec_src->next = NULL;
317 }
318
319 /* If we've been spammed with many duplicates, just drop the query. */
320 if (!daemon->free_frec_src)
321 return 0;
322
Simon Kelley305cb792021-02-18 21:35:09 +0000323 src = daemon->free_frec_src;
324 daemon->free_frec_src = src->next;
325 src->next = forward->frec_src.next;
326 forward->frec_src.next = src;
327 src->orig_id = ntohs(header->id);
328 src->source = *udpaddr;
329 src->dest = *dst_addr;
330 src->log_id = daemon->log_id;
331 src->iface = dst_iface;
332 src->fd = udpfd;
Simon Kelley141a26f2021-02-17 23:56:32 +0000333 }
334 }
335
336 /* retry existing query */
337 if (forward)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000338 {
Simon Kelleya77cec82015-05-08 16:25:38 +0100339 /* If we didn't get an answer advertising a maximal packet in EDNS,
340 fall back to 1280, which should work everywhere on IPv6.
341 If that generates an answer, it will become the new default
342 for this server */
343 forward->flags |= FREC_TEST_PKTSZ;
344
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000345#ifdef HAVE_DNSSEC
Simon Kelleydac74312014-02-13 16:43:49 +0000346 /* If we've already got an answer to this query, but we're awaiting keys for validation,
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000347 there's no point retrying the query, retry the key query instead...... */
348 if (forward->blocking_query)
349 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000350 int fd, is_sign;
351 unsigned char *pheader;
Simon Kelleya77cec82015-05-08 16:25:38 +0100352
353 forward->flags &= ~FREC_TEST_PKTSZ;
354
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000355 while (forward->blocking_query)
356 forward = forward->blocking_query;
Simon Kelleya77cec82015-05-08 16:25:38 +0100357
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000358 blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
359 plen = forward->stash_len;
360
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000361 forward->flags |= FREC_TEST_PKTSZ;
Simon Kelley5bb88f02015-12-21 16:23:47 +0000362 if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000363 PUTSHORT(SAFE_PKTSZ, pheader);
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000364
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000365 if ((fd = allocate_rfd(&forward->rfds, forward->sentto)) != -1)
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000366 {
Petr Menšík6c0bf792021-03-18 00:07:45 +0100367 log_query_mysockaddr(F_NOEXTRA | F_DNSSEC, "retry",
368 &forward->sentto->addr, "dnssec");
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000369
370 while (retry_send(sendto(fd, (char *)header, plen, 0,
371 &forward->sentto->addr.sa,
372 sa_len(&forward->sentto->addr))));
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000373 }
374
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000375 return 1;
376 }
377#endif
378
Simon Kelleyde379512004-06-22 20:23:33 +0100379 /* retry on existing query, send to all available servers */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000380 domain = forward->sentto->domain;
Simon Kelley824af852008-02-12 20:43:05 +0000381 forward->sentto->failed_queries++;
Simon Kelley28866e92011-02-14 20:19:14 +0000382 if (!option_bool(OPT_ORDER))
Simon Kelleyde379512004-06-22 20:23:33 +0100383 {
Simon Kelley0a852542005-03-23 20:28:59 +0000384 forward->forwardall = 1;
Simon Kelley3be34542004-09-11 19:12:13 +0100385 daemon->last_server = NULL;
Simon Kelleyde379512004-06-22 20:23:33 +0100386 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000387 type = forward->sentto->flags & SERV_TYPE;
Simon Kelley367341f2016-01-12 15:58:23 +0000388#ifdef HAVE_DNSSEC
389 do_dnssec = forward->sentto->flags & SERV_DO_DNSSEC;
390#endif
391
Simon Kelleyde379512004-06-22 20:23:33 +0100392 if (!(start = forward->sentto->next))
Simon Kelley3be34542004-09-11 19:12:13 +0100393 start = daemon->servers; /* at end of list, recycle */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000394 header->id = htons(forward->new_id);
395 }
396 else
397 {
Simon Kelley141a26f2021-02-17 23:56:32 +0000398 /* new query */
399
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000400 if (gotname)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100401 flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000402
Simon Kelley367341f2016-01-12 15:58:23 +0000403#ifdef HAVE_DNSSEC
404 do_dnssec = type & SERV_DO_DNSSEC;
Simon Kelleyf7443d72016-01-19 20:29:57 +0000405#endif
406 type &= ~SERV_DO_DNSSEC;
Simon Kelley15b60dd2020-11-18 18:34:55 +0000407
Simon Kelley141a26f2021-02-17 23:56:32 +0000408 /* may be no servers available. */
Simon Kelleyd05dd582016-01-19 21:23:30 +0000409 if (daemon->servers && !flags)
Simon Kelley8caf3d72020-04-04 17:00:32 +0100410 forward = get_new_frec(now, NULL, NULL);
Simon Kelleyd05dd582016-01-19 21:23:30 +0000411 /* table full - flags == 0, return REFUSED */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000412
413 if (forward)
414 {
Simon Kelley15b60dd2020-11-18 18:34:55 +0000415 forward->frec_src.source = *udpaddr;
416 forward->frec_src.orig_id = ntohs(header->id);
417 forward->frec_src.dest = *dst_addr;
418 forward->frec_src.iface = dst_iface;
Simon Kelley6a6e06f2020-12-04 18:35:11 +0000419 forward->frec_src.next = NULL;
Simon Kelley04490bf2021-01-22 16:49:12 +0000420 forward->frec_src.fd = udpfd;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000421 forward->new_id = get_id();
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000422 memcpy(forward->hash, hash, HASH_SIZE);
Simon Kelley0a852542005-03-23 20:28:59 +0000423 forward->forwardall = 0;
Simon Kelley15b60dd2020-11-18 18:34:55 +0000424 forward->flags = fwd_flags;
Simon Kelley28866e92011-02-14 20:19:14 +0000425 if (norebind)
426 forward->flags |= FREC_NOREBIND;
Simon Kelley572b41e2011-02-18 18:11:18 +0000427 if (header->hb4 & HB4_CD)
Simon Kelley28866e92011-02-14 20:19:14 +0000428 forward->flags |= FREC_CHECKING_DISABLED;
Simon Kelley83349b82014-02-10 21:02:01 +0000429 if (ad_reqd)
430 forward->flags |= FREC_AD_QUESTION;
Simon Kelley7fa836e2014-02-10 20:11:24 +0000431#ifdef HAVE_DNSSEC
432 forward->work_counter = DNSSEC_WORK;
Simon Kelley613ad152014-02-25 23:02:28 +0000433 if (do_bit)
434 forward->flags |= FREC_DO_QUESTION;
Simon Kelley7fa836e2014-02-10 20:11:24 +0000435#endif
Simon Kelley613ad152014-02-25 23:02:28 +0000436
Simon Kelley28866e92011-02-14 20:19:14 +0000437 header->id = htons(forward->new_id);
438
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100439 /* In strict_order mode, always try servers in the order
440 specified in resolv.conf, if a domain is given
441 always try all the available servers,
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000442 otherwise, use the one last known to work. */
443
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100444 if (type == 0)
445 {
Simon Kelley28866e92011-02-14 20:19:14 +0000446 if (option_bool(OPT_ORDER))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100447 start = daemon->servers;
448 else if (!(start = daemon->last_server) ||
449 daemon->forwardcount++ > FORWARD_TEST ||
450 difftime(now, daemon->forwardtime) > FORWARD_TIME)
451 {
452 start = daemon->servers;
453 forward->forwardall = 1;
454 daemon->forwardcount = 0;
455 daemon->forwardtime = now;
456 }
457 }
458 else
Simon Kelleyde379512004-06-22 20:23:33 +0100459 {
Simon Kelley3be34542004-09-11 19:12:13 +0100460 start = daemon->servers;
Simon Kelley28866e92011-02-14 20:19:14 +0000461 if (!option_bool(OPT_ORDER))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100462 forward->forwardall = 1;
Simon Kelleyde379512004-06-22 20:23:33 +0100463 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000464 }
465 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100466
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000467 /* check for send errors here (no route to host)
468 if we fail to send to all nameservers, send back an error
469 packet straight away (helps modem users when offline) */
470
471 if (!flags && forward)
472 {
Simon Kelleyde379512004-06-22 20:23:33 +0100473 struct server *firstsentto = start;
Simon Kelley25e63f12020-11-25 21:17:52 +0000474 int subnet, cacheable, forwarded = 0;
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000475 size_t edns0_len;
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000476 unsigned char *pheader;
477
Simon Kelley25cf5e32015-01-09 15:53:03 +0000478 /* If a query is retried, use the log_id for the retry when logging the answer. */
Simon Kelley15b60dd2020-11-18 18:34:55 +0000479 forward->frec_src.log_id = daemon->log_id;
Simon Kelley25cf5e32015-01-09 15:53:03 +0000480
Simon Kelley25e63f12020-11-25 21:17:52 +0000481 plen = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->frec_src.source, now, &subnet, &cacheable);
Simon Kelley33702ab2015-12-28 23:17:15 +0000482
Simon Kelley6fd5d792017-10-13 22:26:40 +0100483 if (subnet)
484 forward->flags |= FREC_HAS_SUBNET;
Simon Kelley25e63f12020-11-25 21:17:52 +0000485
486 if (!cacheable)
487 forward->flags |= FREC_NO_CACHE;
488
Simon Kelley3a237152013-12-12 12:15:50 +0000489#ifdef HAVE_DNSSEC
Simon Kelley367341f2016-01-12 15:58:23 +0000490 if (option_bool(OPT_DNSSEC_VALID) && do_dnssec)
Simon Kelley0fc2f312014-01-08 10:26:58 +0000491 {
Simon Kelley6fd5d792017-10-13 22:26:40 +0100492 plen = add_do_bit(header, plen, ((unsigned char *) header) + PACKETSZ);
493
Simon Kelley5b3bf922014-01-25 17:03:07 +0000494 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
495 this allows it to select auth servers when one is returning bad data. */
496 if (option_bool(OPT_DNSSEC_DEBUG))
497 header->hb4 |= HB4_CD;
Simon Kelley613ad152014-02-25 23:02:28 +0000498
Simon Kelley0fc2f312014-01-08 10:26:58 +0000499 }
Simon Kelley3a237152013-12-12 12:15:50 +0000500#endif
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000501
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000502 if (find_pseudoheader(header, plen, &edns0_len, &pheader, NULL, NULL))
Simon Kelley6fd5d792017-10-13 22:26:40 +0100503 {
504 /* If there wasn't a PH before, and there is now, we added it. */
505 if (!oph)
506 forward->flags |= FREC_ADDED_PHEADER;
507
508 /* If we're sending an EDNS0 with any options, we can't recreate the query from a reply. */
509 if (edns0_len > 11)
510 forward->flags |= FREC_HAS_EXTRADATA;
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000511
512 /* Reduce udp size on retransmits. */
513 if (forward->flags & FREC_TEST_PKTSZ)
514 PUTSHORT(SAFE_PKTSZ, pheader);
Simon Kelley6fd5d792017-10-13 22:26:40 +0100515 }
Simon Kelleya77cec82015-05-08 16:25:38 +0100516
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000517 while (1)
518 {
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000519 int fd;
520
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000521 /* only send to servers dealing with our domain.
522 domain may be NULL, in which case server->domain
523 must be NULL also. */
524
Simon Kelleyde379512004-06-22 20:23:33 +0100525 if (type == (start->flags & SERV_TYPE) &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100526 (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000527 !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)) &&
528 ((fd = allocate_rfd(&forward->rfds, start)) != -1))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000529 {
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000530
Simon Kelley7de060b2011-08-26 17:24:52 +0100531#ifdef HAVE_CONNTRACK
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000532 /* Copy connection mark of incoming query to outgoing connection. */
533 if (option_bool(OPT_CONNTRACK))
Petr Menšík6c0bf792021-03-18 00:07:45 +0100534 set_outgoing_mark(forward, fd);
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000535#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +0100536
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000537#ifdef HAVE_DNSSEC
Simon Kelley5bb88f02015-12-21 16:23:47 +0000538 if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER))
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000539 {
540 /* Difficult one here. If our client didn't send EDNS0, we will have set the UDP
541 packet size to 512. But that won't provide space for the RRSIGS in many cases.
542 The RRSIGS will be stripped out before the answer goes back, so the packet should
543 shrink again. So, if we added a do-bit, bump the udp packet size to the value
Simon Kelley5aa5f0f2015-12-21 17:20:35 +0000544 known to be OK for this server. We check returned size after stripping and set
545 the truncated bit if it's still too big. */
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000546 unsigned char *pheader;
547 int is_sign;
Simon Kelley5bb88f02015-12-21 16:23:47 +0000548 if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000549 PUTSHORT(start->edns_pktsz, pheader);
550 }
551#endif
552
Simon Kelleyff841eb2015-03-11 21:36:30 +0000553 if (retry_send(sendto(fd, (char *)header, plen, 0,
554 &start->addr.sa,
555 sa_len(&start->addr))))
556 continue;
557
558 if (errno == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000559 {
Simon Kelley6b173352018-05-08 18:32:14 +0100560#ifdef HAVE_DUMPFILE
561 dump_packet(DUMP_UP_QUERY, (void *)header, plen, NULL, &start->addr);
562#endif
563
Simon Kelleycdeda282006-03-16 20:16:06 +0000564 /* Keep info in case we want to re-send this packet */
565 daemon->srv_save = start;
566 daemon->packet_len = plen;
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000567 daemon->fd_save = fd;
Simon Kelleycdeda282006-03-16 20:16:06 +0000568
Simon Kelleyde379512004-06-22 20:23:33 +0100569 if (!gotname)
Simon Kelley3be34542004-09-11 19:12:13 +0100570 strcpy(daemon->namebuff, "query");
Petr Menšík6c0bf792021-03-18 00:07:45 +0100571 log_query_mysockaddr(F_SERVER | F_FORWARD, daemon->namebuff,
572 &start->addr, NULL);
Simon Kelley824af852008-02-12 20:43:05 +0000573 start->queries++;
Simon Kelleyde379512004-06-22 20:23:33 +0100574 forwarded = 1;
575 forward->sentto = start;
Simon Kelley0a852542005-03-23 20:28:59 +0000576 if (!forward->forwardall)
Simon Kelleyde379512004-06-22 20:23:33 +0100577 break;
Simon Kelley0a852542005-03-23 20:28:59 +0000578 forward->forwardall++;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000579 }
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000580 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000581
Simon Kelleyde379512004-06-22 20:23:33 +0100582 if (!(start = start->next))
Simon Kelley3be34542004-09-11 19:12:13 +0100583 start = daemon->servers;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000584
Simon Kelleyde379512004-06-22 20:23:33 +0100585 if (start == firstsentto)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000586 break;
587 }
588
Simon Kelleyde379512004-06-22 20:23:33 +0100589 if (forwarded)
Simon Kelley824af852008-02-12 20:43:05 +0000590 return 1;
Simon Kelleyde379512004-06-22 20:23:33 +0100591
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000592 /* could not send on, prepare to return */
Simon Kelley15b60dd2020-11-18 18:34:55 +0000593 header->id = htons(forward->frec_src.orig_id);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100594 free_frec(forward); /* cancel */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000595 }
596
597 /* could not send on, return empty answer or address if known for whole domain */
Simon Kelleyb8187c82005-11-26 21:46:27 +0000598 if (udpfd != -1)
599 {
Simon Kelleycdeda282006-03-16 20:16:06 +0000600 plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl);
Simon Kelley1682d152018-08-03 20:38:18 +0100601 if (oph)
602 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 +0100603 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 +0000604 }
605
Simon Kelley824af852008-02-12 20:43:05 +0000606 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000607}
608
Simon Kelleyed4c0762013-10-08 20:46:34 +0100609static 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 +0100610 int no_cache, int cache_secure, int bogusanswer, int ad_reqd, int do_bit, int added_pheader,
611 int check_subnet, union mysockaddr *query_source)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100612{
Simon Kelley36717ee2004-09-20 19:20:58 +0100613 unsigned char *pheader, *sizep;
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000614 char **sets = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +0000615 int munged = 0, is_sign;
Simon Kelley07ed5852018-05-04 21:52:22 +0100616 unsigned int rcode = RCODE(header);
Simon Kelleycdeda282006-03-16 20:16:06 +0000617 size_t plen;
Simon Kelleya6004d72017-10-25 17:48:19 +0100618
Simon Kelley83349b82014-02-10 21:02:01 +0000619 (void)ad_reqd;
Simon Kelley982faf42015-04-03 21:42:30 +0100620 (void)do_bit;
621 (void)bogusanswer;
Simon Kelley83349b82014-02-10 21:02:01 +0000622
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000623#ifdef HAVE_IPSET
Simon Kelley82a14af2014-04-13 20:48:57 +0100624 if (daemon->ipsets && extract_request(header, n, daemon->namebuff, NULL))
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000625 {
Simon Kelley82a14af2014-04-13 20:48:57 +0100626 /* Similar algorithm to search_servers. */
627 struct ipsets *ipset_pos;
628 unsigned int namelen = strlen(daemon->namebuff);
629 unsigned int matchlen = 0;
630 for (ipset_pos = daemon->ipsets; ipset_pos; ipset_pos = ipset_pos->next)
Simon Kelley6c0cb852014-01-17 14:40:46 +0000631 {
Simon Kelley82a14af2014-04-13 20:48:57 +0100632 unsigned int domainlen = strlen(ipset_pos->domain);
633 char *matchstart = daemon->namebuff + namelen - domainlen;
634 if (namelen >= domainlen && hostname_isequal(matchstart, ipset_pos->domain) &&
635 (domainlen == 0 || namelen == domainlen || *(matchstart - 1) == '.' ) &&
636 domainlen >= matchlen)
637 {
638 matchlen = domainlen;
639 sets = ipset_pos->sets;
640 }
Simon Kelley6c0cb852014-01-17 14:40:46 +0000641 }
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000642 }
643#endif
Simon Kelley25e63f12020-11-25 21:17:52 +0000644
Simon Kelley5bb88f02015-12-21 16:23:47 +0000645 if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign, NULL)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100646 {
Simon Kelley07ed5852018-05-04 21:52:22 +0100647 /* Get extended RCODE. */
648 rcode |= sizep[2] << 4;
649
Simon Kelleyed4c0762013-10-08 20:46:34 +0100650 if (check_subnet && !check_source(header, plen, pheader, query_source))
651 {
652 my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch"));
653 return 0;
654 }
Simon Kelley613ad152014-02-25 23:02:28 +0000655
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000656 if (!is_sign)
Simon Kelley613ad152014-02-25 23:02:28 +0000657 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000658 if (added_pheader)
659 {
660 /* client didn't send EDNS0, we added one, strip it off before returning answer. */
661 n = rrfilter(header, n, 0);
662 pheader = NULL;
663 }
664 else
665 {
Simon Kelley33702ab2015-12-28 23:17:15 +0000666 unsigned short udpsz;
667
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000668 /* If upstream is advertising a larger UDP packet size
669 than we allow, trim it so that we don't get overlarge
670 requests for the client. We can't do this for signed packets. */
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000671 GETSHORT(udpsz, sizep);
672 if (udpsz > daemon->edns_pktsz)
Simon Kelley33702ab2015-12-28 23:17:15 +0000673 {
674 sizep -= 2;
675 PUTSHORT(daemon->edns_pktsz, sizep);
676 }
677
678#ifdef HAVE_DNSSEC
679 /* If the client didn't set the do bit, but we did, reset it. */
680 if (option_bool(OPT_DNSSEC_VALID) && !do_bit)
681 {
682 unsigned short flags;
683 sizep += 2; /* skip RCODE */
684 GETSHORT(flags, sizep);
685 flags &= ~0x8000;
686 sizep -= 2;
687 PUTSHORT(flags, sizep);
688 }
689#endif
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000690 }
Simon Kelley613ad152014-02-25 23:02:28 +0000691 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100692 }
Simon Kelley83349b82014-02-10 21:02:01 +0000693
Simon Kelley28866e92011-02-14 20:19:14 +0000694 /* RFC 4035 sect 4.6 para 3 */
Giovanni Bajo237724c2012-04-05 02:46:52 +0200695 if (!is_sign && !option_bool(OPT_DNSSEC_PROXY))
Simon Kelley795501b2014-01-08 18:11:55 +0000696 header->hb4 &= ~HB4_AD;
Simon Kelley3a237152013-12-12 12:15:50 +0000697
Simon Kelley07ed5852018-05-04 21:52:22 +0100698 if (OPCODE(header) != QUERY)
Simon Kelley8938ae02014-05-01 17:46:25 +0100699 return resize_packet(header, n, pheader, plen);
Simon Kelley07ed5852018-05-04 21:52:22 +0100700
701 if (rcode != NOERROR && rcode != NXDOMAIN)
702 {
Simon Kelleycc921df2019-01-02 22:48:59 +0000703 union all_addr a;
704 a.log.rcode = rcode;
Simon Kelley07ed5852018-05-04 21:52:22 +0100705 log_query(F_UPSTREAM | F_RCODE, "error", &a, NULL);
706
707 return resize_packet(header, n, pheader, plen);
708 }
Simon Kelley36717ee2004-09-20 19:20:58 +0100709
Simon Kelley0a852542005-03-23 20:28:59 +0000710 /* Complain loudly if the upstream server is non-recursive. */
Simon Kelley07ed5852018-05-04 21:52:22 +0100711 if (!(header->hb4 & HB4_RA) && rcode == NOERROR &&
Simon Kelley0a852542005-03-23 20:28:59 +0000712 server && !(server->flags & SERV_WARNED_RECURSIVE))
713 {
Petr Mensik51cdd1a2019-07-04 20:28:08 +0200714 (void)prettyprint_addr(&server->addr, daemon->namebuff);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100715 my_syslog(LOG_WARNING, _("nameserver %s refused to do a recursive query"), daemon->namebuff);
Simon Kelley28866e92011-02-14 20:19:14 +0000716 if (!option_bool(OPT_LOG))
Simon Kelley0a852542005-03-23 20:28:59 +0000717 server->flags |= SERV_WARNED_RECURSIVE;
718 }
Giovanni Bajoe292e932012-04-22 14:32:02 +0200719
Simon Kelley07ed5852018-05-04 21:52:22 +0100720 if (daemon->bogus_addr && rcode != NXDOMAIN &&
Simon Kelley9eaa91b2021-03-17 20:31:06 +0000721 check_for_bogus_wildcard(header, n, daemon->namebuff, now))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100722 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100723 munged = 1;
Simon Kelley572b41e2011-02-18 18:11:18 +0000724 SET_RCODE(header, NXDOMAIN);
725 header->hb3 &= ~HB3_AA;
Simon Kelley6938f342014-01-26 22:47:39 +0000726 cache_secure = 0;
Simon Kelley36717ee2004-09-20 19:20:58 +0100727 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100728 else
Simon Kelley36717ee2004-09-20 19:20:58 +0100729 {
Simon Kelley6938f342014-01-26 22:47:39 +0000730 int doctored = 0;
731
Simon Kelley07ed5852018-05-04 21:52:22 +0100732 if (rcode == NXDOMAIN &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100733 extract_request(header, n, daemon->namebuff, NULL) &&
Simon Kelley5aabfc72007-08-29 11:24:47 +0100734 check_for_local_domain(daemon->namebuff, now))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100735 {
Simon Kelley36717ee2004-09-20 19:20:58 +0100736 /* if we forwarded a query for a locally known name (because it was for
737 an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
738 since we know that the domain exists, even if upstream doesn't */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100739 munged = 1;
Simon Kelley572b41e2011-02-18 18:11:18 +0000740 header->hb3 |= HB3_AA;
741 SET_RCODE(header, NOERROR);
Simon Kelley6938f342014-01-26 22:47:39 +0000742 cache_secure = 0;
Simon Kelley36717ee2004-09-20 19:20:58 +0100743 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000744
Simon Kelley373e9172017-12-01 22:40:56 +0000745 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 +0000746 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100747 my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
Simon Kelley824af852008-02-12 20:43:05 +0000748 munged = 1;
Simon Kelley6938f342014-01-26 22:47:39 +0000749 cache_secure = 0;
Simon Kelley824af852008-02-12 20:43:05 +0000750 }
Simon Kelley6938f342014-01-26 22:47:39 +0000751
752 if (doctored)
753 cache_secure = 0;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100754 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100755
Simon Kelleya25720a2014-01-14 23:13:55 +0000756#ifdef HAVE_DNSSEC
Simon Kelley33702ab2015-12-28 23:17:15 +0000757 if (bogusanswer && !(header->hb4 & HB4_CD) && !option_bool(OPT_DNSSEC_DEBUG))
Simon Kelleya25720a2014-01-14 23:13:55 +0000758 {
Simon Kelley33702ab2015-12-28 23:17:15 +0000759 /* Bogus reply, turn into SERVFAIL */
760 SET_RCODE(header, SERVFAIL);
761 munged = 1;
Simon Kelleya25720a2014-01-14 23:13:55 +0000762 }
Simon Kelley6938f342014-01-26 22:47:39 +0000763
764 if (option_bool(OPT_DNSSEC_VALID))
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000765 {
766 header->hb4 &= ~HB4_AD;
767
768 if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure)
769 header->hb4 |= HB4_AD;
770
771 /* If the requestor didn't set the DO bit, don't return DNSSEC info. */
772 if (!do_bit)
773 n = rrfilter(header, n, 1);
774 }
Simon Kelleya25720a2014-01-14 23:13:55 +0000775#endif
776
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100777 /* do this after extract_addresses. Ensure NODATA reply and remove
778 nameserver info. */
779
780 if (munged)
781 {
782 header->ancount = htons(0);
783 header->nscount = htons(0);
784 header->arcount = htons(0);
Simon Kelley150162b2015-03-27 09:58:26 +0000785 header->hb3 &= ~HB3_TC;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100786 }
787
Simon Kelley36717ee2004-09-20 19:20:58 +0100788 /* the bogus-nxdomain stuff, doctor and NXDOMAIN->NODATA munging can all elide
789 sections of the packet. Find the new length here and put back pseudoheader
790 if it was removed. */
791 return resize_packet(header, n, pheader, plen);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100792}
793
Simon Kelley3be34542004-09-11 19:12:13 +0100794/* sets new last_server */
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000795void reply_query(int fd, time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000796{
797 /* packet from peer server, extract data for cache, and send to
798 original requester */
Simon Kelley572b41e2011-02-18 18:11:18 +0000799 struct dns_header *header;
Simon Kelleyde379512004-06-22 20:23:33 +0100800 union mysockaddr serveraddr;
Simon Kelley832af0b2007-01-21 20:01:28 +0000801 struct frec *forward;
Simon Kelleyde379512004-06-22 20:23:33 +0100802 socklen_t addrlen = sizeof(serveraddr);
Simon Kelley60b68062014-01-08 12:10:28 +0000803 ssize_t n = recvfrom(fd, daemon->packet, daemon->packet_buff_sz, 0, &serveraddr.sa, &addrlen);
Simon Kelleycdeda282006-03-16 20:16:06 +0000804 size_t nn;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100805 struct server *server;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000806 void *hash;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000807
Simon Kelleycdeda282006-03-16 20:16:06 +0000808 /* packet buffer overwritten */
809 daemon->srv_save = NULL;
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000810
Simon Kelleyde379512004-06-22 20:23:33 +0100811 /* Determine the address of the server replying so that we can mark that as good */
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000812 if (serveraddr.sa.sa_family == AF_INET6)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100813 serveraddr.in6.sin6_flowinfo = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000814
Simon Kelley490f9072014-03-24 22:04:42 +0000815 header = (struct dns_header *)daemon->packet;
Simon Kelley6b173352018-05-08 18:32:14 +0100816
Simon Kelley490f9072014-03-24 22:04:42 +0000817 if (n < (int)sizeof(struct dns_header) || !(header->hb3 & HB3_QR))
818 return;
819
Simon Kelley1a6bca82008-07-11 11:11:42 +0100820 /* spoof check: answer must come from known server, */
821 for (server = daemon->servers; server; server = server->next)
822 if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) &&
823 sockaddr_isequal(&server->addr, &serveraddr))
824 break;
Simon Kelley490f9072014-03-24 22:04:42 +0000825
826 if (!server)
827 return;
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000828
829 /* If sufficient time has elapsed, try and expand UDP buffer size again. */
830 if (difftime(now, server->pktsz_reduced) > UDP_TEST_TIME)
831 server->edns_pktsz = daemon->edns_pktsz;
832
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000833 hash = hash_questions(header, n, daemon->namebuff);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100834
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000835 if (!(forward = lookup_frec(ntohs(header->id), fd, hash)))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100836 return;
Simon Kelley490f9072014-03-24 22:04:42 +0000837
Simon Kelley6b173352018-05-08 18:32:14 +0100838#ifdef HAVE_DUMPFILE
839 dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_REPLY : DUMP_UP_REPLY,
840 (void *)header, n, &serveraddr, NULL);
841#endif
Simon Kelleya0088e82018-05-10 21:43:14 +0100842
Simon Kelley25cf5e32015-01-09 15:53:03 +0000843 /* log_query gets called indirectly all over the place, so
844 pass these in global variables - sorry. */
Simon Kelley15b60dd2020-11-18 18:34:55 +0000845 daemon->log_display_id = forward->frec_src.log_id;
846 daemon->log_source_addr = &forward->frec_src.source;
Simon Kelley25cf5e32015-01-09 15:53:03 +0000847
Glen Huang32fc6db2014-12-27 15:28:12 +0000848 if (daemon->ignore_addr && RCODE(header) == NOERROR &&
Simon Kelley9eaa91b2021-03-17 20:31:06 +0000849 check_for_ignored_address(header, n))
Glen Huang32fc6db2014-12-27 15:28:12 +0000850 return;
851
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000852 /* Note: if we send extra options in the EDNS0 header, we can't recreate
853 the query from the reply. */
Simon Kelley34e26e12018-05-10 20:54:57 +0100854 if ((RCODE(header) == REFUSED || RCODE(header) == SERVFAIL) &&
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000855 forward->forwardall == 0 &&
856 !(forward->flags & FREC_HAS_EXTRADATA))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100857 /* for broken servers, attempt to send to another one. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000858 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100859 unsigned char *pheader;
860 size_t plen;
861 int is_sign;
Simon Kelleyef3d1372017-12-05 22:37:29 +0000862
Simon Kelley1f60a182018-05-11 16:44:16 +0100863#ifdef HAVE_DNSSEC
Simon Kelleya0088e82018-05-10 21:43:14 +0100864 if (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY))
865 {
Simon Kelley1f60a182018-05-11 16:44:16 +0100866 struct server *start;
867
Simon Kelleya0088e82018-05-10 21:43:14 +0100868 blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
869 plen = forward->stash_len;
870
871 forward->forwardall = 2; /* only retry once */
Simon Kelley1f60a182018-05-11 16:44:16 +0100872 start = forward->sentto;
873
874 /* for non-domain specific servers, see if we can find another to try. */
875 if ((forward->sentto->flags & SERV_TYPE) == 0)
876 while (1)
877 {
878 if (!(start = start->next))
879 start = daemon->servers;
880 if (start == forward->sentto)
881 break;
882
883 if ((start->flags & SERV_TYPE) == 0 &&
884 (start->flags & SERV_DO_DNSSEC))
885 break;
886 }
887
888
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000889 if ((fd = allocate_rfd(&forward->rfds, start)) == -1)
Simon Kelley82446112020-11-15 22:13:25 +0000890 return;
891
Simon Kelleye3002bf2019-10-11 23:30:08 +0100892#ifdef HAVE_DUMPFILE
893 dump_packet(DUMP_SEC_QUERY, (void *)header, (size_t)plen, NULL, &start->addr);
894#endif
895
Simon Kelleya0088e82018-05-10 21:43:14 +0100896 while (retry_send(sendto(fd, (char *)header, plen, 0,
Simon Kelley1f60a182018-05-11 16:44:16 +0100897 &start->addr.sa,
898 sa_len(&start->addr))));
Simon Kelleya0088e82018-05-10 21:43:14 +0100899
Petr Menšík6c0bf792021-03-18 00:07:45 +0100900 log_query_mysockaddr(F_NOEXTRA | F_DNSSEC, "retry", &start->addr, "dnssec");
Simon Kelleye27825b2018-05-11 17:20:47 +0100901
Simon Kelleya0088e82018-05-10 21:43:14 +0100902 return;
903 }
Simon Kelley1f60a182018-05-11 16:44:16 +0100904#endif
905
Simon Kelleyef3d1372017-12-05 22:37:29 +0000906 /* In strict order mode, there must be a server later in the chain
907 left to send to, otherwise without the forwardall mechanism,
908 code further on will cycle around the list forwever if they
909 all return REFUSED. Note that server is always non-NULL before
910 this executes. */
911 if (option_bool(OPT_ORDER))
912 for (server = forward->sentto->next; server; server = server->next)
913 if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR | SERV_LOOP)))
914 break;
915
Simon Kelley1a6bca82008-07-11 11:11:42 +0100916 /* recreate query from reply */
Simon Kelley5bb88f02015-12-21 16:23:47 +0000917 pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign, NULL);
Simon Kelleyef3d1372017-12-05 22:37:29 +0000918 if (!is_sign && server)
Simon Kelley832af0b2007-01-21 20:01:28 +0000919 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100920 header->ancount = htons(0);
921 header->nscount = htons(0);
922 header->arcount = htons(0);
923 if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
924 {
swiggerbd7bfa22015-06-01 20:54:59 +0100925 header->hb3 &= ~(HB3_QR | HB3_AA | HB3_TC);
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000926 header->hb4 &= ~(HB4_RA | HB4_RCODE | HB4_CD | HB4_AD);
Simon Kelley1801a292016-01-17 21:53:57 +0000927 if (forward->flags & FREC_CHECKING_DISABLED)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000928 header->hb4 |= HB4_CD;
Simon Kelley1801a292016-01-17 21:53:57 +0000929 if (forward->flags & FREC_AD_QUESTION)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000930 header->hb4 |= HB4_AD;
931 if (forward->flags & FREC_DO_QUESTION)
Simon Kelley33702ab2015-12-28 23:17:15 +0000932 add_do_bit(header, nn, (unsigned char *)pheader + plen);
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000933 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 +0100934 return;
935 }
936 }
937 }
Simon Kelley3a237152013-12-12 12:15:50 +0000938
939 server = forward->sentto;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100940 if ((forward->sentto->flags & SERV_TYPE) == 0)
941 {
Simon Kelley51967f92014-03-25 21:07:00 +0000942 if (RCODE(header) == REFUSED)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100943 server = NULL;
944 else
945 {
946 struct server *last_server;
Simon Kelley832af0b2007-01-21 20:01:28 +0000947
Simon Kelley1a6bca82008-07-11 11:11:42 +0100948 /* find good server by address if possible, otherwise assume the last one we sent to */
949 for (last_server = daemon->servers; last_server; last_server = last_server->next)
950 if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) &&
951 sockaddr_isequal(&last_server->addr, &serveraddr))
952 {
953 server = last_server;
954 break;
955 }
956 }
Simon Kelley28866e92011-02-14 20:19:14 +0000957 if (!option_bool(OPT_ALL_SERVERS))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100958 daemon->last_server = server;
959 }
Simon Kelleya77cec82015-05-08 16:25:38 +0100960
961 /* We tried resending to this server with a smaller maximum size and got an answer.
Ville Skyttäfaaf3062018-01-14 17:32:52 +0000962 Make that permanent. To avoid reduxing the packet size for a single dropped packet,
Simon Kelley86fa1042015-05-10 13:50:59 +0100963 only do this when we get a truncated answer, or one larger than the safe size. */
Simon Kelley04db1482019-10-11 23:22:17 +0100964 if (forward->sentto->edns_pktsz > SAFE_PKTSZ && (forward->flags & FREC_TEST_PKTSZ) &&
Simon Kelley86fa1042015-05-10 13:50:59 +0100965 ((header->hb3 & HB3_TC) || n >= SAFE_PKTSZ))
Simon Kelley22dee512017-10-13 22:54:00 +0100966 {
Simon Kelley04db1482019-10-11 23:22:17 +0100967 forward->sentto->edns_pktsz = SAFE_PKTSZ;
968 forward->sentto->pktsz_reduced = now;
Petr Mensik51cdd1a2019-07-04 20:28:08 +0200969 (void)prettyprint_addr(&forward->sentto->addr, daemon->addrbuff);
Simon Kelleyebedcba2017-10-29 20:54:17 +0000970 my_syslog(LOG_WARNING, _("reducing DNS packet size for nameserver %s to %d"), daemon->addrbuff, SAFE_PKTSZ);
Simon Kelley22dee512017-10-13 22:54:00 +0100971 }
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000972
973
Simon Kelley1a6bca82008-07-11 11:11:42 +0100974 /* If the answer is an error, keep the forward record in place in case
975 we get a good reply from another server. Kill it when we've
976 had replies from all to avoid filling the forwarding table when
977 everything is broken */
Simon Kelley122392e2018-10-31 22:24:02 +0000978 if (forward->forwardall == 0 || --forward->forwardall == 1 || RCODE(header) != REFUSED)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100979 {
Simon Kelleyfe3992f2015-04-03 21:25:05 +0100980 int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
Simon Kelleya6004d72017-10-25 17:48:19 +0100981
Simon Kelley3a237152013-12-12 12:15:50 +0000982 if (option_bool(OPT_NO_REBIND))
983 check_rebind = !(forward->flags & FREC_NOREBIND);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100984
Simon Kelley3a237152013-12-12 12:15:50 +0000985 /* Don't cache replies where DNSSEC validation was turned off, either
986 the upstream server told us so, or the original query specified it. */
987 if ((header->hb4 & HB4_CD) || (forward->flags & FREC_CHECKING_DISABLED))
988 no_cache_dnssec = 1;
989
990#ifdef HAVE_DNSSEC
Simon Kelley04db1482019-10-11 23:22:17 +0100991 if ((forward->sentto->flags & SERV_DO_DNSSEC) &&
Simon Kelley57573712016-01-11 22:50:00 +0000992 option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED))
Simon Kelley3a237152013-12-12 12:15:50 +0000993 {
Simon Kelley9a31b682015-12-15 10:20:39 +0000994 int status = 0;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000995
996 /* We've had a reply already, which we're validating. Ignore this duplicate */
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000997 if (forward->blocking_query)
Simon Kelley0fc2f312014-01-08 10:26:58 +0000998 return;
Simon Kelley9a31b682015-12-15 10:20:39 +0000999
1000 /* Truncated answer can't be validated.
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001001 If this is an answer to a DNSSEC-generated query, we still
1002 need to get the client to retry over TCP, so return
1003 an answer with the TC bit set, even if the actual answer fits.
1004 */
Simon Kelley9a31b682015-12-15 10:20:39 +00001005 if (header->hb3 & HB3_TC)
1006 status = STAT_TRUNCATED;
1007
1008 while (1)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001009 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001010 /* As soon as anything returns BOGUS, we stop and unwind, to do otherwise
1011 would invite infinite loops, since the answers to DNSKEY and DS queries
1012 will not be cached, so they'll be repeated. */
1013 if (status != STAT_BOGUS && status != STAT_TRUNCATED && status != STAT_ABANDONED)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001014 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001015 if (forward->flags & FREC_DNSKEY_QUERY)
1016 status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
1017 else if (forward->flags & FREC_DS_QUERY)
1018 status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001019 else
Simon Kelley9a31b682015-12-15 10:20:39 +00001020 status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class,
Simon Kelley203ce0a2019-10-12 21:41:20 +01001021 !option_bool(OPT_DNSSEC_IGN_NS) && (forward->sentto->flags & SERV_DO_DNSSEC),
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001022 NULL, NULL, NULL);
Simon Kelley6b173352018-05-08 18:32:14 +01001023#ifdef HAVE_DUMPFILE
1024 if (status == STAT_BOGUS)
1025 dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_BOGUS : DUMP_BOGUS,
1026 header, (size_t)n, &serveraddr, NULL);
1027#endif
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001028 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001029
Simon Kelley9a31b682015-12-15 10:20:39 +00001030 /* Can't validate, as we're missing key data. Put this
1031 answer aside, whilst we get that. */
1032 if (status == STAT_NEED_DS || status == STAT_NEED_KEY)
Simon Kelley3a237152013-12-12 12:15:50 +00001033 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001034 struct frec *new, *orig;
Simon Kelley9d633042013-12-13 15:36:55 +00001035
Simon Kelley9a31b682015-12-15 10:20:39 +00001036 /* Free any saved query */
1037 if (forward->stash)
1038 blockdata_free(forward->stash);
1039
1040 /* Now save reply pending receipt of key data */
1041 if (!(forward->stash = blockdata_alloc((char *)header, n)))
Simon Kelley97e618a2015-01-07 21:55:43 +00001042 return;
Simon Kelley9a31b682015-12-15 10:20:39 +00001043 forward->stash_len = n;
Simon Kelleye0c0ad32014-01-16 22:42:07 +00001044
Simon Kelley9a31b682015-12-15 10:20:39 +00001045 /* Find the original query that started it all.... */
1046 for (orig = forward; orig->dependent; orig = orig->dependent);
Simon Kelley7fa836e2014-02-10 20:11:24 +00001047
Simon Kelley8caf3d72020-04-04 17:00:32 +01001048 /* Make sure we don't expire and free the orig frec during the
1049 allocation of a new one. */
1050 if (--orig->work_counter == 0 || !(new = get_new_frec(now, NULL, orig)))
Simon Kelley9a31b682015-12-15 10:20:39 +00001051 status = STAT_ABANDONED;
Simon Kelleye0c0ad32014-01-16 22:42:07 +00001052 else
Simon Kelley3a237152013-12-12 12:15:50 +00001053 {
Simon Kelleye1791f32018-10-06 23:23:23 +01001054 int querytype, fd, type = SERV_DO_DNSSEC;
Simon Kelley9a31b682015-12-15 10:20:39 +00001055 struct frec *next = new->next;
Simon Kelley92be34a2016-01-16 18:39:54 +00001056 char *domain;
1057
Simon Kelley9a31b682015-12-15 10:20:39 +00001058 *new = *forward; /* copy everything, then overwrite */
1059 new->next = next;
1060 new->blocking_query = NULL;
Simon Kelley92be34a2016-01-16 18:39:54 +00001061
1062 /* Find server to forward to. This will normally be the
1063 same as for the original query, but may be another if
1064 servers for domains are involved. */
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001065 if (search_servers(now, NULL, F_DNSSECOK, daemon->keyname, &type, &domain, NULL) == 0)
Simon Kelley92be34a2016-01-16 18:39:54 +00001066 {
Simon Kelley203ce0a2019-10-12 21:41:20 +01001067 struct server *start, *new_server = NULL;
1068 start = server = forward->sentto;
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001069
1070 while (1)
1071 {
1072 if (type == (start->flags & (SERV_TYPE | SERV_DO_DNSSEC)) &&
Simon Kelley1f60a182018-05-11 16:44:16 +01001073 ((type & SERV_TYPE) != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001074 !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
1075 {
1076 new_server = start;
1077 if (server == start)
1078 {
1079 new_server = NULL;
1080 break;
1081 }
1082 }
1083
1084 if (!(start = start->next))
1085 start = daemon->servers;
1086 if (start == server)
1087 break;
1088 }
1089
1090 if (new_server)
1091 server = new_server;
Simon Kelley92be34a2016-01-16 18:39:54 +00001092 }
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001093
Simon Kelley9a31b682015-12-15 10:20:39 +00001094 new->sentto = server;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00001095 new->rfds = NULL;
Simon Kelley15b60dd2020-11-18 18:34:55 +00001096 new->frec_src.next = NULL;
Simon Kelleya0088e82018-05-10 21:43:14 +01001097 new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_HAS_EXTRADATA);
1098 new->forwardall = 0;
Simon Kelley9a31b682015-12-15 10:20:39 +00001099
1100 new->dependent = forward; /* to find query awaiting new one. */
1101 forward->blocking_query = new; /* for garbage cleaning */
1102 /* validate routines leave name of required record in daemon->keyname */
1103 if (status == STAT_NEED_KEY)
Simon Kelley7fa836e2014-02-10 20:11:24 +00001104 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001105 new->flags |= FREC_DNSKEY_QUERY;
Simon Kelleye1791f32018-10-06 23:23:23 +01001106 querytype = T_DNSKEY;
Simon Kelleyf1668d22014-01-08 16:53:27 +00001107 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001108 else
1109 {
1110 new->flags |= FREC_DS_QUERY;
Simon Kelleye1791f32018-10-06 23:23:23 +01001111 querytype = T_DS;
Simon Kelley9a31b682015-12-15 10:20:39 +00001112 }
Simon Kelleye1791f32018-10-06 23:23:23 +01001113
1114 nn = dnssec_generate_query(header,((unsigned char *) header) + server->edns_pktsz,
1115 daemon->keyname, forward->class, querytype, server->edns_pktsz);
1116
Petr Menšík6c0bf792021-03-18 00:07:45 +01001117 log_query_mysockaddr(F_NOEXTRA | F_DNSSEC, daemon->keyname, &server->addr,
1118 querystr("dnssec-query", querytype));
1119
Simon Kelley2d765862020-11-12 22:06:07 +00001120 memcpy(new->hash, hash_questions(header, nn, daemon->namebuff), HASH_SIZE);
Simon Kelley9a31b682015-12-15 10:20:39 +00001121 new->new_id = get_id();
1122 header->id = htons(new->new_id);
1123 /* Save query for retransmission */
1124 new->stash = blockdata_alloc((char *)header, nn);
1125 new->stash_len = nn;
1126
1127 /* Don't resend this. */
1128 daemon->srv_save = NULL;
1129
Simon Kelley74d4fcd2021-03-15 21:59:51 +00001130 if ((fd = allocate_rfd(&new->rfds, server)) != -1)
Simon Kelley9a31b682015-12-15 10:20:39 +00001131 {
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001132#ifdef HAVE_CONNTRACK
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001133 if (option_bool(OPT_CONNTRACK))
Petr Menšík6c0bf792021-03-18 00:07:45 +01001134 set_outgoing_mark(orig, fd);
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001135#endif
Simon Kelley6b173352018-05-08 18:32:14 +01001136
1137#ifdef HAVE_DUMPFILE
1138 dump_packet(DUMP_SEC_QUERY, (void *)header, (size_t)nn, NULL, &server->addr);
1139#endif
1140
Simon Kelley9a31b682015-12-15 10:20:39 +00001141 while (retry_send(sendto(fd, (char *)header, nn, 0,
1142 &server->addr.sa,
1143 sa_len(&server->addr))));
1144 server->queries++;
1145 }
1146 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00001147 return;
Simon Kelley3a237152013-12-12 12:15:50 +00001148 }
Simon Kelley3a237152013-12-12 12:15:50 +00001149
Simon Kelley9a31b682015-12-15 10:20:39 +00001150 /* Validated original answer, all done. */
1151 if (!forward->dependent)
1152 break;
1153
Josh Soref730c6742017-02-06 16:14:04 +00001154 /* validated subsidiary query, (and cached result)
Simon Kelley9a31b682015-12-15 10:20:39 +00001155 pop that and return to the previous query we were working on. */
Simon Kelley0744ca62014-01-25 16:40:15 +00001156 struct frec *prev = forward->dependent;
1157 free_frec(forward);
1158 forward = prev;
1159 forward->blocking_query = NULL; /* already gone */
1160 blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
1161 n = forward->stash_len;
Simon Kelley3a237152013-12-12 12:15:50 +00001162 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001163
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001164
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001165 no_cache_dnssec = 0;
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001166
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001167 if (status == STAT_TRUNCATED)
Simon Kelley0744ca62014-01-25 16:40:15 +00001168 header->hb3 |= HB3_TC;
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001169 else
Simon Kelley7fa836e2014-02-10 20:11:24 +00001170 {
Simon Kelley554b5802015-04-17 22:50:20 +01001171 char *result, *domain = "result";
Simon Kelley7fa836e2014-02-10 20:11:24 +00001172
Simon Kelley9a31b682015-12-15 10:20:39 +00001173 if (status == STAT_ABANDONED)
Simon Kelley150162b2015-03-27 09:58:26 +00001174 {
1175 result = "ABANDONED";
1176 status = STAT_BOGUS;
1177 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00001178 else
1179 result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
1180
Simon Kelley554b5802015-04-17 22:50:20 +01001181 if (status == STAT_BOGUS && extract_request(header, n, daemon->namebuff, NULL))
1182 domain = daemon->namebuff;
Simon Kelley9a31b682015-12-15 10:20:39 +00001183
Simon Kelley07ed5852018-05-04 21:52:22 +01001184 log_query(F_SECSTAT, domain, NULL, result);
Simon Kelley7fa836e2014-02-10 20:11:24 +00001185 }
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001186
Simon Kelley3a237152013-12-12 12:15:50 +00001187 if (status == STAT_SECURE)
1188 cache_secure = 1;
Simon Kelley3a237152013-12-12 12:15:50 +00001189 else if (status == STAT_BOGUS)
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001190 {
1191 no_cache_dnssec = 1;
1192 bogusanswer = 1;
1193 }
Simon Kelley3a237152013-12-12 12:15:50 +00001194 }
Simon Kelley04db1482019-10-11 23:22:17 +01001195
Simon Kelley6b173352018-05-08 18:32:14 +01001196#endif
1197
Simon Kelley83349b82014-02-10 21:02:01 +00001198 /* restore CD bit to the value in the query */
1199 if (forward->flags & FREC_CHECKING_DISABLED)
1200 header->hb4 |= HB4_CD;
1201 else
1202 header->hb4 &= ~HB4_CD;
Simon Kelley25e63f12020-11-25 21:17:52 +00001203
1204 /* Never cache answers which are contingent on the source or MAC address EDSN0 option,
1205 since the cache is ignorant of such things. */
1206 if (forward->flags & FREC_NO_CACHE)
1207 no_cache_dnssec = 1;
Simon Kelley3a237152013-12-12 12:15:50 +00001208
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001209 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 +00001210 forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION,
Simon Kelley15b60dd2020-11-18 18:34:55 +00001211 forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->frec_src.source)))
Simon Kelley832af0b2007-01-21 20:01:28 +00001212 {
Simon Kelley15b60dd2020-11-18 18:34:55 +00001213 struct frec_src *src;
1214
1215 header->id = htons(forward->frec_src.orig_id);
Simon Kelley572b41e2011-02-18 18:11:18 +00001216 header->hb4 |= HB4_RA; /* recursion if available */
Simon Kelley5aa5f0f2015-12-21 17:20:35 +00001217#ifdef HAVE_DNSSEC
1218 /* 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 +01001219 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 +00001220 header, the answer is still bigger than 512, truncate it and mark it so. The client then retries with TCP. */
1221 if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER) && (nn > PACKETSZ))
1222 {
1223 header->ancount = htons(0);
1224 header->nscount = htons(0);
1225 header->arcount = htons(0);
1226 header->hb3 |= HB3_TC;
1227 nn = resize_packet(header, nn, NULL, 0);
1228 }
1229#endif
Simon Kelley6b173352018-05-08 18:32:14 +01001230
Simon Kelley15b60dd2020-11-18 18:34:55 +00001231 for (src = &forward->frec_src; src; src = src->next)
1232 {
1233 header->id = htons(src->orig_id);
1234
Simon Kelley6b173352018-05-08 18:32:14 +01001235#ifdef HAVE_DUMPFILE
Simon Kelley15b60dd2020-11-18 18:34:55 +00001236 dump_packet(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &src->source);
Simon Kelley6b173352018-05-08 18:32:14 +01001237#endif
Simon Kelley15b60dd2020-11-18 18:34:55 +00001238
Simon Kelley04490bf2021-01-22 16:49:12 +00001239 send_from(src->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
Simon Kelley15b60dd2020-11-18 18:34:55 +00001240 &src->source, &src->dest, src->iface);
1241
1242 if (option_bool(OPT_EXTRALOG) && src != &forward->frec_src)
1243 {
1244 daemon->log_display_id = src->log_id;
1245 daemon->log_source_addr = &src->source;
1246 log_query(F_UPSTREAM, "query", NULL, "duplicate");
1247 }
1248 }
Simon Kelley832af0b2007-01-21 20:01:28 +00001249 }
Simon Kelley15b60dd2020-11-18 18:34:55 +00001250
Simon Kelley1a6bca82008-07-11 11:11:42 +01001251 free_frec(forward); /* cancel */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001252 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001253}
Simon Kelley44a2a312004-03-10 20:04:35 +00001254
Simon Kelley1a6bca82008-07-11 11:11:42 +01001255
Simon Kelley5aabfc72007-08-29 11:24:47 +01001256void receive_query(struct listener *listen, time_t now)
Simon Kelley44a2a312004-03-10 20:04:35 +00001257{
Simon Kelley572b41e2011-02-18 18:11:18 +00001258 struct dns_header *header = (struct dns_header *)daemon->packet;
Simon Kelley44a2a312004-03-10 20:04:35 +00001259 union mysockaddr source_addr;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001260 unsigned char *pheader;
1261 unsigned short type, udp_size = PACKETSZ; /* default if no EDNS0 */
Simon Kelleycc921df2019-01-02 22:48:59 +00001262 union all_addr dst_addr;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001263 struct in_addr netmask, dst_addr_4;
Simon Kelleycdeda282006-03-16 20:16:06 +00001264 size_t m;
1265 ssize_t n;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001266 int if_index = 0, auth_dns = 0, do_bit = 0, have_pseudoheader = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001267#ifdef HAVE_AUTH
1268 int local_auth = 0;
1269#endif
Simon Kelley44a2a312004-03-10 20:04:35 +00001270 struct iovec iov[1];
1271 struct msghdr msg;
1272 struct cmsghdr *cmptr;
Simon Kelley44a2a312004-03-10 20:04:35 +00001273 union {
1274 struct cmsghdr align; /* this ensures alignment */
Simon Kelley44a2a312004-03-10 20:04:35 +00001275 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001276#if defined(HAVE_LINUX_NETWORK)
Simon Kelley44a2a312004-03-10 20:04:35 +00001277 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
Simon Kelley824af852008-02-12 20:43:05 +00001278#elif defined(IP_RECVDSTADDR) && defined(HAVE_SOLARIS_NETWORK)
1279 char control[CMSG_SPACE(sizeof(struct in_addr)) +
1280 CMSG_SPACE(sizeof(unsigned int))];
Simon Kelley44a2a312004-03-10 20:04:35 +00001281#elif defined(IP_RECVDSTADDR)
1282 char control[CMSG_SPACE(sizeof(struct in_addr)) +
1283 CMSG_SPACE(sizeof(struct sockaddr_dl))];
1284#endif
1285 } control_u;
Petr Menšík1c1b9252019-07-15 17:16:44 +02001286 int family = listen->addr.sa.sa_family;
Simon Kelley2329bef2013-12-03 13:41:16 +00001287 /* Can always get recvd interface for IPv6 */
Petr Menšík1c1b9252019-07-15 17:16:44 +02001288 int check_dst = !option_bool(OPT_NOWILD) || family == AF_INET6;
Simon Kelley2329bef2013-12-03 13:41:16 +00001289
Simon Kelleycdeda282006-03-16 20:16:06 +00001290 /* packet buffer overwritten */
1291 daemon->srv_save = NULL;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00001292
Simon Kelleycc921df2019-01-02 22:48:59 +00001293 dst_addr_4.s_addr = dst_addr.addr4.s_addr = 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001294 netmask.s_addr = 0;
1295
Simon Kelley7e5664b2013-04-05 16:57:41 +01001296 if (option_bool(OPT_NOWILD) && listen->iface)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001297 {
Simon Kelley4f7b3042012-11-28 21:27:02 +00001298 auth_dns = listen->iface->dns_auth;
1299
Petr Menšík1c1b9252019-07-15 17:16:44 +02001300 if (family == AF_INET)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001301 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001302 dst_addr_4 = dst_addr.addr4 = listen->iface->addr.in.sin_addr;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001303 netmask = listen->iface->netmask;
1304 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001305 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00001306
Simon Kelley3be34542004-09-11 19:12:13 +01001307 iov[0].iov_base = daemon->packet;
1308 iov[0].iov_len = daemon->edns_pktsz;
Simon Kelley44a2a312004-03-10 20:04:35 +00001309
1310 msg.msg_control = control_u.control;
1311 msg.msg_controllen = sizeof(control_u);
1312 msg.msg_flags = 0;
1313 msg.msg_name = &source_addr;
1314 msg.msg_namelen = sizeof(source_addr);
1315 msg.msg_iov = iov;
1316 msg.msg_iovlen = 1;
1317
Simon Kelleyde379512004-06-22 20:23:33 +01001318 if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
Simon Kelley3be34542004-09-11 19:12:13 +01001319 return;
Simon Kelley44a2a312004-03-10 20:04:35 +00001320
Simon Kelley572b41e2011-02-18 18:11:18 +00001321 if (n < (int)sizeof(struct dns_header) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001322 (msg.msg_flags & MSG_TRUNC) ||
Simon Kelley572b41e2011-02-18 18:11:18 +00001323 (header->hb3 & HB3_QR))
Simon Kelley3be34542004-09-11 19:12:13 +01001324 return;
Simon Kelley63437ff2017-09-06 22:34:21 +01001325
1326 /* Clear buffer beyond request to avoid risk of
1327 information disclosure. */
1328 memset(daemon->packet + n, 0, daemon->edns_pktsz - n);
Simon Kelley44a2a312004-03-10 20:04:35 +00001329
Petr Menšík1c1b9252019-07-15 17:16:44 +02001330 source_addr.sa.sa_family = family;
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001331
Petr Menšík1c1b9252019-07-15 17:16:44 +02001332 if (family == AF_INET)
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001333 {
1334 /* Source-port == 0 is an error, we can't send back to that.
1335 http://www.ietf.org/mail-archive/web/dnsop/current/msg11441.html */
1336 if (source_addr.in.sin_port == 0)
1337 return;
1338 }
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001339 else
1340 {
1341 /* Source-port == 0 is an error, we can't send back to that. */
1342 if (source_addr.in6.sin6_port == 0)
1343 return;
1344 source_addr.in6.sin6_flowinfo = 0;
1345 }
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001346
Simon Kelleyc8a80482014-03-05 14:29:54 +00001347 /* We can be configured to only accept queries from at-most-one-hop-away addresses. */
1348 if (option_bool(OPT_LOCAL_SERVICE))
1349 {
1350 struct addrlist *addr;
Simon Kelleyee875042018-10-23 22:10:17 +01001351
Petr Menšík1c1b9252019-07-15 17:16:44 +02001352 if (family == AF_INET6)
Simon Kelleyc8a80482014-03-05 14:29:54 +00001353 {
1354 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1355 if ((addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001356 is_same_net6(&addr->addr.addr6, &source_addr.in6.sin6_addr, addr->prefixlen))
Simon Kelleyc8a80482014-03-05 14:29:54 +00001357 break;
1358 }
1359 else
Simon Kelleyc8a80482014-03-05 14:29:54 +00001360 {
1361 struct in_addr netmask;
1362 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1363 {
Richard Genoud15b1b7e2014-09-17 21:12:00 +01001364 netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
Simon Kelleyc8a80482014-03-05 14:29:54 +00001365 if (!(addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001366 is_same_net(addr->addr.addr4, source_addr.in.sin_addr, netmask))
Simon Kelleyc8a80482014-03-05 14:29:54 +00001367 break;
1368 }
1369 }
1370 if (!addr)
1371 {
Simon Kelley0c8584e2014-03-12 20:12:56 +00001372 static int warned = 0;
1373 if (!warned)
1374 {
1375 my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
1376 warned = 1;
1377 }
Simon Kelleyc8a80482014-03-05 14:29:54 +00001378 return;
1379 }
1380 }
1381
Simon Kelley2329bef2013-12-03 13:41:16 +00001382 if (check_dst)
Simon Kelley44a2a312004-03-10 20:04:35 +00001383 {
Simon Kelley8a911cc2004-03-16 18:35:52 +00001384 struct ifreq ifr;
1385
Simon Kelley26128d22004-11-14 16:43:54 +00001386 if (msg.msg_controllen < sizeof(struct cmsghdr))
1387 return;
1388
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001389#if defined(HAVE_LINUX_NETWORK)
Petr Menšík1c1b9252019-07-15 17:16:44 +02001390 if (family == AF_INET)
Simon Kelley26128d22004-11-14 16:43:54 +00001391 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelleyc72daea2012-01-05 21:33:27 +00001392 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
Simon Kelley26128d22004-11-14 16:43:54 +00001393 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001394 union {
1395 unsigned char *c;
1396 struct in_pktinfo *p;
1397 } p;
1398 p.c = CMSG_DATA(cmptr);
Simon Kelleycc921df2019-01-02 22:48:59 +00001399 dst_addr_4 = dst_addr.addr4 = p.p->ipi_spec_dst;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001400 if_index = p.p->ipi_ifindex;
Simon Kelley26128d22004-11-14 16:43:54 +00001401 }
1402#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
Petr Menšík1c1b9252019-07-15 17:16:44 +02001403 if (family == AF_INET)
Simon Kelley26128d22004-11-14 16:43:54 +00001404 {
1405 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001406 {
1407 union {
1408 unsigned char *c;
1409 unsigned int *i;
1410 struct in_addr *a;
1411#ifndef HAVE_SOLARIS_NETWORK
1412 struct sockaddr_dl *s;
Simon Kelley824af852008-02-12 20:43:05 +00001413#endif
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001414 } p;
1415 p.c = CMSG_DATA(cmptr);
1416 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
Simon Kelleycc921df2019-01-02 22:48:59 +00001417 dst_addr_4 = dst_addr.addr4 = *(p.a);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001418 else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
1419#ifdef HAVE_SOLARIS_NETWORK
1420 if_index = *(p.i);
1421#else
1422 if_index = p.s->sdl_index;
1423#endif
1424 }
Simon Kelley26128d22004-11-14 16:43:54 +00001425 }
1426#endif
1427
Petr Menšík1c1b9252019-07-15 17:16:44 +02001428 if (family == AF_INET6)
Simon Kelley26128d22004-11-14 16:43:54 +00001429 {
1430 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelleyc72daea2012-01-05 21:33:27 +00001431 if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
Simon Kelley26128d22004-11-14 16:43:54 +00001432 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001433 union {
1434 unsigned char *c;
1435 struct in6_pktinfo *p;
1436 } p;
1437 p.c = CMSG_DATA(cmptr);
1438
Simon Kelleycc921df2019-01-02 22:48:59 +00001439 dst_addr.addr6 = p.p->ipi6_addr;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001440 if_index = p.p->ipi6_ifindex;
Simon Kelley26128d22004-11-14 16:43:54 +00001441 }
1442 }
Simon Kelley26128d22004-11-14 16:43:54 +00001443
1444 /* enforce available interface configuration */
1445
Simon Kelleye25db1f2013-01-29 22:10:26 +00001446 if (!indextoname(listen->fd, if_index, ifr.ifr_name))
Simon Kelley832af0b2007-01-21 20:01:28 +00001447 return;
1448
Petr Menšík1c1b9252019-07-15 17:16:44 +02001449 if (!iface_check(family, &dst_addr, ifr.ifr_name, &auth_dns))
Simon Kelleye25db1f2013-01-29 22:10:26 +00001450 {
1451 if (!option_bool(OPT_CLEVERBIND))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001452 enumerate_interfaces(0);
Petr Menšík1c1b9252019-07-15 17:16:44 +02001453 if (!loopback_exception(listen->fd, family, &dst_addr, ifr.ifr_name) &&
1454 !label_exception(if_index, family, &dst_addr))
Simon Kelleye25db1f2013-01-29 22:10:26 +00001455 return;
1456 }
1457
Petr Menšík1c1b9252019-07-15 17:16:44 +02001458 if (family == AF_INET && option_bool(OPT_LOCALISE))
Simon Kelley552af8b2012-02-29 20:10:31 +00001459 {
1460 struct irec *iface;
1461
Josh Soref730c6742017-02-06 16:14:04 +00001462 /* get the netmask of the interface which has the address we were sent to.
klemens43517fc2017-02-19 15:53:37 +00001463 This is no necessarily the interface we arrived on. */
Simon Kelley552af8b2012-02-29 20:10:31 +00001464
1465 for (iface = daemon->interfaces; iface; iface = iface->next)
1466 if (iface->addr.sa.sa_family == AF_INET &&
1467 iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
1468 break;
1469
1470 /* interface may be new */
Simon Kelleye25db1f2013-01-29 22:10:26 +00001471 if (!iface && !option_bool(OPT_CLEVERBIND))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001472 enumerate_interfaces(0);
Simon Kelley552af8b2012-02-29 20:10:31 +00001473
1474 for (iface = daemon->interfaces; iface; iface = iface->next)
1475 if (iface->addr.sa.sa_family == AF_INET &&
1476 iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
1477 break;
1478
1479 /* If we failed, abandon localisation */
1480 if (iface)
1481 netmask = iface->netmask;
1482 else
1483 dst_addr_4.s_addr = 0;
1484 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001485 }
Simon Kelley25cf5e32015-01-09 15:53:03 +00001486
1487 /* log_query gets called indirectly all over the place, so
1488 pass these in global variables - sorry. */
1489 daemon->log_display_id = ++daemon->log_id;
1490 daemon->log_source_addr = &source_addr;
Simon Kelley6b173352018-05-08 18:32:14 +01001491
1492#ifdef HAVE_DUMPFILE
1493 dump_packet(DUMP_QUERY, daemon->packet, (size_t)n, &source_addr, NULL);
1494#endif
1495
Simon Kelleycdeda282006-03-16 20:16:06 +00001496 if (extract_request(header, (size_t)n, daemon->namebuff, &type))
Simon Kelley44a2a312004-03-10 20:04:35 +00001497 {
Simon Kelleyb485ed92013-10-18 22:00:39 +01001498#ifdef HAVE_AUTH
1499 struct auth_zone *zone;
1500#endif
Simon Kelley610e7822014-02-06 14:45:17 +00001501 char *types = querystr(auth_dns ? "auth" : "query", type);
Petr Menšík6c0bf792021-03-18 00:07:45 +01001502
1503 log_query_mysockaddr(F_QUERY | F_FORWARD, daemon->namebuff,
1504 &source_addr, types);
Simon Kelley44a2a312004-03-10 20:04:35 +00001505
Simon Kelley4820dce2012-12-18 18:30:30 +00001506#ifdef HAVE_AUTH
Simon Kelleyb485ed92013-10-18 22:00:39 +01001507 /* find queries for zones we're authoritative for, and answer them directly */
Simon Kelley3a3965a2015-08-09 17:45:06 +01001508 if (!auth_dns && !option_bool(OPT_LOCALISE))
Simon Kelley6008bdb2013-10-21 21:47:03 +01001509 for (zone = daemon->auth_zones; zone; zone = zone->next)
1510 if (in_zone(zone, daemon->namebuff, NULL))
1511 {
1512 auth_dns = 1;
1513 local_auth = 1;
1514 break;
1515 }
Simon Kelleyb485ed92013-10-18 22:00:39 +01001516#endif
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01001517
1518#ifdef HAVE_LOOP
1519 /* Check for forwarding loop */
1520 if (detect_loop(daemon->namebuff, type))
1521 return;
1522#endif
Simon Kelleyb485ed92013-10-18 22:00:39 +01001523 }
1524
Simon Kelley5bb88f02015-12-21 16:23:47 +00001525 if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL, NULL))
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001526 {
1527 unsigned short flags;
1528
1529 have_pseudoheader = 1;
1530 GETSHORT(udp_size, pheader);
1531 pheader += 2; /* ext_rcode */
1532 GETSHORT(flags, pheader);
1533
1534 if (flags & 0x8000)
1535 do_bit = 1;/* do bit */
1536
1537 /* If the client provides an EDNS0 UDP size, use that to limit our reply.
1538 (bounded by the maximum configured). If no EDNS0, then it
1539 defaults to 512 */
1540 if (udp_size > daemon->edns_pktsz)
1541 udp_size = daemon->edns_pktsz;
Simon Kelleya3303e12017-09-07 20:45:00 +01001542 else if (udp_size < PACKETSZ)
1543 udp_size = PACKETSZ; /* Sanity check - can't reduce below default. RFC 6891 6.2.3 */
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001544 }
1545
Simon Kelleyb485ed92013-10-18 22:00:39 +01001546#ifdef HAVE_AUTH
Simon Kelley4f7b3042012-11-28 21:27:02 +00001547 if (auth_dns)
Simon Kelley824af852008-02-12 20:43:05 +00001548 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001549 m = answer_auth(header, ((char *) header) + udp_size, (size_t)n, now, &source_addr,
1550 local_auth, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001551 if (m >= 1)
Simon Kelleyb485ed92013-10-18 22:00:39 +01001552 {
1553 send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
1554 (char *)header, m, &source_addr, &dst_addr, if_index);
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001555 daemon->metrics[METRIC_DNS_AUTH_ANSWERED]++;
Simon Kelleyb485ed92013-10-18 22:00:39 +01001556 }
Simon Kelley824af852008-02-12 20:43:05 +00001557 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001558 else
Simon Kelley4820dce2012-12-18 18:30:30 +00001559#endif
Simon Kelley4f7b3042012-11-28 21:27:02 +00001560 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001561 int ad_reqd = do_bit;
1562 /* RFC 6840 5.7 */
1563 if (header->hb4 & HB4_AD)
1564 ad_reqd = 1;
1565
1566 m = answer_request(header, ((char *) header) + udp_size, (size_t)n,
1567 dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001568
1569 if (m >= 1)
1570 {
1571 send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
1572 (char *)header, m, &source_addr, &dst_addr, if_index);
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001573 daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001574 }
1575 else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
Simon Kelley613ad152014-02-25 23:02:28 +00001576 header, (size_t)n, now, NULL, ad_reqd, do_bit))
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001577 daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]++;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001578 else
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001579 daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001580 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001581}
1582
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001583#ifdef HAVE_DNSSEC
Josh Soref730c6742017-02-06 16:14:04 +00001584/* Recurse up the key hierarchy */
Simon Kelley7fa836e2014-02-10 20:11:24 +00001585static int tcp_key_recurse(time_t now, int status, struct dns_header *header, size_t n,
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001586 int class, char *name, char *keyname, struct server *server,
1587 int have_mark, unsigned int mark, int *keycount)
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001588{
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001589 int new_status;
Simon Kelley9a31b682015-12-15 10:20:39 +00001590 unsigned char *packet = NULL;
Simon Kelley9a31b682015-12-15 10:20:39 +00001591 unsigned char *payload = NULL;
1592 struct dns_header *new_header = NULL;
1593 u16 *length = NULL;
Simon Kelley361dfe52017-02-10 21:12:30 +00001594
Simon Kelley9a31b682015-12-15 10:20:39 +00001595 while (1)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001596 {
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001597 int type = SERV_DO_DNSSEC;
1598 char *domain;
1599 size_t m;
1600 unsigned char c1, c2;
Simon Kelley361dfe52017-02-10 21:12:30 +00001601 struct server *firstsendto = NULL;
1602
Simon Kelley9a31b682015-12-15 10:20:39 +00001603 /* limit the amount of work we do, to avoid cycling forever on loops in the DNS */
1604 if (--(*keycount) == 0)
1605 new_status = STAT_ABANDONED;
1606 else if (status == STAT_NEED_KEY)
1607 new_status = dnssec_validate_by_ds(now, header, n, name, keyname, class);
1608 else if (status == STAT_NEED_DS)
1609 new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
1610 else
James Bottomleye33b4872017-03-17 21:44:10 +00001611 new_status = dnssec_validate_reply(now, header, n, name, keyname, &class,
Simon Kelleya6918532018-04-15 16:20:52 +01001612 !option_bool(OPT_DNSSEC_IGN_NS) && (server->flags & SERV_DO_DNSSEC),
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001613 NULL, NULL, NULL);
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001614
Simon Kelley9a31b682015-12-15 10:20:39 +00001615 if (new_status != STAT_NEED_DS && new_status != STAT_NEED_KEY)
1616 break;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001617
Simon Kelley9a31b682015-12-15 10:20:39 +00001618 /* Can't validate because we need a key/DS whose name now in keyname.
1619 Make query for same, and recurse to validate */
Simon Kelley7fa836e2014-02-10 20:11:24 +00001620 if (!packet)
Simon Kelley9a31b682015-12-15 10:20:39 +00001621 {
1622 packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
1623 payload = &packet[2];
1624 new_header = (struct dns_header *)payload;
1625 length = (u16 *)packet;
1626 }
1627
1628 if (!packet)
1629 {
1630 new_status = STAT_ABANDONED;
1631 break;
1632 }
Simon Kelleye1791f32018-10-06 23:23:23 +01001633
Simon Kelley33702ab2015-12-28 23:17:15 +00001634 m = dnssec_generate_query(new_header, ((unsigned char *) new_header) + 65536, keyname, class,
Simon Kelleye1791f32018-10-06 23:23:23 +01001635 new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS, server->edns_pktsz);
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001636
Simon Kelley7fa836e2014-02-10 20:11:24 +00001637 *length = htons(m);
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001638
1639 /* Find server to forward to. This will normally be the
1640 same as for the original query, but may be another if
1641 servers for domains are involved. */
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001642 if (search_servers(now, NULL, F_DNSSECOK, keyname, &type, &domain, NULL) != 0)
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001643 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001644 new_status = STAT_ABANDONED;
1645 break;
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001646 }
Simon Kelley361dfe52017-02-10 21:12:30 +00001647
Simon Kelley361dfe52017-02-10 21:12:30 +00001648 while (1)
1649 {
Simon Kelley608aa9f2019-03-10 22:44:15 +00001650 int data_sent = 0;
1651
Simon Kelley361dfe52017-02-10 21:12:30 +00001652 if (!firstsendto)
1653 firstsendto = server;
1654 else
1655 {
1656 if (!(server = server->next))
1657 server = daemon->servers;
1658 if (server == firstsendto)
1659 {
1660 /* can't find server to accept our query. */
1661 new_status = STAT_ABANDONED;
1662 break;
1663 }
1664 }
1665
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001666 if (type != (server->flags & (SERV_TYPE | SERV_DO_DNSSEC)) ||
Simon Kelley361dfe52017-02-10 21:12:30 +00001667 (type == SERV_HAS_DOMAIN && !hostname_isequal(domain, server->domain)) ||
1668 (server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
1669 continue;
Simon Kelleye1791f32018-10-06 23:23:23 +01001670
1671 retry:
1672 /* may need to make new connection. */
1673 if (server->tcpfd == -1)
1674 {
1675 if ((server->tcpfd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
1676 continue; /* No good, next server */
1677
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001678#ifdef HAVE_CONNTRACK
Simon Kelleye1791f32018-10-06 23:23:23 +01001679 /* Copy connection mark of incoming query to outgoing connection. */
1680 if (have_mark)
1681 setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001682#endif
Simon Kelleye1791f32018-10-06 23:23:23 +01001683
Simon Kelley608aa9f2019-03-10 22:44:15 +00001684 if (!local_bind(server->tcpfd, &server->source_addr, server->interface, 0, 1))
1685 {
1686 close(server->tcpfd);
1687 server->tcpfd = -1;
1688 continue; /* No good, next server */
1689 }
1690
1691#ifdef MSG_FASTOPEN
1692 while(retry_send(sendto(server->tcpfd, packet, m + sizeof(u16),
1693 MSG_FASTOPEN, &server->addr.sa, sa_len(&server->addr))));
1694
1695 if (errno == 0)
1696 data_sent = 1;
1697#endif
1698
1699 if (!data_sent && connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) == -1)
Simon Kelleye1791f32018-10-06 23:23:23 +01001700 {
1701 close(server->tcpfd);
1702 server->tcpfd = -1;
1703 continue; /* No good, next server */
1704 }
1705
1706 server->flags &= ~SERV_GOT_TCP;
1707 }
Simon Kelley361dfe52017-02-10 21:12:30 +00001708
Simon Kelley608aa9f2019-03-10 22:44:15 +00001709 if ((!data_sent && !read_write(server->tcpfd, packet, m + sizeof(u16), 0)) ||
Simon Kelley361dfe52017-02-10 21:12:30 +00001710 !read_write(server->tcpfd, &c1, 1, 1) ||
1711 !read_write(server->tcpfd, &c2, 1, 1) ||
1712 !read_write(server->tcpfd, payload, (c1 << 8) | c2, 1))
1713 {
1714 close(server->tcpfd);
1715 server->tcpfd = -1;
1716 /* We get data then EOF, reopen connection to same server,
1717 else try next. This avoids DoS from a server which accepts
1718 connections and then closes them. */
1719 if (server->flags & SERV_GOT_TCP)
1720 goto retry;
1721 else
1722 continue;
1723 }
Simon Kelleye1791f32018-10-06 23:23:23 +01001724
Petr Menšík6c0bf792021-03-18 00:07:45 +01001725 log_query_mysockaddr(F_NOEXTRA | F_DNSSEC, keyname, &server->addr,
1726 querystr("dnssec-query", new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS));
Simon Kelleye1791f32018-10-06 23:23:23 +01001727
Simon Kelley361dfe52017-02-10 21:12:30 +00001728 server->flags |= SERV_GOT_TCP;
1729
1730 m = (c1 << 8) | c2;
1731 new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, have_mark, mark, keycount);
1732 break;
1733 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001734
1735 if (new_status != STAT_OK)
1736 break;
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001737 }
Simon Kelley361dfe52017-02-10 21:12:30 +00001738
Simon Kelley9a31b682015-12-15 10:20:39 +00001739 if (packet)
1740 free(packet);
1741
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001742 return new_status;
1743}
1744#endif
1745
1746
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001747/* The daemon forks before calling this: it should deal with one connection,
Josh Soref730c6742017-02-06 16:14:04 +00001748 blocking as necessary, and then return. Note, need to be a bit careful
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001749 about resources for debug mode, when the fork is suppressed: that's
1750 done by the caller. */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001751unsigned char *tcp_request(int confd, time_t now,
Simon Kelley4f7b3042012-11-28 21:27:02 +00001752 union mysockaddr *local_addr, struct in_addr netmask, int auth_dns)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001753{
Simon Kelley28866e92011-02-14 20:19:14 +00001754 size_t size = 0;
1755 int norebind = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001756#ifdef HAVE_AUTH
Simon Kelley19b16892013-10-20 10:19:39 +01001757 int local_auth = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001758#endif
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001759 int checking_disabled, do_bit, added_pheader = 0, have_pseudoheader = 0;
Simon Kelley25e63f12020-11-25 21:17:52 +00001760 int check_subnet, cacheable, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
Simon Kelleycdeda282006-03-16 20:16:06 +00001761 size_t m;
Simon Kelleyee86ce62012-12-07 11:54:46 +00001762 unsigned short qtype;
1763 unsigned int gotname;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001764 unsigned char c1, c2;
Simon Kelley4b5ea122013-04-22 10:18:26 +01001765 /* Max TCP packet + slop + size */
1766 unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
1767 unsigned char *payload = &packet[2];
1768 /* largest field in header is 16-bits, so this is still sufficiently aligned */
1769 struct dns_header *header = (struct dns_header *)payload;
1770 u16 *length = (u16 *)packet;
Simon Kelley3be34542004-09-11 19:12:13 +01001771 struct server *last_server;
Simon Kelley7de060b2011-08-26 17:24:52 +01001772 struct in_addr dst_addr_4;
1773 union mysockaddr peer_addr;
1774 socklen_t peer_len = sizeof(union mysockaddr);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001775 int query_count = 0;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001776 unsigned char *pheader;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001777 unsigned int mark = 0;
1778 int have_mark = 0;
Simon Kelley25cf5e32015-01-09 15:53:03 +00001779
Simon Kelleyd05dd582016-01-19 21:23:30 +00001780 (void)mark;
1781 (void)have_mark;
1782
Simon Kelley7de060b2011-08-26 17:24:52 +01001783 if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
1784 return packet;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001785
1786#ifdef HAVE_CONNTRACK
1787 /* Get connection mark of incoming query to set on outgoing connections. */
1788 if (option_bool(OPT_CONNTRACK))
1789 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001790 union all_addr local;
Simon Kelleyee875042018-10-23 22:10:17 +01001791
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001792 if (local_addr->sa.sa_family == AF_INET6)
Simon Kelleycc921df2019-01-02 22:48:59 +00001793 local.addr6 = local_addr->in6.sin6_addr;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001794 else
Simon Kelleycc921df2019-01-02 22:48:59 +00001795 local.addr4 = local_addr->in.sin_addr;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001796
1797 have_mark = get_incoming_mark(&peer_addr, &local, 1, &mark);
1798 }
1799#endif
1800
Simon Kelleyc8a80482014-03-05 14:29:54 +00001801 /* We can be configured to only accept queries from at-most-one-hop-away addresses. */
1802 if (option_bool(OPT_LOCAL_SERVICE))
1803 {
1804 struct addrlist *addr;
Simon Kelleyee875042018-10-23 22:10:17 +01001805
Simon Kelleyc8a80482014-03-05 14:29:54 +00001806 if (peer_addr.sa.sa_family == AF_INET6)
1807 {
1808 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1809 if ((addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001810 is_same_net6(&addr->addr.addr6, &peer_addr.in6.sin6_addr, addr->prefixlen))
Simon Kelleyc8a80482014-03-05 14:29:54 +00001811 break;
1812 }
1813 else
Simon Kelleyc8a80482014-03-05 14:29:54 +00001814 {
1815 struct in_addr netmask;
1816 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1817 {
Richard Genoud15b1b7e2014-09-17 21:12:00 +01001818 netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
Simon Kelleyc8a80482014-03-05 14:29:54 +00001819 if (!(addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001820 is_same_net(addr->addr.addr4, peer_addr.in.sin_addr, netmask))
Simon Kelleyc8a80482014-03-05 14:29:54 +00001821 break;
1822 }
1823 }
1824 if (!addr)
1825 {
1826 my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
1827 return packet;
1828 }
1829 }
Simon Kelley7de060b2011-08-26 17:24:52 +01001830
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001831 while (1)
1832 {
Simon Kelley25cf5e32015-01-09 15:53:03 +00001833 if (query_count == TCP_MAX_QUERIES ||
1834 !packet ||
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001835 !read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
1836 !(size = c1 << 8 | c2) ||
Simon Kelley4b5ea122013-04-22 10:18:26 +01001837 !read_write(confd, payload, size, 1))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001838 return packet;
1839
Simon Kelley572b41e2011-02-18 18:11:18 +00001840 if (size < (int)sizeof(struct dns_header))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001841 continue;
Simon Kelley63437ff2017-09-06 22:34:21 +01001842
1843 /* Clear buffer beyond request to avoid risk of
1844 information disclosure. */
1845 memset(payload + size, 0, 65536 - size);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001846
Simon Kelley25cf5e32015-01-09 15:53:03 +00001847 query_count++;
1848
1849 /* log_query gets called indirectly all over the place, so
1850 pass these in global variables - sorry. */
1851 daemon->log_display_id = ++daemon->log_id;
1852 daemon->log_source_addr = &peer_addr;
1853
Simon Kelley28866e92011-02-14 20:19:14 +00001854 /* save state of "cd" flag in query */
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001855 if ((checking_disabled = header->hb4 & HB4_CD))
1856 no_cache_dnssec = 1;
Simon Kelley28866e92011-02-14 20:19:14 +00001857
Simon Kelley3be34542004-09-11 19:12:13 +01001858 if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001859 {
Simon Kelleyb485ed92013-10-18 22:00:39 +01001860#ifdef HAVE_AUTH
1861 struct auth_zone *zone;
1862#endif
Simon Kelley610e7822014-02-06 14:45:17 +00001863 char *types = querystr(auth_dns ? "auth" : "query", qtype);
Simon Kelley7de060b2011-08-26 17:24:52 +01001864
Petr Menšík6c0bf792021-03-18 00:07:45 +01001865 log_query_mysockaddr(F_QUERY | F_FORWARD, daemon->namebuff,
1866 &peer_addr, types);
Simon Kelleyb485ed92013-10-18 22:00:39 +01001867
1868#ifdef HAVE_AUTH
1869 /* find queries for zones we're authoritative for, and answer them directly */
Simon Kelley3a3965a2015-08-09 17:45:06 +01001870 if (!auth_dns && !option_bool(OPT_LOCALISE))
Simon Kelley6008bdb2013-10-21 21:47:03 +01001871 for (zone = daemon->auth_zones; zone; zone = zone->next)
1872 if (in_zone(zone, daemon->namebuff, NULL))
1873 {
1874 auth_dns = 1;
1875 local_auth = 1;
1876 break;
1877 }
Simon Kelleyb485ed92013-10-18 22:00:39 +01001878#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001879 }
1880
Simon Kelley7de060b2011-08-26 17:24:52 +01001881 if (local_addr->sa.sa_family == AF_INET)
1882 dst_addr_4 = local_addr->in.sin_addr;
1883 else
1884 dst_addr_4.s_addr = 0;
1885
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001886 do_bit = 0;
1887
Simon Kelley5bb88f02015-12-21 16:23:47 +00001888 if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL, NULL))
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001889 {
1890 unsigned short flags;
1891
1892 have_pseudoheader = 1;
1893 pheader += 4; /* udp_size, ext_rcode */
1894 GETSHORT(flags, pheader);
1895
1896 if (flags & 0x8000)
Simon Kelley5bb88f02015-12-21 16:23:47 +00001897 do_bit = 1; /* do bit */
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001898 }
1899
Simon Kelley4820dce2012-12-18 18:30:30 +00001900#ifdef HAVE_AUTH
Simon Kelley4f7b3042012-11-28 21:27:02 +00001901 if (auth_dns)
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001902 m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr,
1903 local_auth, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001904 else
Simon Kelley4820dce2012-12-18 18:30:30 +00001905#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001906 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001907 int ad_reqd = do_bit;
1908 /* RFC 6840 5.7 */
1909 if (header->hb4 & HB4_AD)
1910 ad_reqd = 1;
1911
1912 /* m > 0 if answered from cache */
1913 m = answer_request(header, ((char *) header) + 65536, (size_t)size,
1914 dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001915
Simon Kelley4f7b3042012-11-28 21:27:02 +00001916 /* Do this by steam now we're not in the select() loop */
Simon Kelleyb842bc92015-07-12 21:09:11 +01001917 check_log_writer(1);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001918
1919 if (m == 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001920 {
Simon Kelley4f7b3042012-11-28 21:27:02 +00001921 unsigned int flags = 0;
Simon Kelleycc921df2019-01-02 22:48:59 +00001922 union all_addr *addrp = NULL;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001923 int type = SERV_DO_DNSSEC;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001924 char *domain = NULL;
Simon Kelley6fd5d792017-10-13 22:26:40 +01001925 unsigned char *oph = find_pseudoheader(header, size, NULL, NULL, NULL, NULL);
Simon Kelleyed4c0762013-10-08 20:46:34 +01001926
Simon Kelley25e63f12020-11-25 21:17:52 +00001927 size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet, &cacheable);
Simon Kelley6fd5d792017-10-13 22:26:40 +01001928
Simon Kelley4f7b3042012-11-28 21:27:02 +00001929 if (gotname)
1930 flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
Simon Kelley6fd5d792017-10-13 22:26:40 +01001931
1932#ifdef HAVE_DNSSEC
1933 if (option_bool(OPT_DNSSEC_VALID) && (type & SERV_DO_DNSSEC))
1934 {
1935 size = add_do_bit(header, size, ((unsigned char *) header) + 65536);
1936
1937 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
1938 this allows it to select auth servers when one is returning bad data. */
1939 if (option_bool(OPT_DNSSEC_DEBUG))
1940 header->hb4 |= HB4_CD;
1941 }
1942#endif
1943
1944 /* Check if we added a pheader on forwarding - may need to
1945 strip it from the reply. */
1946 if (!oph && find_pseudoheader(header, size, NULL, NULL, NULL, NULL))
1947 added_pheader = 1;
1948
Simon Kelley367341f2016-01-12 15:58:23 +00001949 type &= ~SERV_DO_DNSSEC;
Simon Kelley367341f2016-01-12 15:58:23 +00001950
Simon Kelley4f7b3042012-11-28 21:27:02 +00001951 if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server)
1952 last_server = daemon->servers;
1953 else
1954 last_server = daemon->last_server;
1955
1956 if (!flags && last_server)
1957 {
1958 struct server *firstsendto = NULL;
Simon Kelley2d765862020-11-12 22:06:07 +00001959 unsigned char hash[HASH_SIZE];
1960 memcpy(hash, hash_questions(header, (unsigned int)size, daemon->namebuff), HASH_SIZE);
1961
Simon Kelley4f7b3042012-11-28 21:27:02 +00001962 /* Loop round available servers until we succeed in connecting to one.
Josh Soref730c6742017-02-06 16:14:04 +00001963 Note that this code subtly ensures that consecutive queries on this connection
Simon Kelley4f7b3042012-11-28 21:27:02 +00001964 which can go to the same server, do so. */
1965 while (1)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001966 {
Simon Kelley608aa9f2019-03-10 22:44:15 +00001967 int data_sent = 0;
1968
Simon Kelley4f7b3042012-11-28 21:27:02 +00001969 if (!firstsendto)
1970 firstsendto = last_server;
1971 else
1972 {
1973 if (!(last_server = last_server->next))
1974 last_server = daemon->servers;
1975
1976 if (last_server == firstsendto)
1977 break;
1978 }
1979
1980 /* server for wrong domain */
1981 if (type != (last_server->flags & SERV_TYPE) ||
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01001982 (type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)) ||
1983 (last_server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
Simon Kelley7de060b2011-08-26 17:24:52 +01001984 continue;
Simon Kelley361dfe52017-02-10 21:12:30 +00001985
1986 retry:
Simon Kelley608aa9f2019-03-10 22:44:15 +00001987 *length = htons(size);
1988
Simon Kelley4f7b3042012-11-28 21:27:02 +00001989 if (last_server->tcpfd == -1)
1990 {
1991 if ((last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
1992 continue;
1993
Karl Vogele9828b62014-10-03 21:45:15 +01001994#ifdef HAVE_CONNTRACK
1995 /* Copy connection mark of incoming query to outgoing connection. */
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001996 if (have_mark)
1997 setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
Simon Kelley608aa9f2019-03-10 22:44:15 +00001998#endif
Karl Vogele9828b62014-10-03 21:45:15 +01001999
Simon Kelley608aa9f2019-03-10 22:44:15 +00002000 if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 0, 1)))
2001 {
2002 close(last_server->tcpfd);
2003 last_server->tcpfd = -1;
2004 continue;
2005 }
2006
2007#ifdef MSG_FASTOPEN
2008 while(retry_send(sendto(last_server->tcpfd, packet, size + sizeof(u16),
2009 MSG_FASTOPEN, &last_server->addr.sa, sa_len(&last_server->addr))));
2010
2011 if (errno == 0)
2012 data_sent = 1;
2013#endif
2014
2015 if (!data_sent && connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1)
Simon Kelley4f7b3042012-11-28 21:27:02 +00002016 {
2017 close(last_server->tcpfd);
2018 last_server->tcpfd = -1;
2019 continue;
2020 }
2021
Simon Kelley361dfe52017-02-10 21:12:30 +00002022 last_server->flags &= ~SERV_GOT_TCP;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002023 }
2024
Simon Kelley1fc02682014-04-29 12:30:18 +01002025 /* get query name again for logging - may have been overwritten */
2026 if (!(gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
2027 strcpy(daemon->namebuff, "query");
Simon Kelley4f7b3042012-11-28 21:27:02 +00002028
Simon Kelley608aa9f2019-03-10 22:44:15 +00002029 if ((!data_sent && !read_write(last_server->tcpfd, packet, size + sizeof(u16), 0)) ||
Simon Kelley4f7b3042012-11-28 21:27:02 +00002030 !read_write(last_server->tcpfd, &c1, 1, 1) ||
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002031 !read_write(last_server->tcpfd, &c2, 1, 1) ||
2032 !read_write(last_server->tcpfd, payload, (c1 << 8) | c2, 1))
Simon Kelley7de060b2011-08-26 17:24:52 +01002033 {
2034 close(last_server->tcpfd);
2035 last_server->tcpfd = -1;
Simon Kelley361dfe52017-02-10 21:12:30 +00002036 /* We get data then EOF, reopen connection to same server,
2037 else try next. This avoids DoS from a server which accepts
2038 connections and then closes them. */
2039 if (last_server->flags & SERV_GOT_TCP)
2040 goto retry;
2041 else
2042 continue;
2043 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00002044
Simon Kelley361dfe52017-02-10 21:12:30 +00002045 last_server->flags |= SERV_GOT_TCP;
2046
Simon Kelley4f7b3042012-11-28 21:27:02 +00002047 m = (c1 << 8) | c2;
Petr Menšík6c0bf792021-03-18 00:07:45 +01002048
2049 log_query_mysockaddr(F_SERVER | F_FORWARD, daemon->namebuff,
2050 &last_server->addr, NULL);
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002051
2052#ifdef HAVE_DNSSEC
Simon Kelley367341f2016-01-12 15:58:23 +00002053 if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled && (last_server->flags & SERV_DO_DNSSEC))
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002054 {
Simon Kelley7fa836e2014-02-10 20:11:24 +00002055 int keycount = DNSSEC_WORK; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
Simon Kelleyf344dbc2016-01-18 18:04:17 +00002056 int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname,
2057 last_server, have_mark, mark, &keycount);
Simon Kelley554b5802015-04-17 22:50:20 +01002058 char *result, *domain = "result";
Simon Kelleyfe3992f2015-04-03 21:25:05 +01002059
Simon Kelley9a31b682015-12-15 10:20:39 +00002060 if (status == STAT_ABANDONED)
Simon Kelley150162b2015-03-27 09:58:26 +00002061 {
2062 result = "ABANDONED";
2063 status = STAT_BOGUS;
2064 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00002065 else
2066 result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
Simon Kelleye66b4df2015-04-28 20:45:57 +01002067
2068 if (status == STAT_BOGUS && extract_request(header, m, daemon->namebuff, NULL))
2069 domain = daemon->namebuff;
Simon Kelley554b5802015-04-17 22:50:20 +01002070
Simon Kelley07ed5852018-05-04 21:52:22 +01002071 log_query(F_SECSTAT, domain, NULL, result);
Simon Kelley7fa836e2014-02-10 20:11:24 +00002072
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002073 if (status == STAT_BOGUS)
Simon Kelleyfe3992f2015-04-03 21:25:05 +01002074 {
2075 no_cache_dnssec = 1;
2076 bogusanswer = 1;
2077 }
2078
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002079 if (status == STAT_SECURE)
2080 cache_secure = 1;
2081 }
2082#endif
2083
2084 /* restore CD bit to the value in the query */
2085 if (checking_disabled)
2086 header->hb4 |= HB4_CD;
2087 else
2088 header->hb4 &= ~HB4_CD;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002089
2090 /* There's no point in updating the cache, since this process will exit and
2091 lose the information after a few queries. We make this call for the alias and
2092 bogus-nxdomain side-effects. */
2093 /* If the crc of the question section doesn't match the crc we sent, then
2094 someone might be attempting to insert bogus values into the cache by
2095 sending replies containing questions and bogus answers. */
Simon Kelley2d765862020-11-12 22:06:07 +00002096 if (memcmp(hash, hash_questions(header, (unsigned int)m, daemon->namebuff), HASH_SIZE) != 0)
Simon Kelley703c7ff2014-01-25 23:46:23 +00002097 {
2098 m = 0;
2099 break;
2100 }
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002101
Simon Kelley25e63f12020-11-25 21:17:52 +00002102 /* Never cache answers which are contingent on the source or MAC address EDSN0 option,
2103 since the cache is ignorant of such things. */
2104 if (!cacheable)
2105 no_cache_dnssec = 1;
2106
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002107 m = process_reply(header, now, last_server, (unsigned int)m,
Simon Kelleye66b4df2015-04-28 20:45:57 +01002108 option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
Simon Kelleyfa14bec2015-12-20 17:12:16 +00002109 ad_reqd, do_bit, added_pheader, check_subnet, &peer_addr);
Simon Kelley4f7b3042012-11-28 21:27:02 +00002110
2111 break;
2112 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002113 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00002114
2115 /* In case of local answer or no connections made. */
2116 if (m == 0)
Simon Kelley1682d152018-08-03 20:38:18 +01002117 {
2118 m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl);
2119 if (have_pseudoheader)
2120 m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
2121 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002122 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002123 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00002124
Simon Kelleyb842bc92015-07-12 21:09:11 +01002125 check_log_writer(1);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002126
Simon Kelley4b5ea122013-04-22 10:18:26 +01002127 *length = htons(m);
2128
2129 if (m == 0 || !read_write(confd, packet, m + sizeof(u16), 0))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002130 return packet;
2131 }
2132}
2133
Simon Kelley16972692006-10-16 20:04:18 +01002134static struct frec *allocate_frec(time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002135{
Simon Kelley16972692006-10-16 20:04:18 +01002136 struct frec *f;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002137
Simon Kelley5aabfc72007-08-29 11:24:47 +01002138 if ((f = (struct frec *)whine_malloc(sizeof(struct frec))))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002139 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01002140 f->next = daemon->frec_list;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002141 f->time = now;
Simon Kelley832af0b2007-01-21 20:01:28 +00002142 f->sentto = NULL;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002143 f->rfds = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +00002144 f->flags = 0;
Simon Kelley3a237152013-12-12 12:15:50 +00002145#ifdef HAVE_DNSSEC
Simon Kelley97bc7982014-01-31 10:19:52 +00002146 f->dependent = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002147 f->blocking_query = NULL;
Simon Kelley4619d942014-01-16 19:53:06 +00002148 f->stash = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002149#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +01002150 daemon->frec_list = f;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002151 }
Simon Kelley16972692006-10-16 20:04:18 +01002152
2153 return f;
2154}
2155
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002156/* return a UDP socket bound to a random port, have to cope with straying into
2157 occupied port nos and reserved ones. */
2158static int random_sock(struct server *s)
2159{
2160 int fd;
2161
2162 if ((fd = socket(s->source_addr.sa.sa_family, SOCK_DGRAM, 0)) != -1)
2163 {
2164 if (local_bind(fd, &s->source_addr, s->interface, s->ifindex, 0))
2165 return fd;
2166
2167 if (s->interface[0] == 0)
2168 (void)prettyprint_addr(&s->source_addr, daemon->namebuff);
2169 else
2170 strcpy(daemon->namebuff, s->interface);
2171
2172 my_syslog(LOG_ERR, _("failed to bind server socket to %s: %s"),
2173 daemon->namebuff, strerror(errno));
2174 close(fd);
2175 }
2176
2177 return -1;
2178}
2179
2180/* compare source addresses and interface, serv2 can be null. */
2181static int server_isequal(const struct server *serv1,
2182 const struct server *serv2)
2183{
2184 return (serv2 &&
2185 serv2->ifindex == serv1->ifindex &&
2186 sockaddr_isequal(&serv2->source_addr, &serv1->source_addr) &&
2187 strncmp(serv2->interface, serv1->interface, IF_NAMESIZE) == 0);
2188}
2189
2190/* fdlp points to chain of randomfds already in use by transaction.
2191 If there's already a suitable one, return it, else allocate a
2192 new one and add it to the list.
2193
2194 Not leaking any resources in the face of allocation failures
2195 is rather convoluted here.
2196
2197 Note that rfd->serv may be NULL, when a server goes away.
2198*/
2199int allocate_rfd(struct randfd_list **fdlp, struct server *serv)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002200{
2201 static int finger = 0;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002202 int i, j = 0;
2203 struct randfd_list *rfl;
2204 struct randfd *rfd = NULL;
2205 int fd = 0;
2206
2207 /* If server has a pre-allocated fd, use that. */
2208 if (serv->sfd)
2209 return serv->sfd->fd;
2210
2211 /* existing suitable random port socket linked to this transaction? */
2212 for (rfl = *fdlp; rfl; rfl = rfl->next)
2213 if (server_isequal(serv, rfl->rfd->serv))
2214 return rfl->rfd->fd;
Simon Kelley1a6bca82008-07-11 11:11:42 +01002215
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002216 /* No. need new link. */
2217 if ((rfl = daemon->rfl_spare))
2218 daemon->rfl_spare = rfl->next;
2219 else if (!(rfl = whine_malloc(sizeof(struct randfd_list))))
2220 return -1;
2221
Simon Kelley1a6bca82008-07-11 11:11:42 +01002222 /* limit the number of sockets we have open to avoid starvation of
2223 (eg) TFTP. Once we have a reasonable number, randomness should be OK */
Simon Kelley1a6bca82008-07-11 11:11:42 +01002224 for (i = 0; i < RANDOM_SOCKS; i++)
Simon Kelley9009d742008-11-14 20:04:27 +00002225 if (daemon->randomsocks[i].refcount == 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002226 {
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002227 if ((fd = random_sock(serv)) != -1)
2228 {
2229 rfd = &daemon->randomsocks[i];
2230 rfd->serv = serv;
2231 rfd->fd = fd;
2232 rfd->refcount = 1;
2233 }
2234 break;
2235 }
2236
2237 /* No free ones or cannot get new socket, grab an existing one */
2238 if (!rfd)
2239 for (j = 0; j < RANDOM_SOCKS; j++)
2240 {
2241 i = (j + finger) % RANDOM_SOCKS;
2242 if (daemon->randomsocks[i].refcount != 0 &&
2243 server_isequal(serv, daemon->randomsocks[i].serv) &&
2244 daemon->randomsocks[i].refcount != 0xfffe)
2245 {
2246 finger = i + 1;
2247 rfd = &daemon->randomsocks[i];
2248 rfd->refcount++;
2249 break;
2250 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01002251 }
2252
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002253 if (j == RANDOM_SOCKS)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002254 {
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002255 struct randfd_list *rfl_poll;
Simon Kelley1a6bca82008-07-11 11:11:42 +01002256
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002257 /* there are no free slots, and non with the same parameters we can piggy-back on.
2258 We're going to have to allocate a new temporary record, distinguished by
2259 refcount == 0xffff. This will exist in the frec randfd list, never be shared,
2260 and be freed when no longer in use. It will also be held on
2261 the daemon->rfl_poll list so the poll system can find it. */
2262
2263 if ((rfl_poll = daemon->rfl_spare))
2264 daemon->rfl_spare = rfl_poll->next;
2265 else
2266 rfl_poll = whine_malloc(sizeof(struct randfd_list));
2267
2268 if (!rfl_poll ||
2269 !(rfd = whine_malloc(sizeof(struct randfd))) ||
2270 (fd = random_sock(serv)) == -1)
2271 {
2272
2273 /* Don't leak anything we may already have */
2274 rfl->next = daemon->rfl_spare;
2275 daemon->rfl_spare = rfl;
2276
2277 if (rfl_poll)
2278 {
2279 rfl_poll->next = daemon->rfl_spare;
2280 daemon->rfl_spare = rfl_poll;
2281 }
2282
2283 if (rfd)
2284 free(rfd);
2285
2286 return -1; /* doom */
2287 }
2288
2289 /* Note rfd->serv not set here, since it's not reused */
2290 rfd->fd = fd;
2291 rfd->refcount = 0xffff; /* marker for temp record */
2292
2293 rfl_poll->rfd = rfd;
2294 rfl_poll->next = daemon->rfl_poll;
2295 daemon->rfl_poll = rfl_poll;
2296 }
2297
2298 rfl->rfd = rfd;
2299 rfl->next = *fdlp;
2300 *fdlp = rfl;
2301
2302 return rfl->rfd->fd;
Simon Kelley1a6bca82008-07-11 11:11:42 +01002303}
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002304
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002305void free_rfds(struct randfd_list **fdlp)
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002306{
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002307 struct randfd_list *tmp, *rfl, *poll, *next, **up;
2308
2309 for (rfl = *fdlp; rfl; rfl = tmp)
2310 {
2311 if (rfl->rfd->refcount == 0xffff || --(rfl->rfd->refcount) == 0)
2312 close(rfl->rfd->fd);
2313
2314 /* temporary overflow record */
2315 if (rfl->rfd->refcount == 0xffff)
2316 {
2317 free(rfl->rfd);
2318
2319 /* go through the link of all these by steam to delete.
2320 This list is expected to be almost always empty. */
2321 for (poll = daemon->rfl_poll, up = &daemon->rfl_poll; poll; poll = next)
2322 {
2323 next = poll->next;
2324
2325 if (poll->rfd == rfl->rfd)
2326 {
2327 *up = poll->next;
2328 poll->next = daemon->rfl_spare;
2329 daemon->rfl_spare = poll;
2330 }
2331 else
2332 up = &poll->next;
2333 }
2334 }
2335
2336 tmp = rfl->next;
2337 rfl->next = daemon->rfl_spare;
2338 daemon->rfl_spare = rfl;
2339 }
2340
2341 *fdlp = NULL;
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002342}
2343
Simon Kelley1a6bca82008-07-11 11:11:42 +01002344static void free_frec(struct frec *f)
2345{
Simon Kelley6a6e06f2020-12-04 18:35:11 +00002346 struct frec_src *last;
Simon Kelley15b60dd2020-11-18 18:34:55 +00002347
Simon Kelley6a6e06f2020-12-04 18:35:11 +00002348 /* add back to freelist if not the record builtin to every frec. */
2349 for (last = f->frec_src.next; last && last->next; last = last->next) ;
2350 if (last)
2351 {
2352 last->next = daemon->free_frec_src;
2353 daemon->free_frec_src = f->frec_src.next;
2354 }
2355
Simon Kelley15b60dd2020-11-18 18:34:55 +00002356 f->frec_src.next = NULL;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002357 free_rfds(&f->rfds);
Simon Kelley1a6bca82008-07-11 11:11:42 +01002358 f->sentto = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +00002359 f->flags = 0;
Simon Kelley3a237152013-12-12 12:15:50 +00002360
2361#ifdef HAVE_DNSSEC
2362 if (f->stash)
Simon Kelley0fc2f312014-01-08 10:26:58 +00002363 {
2364 blockdata_free(f->stash);
2365 f->stash = NULL;
2366 }
Simon Kelley3a237152013-12-12 12:15:50 +00002367
2368 /* Anything we're waiting on is pointless now, too */
2369 if (f->blocking_query)
2370 free_frec(f->blocking_query);
2371 f->blocking_query = NULL;
Simon Kelley39048ad2014-01-21 17:33:58 +00002372 f->dependent = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002373#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +01002374}
2375
Simon Kelley09f3b2c2017-05-09 01:34:02 +01002376
2377
Simon Kelley16972692006-10-16 20:04:18 +01002378/* if wait==NULL return a free or older than TIMEOUT record.
2379 else return *wait zero if one available, or *wait is delay to
Simon Kelley1a6bca82008-07-11 11:11:42 +01002380 when the oldest in-use record will expire. Impose an absolute
Simon Kelley3a237152013-12-12 12:15:50 +00002381 limit of 4*TIMEOUT before we wipe things (for random sockets).
Simon Kelley8caf3d72020-04-04 17:00:32 +01002382 If force is non-NULL, always return a result, even if we have
2383 to allocate above the limit, and never free the record pointed
2384 to by the force argument. */
2385struct frec *get_new_frec(time_t now, int *wait, struct frec *force)
Simon Kelley16972692006-10-16 20:04:18 +01002386{
Simon Kelley1a6bca82008-07-11 11:11:42 +01002387 struct frec *f, *oldest, *target;
Simon Kelley16972692006-10-16 20:04:18 +01002388 int count;
2389
2390 if (wait)
2391 *wait = 0;
2392
Simon Kelley1a6bca82008-07-11 11:11:42 +01002393 for (f = daemon->frec_list, oldest = NULL, target = NULL, count = 0; f; f = f->next, count++)
Simon Kelley832af0b2007-01-21 20:01:28 +00002394 if (!f->sentto)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002395 target = f;
2396 else
Simon Kelley16972692006-10-16 20:04:18 +01002397 {
Simon Kelley9a31b682015-12-15 10:20:39 +00002398#ifdef HAVE_DNSSEC
2399 /* Don't free DNSSEC sub-queries here, as we may end up with
2400 dangling references to them. They'll go when their "real" query
2401 is freed. */
Simon Kelley8caf3d72020-04-04 17:00:32 +01002402 if (!f->dependent && f != force)
Simon Kelley9a31b682015-12-15 10:20:39 +00002403#endif
2404 {
2405 if (difftime(now, f->time) >= 4*TIMEOUT)
2406 {
2407 free_frec(f);
2408 target = f;
2409 }
2410
2411
2412 if (!oldest || difftime(f->time, oldest->time) <= 0)
2413 oldest = f;
2414 }
Simon Kelley16972692006-10-16 20:04:18 +01002415 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01002416
2417 if (target)
2418 {
2419 target->time = now;
2420 return target;
2421 }
Simon Kelley16972692006-10-16 20:04:18 +01002422
2423 /* can't find empty one, use oldest if there is one
2424 and it's older than timeout */
Simon Kelley09f3b2c2017-05-09 01:34:02 +01002425 if (!force && oldest && ((int)difftime(now, oldest->time)) >= TIMEOUT)
Simon Kelley16972692006-10-16 20:04:18 +01002426 {
2427 /* keep stuff for twice timeout if we can by allocating a new
2428 record instead */
2429 if (difftime(now, oldest->time) < 2*TIMEOUT &&
2430 count <= daemon->ftabsize &&
2431 (f = allocate_frec(now)))
2432 return f;
2433
2434 if (!wait)
2435 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01002436 free_frec(oldest);
Simon Kelley16972692006-10-16 20:04:18 +01002437 oldest->time = now;
2438 }
2439 return oldest;
2440 }
2441
2442 /* none available, calculate time 'till oldest record expires */
Simon Kelley3a237152013-12-12 12:15:50 +00002443 if (!force && count > daemon->ftabsize)
Simon Kelley16972692006-10-16 20:04:18 +01002444 {
Marcelo Salhab Brogliato0da5e892013-05-31 11:49:06 +01002445 static time_t last_log = 0;
2446
Simon Kelley16972692006-10-16 20:04:18 +01002447 if (oldest && wait)
2448 *wait = oldest->time + (time_t)TIMEOUT - now;
Marcelo Salhab Brogliato0da5e892013-05-31 11:49:06 +01002449
2450 if ((int)difftime(now, last_log) > 5)
2451 {
2452 last_log = now;
2453 my_syslog(LOG_WARNING, _("Maximum number of concurrent DNS queries reached (max: %d)"), daemon->ftabsize);
2454 }
2455
Simon Kelley16972692006-10-16 20:04:18 +01002456 return NULL;
2457 }
2458
2459 if (!(f = allocate_frec(now)) && wait)
2460 /* wait one second on malloc failure */
2461 *wait = 1;
2462
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002463 return f; /* OK if malloc fails and this is NULL */
2464}
Simon Kelley09f3b2c2017-05-09 01:34:02 +01002465
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002466static struct frec *lookup_frec(unsigned short id, int fd, void *hash)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002467{
2468 struct frec *f;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002469 struct server *s;
2470 int type;
2471 struct randfd_list *fdl;
2472
Simon Kelley1a6bca82008-07-11 11:11:42 +01002473 for(f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00002474 if (f->sentto && f->new_id == id &&
Simon Kelley2d765862020-11-12 22:06:07 +00002475 (memcmp(hash, f->hash, HASH_SIZE) == 0))
Simon Kelley257ac0c2020-11-12 18:49:23 +00002476 {
2477 /* sent from random port */
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002478 for (fdl = f->rfds; fdl; fdl = fdl->next)
2479 if (fdl->rfd->fd == fd)
Simon Kelley257ac0c2020-11-12 18:49:23 +00002480 return f;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002481
2482 /* Sent to upstream from socket associated with a server.
2483 Note we have to iterate over all the possible servers, since they may
2484 have different bound sockets. */
2485 type = f->sentto->flags & SERV_TYPE;
2486 s = f->sentto;
2487 do {
2488 if ((type == (s->flags & SERV_TYPE)) &&
2489 (type != SERV_HAS_DOMAIN ||
2490 (s->domain && hostname_isequal(f->sentto->domain, s->domain))) &&
2491 !(s->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)) &&
2492 s->sfd && s->sfd->fd == fd)
2493 return f;
2494
2495 s = s->next ? s->next : daemon->servers;
2496 } while (s != f->sentto);
Simon Kelley257ac0c2020-11-12 18:49:23 +00002497 }
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002498
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002499 return NULL;
2500}
2501
Simon Kelley15b60dd2020-11-18 18:34:55 +00002502static struct frec *lookup_frec_by_query(void *hash, unsigned int flags)
2503{
2504 struct frec *f;
2505
2506 /* FREC_DNSKEY and FREC_DS_QUERY are never set in flags, so the test below
Simon Kelley25e63f12020-11-25 21:17:52 +00002507 ensures that no frec created for internal DNSSEC query can be returned here.
2508
2509 Similarly FREC_NO_CACHE is never set in flags, so a query which is
2510 contigent on a particular source address EDNS0 option will never be matched. */
Simon Kelley15b60dd2020-11-18 18:34:55 +00002511
2512#define FLAGMASK (FREC_CHECKING_DISABLED | FREC_AD_QUESTION | FREC_DO_QUESTION \
Simon Kelley25e63f12020-11-25 21:17:52 +00002513 | FREC_HAS_PHEADER | FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_NO_CACHE)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002514
Simon Kelley1a6bca82008-07-11 11:11:42 +01002515 for(f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00002516 if (f->sentto &&
Simon Kelley15b60dd2020-11-18 18:34:55 +00002517 (f->flags & FLAGMASK) == flags &&
2518 memcmp(hash, f->hash, HASH_SIZE) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002519 return f;
Simon Kelley15b60dd2020-11-18 18:34:55 +00002520
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002521 return NULL;
2522}
Simon Kelley15b60dd2020-11-18 18:34:55 +00002523
Simon Kelley47a95162014-07-08 22:22:02 +01002524/* Send query packet again, if we can. */
2525void resend_query()
2526{
2527 if (daemon->srv_save)
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002528 while(retry_send(sendto(daemon->fd_save, daemon->packet, daemon->packet_len, 0,
2529 &daemon->srv_save->addr.sa,
2530 sa_len(&daemon->srv_save->addr))));
Simon Kelley47a95162014-07-08 22:22:02 +01002531}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002532
Simon Kelley849a8352006-06-09 21:02:31 +01002533/* A server record is going away, remove references to it */
Simon Kelley5aabfc72007-08-29 11:24:47 +01002534void server_gone(struct server *server)
Simon Kelley849a8352006-06-09 21:02:31 +01002535{
2536 struct frec *f;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002537 int i;
Simon Kelley849a8352006-06-09 21:02:31 +01002538
Simon Kelley1a6bca82008-07-11 11:11:42 +01002539 for (f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00002540 if (f->sentto && f->sentto == server)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002541 free_frec(f);
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002542
2543 /* If any random socket refers to this server, NULL the reference.
2544 No more references to the socket will be created in the future. */
2545 for (i = 0; i < RANDOM_SOCKS; i++)
2546 if (daemon->randomsocks[i].refcount != 0 && daemon->randomsocks[i].serv == server)
2547 daemon->randomsocks[i].serv = NULL;
Simon Kelley849a8352006-06-09 21:02:31 +01002548
2549 if (daemon->last_server == server)
2550 daemon->last_server = NULL;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002551
Simon Kelley849a8352006-06-09 21:02:31 +01002552 if (daemon->srv_save == server)
2553 daemon->srv_save = NULL;
2554}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002555
Simon Kelley316e2732010-01-22 20:16:09 +00002556/* return unique random ids. */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002557static unsigned short get_id(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002558{
2559 unsigned short ret = 0;
Simon Kelley257ac0c2020-11-12 18:49:23 +00002560 struct frec *f;
Simon Kelley832af0b2007-01-21 20:01:28 +00002561
Simon Kelley257ac0c2020-11-12 18:49:23 +00002562 while (1)
2563 {
2564 ret = rand16();
2565
2566 /* ensure id is unique. */
2567 for (f = daemon->frec_list; f; f = f->next)
2568 if (f->sentto && f->new_id == ret)
2569 break;
2570
2571 if (!f)
2572 return ret;
2573 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002574}
2575
2576
2577
2578
2579