blob: 8fb03273e1744fb2c2a7606213eee7249ab02278 [file] [log] [blame]
Simon Kelleyc8e8f5c2021-01-24 21:59:37 +00001/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
Simon Kelley824af852008-02-12 20:43:05 +00005 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
Simon Kelley9e4abcb2004-01-22 19:47:41 +00008 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
Simon Kelley824af852008-02-12 20:43:05 +000012
Simon Kelley73a08a22009-02-05 20:28:08 +000013 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
Simon Kelley9e4abcb2004-01-22 19:47:41 +000015*/
16
Simon Kelley9e4abcb2004-01-22 19:47:41 +000017#include "dnsmasq.h"
18
Simon 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;
Simon Kelley3f535da2021-01-22 22:26:25 +0000381 new->fd = udpfd;
Simon Kelley15b60dd2020-11-18 18:34:55 +0000382 }
383
384 return 1;
385 }
386
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000387 if (gotname)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100388 flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000389
Simon Kelley367341f2016-01-12 15:58:23 +0000390#ifdef HAVE_DNSSEC
391 do_dnssec = type & SERV_DO_DNSSEC;
Simon Kelleyf7443d72016-01-19 20:29:57 +0000392#endif
393 type &= ~SERV_DO_DNSSEC;
Simon Kelley15b60dd2020-11-18 18:34:55 +0000394
Simon Kelleyd05dd582016-01-19 21:23:30 +0000395 if (daemon->servers && !flags)
Simon Kelley8caf3d72020-04-04 17:00:32 +0100396 forward = get_new_frec(now, NULL, NULL);
Simon Kelleyd05dd582016-01-19 21:23:30 +0000397 /* table full - flags == 0, return REFUSED */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000398
399 if (forward)
400 {
Simon Kelley15b60dd2020-11-18 18:34:55 +0000401 forward->frec_src.source = *udpaddr;
402 forward->frec_src.orig_id = ntohs(header->id);
403 forward->frec_src.dest = *dst_addr;
404 forward->frec_src.iface = dst_iface;
Simon Kelley6a6e06f2020-12-04 18:35:11 +0000405 forward->frec_src.next = NULL;
Simon Kelley04490bf2021-01-22 16:49:12 +0000406 forward->frec_src.fd = udpfd;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000407 forward->new_id = get_id();
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000408 memcpy(forward->hash, hash, HASH_SIZE);
Simon Kelley0a852542005-03-23 20:28:59 +0000409 forward->forwardall = 0;
Simon Kelley15b60dd2020-11-18 18:34:55 +0000410 forward->flags = fwd_flags;
Simon Kelley28866e92011-02-14 20:19:14 +0000411 if (norebind)
412 forward->flags |= FREC_NOREBIND;
Simon Kelley572b41e2011-02-18 18:11:18 +0000413 if (header->hb4 & HB4_CD)
Simon Kelley28866e92011-02-14 20:19:14 +0000414 forward->flags |= FREC_CHECKING_DISABLED;
Simon Kelley83349b82014-02-10 21:02:01 +0000415 if (ad_reqd)
416 forward->flags |= FREC_AD_QUESTION;
Simon Kelley7fa836e2014-02-10 20:11:24 +0000417#ifdef HAVE_DNSSEC
418 forward->work_counter = DNSSEC_WORK;
Simon Kelley613ad152014-02-25 23:02:28 +0000419 if (do_bit)
420 forward->flags |= FREC_DO_QUESTION;
Simon Kelley7fa836e2014-02-10 20:11:24 +0000421#endif
Simon Kelley613ad152014-02-25 23:02:28 +0000422
Simon Kelley28866e92011-02-14 20:19:14 +0000423 header->id = htons(forward->new_id);
424
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100425 /* In strict_order mode, always try servers in the order
426 specified in resolv.conf, if a domain is given
427 always try all the available servers,
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000428 otherwise, use the one last known to work. */
429
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100430 if (type == 0)
431 {
Simon Kelley28866e92011-02-14 20:19:14 +0000432 if (option_bool(OPT_ORDER))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100433 start = daemon->servers;
434 else if (!(start = daemon->last_server) ||
435 daemon->forwardcount++ > FORWARD_TEST ||
436 difftime(now, daemon->forwardtime) > FORWARD_TIME)
437 {
438 start = daemon->servers;
439 forward->forwardall = 1;
440 daemon->forwardcount = 0;
441 daemon->forwardtime = now;
442 }
443 }
444 else
Simon Kelleyde379512004-06-22 20:23:33 +0100445 {
Simon Kelley3be34542004-09-11 19:12:13 +0100446 start = daemon->servers;
Simon Kelley28866e92011-02-14 20:19:14 +0000447 if (!option_bool(OPT_ORDER))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100448 forward->forwardall = 1;
Simon Kelleyde379512004-06-22 20:23:33 +0100449 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000450 }
451 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100452
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000453 /* check for send errors here (no route to host)
454 if we fail to send to all nameservers, send back an error
455 packet straight away (helps modem users when offline) */
456
457 if (!flags && forward)
458 {
Simon Kelleyde379512004-06-22 20:23:33 +0100459 struct server *firstsentto = start;
Simon Kelley25e63f12020-11-25 21:17:52 +0000460 int subnet, cacheable, forwarded = 0;
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000461 size_t edns0_len;
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000462 unsigned char *pheader;
463
Simon Kelley25cf5e32015-01-09 15:53:03 +0000464 /* If a query is retried, use the log_id for the retry when logging the answer. */
Simon Kelley15b60dd2020-11-18 18:34:55 +0000465 forward->frec_src.log_id = daemon->log_id;
Simon Kelley25cf5e32015-01-09 15:53:03 +0000466
Simon Kelley25e63f12020-11-25 21:17:52 +0000467 plen = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->frec_src.source, now, &subnet, &cacheable);
Simon Kelley33702ab2015-12-28 23:17:15 +0000468
Simon Kelley6fd5d792017-10-13 22:26:40 +0100469 if (subnet)
470 forward->flags |= FREC_HAS_SUBNET;
Simon Kelley25e63f12020-11-25 21:17:52 +0000471
472 if (!cacheable)
473 forward->flags |= FREC_NO_CACHE;
474
Simon Kelley3a237152013-12-12 12:15:50 +0000475#ifdef HAVE_DNSSEC
Simon Kelley367341f2016-01-12 15:58:23 +0000476 if (option_bool(OPT_DNSSEC_VALID) && do_dnssec)
Simon Kelley0fc2f312014-01-08 10:26:58 +0000477 {
Simon Kelley6fd5d792017-10-13 22:26:40 +0100478 plen = add_do_bit(header, plen, ((unsigned char *) header) + PACKETSZ);
479
Simon Kelley5b3bf922014-01-25 17:03:07 +0000480 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
481 this allows it to select auth servers when one is returning bad data. */
482 if (option_bool(OPT_DNSSEC_DEBUG))
483 header->hb4 |= HB4_CD;
Simon Kelley613ad152014-02-25 23:02:28 +0000484
Simon Kelley0fc2f312014-01-08 10:26:58 +0000485 }
Simon Kelley3a237152013-12-12 12:15:50 +0000486#endif
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000487
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000488 if (find_pseudoheader(header, plen, &edns0_len, &pheader, NULL, NULL))
Simon Kelley6fd5d792017-10-13 22:26:40 +0100489 {
490 /* If there wasn't a PH before, and there is now, we added it. */
491 if (!oph)
492 forward->flags |= FREC_ADDED_PHEADER;
493
494 /* If we're sending an EDNS0 with any options, we can't recreate the query from a reply. */
495 if (edns0_len > 11)
496 forward->flags |= FREC_HAS_EXTRADATA;
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000497
498 /* Reduce udp size on retransmits. */
499 if (forward->flags & FREC_TEST_PKTSZ)
500 PUTSHORT(SAFE_PKTSZ, pheader);
Simon Kelley6fd5d792017-10-13 22:26:40 +0100501 }
Simon Kelleya77cec82015-05-08 16:25:38 +0100502
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000503 while (1)
504 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000505 /* only send to servers dealing with our domain.
506 domain may be NULL, in which case server->domain
507 must be NULL also. */
508
Simon Kelleyde379512004-06-22 20:23:33 +0100509 if (type == (start->flags & SERV_TYPE) &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100510 (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +0100511 !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000512 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100513 int fd;
514
515 /* find server socket to use, may need to get random one. */
516 if (start->sfd)
517 fd = start->sfd->fd;
518 else
519 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100520 if (start->addr.sa.sa_family == AF_INET6)
521 {
522 if (!forward->rfd6 &&
523 !(forward->rfd6 = allocate_rfd(AF_INET6)))
524 break;
Simon Kelley3927da42008-07-20 15:10:39 +0100525 daemon->rfd_save = forward->rfd6;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100526 fd = forward->rfd6->fd;
527 }
528 else
Simon Kelley1a6bca82008-07-11 11:11:42 +0100529 {
530 if (!forward->rfd4 &&
531 !(forward->rfd4 = allocate_rfd(AF_INET)))
532 break;
Simon Kelley3927da42008-07-20 15:10:39 +0100533 daemon->rfd_save = forward->rfd4;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100534 fd = forward->rfd4->fd;
535 }
Simon Kelley7de060b2011-08-26 17:24:52 +0100536
537#ifdef HAVE_CONNTRACK
538 /* Copy connection mark of incoming query to outgoing connection. */
539 if (option_bool(OPT_CONNTRACK))
540 {
541 unsigned int mark;
Simon Kelleycc0b4482021-01-15 22:21:52 +0000542 if (get_incoming_mark(&forward->frec_src.source, &forward->frec_src.dest, 0, &mark))
Simon Kelley7de060b2011-08-26 17:24:52 +0100543 setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
544 }
545#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +0100546 }
547
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000548#ifdef HAVE_DNSSEC
Simon Kelley5bb88f02015-12-21 16:23:47 +0000549 if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER))
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000550 {
551 /* Difficult one here. If our client didn't send EDNS0, we will have set the UDP
552 packet size to 512. But that won't provide space for the RRSIGS in many cases.
553 The RRSIGS will be stripped out before the answer goes back, so the packet should
554 shrink again. So, if we added a do-bit, bump the udp packet size to the value
Simon Kelley5aa5f0f2015-12-21 17:20:35 +0000555 known to be OK for this server. We check returned size after stripping and set
556 the truncated bit if it's still too big. */
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000557 unsigned char *pheader;
558 int is_sign;
Simon Kelley5bb88f02015-12-21 16:23:47 +0000559 if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000560 PUTSHORT(start->edns_pktsz, pheader);
561 }
562#endif
563
Simon Kelleyff841eb2015-03-11 21:36:30 +0000564 if (retry_send(sendto(fd, (char *)header, plen, 0,
565 &start->addr.sa,
566 sa_len(&start->addr))))
567 continue;
568
569 if (errno == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000570 {
Simon Kelley6b173352018-05-08 18:32:14 +0100571#ifdef HAVE_DUMPFILE
572 dump_packet(DUMP_UP_QUERY, (void *)header, plen, NULL, &start->addr);
573#endif
574
Simon Kelleycdeda282006-03-16 20:16:06 +0000575 /* Keep info in case we want to re-send this packet */
576 daemon->srv_save = start;
577 daemon->packet_len = plen;
578
Simon Kelleyde379512004-06-22 20:23:33 +0100579 if (!gotname)
Simon Kelley3be34542004-09-11 19:12:13 +0100580 strcpy(daemon->namebuff, "query");
Simon Kelleyde379512004-06-22 20:23:33 +0100581 if (start->addr.sa.sa_family == AF_INET)
Simon Kelley3be34542004-09-11 19:12:13 +0100582 log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
Simon Kelleycc921df2019-01-02 22:48:59 +0000583 (union all_addr *)&start->addr.in.sin_addr, NULL);
Simon Kelleyde379512004-06-22 20:23:33 +0100584 else
Simon Kelley3be34542004-09-11 19:12:13 +0100585 log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
Simon Kelleycc921df2019-01-02 22:48:59 +0000586 (union all_addr *)&start->addr.in6.sin6_addr, NULL);
Simon Kelley824af852008-02-12 20:43:05 +0000587 start->queries++;
Simon Kelleyde379512004-06-22 20:23:33 +0100588 forwarded = 1;
589 forward->sentto = start;
Simon Kelley0a852542005-03-23 20:28:59 +0000590 if (!forward->forwardall)
Simon Kelleyde379512004-06-22 20:23:33 +0100591 break;
Simon Kelley0a852542005-03-23 20:28:59 +0000592 forward->forwardall++;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000593 }
594 }
595
Simon Kelleyde379512004-06-22 20:23:33 +0100596 if (!(start = start->next))
Simon Kelley3be34542004-09-11 19:12:13 +0100597 start = daemon->servers;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000598
Simon Kelleyde379512004-06-22 20:23:33 +0100599 if (start == firstsentto)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000600 break;
601 }
602
Simon Kelleyde379512004-06-22 20:23:33 +0100603 if (forwarded)
Simon Kelley824af852008-02-12 20:43:05 +0000604 return 1;
Simon Kelleyde379512004-06-22 20:23:33 +0100605
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000606 /* could not send on, prepare to return */
Simon Kelley15b60dd2020-11-18 18:34:55 +0000607 header->id = htons(forward->frec_src.orig_id);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100608 free_frec(forward); /* cancel */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000609 }
610
611 /* could not send on, return empty answer or address if known for whole domain */
Simon Kelleyb8187c82005-11-26 21:46:27 +0000612 if (udpfd != -1)
613 {
Simon Kelleycdeda282006-03-16 20:16:06 +0000614 plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl);
Simon Kelley1682d152018-08-03 20:38:18 +0100615 if (oph)
616 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 +0100617 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 +0000618 }
619
Simon Kelley824af852008-02-12 20:43:05 +0000620 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000621}
622
Simon Kelleyed4c0762013-10-08 20:46:34 +0100623static 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 +0100624 int no_cache, int cache_secure, int bogusanswer, int ad_reqd, int do_bit, int added_pheader,
625 int check_subnet, union mysockaddr *query_source)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100626{
Simon Kelley36717ee2004-09-20 19:20:58 +0100627 unsigned char *pheader, *sizep;
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000628 char **sets = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +0000629 int munged = 0, is_sign;
Simon Kelley07ed5852018-05-04 21:52:22 +0100630 unsigned int rcode = RCODE(header);
Simon Kelleycdeda282006-03-16 20:16:06 +0000631 size_t plen;
Simon Kelleya6004d72017-10-25 17:48:19 +0100632
Simon Kelley83349b82014-02-10 21:02:01 +0000633 (void)ad_reqd;
Simon Kelley982faf42015-04-03 21:42:30 +0100634 (void)do_bit;
635 (void)bogusanswer;
Simon Kelley83349b82014-02-10 21:02:01 +0000636
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000637#ifdef HAVE_IPSET
Simon Kelley82a14af2014-04-13 20:48:57 +0100638 if (daemon->ipsets && extract_request(header, n, daemon->namebuff, NULL))
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000639 {
Simon Kelley82a14af2014-04-13 20:48:57 +0100640 /* Similar algorithm to search_servers. */
641 struct ipsets *ipset_pos;
642 unsigned int namelen = strlen(daemon->namebuff);
643 unsigned int matchlen = 0;
644 for (ipset_pos = daemon->ipsets; ipset_pos; ipset_pos = ipset_pos->next)
Simon Kelley6c0cb852014-01-17 14:40:46 +0000645 {
Simon Kelley82a14af2014-04-13 20:48:57 +0100646 unsigned int domainlen = strlen(ipset_pos->domain);
647 char *matchstart = daemon->namebuff + namelen - domainlen;
648 if (namelen >= domainlen && hostname_isequal(matchstart, ipset_pos->domain) &&
649 (domainlen == 0 || namelen == domainlen || *(matchstart - 1) == '.' ) &&
650 domainlen >= matchlen)
651 {
652 matchlen = domainlen;
653 sets = ipset_pos->sets;
654 }
Simon Kelley6c0cb852014-01-17 14:40:46 +0000655 }
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000656 }
657#endif
Simon Kelley25e63f12020-11-25 21:17:52 +0000658
Simon Kelley5bb88f02015-12-21 16:23:47 +0000659 if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign, NULL)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100660 {
Simon Kelley07ed5852018-05-04 21:52:22 +0100661 /* Get extended RCODE. */
662 rcode |= sizep[2] << 4;
663
Simon Kelleyed4c0762013-10-08 20:46:34 +0100664 if (check_subnet && !check_source(header, plen, pheader, query_source))
665 {
666 my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch"));
667 return 0;
668 }
Simon Kelley613ad152014-02-25 23:02:28 +0000669
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000670 if (!is_sign)
Simon Kelley613ad152014-02-25 23:02:28 +0000671 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000672 if (added_pheader)
673 {
674 /* client didn't send EDNS0, we added one, strip it off before returning answer. */
675 n = rrfilter(header, n, 0);
676 pheader = NULL;
677 }
678 else
679 {
Simon Kelley33702ab2015-12-28 23:17:15 +0000680 unsigned short udpsz;
681
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000682 /* If upstream is advertising a larger UDP packet size
683 than we allow, trim it so that we don't get overlarge
684 requests for the client. We can't do this for signed packets. */
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000685 GETSHORT(udpsz, sizep);
686 if (udpsz > daemon->edns_pktsz)
Simon Kelley33702ab2015-12-28 23:17:15 +0000687 {
688 sizep -= 2;
689 PUTSHORT(daemon->edns_pktsz, sizep);
690 }
691
692#ifdef HAVE_DNSSEC
693 /* If the client didn't set the do bit, but we did, reset it. */
694 if (option_bool(OPT_DNSSEC_VALID) && !do_bit)
695 {
696 unsigned short flags;
697 sizep += 2; /* skip RCODE */
698 GETSHORT(flags, sizep);
699 flags &= ~0x8000;
700 sizep -= 2;
701 PUTSHORT(flags, sizep);
702 }
703#endif
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000704 }
Simon Kelley613ad152014-02-25 23:02:28 +0000705 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100706 }
Simon Kelley83349b82014-02-10 21:02:01 +0000707
Simon Kelley28866e92011-02-14 20:19:14 +0000708 /* RFC 4035 sect 4.6 para 3 */
Giovanni Bajo237724c2012-04-05 02:46:52 +0200709 if (!is_sign && !option_bool(OPT_DNSSEC_PROXY))
Simon Kelley795501b2014-01-08 18:11:55 +0000710 header->hb4 &= ~HB4_AD;
Simon Kelley3a237152013-12-12 12:15:50 +0000711
Simon Kelley07ed5852018-05-04 21:52:22 +0100712 if (OPCODE(header) != QUERY)
Simon Kelley8938ae02014-05-01 17:46:25 +0100713 return resize_packet(header, n, pheader, plen);
Simon Kelley07ed5852018-05-04 21:52:22 +0100714
715 if (rcode != NOERROR && rcode != NXDOMAIN)
716 {
Simon Kelleycc921df2019-01-02 22:48:59 +0000717 union all_addr a;
718 a.log.rcode = rcode;
Simon Kelley07ed5852018-05-04 21:52:22 +0100719 log_query(F_UPSTREAM | F_RCODE, "error", &a, NULL);
720
721 return resize_packet(header, n, pheader, plen);
722 }
Simon Kelley36717ee2004-09-20 19:20:58 +0100723
Simon Kelley0a852542005-03-23 20:28:59 +0000724 /* Complain loudly if the upstream server is non-recursive. */
Simon Kelley07ed5852018-05-04 21:52:22 +0100725 if (!(header->hb4 & HB4_RA) && rcode == NOERROR &&
Simon Kelley0a852542005-03-23 20:28:59 +0000726 server && !(server->flags & SERV_WARNED_RECURSIVE))
727 {
Petr Mensik51cdd1a2019-07-04 20:28:08 +0200728 (void)prettyprint_addr(&server->addr, daemon->namebuff);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100729 my_syslog(LOG_WARNING, _("nameserver %s refused to do a recursive query"), daemon->namebuff);
Simon Kelley28866e92011-02-14 20:19:14 +0000730 if (!option_bool(OPT_LOG))
Simon Kelley0a852542005-03-23 20:28:59 +0000731 server->flags |= SERV_WARNED_RECURSIVE;
732 }
Giovanni Bajoe292e932012-04-22 14:32:02 +0200733
Simon Kelley07ed5852018-05-04 21:52:22 +0100734 if (daemon->bogus_addr && rcode != NXDOMAIN &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100735 check_for_bogus_wildcard(header, n, daemon->namebuff, daemon->bogus_addr, now))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100736 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100737 munged = 1;
Simon Kelley572b41e2011-02-18 18:11:18 +0000738 SET_RCODE(header, NXDOMAIN);
739 header->hb3 &= ~HB3_AA;
Simon Kelley6938f342014-01-26 22:47:39 +0000740 cache_secure = 0;
Simon Kelley36717ee2004-09-20 19:20:58 +0100741 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100742 else
Simon Kelley36717ee2004-09-20 19:20:58 +0100743 {
Simon Kelley6938f342014-01-26 22:47:39 +0000744 int doctored = 0;
745
Simon Kelley07ed5852018-05-04 21:52:22 +0100746 if (rcode == NXDOMAIN &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100747 extract_request(header, n, daemon->namebuff, NULL) &&
Simon Kelley5aabfc72007-08-29 11:24:47 +0100748 check_for_local_domain(daemon->namebuff, now))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100749 {
Simon Kelley36717ee2004-09-20 19:20:58 +0100750 /* if we forwarded a query for a locally known name (because it was for
751 an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
752 since we know that the domain exists, even if upstream doesn't */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100753 munged = 1;
Simon Kelley572b41e2011-02-18 18:11:18 +0000754 header->hb3 |= HB3_AA;
755 SET_RCODE(header, NOERROR);
Simon Kelley6938f342014-01-26 22:47:39 +0000756 cache_secure = 0;
Simon Kelley36717ee2004-09-20 19:20:58 +0100757 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000758
Simon Kelley373e9172017-12-01 22:40:56 +0000759 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 +0000760 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100761 my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
Simon Kelley824af852008-02-12 20:43:05 +0000762 munged = 1;
Simon Kelley6938f342014-01-26 22:47:39 +0000763 cache_secure = 0;
Simon Kelley824af852008-02-12 20:43:05 +0000764 }
Simon Kelley6938f342014-01-26 22:47:39 +0000765
766 if (doctored)
767 cache_secure = 0;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100768 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100769
Simon Kelleya25720a2014-01-14 23:13:55 +0000770#ifdef HAVE_DNSSEC
Simon Kelley33702ab2015-12-28 23:17:15 +0000771 if (bogusanswer && !(header->hb4 & HB4_CD) && !option_bool(OPT_DNSSEC_DEBUG))
Simon Kelleya25720a2014-01-14 23:13:55 +0000772 {
Simon Kelley33702ab2015-12-28 23:17:15 +0000773 /* Bogus reply, turn into SERVFAIL */
774 SET_RCODE(header, SERVFAIL);
775 munged = 1;
Simon Kelleya25720a2014-01-14 23:13:55 +0000776 }
Simon Kelley6938f342014-01-26 22:47:39 +0000777
778 if (option_bool(OPT_DNSSEC_VALID))
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000779 {
780 header->hb4 &= ~HB4_AD;
781
782 if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure)
783 header->hb4 |= HB4_AD;
784
785 /* If the requestor didn't set the DO bit, don't return DNSSEC info. */
786 if (!do_bit)
787 n = rrfilter(header, n, 1);
788 }
Simon Kelleya25720a2014-01-14 23:13:55 +0000789#endif
790
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100791 /* do this after extract_addresses. Ensure NODATA reply and remove
792 nameserver info. */
793
794 if (munged)
795 {
796 header->ancount = htons(0);
797 header->nscount = htons(0);
798 header->arcount = htons(0);
Simon Kelley150162b2015-03-27 09:58:26 +0000799 header->hb3 &= ~HB3_TC;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100800 }
801
Simon Kelley36717ee2004-09-20 19:20:58 +0100802 /* the bogus-nxdomain stuff, doctor and NXDOMAIN->NODATA munging can all elide
803 sections of the packet. Find the new length here and put back pseudoheader
804 if it was removed. */
805 return resize_packet(header, n, pheader, plen);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100806}
807
Simon Kelley3be34542004-09-11 19:12:13 +0100808/* sets new last_server */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100809void reply_query(int fd, int family, time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000810{
811 /* packet from peer server, extract data for cache, and send to
812 original requester */
Simon Kelley572b41e2011-02-18 18:11:18 +0000813 struct dns_header *header;
Simon Kelleyde379512004-06-22 20:23:33 +0100814 union mysockaddr serveraddr;
Simon Kelley832af0b2007-01-21 20:01:28 +0000815 struct frec *forward;
Simon Kelleyde379512004-06-22 20:23:33 +0100816 socklen_t addrlen = sizeof(serveraddr);
Simon Kelley60b68062014-01-08 12:10:28 +0000817 ssize_t n = recvfrom(fd, daemon->packet, daemon->packet_buff_sz, 0, &serveraddr.sa, &addrlen);
Simon Kelleycdeda282006-03-16 20:16:06 +0000818 size_t nn;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100819 struct server *server;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000820 void *hash;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000821
Simon Kelleycdeda282006-03-16 20:16:06 +0000822 /* packet buffer overwritten */
823 daemon->srv_save = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +0000824
Simon Kelleyde379512004-06-22 20:23:33 +0100825 /* Determine the address of the server replying so that we can mark that as good */
Simon Kelleyee875042018-10-23 22:10:17 +0100826 if ((serveraddr.sa.sa_family = family) == AF_INET6)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100827 serveraddr.in6.sin6_flowinfo = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000828
Simon Kelley490f9072014-03-24 22:04:42 +0000829 header = (struct dns_header *)daemon->packet;
Simon Kelley6b173352018-05-08 18:32:14 +0100830
Simon Kelley490f9072014-03-24 22:04:42 +0000831 if (n < (int)sizeof(struct dns_header) || !(header->hb3 & HB3_QR))
832 return;
833
Simon Kelley1a6bca82008-07-11 11:11:42 +0100834 /* spoof check: answer must come from known server, */
835 for (server = daemon->servers; server; server = server->next)
836 if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) &&
837 sockaddr_isequal(&server->addr, &serveraddr))
838 break;
Simon Kelley490f9072014-03-24 22:04:42 +0000839
840 if (!server)
841 return;
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000842
843 /* If sufficient time has elapsed, try and expand UDP buffer size again. */
844 if (difftime(now, server->pktsz_reduced) > UDP_TEST_TIME)
845 server->edns_pktsz = daemon->edns_pktsz;
846
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000847 hash = hash_questions(header, n, daemon->namebuff);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100848
Simon Kelley257ac0c2020-11-12 18:49:23 +0000849 if (!(forward = lookup_frec(ntohs(header->id), fd, family, hash)))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100850 return;
Simon Kelley490f9072014-03-24 22:04:42 +0000851
Simon Kelley6b173352018-05-08 18:32:14 +0100852#ifdef HAVE_DUMPFILE
853 dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_REPLY : DUMP_UP_REPLY,
854 (void *)header, n, &serveraddr, NULL);
855#endif
Simon Kelleya0088e82018-05-10 21:43:14 +0100856
Simon Kelley25cf5e32015-01-09 15:53:03 +0000857 /* log_query gets called indirectly all over the place, so
858 pass these in global variables - sorry. */
Simon Kelley15b60dd2020-11-18 18:34:55 +0000859 daemon->log_display_id = forward->frec_src.log_id;
860 daemon->log_source_addr = &forward->frec_src.source;
Simon Kelley25cf5e32015-01-09 15:53:03 +0000861
Glen Huang32fc6db2014-12-27 15:28:12 +0000862 if (daemon->ignore_addr && RCODE(header) == NOERROR &&
863 check_for_ignored_address(header, n, daemon->ignore_addr))
864 return;
865
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000866 /* Note: if we send extra options in the EDNS0 header, we can't recreate
867 the query from the reply. */
Simon Kelley34e26e12018-05-10 20:54:57 +0100868 if ((RCODE(header) == REFUSED || RCODE(header) == SERVFAIL) &&
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000869 forward->forwardall == 0 &&
870 !(forward->flags & FREC_HAS_EXTRADATA))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100871 /* for broken servers, attempt to send to another one. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000872 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100873 unsigned char *pheader;
874 size_t plen;
875 int is_sign;
Simon Kelleyef3d1372017-12-05 22:37:29 +0000876
Simon Kelley1f60a182018-05-11 16:44:16 +0100877#ifdef HAVE_DNSSEC
Simon Kelleya0088e82018-05-10 21:43:14 +0100878 if (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY))
879 {
Simon Kelley1f60a182018-05-11 16:44:16 +0100880 struct server *start;
881
Simon Kelleya0088e82018-05-10 21:43:14 +0100882 blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
883 plen = forward->stash_len;
884
885 forward->forwardall = 2; /* only retry once */
Simon Kelley1f60a182018-05-11 16:44:16 +0100886 start = forward->sentto;
887
888 /* for non-domain specific servers, see if we can find another to try. */
889 if ((forward->sentto->flags & SERV_TYPE) == 0)
890 while (1)
891 {
892 if (!(start = start->next))
893 start = daemon->servers;
894 if (start == forward->sentto)
895 break;
896
897 if ((start->flags & SERV_TYPE) == 0 &&
898 (start->flags & SERV_DO_DNSSEC))
899 break;
900 }
901
902
Simon Kelley82446112020-11-15 22:13:25 +0000903 fd = -1;
904
Simon Kelley1f60a182018-05-11 16:44:16 +0100905 if (start->sfd)
906 fd = start->sfd->fd;
Simon Kelleya0088e82018-05-10 21:43:14 +0100907 else
908 {
Simon Kelley1f60a182018-05-11 16:44:16 +0100909 if (start->addr.sa.sa_family == AF_INET6)
910 {
911 /* may have changed family */
Simon Kelley82446112020-11-15 22:13:25 +0000912 if (forward->rfd6 || (forward->rfd6 = allocate_rfd(AF_INET6)))
913 fd = forward->rfd6->fd;
Simon Kelley1f60a182018-05-11 16:44:16 +0100914 }
Simon Kelleya0088e82018-05-10 21:43:14 +0100915 else
Simon Kelley1f60a182018-05-11 16:44:16 +0100916 {
917 /* may have changed family */
Simon Kelley82446112020-11-15 22:13:25 +0000918 if (forward->rfd4 || (forward->rfd4 = allocate_rfd(AF_INET)))
919 fd = forward->rfd4->fd;
Simon Kelley1f60a182018-05-11 16:44:16 +0100920 }
Simon Kelleya0088e82018-05-10 21:43:14 +0100921 }
Simon Kelleye3002bf2019-10-11 23:30:08 +0100922
Simon Kelley82446112020-11-15 22:13:25 +0000923 /* Can't get socket. */
924 if (fd == -1)
925 return;
926
Simon Kelleye3002bf2019-10-11 23:30:08 +0100927#ifdef HAVE_DUMPFILE
928 dump_packet(DUMP_SEC_QUERY, (void *)header, (size_t)plen, NULL, &start->addr);
929#endif
930
Simon Kelleya0088e82018-05-10 21:43:14 +0100931 while (retry_send(sendto(fd, (char *)header, plen, 0,
Simon Kelley1f60a182018-05-11 16:44:16 +0100932 &start->addr.sa,
933 sa_len(&start->addr))));
Simon Kelleya0088e82018-05-10 21:43:14 +0100934
Simon Kelleye27825b2018-05-11 17:20:47 +0100935 if (start->addr.sa.sa_family == AF_INET)
Simon Kelleycc921df2019-01-02 22:48:59 +0000936 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 +0100937 else
Simon Kelleycc921df2019-01-02 22:48:59 +0000938 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 +0100939
Simon Kelleya0088e82018-05-10 21:43:14 +0100940 return;
941 }
Simon Kelley1f60a182018-05-11 16:44:16 +0100942#endif
943
Simon Kelleyef3d1372017-12-05 22:37:29 +0000944 /* In strict order mode, there must be a server later in the chain
945 left to send to, otherwise without the forwardall mechanism,
946 code further on will cycle around the list forwever if they
947 all return REFUSED. Note that server is always non-NULL before
948 this executes. */
949 if (option_bool(OPT_ORDER))
950 for (server = forward->sentto->next; server; server = server->next)
951 if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR | SERV_LOOP)))
952 break;
953
Simon Kelley1a6bca82008-07-11 11:11:42 +0100954 /* recreate query from reply */
Simon Kelley5bb88f02015-12-21 16:23:47 +0000955 pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign, NULL);
Simon Kelleyef3d1372017-12-05 22:37:29 +0000956 if (!is_sign && server)
Simon Kelley832af0b2007-01-21 20:01:28 +0000957 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100958 header->ancount = htons(0);
959 header->nscount = htons(0);
960 header->arcount = htons(0);
961 if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
962 {
swiggerbd7bfa22015-06-01 20:54:59 +0100963 header->hb3 &= ~(HB3_QR | HB3_AA | HB3_TC);
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000964 header->hb4 &= ~(HB4_RA | HB4_RCODE | HB4_CD | HB4_AD);
Simon Kelley1801a292016-01-17 21:53:57 +0000965 if (forward->flags & FREC_CHECKING_DISABLED)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000966 header->hb4 |= HB4_CD;
Simon Kelley1801a292016-01-17 21:53:57 +0000967 if (forward->flags & FREC_AD_QUESTION)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000968 header->hb4 |= HB4_AD;
969 if (forward->flags & FREC_DO_QUESTION)
Simon Kelley33702ab2015-12-28 23:17:15 +0000970 add_do_bit(header, nn, (unsigned char *)pheader + plen);
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000971 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 +0100972 return;
973 }
974 }
975 }
Simon Kelley3a237152013-12-12 12:15:50 +0000976
977 server = forward->sentto;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100978 if ((forward->sentto->flags & SERV_TYPE) == 0)
979 {
Simon Kelley51967f92014-03-25 21:07:00 +0000980 if (RCODE(header) == REFUSED)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100981 server = NULL;
982 else
983 {
984 struct server *last_server;
Simon Kelley832af0b2007-01-21 20:01:28 +0000985
Simon Kelley1a6bca82008-07-11 11:11:42 +0100986 /* find good server by address if possible, otherwise assume the last one we sent to */
987 for (last_server = daemon->servers; last_server; last_server = last_server->next)
988 if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) &&
989 sockaddr_isequal(&last_server->addr, &serveraddr))
990 {
991 server = last_server;
992 break;
993 }
994 }
Simon Kelley28866e92011-02-14 20:19:14 +0000995 if (!option_bool(OPT_ALL_SERVERS))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100996 daemon->last_server = server;
997 }
Simon Kelleya77cec82015-05-08 16:25:38 +0100998
999 /* We tried resending to this server with a smaller maximum size and got an answer.
Ville Skyttäfaaf3062018-01-14 17:32:52 +00001000 Make that permanent. To avoid reduxing the packet size for a single dropped packet,
Simon Kelley86fa1042015-05-10 13:50:59 +01001001 only do this when we get a truncated answer, or one larger than the safe size. */
Simon Kelley04db1482019-10-11 23:22:17 +01001002 if (forward->sentto->edns_pktsz > SAFE_PKTSZ && (forward->flags & FREC_TEST_PKTSZ) &&
Simon Kelley86fa1042015-05-10 13:50:59 +01001003 ((header->hb3 & HB3_TC) || n >= SAFE_PKTSZ))
Simon Kelley22dee512017-10-13 22:54:00 +01001004 {
Simon Kelley04db1482019-10-11 23:22:17 +01001005 forward->sentto->edns_pktsz = SAFE_PKTSZ;
1006 forward->sentto->pktsz_reduced = now;
Petr Mensik51cdd1a2019-07-04 20:28:08 +02001007 (void)prettyprint_addr(&forward->sentto->addr, daemon->addrbuff);
Simon Kelleyebedcba2017-10-29 20:54:17 +00001008 my_syslog(LOG_WARNING, _("reducing DNS packet size for nameserver %s to %d"), daemon->addrbuff, SAFE_PKTSZ);
Simon Kelley22dee512017-10-13 22:54:00 +01001009 }
Simon Kelleyc1a4e252018-01-19 22:00:05 +00001010
1011
Simon Kelley1a6bca82008-07-11 11:11:42 +01001012 /* If the answer is an error, keep the forward record in place in case
1013 we get a good reply from another server. Kill it when we've
1014 had replies from all to avoid filling the forwarding table when
1015 everything is broken */
Simon Kelley122392e2018-10-31 22:24:02 +00001016 if (forward->forwardall == 0 || --forward->forwardall == 1 || RCODE(header) != REFUSED)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001017 {
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001018 int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
Simon Kelleya6004d72017-10-25 17:48:19 +01001019
Simon Kelley3a237152013-12-12 12:15:50 +00001020 if (option_bool(OPT_NO_REBIND))
1021 check_rebind = !(forward->flags & FREC_NOREBIND);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001022
Simon Kelley3a237152013-12-12 12:15:50 +00001023 /* Don't cache replies where DNSSEC validation was turned off, either
1024 the upstream server told us so, or the original query specified it. */
1025 if ((header->hb4 & HB4_CD) || (forward->flags & FREC_CHECKING_DISABLED))
1026 no_cache_dnssec = 1;
1027
1028#ifdef HAVE_DNSSEC
Simon Kelley04db1482019-10-11 23:22:17 +01001029 if ((forward->sentto->flags & SERV_DO_DNSSEC) &&
Simon Kelley57573712016-01-11 22:50:00 +00001030 option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED))
Simon Kelley3a237152013-12-12 12:15:50 +00001031 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001032 int status = 0;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001033
1034 /* We've had a reply already, which we're validating. Ignore this duplicate */
Simon Kelleye0c0ad32014-01-16 22:42:07 +00001035 if (forward->blocking_query)
Simon Kelley0fc2f312014-01-08 10:26:58 +00001036 return;
Simon Kelley9a31b682015-12-15 10:20:39 +00001037
1038 /* Truncated answer can't be validated.
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001039 If this is an answer to a DNSSEC-generated query, we still
1040 need to get the client to retry over TCP, so return
1041 an answer with the TC bit set, even if the actual answer fits.
1042 */
Simon Kelley9a31b682015-12-15 10:20:39 +00001043 if (header->hb3 & HB3_TC)
1044 status = STAT_TRUNCATED;
1045
1046 while (1)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001047 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001048 /* As soon as anything returns BOGUS, we stop and unwind, to do otherwise
1049 would invite infinite loops, since the answers to DNSKEY and DS queries
1050 will not be cached, so they'll be repeated. */
1051 if (status != STAT_BOGUS && status != STAT_TRUNCATED && status != STAT_ABANDONED)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001052 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001053 if (forward->flags & FREC_DNSKEY_QUERY)
1054 status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
1055 else if (forward->flags & FREC_DS_QUERY)
1056 status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001057 else
Simon Kelley9a31b682015-12-15 10:20:39 +00001058 status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class,
Simon Kelley203ce0a2019-10-12 21:41:20 +01001059 !option_bool(OPT_DNSSEC_IGN_NS) && (forward->sentto->flags & SERV_DO_DNSSEC),
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001060 NULL, NULL, NULL);
Simon Kelley6b173352018-05-08 18:32:14 +01001061#ifdef HAVE_DUMPFILE
1062 if (status == STAT_BOGUS)
1063 dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_BOGUS : DUMP_BOGUS,
1064 header, (size_t)n, &serveraddr, NULL);
1065#endif
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001066 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001067
Simon Kelley9a31b682015-12-15 10:20:39 +00001068 /* Can't validate, as we're missing key data. Put this
1069 answer aside, whilst we get that. */
1070 if (status == STAT_NEED_DS || status == STAT_NEED_KEY)
Simon Kelley3a237152013-12-12 12:15:50 +00001071 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001072 struct frec *new, *orig;
Simon Kelley9d633042013-12-13 15:36:55 +00001073
Simon Kelley9a31b682015-12-15 10:20:39 +00001074 /* Free any saved query */
1075 if (forward->stash)
1076 blockdata_free(forward->stash);
1077
1078 /* Now save reply pending receipt of key data */
1079 if (!(forward->stash = blockdata_alloc((char *)header, n)))
Simon Kelley97e618a2015-01-07 21:55:43 +00001080 return;
Simon Kelley9a31b682015-12-15 10:20:39 +00001081 forward->stash_len = n;
Simon Kelleye0c0ad32014-01-16 22:42:07 +00001082
Simon Kelley9a31b682015-12-15 10:20:39 +00001083 /* Find the original query that started it all.... */
1084 for (orig = forward; orig->dependent; orig = orig->dependent);
Simon Kelley7fa836e2014-02-10 20:11:24 +00001085
Simon Kelley8caf3d72020-04-04 17:00:32 +01001086 /* Make sure we don't expire and free the orig frec during the
1087 allocation of a new one. */
1088 if (--orig->work_counter == 0 || !(new = get_new_frec(now, NULL, orig)))
Simon Kelley9a31b682015-12-15 10:20:39 +00001089 status = STAT_ABANDONED;
Simon Kelleye0c0ad32014-01-16 22:42:07 +00001090 else
Simon Kelley3a237152013-12-12 12:15:50 +00001091 {
Simon Kelleye1791f32018-10-06 23:23:23 +01001092 int querytype, fd, type = SERV_DO_DNSSEC;
Simon Kelley9a31b682015-12-15 10:20:39 +00001093 struct frec *next = new->next;
Simon Kelley92be34a2016-01-16 18:39:54 +00001094 char *domain;
1095
Simon Kelley9a31b682015-12-15 10:20:39 +00001096 *new = *forward; /* copy everything, then overwrite */
1097 new->next = next;
1098 new->blocking_query = NULL;
Simon Kelley92be34a2016-01-16 18:39:54 +00001099
1100 /* Find server to forward to. This will normally be the
1101 same as for the original query, but may be another if
1102 servers for domains are involved. */
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001103 if (search_servers(now, NULL, F_DNSSECOK, daemon->keyname, &type, &domain, NULL) == 0)
Simon Kelley92be34a2016-01-16 18:39:54 +00001104 {
Simon Kelley203ce0a2019-10-12 21:41:20 +01001105 struct server *start, *new_server = NULL;
1106 start = server = forward->sentto;
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001107
1108 while (1)
1109 {
1110 if (type == (start->flags & (SERV_TYPE | SERV_DO_DNSSEC)) &&
Simon Kelley1f60a182018-05-11 16:44:16 +01001111 ((type & SERV_TYPE) != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001112 !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
1113 {
1114 new_server = start;
1115 if (server == start)
1116 {
1117 new_server = NULL;
1118 break;
1119 }
1120 }
1121
1122 if (!(start = start->next))
1123 start = daemon->servers;
1124 if (start == server)
1125 break;
1126 }
1127
1128 if (new_server)
1129 server = new_server;
Simon Kelley92be34a2016-01-16 18:39:54 +00001130 }
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001131
Simon Kelley9a31b682015-12-15 10:20:39 +00001132 new->sentto = server;
1133 new->rfd4 = NULL;
Simon Kelley9a31b682015-12-15 10:20:39 +00001134 new->rfd6 = NULL;
Simon Kelley15b60dd2020-11-18 18:34:55 +00001135 new->frec_src.next = NULL;
Simon Kelleya0088e82018-05-10 21:43:14 +01001136 new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_HAS_EXTRADATA);
1137 new->forwardall = 0;
Simon Kelley9a31b682015-12-15 10:20:39 +00001138
1139 new->dependent = forward; /* to find query awaiting new one. */
1140 forward->blocking_query = new; /* for garbage cleaning */
1141 /* validate routines leave name of required record in daemon->keyname */
1142 if (status == STAT_NEED_KEY)
Simon Kelley7fa836e2014-02-10 20:11:24 +00001143 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001144 new->flags |= FREC_DNSKEY_QUERY;
Simon Kelleye1791f32018-10-06 23:23:23 +01001145 querytype = T_DNSKEY;
Simon Kelleyf1668d22014-01-08 16:53:27 +00001146 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001147 else
1148 {
1149 new->flags |= FREC_DS_QUERY;
Simon Kelleye1791f32018-10-06 23:23:23 +01001150 querytype = T_DS;
Simon Kelley9a31b682015-12-15 10:20:39 +00001151 }
Simon Kelleye1791f32018-10-06 23:23:23 +01001152
1153 nn = dnssec_generate_query(header,((unsigned char *) header) + server->edns_pktsz,
1154 daemon->keyname, forward->class, querytype, server->edns_pktsz);
1155
1156 if (server->addr.sa.sa_family == AF_INET)
Simon Kelleycc921df2019-01-02 22:48:59 +00001157 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 +01001158 querystr("dnssec-query", querytype));
Simon Kelleye1791f32018-10-06 23:23:23 +01001159 else
Simon Kelleycc921df2019-01-02 22:48:59 +00001160 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 +01001161 querystr("dnssec-query", querytype));
Simon Kelleye1791f32018-10-06 23:23:23 +01001162
Simon Kelley2d765862020-11-12 22:06:07 +00001163 memcpy(new->hash, hash_questions(header, nn, daemon->namebuff), HASH_SIZE);
Simon Kelley9a31b682015-12-15 10:20:39 +00001164 new->new_id = get_id();
1165 header->id = htons(new->new_id);
1166 /* Save query for retransmission */
1167 new->stash = blockdata_alloc((char *)header, nn);
1168 new->stash_len = nn;
1169
1170 /* Don't resend this. */
1171 daemon->srv_save = NULL;
1172
1173 if (server->sfd)
1174 fd = server->sfd->fd;
1175 else
1176 {
1177 fd = -1;
Simon Kelley9a31b682015-12-15 10:20:39 +00001178 if (server->addr.sa.sa_family == AF_INET6)
1179 {
1180 if (new->rfd6 || (new->rfd6 = allocate_rfd(AF_INET6)))
1181 fd = new->rfd6->fd;
1182 }
1183 else
Simon Kelley9a31b682015-12-15 10:20:39 +00001184 {
1185 if (new->rfd4 || (new->rfd4 = allocate_rfd(AF_INET)))
1186 fd = new->rfd4->fd;
1187 }
1188 }
1189
1190 if (fd != -1)
1191 {
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001192#ifdef HAVE_CONNTRACK
1193 /* Copy connection mark of incoming query to outgoing connection. */
1194 if (option_bool(OPT_CONNTRACK))
1195 {
1196 unsigned int mark;
Simon Kelleycc0b4482021-01-15 22:21:52 +00001197 if (get_incoming_mark(&orig->frec_src.source, &orig->frec_src.dest, 0, &mark))
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001198 setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
1199 }
1200#endif
Simon Kelley6b173352018-05-08 18:32:14 +01001201
1202#ifdef HAVE_DUMPFILE
1203 dump_packet(DUMP_SEC_QUERY, (void *)header, (size_t)nn, NULL, &server->addr);
1204#endif
1205
Simon Kelley9a31b682015-12-15 10:20:39 +00001206 while (retry_send(sendto(fd, (char *)header, nn, 0,
1207 &server->addr.sa,
1208 sa_len(&server->addr))));
1209 server->queries++;
1210 }
1211 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00001212 return;
Simon Kelley3a237152013-12-12 12:15:50 +00001213 }
Simon Kelley3a237152013-12-12 12:15:50 +00001214
Simon Kelley9a31b682015-12-15 10:20:39 +00001215 /* Validated original answer, all done. */
1216 if (!forward->dependent)
1217 break;
1218
Josh Soref730c6742017-02-06 16:14:04 +00001219 /* validated subsidiary query, (and cached result)
Simon Kelley9a31b682015-12-15 10:20:39 +00001220 pop that and return to the previous query we were working on. */
Simon Kelley0744ca62014-01-25 16:40:15 +00001221 struct frec *prev = forward->dependent;
1222 free_frec(forward);
1223 forward = prev;
1224 forward->blocking_query = NULL; /* already gone */
1225 blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
1226 n = forward->stash_len;
Simon Kelley3a237152013-12-12 12:15:50 +00001227 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001228
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001229
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001230 no_cache_dnssec = 0;
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001231
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001232 if (status == STAT_TRUNCATED)
Simon Kelley0744ca62014-01-25 16:40:15 +00001233 header->hb3 |= HB3_TC;
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001234 else
Simon Kelley7fa836e2014-02-10 20:11:24 +00001235 {
Simon Kelley554b5802015-04-17 22:50:20 +01001236 char *result, *domain = "result";
Simon Kelley7fa836e2014-02-10 20:11:24 +00001237
Simon Kelley9a31b682015-12-15 10:20:39 +00001238 if (status == STAT_ABANDONED)
Simon Kelley150162b2015-03-27 09:58:26 +00001239 {
1240 result = "ABANDONED";
1241 status = STAT_BOGUS;
1242 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00001243 else
1244 result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
1245
Simon Kelley554b5802015-04-17 22:50:20 +01001246 if (status == STAT_BOGUS && extract_request(header, n, daemon->namebuff, NULL))
1247 domain = daemon->namebuff;
Simon Kelley9a31b682015-12-15 10:20:39 +00001248
Simon Kelley07ed5852018-05-04 21:52:22 +01001249 log_query(F_SECSTAT, domain, NULL, result);
Simon Kelley7fa836e2014-02-10 20:11:24 +00001250 }
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001251
Simon Kelley3a237152013-12-12 12:15:50 +00001252 if (status == STAT_SECURE)
1253 cache_secure = 1;
Simon Kelley3a237152013-12-12 12:15:50 +00001254 else if (status == STAT_BOGUS)
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001255 {
1256 no_cache_dnssec = 1;
1257 bogusanswer = 1;
1258 }
Simon Kelley3a237152013-12-12 12:15:50 +00001259 }
Simon Kelley04db1482019-10-11 23:22:17 +01001260
Simon Kelley6b173352018-05-08 18:32:14 +01001261#endif
1262
Simon Kelley83349b82014-02-10 21:02:01 +00001263 /* restore CD bit to the value in the query */
1264 if (forward->flags & FREC_CHECKING_DISABLED)
1265 header->hb4 |= HB4_CD;
1266 else
1267 header->hb4 &= ~HB4_CD;
Simon Kelley25e63f12020-11-25 21:17:52 +00001268
1269 /* Never cache answers which are contingent on the source or MAC address EDSN0 option,
1270 since the cache is ignorant of such things. */
1271 if (forward->flags & FREC_NO_CACHE)
1272 no_cache_dnssec = 1;
Simon Kelley3a237152013-12-12 12:15:50 +00001273
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001274 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 +00001275 forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION,
Simon Kelley15b60dd2020-11-18 18:34:55 +00001276 forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->frec_src.source)))
Simon Kelley832af0b2007-01-21 20:01:28 +00001277 {
Simon Kelley15b60dd2020-11-18 18:34:55 +00001278 struct frec_src *src;
1279
1280 header->id = htons(forward->frec_src.orig_id);
Simon Kelley572b41e2011-02-18 18:11:18 +00001281 header->hb4 |= HB4_RA; /* recursion if available */
Simon Kelley5aa5f0f2015-12-21 17:20:35 +00001282#ifdef HAVE_DNSSEC
1283 /* 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 +01001284 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 +00001285 header, the answer is still bigger than 512, truncate it and mark it so. The client then retries with TCP. */
1286 if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER) && (nn > PACKETSZ))
1287 {
1288 header->ancount = htons(0);
1289 header->nscount = htons(0);
1290 header->arcount = htons(0);
1291 header->hb3 |= HB3_TC;
1292 nn = resize_packet(header, nn, NULL, 0);
1293 }
1294#endif
Simon Kelley6b173352018-05-08 18:32:14 +01001295
Simon Kelley15b60dd2020-11-18 18:34:55 +00001296 for (src = &forward->frec_src; src; src = src->next)
1297 {
1298 header->id = htons(src->orig_id);
1299
Simon Kelley6b173352018-05-08 18:32:14 +01001300#ifdef HAVE_DUMPFILE
Simon Kelley15b60dd2020-11-18 18:34:55 +00001301 dump_packet(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &src->source);
Simon Kelley6b173352018-05-08 18:32:14 +01001302#endif
Simon Kelley15b60dd2020-11-18 18:34:55 +00001303
Simon Kelley04490bf2021-01-22 16:49:12 +00001304 send_from(src->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
Simon Kelley15b60dd2020-11-18 18:34:55 +00001305 &src->source, &src->dest, src->iface);
1306
1307 if (option_bool(OPT_EXTRALOG) && src != &forward->frec_src)
1308 {
1309 daemon->log_display_id = src->log_id;
1310 daemon->log_source_addr = &src->source;
1311 log_query(F_UPSTREAM, "query", NULL, "duplicate");
1312 }
1313 }
Simon Kelley832af0b2007-01-21 20:01:28 +00001314 }
Simon Kelley15b60dd2020-11-18 18:34:55 +00001315
Simon Kelley1a6bca82008-07-11 11:11:42 +01001316 free_frec(forward); /* cancel */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001317 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001318}
Simon Kelley44a2a312004-03-10 20:04:35 +00001319
Simon Kelley1a6bca82008-07-11 11:11:42 +01001320
Simon Kelley5aabfc72007-08-29 11:24:47 +01001321void receive_query(struct listener *listen, time_t now)
Simon Kelley44a2a312004-03-10 20:04:35 +00001322{
Simon Kelley572b41e2011-02-18 18:11:18 +00001323 struct dns_header *header = (struct dns_header *)daemon->packet;
Simon Kelley44a2a312004-03-10 20:04:35 +00001324 union mysockaddr source_addr;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001325 unsigned char *pheader;
1326 unsigned short type, udp_size = PACKETSZ; /* default if no EDNS0 */
Simon Kelleycc921df2019-01-02 22:48:59 +00001327 union all_addr dst_addr;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001328 struct in_addr netmask, dst_addr_4;
Simon Kelleycdeda282006-03-16 20:16:06 +00001329 size_t m;
1330 ssize_t n;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001331 int if_index = 0, auth_dns = 0, do_bit = 0, have_pseudoheader = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001332#ifdef HAVE_AUTH
1333 int local_auth = 0;
1334#endif
Simon Kelley44a2a312004-03-10 20:04:35 +00001335 struct iovec iov[1];
1336 struct msghdr msg;
1337 struct cmsghdr *cmptr;
Simon Kelley44a2a312004-03-10 20:04:35 +00001338 union {
1339 struct cmsghdr align; /* this ensures alignment */
Simon Kelley44a2a312004-03-10 20:04:35 +00001340 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001341#if defined(HAVE_LINUX_NETWORK)
Simon Kelley44a2a312004-03-10 20:04:35 +00001342 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
Simon Kelley824af852008-02-12 20:43:05 +00001343#elif defined(IP_RECVDSTADDR) && defined(HAVE_SOLARIS_NETWORK)
1344 char control[CMSG_SPACE(sizeof(struct in_addr)) +
1345 CMSG_SPACE(sizeof(unsigned int))];
Simon Kelley44a2a312004-03-10 20:04:35 +00001346#elif defined(IP_RECVDSTADDR)
1347 char control[CMSG_SPACE(sizeof(struct in_addr)) +
1348 CMSG_SPACE(sizeof(struct sockaddr_dl))];
1349#endif
1350 } control_u;
Petr Menšík1c1b9252019-07-15 17:16:44 +02001351 int family = listen->addr.sa.sa_family;
Simon Kelley2329bef2013-12-03 13:41:16 +00001352 /* Can always get recvd interface for IPv6 */
Petr Menšík1c1b9252019-07-15 17:16:44 +02001353 int check_dst = !option_bool(OPT_NOWILD) || family == AF_INET6;
Simon Kelley2329bef2013-12-03 13:41:16 +00001354
Simon Kelleycdeda282006-03-16 20:16:06 +00001355 /* packet buffer overwritten */
1356 daemon->srv_save = NULL;
1357
Simon Kelleycc921df2019-01-02 22:48:59 +00001358 dst_addr_4.s_addr = dst_addr.addr4.s_addr = 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001359 netmask.s_addr = 0;
1360
Simon Kelley7e5664b2013-04-05 16:57:41 +01001361 if (option_bool(OPT_NOWILD) && listen->iface)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001362 {
Simon Kelley4f7b3042012-11-28 21:27:02 +00001363 auth_dns = listen->iface->dns_auth;
1364
Petr Menšík1c1b9252019-07-15 17:16:44 +02001365 if (family == AF_INET)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001366 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001367 dst_addr_4 = dst_addr.addr4 = listen->iface->addr.in.sin_addr;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001368 netmask = listen->iface->netmask;
1369 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001370 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00001371
Simon Kelley3be34542004-09-11 19:12:13 +01001372 iov[0].iov_base = daemon->packet;
1373 iov[0].iov_len = daemon->edns_pktsz;
Simon Kelley44a2a312004-03-10 20:04:35 +00001374
1375 msg.msg_control = control_u.control;
1376 msg.msg_controllen = sizeof(control_u);
1377 msg.msg_flags = 0;
1378 msg.msg_name = &source_addr;
1379 msg.msg_namelen = sizeof(source_addr);
1380 msg.msg_iov = iov;
1381 msg.msg_iovlen = 1;
1382
Simon Kelleyde379512004-06-22 20:23:33 +01001383 if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
Simon Kelley3be34542004-09-11 19:12:13 +01001384 return;
Simon Kelley44a2a312004-03-10 20:04:35 +00001385
Simon Kelley572b41e2011-02-18 18:11:18 +00001386 if (n < (int)sizeof(struct dns_header) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001387 (msg.msg_flags & MSG_TRUNC) ||
Simon Kelley572b41e2011-02-18 18:11:18 +00001388 (header->hb3 & HB3_QR))
Simon Kelley3be34542004-09-11 19:12:13 +01001389 return;
Simon Kelley63437ff2017-09-06 22:34:21 +01001390
1391 /* Clear buffer beyond request to avoid risk of
1392 information disclosure. */
1393 memset(daemon->packet + n, 0, daemon->edns_pktsz - n);
Simon Kelley44a2a312004-03-10 20:04:35 +00001394
Petr Menšík1c1b9252019-07-15 17:16:44 +02001395 source_addr.sa.sa_family = family;
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001396
Petr Menšík1c1b9252019-07-15 17:16:44 +02001397 if (family == AF_INET)
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001398 {
1399 /* Source-port == 0 is an error, we can't send back to that.
1400 http://www.ietf.org/mail-archive/web/dnsop/current/msg11441.html */
1401 if (source_addr.in.sin_port == 0)
1402 return;
1403 }
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001404 else
1405 {
1406 /* Source-port == 0 is an error, we can't send back to that. */
1407 if (source_addr.in6.sin6_port == 0)
1408 return;
1409 source_addr.in6.sin6_flowinfo = 0;
1410 }
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001411
Simon Kelleyc8a80482014-03-05 14:29:54 +00001412 /* We can be configured to only accept queries from at-most-one-hop-away addresses. */
1413 if (option_bool(OPT_LOCAL_SERVICE))
1414 {
1415 struct addrlist *addr;
Simon Kelleyee875042018-10-23 22:10:17 +01001416
Petr Menšík1c1b9252019-07-15 17:16:44 +02001417 if (family == AF_INET6)
Simon Kelleyc8a80482014-03-05 14:29:54 +00001418 {
1419 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1420 if ((addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001421 is_same_net6(&addr->addr.addr6, &source_addr.in6.sin6_addr, addr->prefixlen))
Simon Kelleyc8a80482014-03-05 14:29:54 +00001422 break;
1423 }
1424 else
Simon Kelleyc8a80482014-03-05 14:29:54 +00001425 {
1426 struct in_addr netmask;
1427 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1428 {
Richard Genoud15b1b7e2014-09-17 21:12:00 +01001429 netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
Simon Kelleyc8a80482014-03-05 14:29:54 +00001430 if (!(addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001431 is_same_net(addr->addr.addr4, source_addr.in.sin_addr, netmask))
Simon Kelleyc8a80482014-03-05 14:29:54 +00001432 break;
1433 }
1434 }
1435 if (!addr)
1436 {
Simon Kelley0c8584e2014-03-12 20:12:56 +00001437 static int warned = 0;
1438 if (!warned)
1439 {
1440 my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
1441 warned = 1;
1442 }
Simon Kelleyc8a80482014-03-05 14:29:54 +00001443 return;
1444 }
1445 }
1446
Simon Kelley2329bef2013-12-03 13:41:16 +00001447 if (check_dst)
Simon Kelley44a2a312004-03-10 20:04:35 +00001448 {
Simon Kelley8a911cc2004-03-16 18:35:52 +00001449 struct ifreq ifr;
1450
Simon Kelley26128d22004-11-14 16:43:54 +00001451 if (msg.msg_controllen < sizeof(struct cmsghdr))
1452 return;
1453
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001454#if defined(HAVE_LINUX_NETWORK)
Petr Menšík1c1b9252019-07-15 17:16:44 +02001455 if (family == AF_INET)
Simon Kelley26128d22004-11-14 16:43:54 +00001456 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelleyc72daea2012-01-05 21:33:27 +00001457 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
Simon Kelley26128d22004-11-14 16:43:54 +00001458 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001459 union {
1460 unsigned char *c;
1461 struct in_pktinfo *p;
1462 } p;
1463 p.c = CMSG_DATA(cmptr);
Simon Kelleycc921df2019-01-02 22:48:59 +00001464 dst_addr_4 = dst_addr.addr4 = p.p->ipi_spec_dst;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001465 if_index = p.p->ipi_ifindex;
Simon Kelley26128d22004-11-14 16:43:54 +00001466 }
1467#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
Petr Menšík1c1b9252019-07-15 17:16:44 +02001468 if (family == AF_INET)
Simon Kelley26128d22004-11-14 16:43:54 +00001469 {
1470 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001471 {
1472 union {
1473 unsigned char *c;
1474 unsigned int *i;
1475 struct in_addr *a;
1476#ifndef HAVE_SOLARIS_NETWORK
1477 struct sockaddr_dl *s;
Simon Kelley824af852008-02-12 20:43:05 +00001478#endif
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001479 } p;
1480 p.c = CMSG_DATA(cmptr);
1481 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
Simon Kelleycc921df2019-01-02 22:48:59 +00001482 dst_addr_4 = dst_addr.addr4 = *(p.a);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001483 else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
1484#ifdef HAVE_SOLARIS_NETWORK
1485 if_index = *(p.i);
1486#else
1487 if_index = p.s->sdl_index;
1488#endif
1489 }
Simon Kelley26128d22004-11-14 16:43:54 +00001490 }
1491#endif
1492
Petr Menšík1c1b9252019-07-15 17:16:44 +02001493 if (family == AF_INET6)
Simon Kelley26128d22004-11-14 16:43:54 +00001494 {
1495 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelleyc72daea2012-01-05 21:33:27 +00001496 if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
Simon Kelley26128d22004-11-14 16:43:54 +00001497 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001498 union {
1499 unsigned char *c;
1500 struct in6_pktinfo *p;
1501 } p;
1502 p.c = CMSG_DATA(cmptr);
1503
Simon Kelleycc921df2019-01-02 22:48:59 +00001504 dst_addr.addr6 = p.p->ipi6_addr;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001505 if_index = p.p->ipi6_ifindex;
Simon Kelley26128d22004-11-14 16:43:54 +00001506 }
1507 }
Simon Kelley26128d22004-11-14 16:43:54 +00001508
1509 /* enforce available interface configuration */
1510
Simon Kelleye25db1f2013-01-29 22:10:26 +00001511 if (!indextoname(listen->fd, if_index, ifr.ifr_name))
Simon Kelley832af0b2007-01-21 20:01:28 +00001512 return;
1513
Petr Menšík1c1b9252019-07-15 17:16:44 +02001514 if (!iface_check(family, &dst_addr, ifr.ifr_name, &auth_dns))
Simon Kelleye25db1f2013-01-29 22:10:26 +00001515 {
1516 if (!option_bool(OPT_CLEVERBIND))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001517 enumerate_interfaces(0);
Petr Menšík1c1b9252019-07-15 17:16:44 +02001518 if (!loopback_exception(listen->fd, family, &dst_addr, ifr.ifr_name) &&
1519 !label_exception(if_index, family, &dst_addr))
Simon Kelleye25db1f2013-01-29 22:10:26 +00001520 return;
1521 }
1522
Petr Menšík1c1b9252019-07-15 17:16:44 +02001523 if (family == AF_INET && option_bool(OPT_LOCALISE))
Simon Kelley552af8b2012-02-29 20:10:31 +00001524 {
1525 struct irec *iface;
1526
Josh Soref730c6742017-02-06 16:14:04 +00001527 /* get the netmask of the interface which has the address we were sent to.
klemens43517fc2017-02-19 15:53:37 +00001528 This is no necessarily the interface we arrived on. */
Simon Kelley552af8b2012-02-29 20:10:31 +00001529
1530 for (iface = daemon->interfaces; iface; iface = iface->next)
1531 if (iface->addr.sa.sa_family == AF_INET &&
1532 iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
1533 break;
1534
1535 /* interface may be new */
Simon Kelleye25db1f2013-01-29 22:10:26 +00001536 if (!iface && !option_bool(OPT_CLEVERBIND))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001537 enumerate_interfaces(0);
Simon Kelley552af8b2012-02-29 20:10:31 +00001538
1539 for (iface = daemon->interfaces; iface; iface = iface->next)
1540 if (iface->addr.sa.sa_family == AF_INET &&
1541 iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
1542 break;
1543
1544 /* If we failed, abandon localisation */
1545 if (iface)
1546 netmask = iface->netmask;
1547 else
1548 dst_addr_4.s_addr = 0;
1549 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001550 }
Simon Kelley25cf5e32015-01-09 15:53:03 +00001551
1552 /* log_query gets called indirectly all over the place, so
1553 pass these in global variables - sorry. */
1554 daemon->log_display_id = ++daemon->log_id;
1555 daemon->log_source_addr = &source_addr;
Simon Kelley6b173352018-05-08 18:32:14 +01001556
1557#ifdef HAVE_DUMPFILE
1558 dump_packet(DUMP_QUERY, daemon->packet, (size_t)n, &source_addr, NULL);
1559#endif
1560
Simon Kelleycdeda282006-03-16 20:16:06 +00001561 if (extract_request(header, (size_t)n, daemon->namebuff, &type))
Simon Kelley44a2a312004-03-10 20:04:35 +00001562 {
Simon Kelleyb485ed92013-10-18 22:00:39 +01001563#ifdef HAVE_AUTH
1564 struct auth_zone *zone;
1565#endif
Simon Kelley610e7822014-02-06 14:45:17 +00001566 char *types = querystr(auth_dns ? "auth" : "query", type);
1567
Petr Menšík1c1b9252019-07-15 17:16:44 +02001568 if (family == AF_INET)
Simon Kelley3be34542004-09-11 19:12:13 +01001569 log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
Simon Kelleycc921df2019-01-02 22:48:59 +00001570 (union all_addr *)&source_addr.in.sin_addr, types);
Simon Kelley44a2a312004-03-10 20:04:35 +00001571 else
Simon Kelley3be34542004-09-11 19:12:13 +01001572 log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
Simon Kelleycc921df2019-01-02 22:48:59 +00001573 (union all_addr *)&source_addr.in6.sin6_addr, types);
Simon Kelley44a2a312004-03-10 20:04:35 +00001574
Simon Kelley4820dce2012-12-18 18:30:30 +00001575#ifdef HAVE_AUTH
Simon Kelleyb485ed92013-10-18 22:00:39 +01001576 /* find queries for zones we're authoritative for, and answer them directly */
Simon Kelley3a3965a2015-08-09 17:45:06 +01001577 if (!auth_dns && !option_bool(OPT_LOCALISE))
Simon Kelley6008bdb2013-10-21 21:47:03 +01001578 for (zone = daemon->auth_zones; zone; zone = zone->next)
1579 if (in_zone(zone, daemon->namebuff, NULL))
1580 {
1581 auth_dns = 1;
1582 local_auth = 1;
1583 break;
1584 }
Simon Kelleyb485ed92013-10-18 22:00:39 +01001585#endif
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01001586
1587#ifdef HAVE_LOOP
1588 /* Check for forwarding loop */
1589 if (detect_loop(daemon->namebuff, type))
1590 return;
1591#endif
Simon Kelleyb485ed92013-10-18 22:00:39 +01001592 }
1593
Simon Kelley5bb88f02015-12-21 16:23:47 +00001594 if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL, NULL))
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001595 {
1596 unsigned short flags;
1597
1598 have_pseudoheader = 1;
1599 GETSHORT(udp_size, pheader);
1600 pheader += 2; /* ext_rcode */
1601 GETSHORT(flags, pheader);
1602
1603 if (flags & 0x8000)
1604 do_bit = 1;/* do bit */
1605
1606 /* If the client provides an EDNS0 UDP size, use that to limit our reply.
1607 (bounded by the maximum configured). If no EDNS0, then it
1608 defaults to 512 */
1609 if (udp_size > daemon->edns_pktsz)
1610 udp_size = daemon->edns_pktsz;
Simon Kelleya3303e12017-09-07 20:45:00 +01001611 else if (udp_size < PACKETSZ)
1612 udp_size = PACKETSZ; /* Sanity check - can't reduce below default. RFC 6891 6.2.3 */
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001613 }
1614
Simon Kelleyb485ed92013-10-18 22:00:39 +01001615#ifdef HAVE_AUTH
Simon Kelley4f7b3042012-11-28 21:27:02 +00001616 if (auth_dns)
Simon Kelley824af852008-02-12 20:43:05 +00001617 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001618 m = answer_auth(header, ((char *) header) + udp_size, (size_t)n, now, &source_addr,
1619 local_auth, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001620 if (m >= 1)
Simon Kelleyb485ed92013-10-18 22:00:39 +01001621 {
1622 send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
1623 (char *)header, m, &source_addr, &dst_addr, if_index);
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001624 daemon->metrics[METRIC_DNS_AUTH_ANSWERED]++;
Simon Kelleyb485ed92013-10-18 22:00:39 +01001625 }
Simon Kelley824af852008-02-12 20:43:05 +00001626 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001627 else
Simon Kelley4820dce2012-12-18 18:30:30 +00001628#endif
Simon Kelley4f7b3042012-11-28 21:27:02 +00001629 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001630 int ad_reqd = do_bit;
1631 /* RFC 6840 5.7 */
1632 if (header->hb4 & HB4_AD)
1633 ad_reqd = 1;
1634
1635 m = answer_request(header, ((char *) header) + udp_size, (size_t)n,
1636 dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001637
1638 if (m >= 1)
1639 {
1640 send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
1641 (char *)header, m, &source_addr, &dst_addr, if_index);
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001642 daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001643 }
1644 else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
Simon Kelley613ad152014-02-25 23:02:28 +00001645 header, (size_t)n, now, NULL, ad_reqd, do_bit))
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001646 daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]++;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001647 else
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001648 daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001649 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001650}
1651
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001652#ifdef HAVE_DNSSEC
Josh Soref730c6742017-02-06 16:14:04 +00001653/* Recurse up the key hierarchy */
Simon Kelley7fa836e2014-02-10 20:11:24 +00001654static int tcp_key_recurse(time_t now, int status, struct dns_header *header, size_t n,
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001655 int class, char *name, char *keyname, struct server *server,
1656 int have_mark, unsigned int mark, int *keycount)
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001657{
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001658 int new_status;
Simon Kelley9a31b682015-12-15 10:20:39 +00001659 unsigned char *packet = NULL;
Simon Kelley9a31b682015-12-15 10:20:39 +00001660 unsigned char *payload = NULL;
1661 struct dns_header *new_header = NULL;
1662 u16 *length = NULL;
Simon Kelley361dfe52017-02-10 21:12:30 +00001663
Simon Kelley9a31b682015-12-15 10:20:39 +00001664 while (1)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001665 {
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001666 int type = SERV_DO_DNSSEC;
1667 char *domain;
1668 size_t m;
1669 unsigned char c1, c2;
Simon Kelley361dfe52017-02-10 21:12:30 +00001670 struct server *firstsendto = NULL;
1671
Simon Kelley9a31b682015-12-15 10:20:39 +00001672 /* limit the amount of work we do, to avoid cycling forever on loops in the DNS */
1673 if (--(*keycount) == 0)
1674 new_status = STAT_ABANDONED;
1675 else if (status == STAT_NEED_KEY)
1676 new_status = dnssec_validate_by_ds(now, header, n, name, keyname, class);
1677 else if (status == STAT_NEED_DS)
1678 new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
1679 else
James Bottomleye33b4872017-03-17 21:44:10 +00001680 new_status = dnssec_validate_reply(now, header, n, name, keyname, &class,
Simon Kelleya6918532018-04-15 16:20:52 +01001681 !option_bool(OPT_DNSSEC_IGN_NS) && (server->flags & SERV_DO_DNSSEC),
Simon Kelleyfef2f1c2019-08-29 21:59:00 +01001682 NULL, NULL, NULL);
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001683
Simon Kelley9a31b682015-12-15 10:20:39 +00001684 if (new_status != STAT_NEED_DS && new_status != STAT_NEED_KEY)
1685 break;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001686
Simon Kelley9a31b682015-12-15 10:20:39 +00001687 /* Can't validate because we need a key/DS whose name now in keyname.
1688 Make query for same, and recurse to validate */
Simon Kelley7fa836e2014-02-10 20:11:24 +00001689 if (!packet)
Simon Kelley9a31b682015-12-15 10:20:39 +00001690 {
1691 packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
1692 payload = &packet[2];
1693 new_header = (struct dns_header *)payload;
1694 length = (u16 *)packet;
1695 }
1696
1697 if (!packet)
1698 {
1699 new_status = STAT_ABANDONED;
1700 break;
1701 }
Simon Kelleye1791f32018-10-06 23:23:23 +01001702
Simon Kelley33702ab2015-12-28 23:17:15 +00001703 m = dnssec_generate_query(new_header, ((unsigned char *) new_header) + 65536, keyname, class,
Simon Kelleye1791f32018-10-06 23:23:23 +01001704 new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS, server->edns_pktsz);
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001705
Simon Kelley7fa836e2014-02-10 20:11:24 +00001706 *length = htons(m);
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001707
1708 /* Find server to forward to. This will normally be the
1709 same as for the original query, but may be another if
1710 servers for domains are involved. */
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001711 if (search_servers(now, NULL, F_DNSSECOK, keyname, &type, &domain, NULL) != 0)
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001712 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001713 new_status = STAT_ABANDONED;
1714 break;
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001715 }
Simon Kelley361dfe52017-02-10 21:12:30 +00001716
Simon Kelley361dfe52017-02-10 21:12:30 +00001717 while (1)
1718 {
Simon Kelley608aa9f2019-03-10 22:44:15 +00001719 int data_sent = 0;
1720
Simon Kelley361dfe52017-02-10 21:12:30 +00001721 if (!firstsendto)
1722 firstsendto = server;
1723 else
1724 {
1725 if (!(server = server->next))
1726 server = daemon->servers;
1727 if (server == firstsendto)
1728 {
1729 /* can't find server to accept our query. */
1730 new_status = STAT_ABANDONED;
1731 break;
1732 }
1733 }
1734
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001735 if (type != (server->flags & (SERV_TYPE | SERV_DO_DNSSEC)) ||
Simon Kelley361dfe52017-02-10 21:12:30 +00001736 (type == SERV_HAS_DOMAIN && !hostname_isequal(domain, server->domain)) ||
1737 (server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
1738 continue;
Simon Kelleye1791f32018-10-06 23:23:23 +01001739
1740 retry:
1741 /* may need to make new connection. */
1742 if (server->tcpfd == -1)
1743 {
1744 if ((server->tcpfd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
1745 continue; /* No good, next server */
1746
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001747#ifdef HAVE_CONNTRACK
Simon Kelleye1791f32018-10-06 23:23:23 +01001748 /* Copy connection mark of incoming query to outgoing connection. */
1749 if (have_mark)
1750 setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001751#endif
Simon Kelleye1791f32018-10-06 23:23:23 +01001752
Simon Kelley608aa9f2019-03-10 22:44:15 +00001753 if (!local_bind(server->tcpfd, &server->source_addr, server->interface, 0, 1))
1754 {
1755 close(server->tcpfd);
1756 server->tcpfd = -1;
1757 continue; /* No good, next server */
1758 }
1759
1760#ifdef MSG_FASTOPEN
1761 while(retry_send(sendto(server->tcpfd, packet, m + sizeof(u16),
1762 MSG_FASTOPEN, &server->addr.sa, sa_len(&server->addr))));
1763
1764 if (errno == 0)
1765 data_sent = 1;
1766#endif
1767
1768 if (!data_sent && connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) == -1)
Simon Kelleye1791f32018-10-06 23:23:23 +01001769 {
1770 close(server->tcpfd);
1771 server->tcpfd = -1;
1772 continue; /* No good, next server */
1773 }
1774
1775 server->flags &= ~SERV_GOT_TCP;
1776 }
Simon Kelley361dfe52017-02-10 21:12:30 +00001777
Simon Kelley608aa9f2019-03-10 22:44:15 +00001778 if ((!data_sent && !read_write(server->tcpfd, packet, m + sizeof(u16), 0)) ||
Simon Kelley361dfe52017-02-10 21:12:30 +00001779 !read_write(server->tcpfd, &c1, 1, 1) ||
1780 !read_write(server->tcpfd, &c2, 1, 1) ||
1781 !read_write(server->tcpfd, payload, (c1 << 8) | c2, 1))
1782 {
1783 close(server->tcpfd);
1784 server->tcpfd = -1;
1785 /* We get data then EOF, reopen connection to same server,
1786 else try next. This avoids DoS from a server which accepts
1787 connections and then closes them. */
1788 if (server->flags & SERV_GOT_TCP)
1789 goto retry;
1790 else
1791 continue;
1792 }
Simon Kelleye1791f32018-10-06 23:23:23 +01001793
1794
1795 if (server->addr.sa.sa_family == AF_INET)
Simon Kelleycc921df2019-01-02 22:48:59 +00001796 log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, keyname, (union all_addr *)&(server->addr.in.sin_addr),
Simon Kelleye1791f32018-10-06 23:23:23 +01001797 querystr("dnssec-query", new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS));
Simon Kelleye1791f32018-10-06 23:23:23 +01001798 else
Simon Kelleycc921df2019-01-02 22:48:59 +00001799 log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, keyname, (union all_addr *)&(server->addr.in6.sin6_addr),
Simon Kelleye1791f32018-10-06 23:23:23 +01001800 querystr("dnssec-query", new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS));
Simon Kelley361dfe52017-02-10 21:12:30 +00001801
1802 server->flags |= SERV_GOT_TCP;
1803
1804 m = (c1 << 8) | c2;
1805 new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, have_mark, mark, keycount);
1806 break;
1807 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001808
1809 if (new_status != STAT_OK)
1810 break;
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001811 }
Simon Kelley361dfe52017-02-10 21:12:30 +00001812
Simon Kelley9a31b682015-12-15 10:20:39 +00001813 if (packet)
1814 free(packet);
1815
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001816 return new_status;
1817}
1818#endif
1819
1820
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001821/* The daemon forks before calling this: it should deal with one connection,
Josh Soref730c6742017-02-06 16:14:04 +00001822 blocking as necessary, and then return. Note, need to be a bit careful
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001823 about resources for debug mode, when the fork is suppressed: that's
1824 done by the caller. */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001825unsigned char *tcp_request(int confd, time_t now,
Simon Kelley4f7b3042012-11-28 21:27:02 +00001826 union mysockaddr *local_addr, struct in_addr netmask, int auth_dns)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001827{
Simon Kelley28866e92011-02-14 20:19:14 +00001828 size_t size = 0;
1829 int norebind = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001830#ifdef HAVE_AUTH
Simon Kelley19b16892013-10-20 10:19:39 +01001831 int local_auth = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001832#endif
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001833 int checking_disabled, do_bit, added_pheader = 0, have_pseudoheader = 0;
Simon Kelley25e63f12020-11-25 21:17:52 +00001834 int check_subnet, cacheable, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
Simon Kelleycdeda282006-03-16 20:16:06 +00001835 size_t m;
Simon Kelleyee86ce62012-12-07 11:54:46 +00001836 unsigned short qtype;
1837 unsigned int gotname;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001838 unsigned char c1, c2;
Simon Kelley4b5ea122013-04-22 10:18:26 +01001839 /* Max TCP packet + slop + size */
1840 unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
1841 unsigned char *payload = &packet[2];
1842 /* largest field in header is 16-bits, so this is still sufficiently aligned */
1843 struct dns_header *header = (struct dns_header *)payload;
1844 u16 *length = (u16 *)packet;
Simon Kelley3be34542004-09-11 19:12:13 +01001845 struct server *last_server;
Simon Kelley7de060b2011-08-26 17:24:52 +01001846 struct in_addr dst_addr_4;
1847 union mysockaddr peer_addr;
1848 socklen_t peer_len = sizeof(union mysockaddr);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001849 int query_count = 0;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001850 unsigned char *pheader;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001851 unsigned int mark = 0;
1852 int have_mark = 0;
Simon Kelley25cf5e32015-01-09 15:53:03 +00001853
Simon Kelleyd05dd582016-01-19 21:23:30 +00001854 (void)mark;
1855 (void)have_mark;
1856
Simon Kelley7de060b2011-08-26 17:24:52 +01001857 if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
1858 return packet;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001859
1860#ifdef HAVE_CONNTRACK
1861 /* Get connection mark of incoming query to set on outgoing connections. */
1862 if (option_bool(OPT_CONNTRACK))
1863 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001864 union all_addr local;
Simon Kelleyee875042018-10-23 22:10:17 +01001865
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001866 if (local_addr->sa.sa_family == AF_INET6)
Simon Kelleycc921df2019-01-02 22:48:59 +00001867 local.addr6 = local_addr->in6.sin6_addr;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001868 else
Simon Kelleycc921df2019-01-02 22:48:59 +00001869 local.addr4 = local_addr->in.sin_addr;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001870
1871 have_mark = get_incoming_mark(&peer_addr, &local, 1, &mark);
1872 }
1873#endif
1874
Simon Kelleyc8a80482014-03-05 14:29:54 +00001875 /* We can be configured to only accept queries from at-most-one-hop-away addresses. */
1876 if (option_bool(OPT_LOCAL_SERVICE))
1877 {
1878 struct addrlist *addr;
Simon Kelleyee875042018-10-23 22:10:17 +01001879
Simon Kelleyc8a80482014-03-05 14:29:54 +00001880 if (peer_addr.sa.sa_family == AF_INET6)
1881 {
1882 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1883 if ((addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001884 is_same_net6(&addr->addr.addr6, &peer_addr.in6.sin6_addr, addr->prefixlen))
Simon Kelleyc8a80482014-03-05 14:29:54 +00001885 break;
1886 }
1887 else
Simon Kelleyc8a80482014-03-05 14:29:54 +00001888 {
1889 struct in_addr netmask;
1890 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1891 {
Richard Genoud15b1b7e2014-09-17 21:12:00 +01001892 netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
Simon Kelleyc8a80482014-03-05 14:29:54 +00001893 if (!(addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001894 is_same_net(addr->addr.addr4, peer_addr.in.sin_addr, netmask))
Simon Kelleyc8a80482014-03-05 14:29:54 +00001895 break;
1896 }
1897 }
1898 if (!addr)
1899 {
1900 my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
1901 return packet;
1902 }
1903 }
Simon Kelley7de060b2011-08-26 17:24:52 +01001904
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001905 while (1)
1906 {
Simon Kelley25cf5e32015-01-09 15:53:03 +00001907 if (query_count == TCP_MAX_QUERIES ||
1908 !packet ||
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001909 !read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
1910 !(size = c1 << 8 | c2) ||
Simon Kelley4b5ea122013-04-22 10:18:26 +01001911 !read_write(confd, payload, size, 1))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001912 return packet;
1913
Simon Kelley572b41e2011-02-18 18:11:18 +00001914 if (size < (int)sizeof(struct dns_header))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001915 continue;
Simon Kelley63437ff2017-09-06 22:34:21 +01001916
1917 /* Clear buffer beyond request to avoid risk of
1918 information disclosure. */
1919 memset(payload + size, 0, 65536 - size);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001920
Simon Kelley25cf5e32015-01-09 15:53:03 +00001921 query_count++;
1922
1923 /* log_query gets called indirectly all over the place, so
1924 pass these in global variables - sorry. */
1925 daemon->log_display_id = ++daemon->log_id;
1926 daemon->log_source_addr = &peer_addr;
1927
Simon Kelley28866e92011-02-14 20:19:14 +00001928 /* save state of "cd" flag in query */
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001929 if ((checking_disabled = header->hb4 & HB4_CD))
1930 no_cache_dnssec = 1;
Simon Kelley28866e92011-02-14 20:19:14 +00001931
Simon Kelley3be34542004-09-11 19:12:13 +01001932 if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001933 {
Simon Kelleyb485ed92013-10-18 22:00:39 +01001934#ifdef HAVE_AUTH
1935 struct auth_zone *zone;
1936#endif
Simon Kelley610e7822014-02-06 14:45:17 +00001937 char *types = querystr(auth_dns ? "auth" : "query", qtype);
Simon Kelley7de060b2011-08-26 17:24:52 +01001938
1939 if (peer_addr.sa.sa_family == AF_INET)
1940 log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
Simon Kelleycc921df2019-01-02 22:48:59 +00001941 (union all_addr *)&peer_addr.in.sin_addr, types);
Simon Kelley7de060b2011-08-26 17:24:52 +01001942 else
1943 log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
Simon Kelleycc921df2019-01-02 22:48:59 +00001944 (union all_addr *)&peer_addr.in6.sin6_addr, types);
Simon Kelleyb485ed92013-10-18 22:00:39 +01001945
1946#ifdef HAVE_AUTH
1947 /* find queries for zones we're authoritative for, and answer them directly */
Simon Kelley3a3965a2015-08-09 17:45:06 +01001948 if (!auth_dns && !option_bool(OPT_LOCALISE))
Simon Kelley6008bdb2013-10-21 21:47:03 +01001949 for (zone = daemon->auth_zones; zone; zone = zone->next)
1950 if (in_zone(zone, daemon->namebuff, NULL))
1951 {
1952 auth_dns = 1;
1953 local_auth = 1;
1954 break;
1955 }
Simon Kelleyb485ed92013-10-18 22:00:39 +01001956#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001957 }
1958
Simon Kelley7de060b2011-08-26 17:24:52 +01001959 if (local_addr->sa.sa_family == AF_INET)
1960 dst_addr_4 = local_addr->in.sin_addr;
1961 else
1962 dst_addr_4.s_addr = 0;
1963
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001964 do_bit = 0;
1965
Simon Kelley5bb88f02015-12-21 16:23:47 +00001966 if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL, NULL))
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001967 {
1968 unsigned short flags;
1969
1970 have_pseudoheader = 1;
1971 pheader += 4; /* udp_size, ext_rcode */
1972 GETSHORT(flags, pheader);
1973
1974 if (flags & 0x8000)
Simon Kelley5bb88f02015-12-21 16:23:47 +00001975 do_bit = 1; /* do bit */
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001976 }
1977
Simon Kelley4820dce2012-12-18 18:30:30 +00001978#ifdef HAVE_AUTH
Simon Kelley4f7b3042012-11-28 21:27:02 +00001979 if (auth_dns)
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001980 m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr,
1981 local_auth, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001982 else
Simon Kelley4820dce2012-12-18 18:30:30 +00001983#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001984 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001985 int ad_reqd = do_bit;
1986 /* RFC 6840 5.7 */
1987 if (header->hb4 & HB4_AD)
1988 ad_reqd = 1;
1989
1990 /* m > 0 if answered from cache */
1991 m = answer_request(header, ((char *) header) + 65536, (size_t)size,
1992 dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001993
Simon Kelley4f7b3042012-11-28 21:27:02 +00001994 /* Do this by steam now we're not in the select() loop */
Simon Kelleyb842bc92015-07-12 21:09:11 +01001995 check_log_writer(1);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001996
1997 if (m == 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001998 {
Simon Kelley4f7b3042012-11-28 21:27:02 +00001999 unsigned int flags = 0;
Simon Kelleycc921df2019-01-02 22:48:59 +00002000 union all_addr *addrp = NULL;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00002001 int type = SERV_DO_DNSSEC;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002002 char *domain = NULL;
Simon Kelley6fd5d792017-10-13 22:26:40 +01002003 unsigned char *oph = find_pseudoheader(header, size, NULL, NULL, NULL, NULL);
Simon Kelleyed4c0762013-10-08 20:46:34 +01002004
Simon Kelley25e63f12020-11-25 21:17:52 +00002005 size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet, &cacheable);
Simon Kelley6fd5d792017-10-13 22:26:40 +01002006
Simon Kelley4f7b3042012-11-28 21:27:02 +00002007 if (gotname)
2008 flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
Simon Kelley6fd5d792017-10-13 22:26:40 +01002009
2010#ifdef HAVE_DNSSEC
2011 if (option_bool(OPT_DNSSEC_VALID) && (type & SERV_DO_DNSSEC))
2012 {
2013 size = add_do_bit(header, size, ((unsigned char *) header) + 65536);
2014
2015 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
2016 this allows it to select auth servers when one is returning bad data. */
2017 if (option_bool(OPT_DNSSEC_DEBUG))
2018 header->hb4 |= HB4_CD;
2019 }
2020#endif
2021
2022 /* Check if we added a pheader on forwarding - may need to
2023 strip it from the reply. */
2024 if (!oph && find_pseudoheader(header, size, NULL, NULL, NULL, NULL))
2025 added_pheader = 1;
2026
Simon Kelley367341f2016-01-12 15:58:23 +00002027 type &= ~SERV_DO_DNSSEC;
Simon Kelley367341f2016-01-12 15:58:23 +00002028
Simon Kelley4f7b3042012-11-28 21:27:02 +00002029 if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server)
2030 last_server = daemon->servers;
2031 else
2032 last_server = daemon->last_server;
2033
2034 if (!flags && last_server)
2035 {
2036 struct server *firstsendto = NULL;
Simon Kelley2d765862020-11-12 22:06:07 +00002037 unsigned char hash[HASH_SIZE];
2038 memcpy(hash, hash_questions(header, (unsigned int)size, daemon->namebuff), HASH_SIZE);
2039
Simon Kelley4f7b3042012-11-28 21:27:02 +00002040 /* Loop round available servers until we succeed in connecting to one.
Josh Soref730c6742017-02-06 16:14:04 +00002041 Note that this code subtly ensures that consecutive queries on this connection
Simon Kelley4f7b3042012-11-28 21:27:02 +00002042 which can go to the same server, do so. */
2043 while (1)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002044 {
Simon Kelley608aa9f2019-03-10 22:44:15 +00002045 int data_sent = 0;
2046
Simon Kelley4f7b3042012-11-28 21:27:02 +00002047 if (!firstsendto)
2048 firstsendto = last_server;
2049 else
2050 {
2051 if (!(last_server = last_server->next))
2052 last_server = daemon->servers;
2053
2054 if (last_server == firstsendto)
2055 break;
2056 }
2057
2058 /* server for wrong domain */
2059 if (type != (last_server->flags & SERV_TYPE) ||
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002060 (type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)) ||
2061 (last_server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
Simon Kelley7de060b2011-08-26 17:24:52 +01002062 continue;
Simon Kelley361dfe52017-02-10 21:12:30 +00002063
2064 retry:
Simon Kelley608aa9f2019-03-10 22:44:15 +00002065 *length = htons(size);
2066
Simon Kelley4f7b3042012-11-28 21:27:02 +00002067 if (last_server->tcpfd == -1)
2068 {
2069 if ((last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
2070 continue;
2071
Karl Vogele9828b62014-10-03 21:45:15 +01002072#ifdef HAVE_CONNTRACK
2073 /* Copy connection mark of incoming query to outgoing connection. */
Simon Kelleyf344dbc2016-01-18 18:04:17 +00002074 if (have_mark)
2075 setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
Simon Kelley608aa9f2019-03-10 22:44:15 +00002076#endif
Karl Vogele9828b62014-10-03 21:45:15 +01002077
Simon Kelley608aa9f2019-03-10 22:44:15 +00002078 if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 0, 1)))
2079 {
2080 close(last_server->tcpfd);
2081 last_server->tcpfd = -1;
2082 continue;
2083 }
2084
2085#ifdef MSG_FASTOPEN
2086 while(retry_send(sendto(last_server->tcpfd, packet, size + sizeof(u16),
2087 MSG_FASTOPEN, &last_server->addr.sa, sa_len(&last_server->addr))));
2088
2089 if (errno == 0)
2090 data_sent = 1;
2091#endif
2092
2093 if (!data_sent && connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1)
Simon Kelley4f7b3042012-11-28 21:27:02 +00002094 {
2095 close(last_server->tcpfd);
2096 last_server->tcpfd = -1;
2097 continue;
2098 }
2099
Simon Kelley361dfe52017-02-10 21:12:30 +00002100 last_server->flags &= ~SERV_GOT_TCP;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002101 }
2102
Simon Kelley1fc02682014-04-29 12:30:18 +01002103 /* get query name again for logging - may have been overwritten */
2104 if (!(gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
2105 strcpy(daemon->namebuff, "query");
Simon Kelley4f7b3042012-11-28 21:27:02 +00002106
Simon Kelley608aa9f2019-03-10 22:44:15 +00002107 if ((!data_sent && !read_write(last_server->tcpfd, packet, size + sizeof(u16), 0)) ||
Simon Kelley4f7b3042012-11-28 21:27:02 +00002108 !read_write(last_server->tcpfd, &c1, 1, 1) ||
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002109 !read_write(last_server->tcpfd, &c2, 1, 1) ||
2110 !read_write(last_server->tcpfd, payload, (c1 << 8) | c2, 1))
Simon Kelley7de060b2011-08-26 17:24:52 +01002111 {
2112 close(last_server->tcpfd);
2113 last_server->tcpfd = -1;
Simon Kelley361dfe52017-02-10 21:12:30 +00002114 /* We get data then EOF, reopen connection to same server,
2115 else try next. This avoids DoS from a server which accepts
2116 connections and then closes them. */
2117 if (last_server->flags & SERV_GOT_TCP)
2118 goto retry;
2119 else
2120 continue;
2121 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00002122
Simon Kelley361dfe52017-02-10 21:12:30 +00002123 last_server->flags |= SERV_GOT_TCP;
2124
Simon Kelley4f7b3042012-11-28 21:27:02 +00002125 m = (c1 << 8) | c2;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002126
Simon Kelley4f7b3042012-11-28 21:27:02 +00002127 if (last_server->addr.sa.sa_family == AF_INET)
2128 log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
Simon Kelleycc921df2019-01-02 22:48:59 +00002129 (union all_addr *)&last_server->addr.in.sin_addr, NULL);
Simon Kelley4f7b3042012-11-28 21:27:02 +00002130 else
2131 log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
Simon Kelleycc921df2019-01-02 22:48:59 +00002132 (union all_addr *)&last_server->addr.in6.sin6_addr, NULL);
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002133
2134#ifdef HAVE_DNSSEC
Simon Kelley367341f2016-01-12 15:58:23 +00002135 if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled && (last_server->flags & SERV_DO_DNSSEC))
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002136 {
Simon Kelley7fa836e2014-02-10 20:11:24 +00002137 int keycount = DNSSEC_WORK; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
Simon Kelleyf344dbc2016-01-18 18:04:17 +00002138 int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname,
2139 last_server, have_mark, mark, &keycount);
Simon Kelley554b5802015-04-17 22:50:20 +01002140 char *result, *domain = "result";
Simon Kelleyfe3992f2015-04-03 21:25:05 +01002141
Simon Kelley9a31b682015-12-15 10:20:39 +00002142 if (status == STAT_ABANDONED)
Simon Kelley150162b2015-03-27 09:58:26 +00002143 {
2144 result = "ABANDONED";
2145 status = STAT_BOGUS;
2146 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00002147 else
2148 result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
Simon Kelleye66b4df2015-04-28 20:45:57 +01002149
2150 if (status == STAT_BOGUS && extract_request(header, m, daemon->namebuff, NULL))
2151 domain = daemon->namebuff;
Simon Kelley554b5802015-04-17 22:50:20 +01002152
Simon Kelley07ed5852018-05-04 21:52:22 +01002153 log_query(F_SECSTAT, domain, NULL, result);
Simon Kelley7fa836e2014-02-10 20:11:24 +00002154
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002155 if (status == STAT_BOGUS)
Simon Kelleyfe3992f2015-04-03 21:25:05 +01002156 {
2157 no_cache_dnssec = 1;
2158 bogusanswer = 1;
2159 }
2160
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002161 if (status == STAT_SECURE)
2162 cache_secure = 1;
2163 }
2164#endif
2165
2166 /* restore CD bit to the value in the query */
2167 if (checking_disabled)
2168 header->hb4 |= HB4_CD;
2169 else
2170 header->hb4 &= ~HB4_CD;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002171
2172 /* There's no point in updating the cache, since this process will exit and
2173 lose the information after a few queries. We make this call for the alias and
2174 bogus-nxdomain side-effects. */
2175 /* If the crc of the question section doesn't match the crc we sent, then
2176 someone might be attempting to insert bogus values into the cache by
2177 sending replies containing questions and bogus answers. */
Simon Kelley2d765862020-11-12 22:06:07 +00002178 if (memcmp(hash, hash_questions(header, (unsigned int)m, daemon->namebuff), HASH_SIZE) != 0)
Simon Kelley703c7ff2014-01-25 23:46:23 +00002179 {
2180 m = 0;
2181 break;
2182 }
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002183
Simon Kelley25e63f12020-11-25 21:17:52 +00002184 /* Never cache answers which are contingent on the source or MAC address EDSN0 option,
2185 since the cache is ignorant of such things. */
2186 if (!cacheable)
2187 no_cache_dnssec = 1;
2188
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002189 m = process_reply(header, now, last_server, (unsigned int)m,
Simon Kelleye66b4df2015-04-28 20:45:57 +01002190 option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
Simon Kelleyfa14bec2015-12-20 17:12:16 +00002191 ad_reqd, do_bit, added_pheader, check_subnet, &peer_addr);
Simon Kelley4f7b3042012-11-28 21:27:02 +00002192
2193 break;
2194 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002195 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00002196
2197 /* In case of local answer or no connections made. */
2198 if (m == 0)
Simon Kelley1682d152018-08-03 20:38:18 +01002199 {
2200 m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl);
2201 if (have_pseudoheader)
2202 m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
2203 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002204 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002205 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00002206
Simon Kelleyb842bc92015-07-12 21:09:11 +01002207 check_log_writer(1);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002208
Simon Kelley4b5ea122013-04-22 10:18:26 +01002209 *length = htons(m);
2210
2211 if (m == 0 || !read_write(confd, packet, m + sizeof(u16), 0))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002212 return packet;
2213 }
2214}
2215
Simon Kelley16972692006-10-16 20:04:18 +01002216static struct frec *allocate_frec(time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002217{
Simon Kelley16972692006-10-16 20:04:18 +01002218 struct frec *f;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002219
Simon Kelley5aabfc72007-08-29 11:24:47 +01002220 if ((f = (struct frec *)whine_malloc(sizeof(struct frec))))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002221 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01002222 f->next = daemon->frec_list;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002223 f->time = now;
Simon Kelley832af0b2007-01-21 20:01:28 +00002224 f->sentto = NULL;
Simon Kelley1a6bca82008-07-11 11:11:42 +01002225 f->rfd4 = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +00002226 f->flags = 0;
Simon Kelley1a6bca82008-07-11 11:11:42 +01002227 f->rfd6 = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002228#ifdef HAVE_DNSSEC
Simon Kelley97bc7982014-01-31 10:19:52 +00002229 f->dependent = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002230 f->blocking_query = NULL;
Simon Kelley4619d942014-01-16 19:53:06 +00002231 f->stash = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002232#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +01002233 daemon->frec_list = f;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002234 }
Simon Kelley16972692006-10-16 20:04:18 +01002235
2236 return f;
2237}
2238
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002239struct randfd *allocate_rfd(int family)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002240{
2241 static int finger = 0;
2242 int i;
2243
2244 /* limit the number of sockets we have open to avoid starvation of
2245 (eg) TFTP. Once we have a reasonable number, randomness should be OK */
2246
2247 for (i = 0; i < RANDOM_SOCKS; i++)
Simon Kelley9009d742008-11-14 20:04:27 +00002248 if (daemon->randomsocks[i].refcount == 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002249 {
Simon Kelley9009d742008-11-14 20:04:27 +00002250 if ((daemon->randomsocks[i].fd = random_sock(family)) == -1)
2251 break;
2252
Simon Kelley1a6bca82008-07-11 11:11:42 +01002253 daemon->randomsocks[i].refcount = 1;
2254 daemon->randomsocks[i].family = family;
2255 return &daemon->randomsocks[i];
2256 }
2257
Simon Kelley9009d742008-11-14 20:04:27 +00002258 /* No free ones or cannot get new socket, grab an existing one */
Simon Kelley1a6bca82008-07-11 11:11:42 +01002259 for (i = 0; i < RANDOM_SOCKS; i++)
2260 {
2261 int j = (i+finger) % RANDOM_SOCKS;
Simon Kelley9009d742008-11-14 20:04:27 +00002262 if (daemon->randomsocks[j].refcount != 0 &&
2263 daemon->randomsocks[j].family == family &&
2264 daemon->randomsocks[j].refcount != 0xffff)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002265 {
2266 finger = j;
2267 daemon->randomsocks[j].refcount++;
2268 return &daemon->randomsocks[j];
2269 }
2270 }
2271
2272 return NULL; /* doom */
2273}
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002274
2275void free_rfd(struct randfd *rfd)
2276{
2277 if (rfd && --(rfd->refcount) == 0)
2278 close(rfd->fd);
2279}
2280
Simon Kelley1a6bca82008-07-11 11:11:42 +01002281static void free_frec(struct frec *f)
2282{
Simon Kelley6a6e06f2020-12-04 18:35:11 +00002283 struct frec_src *last;
Simon Kelley15b60dd2020-11-18 18:34:55 +00002284
Simon Kelley6a6e06f2020-12-04 18:35:11 +00002285 /* add back to freelist if not the record builtin to every frec. */
2286 for (last = f->frec_src.next; last && last->next; last = last->next) ;
2287 if (last)
2288 {
2289 last->next = daemon->free_frec_src;
2290 daemon->free_frec_src = f->frec_src.next;
2291 }
2292
Simon Kelley15b60dd2020-11-18 18:34:55 +00002293 f->frec_src.next = NULL;
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002294 free_rfd(f->rfd4);
Simon Kelley1a6bca82008-07-11 11:11:42 +01002295 f->rfd4 = NULL;
2296 f->sentto = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +00002297 f->flags = 0;
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002298 free_rfd(f->rfd6);
Simon Kelley1a6bca82008-07-11 11:11:42 +01002299 f->rfd6 = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002300
2301#ifdef HAVE_DNSSEC
2302 if (f->stash)
Simon Kelley0fc2f312014-01-08 10:26:58 +00002303 {
2304 blockdata_free(f->stash);
2305 f->stash = NULL;
2306 }
Simon Kelley3a237152013-12-12 12:15:50 +00002307
2308 /* Anything we're waiting on is pointless now, too */
2309 if (f->blocking_query)
2310 free_frec(f->blocking_query);
2311 f->blocking_query = NULL;
Simon Kelley39048ad2014-01-21 17:33:58 +00002312 f->dependent = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002313#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +01002314}
2315
Simon Kelley09f3b2c2017-05-09 01:34:02 +01002316
2317
Simon Kelley16972692006-10-16 20:04:18 +01002318/* if wait==NULL return a free or older than TIMEOUT record.
2319 else return *wait zero if one available, or *wait is delay to
Simon Kelley1a6bca82008-07-11 11:11:42 +01002320 when the oldest in-use record will expire. Impose an absolute
Simon Kelley3a237152013-12-12 12:15:50 +00002321 limit of 4*TIMEOUT before we wipe things (for random sockets).
Simon Kelley8caf3d72020-04-04 17:00:32 +01002322 If force is non-NULL, always return a result, even if we have
2323 to allocate above the limit, and never free the record pointed
2324 to by the force argument. */
2325struct frec *get_new_frec(time_t now, int *wait, struct frec *force)
Simon Kelley16972692006-10-16 20:04:18 +01002326{
Simon Kelley1a6bca82008-07-11 11:11:42 +01002327 struct frec *f, *oldest, *target;
Simon Kelley16972692006-10-16 20:04:18 +01002328 int count;
2329
2330 if (wait)
2331 *wait = 0;
2332
Simon Kelley1a6bca82008-07-11 11:11:42 +01002333 for (f = daemon->frec_list, oldest = NULL, target = NULL, count = 0; f; f = f->next, count++)
Simon Kelley832af0b2007-01-21 20:01:28 +00002334 if (!f->sentto)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002335 target = f;
2336 else
Simon Kelley16972692006-10-16 20:04:18 +01002337 {
Simon Kelley9a31b682015-12-15 10:20:39 +00002338#ifdef HAVE_DNSSEC
2339 /* Don't free DNSSEC sub-queries here, as we may end up with
2340 dangling references to them. They'll go when their "real" query
2341 is freed. */
Simon Kelley8caf3d72020-04-04 17:00:32 +01002342 if (!f->dependent && f != force)
Simon Kelley9a31b682015-12-15 10:20:39 +00002343#endif
2344 {
2345 if (difftime(now, f->time) >= 4*TIMEOUT)
2346 {
2347 free_frec(f);
2348 target = f;
2349 }
2350
2351
2352 if (!oldest || difftime(f->time, oldest->time) <= 0)
2353 oldest = f;
2354 }
Simon Kelley16972692006-10-16 20:04:18 +01002355 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01002356
2357 if (target)
2358 {
2359 target->time = now;
2360 return target;
2361 }
Simon Kelley16972692006-10-16 20:04:18 +01002362
2363 /* can't find empty one, use oldest if there is one
2364 and it's older than timeout */
Simon Kelley09f3b2c2017-05-09 01:34:02 +01002365 if (!force && oldest && ((int)difftime(now, oldest->time)) >= TIMEOUT)
Simon Kelley16972692006-10-16 20:04:18 +01002366 {
2367 /* keep stuff for twice timeout if we can by allocating a new
2368 record instead */
2369 if (difftime(now, oldest->time) < 2*TIMEOUT &&
2370 count <= daemon->ftabsize &&
2371 (f = allocate_frec(now)))
2372 return f;
2373
2374 if (!wait)
2375 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01002376 free_frec(oldest);
Simon Kelley16972692006-10-16 20:04:18 +01002377 oldest->time = now;
2378 }
2379 return oldest;
2380 }
2381
2382 /* none available, calculate time 'till oldest record expires */
Simon Kelley3a237152013-12-12 12:15:50 +00002383 if (!force && count > daemon->ftabsize)
Simon Kelley16972692006-10-16 20:04:18 +01002384 {
Marcelo Salhab Brogliato0da5e892013-05-31 11:49:06 +01002385 static time_t last_log = 0;
2386
Simon Kelley16972692006-10-16 20:04:18 +01002387 if (oldest && wait)
2388 *wait = oldest->time + (time_t)TIMEOUT - now;
Marcelo Salhab Brogliato0da5e892013-05-31 11:49:06 +01002389
2390 if ((int)difftime(now, last_log) > 5)
2391 {
2392 last_log = now;
2393 my_syslog(LOG_WARNING, _("Maximum number of concurrent DNS queries reached (max: %d)"), daemon->ftabsize);
2394 }
2395
Simon Kelley16972692006-10-16 20:04:18 +01002396 return NULL;
2397 }
2398
2399 if (!(f = allocate_frec(now)) && wait)
2400 /* wait one second on malloc failure */
2401 *wait = 1;
2402
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002403 return f; /* OK if malloc fails and this is NULL */
2404}
Simon Kelley09f3b2c2017-05-09 01:34:02 +01002405
Simon Kelley257ac0c2020-11-12 18:49:23 +00002406static struct frec *lookup_frec(unsigned short id, int fd, int family, void *hash)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002407{
2408 struct frec *f;
2409
Simon Kelley1a6bca82008-07-11 11:11:42 +01002410 for(f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00002411 if (f->sentto && f->new_id == id &&
Simon Kelley2d765862020-11-12 22:06:07 +00002412 (memcmp(hash, f->hash, HASH_SIZE) == 0))
Simon Kelley257ac0c2020-11-12 18:49:23 +00002413 {
2414 /* sent from random port */
2415 if (family == AF_INET && f->rfd4 && f->rfd4->fd == fd)
2416 return f;
2417
2418 if (family == AF_INET6 && f->rfd6 && f->rfd6->fd == fd)
2419 return f;
2420
2421 /* sent to upstream from bound socket. */
2422 if (f->sentto->sfd && f->sentto->sfd->fd == fd)
2423 return f;
2424 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002425
2426 return NULL;
2427}
2428
2429static struct frec *lookup_frec_by_sender(unsigned short id,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01002430 union mysockaddr *addr,
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002431 void *hash)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002432{
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002433 struct frec *f;
Simon Kelley15b60dd2020-11-18 18:34:55 +00002434 struct frec_src *src;
2435
2436 for (f = daemon->frec_list; f; f = f->next)
2437 if (f->sentto &&
2438 !(f->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) &&
2439 memcmp(hash, f->hash, HASH_SIZE) == 0)
2440 for (src = &f->frec_src; src; src = src->next)
2441 if (src->orig_id == id &&
2442 sockaddr_isequal(&src->source, addr))
2443 return f;
2444
2445 return NULL;
2446}
2447
2448static struct frec *lookup_frec_by_query(void *hash, unsigned int flags)
2449{
2450 struct frec *f;
2451
2452 /* FREC_DNSKEY and FREC_DS_QUERY are never set in flags, so the test below
Simon Kelley25e63f12020-11-25 21:17:52 +00002453 ensures that no frec created for internal DNSSEC query can be returned here.
2454
2455 Similarly FREC_NO_CACHE is never set in flags, so a query which is
2456 contigent on a particular source address EDNS0 option will never be matched. */
Simon Kelley15b60dd2020-11-18 18:34:55 +00002457
2458#define FLAGMASK (FREC_CHECKING_DISABLED | FREC_AD_QUESTION | FREC_DO_QUESTION \
Simon Kelley25e63f12020-11-25 21:17:52 +00002459 | FREC_HAS_PHEADER | FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_NO_CACHE)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002460
Simon Kelley1a6bca82008-07-11 11:11:42 +01002461 for(f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00002462 if (f->sentto &&
Simon Kelley15b60dd2020-11-18 18:34:55 +00002463 (f->flags & FLAGMASK) == flags &&
2464 memcmp(hash, f->hash, HASH_SIZE) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002465 return f;
Simon Kelley15b60dd2020-11-18 18:34:55 +00002466
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002467 return NULL;
2468}
Simon Kelley15b60dd2020-11-18 18:34:55 +00002469
Simon Kelley47a95162014-07-08 22:22:02 +01002470/* Send query packet again, if we can. */
2471void resend_query()
2472{
2473 if (daemon->srv_save)
2474 {
2475 int fd;
2476
2477 if (daemon->srv_save->sfd)
2478 fd = daemon->srv_save->sfd->fd;
2479 else if (daemon->rfd_save && daemon->rfd_save->refcount != 0)
2480 fd = daemon->rfd_save->fd;
2481 else
2482 return;
2483
Simon Kelleyff841eb2015-03-11 21:36:30 +00002484 while(retry_send(sendto(fd, daemon->packet, daemon->packet_len, 0,
2485 &daemon->srv_save->addr.sa,
2486 sa_len(&daemon->srv_save->addr))));
Simon Kelley47a95162014-07-08 22:22:02 +01002487 }
2488}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002489
Simon Kelley849a8352006-06-09 21:02:31 +01002490/* A server record is going away, remove references to it */
Simon Kelley5aabfc72007-08-29 11:24:47 +01002491void server_gone(struct server *server)
Simon Kelley849a8352006-06-09 21:02:31 +01002492{
2493 struct frec *f;
2494
Simon Kelley1a6bca82008-07-11 11:11:42 +01002495 for (f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00002496 if (f->sentto && f->sentto == server)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002497 free_frec(f);
Simon Kelley849a8352006-06-09 21:02:31 +01002498
2499 if (daemon->last_server == server)
2500 daemon->last_server = NULL;
2501
2502 if (daemon->srv_save == server)
2503 daemon->srv_save = NULL;
2504}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002505
Simon Kelley316e2732010-01-22 20:16:09 +00002506/* return unique random ids. */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002507static unsigned short get_id(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002508{
2509 unsigned short ret = 0;
Simon Kelley257ac0c2020-11-12 18:49:23 +00002510 struct frec *f;
Simon Kelley832af0b2007-01-21 20:01:28 +00002511
Simon Kelley257ac0c2020-11-12 18:49:23 +00002512 while (1)
2513 {
2514 ret = rand16();
2515
2516 /* ensure id is unique. */
2517 for (f = daemon->frec_list; f; f = f->next)
2518 if (f->sentto && f->new_id == ret)
2519 break;
2520
2521 if (!f)
2522 return ret;
2523 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002524}
2525
2526
2527
2528
2529