blob: f94c4cfeb0d032f46ef70715366669f45eb6e72d [file] [log] [blame]
Simon Kelley2a8710a2020-01-05 16:40:06 +00001/* dnsmasq is Copyright (c) 2000-2020 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 Kelley257ac0c2020-11-12 18:49:23 +000019static struct frec *lookup_frec(unsigned short id, int fd, int family, void *hash);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000020static struct frec *lookup_frec_by_sender(unsigned short id,
Simon Kelleyfd9fa482004-10-21 20:24:00 +010021 union mysockaddr *addr,
Simon Kelley8a9be9e2014-01-25 23:17:21 +000022 void *hash);
Simon Kelley15b60dd2020-11-18 18:34:55 +000023static struct frec *lookup_frec_by_query(void *hash, unsigned int flags);
24
Simon Kelley8a9be9e2014-01-25 23:17:21 +000025static unsigned short get_id(void);
Simon Kelley1a6bca82008-07-11 11:11:42 +010026static void free_frec(struct frec *f);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000027
Simon Kelley824af852008-02-12 20:43:05 +000028/* Send a UDP packet with its source address set as "source"
Simon Kelley44a2a312004-03-10 20:04:35 +000029 unless nowild is true, when we just send it with the kernel default */
Simon Kelley29689cf2012-03-22 14:01:00 +000030int send_from(int fd, int nowild, char *packet, size_t len,
Simon Kelleycc921df2019-01-02 22:48:59 +000031 union mysockaddr *to, union all_addr *source,
Simon Kelley50303b12012-04-04 22:13:17 +010032 unsigned int iface)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000033{
Simon Kelley44a2a312004-03-10 20:04:35 +000034 struct msghdr msg;
35 struct iovec iov[1];
Simon Kelley44a2a312004-03-10 20:04:35 +000036 union {
37 struct cmsghdr align; /* this ensures alignment */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010038#if defined(HAVE_LINUX_NETWORK)
Simon Kelley44a2a312004-03-10 20:04:35 +000039 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
40#elif defined(IP_SENDSRCADDR)
41 char control[CMSG_SPACE(sizeof(struct in_addr))];
42#endif
Simon Kelley44a2a312004-03-10 20:04:35 +000043 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
Simon Kelley44a2a312004-03-10 20:04:35 +000044 } control_u;
Simon Kelleyfeba5c12004-07-27 20:28:58 +010045
Simon Kelley44a2a312004-03-10 20:04:35 +000046 iov[0].iov_base = packet;
47 iov[0].iov_len = len;
48
Simon Kelleyfeba5c12004-07-27 20:28:58 +010049 msg.msg_control = NULL;
50 msg.msg_controllen = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +000051 msg.msg_flags = 0;
52 msg.msg_name = to;
53 msg.msg_namelen = sa_len(to);
54 msg.msg_iov = iov;
55 msg.msg_iovlen = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +010056
Simon Kelley26128d22004-11-14 16:43:54 +000057 if (!nowild)
Simon Kelleyfeba5c12004-07-27 20:28:58 +010058 {
Simon Kelley26128d22004-11-14 16:43:54 +000059 struct cmsghdr *cmptr;
Simon Kelleyfeba5c12004-07-27 20:28:58 +010060 msg.msg_control = &control_u;
61 msg.msg_controllen = sizeof(control_u);
Simon Kelley26128d22004-11-14 16:43:54 +000062 cmptr = CMSG_FIRSTHDR(&msg);
Simon Kelley44a2a312004-03-10 20:04:35 +000063
Simon Kelley26128d22004-11-14 16:43:54 +000064 if (to->sa.sa_family == AF_INET)
65 {
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010066#if defined(HAVE_LINUX_NETWORK)
Simon Kelley8ef5ada2010-06-03 19:42:45 +010067 struct in_pktinfo p;
68 p.ipi_ifindex = 0;
Simon Kelleycc921df2019-01-02 22:48:59 +000069 p.ipi_spec_dst = source->addr4;
Jérémie Courrèges-Anglasc6cc4552019-03-22 10:56:13 +010070 msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
Simon Kelley8ef5ada2010-06-03 19:42:45 +010071 memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
Jérémie Courrèges-Anglasc6cc4552019-03-22 10:56:13 +010072 cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
Simon Kelleyc72daea2012-01-05 21:33:27 +000073 cmptr->cmsg_level = IPPROTO_IP;
Simon Kelley26128d22004-11-14 16:43:54 +000074 cmptr->cmsg_type = IP_PKTINFO;
75#elif defined(IP_SENDSRCADDR)
Jérémie Courrèges-Anglasc6cc4552019-03-22 10:56:13 +010076 msg.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
Simon Kelleycc921df2019-01-02 22:48:59 +000077 memcpy(CMSG_DATA(cmptr), &(source->addr4), sizeof(source->addr4));
Jérémie Courrèges-Anglasc6cc4552019-03-22 10:56:13 +010078 cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
Simon Kelley26128d22004-11-14 16:43:54 +000079 cmptr->cmsg_level = IPPROTO_IP;
80 cmptr->cmsg_type = IP_SENDSRCADDR;
Simon Kelley44a2a312004-03-10 20:04:35 +000081#endif
Simon Kelley26128d22004-11-14 16:43:54 +000082 }
Simon Kelley26128d22004-11-14 16:43:54 +000083 else
84 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +010085 struct in6_pktinfo p;
86 p.ipi6_ifindex = iface; /* Need iface for IPv6 to handle link-local addrs */
Simon Kelleycc921df2019-01-02 22:48:59 +000087 p.ipi6_addr = source->addr6;
Jérémie Courrèges-Anglasc6cc4552019-03-22 10:56:13 +010088 msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
Simon Kelley8ef5ada2010-06-03 19:42:45 +010089 memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
Jérémie Courrèges-Anglasc6cc4552019-03-22 10:56:13 +010090 cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
Simon Kelley316e2732010-01-22 20:16:09 +000091 cmptr->cmsg_type = daemon->v6pktinfo;
Simon Kelleyc72daea2012-01-05 21:33:27 +000092 cmptr->cmsg_level = IPPROTO_IPV6;
Simon Kelley26128d22004-11-14 16:43:54 +000093 }
Simon Kelley26128d22004-11-14 16:43:54 +000094 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +010095
Simon Kelleyff841eb2015-03-11 21:36:30 +000096 while (retry_send(sendmsg(fd, &msg, 0)));
97
Brad Smithea3c60a2020-03-08 14:53:59 +000098 if (errno != 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +010099 {
Brad Smithea3c60a2020-03-08 14:53:59 +0000100#ifdef HAVE_LINUX_NETWORK
101 /* If interface is still in DAD, EINVAL results - ignore that. */
102 if (errno != EINVAL)
103 my_syslog(LOG_ERR, _("failed to send packet: %s"), strerror(errno));
104#endif
Simon Kelley29689cf2012-03-22 14:01:00 +0000105 return 0;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100106 }
Simon Kelley29d28dd2012-12-03 14:05:59 +0000107
Simon Kelley29689cf2012-03-22 14:01:00 +0000108 return 1;
Simon Kelley44a2a312004-03-10 20:04:35 +0000109}
110
Simon Kelleycc921df2019-01-02 22:48:59 +0000111static unsigned int search_servers(time_t now, union all_addr **addrpp, unsigned int qtype,
Simon Kelley367341f2016-01-12 15:58:23 +0000112 char *qdomain, int *type, char **domain, int *norebind)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100113
114{
115 /* If the query ends in the domain in one of our servers, set
116 domain to point to that name. We find the largest match to allow both
117 domain.org and sub.domain.org to exist. */
118
119 unsigned int namelen = strlen(qdomain);
120 unsigned int matchlen = 0;
121 struct server *serv;
Simon Kelley28866e92011-02-14 20:19:14 +0000122 unsigned int flags = 0;
Simon Kelleycc921df2019-01-02 22:48:59 +0000123 static union all_addr zero;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100124
Simon Kelley3be34542004-09-11 19:12:13 +0100125 for (serv = daemon->servers; serv; serv=serv->next)
Simon Kelley09f3b2c2017-05-09 01:34:02 +0100126 if (qtype == F_DNSSECOK && !(serv->flags & SERV_DO_DNSSEC))
127 continue;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100128 /* domain matches take priority over NODOTS matches */
Simon Kelley09f3b2c2017-05-09 01:34:02 +0100129 else if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.') && namelen != 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100130 {
Simon Kelley28866e92011-02-14 20:19:14 +0000131 unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100132 *type = SERV_FOR_NODOTS;
Sung Paea914d0a2019-12-30 17:07:37 -0600133 if ((serv->flags & SERV_NO_REBIND) && norebind)
134 *norebind = 1;
135 else if (serv->flags & SERV_NO_ADDR)
Simon Kelley36717ee2004-09-20 19:20:58 +0100136 flags = F_NXDOMAIN;
Simon Kelleyda8b6512018-09-03 23:18:36 +0100137 else if (serv->flags & SERV_LITERAL_ADDRESS)
Simon Kelley36717ee2004-09-20 19:20:58 +0100138 {
Simon Kelleyda8b6512018-09-03 23:18:36 +0100139 /* literal address = '#' -> return all-zero address for IPv4 and IPv6 */
140 if ((serv->flags & SERV_USE_RESOLV) && (qtype & (F_IPV6 | F_IPV4)))
141 {
142 memset(&zero, 0, sizeof(zero));
143 flags = qtype;
144 *addrpp = &zero;
145 }
146 else if (sflag & qtype)
Simon Kelley36717ee2004-09-20 19:20:58 +0100147 {
148 flags = sflag;
149 if (serv->addr.sa.sa_family == AF_INET)
Simon Kelleycc921df2019-01-02 22:48:59 +0000150 *addrpp = (union all_addr *)&serv->addr.in.sin_addr;
Simon Kelley36717ee2004-09-20 19:20:58 +0100151 else
Simon Kelleycc921df2019-01-02 22:48:59 +0000152 *addrpp = (union all_addr *)&serv->addr.in6.sin6_addr;
Simon Kelley36717ee2004-09-20 19:20:58 +0100153 }
Simon Kelley824af852008-02-12 20:43:05 +0000154 else if (!flags || (flags & F_NXDOMAIN))
Simon Kelley36717ee2004-09-20 19:20:58 +0100155 flags = F_NOERR;
156 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100157 }
158 else if (serv->flags & SERV_HAS_DOMAIN)
159 {
160 unsigned int domainlen = strlen(serv->domain);
Simon Kelleyb8187c82005-11-26 21:46:27 +0000161 char *matchstart = qdomain + namelen - domainlen;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100162 if (namelen >= domainlen &&
Simon Kelleyb8187c82005-11-26 21:46:27 +0000163 hostname_isequal(matchstart, serv->domain) &&
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100164 (domainlen == 0 || namelen == domainlen || *(matchstart-1) == '.' ))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100165 {
Simon Kelley92be34a2016-01-16 18:39:54 +0000166 if ((serv->flags & SERV_NO_REBIND) && norebind)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100167 *norebind = 1;
Simon Kelley28866e92011-02-14 20:19:14 +0000168 else
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100169 {
Simon Kelley28866e92011-02-14 20:19:14 +0000170 unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
171 /* implement priority rules for --address and --server for same domain.
172 --address wins if the address is for the correct AF
173 --server wins otherwise. */
174 if (domainlen != 0 && domainlen == matchlen)
Simon Kelley36717ee2004-09-20 19:20:58 +0100175 {
Simon Kelley28866e92011-02-14 20:19:14 +0000176 if ((serv->flags & SERV_LITERAL_ADDRESS))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100177 {
Simon Kelley28866e92011-02-14 20:19:14 +0000178 if (!(sflag & qtype) && flags == 0)
179 continue;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100180 }
Simon Kelley28866e92011-02-14 20:19:14 +0000181 else
182 {
183 if (flags & (F_IPV4 | F_IPV6))
184 continue;
185 }
Simon Kelley36717ee2004-09-20 19:20:58 +0100186 }
Simon Kelley28866e92011-02-14 20:19:14 +0000187
188 if (domainlen >= matchlen)
189 {
Simon Kelley367341f2016-01-12 15:58:23 +0000190 *type = serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_DO_DNSSEC);
Simon Kelley28866e92011-02-14 20:19:14 +0000191 *domain = serv->domain;
192 matchlen = domainlen;
193 if (serv->flags & SERV_NO_ADDR)
194 flags = F_NXDOMAIN;
195 else if (serv->flags & SERV_LITERAL_ADDRESS)
196 {
Simon Kelleyda8b6512018-09-03 23:18:36 +0100197 /* literal address = '#' -> return all-zero address for IPv4 and IPv6 */
198 if ((serv->flags & SERV_USE_RESOLV) && (qtype & (F_IPV6 | F_IPV4)))
199 {
200 memset(&zero, 0, sizeof(zero));
201 flags = qtype;
202 *addrpp = &zero;
203 }
204 else if (sflag & qtype)
Simon Kelley28866e92011-02-14 20:19:14 +0000205 {
206 flags = sflag;
207 if (serv->addr.sa.sa_family == AF_INET)
Simon Kelleycc921df2019-01-02 22:48:59 +0000208 *addrpp = (union all_addr *)&serv->addr.in.sin_addr;
Simon Kelley28866e92011-02-14 20:19:14 +0000209 else
Simon Kelleycc921df2019-01-02 22:48:59 +0000210 *addrpp = (union all_addr *)&serv->addr.in6.sin6_addr;
Simon Kelley28866e92011-02-14 20:19:14 +0000211 }
212 else if (!flags || (flags & F_NXDOMAIN))
213 flags = F_NOERR;
214 }
215 else
216 flags = 0;
217 }
218 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100219 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100220 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100221
Simon Kelleybf05f8f2017-05-09 22:37:46 +0100222 if (flags == 0 && !(qtype & (F_QUERY | F_DNSSECOK)) &&
Simon Kelley28866e92011-02-14 20:19:14 +0000223 option_bool(OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
Simon Kelley7de060b2011-08-26 17:24:52 +0100224 /* don't forward A or AAAA queries for simple names, except the empty name */
225 flags = F_NOERR;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100226
Simon Kelley5aabfc72007-08-29 11:24:47 +0100227 if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now))
Simon Kelleyc1bb8502004-08-11 18:40:17 +0100228 flags = F_NOERR;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100229
Simon Kelley824af852008-02-12 20:43:05 +0000230 if (flags)
231 {
Simon Kelleyc346f612018-09-04 21:14:18 +0100232 if (flags == F_NXDOMAIN || flags == F_NOERR)
233 log_query(flags | qtype | F_NEG | F_CONFIG | F_FORWARD, qdomain, NULL, NULL);
234 else
235 {
236 /* handle F_IPV4 and F_IPV6 set on ANY query to 0.0.0.0/:: domain. */
237 if (flags & F_IPV4)
238 log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV6, qdomain, *addrpp, NULL);
Simon Kelleyc346f612018-09-04 21:14:18 +0100239 if (flags & F_IPV6)
240 log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV4, qdomain, *addrpp, NULL);
Simon Kelleyc346f612018-09-04 21:14:18 +0100241 }
Simon Kelley824af852008-02-12 20:43:05 +0000242 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100243 else if ((*type) & SERV_USE_RESOLV)
244 {
245 *type = 0; /* use normal servers for this domain */
246 *domain = NULL;
247 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100248 return flags;
249}
Simon Kelley44a2a312004-03-10 20:04:35 +0000250
Simon Kelley824af852008-02-12 20:43:05 +0000251static int forward_query(int udpfd, union mysockaddr *udpaddr,
Simon Kelleycc921df2019-01-02 22:48:59 +0000252 union all_addr *dst_addr, unsigned int dst_iface,
Simon Kelley83349b82014-02-10 21:02:01 +0000253 struct dns_header *header, size_t plen, time_t now,
Simon Kelley613ad152014-02-25 23:02:28 +0000254 struct frec *forward, int ad_reqd, int do_bit)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000255{
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000256 char *domain = NULL;
Simon Kelley367341f2016-01-12 15:58:23 +0000257 int type = SERV_DO_DNSSEC, norebind = 0;
Simon Kelleycc921df2019-01-02 22:48:59 +0000258 union all_addr *addrp = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +0000259 unsigned int flags = 0;
Simon Kelley15b60dd2020-11-18 18:34:55 +0000260 unsigned int fwd_flags = 0;
Simon Kelleyde379512004-06-22 20:23:33 +0100261 struct server *start = NULL;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000262 void *hash = hash_questions(header, plen, daemon->namebuff);
Simon Kelley2d765862020-11-12 22:06:07 +0000263#ifdef HAVE_DNSSEC
Simon Kelley367341f2016-01-12 15:58:23 +0000264 int do_dnssec = 0;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000265#endif
Simon Kelley1682d152018-08-03 20:38:18 +0100266 unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
267 unsigned char *oph = find_pseudoheader(header, plen, NULL, NULL, NULL, NULL);
268 (void)do_bit;
Simon Kelley15b60dd2020-11-18 18:34:55 +0000269
270 if (header->hb4 & HB4_CD)
271 fwd_flags |= FREC_CHECKING_DISABLED;
272 if (ad_reqd)
273 fwd_flags |= FREC_AD_QUESTION;
274 if (oph)
275 fwd_flags |= FREC_HAS_PHEADER;
276#ifdef HAVE_DNSSEC
277 if (do_bit)
278 fwd_flags |= FREC_DO_QUESTION;
279#endif
280
Simon Kelley3d8df262005-08-29 12:19:27 +0100281 /* may be no servers available. */
Simon Kelley2d765862020-11-12 22:06:07 +0000282 if (forward || (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000283 {
Simon Kelleya77cec82015-05-08 16:25:38 +0100284 /* If we didn't get an answer advertising a maximal packet in EDNS,
285 fall back to 1280, which should work everywhere on IPv6.
286 If that generates an answer, it will become the new default
287 for this server */
288 forward->flags |= FREC_TEST_PKTSZ;
289
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000290#ifdef HAVE_DNSSEC
Simon Kelleydac74312014-02-13 16:43:49 +0000291 /* If we've already got an answer to this query, but we're awaiting keys for validation,
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000292 there's no point retrying the query, retry the key query instead...... */
293 if (forward->blocking_query)
294 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000295 int fd, is_sign;
296 unsigned char *pheader;
Simon Kelleya77cec82015-05-08 16:25:38 +0100297
298 forward->flags &= ~FREC_TEST_PKTSZ;
299
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000300 while (forward->blocking_query)
301 forward = forward->blocking_query;
Simon Kelleya77cec82015-05-08 16:25:38 +0100302
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000303 blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
304 plen = forward->stash_len;
305
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000306 forward->flags |= FREC_TEST_PKTSZ;
Simon Kelley5bb88f02015-12-21 16:23:47 +0000307 if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000308 PUTSHORT(SAFE_PKTSZ, pheader);
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000309
Simon Kelley2b291912014-03-21 11:13:55 +0000310 if (forward->sentto->addr.sa.sa_family == AF_INET)
Simon Kelleycc921df2019-01-02 22:48:59 +0000311 log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (union all_addr *)&forward->sentto->addr.in.sin_addr, "dnssec");
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000312 else
Simon Kelleycc921df2019-01-02 22:48:59 +0000313 log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, "retry", (union all_addr *)&forward->sentto->addr.in6.sin6_addr, "dnssec");
Simon Kelleyee875042018-10-23 22:10:17 +0100314
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000315
316 if (forward->sentto->sfd)
317 fd = forward->sentto->sfd->fd;
318 else
319 {
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000320 if (forward->sentto->addr.sa.sa_family == AF_INET6)
321 fd = forward->rfd6->fd;
322 else
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000323 fd = forward->rfd4->fd;
324 }
325
Simon Kelleya0088e82018-05-10 21:43:14 +0100326 while (retry_send(sendto(fd, (char *)header, plen, 0,
327 &forward->sentto->addr.sa,
328 sa_len(&forward->sentto->addr))));
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000329
330 return 1;
331 }
332#endif
333
Simon Kelleyde379512004-06-22 20:23:33 +0100334 /* retry on existing query, send to all available servers */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000335 domain = forward->sentto->domain;
Simon Kelley824af852008-02-12 20:43:05 +0000336 forward->sentto->failed_queries++;
Simon Kelley28866e92011-02-14 20:19:14 +0000337 if (!option_bool(OPT_ORDER))
Simon Kelleyde379512004-06-22 20:23:33 +0100338 {
Simon Kelley0a852542005-03-23 20:28:59 +0000339 forward->forwardall = 1;
Simon Kelley3be34542004-09-11 19:12:13 +0100340 daemon->last_server = NULL;
Simon Kelleyde379512004-06-22 20:23:33 +0100341 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000342 type = forward->sentto->flags & SERV_TYPE;
Simon Kelley367341f2016-01-12 15:58:23 +0000343#ifdef HAVE_DNSSEC
344 do_dnssec = forward->sentto->flags & SERV_DO_DNSSEC;
345#endif
346
Simon Kelleyde379512004-06-22 20:23:33 +0100347 if (!(start = forward->sentto->next))
Simon Kelley3be34542004-09-11 19:12:13 +0100348 start = daemon->servers; /* at end of list, recycle */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000349 header->id = htons(forward->new_id);
350 }
351 else
352 {
Simon Kelley15b60dd2020-11-18 18:34:55 +0000353 /* Query from new source, but the same query may be in progress
354 from another source. If so, just add this client to the
Simon Kelley25e63f12020-11-25 21:17:52 +0000355 list that will get the reply.*/
Simon Kelley15b60dd2020-11-18 18:34:55 +0000356
Simon Kelley25e63f12020-11-25 21:17:52 +0000357 if (!option_bool(OPT_ADD_MAC) && !option_bool(OPT_MAC_B64) &&
358 (forward = lookup_frec_by_query(hash, fwd_flags)))
Simon Kelley15b60dd2020-11-18 18:34:55 +0000359 {
360 /* Note whine_malloc() zeros memory. */
361 if (!daemon->free_frec_src &&
362 daemon->frec_src_count < daemon->ftabsize &&
363 (daemon->free_frec_src = whine_malloc(sizeof(struct frec_src))))
Simon Kelley6a6e06f2020-12-04 18:35:11 +0000364 {
365 daemon->frec_src_count++;
366 daemon->free_frec_src->next = NULL;
367 }
Simon Kelley15b60dd2020-11-18 18:34:55 +0000368
369 /* If we've been spammed with many duplicates, just drop the query. */
370 if (daemon->free_frec_src)
371 {
372 struct frec_src *new = daemon->free_frec_src;
373 daemon->free_frec_src = new->next;
374 new->next = forward->frec_src.next;
375 forward->frec_src.next = new;
376 new->orig_id = ntohs(header->id);
377 new->source = *udpaddr;
378 new->dest = *dst_addr;
379 new->log_id = daemon->log_id;
380 new->iface = dst_iface;
381 }
382
383 return 1;
384 }
385
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000386 if (gotname)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100387 flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000388
Simon Kelley367341f2016-01-12 15:58:23 +0000389#ifdef HAVE_DNSSEC
390 do_dnssec = type & SERV_DO_DNSSEC;
Simon Kelleyf7443d72016-01-19 20:29:57 +0000391#endif
392 type &= ~SERV_DO_DNSSEC;
Simon Kelley15b60dd2020-11-18 18:34:55 +0000393
Simon Kelleyd05dd582016-01-19 21:23:30 +0000394 if (daemon->servers && !flags)
Simon Kelley8caf3d72020-04-04 17:00:32 +0100395 forward = get_new_frec(now, NULL, NULL);
Simon Kelleyd05dd582016-01-19 21:23:30 +0000396 /* table full - flags == 0, return REFUSED */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000397
398 if (forward)
399 {
Simon Kelley15b60dd2020-11-18 18:34:55 +0000400 forward->frec_src.source = *udpaddr;
401 forward->frec_src.orig_id = ntohs(header->id);
402 forward->frec_src.dest = *dst_addr;
403 forward->frec_src.iface = dst_iface;
Simon Kelley6a6e06f2020-12-04 18:35:11 +0000404 forward->frec_src.next = NULL;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000405 forward->new_id = get_id();
Simon Kelley832af0b2007-01-21 20:01:28 +0000406 forward->fd = udpfd;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000407 memcpy(forward->hash, hash, HASH_SIZE);
Simon Kelley0a852542005-03-23 20:28:59 +0000408 forward->forwardall = 0;
Simon Kelley15b60dd2020-11-18 18:34:55 +0000409 forward->flags = fwd_flags;
Simon Kelley28866e92011-02-14 20:19:14 +0000410 if (norebind)
411 forward->flags |= FREC_NOREBIND;
Simon Kelley572b41e2011-02-18 18:11:18 +0000412 if (header->hb4 & HB4_CD)
Simon Kelley28866e92011-02-14 20:19:14 +0000413 forward->flags |= FREC_CHECKING_DISABLED;
Simon Kelley83349b82014-02-10 21:02:01 +0000414 if (ad_reqd)
415 forward->flags |= FREC_AD_QUESTION;
Simon Kelley7fa836e2014-02-10 20:11:24 +0000416#ifdef HAVE_DNSSEC
417 forward->work_counter = DNSSEC_WORK;
Simon Kelley613ad152014-02-25 23:02:28 +0000418 if (do_bit)
419 forward->flags |= FREC_DO_QUESTION;
Simon Kelley7fa836e2014-02-10 20:11:24 +0000420#endif
Simon Kelley613ad152014-02-25 23:02:28 +0000421
Simon Kelley28866e92011-02-14 20:19:14 +0000422 header->id = htons(forward->new_id);
423
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100424 /* In strict_order mode, always try servers in the order
425 specified in resolv.conf, if a domain is given
426 always try all the available servers,
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000427 otherwise, use the one last known to work. */
428
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100429 if (type == 0)
430 {
Simon Kelley28866e92011-02-14 20:19:14 +0000431 if (option_bool(OPT_ORDER))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100432 start = daemon->servers;
433 else if (!(start = daemon->last_server) ||
434 daemon->forwardcount++ > FORWARD_TEST ||
435 difftime(now, daemon->forwardtime) > FORWARD_TIME)
436 {
437 start = daemon->servers;
438 forward->forwardall = 1;
439 daemon->forwardcount = 0;
440 daemon->forwardtime = now;
441 }
442 }
443 else
Simon Kelleyde379512004-06-22 20:23:33 +0100444 {
Simon Kelley3be34542004-09-11 19:12:13 +0100445 start = daemon->servers;
Simon Kelley28866e92011-02-14 20:19:14 +0000446 if (!option_bool(OPT_ORDER))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100447 forward->forwardall = 1;
Simon Kelleyde379512004-06-22 20:23:33 +0100448 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000449 }
450 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100451
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000452 /* check for send errors here (no route to host)
453 if we fail to send to all nameservers, send back an error
454 packet straight away (helps modem users when offline) */
455
456 if (!flags && forward)
457 {
Simon Kelleyde379512004-06-22 20:23:33 +0100458 struct server *firstsentto = start;
Simon Kelley25e63f12020-11-25 21:17:52 +0000459 int subnet, cacheable, forwarded = 0;
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000460 size_t edns0_len;
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000461 unsigned char *pheader;
462
Simon Kelley25cf5e32015-01-09 15:53:03 +0000463 /* If a query is retried, use the log_id for the retry when logging the answer. */
Simon Kelley15b60dd2020-11-18 18:34:55 +0000464 forward->frec_src.log_id = daemon->log_id;
Simon Kelley25cf5e32015-01-09 15:53:03 +0000465
Simon Kelley25e63f12020-11-25 21:17:52 +0000466 plen = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->frec_src.source, now, &subnet, &cacheable);
Simon Kelley33702ab2015-12-28 23:17:15 +0000467
Simon Kelley6fd5d792017-10-13 22:26:40 +0100468 if (subnet)
469 forward->flags |= FREC_HAS_SUBNET;
Simon Kelley25e63f12020-11-25 21:17:52 +0000470
471 if (!cacheable)
472 forward->flags |= FREC_NO_CACHE;
473
Simon Kelley3a237152013-12-12 12:15:50 +0000474#ifdef HAVE_DNSSEC
Simon Kelley367341f2016-01-12 15:58:23 +0000475 if (option_bool(OPT_DNSSEC_VALID) && do_dnssec)
Simon Kelley0fc2f312014-01-08 10:26:58 +0000476 {
Simon Kelley6fd5d792017-10-13 22:26:40 +0100477 plen = add_do_bit(header, plen, ((unsigned char *) header) + PACKETSZ);
478
Simon Kelley5b3bf922014-01-25 17:03:07 +0000479 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
480 this allows it to select auth servers when one is returning bad data. */
481 if (option_bool(OPT_DNSSEC_DEBUG))
482 header->hb4 |= HB4_CD;
Simon Kelley613ad152014-02-25 23:02:28 +0000483
Simon Kelley0fc2f312014-01-08 10:26:58 +0000484 }
Simon Kelley3a237152013-12-12 12:15:50 +0000485#endif
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000486
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000487 if (find_pseudoheader(header, plen, &edns0_len, &pheader, NULL, NULL))
Simon Kelley6fd5d792017-10-13 22:26:40 +0100488 {
489 /* If there wasn't a PH before, and there is now, we added it. */
490 if (!oph)
491 forward->flags |= FREC_ADDED_PHEADER;
492
493 /* If we're sending an EDNS0 with any options, we can't recreate the query from a reply. */
494 if (edns0_len > 11)
495 forward->flags |= FREC_HAS_EXTRADATA;
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000496
497 /* Reduce udp size on retransmits. */
498 if (forward->flags & FREC_TEST_PKTSZ)
499 PUTSHORT(SAFE_PKTSZ, pheader);
Simon Kelley6fd5d792017-10-13 22:26:40 +0100500 }
Simon Kelleya77cec82015-05-08 16:25:38 +0100501
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000502 while (1)
503 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000504 /* only send to servers dealing with our domain.
505 domain may be NULL, in which case server->domain
506 must be NULL also. */
507
Simon Kelleyde379512004-06-22 20:23:33 +0100508 if (type == (start->flags & SERV_TYPE) &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100509 (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +0100510 !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000511 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100512 int fd;
513
514 /* find server socket to use, may need to get random one. */
515 if (start->sfd)
516 fd = start->sfd->fd;
517 else
518 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100519 if (start->addr.sa.sa_family == AF_INET6)
520 {
521 if (!forward->rfd6 &&
522 !(forward->rfd6 = allocate_rfd(AF_INET6)))
523 break;
Simon Kelley3927da42008-07-20 15:10:39 +0100524 daemon->rfd_save = forward->rfd6;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100525 fd = forward->rfd6->fd;
526 }
527 else
Simon Kelley1a6bca82008-07-11 11:11:42 +0100528 {
529 if (!forward->rfd4 &&
530 !(forward->rfd4 = allocate_rfd(AF_INET)))
531 break;
Simon Kelley3927da42008-07-20 15:10:39 +0100532 daemon->rfd_save = forward->rfd4;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100533 fd = forward->rfd4->fd;
534 }
Simon Kelley7de060b2011-08-26 17:24:52 +0100535
536#ifdef HAVE_CONNTRACK
537 /* Copy connection mark of incoming query to outgoing connection. */
538 if (option_bool(OPT_CONNTRACK))
539 {
540 unsigned int mark;
Giacomo Tazzari797a7af2013-04-22 13:16:37 +0100541 if (get_incoming_mark(&forward->source, &forward->dest, 0, &mark))
Simon Kelley7de060b2011-08-26 17:24:52 +0100542 setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
543 }
544#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +0100545 }
546
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000547#ifdef HAVE_DNSSEC
Simon Kelley5bb88f02015-12-21 16:23:47 +0000548 if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER))
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000549 {
550 /* Difficult one here. If our client didn't send EDNS0, we will have set the UDP
551 packet size to 512. But that won't provide space for the RRSIGS in many cases.
552 The RRSIGS will be stripped out before the answer goes back, so the packet should
553 shrink again. So, if we added a do-bit, bump the udp packet size to the value
Simon Kelley5aa5f0f2015-12-21 17:20:35 +0000554 known to be OK for this server. We check returned size after stripping and set
555 the truncated bit if it's still too big. */
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000556 unsigned char *pheader;
557 int is_sign;
Simon Kelley5bb88f02015-12-21 16:23:47 +0000558 if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000559 PUTSHORT(start->edns_pktsz, pheader);
560 }
561#endif
562
Simon Kelleyff841eb2015-03-11 21:36:30 +0000563 if (retry_send(sendto(fd, (char *)header, plen, 0,
564 &start->addr.sa,
565 sa_len(&start->addr))))
566 continue;
567
568 if (errno == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000569 {
Simon Kelley6b173352018-05-08 18:32:14 +0100570#ifdef HAVE_DUMPFILE
571 dump_packet(DUMP_UP_QUERY, (void *)header, plen, NULL, &start->addr);
572#endif
573
Simon Kelleycdeda282006-03-16 20:16:06 +0000574 /* Keep info in case we want to re-send this packet */
575 daemon->srv_save = start;
576 daemon->packet_len = plen;
577
Simon Kelleyde379512004-06-22 20:23:33 +0100578 if (!gotname)
Simon Kelley3be34542004-09-11 19:12:13 +0100579 strcpy(daemon->namebuff, "query");
Simon Kelleyde379512004-06-22 20:23:33 +0100580 if (start->addr.sa.sa_family == AF_INET)
Simon Kelley3be34542004-09-11 19:12:13 +0100581 log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
Simon Kelleycc921df2019-01-02 22:48:59 +0000582 (union all_addr *)&start->addr.in.sin_addr, NULL);
Simon Kelleyde379512004-06-22 20:23:33 +0100583 else
Simon Kelley3be34542004-09-11 19:12:13 +0100584 log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
Simon Kelleycc921df2019-01-02 22:48:59 +0000585 (union all_addr *)&start->addr.in6.sin6_addr, NULL);
Simon Kelley824af852008-02-12 20:43:05 +0000586 start->queries++;
Simon Kelleyde379512004-06-22 20:23:33 +0100587 forwarded = 1;
588 forward->sentto = start;
Simon Kelley0a852542005-03-23 20:28:59 +0000589 if (!forward->forwardall)
Simon Kelleyde379512004-06-22 20:23:33 +0100590 break;
Simon Kelley0a852542005-03-23 20:28:59 +0000591 forward->forwardall++;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000592 }
593 }
594
Simon Kelleyde379512004-06-22 20:23:33 +0100595 if (!(start = start->next))
Simon Kelley3be34542004-09-11 19:12:13 +0100596 start = daemon->servers;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000597
Simon Kelleyde379512004-06-22 20:23:33 +0100598 if (start == firstsentto)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000599 break;
600 }
601
Simon Kelleyde379512004-06-22 20:23:33 +0100602 if (forwarded)
Simon Kelley824af852008-02-12 20:43:05 +0000603 return 1;
Simon Kelleyde379512004-06-22 20:23:33 +0100604
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000605 /* could not send on, prepare to return */
Simon Kelley15b60dd2020-11-18 18:34:55 +0000606 header->id = htons(forward->frec_src.orig_id);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100607 free_frec(forward); /* cancel */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000608 }
609
610 /* could not send on, return empty answer or address if known for whole domain */
Simon Kelleyb8187c82005-11-26 21:46:27 +0000611 if (udpfd != -1)
612 {
Simon Kelleycdeda282006-03-16 20:16:06 +0000613 plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl);
Simon Kelley1682d152018-08-03 20:38:18 +0100614 if (oph)
615 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 +0100616 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 +0000617 }
618
Simon Kelley824af852008-02-12 20:43:05 +0000619 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000620}
621
Simon Kelleyed4c0762013-10-08 20:46:34 +0100622static 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 +0100623 int no_cache, int cache_secure, int bogusanswer, int ad_reqd, int do_bit, int added_pheader,
624 int check_subnet, union mysockaddr *query_source)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100625{
Simon Kelley36717ee2004-09-20 19:20:58 +0100626 unsigned char *pheader, *sizep;
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000627 char **sets = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +0000628 int munged = 0, is_sign;
Simon Kelley07ed5852018-05-04 21:52:22 +0100629 unsigned int rcode = RCODE(header);
Simon Kelleycdeda282006-03-16 20:16:06 +0000630 size_t plen;
Simon Kelleya6004d72017-10-25 17:48:19 +0100631
Simon Kelley83349b82014-02-10 21:02:01 +0000632 (void)ad_reqd;
Simon Kelley982faf42015-04-03 21:42:30 +0100633 (void)do_bit;
634 (void)bogusanswer;
Simon Kelley83349b82014-02-10 21:02:01 +0000635
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000636#ifdef HAVE_IPSET
Simon Kelley82a14af2014-04-13 20:48:57 +0100637 if (daemon->ipsets && extract_request(header, n, daemon->namebuff, NULL))
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000638 {
Simon Kelley82a14af2014-04-13 20:48:57 +0100639 /* Similar algorithm to search_servers. */
640 struct ipsets *ipset_pos;
641 unsigned int namelen = strlen(daemon->namebuff);
642 unsigned int matchlen = 0;
643 for (ipset_pos = daemon->ipsets; ipset_pos; ipset_pos = ipset_pos->next)
Simon Kelley6c0cb852014-01-17 14:40:46 +0000644 {
Simon Kelley82a14af2014-04-13 20:48:57 +0100645 unsigned int domainlen = strlen(ipset_pos->domain);
646 char *matchstart = daemon->namebuff + namelen - domainlen;
647 if (namelen >= domainlen && hostname_isequal(matchstart, ipset_pos->domain) &&
648 (domainlen == 0 || namelen == domainlen || *(matchstart - 1) == '.' ) &&
649 domainlen >= matchlen)
650 {
651 matchlen = domainlen;
652 sets = ipset_pos->sets;
653 }
Simon Kelley6c0cb852014-01-17 14:40:46 +0000654 }
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000655 }
656#endif
Simon Kelley25e63f12020-11-25 21:17:52 +0000657
Simon Kelley5bb88f02015-12-21 16:23:47 +0000658 if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign, NULL)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100659 {
Simon Kelley07ed5852018-05-04 21:52:22 +0100660 /* Get extended RCODE. */
661 rcode |= sizep[2] << 4;
662
Simon Kelleyed4c0762013-10-08 20:46:34 +0100663 if (check_subnet && !check_source(header, plen, pheader, query_source))
664 {
665 my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch"));
666 return 0;
667 }
Simon Kelley613ad152014-02-25 23:02:28 +0000668
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000669 if (!is_sign)
Simon Kelley613ad152014-02-25 23:02:28 +0000670 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000671 if (added_pheader)
672 {
673 /* client didn't send EDNS0, we added one, strip it off before returning answer. */
674 n = rrfilter(header, n, 0);
675 pheader = NULL;
676 }
677 else
678 {
Simon Kelley33702ab2015-12-28 23:17:15 +0000679 unsigned short udpsz;
680
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000681 /* If upstream is advertising a larger UDP packet size
682 than we allow, trim it so that we don't get overlarge
683 requests for the client. We can't do this for signed packets. */
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000684 GETSHORT(udpsz, sizep);
685 if (udpsz > daemon->edns_pktsz)
Simon Kelley33702ab2015-12-28 23:17:15 +0000686 {
687 sizep -= 2;
688 PUTSHORT(daemon->edns_pktsz, sizep);
689 }
690
691#ifdef HAVE_DNSSEC
692 /* If the client didn't set the do bit, but we did, reset it. */
693 if (option_bool(OPT_DNSSEC_VALID) && !do_bit)
694 {
695 unsigned short flags;
696 sizep += 2; /* skip RCODE */
697 GETSHORT(flags, sizep);
698 flags &= ~0x8000;
699 sizep -= 2;
700 PUTSHORT(flags, sizep);
701 }
702#endif
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000703 }
Simon Kelley613ad152014-02-25 23:02:28 +0000704 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100705 }
Simon Kelley83349b82014-02-10 21:02:01 +0000706
Simon Kelley28866e92011-02-14 20:19:14 +0000707 /* RFC 4035 sect 4.6 para 3 */
Giovanni Bajo237724c2012-04-05 02:46:52 +0200708 if (!is_sign && !option_bool(OPT_DNSSEC_PROXY))
Simon Kelley795501b2014-01-08 18:11:55 +0000709 header->hb4 &= ~HB4_AD;
Simon Kelley3a237152013-12-12 12:15:50 +0000710
Simon Kelley07ed5852018-05-04 21:52:22 +0100711 if (OPCODE(header) != QUERY)
Simon Kelley8938ae02014-05-01 17:46:25 +0100712 return resize_packet(header, n, pheader, plen);
Simon Kelley07ed5852018-05-04 21:52:22 +0100713
714 if (rcode != NOERROR && rcode != NXDOMAIN)
715 {
Simon Kelleycc921df2019-01-02 22:48:59 +0000716 union all_addr a;
717 a.log.rcode = rcode;
Simon Kelley07ed5852018-05-04 21:52:22 +0100718 log_query(F_UPSTREAM | F_RCODE, "error", &a, NULL);
719
720 return resize_packet(header, n, pheader, plen);
721 }
Simon Kelley36717ee2004-09-20 19:20:58 +0100722
Simon Kelley0a852542005-03-23 20:28:59 +0000723 /* Complain loudly if the upstream server is non-recursive. */
Simon Kelley07ed5852018-05-04 21:52:22 +0100724 if (!(header->hb4 & HB4_RA) && rcode == NOERROR &&
Simon Kelley0a852542005-03-23 20:28:59 +0000725 server && !(server->flags & SERV_WARNED_RECURSIVE))
726 {
Petr Mensik51cdd1a2019-07-04 20:28:08 +0200727 (void)prettyprint_addr(&server->addr, daemon->namebuff);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100728 my_syslog(LOG_WARNING, _("nameserver %s refused to do a recursive query"), daemon->namebuff);
Simon Kelley28866e92011-02-14 20:19:14 +0000729 if (!option_bool(OPT_LOG))
Simon Kelley0a852542005-03-23 20:28:59 +0000730 server->flags |= SERV_WARNED_RECURSIVE;
731 }
Giovanni Bajoe292e932012-04-22 14:32:02 +0200732
Simon Kelley07ed5852018-05-04 21:52:22 +0100733 if (daemon->bogus_addr && rcode != NXDOMAIN &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100734 check_for_bogus_wildcard(header, n, daemon->namebuff, daemon->bogus_addr, now))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100735 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100736 munged = 1;
Simon Kelley572b41e2011-02-18 18:11:18 +0000737 SET_RCODE(header, NXDOMAIN);
738 header->hb3 &= ~HB3_AA;
Simon Kelley6938f342014-01-26 22:47:39 +0000739 cache_secure = 0;
Simon Kelley36717ee2004-09-20 19:20:58 +0100740 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100741 else
Simon Kelley36717ee2004-09-20 19:20:58 +0100742 {
Simon Kelley6938f342014-01-26 22:47:39 +0000743 int doctored = 0;
744
Simon Kelley07ed5852018-05-04 21:52:22 +0100745 if (rcode == NXDOMAIN &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100746 extract_request(header, n, daemon->namebuff, NULL) &&
Simon Kelley5aabfc72007-08-29 11:24:47 +0100747 check_for_local_domain(daemon->namebuff, now))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100748 {
Simon Kelley36717ee2004-09-20 19:20:58 +0100749 /* if we forwarded a query for a locally known name (because it was for
750 an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
751 since we know that the domain exists, even if upstream doesn't */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100752 munged = 1;
Simon Kelley572b41e2011-02-18 18:11:18 +0000753 header->hb3 |= HB3_AA;
754 SET_RCODE(header, NOERROR);
Simon Kelley6938f342014-01-26 22:47:39 +0000755 cache_secure = 0;
Simon Kelley36717ee2004-09-20 19:20:58 +0100756 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000757
Simon Kelley373e9172017-12-01 22:40:56 +0000758 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 +0000759 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100760 my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
Simon Kelley824af852008-02-12 20:43:05 +0000761 munged = 1;
Simon Kelley6938f342014-01-26 22:47:39 +0000762 cache_secure = 0;
Simon Kelley824af852008-02-12 20:43:05 +0000763 }
Simon Kelley6938f342014-01-26 22:47:39 +0000764
765 if (doctored)
766 cache_secure = 0;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100767 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100768
Simon Kelleya25720a2014-01-14 23:13:55 +0000769#ifdef HAVE_DNSSEC
Simon Kelley33702ab2015-12-28 23:17:15 +0000770 if (bogusanswer && !(header->hb4 & HB4_CD) && !option_bool(OPT_DNSSEC_DEBUG))
Simon Kelleya25720a2014-01-14 23:13:55 +0000771 {
Simon Kelley33702ab2015-12-28 23:17:15 +0000772 /* Bogus reply, turn into SERVFAIL */
773 SET_RCODE(header, SERVFAIL);
774 munged = 1;
Simon Kelleya25720a2014-01-14 23:13:55 +0000775 }
Simon Kelley6938f342014-01-26 22:47:39 +0000776
777 if (option_bool(OPT_DNSSEC_VALID))
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000778 {
779 header->hb4 &= ~HB4_AD;
780
781 if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure)
782 header->hb4 |= HB4_AD;
783
784 /* If the requestor didn't set the DO bit, don't return DNSSEC info. */
785 if (!do_bit)
786 n = rrfilter(header, n, 1);
787 }
Simon Kelleya25720a2014-01-14 23:13:55 +0000788#endif
789
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100790 /* do this after extract_addresses. Ensure NODATA reply and remove
791 nameserver info. */
792
793 if (munged)
794 {
795 header->ancount = htons(0);
796 header->nscount = htons(0);
797 header->arcount = htons(0);
Simon Kelley150162b2015-03-27 09:58:26 +0000798 header->hb3 &= ~HB3_TC;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100799 }
800
Simon Kelley36717ee2004-09-20 19:20:58 +0100801 /* the bogus-nxdomain stuff, doctor and NXDOMAIN->NODATA munging can all elide
802 sections of the packet. Find the new length here and put back pseudoheader
803 if it was removed. */
804 return resize_packet(header, n, pheader, plen);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100805}
806
Simon Kelley3be34542004-09-11 19:12:13 +0100807/* sets new last_server */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100808void reply_query(int fd, int family, time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000809{
810 /* packet from peer server, extract data for cache, and send to
811 original requester */
Simon Kelley572b41e2011-02-18 18:11:18 +0000812 struct dns_header *header;
Simon Kelleyde379512004-06-22 20:23:33 +0100813 union mysockaddr serveraddr;
Simon Kelley832af0b2007-01-21 20:01:28 +0000814 struct frec *forward;
Simon Kelleyde379512004-06-22 20:23:33 +0100815 socklen_t addrlen = sizeof(serveraddr);
Simon Kelley60b68062014-01-08 12:10:28 +0000816 ssize_t n = recvfrom(fd, daemon->packet, daemon->packet_buff_sz, 0, &serveraddr.sa, &addrlen);
Simon Kelleycdeda282006-03-16 20:16:06 +0000817 size_t nn;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100818 struct server *server;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000819 void *hash;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000820
Simon Kelleycdeda282006-03-16 20:16:06 +0000821 /* packet buffer overwritten */
822 daemon->srv_save = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +0000823
Simon Kelleyde379512004-06-22 20:23:33 +0100824 /* Determine the address of the server replying so that we can mark that as good */
Simon Kelleyee875042018-10-23 22:10:17 +0100825 if ((serveraddr.sa.sa_family = family) == AF_INET6)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100826 serveraddr.in6.sin6_flowinfo = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000827
Simon Kelley490f9072014-03-24 22:04:42 +0000828 header = (struct dns_header *)daemon->packet;
Simon Kelley6b173352018-05-08 18:32:14 +0100829
Simon Kelley490f9072014-03-24 22:04:42 +0000830 if (n < (int)sizeof(struct dns_header) || !(header->hb3 & HB3_QR))
831 return;
832
Simon Kelley1a6bca82008-07-11 11:11:42 +0100833 /* spoof check: answer must come from known server, */
834 for (server = daemon->servers; server; server = server->next)
835 if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) &&
836 sockaddr_isequal(&server->addr, &serveraddr))
837 break;
Simon Kelley490f9072014-03-24 22:04:42 +0000838
839 if (!server)
840 return;
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000841
842 /* If sufficient time has elapsed, try and expand UDP buffer size again. */
843 if (difftime(now, server->pktsz_reduced) > UDP_TEST_TIME)
844 server->edns_pktsz = daemon->edns_pktsz;
845
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000846 hash = hash_questions(header, n, daemon->namebuff);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100847
Simon Kelley257ac0c2020-11-12 18:49:23 +0000848 if (!(forward = lookup_frec(ntohs(header->id), fd, family, hash)))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100849 return;
Simon Kelley490f9072014-03-24 22:04:42 +0000850
Simon Kelley6b173352018-05-08 18:32:14 +0100851#ifdef HAVE_DUMPFILE
852 dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_REPLY : DUMP_UP_REPLY,
853 (void *)header, n, &serveraddr, NULL);
854#endif
Simon Kelleya0088e82018-05-10 21:43:14 +0100855
Simon Kelley25cf5e32015-01-09 15:53:03 +0000856 /* log_query gets called indirectly all over the place, so
857 pass these in global variables - sorry. */
Simon Kelley15b60dd2020-11-18 18:34:55 +0000858 daemon->log_display_id = forward->frec_src.log_id;
859 daemon->log_source_addr = &forward->frec_src.source;
Simon Kelley25cf5e32015-01-09 15:53:03 +0000860
Glen Huang32fc6db2014-12-27 15:28:12 +0000861 if (daemon->ignore_addr && RCODE(header) == NOERROR &&
862 check_for_ignored_address(header, n, daemon->ignore_addr))
863 return;
864
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000865 /* Note: if we send extra options in the EDNS0 header, we can't recreate
866 the query from the reply. */
Simon Kelley34e26e12018-05-10 20:54:57 +0100867 if ((RCODE(header) == REFUSED || RCODE(header) == SERVFAIL) &&
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000868 forward->forwardall == 0 &&
869 !(forward->flags & FREC_HAS_EXTRADATA))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100870 /* for broken servers, attempt to send to another one. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000871 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100872 unsigned char *pheader;
873 size_t plen;
874 int is_sign;
Simon Kelleyef3d1372017-12-05 22:37:29 +0000875
Simon Kelley1f60a182018-05-11 16:44:16 +0100876#ifdef HAVE_DNSSEC
Simon Kelleya0088e82018-05-10 21:43:14 +0100877 if (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY))
878 {
Simon Kelley1f60a182018-05-11 16:44:16 +0100879 struct server *start;
880
Simon Kelleya0088e82018-05-10 21:43:14 +0100881 blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
882 plen = forward->stash_len;
883
884 forward->forwardall = 2; /* only retry once */
Simon Kelley1f60a182018-05-11 16:44:16 +0100885 start = forward->sentto;
886
887 /* for non-domain specific servers, see if we can find another to try. */
888 if ((forward->sentto->flags & SERV_TYPE) == 0)
889 while (1)
890 {
891 if (!(start = start->next))
892 start = daemon->servers;
893 if (start == forward->sentto)
894 break;
895
896 if ((start->flags & SERV_TYPE) == 0 &&
897 (start->flags & SERV_DO_DNSSEC))
898 break;
899 }
900
901
Simon Kelley82446112020-11-15 22:13:25 +0000902 fd = -1;
903
Simon Kelley1f60a182018-05-11 16:44:16 +0100904 if (start->sfd)
905 fd = start->sfd->fd;
Simon Kelleya0088e82018-05-10 21:43:14 +0100906 else
907 {
Simon Kelley1f60a182018-05-11 16:44:16 +0100908 if (start->addr.sa.sa_family == AF_INET6)
909 {
910 /* may have changed family */
Simon Kelley82446112020-11-15 22:13:25 +0000911 if (forward->rfd6 || (forward->rfd6 = allocate_rfd(AF_INET6)))
912 fd = forward->rfd6->fd;
Simon Kelley1f60a182018-05-11 16:44:16 +0100913 }
Simon Kelleya0088e82018-05-10 21:43:14 +0100914 else
Simon Kelley1f60a182018-05-11 16:44:16 +0100915 {
916 /* may have changed family */
Simon Kelley82446112020-11-15 22:13:25 +0000917 if (forward->rfd4 || (forward->rfd4 = allocate_rfd(AF_INET)))
918 fd = forward->rfd4->fd;
Simon Kelley1f60a182018-05-11 16:44:16 +0100919 }
Simon Kelleya0088e82018-05-10 21:43:14 +0100920 }
Simon Kelleye3002bf2019-10-11 23:30:08 +0100921
Simon Kelley82446112020-11-15 22:13:25 +0000922 /* Can't get socket. */
923 if (fd == -1)
924 return;
925
Simon Kelleye3002bf2019-10-11 23:30:08 +0100926#ifdef HAVE_DUMPFILE
927 dump_packet(DUMP_SEC_QUERY, (void *)header, (size_t)plen, NULL, &start->addr);
928#endif
929
Simon Kelleya0088e82018-05-10 21:43:14 +0100930 while (retry_send(sendto(fd, (char *)header, plen, 0,
Simon Kelley1f60a182018-05-11 16:44:16 +0100931 &start->addr.sa,
932 sa_len(&start->addr))));
Simon Kelleya0088e82018-05-10 21:43:14 +0100933
Simon Kelleye27825b2018-05-11 17:20:47 +0100934 if (start->addr.sa.sa_family == AF_INET)
Simon Kelleycc921df2019-01-02 22:48:59 +0000935 log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (union all_addr *)&start->addr.in.sin_addr, "dnssec");
Simon Kelleye27825b2018-05-11 17:20:47 +0100936 else
Simon Kelleycc921df2019-01-02 22:48:59 +0000937 log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, "retry", (union all_addr *)&start->addr.in6.sin6_addr, "dnssec");
Simon Kelleye27825b2018-05-11 17:20:47 +0100938
Simon Kelleya0088e82018-05-10 21:43:14 +0100939 return;
940 }
Simon Kelley1f60a182018-05-11 16:44:16 +0100941#endif
942
Simon Kelleyef3d1372017-12-05 22:37:29 +0000943 /* In strict order mode, there must be a server later in the chain
944 left to send to, otherwise without the forwardall mechanism,
945 code further on will cycle around the list forwever if they
946 all return REFUSED. Note that server is always non-NULL before
947 this executes. */
948 if (option_bool(OPT_ORDER))
949 for (server = forward->sentto->next; server; server = server->next)
950 if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR | SERV_LOOP)))
951 break;
952
Simon Kelley1a6bca82008-07-11 11:11:42 +0100953 /* recreate query from reply */
Simon Kelley5bb88f02015-12-21 16:23:47 +0000954 pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign, NULL);
Simon Kelleyef3d1372017-12-05 22:37:29 +0000955 if (!is_sign && server)
Simon Kelley832af0b2007-01-21 20:01:28 +0000956 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100957 header->ancount = htons(0);
958 header->nscount = htons(0);
959 header->arcount = htons(0);
960 if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
961 {
swiggerbd7bfa22015-06-01 20:54:59 +0100962 header->hb3 &= ~(HB3_QR | HB3_AA | HB3_TC);
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000963 header->hb4 &= ~(HB4_RA | HB4_RCODE | HB4_CD | HB4_AD);
Simon Kelley1801a292016-01-17 21:53:57 +0000964 if (forward->flags & FREC_CHECKING_DISABLED)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000965 header->hb4 |= HB4_CD;
Simon Kelley1801a292016-01-17 21:53:57 +0000966 if (forward->flags & FREC_AD_QUESTION)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000967 header->hb4 |= HB4_AD;
968 if (forward->flags & FREC_DO_QUESTION)
Simon Kelley33702ab2015-12-28 23:17:15 +0000969 add_do_bit(header, nn, (unsigned char *)pheader + plen);
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000970 forward_query(-1, NULL, NULL, 0, header, nn, now, forward, forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100971 return;
972 }
973 }
974 }
Simon Kelley3a237152013-12-12 12:15:50 +0000975
976 server = forward->sentto;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100977 if ((forward->sentto->flags & SERV_TYPE) == 0)
978 {
Simon Kelley51967f92014-03-25 21:07:00 +0000979 if (RCODE(header) == REFUSED)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100980 server = NULL;
981 else
982 {
983 struct server *last_server;
Simon Kelley832af0b2007-01-21 20:01:28 +0000984
Simon Kelley1a6bca82008-07-11 11:11:42 +0100985 /* find good server by address if possible, otherwise assume the last one we sent to */
986 for (last_server = daemon->servers; last_server; last_server = last_server->next)
987 if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) &&
988 sockaddr_isequal(&last_server->addr, &serveraddr))
989 {
990 server = last_server;
991 break;
992 }
993 }
Simon Kelley28866e92011-02-14 20:19:14 +0000994 if (!option_bool(OPT_ALL_SERVERS))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100995 daemon->last_server = server;
996 }
Simon Kelleya77cec82015-05-08 16:25:38 +0100997
998 /* We tried resending to this server with a smaller maximum size and got an answer.
Ville Skyttäfaaf3062018-01-14 17:32:52 +0000999 Make that permanent. To avoid reduxing the packet size for a single dropped packet,
Simon Kelley86fa1042015-05-10 13:50:59 +01001000 only do this when we get a truncated answer, or one larger than the safe size. */
Simon Kelley04db1482019-10-11 23:22:17 +01001001 if (forward->sentto->edns_pktsz > SAFE_PKTSZ && (forward->flags & FREC_TEST_PKTSZ) &&
Simon Kelley86fa1042015-05-10 13:50:59 +01001002 ((header->hb3 & HB3_TC) || n >= SAFE_PKTSZ))
Simon Kelley22dee512017-10-13 22:54:00 +01001003 {
Simon Kelley04db1482019-10-11 23:22:17 +01001004 forward->sentto->edns_pktsz = SAFE_PKTSZ;
1005 forward->sentto->pktsz_reduced = now;
Petr Mensik51cdd1a2019-07-04 20:28:08 +02001006 (void)prettyprint_addr(&forward->sentto->addr, daemon->addrbuff);
Simon Kelleyebedcba2017-10-29 20:54:17 +00001007 my_syslog(LOG_WARNING, _("reducing DNS packet size for nameserver %s to %d"), daemon->addrbuff, SAFE_PKTSZ);
Simon Kelley22dee512017-10-13 22:54:00 +01001008 }
Simon Kelleyc1a4e252018-01-19 22:00:05 +00001009
1010
Simon Kelley1a6bca82008-07-11 11:11:42 +01001011 /* If the answer is an error, keep the forward record in place in case
1012 we get a good reply from another server. Kill it when we've
1013 had replies from all to avoid filling the forwarding table when
1014 everything is broken */
Simon Kelley122392e2018-10-31 22:24:02 +00001015 if (forward->forwardall == 0 || --forward->forwardall == 1 || RCODE(header) != REFUSED)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001016 {
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001017 int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
Simon Kelleya6004d72017-10-25 17:48:19 +01001018
Simon Kelley3a237152013-12-12 12:15:50 +00001019 if (option_bool(OPT_NO_REBIND))
1020 check_rebind = !(forward->flags & FREC_NOREBIND);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001021
Simon Kelley3a237152013-12-12 12:15:50 +00001022 /* Don't cache replies where DNSSEC validation was turned off, either
1023 the upstream server told us so, or the original query specified it. */
1024 if ((header->hb4 & HB4_CD) || (forward->flags & FREC_CHECKING_DISABLED))
1025 no_cache_dnssec = 1;
1026
1027#ifdef HAVE_DNSSEC
Simon Kelley04db1482019-10-11 23:22:17 +01001028 if ((forward->sentto->flags & SERV_DO_DNSSEC) &&
Simon Kelley57573712016-01-11 22:50:00 +00001029 option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED))
Simon Kelley3a237152013-12-12 12:15:50 +00001030 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001031 int status = 0;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001032
1033 /* We've had a reply already, which we're validating. Ignore this duplicate */
Simon Kelleye0c0ad32014-01-16 22:42:07 +00001034 if (forward->blocking_query)
Simon Kelley0fc2f312014-01-08 10:26:58 +00001035 return;
Simon Kelley9a31b682015-12-15 10:20:39 +00001036
1037 /* Truncated answer can't be validated.
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001038 If this is an answer to a DNSSEC-generated query, we still
1039 need to get the client to retry over TCP, so return
1040 an answer with the TC bit set, even if the actual answer fits.
1041 */
Simon Kelley9a31b682015-12-15 10:20:39 +00001042 if (header->hb3 & HB3_TC)
1043 status = STAT_TRUNCATED;
1044
1045 while (1)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001046 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001047 /* As soon as anything returns BOGUS, we stop and unwind, to do otherwise
1048 would invite infinite loops, since the answers to DNSKEY and DS queries
1049 will not be cached, so they'll be repeated. */
1050 if (status != STAT_BOGUS && status != STAT_TRUNCATED && status != STAT_ABANDONED)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001051 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001052 if (forward->flags & FREC_DNSKEY_QUERY)
1053 status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
1054 else if (forward->flags & FREC_DS_QUERY)
1055 status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001056 else
Simon Kelley9a31b682015-12-15 10:20:39 +00001057 status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class,
Simon Kelley203ce0a2019-10-12 21:41:20 +01001058 !option_bool(OPT_DNSSEC_IGN_NS) && (forward->sentto->flags & SERV_DO_DNSSEC),
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001059 NULL, NULL, NULL);
Simon Kelley6b173352018-05-08 18:32:14 +01001060#ifdef HAVE_DUMPFILE
1061 if (status == STAT_BOGUS)
1062 dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_BOGUS : DUMP_BOGUS,
1063 header, (size_t)n, &serveraddr, NULL);
1064#endif
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001065 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001066
Simon Kelley9a31b682015-12-15 10:20:39 +00001067 /* Can't validate, as we're missing key data. Put this
1068 answer aside, whilst we get that. */
1069 if (status == STAT_NEED_DS || status == STAT_NEED_KEY)
Simon Kelley3a237152013-12-12 12:15:50 +00001070 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001071 struct frec *new, *orig;
Simon Kelley9d633042013-12-13 15:36:55 +00001072
Simon Kelley9a31b682015-12-15 10:20:39 +00001073 /* Free any saved query */
1074 if (forward->stash)
1075 blockdata_free(forward->stash);
1076
1077 /* Now save reply pending receipt of key data */
1078 if (!(forward->stash = blockdata_alloc((char *)header, n)))
Simon Kelley97e618a2015-01-07 21:55:43 +00001079 return;
Simon Kelley9a31b682015-12-15 10:20:39 +00001080 forward->stash_len = n;
Simon Kelleye0c0ad32014-01-16 22:42:07 +00001081
Simon Kelley9a31b682015-12-15 10:20:39 +00001082 /* Find the original query that started it all.... */
1083 for (orig = forward; orig->dependent; orig = orig->dependent);
Simon Kelley7fa836e2014-02-10 20:11:24 +00001084
Simon Kelley8caf3d72020-04-04 17:00:32 +01001085 /* Make sure we don't expire and free the orig frec during the
1086 allocation of a new one. */
1087 if (--orig->work_counter == 0 || !(new = get_new_frec(now, NULL, orig)))
Simon Kelley9a31b682015-12-15 10:20:39 +00001088 status = STAT_ABANDONED;
Simon Kelleye0c0ad32014-01-16 22:42:07 +00001089 else
Simon Kelley3a237152013-12-12 12:15:50 +00001090 {
Simon Kelleye1791f32018-10-06 23:23:23 +01001091 int querytype, fd, type = SERV_DO_DNSSEC;
Simon Kelley9a31b682015-12-15 10:20:39 +00001092 struct frec *next = new->next;
Simon Kelley92be34a2016-01-16 18:39:54 +00001093 char *domain;
1094
Simon Kelley9a31b682015-12-15 10:20:39 +00001095 *new = *forward; /* copy everything, then overwrite */
1096 new->next = next;
1097 new->blocking_query = NULL;
Simon Kelley92be34a2016-01-16 18:39:54 +00001098
1099 /* Find server to forward to. This will normally be the
1100 same as for the original query, but may be another if
1101 servers for domains are involved. */
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001102 if (search_servers(now, NULL, F_DNSSECOK, daemon->keyname, &type, &domain, NULL) == 0)
Simon Kelley92be34a2016-01-16 18:39:54 +00001103 {
Simon Kelley203ce0a2019-10-12 21:41:20 +01001104 struct server *start, *new_server = NULL;
1105 start = server = forward->sentto;
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001106
1107 while (1)
1108 {
1109 if (type == (start->flags & (SERV_TYPE | SERV_DO_DNSSEC)) &&
Simon Kelley1f60a182018-05-11 16:44:16 +01001110 ((type & SERV_TYPE) != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001111 !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
1112 {
1113 new_server = start;
1114 if (server == start)
1115 {
1116 new_server = NULL;
1117 break;
1118 }
1119 }
1120
1121 if (!(start = start->next))
1122 start = daemon->servers;
1123 if (start == server)
1124 break;
1125 }
1126
1127 if (new_server)
1128 server = new_server;
Simon Kelley92be34a2016-01-16 18:39:54 +00001129 }
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001130
Simon Kelley9a31b682015-12-15 10:20:39 +00001131 new->sentto = server;
1132 new->rfd4 = NULL;
Simon Kelley9a31b682015-12-15 10:20:39 +00001133 new->rfd6 = NULL;
Simon Kelley15b60dd2020-11-18 18:34:55 +00001134 new->frec_src.next = NULL;
Simon Kelleya0088e82018-05-10 21:43:14 +01001135 new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_HAS_EXTRADATA);
1136 new->forwardall = 0;
Simon Kelley9a31b682015-12-15 10:20:39 +00001137
1138 new->dependent = forward; /* to find query awaiting new one. */
1139 forward->blocking_query = new; /* for garbage cleaning */
1140 /* validate routines leave name of required record in daemon->keyname */
1141 if (status == STAT_NEED_KEY)
Simon Kelley7fa836e2014-02-10 20:11:24 +00001142 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001143 new->flags |= FREC_DNSKEY_QUERY;
Simon Kelleye1791f32018-10-06 23:23:23 +01001144 querytype = T_DNSKEY;
Simon Kelleyf1668d22014-01-08 16:53:27 +00001145 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001146 else
1147 {
1148 new->flags |= FREC_DS_QUERY;
Simon Kelleye1791f32018-10-06 23:23:23 +01001149 querytype = T_DS;
Simon Kelley9a31b682015-12-15 10:20:39 +00001150 }
Simon Kelleye1791f32018-10-06 23:23:23 +01001151
1152 nn = dnssec_generate_query(header,((unsigned char *) header) + server->edns_pktsz,
1153 daemon->keyname, forward->class, querytype, server->edns_pktsz);
1154
1155 if (server->addr.sa.sa_family == AF_INET)
Simon Kelleycc921df2019-01-02 22:48:59 +00001156 log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, daemon->keyname, (union all_addr *)&(server->addr.in.sin_addr),
Simon Kelleye1791f32018-10-06 23:23:23 +01001157 querystr("dnssec-query", querytype));
Simon Kelleye1791f32018-10-06 23:23:23 +01001158 else
Simon Kelleycc921df2019-01-02 22:48:59 +00001159 log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, daemon->keyname, (union all_addr *)&(server->addr.in6.sin6_addr),
Simon Kelleye1791f32018-10-06 23:23:23 +01001160 querystr("dnssec-query", querytype));
Simon Kelleye1791f32018-10-06 23:23:23 +01001161
Simon Kelley2d765862020-11-12 22:06:07 +00001162 memcpy(new->hash, hash_questions(header, nn, daemon->namebuff), HASH_SIZE);
Simon Kelley9a31b682015-12-15 10:20:39 +00001163 new->new_id = get_id();
1164 header->id = htons(new->new_id);
1165 /* Save query for retransmission */
1166 new->stash = blockdata_alloc((char *)header, nn);
1167 new->stash_len = nn;
1168
1169 /* Don't resend this. */
1170 daemon->srv_save = NULL;
1171
1172 if (server->sfd)
1173 fd = server->sfd->fd;
1174 else
1175 {
1176 fd = -1;
Simon Kelley9a31b682015-12-15 10:20:39 +00001177 if (server->addr.sa.sa_family == AF_INET6)
1178 {
1179 if (new->rfd6 || (new->rfd6 = allocate_rfd(AF_INET6)))
1180 fd = new->rfd6->fd;
1181 }
1182 else
Simon Kelley9a31b682015-12-15 10:20:39 +00001183 {
1184 if (new->rfd4 || (new->rfd4 = allocate_rfd(AF_INET)))
1185 fd = new->rfd4->fd;
1186 }
1187 }
1188
1189 if (fd != -1)
1190 {
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001191#ifdef HAVE_CONNTRACK
1192 /* Copy connection mark of incoming query to outgoing connection. */
1193 if (option_bool(OPT_CONNTRACK))
1194 {
1195 unsigned int mark;
1196 if (get_incoming_mark(&orig->source, &orig->dest, 0, &mark))
1197 setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
1198 }
1199#endif
Simon Kelley6b173352018-05-08 18:32:14 +01001200
1201#ifdef HAVE_DUMPFILE
1202 dump_packet(DUMP_SEC_QUERY, (void *)header, (size_t)nn, NULL, &server->addr);
1203#endif
1204
Simon Kelley9a31b682015-12-15 10:20:39 +00001205 while (retry_send(sendto(fd, (char *)header, nn, 0,
1206 &server->addr.sa,
1207 sa_len(&server->addr))));
1208 server->queries++;
1209 }
1210 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00001211 return;
Simon Kelley3a237152013-12-12 12:15:50 +00001212 }
Simon Kelley3a237152013-12-12 12:15:50 +00001213
Simon Kelley9a31b682015-12-15 10:20:39 +00001214 /* Validated original answer, all done. */
1215 if (!forward->dependent)
1216 break;
1217
Josh Soref730c6742017-02-06 16:14:04 +00001218 /* validated subsidiary query, (and cached result)
Simon Kelley9a31b682015-12-15 10:20:39 +00001219 pop that and return to the previous query we were working on. */
Simon Kelley0744ca62014-01-25 16:40:15 +00001220 struct frec *prev = forward->dependent;
1221 free_frec(forward);
1222 forward = prev;
1223 forward->blocking_query = NULL; /* already gone */
1224 blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
1225 n = forward->stash_len;
Simon Kelley3a237152013-12-12 12:15:50 +00001226 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001227
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001228
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001229 no_cache_dnssec = 0;
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001230
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001231 if (status == STAT_TRUNCATED)
Simon Kelley0744ca62014-01-25 16:40:15 +00001232 header->hb3 |= HB3_TC;
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001233 else
Simon Kelley7fa836e2014-02-10 20:11:24 +00001234 {
Simon Kelley554b5802015-04-17 22:50:20 +01001235 char *result, *domain = "result";
Simon Kelley7fa836e2014-02-10 20:11:24 +00001236
Simon Kelley9a31b682015-12-15 10:20:39 +00001237 if (status == STAT_ABANDONED)
Simon Kelley150162b2015-03-27 09:58:26 +00001238 {
1239 result = "ABANDONED";
1240 status = STAT_BOGUS;
1241 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00001242 else
1243 result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
1244
Simon Kelley554b5802015-04-17 22:50:20 +01001245 if (status == STAT_BOGUS && extract_request(header, n, daemon->namebuff, NULL))
1246 domain = daemon->namebuff;
Simon Kelley9a31b682015-12-15 10:20:39 +00001247
Simon Kelley07ed5852018-05-04 21:52:22 +01001248 log_query(F_SECSTAT, domain, NULL, result);
Simon Kelley7fa836e2014-02-10 20:11:24 +00001249 }
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001250
Simon Kelley3a237152013-12-12 12:15:50 +00001251 if (status == STAT_SECURE)
1252 cache_secure = 1;
Simon Kelley3a237152013-12-12 12:15:50 +00001253 else if (status == STAT_BOGUS)
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001254 {
1255 no_cache_dnssec = 1;
1256 bogusanswer = 1;
1257 }
Simon Kelley3a237152013-12-12 12:15:50 +00001258 }
Simon Kelley04db1482019-10-11 23:22:17 +01001259
Simon Kelley6b173352018-05-08 18:32:14 +01001260#endif
1261
Simon Kelley83349b82014-02-10 21:02:01 +00001262 /* restore CD bit to the value in the query */
1263 if (forward->flags & FREC_CHECKING_DISABLED)
1264 header->hb4 |= HB4_CD;
1265 else
1266 header->hb4 &= ~HB4_CD;
Simon Kelley25e63f12020-11-25 21:17:52 +00001267
1268 /* Never cache answers which are contingent on the source or MAC address EDSN0 option,
1269 since the cache is ignorant of such things. */
1270 if (forward->flags & FREC_NO_CACHE)
1271 no_cache_dnssec = 1;
Simon Kelley3a237152013-12-12 12:15:50 +00001272
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001273 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 +00001274 forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION,
Simon Kelley15b60dd2020-11-18 18:34:55 +00001275 forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->frec_src.source)))
Simon Kelley832af0b2007-01-21 20:01:28 +00001276 {
Simon Kelley15b60dd2020-11-18 18:34:55 +00001277 struct frec_src *src;
1278
1279 header->id = htons(forward->frec_src.orig_id);
Simon Kelley572b41e2011-02-18 18:11:18 +00001280 header->hb4 |= HB4_RA; /* recursion if available */
Simon Kelley5aa5f0f2015-12-21 17:20:35 +00001281#ifdef HAVE_DNSSEC
1282 /* 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 +01001283 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 +00001284 header, the answer is still bigger than 512, truncate it and mark it so. The client then retries with TCP. */
1285 if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER) && (nn > PACKETSZ))
1286 {
1287 header->ancount = htons(0);
1288 header->nscount = htons(0);
1289 header->arcount = htons(0);
1290 header->hb3 |= HB3_TC;
1291 nn = resize_packet(header, nn, NULL, 0);
1292 }
1293#endif
Simon Kelley6b173352018-05-08 18:32:14 +01001294
Simon Kelley15b60dd2020-11-18 18:34:55 +00001295 for (src = &forward->frec_src; src; src = src->next)
1296 {
1297 header->id = htons(src->orig_id);
1298
Simon Kelley6b173352018-05-08 18:32:14 +01001299#ifdef HAVE_DUMPFILE
Simon Kelley15b60dd2020-11-18 18:34:55 +00001300 dump_packet(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &src->source);
Simon Kelley6b173352018-05-08 18:32:14 +01001301#endif
Simon Kelley15b60dd2020-11-18 18:34:55 +00001302
1303 send_from(forward->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
1304 &src->source, &src->dest, src->iface);
1305
1306 if (option_bool(OPT_EXTRALOG) && src != &forward->frec_src)
1307 {
1308 daemon->log_display_id = src->log_id;
1309 daemon->log_source_addr = &src->source;
1310 log_query(F_UPSTREAM, "query", NULL, "duplicate");
1311 }
1312 }
Simon Kelley832af0b2007-01-21 20:01:28 +00001313 }
Simon Kelley15b60dd2020-11-18 18:34:55 +00001314
Simon Kelley1a6bca82008-07-11 11:11:42 +01001315 free_frec(forward); /* cancel */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001316 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001317}
Simon Kelley44a2a312004-03-10 20:04:35 +00001318
Simon Kelley1a6bca82008-07-11 11:11:42 +01001319
Simon Kelley5aabfc72007-08-29 11:24:47 +01001320void receive_query(struct listener *listen, time_t now)
Simon Kelley44a2a312004-03-10 20:04:35 +00001321{
Simon Kelley572b41e2011-02-18 18:11:18 +00001322 struct dns_header *header = (struct dns_header *)daemon->packet;
Simon Kelley44a2a312004-03-10 20:04:35 +00001323 union mysockaddr source_addr;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001324 unsigned char *pheader;
1325 unsigned short type, udp_size = PACKETSZ; /* default if no EDNS0 */
Simon Kelleycc921df2019-01-02 22:48:59 +00001326 union all_addr dst_addr;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001327 struct in_addr netmask, dst_addr_4;
Simon Kelleycdeda282006-03-16 20:16:06 +00001328 size_t m;
1329 ssize_t n;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001330 int if_index = 0, auth_dns = 0, do_bit = 0, have_pseudoheader = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001331#ifdef HAVE_AUTH
1332 int local_auth = 0;
1333#endif
Simon Kelley44a2a312004-03-10 20:04:35 +00001334 struct iovec iov[1];
1335 struct msghdr msg;
1336 struct cmsghdr *cmptr;
Simon Kelley44a2a312004-03-10 20:04:35 +00001337 union {
1338 struct cmsghdr align; /* this ensures alignment */
Simon Kelley44a2a312004-03-10 20:04:35 +00001339 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001340#if defined(HAVE_LINUX_NETWORK)
Simon Kelley44a2a312004-03-10 20:04:35 +00001341 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
Simon Kelley824af852008-02-12 20:43:05 +00001342#elif defined(IP_RECVDSTADDR) && defined(HAVE_SOLARIS_NETWORK)
1343 char control[CMSG_SPACE(sizeof(struct in_addr)) +
1344 CMSG_SPACE(sizeof(unsigned int))];
Simon Kelley44a2a312004-03-10 20:04:35 +00001345#elif defined(IP_RECVDSTADDR)
1346 char control[CMSG_SPACE(sizeof(struct in_addr)) +
1347 CMSG_SPACE(sizeof(struct sockaddr_dl))];
1348#endif
1349 } control_u;
Petr Menšík1c1b9252019-07-15 17:16:44 +02001350 int family = listen->addr.sa.sa_family;
Simon Kelley2329bef2013-12-03 13:41:16 +00001351 /* Can always get recvd interface for IPv6 */
Petr Menšík1c1b9252019-07-15 17:16:44 +02001352 int check_dst = !option_bool(OPT_NOWILD) || family == AF_INET6;
Simon Kelley2329bef2013-12-03 13:41:16 +00001353
Simon Kelleycdeda282006-03-16 20:16:06 +00001354 /* packet buffer overwritten */
1355 daemon->srv_save = NULL;
1356
Simon Kelleycc921df2019-01-02 22:48:59 +00001357 dst_addr_4.s_addr = dst_addr.addr4.s_addr = 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001358 netmask.s_addr = 0;
1359
Simon Kelley7e5664b2013-04-05 16:57:41 +01001360 if (option_bool(OPT_NOWILD) && listen->iface)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001361 {
Simon Kelley4f7b3042012-11-28 21:27:02 +00001362 auth_dns = listen->iface->dns_auth;
1363
Petr Menšík1c1b9252019-07-15 17:16:44 +02001364 if (family == AF_INET)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001365 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001366 dst_addr_4 = dst_addr.addr4 = listen->iface->addr.in.sin_addr;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001367 netmask = listen->iface->netmask;
1368 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001369 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00001370
Simon Kelley3be34542004-09-11 19:12:13 +01001371 iov[0].iov_base = daemon->packet;
1372 iov[0].iov_len = daemon->edns_pktsz;
Simon Kelley44a2a312004-03-10 20:04:35 +00001373
1374 msg.msg_control = control_u.control;
1375 msg.msg_controllen = sizeof(control_u);
1376 msg.msg_flags = 0;
1377 msg.msg_name = &source_addr;
1378 msg.msg_namelen = sizeof(source_addr);
1379 msg.msg_iov = iov;
1380 msg.msg_iovlen = 1;
1381
Simon Kelleyde379512004-06-22 20:23:33 +01001382 if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
Simon Kelley3be34542004-09-11 19:12:13 +01001383 return;
Simon Kelley44a2a312004-03-10 20:04:35 +00001384
Simon Kelley572b41e2011-02-18 18:11:18 +00001385 if (n < (int)sizeof(struct dns_header) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001386 (msg.msg_flags & MSG_TRUNC) ||
Simon Kelley572b41e2011-02-18 18:11:18 +00001387 (header->hb3 & HB3_QR))
Simon Kelley3be34542004-09-11 19:12:13 +01001388 return;
Simon Kelley63437ff2017-09-06 22:34:21 +01001389
1390 /* Clear buffer beyond request to avoid risk of
1391 information disclosure. */
1392 memset(daemon->packet + n, 0, daemon->edns_pktsz - n);
Simon Kelley44a2a312004-03-10 20:04:35 +00001393
Petr Menšík1c1b9252019-07-15 17:16:44 +02001394 source_addr.sa.sa_family = family;
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001395
Petr Menšík1c1b9252019-07-15 17:16:44 +02001396 if (family == AF_INET)
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001397 {
1398 /* Source-port == 0 is an error, we can't send back to that.
1399 http://www.ietf.org/mail-archive/web/dnsop/current/msg11441.html */
1400 if (source_addr.in.sin_port == 0)
1401 return;
1402 }
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001403 else
1404 {
1405 /* Source-port == 0 is an error, we can't send back to that. */
1406 if (source_addr.in6.sin6_port == 0)
1407 return;
1408 source_addr.in6.sin6_flowinfo = 0;
1409 }
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001410
Simon Kelleyc8a80482014-03-05 14:29:54 +00001411 /* We can be configured to only accept queries from at-most-one-hop-away addresses. */
1412 if (option_bool(OPT_LOCAL_SERVICE))
1413 {
1414 struct addrlist *addr;
Simon Kelleyee875042018-10-23 22:10:17 +01001415
Petr Menšík1c1b9252019-07-15 17:16:44 +02001416 if (family == AF_INET6)
Simon Kelleyc8a80482014-03-05 14:29:54 +00001417 {
1418 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1419 if ((addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001420 is_same_net6(&addr->addr.addr6, &source_addr.in6.sin6_addr, addr->prefixlen))
Simon Kelleyc8a80482014-03-05 14:29:54 +00001421 break;
1422 }
1423 else
Simon Kelleyc8a80482014-03-05 14:29:54 +00001424 {
1425 struct in_addr netmask;
1426 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1427 {
Richard Genoud15b1b7e2014-09-17 21:12:00 +01001428 netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
Simon Kelleyc8a80482014-03-05 14:29:54 +00001429 if (!(addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001430 is_same_net(addr->addr.addr4, source_addr.in.sin_addr, netmask))
Simon Kelleyc8a80482014-03-05 14:29:54 +00001431 break;
1432 }
1433 }
1434 if (!addr)
1435 {
Simon Kelley0c8584e2014-03-12 20:12:56 +00001436 static int warned = 0;
1437 if (!warned)
1438 {
1439 my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
1440 warned = 1;
1441 }
Simon Kelleyc8a80482014-03-05 14:29:54 +00001442 return;
1443 }
1444 }
1445
Simon Kelley2329bef2013-12-03 13:41:16 +00001446 if (check_dst)
Simon Kelley44a2a312004-03-10 20:04:35 +00001447 {
Simon Kelley8a911cc2004-03-16 18:35:52 +00001448 struct ifreq ifr;
1449
Simon Kelley26128d22004-11-14 16:43:54 +00001450 if (msg.msg_controllen < sizeof(struct cmsghdr))
1451 return;
1452
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001453#if defined(HAVE_LINUX_NETWORK)
Petr Menšík1c1b9252019-07-15 17:16:44 +02001454 if (family == AF_INET)
Simon Kelley26128d22004-11-14 16:43:54 +00001455 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelleyc72daea2012-01-05 21:33:27 +00001456 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
Simon Kelley26128d22004-11-14 16:43:54 +00001457 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001458 union {
1459 unsigned char *c;
1460 struct in_pktinfo *p;
1461 } p;
1462 p.c = CMSG_DATA(cmptr);
Simon Kelleycc921df2019-01-02 22:48:59 +00001463 dst_addr_4 = dst_addr.addr4 = p.p->ipi_spec_dst;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001464 if_index = p.p->ipi_ifindex;
Simon Kelley26128d22004-11-14 16:43:54 +00001465 }
1466#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
Petr Menšík1c1b9252019-07-15 17:16:44 +02001467 if (family == AF_INET)
Simon Kelley26128d22004-11-14 16:43:54 +00001468 {
1469 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001470 {
1471 union {
1472 unsigned char *c;
1473 unsigned int *i;
1474 struct in_addr *a;
1475#ifndef HAVE_SOLARIS_NETWORK
1476 struct sockaddr_dl *s;
Simon Kelley824af852008-02-12 20:43:05 +00001477#endif
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001478 } p;
1479 p.c = CMSG_DATA(cmptr);
1480 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
Simon Kelleycc921df2019-01-02 22:48:59 +00001481 dst_addr_4 = dst_addr.addr4 = *(p.a);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001482 else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
1483#ifdef HAVE_SOLARIS_NETWORK
1484 if_index = *(p.i);
1485#else
1486 if_index = p.s->sdl_index;
1487#endif
1488 }
Simon Kelley26128d22004-11-14 16:43:54 +00001489 }
1490#endif
1491
Petr Menšík1c1b9252019-07-15 17:16:44 +02001492 if (family == AF_INET6)
Simon Kelley26128d22004-11-14 16:43:54 +00001493 {
1494 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelleyc72daea2012-01-05 21:33:27 +00001495 if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
Simon Kelley26128d22004-11-14 16:43:54 +00001496 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001497 union {
1498 unsigned char *c;
1499 struct in6_pktinfo *p;
1500 } p;
1501 p.c = CMSG_DATA(cmptr);
1502
Simon Kelleycc921df2019-01-02 22:48:59 +00001503 dst_addr.addr6 = p.p->ipi6_addr;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001504 if_index = p.p->ipi6_ifindex;
Simon Kelley26128d22004-11-14 16:43:54 +00001505 }
1506 }
Simon Kelley26128d22004-11-14 16:43:54 +00001507
1508 /* enforce available interface configuration */
1509
Simon Kelleye25db1f2013-01-29 22:10:26 +00001510 if (!indextoname(listen->fd, if_index, ifr.ifr_name))
Simon Kelley832af0b2007-01-21 20:01:28 +00001511 return;
1512
Petr Menšík1c1b9252019-07-15 17:16:44 +02001513 if (!iface_check(family, &dst_addr, ifr.ifr_name, &auth_dns))
Simon Kelleye25db1f2013-01-29 22:10:26 +00001514 {
1515 if (!option_bool(OPT_CLEVERBIND))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001516 enumerate_interfaces(0);
Petr Menšík1c1b9252019-07-15 17:16:44 +02001517 if (!loopback_exception(listen->fd, family, &dst_addr, ifr.ifr_name) &&
1518 !label_exception(if_index, family, &dst_addr))
Simon Kelleye25db1f2013-01-29 22:10:26 +00001519 return;
1520 }
1521
Petr Menšík1c1b9252019-07-15 17:16:44 +02001522 if (family == AF_INET && option_bool(OPT_LOCALISE))
Simon Kelley552af8b2012-02-29 20:10:31 +00001523 {
1524 struct irec *iface;
1525
Josh Soref730c6742017-02-06 16:14:04 +00001526 /* get the netmask of the interface which has the address we were sent to.
klemens43517fc2017-02-19 15:53:37 +00001527 This is no necessarily the interface we arrived on. */
Simon Kelley552af8b2012-02-29 20:10:31 +00001528
1529 for (iface = daemon->interfaces; iface; iface = iface->next)
1530 if (iface->addr.sa.sa_family == AF_INET &&
1531 iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
1532 break;
1533
1534 /* interface may be new */
Simon Kelleye25db1f2013-01-29 22:10:26 +00001535 if (!iface && !option_bool(OPT_CLEVERBIND))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001536 enumerate_interfaces(0);
Simon Kelley552af8b2012-02-29 20:10:31 +00001537
1538 for (iface = daemon->interfaces; iface; iface = iface->next)
1539 if (iface->addr.sa.sa_family == AF_INET &&
1540 iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
1541 break;
1542
1543 /* If we failed, abandon localisation */
1544 if (iface)
1545 netmask = iface->netmask;
1546 else
1547 dst_addr_4.s_addr = 0;
1548 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001549 }
Simon Kelley25cf5e32015-01-09 15:53:03 +00001550
1551 /* log_query gets called indirectly all over the place, so
1552 pass these in global variables - sorry. */
1553 daemon->log_display_id = ++daemon->log_id;
1554 daemon->log_source_addr = &source_addr;
Simon Kelley6b173352018-05-08 18:32:14 +01001555
1556#ifdef HAVE_DUMPFILE
1557 dump_packet(DUMP_QUERY, daemon->packet, (size_t)n, &source_addr, NULL);
1558#endif
1559
Simon Kelleycdeda282006-03-16 20:16:06 +00001560 if (extract_request(header, (size_t)n, daemon->namebuff, &type))
Simon Kelley44a2a312004-03-10 20:04:35 +00001561 {
Simon Kelleyb485ed92013-10-18 22:00:39 +01001562#ifdef HAVE_AUTH
1563 struct auth_zone *zone;
1564#endif
Simon Kelley610e7822014-02-06 14:45:17 +00001565 char *types = querystr(auth_dns ? "auth" : "query", type);
1566
Petr Menšík1c1b9252019-07-15 17:16:44 +02001567 if (family == AF_INET)
Simon Kelley3be34542004-09-11 19:12:13 +01001568 log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
Simon Kelleycc921df2019-01-02 22:48:59 +00001569 (union all_addr *)&source_addr.in.sin_addr, types);
Simon Kelley44a2a312004-03-10 20:04:35 +00001570 else
Simon Kelley3be34542004-09-11 19:12:13 +01001571 log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
Simon Kelleycc921df2019-01-02 22:48:59 +00001572 (union all_addr *)&source_addr.in6.sin6_addr, types);
Simon Kelley44a2a312004-03-10 20:04:35 +00001573
Simon Kelley4820dce2012-12-18 18:30:30 +00001574#ifdef HAVE_AUTH
Simon Kelleyb485ed92013-10-18 22:00:39 +01001575 /* find queries for zones we're authoritative for, and answer them directly */
Simon Kelley3a3965a2015-08-09 17:45:06 +01001576 if (!auth_dns && !option_bool(OPT_LOCALISE))
Simon Kelley6008bdb2013-10-21 21:47:03 +01001577 for (zone = daemon->auth_zones; zone; zone = zone->next)
1578 if (in_zone(zone, daemon->namebuff, NULL))
1579 {
1580 auth_dns = 1;
1581 local_auth = 1;
1582 break;
1583 }
Simon Kelleyb485ed92013-10-18 22:00:39 +01001584#endif
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01001585
1586#ifdef HAVE_LOOP
1587 /* Check for forwarding loop */
1588 if (detect_loop(daemon->namebuff, type))
1589 return;
1590#endif
Simon Kelleyb485ed92013-10-18 22:00:39 +01001591 }
1592
Simon Kelley5bb88f02015-12-21 16:23:47 +00001593 if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL, NULL))
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001594 {
1595 unsigned short flags;
1596
1597 have_pseudoheader = 1;
1598 GETSHORT(udp_size, pheader);
1599 pheader += 2; /* ext_rcode */
1600 GETSHORT(flags, pheader);
1601
1602 if (flags & 0x8000)
1603 do_bit = 1;/* do bit */
1604
1605 /* If the client provides an EDNS0 UDP size, use that to limit our reply.
1606 (bounded by the maximum configured). If no EDNS0, then it
1607 defaults to 512 */
1608 if (udp_size > daemon->edns_pktsz)
1609 udp_size = daemon->edns_pktsz;
Simon Kelleya3303e12017-09-07 20:45:00 +01001610 else if (udp_size < PACKETSZ)
1611 udp_size = PACKETSZ; /* Sanity check - can't reduce below default. RFC 6891 6.2.3 */
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001612 }
1613
Simon Kelleyb485ed92013-10-18 22:00:39 +01001614#ifdef HAVE_AUTH
Simon Kelley4f7b3042012-11-28 21:27:02 +00001615 if (auth_dns)
Simon Kelley824af852008-02-12 20:43:05 +00001616 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001617 m = answer_auth(header, ((char *) header) + udp_size, (size_t)n, now, &source_addr,
1618 local_auth, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001619 if (m >= 1)
Simon Kelleyb485ed92013-10-18 22:00:39 +01001620 {
1621 send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
1622 (char *)header, m, &source_addr, &dst_addr, if_index);
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001623 daemon->metrics[METRIC_DNS_AUTH_ANSWERED]++;
Simon Kelleyb485ed92013-10-18 22:00:39 +01001624 }
Simon Kelley824af852008-02-12 20:43:05 +00001625 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001626 else
Simon Kelley4820dce2012-12-18 18:30:30 +00001627#endif
Simon Kelley4f7b3042012-11-28 21:27:02 +00001628 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001629 int ad_reqd = do_bit;
1630 /* RFC 6840 5.7 */
1631 if (header->hb4 & HB4_AD)
1632 ad_reqd = 1;
1633
1634 m = answer_request(header, ((char *) header) + udp_size, (size_t)n,
1635 dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001636
1637 if (m >= 1)
1638 {
1639 send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
1640 (char *)header, m, &source_addr, &dst_addr, if_index);
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001641 daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001642 }
1643 else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
Simon Kelley613ad152014-02-25 23:02:28 +00001644 header, (size_t)n, now, NULL, ad_reqd, do_bit))
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001645 daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]++;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001646 else
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001647 daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001648 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001649}
1650
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001651#ifdef HAVE_DNSSEC
Josh Soref730c6742017-02-06 16:14:04 +00001652/* Recurse up the key hierarchy */
Simon Kelley7fa836e2014-02-10 20:11:24 +00001653static int tcp_key_recurse(time_t now, int status, struct dns_header *header, size_t n,
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001654 int class, char *name, char *keyname, struct server *server,
1655 int have_mark, unsigned int mark, int *keycount)
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001656{
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001657 int new_status;
Simon Kelley9a31b682015-12-15 10:20:39 +00001658 unsigned char *packet = NULL;
Simon Kelley9a31b682015-12-15 10:20:39 +00001659 unsigned char *payload = NULL;
1660 struct dns_header *new_header = NULL;
1661 u16 *length = NULL;
Simon Kelley361dfe52017-02-10 21:12:30 +00001662
Simon Kelley9a31b682015-12-15 10:20:39 +00001663 while (1)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001664 {
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001665 int type = SERV_DO_DNSSEC;
1666 char *domain;
1667 size_t m;
1668 unsigned char c1, c2;
Simon Kelley361dfe52017-02-10 21:12:30 +00001669 struct server *firstsendto = NULL;
1670
Simon Kelley9a31b682015-12-15 10:20:39 +00001671 /* limit the amount of work we do, to avoid cycling forever on loops in the DNS */
1672 if (--(*keycount) == 0)
1673 new_status = STAT_ABANDONED;
1674 else if (status == STAT_NEED_KEY)
1675 new_status = dnssec_validate_by_ds(now, header, n, name, keyname, class);
1676 else if (status == STAT_NEED_DS)
1677 new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
1678 else
James Bottomleye33b4872017-03-17 21:44:10 +00001679 new_status = dnssec_validate_reply(now, header, n, name, keyname, &class,
Simon Kelleya6918532018-04-15 16:20:52 +01001680 !option_bool(OPT_DNSSEC_IGN_NS) && (server->flags & SERV_DO_DNSSEC),
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001681 NULL, NULL, NULL);
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001682
Simon Kelley9a31b682015-12-15 10:20:39 +00001683 if (new_status != STAT_NEED_DS && new_status != STAT_NEED_KEY)
1684 break;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001685
Simon Kelley9a31b682015-12-15 10:20:39 +00001686 /* Can't validate because we need a key/DS whose name now in keyname.
1687 Make query for same, and recurse to validate */
Simon Kelley7fa836e2014-02-10 20:11:24 +00001688 if (!packet)
Simon Kelley9a31b682015-12-15 10:20:39 +00001689 {
1690 packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
1691 payload = &packet[2];
1692 new_header = (struct dns_header *)payload;
1693 length = (u16 *)packet;
1694 }
1695
1696 if (!packet)
1697 {
1698 new_status = STAT_ABANDONED;
1699 break;
1700 }
Simon Kelleye1791f32018-10-06 23:23:23 +01001701
Simon Kelley33702ab2015-12-28 23:17:15 +00001702 m = dnssec_generate_query(new_header, ((unsigned char *) new_header) + 65536, keyname, class,
Simon Kelleye1791f32018-10-06 23:23:23 +01001703 new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS, server->edns_pktsz);
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001704
Simon Kelley7fa836e2014-02-10 20:11:24 +00001705 *length = htons(m);
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001706
1707 /* Find server to forward to. This will normally be the
1708 same as for the original query, but may be another if
1709 servers for domains are involved. */
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001710 if (search_servers(now, NULL, F_DNSSECOK, keyname, &type, &domain, NULL) != 0)
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001711 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001712 new_status = STAT_ABANDONED;
1713 break;
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001714 }
Simon Kelley361dfe52017-02-10 21:12:30 +00001715
Simon Kelley361dfe52017-02-10 21:12:30 +00001716 while (1)
1717 {
Simon Kelley608aa9f2019-03-10 22:44:15 +00001718 int data_sent = 0;
1719
Simon Kelley361dfe52017-02-10 21:12:30 +00001720 if (!firstsendto)
1721 firstsendto = server;
1722 else
1723 {
1724 if (!(server = server->next))
1725 server = daemon->servers;
1726 if (server == firstsendto)
1727 {
1728 /* can't find server to accept our query. */
1729 new_status = STAT_ABANDONED;
1730 break;
1731 }
1732 }
1733
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001734 if (type != (server->flags & (SERV_TYPE | SERV_DO_DNSSEC)) ||
Simon Kelley361dfe52017-02-10 21:12:30 +00001735 (type == SERV_HAS_DOMAIN && !hostname_isequal(domain, server->domain)) ||
1736 (server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
1737 continue;
Simon Kelleye1791f32018-10-06 23:23:23 +01001738
1739 retry:
1740 /* may need to make new connection. */
1741 if (server->tcpfd == -1)
1742 {
1743 if ((server->tcpfd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
1744 continue; /* No good, next server */
1745
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001746#ifdef HAVE_CONNTRACK
Simon Kelleye1791f32018-10-06 23:23:23 +01001747 /* Copy connection mark of incoming query to outgoing connection. */
1748 if (have_mark)
1749 setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001750#endif
Simon Kelleye1791f32018-10-06 23:23:23 +01001751
Simon Kelley608aa9f2019-03-10 22:44:15 +00001752 if (!local_bind(server->tcpfd, &server->source_addr, server->interface, 0, 1))
1753 {
1754 close(server->tcpfd);
1755 server->tcpfd = -1;
1756 continue; /* No good, next server */
1757 }
1758
1759#ifdef MSG_FASTOPEN
1760 while(retry_send(sendto(server->tcpfd, packet, m + sizeof(u16),
1761 MSG_FASTOPEN, &server->addr.sa, sa_len(&server->addr))));
1762
1763 if (errno == 0)
1764 data_sent = 1;
1765#endif
1766
1767 if (!data_sent && connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) == -1)
Simon Kelleye1791f32018-10-06 23:23:23 +01001768 {
1769 close(server->tcpfd);
1770 server->tcpfd = -1;
1771 continue; /* No good, next server */
1772 }
1773
1774 server->flags &= ~SERV_GOT_TCP;
1775 }
Simon Kelley361dfe52017-02-10 21:12:30 +00001776
Simon Kelley608aa9f2019-03-10 22:44:15 +00001777 if ((!data_sent && !read_write(server->tcpfd, packet, m + sizeof(u16), 0)) ||
Simon Kelley361dfe52017-02-10 21:12:30 +00001778 !read_write(server->tcpfd, &c1, 1, 1) ||
1779 !read_write(server->tcpfd, &c2, 1, 1) ||
1780 !read_write(server->tcpfd, payload, (c1 << 8) | c2, 1))
1781 {
1782 close(server->tcpfd);
1783 server->tcpfd = -1;
1784 /* We get data then EOF, reopen connection to same server,
1785 else try next. This avoids DoS from a server which accepts
1786 connections and then closes them. */
1787 if (server->flags & SERV_GOT_TCP)
1788 goto retry;
1789 else
1790 continue;
1791 }
Simon Kelleye1791f32018-10-06 23:23:23 +01001792
1793
1794 if (server->addr.sa.sa_family == AF_INET)
Simon Kelleycc921df2019-01-02 22:48:59 +00001795 log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, keyname, (union all_addr *)&(server->addr.in.sin_addr),
Simon Kelleye1791f32018-10-06 23:23:23 +01001796 querystr("dnssec-query", new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS));
Simon Kelleye1791f32018-10-06 23:23:23 +01001797 else
Simon Kelleycc921df2019-01-02 22:48:59 +00001798 log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, keyname, (union all_addr *)&(server->addr.in6.sin6_addr),
Simon Kelleye1791f32018-10-06 23:23:23 +01001799 querystr("dnssec-query", new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS));
Simon Kelley361dfe52017-02-10 21:12:30 +00001800
1801 server->flags |= SERV_GOT_TCP;
1802
1803 m = (c1 << 8) | c2;
1804 new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, have_mark, mark, keycount);
1805 break;
1806 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001807
1808 if (new_status != STAT_OK)
1809 break;
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001810 }
Simon Kelley361dfe52017-02-10 21:12:30 +00001811
Simon Kelley9a31b682015-12-15 10:20:39 +00001812 if (packet)
1813 free(packet);
1814
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001815 return new_status;
1816}
1817#endif
1818
1819
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001820/* The daemon forks before calling this: it should deal with one connection,
Josh Soref730c6742017-02-06 16:14:04 +00001821 blocking as necessary, and then return. Note, need to be a bit careful
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001822 about resources for debug mode, when the fork is suppressed: that's
1823 done by the caller. */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001824unsigned char *tcp_request(int confd, time_t now,
Simon Kelley4f7b3042012-11-28 21:27:02 +00001825 union mysockaddr *local_addr, struct in_addr netmask, int auth_dns)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001826{
Simon Kelley28866e92011-02-14 20:19:14 +00001827 size_t size = 0;
1828 int norebind = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001829#ifdef HAVE_AUTH
Simon Kelley19b16892013-10-20 10:19:39 +01001830 int local_auth = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001831#endif
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001832 int checking_disabled, do_bit, added_pheader = 0, have_pseudoheader = 0;
Simon Kelley25e63f12020-11-25 21:17:52 +00001833 int check_subnet, cacheable, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
Simon Kelleycdeda282006-03-16 20:16:06 +00001834 size_t m;
Simon Kelleyee86ce62012-12-07 11:54:46 +00001835 unsigned short qtype;
1836 unsigned int gotname;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001837 unsigned char c1, c2;
Simon Kelley4b5ea122013-04-22 10:18:26 +01001838 /* Max TCP packet + slop + size */
1839 unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
1840 unsigned char *payload = &packet[2];
1841 /* largest field in header is 16-bits, so this is still sufficiently aligned */
1842 struct dns_header *header = (struct dns_header *)payload;
1843 u16 *length = (u16 *)packet;
Simon Kelley3be34542004-09-11 19:12:13 +01001844 struct server *last_server;
Simon Kelley7de060b2011-08-26 17:24:52 +01001845 struct in_addr dst_addr_4;
1846 union mysockaddr peer_addr;
1847 socklen_t peer_len = sizeof(union mysockaddr);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001848 int query_count = 0;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001849 unsigned char *pheader;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001850 unsigned int mark = 0;
1851 int have_mark = 0;
Simon Kelley25cf5e32015-01-09 15:53:03 +00001852
Simon Kelleyd05dd582016-01-19 21:23:30 +00001853 (void)mark;
1854 (void)have_mark;
1855
Simon Kelley7de060b2011-08-26 17:24:52 +01001856 if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
1857 return packet;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001858
1859#ifdef HAVE_CONNTRACK
1860 /* Get connection mark of incoming query to set on outgoing connections. */
1861 if (option_bool(OPT_CONNTRACK))
1862 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001863 union all_addr local;
Simon Kelleyee875042018-10-23 22:10:17 +01001864
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001865 if (local_addr->sa.sa_family == AF_INET6)
Simon Kelleycc921df2019-01-02 22:48:59 +00001866 local.addr6 = local_addr->in6.sin6_addr;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001867 else
Simon Kelleycc921df2019-01-02 22:48:59 +00001868 local.addr4 = local_addr->in.sin_addr;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001869
1870 have_mark = get_incoming_mark(&peer_addr, &local, 1, &mark);
1871 }
1872#endif
1873
Simon Kelleyc8a80482014-03-05 14:29:54 +00001874 /* We can be configured to only accept queries from at-most-one-hop-away addresses. */
1875 if (option_bool(OPT_LOCAL_SERVICE))
1876 {
1877 struct addrlist *addr;
Simon Kelleyee875042018-10-23 22:10:17 +01001878
Simon Kelleyc8a80482014-03-05 14:29:54 +00001879 if (peer_addr.sa.sa_family == AF_INET6)
1880 {
1881 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1882 if ((addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001883 is_same_net6(&addr->addr.addr6, &peer_addr.in6.sin6_addr, addr->prefixlen))
Simon Kelleyc8a80482014-03-05 14:29:54 +00001884 break;
1885 }
1886 else
Simon Kelleyc8a80482014-03-05 14:29:54 +00001887 {
1888 struct in_addr netmask;
1889 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1890 {
Richard Genoud15b1b7e2014-09-17 21:12:00 +01001891 netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
Simon Kelleyc8a80482014-03-05 14:29:54 +00001892 if (!(addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001893 is_same_net(addr->addr.addr4, peer_addr.in.sin_addr, netmask))
Simon Kelleyc8a80482014-03-05 14:29:54 +00001894 break;
1895 }
1896 }
1897 if (!addr)
1898 {
1899 my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
1900 return packet;
1901 }
1902 }
Simon Kelley7de060b2011-08-26 17:24:52 +01001903
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001904 while (1)
1905 {
Simon Kelley25cf5e32015-01-09 15:53:03 +00001906 if (query_count == TCP_MAX_QUERIES ||
1907 !packet ||
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001908 !read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
1909 !(size = c1 << 8 | c2) ||
Simon Kelley4b5ea122013-04-22 10:18:26 +01001910 !read_write(confd, payload, size, 1))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001911 return packet;
1912
Simon Kelley572b41e2011-02-18 18:11:18 +00001913 if (size < (int)sizeof(struct dns_header))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001914 continue;
Simon Kelley63437ff2017-09-06 22:34:21 +01001915
1916 /* Clear buffer beyond request to avoid risk of
1917 information disclosure. */
1918 memset(payload + size, 0, 65536 - size);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001919
Simon Kelley25cf5e32015-01-09 15:53:03 +00001920 query_count++;
1921
1922 /* log_query gets called indirectly all over the place, so
1923 pass these in global variables - sorry. */
1924 daemon->log_display_id = ++daemon->log_id;
1925 daemon->log_source_addr = &peer_addr;
1926
Simon Kelley28866e92011-02-14 20:19:14 +00001927 /* save state of "cd" flag in query */
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001928 if ((checking_disabled = header->hb4 & HB4_CD))
1929 no_cache_dnssec = 1;
Simon Kelley28866e92011-02-14 20:19:14 +00001930
Simon Kelley3be34542004-09-11 19:12:13 +01001931 if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001932 {
Simon Kelleyb485ed92013-10-18 22:00:39 +01001933#ifdef HAVE_AUTH
1934 struct auth_zone *zone;
1935#endif
Simon Kelley610e7822014-02-06 14:45:17 +00001936 char *types = querystr(auth_dns ? "auth" : "query", qtype);
Simon Kelley7de060b2011-08-26 17:24:52 +01001937
1938 if (peer_addr.sa.sa_family == AF_INET)
1939 log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
Simon Kelleycc921df2019-01-02 22:48:59 +00001940 (union all_addr *)&peer_addr.in.sin_addr, types);
Simon Kelley7de060b2011-08-26 17:24:52 +01001941 else
1942 log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
Simon Kelleycc921df2019-01-02 22:48:59 +00001943 (union all_addr *)&peer_addr.in6.sin6_addr, types);
Simon Kelleyb485ed92013-10-18 22:00:39 +01001944
1945#ifdef HAVE_AUTH
1946 /* find queries for zones we're authoritative for, and answer them directly */
Simon Kelley3a3965a2015-08-09 17:45:06 +01001947 if (!auth_dns && !option_bool(OPT_LOCALISE))
Simon Kelley6008bdb2013-10-21 21:47:03 +01001948 for (zone = daemon->auth_zones; zone; zone = zone->next)
1949 if (in_zone(zone, daemon->namebuff, NULL))
1950 {
1951 auth_dns = 1;
1952 local_auth = 1;
1953 break;
1954 }
Simon Kelleyb485ed92013-10-18 22:00:39 +01001955#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001956 }
1957
Simon Kelley7de060b2011-08-26 17:24:52 +01001958 if (local_addr->sa.sa_family == AF_INET)
1959 dst_addr_4 = local_addr->in.sin_addr;
1960 else
1961 dst_addr_4.s_addr = 0;
1962
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001963 do_bit = 0;
1964
Simon Kelley5bb88f02015-12-21 16:23:47 +00001965 if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL, NULL))
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001966 {
1967 unsigned short flags;
1968
1969 have_pseudoheader = 1;
1970 pheader += 4; /* udp_size, ext_rcode */
1971 GETSHORT(flags, pheader);
1972
1973 if (flags & 0x8000)
Simon Kelley5bb88f02015-12-21 16:23:47 +00001974 do_bit = 1; /* do bit */
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001975 }
1976
Simon Kelley4820dce2012-12-18 18:30:30 +00001977#ifdef HAVE_AUTH
Simon Kelley4f7b3042012-11-28 21:27:02 +00001978 if (auth_dns)
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001979 m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr,
1980 local_auth, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001981 else
Simon Kelley4820dce2012-12-18 18:30:30 +00001982#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001983 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001984 int ad_reqd = do_bit;
1985 /* RFC 6840 5.7 */
1986 if (header->hb4 & HB4_AD)
1987 ad_reqd = 1;
1988
1989 /* m > 0 if answered from cache */
1990 m = answer_request(header, ((char *) header) + 65536, (size_t)size,
1991 dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001992
Simon Kelley4f7b3042012-11-28 21:27:02 +00001993 /* Do this by steam now we're not in the select() loop */
Simon Kelleyb842bc92015-07-12 21:09:11 +01001994 check_log_writer(1);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001995
1996 if (m == 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001997 {
Simon Kelley4f7b3042012-11-28 21:27:02 +00001998 unsigned int flags = 0;
Simon Kelleycc921df2019-01-02 22:48:59 +00001999 union all_addr *addrp = NULL;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00002000 int type = SERV_DO_DNSSEC;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002001 char *domain = NULL;
Simon Kelley6fd5d792017-10-13 22:26:40 +01002002 unsigned char *oph = find_pseudoheader(header, size, NULL, NULL, NULL, NULL);
Simon Kelleyed4c0762013-10-08 20:46:34 +01002003
Simon Kelley25e63f12020-11-25 21:17:52 +00002004 size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet, &cacheable);
Simon Kelley6fd5d792017-10-13 22:26:40 +01002005
Simon Kelley4f7b3042012-11-28 21:27:02 +00002006 if (gotname)
2007 flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
Simon Kelley6fd5d792017-10-13 22:26:40 +01002008
2009#ifdef HAVE_DNSSEC
2010 if (option_bool(OPT_DNSSEC_VALID) && (type & SERV_DO_DNSSEC))
2011 {
2012 size = add_do_bit(header, size, ((unsigned char *) header) + 65536);
2013
2014 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
2015 this allows it to select auth servers when one is returning bad data. */
2016 if (option_bool(OPT_DNSSEC_DEBUG))
2017 header->hb4 |= HB4_CD;
2018 }
2019#endif
2020
2021 /* Check if we added a pheader on forwarding - may need to
2022 strip it from the reply. */
2023 if (!oph && find_pseudoheader(header, size, NULL, NULL, NULL, NULL))
2024 added_pheader = 1;
2025
Simon Kelley367341f2016-01-12 15:58:23 +00002026 type &= ~SERV_DO_DNSSEC;
Simon Kelley367341f2016-01-12 15:58:23 +00002027
Simon Kelley4f7b3042012-11-28 21:27:02 +00002028 if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server)
2029 last_server = daemon->servers;
2030 else
2031 last_server = daemon->last_server;
2032
2033 if (!flags && last_server)
2034 {
2035 struct server *firstsendto = NULL;
Simon Kelley2d765862020-11-12 22:06:07 +00002036 unsigned char hash[HASH_SIZE];
2037 memcpy(hash, hash_questions(header, (unsigned int)size, daemon->namebuff), HASH_SIZE);
2038
Simon Kelley4f7b3042012-11-28 21:27:02 +00002039 /* Loop round available servers until we succeed in connecting to one.
Josh Soref730c6742017-02-06 16:14:04 +00002040 Note that this code subtly ensures that consecutive queries on this connection
Simon Kelley4f7b3042012-11-28 21:27:02 +00002041 which can go to the same server, do so. */
2042 while (1)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002043 {
Simon Kelley608aa9f2019-03-10 22:44:15 +00002044 int data_sent = 0;
2045
Simon Kelley4f7b3042012-11-28 21:27:02 +00002046 if (!firstsendto)
2047 firstsendto = last_server;
2048 else
2049 {
2050 if (!(last_server = last_server->next))
2051 last_server = daemon->servers;
2052
2053 if (last_server == firstsendto)
2054 break;
2055 }
2056
2057 /* server for wrong domain */
2058 if (type != (last_server->flags & SERV_TYPE) ||
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002059 (type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)) ||
2060 (last_server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
Simon Kelley7de060b2011-08-26 17:24:52 +01002061 continue;
Simon Kelley361dfe52017-02-10 21:12:30 +00002062
2063 retry:
Simon Kelley608aa9f2019-03-10 22:44:15 +00002064 *length = htons(size);
2065
Simon Kelley4f7b3042012-11-28 21:27:02 +00002066 if (last_server->tcpfd == -1)
2067 {
2068 if ((last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
2069 continue;
2070
Karl Vogele9828b62014-10-03 21:45:15 +01002071#ifdef HAVE_CONNTRACK
2072 /* Copy connection mark of incoming query to outgoing connection. */
Simon Kelleyf344dbc2016-01-18 18:04:17 +00002073 if (have_mark)
2074 setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
Simon Kelley608aa9f2019-03-10 22:44:15 +00002075#endif
Karl Vogele9828b62014-10-03 21:45:15 +01002076
Simon Kelley608aa9f2019-03-10 22:44:15 +00002077 if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 0, 1)))
2078 {
2079 close(last_server->tcpfd);
2080 last_server->tcpfd = -1;
2081 continue;
2082 }
2083
2084#ifdef MSG_FASTOPEN
2085 while(retry_send(sendto(last_server->tcpfd, packet, size + sizeof(u16),
2086 MSG_FASTOPEN, &last_server->addr.sa, sa_len(&last_server->addr))));
2087
2088 if (errno == 0)
2089 data_sent = 1;
2090#endif
2091
2092 if (!data_sent && connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1)
Simon Kelley4f7b3042012-11-28 21:27:02 +00002093 {
2094 close(last_server->tcpfd);
2095 last_server->tcpfd = -1;
2096 continue;
2097 }
2098
Simon Kelley361dfe52017-02-10 21:12:30 +00002099 last_server->flags &= ~SERV_GOT_TCP;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002100 }
2101
Simon Kelley1fc02682014-04-29 12:30:18 +01002102 /* get query name again for logging - may have been overwritten */
2103 if (!(gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
2104 strcpy(daemon->namebuff, "query");
Simon Kelley4f7b3042012-11-28 21:27:02 +00002105
Simon Kelley608aa9f2019-03-10 22:44:15 +00002106 if ((!data_sent && !read_write(last_server->tcpfd, packet, size + sizeof(u16), 0)) ||
Simon Kelley4f7b3042012-11-28 21:27:02 +00002107 !read_write(last_server->tcpfd, &c1, 1, 1) ||
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002108 !read_write(last_server->tcpfd, &c2, 1, 1) ||
2109 !read_write(last_server->tcpfd, payload, (c1 << 8) | c2, 1))
Simon Kelley7de060b2011-08-26 17:24:52 +01002110 {
2111 close(last_server->tcpfd);
2112 last_server->tcpfd = -1;
Simon Kelley361dfe52017-02-10 21:12:30 +00002113 /* We get data then EOF, reopen connection to same server,
2114 else try next. This avoids DoS from a server which accepts
2115 connections and then closes them. */
2116 if (last_server->flags & SERV_GOT_TCP)
2117 goto retry;
2118 else
2119 continue;
2120 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00002121
Simon Kelley361dfe52017-02-10 21:12:30 +00002122 last_server->flags |= SERV_GOT_TCP;
2123
Simon Kelley4f7b3042012-11-28 21:27:02 +00002124 m = (c1 << 8) | c2;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002125
Simon Kelley4f7b3042012-11-28 21:27:02 +00002126 if (last_server->addr.sa.sa_family == AF_INET)
2127 log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
Simon Kelleycc921df2019-01-02 22:48:59 +00002128 (union all_addr *)&last_server->addr.in.sin_addr, NULL);
Simon Kelley4f7b3042012-11-28 21:27:02 +00002129 else
2130 log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
Simon Kelleycc921df2019-01-02 22:48:59 +00002131 (union all_addr *)&last_server->addr.in6.sin6_addr, NULL);
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002132
2133#ifdef HAVE_DNSSEC
Simon Kelley367341f2016-01-12 15:58:23 +00002134 if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled && (last_server->flags & SERV_DO_DNSSEC))
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002135 {
Simon Kelley7fa836e2014-02-10 20:11:24 +00002136 int keycount = DNSSEC_WORK; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
Simon Kelleyf344dbc2016-01-18 18:04:17 +00002137 int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname,
2138 last_server, have_mark, mark, &keycount);
Simon Kelley554b5802015-04-17 22:50:20 +01002139 char *result, *domain = "result";
Simon Kelleyfe3992f2015-04-03 21:25:05 +01002140
Simon Kelley9a31b682015-12-15 10:20:39 +00002141 if (status == STAT_ABANDONED)
Simon Kelley150162b2015-03-27 09:58:26 +00002142 {
2143 result = "ABANDONED";
2144 status = STAT_BOGUS;
2145 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00002146 else
2147 result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
Simon Kelleye66b4df2015-04-28 20:45:57 +01002148
2149 if (status == STAT_BOGUS && extract_request(header, m, daemon->namebuff, NULL))
2150 domain = daemon->namebuff;
Simon Kelley554b5802015-04-17 22:50:20 +01002151
Simon Kelley07ed5852018-05-04 21:52:22 +01002152 log_query(F_SECSTAT, domain, NULL, result);
Simon Kelley7fa836e2014-02-10 20:11:24 +00002153
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002154 if (status == STAT_BOGUS)
Simon Kelleyfe3992f2015-04-03 21:25:05 +01002155 {
2156 no_cache_dnssec = 1;
2157 bogusanswer = 1;
2158 }
2159
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002160 if (status == STAT_SECURE)
2161 cache_secure = 1;
2162 }
2163#endif
2164
2165 /* restore CD bit to the value in the query */
2166 if (checking_disabled)
2167 header->hb4 |= HB4_CD;
2168 else
2169 header->hb4 &= ~HB4_CD;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002170
2171 /* There's no point in updating the cache, since this process will exit and
2172 lose the information after a few queries. We make this call for the alias and
2173 bogus-nxdomain side-effects. */
2174 /* If the crc of the question section doesn't match the crc we sent, then
2175 someone might be attempting to insert bogus values into the cache by
2176 sending replies containing questions and bogus answers. */
Simon Kelley2d765862020-11-12 22:06:07 +00002177 if (memcmp(hash, hash_questions(header, (unsigned int)m, daemon->namebuff), HASH_SIZE) != 0)
Simon Kelley703c7ff2014-01-25 23:46:23 +00002178 {
2179 m = 0;
2180 break;
2181 }
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002182
Simon Kelley25e63f12020-11-25 21:17:52 +00002183 /* Never cache answers which are contingent on the source or MAC address EDSN0 option,
2184 since the cache is ignorant of such things. */
2185 if (!cacheable)
2186 no_cache_dnssec = 1;
2187
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002188 m = process_reply(header, now, last_server, (unsigned int)m,
Simon Kelleye66b4df2015-04-28 20:45:57 +01002189 option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
Simon Kelleyfa14bec2015-12-20 17:12:16 +00002190 ad_reqd, do_bit, added_pheader, check_subnet, &peer_addr);
Simon Kelley4f7b3042012-11-28 21:27:02 +00002191
2192 break;
2193 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002194 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00002195
2196 /* In case of local answer or no connections made. */
2197 if (m == 0)
Simon Kelley1682d152018-08-03 20:38:18 +01002198 {
2199 m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl);
2200 if (have_pseudoheader)
2201 m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
2202 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002203 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002204 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00002205
Simon Kelleyb842bc92015-07-12 21:09:11 +01002206 check_log_writer(1);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002207
Simon Kelley4b5ea122013-04-22 10:18:26 +01002208 *length = htons(m);
2209
2210 if (m == 0 || !read_write(confd, packet, m + sizeof(u16), 0))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002211 return packet;
2212 }
2213}
2214
Simon Kelley16972692006-10-16 20:04:18 +01002215static struct frec *allocate_frec(time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002216{
Simon Kelley16972692006-10-16 20:04:18 +01002217 struct frec *f;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002218
Simon Kelley5aabfc72007-08-29 11:24:47 +01002219 if ((f = (struct frec *)whine_malloc(sizeof(struct frec))))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002220 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01002221 f->next = daemon->frec_list;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002222 f->time = now;
Simon Kelley832af0b2007-01-21 20:01:28 +00002223 f->sentto = NULL;
Simon Kelley1a6bca82008-07-11 11:11:42 +01002224 f->rfd4 = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +00002225 f->flags = 0;
Simon Kelley1a6bca82008-07-11 11:11:42 +01002226 f->rfd6 = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002227#ifdef HAVE_DNSSEC
Simon Kelley97bc7982014-01-31 10:19:52 +00002228 f->dependent = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002229 f->blocking_query = NULL;
Simon Kelley4619d942014-01-16 19:53:06 +00002230 f->stash = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002231#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +01002232 daemon->frec_list = f;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002233 }
Simon Kelley16972692006-10-16 20:04:18 +01002234
2235 return f;
2236}
2237
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002238struct randfd *allocate_rfd(int family)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002239{
2240 static int finger = 0;
2241 int i;
2242
2243 /* limit the number of sockets we have open to avoid starvation of
2244 (eg) TFTP. Once we have a reasonable number, randomness should be OK */
2245
2246 for (i = 0; i < RANDOM_SOCKS; i++)
Simon Kelley9009d742008-11-14 20:04:27 +00002247 if (daemon->randomsocks[i].refcount == 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002248 {
Simon Kelley9009d742008-11-14 20:04:27 +00002249 if ((daemon->randomsocks[i].fd = random_sock(family)) == -1)
2250 break;
2251
Simon Kelley1a6bca82008-07-11 11:11:42 +01002252 daemon->randomsocks[i].refcount = 1;
2253 daemon->randomsocks[i].family = family;
2254 return &daemon->randomsocks[i];
2255 }
2256
Simon Kelley9009d742008-11-14 20:04:27 +00002257 /* No free ones or cannot get new socket, grab an existing one */
Simon Kelley1a6bca82008-07-11 11:11:42 +01002258 for (i = 0; i < RANDOM_SOCKS; i++)
2259 {
2260 int j = (i+finger) % RANDOM_SOCKS;
Simon Kelley9009d742008-11-14 20:04:27 +00002261 if (daemon->randomsocks[j].refcount != 0 &&
2262 daemon->randomsocks[j].family == family &&
2263 daemon->randomsocks[j].refcount != 0xffff)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002264 {
2265 finger = j;
2266 daemon->randomsocks[j].refcount++;
2267 return &daemon->randomsocks[j];
2268 }
2269 }
2270
2271 return NULL; /* doom */
2272}
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002273
2274void free_rfd(struct randfd *rfd)
2275{
2276 if (rfd && --(rfd->refcount) == 0)
2277 close(rfd->fd);
2278}
2279
Simon Kelley1a6bca82008-07-11 11:11:42 +01002280static void free_frec(struct frec *f)
2281{
Simon Kelley6a6e06f2020-12-04 18:35:11 +00002282 struct frec_src *last;
Simon Kelley15b60dd2020-11-18 18:34:55 +00002283
Simon Kelley6a6e06f2020-12-04 18:35:11 +00002284 /* add back to freelist if not the record builtin to every frec. */
2285 for (last = f->frec_src.next; last && last->next; last = last->next) ;
2286 if (last)
2287 {
2288 last->next = daemon->free_frec_src;
2289 daemon->free_frec_src = f->frec_src.next;
2290 }
2291
Simon Kelley15b60dd2020-11-18 18:34:55 +00002292 f->frec_src.next = NULL;
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002293 free_rfd(f->rfd4);
Simon Kelley1a6bca82008-07-11 11:11:42 +01002294 f->rfd4 = NULL;
2295 f->sentto = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +00002296 f->flags = 0;
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002297 free_rfd(f->rfd6);
Simon Kelley1a6bca82008-07-11 11:11:42 +01002298 f->rfd6 = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002299
2300#ifdef HAVE_DNSSEC
2301 if (f->stash)
Simon Kelley0fc2f312014-01-08 10:26:58 +00002302 {
2303 blockdata_free(f->stash);
2304 f->stash = NULL;
2305 }
Simon Kelley3a237152013-12-12 12:15:50 +00002306
2307 /* Anything we're waiting on is pointless now, too */
2308 if (f->blocking_query)
2309 free_frec(f->blocking_query);
2310 f->blocking_query = NULL;
Simon Kelley39048ad2014-01-21 17:33:58 +00002311 f->dependent = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002312#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +01002313}
2314
Simon Kelley09f3b2c2017-05-09 01:34:02 +01002315
2316
Simon Kelley16972692006-10-16 20:04:18 +01002317/* if wait==NULL return a free or older than TIMEOUT record.
2318 else return *wait zero if one available, or *wait is delay to
Simon Kelley1a6bca82008-07-11 11:11:42 +01002319 when the oldest in-use record will expire. Impose an absolute
Simon Kelley3a237152013-12-12 12:15:50 +00002320 limit of 4*TIMEOUT before we wipe things (for random sockets).
Simon Kelley8caf3d72020-04-04 17:00:32 +01002321 If force is non-NULL, always return a result, even if we have
2322 to allocate above the limit, and never free the record pointed
2323 to by the force argument. */
2324struct frec *get_new_frec(time_t now, int *wait, struct frec *force)
Simon Kelley16972692006-10-16 20:04:18 +01002325{
Simon Kelley1a6bca82008-07-11 11:11:42 +01002326 struct frec *f, *oldest, *target;
Simon Kelley16972692006-10-16 20:04:18 +01002327 int count;
2328
2329 if (wait)
2330 *wait = 0;
2331
Simon Kelley1a6bca82008-07-11 11:11:42 +01002332 for (f = daemon->frec_list, oldest = NULL, target = NULL, count = 0; f; f = f->next, count++)
Simon Kelley832af0b2007-01-21 20:01:28 +00002333 if (!f->sentto)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002334 target = f;
2335 else
Simon Kelley16972692006-10-16 20:04:18 +01002336 {
Simon Kelley9a31b682015-12-15 10:20:39 +00002337#ifdef HAVE_DNSSEC
2338 /* Don't free DNSSEC sub-queries here, as we may end up with
2339 dangling references to them. They'll go when their "real" query
2340 is freed. */
Simon Kelley8caf3d72020-04-04 17:00:32 +01002341 if (!f->dependent && f != force)
Simon Kelley9a31b682015-12-15 10:20:39 +00002342#endif
2343 {
2344 if (difftime(now, f->time) >= 4*TIMEOUT)
2345 {
2346 free_frec(f);
2347 target = f;
2348 }
2349
2350
2351 if (!oldest || difftime(f->time, oldest->time) <= 0)
2352 oldest = f;
2353 }
Simon Kelley16972692006-10-16 20:04:18 +01002354 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01002355
2356 if (target)
2357 {
2358 target->time = now;
2359 return target;
2360 }
Simon Kelley16972692006-10-16 20:04:18 +01002361
2362 /* can't find empty one, use oldest if there is one
2363 and it's older than timeout */
Simon Kelley09f3b2c2017-05-09 01:34:02 +01002364 if (!force && oldest && ((int)difftime(now, oldest->time)) >= TIMEOUT)
Simon Kelley16972692006-10-16 20:04:18 +01002365 {
2366 /* keep stuff for twice timeout if we can by allocating a new
2367 record instead */
2368 if (difftime(now, oldest->time) < 2*TIMEOUT &&
2369 count <= daemon->ftabsize &&
2370 (f = allocate_frec(now)))
2371 return f;
2372
2373 if (!wait)
2374 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01002375 free_frec(oldest);
Simon Kelley16972692006-10-16 20:04:18 +01002376 oldest->time = now;
2377 }
2378 return oldest;
2379 }
2380
2381 /* none available, calculate time 'till oldest record expires */
Simon Kelley3a237152013-12-12 12:15:50 +00002382 if (!force && count > daemon->ftabsize)
Simon Kelley16972692006-10-16 20:04:18 +01002383 {
Marcelo Salhab Brogliato0da5e892013-05-31 11:49:06 +01002384 static time_t last_log = 0;
2385
Simon Kelley16972692006-10-16 20:04:18 +01002386 if (oldest && wait)
2387 *wait = oldest->time + (time_t)TIMEOUT - now;
Marcelo Salhab Brogliato0da5e892013-05-31 11:49:06 +01002388
2389 if ((int)difftime(now, last_log) > 5)
2390 {
2391 last_log = now;
2392 my_syslog(LOG_WARNING, _("Maximum number of concurrent DNS queries reached (max: %d)"), daemon->ftabsize);
2393 }
2394
Simon Kelley16972692006-10-16 20:04:18 +01002395 return NULL;
2396 }
2397
2398 if (!(f = allocate_frec(now)) && wait)
2399 /* wait one second on malloc failure */
2400 *wait = 1;
2401
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002402 return f; /* OK if malloc fails and this is NULL */
2403}
Simon Kelley09f3b2c2017-05-09 01:34:02 +01002404
Simon Kelley257ac0c2020-11-12 18:49:23 +00002405static struct frec *lookup_frec(unsigned short id, int fd, int family, void *hash)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002406{
2407 struct frec *f;
2408
Simon Kelley1a6bca82008-07-11 11:11:42 +01002409 for(f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00002410 if (f->sentto && f->new_id == id &&
Simon Kelley2d765862020-11-12 22:06:07 +00002411 (memcmp(hash, f->hash, HASH_SIZE) == 0))
Simon Kelley257ac0c2020-11-12 18:49:23 +00002412 {
2413 /* sent from random port */
2414 if (family == AF_INET && f->rfd4 && f->rfd4->fd == fd)
2415 return f;
2416
2417 if (family == AF_INET6 && f->rfd6 && f->rfd6->fd == fd)
2418 return f;
2419
2420 /* sent to upstream from bound socket. */
2421 if (f->sentto->sfd && f->sentto->sfd->fd == fd)
2422 return f;
2423 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002424
2425 return NULL;
2426}
2427
2428static struct frec *lookup_frec_by_sender(unsigned short id,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01002429 union mysockaddr *addr,
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002430 void *hash)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002431{
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002432 struct frec *f;
Simon Kelley15b60dd2020-11-18 18:34:55 +00002433 struct frec_src *src;
2434
2435 for (f = daemon->frec_list; f; f = f->next)
2436 if (f->sentto &&
2437 !(f->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) &&
2438 memcmp(hash, f->hash, HASH_SIZE) == 0)
2439 for (src = &f->frec_src; src; src = src->next)
2440 if (src->orig_id == id &&
2441 sockaddr_isequal(&src->source, addr))
2442 return f;
2443
2444 return NULL;
2445}
2446
2447static struct frec *lookup_frec_by_query(void *hash, unsigned int flags)
2448{
2449 struct frec *f;
2450
2451 /* FREC_DNSKEY and FREC_DS_QUERY are never set in flags, so the test below
Simon Kelley25e63f12020-11-25 21:17:52 +00002452 ensures that no frec created for internal DNSSEC query can be returned here.
2453
2454 Similarly FREC_NO_CACHE is never set in flags, so a query which is
2455 contigent on a particular source address EDNS0 option will never be matched. */
Simon Kelley15b60dd2020-11-18 18:34:55 +00002456
2457#define FLAGMASK (FREC_CHECKING_DISABLED | FREC_AD_QUESTION | FREC_DO_QUESTION \
Simon Kelley25e63f12020-11-25 21:17:52 +00002458 | FREC_HAS_PHEADER | FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_NO_CACHE)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002459
Simon Kelley1a6bca82008-07-11 11:11:42 +01002460 for(f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00002461 if (f->sentto &&
Simon Kelley15b60dd2020-11-18 18:34:55 +00002462 (f->flags & FLAGMASK) == flags &&
2463 memcmp(hash, f->hash, HASH_SIZE) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002464 return f;
Simon Kelley15b60dd2020-11-18 18:34:55 +00002465
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002466 return NULL;
2467}
Simon Kelley15b60dd2020-11-18 18:34:55 +00002468
Simon Kelley47a95162014-07-08 22:22:02 +01002469/* Send query packet again, if we can. */
2470void resend_query()
2471{
2472 if (daemon->srv_save)
2473 {
2474 int fd;
2475
2476 if (daemon->srv_save->sfd)
2477 fd = daemon->srv_save->sfd->fd;
2478 else if (daemon->rfd_save && daemon->rfd_save->refcount != 0)
2479 fd = daemon->rfd_save->fd;
2480 else
2481 return;
2482
Simon Kelleyff841eb2015-03-11 21:36:30 +00002483 while(retry_send(sendto(fd, daemon->packet, daemon->packet_len, 0,
2484 &daemon->srv_save->addr.sa,
2485 sa_len(&daemon->srv_save->addr))));
Simon Kelley47a95162014-07-08 22:22:02 +01002486 }
2487}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002488
Simon Kelley849a8352006-06-09 21:02:31 +01002489/* A server record is going away, remove references to it */
Simon Kelley5aabfc72007-08-29 11:24:47 +01002490void server_gone(struct server *server)
Simon Kelley849a8352006-06-09 21:02:31 +01002491{
2492 struct frec *f;
2493
Simon Kelley1a6bca82008-07-11 11:11:42 +01002494 for (f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00002495 if (f->sentto && f->sentto == server)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002496 free_frec(f);
Simon Kelley849a8352006-06-09 21:02:31 +01002497
2498 if (daemon->last_server == server)
2499 daemon->last_server = NULL;
2500
2501 if (daemon->srv_save == server)
2502 daemon->srv_save = NULL;
2503}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002504
Simon Kelley316e2732010-01-22 20:16:09 +00002505/* return unique random ids. */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002506static unsigned short get_id(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002507{
2508 unsigned short ret = 0;
Simon Kelley257ac0c2020-11-12 18:49:23 +00002509 struct frec *f;
Simon Kelley832af0b2007-01-21 20:01:28 +00002510
Simon Kelley257ac0c2020-11-12 18:49:23 +00002511 while (1)
2512 {
2513 ret = rand16();
2514
2515 /* ensure id is unique. */
2516 for (f = daemon->frec_list; f; f = f->next)
2517 if (f->sentto && f->new_id == ret)
2518 break;
2519
2520 if (!f)
2521 return ret;
2522 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002523}
2524
2525
2526
2527
2528