blob: 4f3a36663453527f6be5c80931f722294d84a934 [file] [log] [blame]
Simon Kelley50ca8552017-06-24 22:36:43 +01001/* dnsmasq is Copyright (c) 2000-2017 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 Kelley8a9be9e2014-01-25 23:17:21 +000019static struct frec *lookup_frec(unsigned short id, 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);
23static unsigned short get_id(void);
Simon Kelley1a6bca82008-07-11 11:11:42 +010024static void free_frec(struct frec *f);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000025
Simon Kelley824af852008-02-12 20:43:05 +000026/* Send a UDP packet with its source address set as "source"
Simon Kelley44a2a312004-03-10 20:04:35 +000027 unless nowild is true, when we just send it with the kernel default */
Simon Kelley29689cf2012-03-22 14:01:00 +000028int send_from(int fd, int nowild, char *packet, size_t len,
29 union mysockaddr *to, struct all_addr *source,
Simon Kelley50303b12012-04-04 22:13:17 +010030 unsigned int iface)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000031{
Simon Kelley44a2a312004-03-10 20:04:35 +000032 struct msghdr msg;
33 struct iovec iov[1];
Simon Kelley44a2a312004-03-10 20:04:35 +000034 union {
35 struct cmsghdr align; /* this ensures alignment */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010036#if defined(HAVE_LINUX_NETWORK)
Simon Kelley44a2a312004-03-10 20:04:35 +000037 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
38#elif defined(IP_SENDSRCADDR)
39 char control[CMSG_SPACE(sizeof(struct in_addr))];
40#endif
41#ifdef HAVE_IPV6
42 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
43#endif
44 } 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;
69 p.ipi_spec_dst = source->addr.addr4;
70 memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
Simon Kelley26128d22004-11-14 16:43:54 +000071 msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
Simon Kelleyc72daea2012-01-05 21:33:27 +000072 cmptr->cmsg_level = IPPROTO_IP;
Simon Kelley26128d22004-11-14 16:43:54 +000073 cmptr->cmsg_type = IP_PKTINFO;
74#elif defined(IP_SENDSRCADDR)
Simon Kelley8ef5ada2010-06-03 19:42:45 +010075 memcpy(CMSG_DATA(cmptr), &(source->addr.addr4), sizeof(source->addr.addr4));
Simon Kelley26128d22004-11-14 16:43:54 +000076 msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
77 cmptr->cmsg_level = IPPROTO_IP;
78 cmptr->cmsg_type = IP_SENDSRCADDR;
Simon Kelley44a2a312004-03-10 20:04:35 +000079#endif
Simon Kelley26128d22004-11-14 16:43:54 +000080 }
Simon Kelley26128d22004-11-14 16:43:54 +000081 else
Simon Kelleyb8187c82005-11-26 21:46:27 +000082#ifdef HAVE_IPV6
Simon Kelley26128d22004-11-14 16:43:54 +000083 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +010084 struct in6_pktinfo p;
85 p.ipi6_ifindex = iface; /* Need iface for IPv6 to handle link-local addrs */
86 p.ipi6_addr = source->addr.addr6;
87 memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
Simon Kelley26128d22004-11-14 16:43:54 +000088 msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
Simon Kelley316e2732010-01-22 20:16:09 +000089 cmptr->cmsg_type = daemon->v6pktinfo;
Simon Kelleyc72daea2012-01-05 21:33:27 +000090 cmptr->cmsg_level = IPPROTO_IPV6;
Simon Kelley26128d22004-11-14 16:43:54 +000091 }
Simon Kelley3d8df262005-08-29 12:19:27 +010092#else
Simon Kelleyc72daea2012-01-05 21:33:27 +000093 (void)iface; /* eliminate warning */
Simon Kelley26128d22004-11-14 16:43:54 +000094#endif
95 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +010096
Simon Kelleyff841eb2015-03-11 21:36:30 +000097 while (retry_send(sendmsg(fd, &msg, 0)));
98
99 /* If interface is still in DAD, EINVAL results - ignore that. */
100 if (errno != 0 && errno != EINVAL)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100101 {
Simon Kelley50303b12012-04-04 22:13:17 +0100102 my_syslog(LOG_ERR, _("failed to send packet: %s"), strerror(errno));
Simon Kelley29689cf2012-03-22 14:01:00 +0000103 return 0;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100104 }
Simon Kelley29d28dd2012-12-03 14:05:59 +0000105
Simon Kelley29689cf2012-03-22 14:01:00 +0000106 return 1;
Simon Kelley44a2a312004-03-10 20:04:35 +0000107}
108
Simon Kelley367341f2016-01-12 15:58:23 +0000109static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigned int qtype,
110 char *qdomain, int *type, char **domain, int *norebind)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100111
112{
113 /* If the query ends in the domain in one of our servers, set
114 domain to point to that name. We find the largest match to allow both
115 domain.org and sub.domain.org to exist. */
116
117 unsigned int namelen = strlen(qdomain);
118 unsigned int matchlen = 0;
119 struct server *serv;
Simon Kelley28866e92011-02-14 20:19:14 +0000120 unsigned int flags = 0;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100121
Simon Kelley3be34542004-09-11 19:12:13 +0100122 for (serv = daemon->servers; serv; serv=serv->next)
Simon Kelley09f3b2c2017-05-09 01:34:02 +0100123 if (qtype == F_DNSSECOK && !(serv->flags & SERV_DO_DNSSEC))
124 continue;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100125 /* domain matches take priority over NODOTS matches */
Simon Kelley09f3b2c2017-05-09 01:34:02 +0100126 else if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.') && namelen != 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100127 {
Simon Kelley28866e92011-02-14 20:19:14 +0000128 unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100129 *type = SERV_FOR_NODOTS;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100130 if (serv->flags & SERV_NO_ADDR)
Simon Kelley36717ee2004-09-20 19:20:58 +0100131 flags = F_NXDOMAIN;
132 else if (serv->flags & SERV_LITERAL_ADDRESS)
133 {
134 if (sflag & qtype)
135 {
136 flags = sflag;
137 if (serv->addr.sa.sa_family == AF_INET)
138 *addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100139#ifdef HAVE_IPV6
Simon Kelley36717ee2004-09-20 19:20:58 +0100140 else
141 *addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100142#endif
Simon Kelley36717ee2004-09-20 19:20:58 +0100143 }
Simon Kelley824af852008-02-12 20:43:05 +0000144 else if (!flags || (flags & F_NXDOMAIN))
Simon Kelley36717ee2004-09-20 19:20:58 +0100145 flags = F_NOERR;
146 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100147 }
148 else if (serv->flags & SERV_HAS_DOMAIN)
149 {
150 unsigned int domainlen = strlen(serv->domain);
Simon Kelleyb8187c82005-11-26 21:46:27 +0000151 char *matchstart = qdomain + namelen - domainlen;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100152 if (namelen >= domainlen &&
Simon Kelleyb8187c82005-11-26 21:46:27 +0000153 hostname_isequal(matchstart, serv->domain) &&
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100154 (domainlen == 0 || namelen == domainlen || *(matchstart-1) == '.' ))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100155 {
Simon Kelley92be34a2016-01-16 18:39:54 +0000156 if ((serv->flags & SERV_NO_REBIND) && norebind)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100157 *norebind = 1;
Simon Kelley28866e92011-02-14 20:19:14 +0000158 else
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100159 {
Simon Kelley28866e92011-02-14 20:19:14 +0000160 unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
161 /* implement priority rules for --address and --server for same domain.
162 --address wins if the address is for the correct AF
163 --server wins otherwise. */
164 if (domainlen != 0 && domainlen == matchlen)
Simon Kelley36717ee2004-09-20 19:20:58 +0100165 {
Simon Kelley28866e92011-02-14 20:19:14 +0000166 if ((serv->flags & SERV_LITERAL_ADDRESS))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100167 {
Simon Kelley28866e92011-02-14 20:19:14 +0000168 if (!(sflag & qtype) && flags == 0)
169 continue;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100170 }
Simon Kelley28866e92011-02-14 20:19:14 +0000171 else
172 {
173 if (flags & (F_IPV4 | F_IPV6))
174 continue;
175 }
Simon Kelley36717ee2004-09-20 19:20:58 +0100176 }
Simon Kelley28866e92011-02-14 20:19:14 +0000177
178 if (domainlen >= matchlen)
179 {
Simon Kelley367341f2016-01-12 15:58:23 +0000180 *type = serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_DO_DNSSEC);
Simon Kelley28866e92011-02-14 20:19:14 +0000181 *domain = serv->domain;
182 matchlen = domainlen;
183 if (serv->flags & SERV_NO_ADDR)
184 flags = F_NXDOMAIN;
185 else if (serv->flags & SERV_LITERAL_ADDRESS)
186 {
187 if (sflag & qtype)
188 {
189 flags = sflag;
190 if (serv->addr.sa.sa_family == AF_INET)
191 *addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
192#ifdef HAVE_IPV6
193 else
194 *addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
195#endif
196 }
197 else if (!flags || (flags & F_NXDOMAIN))
198 flags = F_NOERR;
199 }
200 else
201 flags = 0;
202 }
203 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100204 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100205 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100206
Simon Kelleybf05f8f2017-05-09 22:37:46 +0100207 if (flags == 0 && !(qtype & (F_QUERY | F_DNSSECOK)) &&
Simon Kelley28866e92011-02-14 20:19:14 +0000208 option_bool(OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
Simon Kelley7de060b2011-08-26 17:24:52 +0100209 /* don't forward A or AAAA queries for simple names, except the empty name */
210 flags = F_NOERR;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100211
Simon Kelley5aabfc72007-08-29 11:24:47 +0100212 if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now))
Simon Kelleyc1bb8502004-08-11 18:40:17 +0100213 flags = F_NOERR;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100214
Simon Kelley824af852008-02-12 20:43:05 +0000215 if (flags)
216 {
217 int logflags = 0;
218
219 if (flags == F_NXDOMAIN || flags == F_NOERR)
220 logflags = F_NEG | qtype;
221
Simon Kelley1a6bca82008-07-11 11:11:42 +0100222 log_query(logflags | flags | F_CONFIG | F_FORWARD, qdomain, *addrpp, NULL);
Simon Kelley824af852008-02-12 20:43:05 +0000223 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100224 else if ((*type) & SERV_USE_RESOLV)
225 {
226 *type = 0; /* use normal servers for this domain */
227 *domain = NULL;
228 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100229 return flags;
230}
Simon Kelley44a2a312004-03-10 20:04:35 +0000231
Simon Kelley824af852008-02-12 20:43:05 +0000232static int forward_query(int udpfd, union mysockaddr *udpaddr,
233 struct all_addr *dst_addr, unsigned int dst_iface,
Simon Kelley83349b82014-02-10 21:02:01 +0000234 struct dns_header *header, size_t plen, time_t now,
Simon Kelley613ad152014-02-25 23:02:28 +0000235 struct frec *forward, int ad_reqd, int do_bit)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000236{
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000237 char *domain = NULL;
Simon Kelley367341f2016-01-12 15:58:23 +0000238 int type = SERV_DO_DNSSEC, norebind = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000239 struct all_addr *addrp = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +0000240 unsigned int flags = 0;
Simon Kelleyde379512004-06-22 20:23:33 +0100241 struct server *start = NULL;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000242#ifdef HAVE_DNSSEC
243 void *hash = hash_questions(header, plen, daemon->namebuff);
Simon Kelley367341f2016-01-12 15:58:23 +0000244 int do_dnssec = 0;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000245#else
246 unsigned int crc = questions_crc(header, plen, daemon->namebuff);
247 void *hash = &crc;
248#endif
249 unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
250
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000251 (void)do_bit;
252
Simon Kelley3d8df262005-08-29 12:19:27 +0100253 /* may be no servers available. */
Simon Kelleyd05dd582016-01-19 21:23:30 +0000254 if (forward || (hash && (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash))))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000255 {
Simon Kelleya77cec82015-05-08 16:25:38 +0100256 /* If we didn't get an answer advertising a maximal packet in EDNS,
257 fall back to 1280, which should work everywhere on IPv6.
258 If that generates an answer, it will become the new default
259 for this server */
260 forward->flags |= FREC_TEST_PKTSZ;
261
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000262#ifdef HAVE_DNSSEC
Simon Kelleydac74312014-02-13 16:43:49 +0000263 /* If we've already got an answer to this query, but we're awaiting keys for validation,
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000264 there's no point retrying the query, retry the key query instead...... */
265 if (forward->blocking_query)
266 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000267 int fd, is_sign;
268 unsigned char *pheader;
Simon Kelleya77cec82015-05-08 16:25:38 +0100269
270 forward->flags &= ~FREC_TEST_PKTSZ;
271
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000272 while (forward->blocking_query)
273 forward = forward->blocking_query;
Simon Kelleya77cec82015-05-08 16:25:38 +0100274
275 forward->flags |= FREC_TEST_PKTSZ;
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000276
277 blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
278 plen = forward->stash_len;
279
Simon Kelley5bb88f02015-12-21 16:23:47 +0000280 if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000281 PUTSHORT(SAFE_PKTSZ, pheader);
Simon Kelleya77cec82015-05-08 16:25:38 +0100282
Simon Kelley2b291912014-03-21 11:13:55 +0000283 if (forward->sentto->addr.sa.sa_family == AF_INET)
Simon Kelley25cf5e32015-01-09 15:53:03 +0000284 log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (struct all_addr *)&forward->sentto->addr.in.sin_addr, "dnssec");
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000285#ifdef HAVE_IPV6
286 else
Simon Kelley25cf5e32015-01-09 15:53:03 +0000287 log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, "retry", (struct all_addr *)&forward->sentto->addr.in6.sin6_addr, "dnssec");
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000288#endif
289
290 if (forward->sentto->sfd)
291 fd = forward->sentto->sfd->fd;
292 else
293 {
294#ifdef HAVE_IPV6
295 if (forward->sentto->addr.sa.sa_family == AF_INET6)
296 fd = forward->rfd6->fd;
297 else
298#endif
299 fd = forward->rfd4->fd;
300 }
301
Simon Kelleyff841eb2015-03-11 21:36:30 +0000302 while (retry_send( sendto(fd, (char *)header, plen, 0,
303 &forward->sentto->addr.sa,
304 sa_len(&forward->sentto->addr))));
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000305
306 return 1;
307 }
308#endif
309
Simon Kelleyde379512004-06-22 20:23:33 +0100310 /* retry on existing query, send to all available servers */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000311 domain = forward->sentto->domain;
Simon Kelley824af852008-02-12 20:43:05 +0000312 forward->sentto->failed_queries++;
Simon Kelley28866e92011-02-14 20:19:14 +0000313 if (!option_bool(OPT_ORDER))
Simon Kelleyde379512004-06-22 20:23:33 +0100314 {
Simon Kelley0a852542005-03-23 20:28:59 +0000315 forward->forwardall = 1;
Simon Kelley3be34542004-09-11 19:12:13 +0100316 daemon->last_server = NULL;
Simon Kelleyde379512004-06-22 20:23:33 +0100317 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000318 type = forward->sentto->flags & SERV_TYPE;
Simon Kelley367341f2016-01-12 15:58:23 +0000319#ifdef HAVE_DNSSEC
320 do_dnssec = forward->sentto->flags & SERV_DO_DNSSEC;
321#endif
322
Simon Kelleyde379512004-06-22 20:23:33 +0100323 if (!(start = forward->sentto->next))
Simon Kelley3be34542004-09-11 19:12:13 +0100324 start = daemon->servers; /* at end of list, recycle */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000325 header->id = htons(forward->new_id);
326 }
327 else
328 {
329 if (gotname)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100330 flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000331
Simon Kelley367341f2016-01-12 15:58:23 +0000332#ifdef HAVE_DNSSEC
333 do_dnssec = type & SERV_DO_DNSSEC;
Simon Kelleyf7443d72016-01-19 20:29:57 +0000334#endif
335 type &= ~SERV_DO_DNSSEC;
Simon Kelley367341f2016-01-12 15:58:23 +0000336
Simon Kelleyd05dd582016-01-19 21:23:30 +0000337 if (daemon->servers && !flags)
338 forward = get_new_frec(now, NULL, 0);
339 /* table full - flags == 0, return REFUSED */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000340
341 if (forward)
342 {
Simon Kelley0a852542005-03-23 20:28:59 +0000343 forward->source = *udpaddr;
344 forward->dest = *dst_addr;
345 forward->iface = dst_iface;
Simon Kelley0a852542005-03-23 20:28:59 +0000346 forward->orig_id = ntohs(header->id);
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000347 forward->new_id = get_id();
Simon Kelley832af0b2007-01-21 20:01:28 +0000348 forward->fd = udpfd;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000349 memcpy(forward->hash, hash, HASH_SIZE);
Simon Kelley0a852542005-03-23 20:28:59 +0000350 forward->forwardall = 0;
Simon Kelleyed4c0762013-10-08 20:46:34 +0100351 forward->flags = 0;
Simon Kelley28866e92011-02-14 20:19:14 +0000352 if (norebind)
353 forward->flags |= FREC_NOREBIND;
Simon Kelley572b41e2011-02-18 18:11:18 +0000354 if (header->hb4 & HB4_CD)
Simon Kelley28866e92011-02-14 20:19:14 +0000355 forward->flags |= FREC_CHECKING_DISABLED;
Simon Kelley83349b82014-02-10 21:02:01 +0000356 if (ad_reqd)
357 forward->flags |= FREC_AD_QUESTION;
Simon Kelley7fa836e2014-02-10 20:11:24 +0000358#ifdef HAVE_DNSSEC
359 forward->work_counter = DNSSEC_WORK;
Simon Kelley613ad152014-02-25 23:02:28 +0000360 if (do_bit)
361 forward->flags |= FREC_DO_QUESTION;
Simon Kelley7fa836e2014-02-10 20:11:24 +0000362#endif
Simon Kelley613ad152014-02-25 23:02:28 +0000363
Simon Kelley28866e92011-02-14 20:19:14 +0000364 header->id = htons(forward->new_id);
365
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100366 /* In strict_order mode, always try servers in the order
367 specified in resolv.conf, if a domain is given
368 always try all the available servers,
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000369 otherwise, use the one last known to work. */
370
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100371 if (type == 0)
372 {
Simon Kelley28866e92011-02-14 20:19:14 +0000373 if (option_bool(OPT_ORDER))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100374 start = daemon->servers;
375 else if (!(start = daemon->last_server) ||
376 daemon->forwardcount++ > FORWARD_TEST ||
377 difftime(now, daemon->forwardtime) > FORWARD_TIME)
378 {
379 start = daemon->servers;
380 forward->forwardall = 1;
381 daemon->forwardcount = 0;
382 daemon->forwardtime = now;
383 }
384 }
385 else
Simon Kelleyde379512004-06-22 20:23:33 +0100386 {
Simon Kelley3be34542004-09-11 19:12:13 +0100387 start = daemon->servers;
Simon Kelley28866e92011-02-14 20:19:14 +0000388 if (!option_bool(OPT_ORDER))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100389 forward->forwardall = 1;
Simon Kelleyde379512004-06-22 20:23:33 +0100390 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000391 }
392 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100393
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000394 /* check for send errors here (no route to host)
395 if we fail to send to all nameservers, send back an error
396 packet straight away (helps modem users when offline) */
397
398 if (!flags && forward)
399 {
Simon Kelleyde379512004-06-22 20:23:33 +0100400 struct server *firstsentto = start;
Simon Kelley33702ab2015-12-28 23:17:15 +0000401 int subnet, forwarded = 0;
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000402 size_t edns0_len;
Simon Kelley6fd5d792017-10-13 22:26:40 +0100403 unsigned char *oph = find_pseudoheader(header, plen, NULL, NULL, NULL, NULL);
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000404
Simon Kelley25cf5e32015-01-09 15:53:03 +0000405 /* If a query is retried, use the log_id for the retry when logging the answer. */
406 forward->log_id = daemon->log_id;
407
Simon Kelley6fd5d792017-10-13 22:26:40 +0100408 plen = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->source, now, &subnet);
Simon Kelley33702ab2015-12-28 23:17:15 +0000409
Simon Kelley6fd5d792017-10-13 22:26:40 +0100410 if (subnet)
411 forward->flags |= FREC_HAS_SUBNET;
Simon Kelley33702ab2015-12-28 23:17:15 +0000412
Simon Kelley3a237152013-12-12 12:15:50 +0000413#ifdef HAVE_DNSSEC
Simon Kelley367341f2016-01-12 15:58:23 +0000414 if (option_bool(OPT_DNSSEC_VALID) && do_dnssec)
Simon Kelley0fc2f312014-01-08 10:26:58 +0000415 {
Simon Kelley6fd5d792017-10-13 22:26:40 +0100416 plen = add_do_bit(header, plen, ((unsigned char *) header) + PACKETSZ);
417
Simon Kelley5b3bf922014-01-25 17:03:07 +0000418 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
419 this allows it to select auth servers when one is returning bad data. */
420 if (option_bool(OPT_DNSSEC_DEBUG))
421 header->hb4 |= HB4_CD;
Simon Kelley613ad152014-02-25 23:02:28 +0000422
Simon Kelley0fc2f312014-01-08 10:26:58 +0000423 }
Simon Kelley3a237152013-12-12 12:15:50 +0000424#endif
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000425
Simon Kelley6fd5d792017-10-13 22:26:40 +0100426 if (find_pseudoheader(header, plen, &edns0_len, NULL, NULL, NULL))
427 {
428 /* If there wasn't a PH before, and there is now, we added it. */
429 if (!oph)
430 forward->flags |= FREC_ADDED_PHEADER;
431
432 /* If we're sending an EDNS0 with any options, we can't recreate the query from a reply. */
433 if (edns0_len > 11)
434 forward->flags |= FREC_HAS_EXTRADATA;
435 }
Simon Kelleya77cec82015-05-08 16:25:38 +0100436
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000437 while (1)
438 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000439 /* only send to servers dealing with our domain.
440 domain may be NULL, in which case server->domain
441 must be NULL also. */
442
Simon Kelleyde379512004-06-22 20:23:33 +0100443 if (type == (start->flags & SERV_TYPE) &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100444 (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +0100445 !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000446 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100447 int fd;
448
449 /* find server socket to use, may need to get random one. */
450 if (start->sfd)
451 fd = start->sfd->fd;
452 else
453 {
454#ifdef HAVE_IPV6
455 if (start->addr.sa.sa_family == AF_INET6)
456 {
457 if (!forward->rfd6 &&
458 !(forward->rfd6 = allocate_rfd(AF_INET6)))
459 break;
Simon Kelley3927da42008-07-20 15:10:39 +0100460 daemon->rfd_save = forward->rfd6;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100461 fd = forward->rfd6->fd;
462 }
463 else
464#endif
465 {
466 if (!forward->rfd4 &&
467 !(forward->rfd4 = allocate_rfd(AF_INET)))
468 break;
Simon Kelley3927da42008-07-20 15:10:39 +0100469 daemon->rfd_save = forward->rfd4;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100470 fd = forward->rfd4->fd;
471 }
Simon Kelley7de060b2011-08-26 17:24:52 +0100472
473#ifdef HAVE_CONNTRACK
474 /* Copy connection mark of incoming query to outgoing connection. */
475 if (option_bool(OPT_CONNTRACK))
476 {
477 unsigned int mark;
Giacomo Tazzari797a7af2013-04-22 13:16:37 +0100478 if (get_incoming_mark(&forward->source, &forward->dest, 0, &mark))
Simon Kelley7de060b2011-08-26 17:24:52 +0100479 setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
480 }
481#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +0100482 }
483
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000484#ifdef HAVE_DNSSEC
Simon Kelley5bb88f02015-12-21 16:23:47 +0000485 if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER))
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000486 {
487 /* Difficult one here. If our client didn't send EDNS0, we will have set the UDP
488 packet size to 512. But that won't provide space for the RRSIGS in many cases.
489 The RRSIGS will be stripped out before the answer goes back, so the packet should
490 shrink again. So, if we added a do-bit, bump the udp packet size to the value
Simon Kelley5aa5f0f2015-12-21 17:20:35 +0000491 known to be OK for this server. We check returned size after stripping and set
492 the truncated bit if it's still too big. */
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000493 unsigned char *pheader;
494 int is_sign;
Simon Kelley5bb88f02015-12-21 16:23:47 +0000495 if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000496 PUTSHORT(start->edns_pktsz, pheader);
497 }
498#endif
499
Simon Kelleyff841eb2015-03-11 21:36:30 +0000500 if (retry_send(sendto(fd, (char *)header, plen, 0,
501 &start->addr.sa,
502 sa_len(&start->addr))))
503 continue;
504
505 if (errno == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000506 {
Simon Kelleycdeda282006-03-16 20:16:06 +0000507 /* Keep info in case we want to re-send this packet */
508 daemon->srv_save = start;
509 daemon->packet_len = plen;
510
Simon Kelleyde379512004-06-22 20:23:33 +0100511 if (!gotname)
Simon Kelley3be34542004-09-11 19:12:13 +0100512 strcpy(daemon->namebuff, "query");
Simon Kelleyde379512004-06-22 20:23:33 +0100513 if (start->addr.sa.sa_family == AF_INET)
Simon Kelley3be34542004-09-11 19:12:13 +0100514 log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
Simon Kelley1a6bca82008-07-11 11:11:42 +0100515 (struct all_addr *)&start->addr.in.sin_addr, NULL);
Simon Kelleyde379512004-06-22 20:23:33 +0100516#ifdef HAVE_IPV6
517 else
Simon Kelley3be34542004-09-11 19:12:13 +0100518 log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
Simon Kelley1a6bca82008-07-11 11:11:42 +0100519 (struct all_addr *)&start->addr.in6.sin6_addr, NULL);
Simon Kelleyde379512004-06-22 20:23:33 +0100520#endif
Simon Kelley824af852008-02-12 20:43:05 +0000521 start->queries++;
Simon Kelleyde379512004-06-22 20:23:33 +0100522 forwarded = 1;
523 forward->sentto = start;
Simon Kelley0a852542005-03-23 20:28:59 +0000524 if (!forward->forwardall)
Simon Kelleyde379512004-06-22 20:23:33 +0100525 break;
Simon Kelley0a852542005-03-23 20:28:59 +0000526 forward->forwardall++;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000527 }
528 }
529
Simon Kelleyde379512004-06-22 20:23:33 +0100530 if (!(start = start->next))
Simon Kelley3be34542004-09-11 19:12:13 +0100531 start = daemon->servers;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000532
Simon Kelleyde379512004-06-22 20:23:33 +0100533 if (start == firstsentto)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000534 break;
535 }
536
Simon Kelleyde379512004-06-22 20:23:33 +0100537 if (forwarded)
Simon Kelley824af852008-02-12 20:43:05 +0000538 return 1;
Simon Kelleyde379512004-06-22 20:23:33 +0100539
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000540 /* could not send on, prepare to return */
541 header->id = htons(forward->orig_id);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100542 free_frec(forward); /* cancel */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000543 }
544
545 /* could not send on, return empty answer or address if known for whole domain */
Simon Kelleyb8187c82005-11-26 21:46:27 +0000546 if (udpfd != -1)
547 {
Simon Kelleycdeda282006-03-16 20:16:06 +0000548 plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl);
Simon Kelley54dd3932012-06-20 11:23:38 +0100549 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 +0000550 }
551
Simon Kelley824af852008-02-12 20:43:05 +0000552 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000553}
554
Simon Kelleyed4c0762013-10-08 20:46:34 +0100555static 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 +0100556 int no_cache, int cache_secure, int bogusanswer, int ad_reqd, int do_bit, int added_pheader,
557 int check_subnet, union mysockaddr *query_source)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100558{
Simon Kelley36717ee2004-09-20 19:20:58 +0100559 unsigned char *pheader, *sizep;
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000560 char **sets = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +0000561 int munged = 0, is_sign;
Simon Kelleycdeda282006-03-16 20:16:06 +0000562 size_t plen;
563
Simon Kelley83349b82014-02-10 21:02:01 +0000564 (void)ad_reqd;
Simon Kelley982faf42015-04-03 21:42:30 +0100565 (void)do_bit;
566 (void)bogusanswer;
Simon Kelley83349b82014-02-10 21:02:01 +0000567
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000568#ifdef HAVE_IPSET
Simon Kelley82a14af2014-04-13 20:48:57 +0100569 if (daemon->ipsets && extract_request(header, n, daemon->namebuff, NULL))
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000570 {
Simon Kelley82a14af2014-04-13 20:48:57 +0100571 /* Similar algorithm to search_servers. */
572 struct ipsets *ipset_pos;
573 unsigned int namelen = strlen(daemon->namebuff);
574 unsigned int matchlen = 0;
575 for (ipset_pos = daemon->ipsets; ipset_pos; ipset_pos = ipset_pos->next)
Simon Kelley6c0cb852014-01-17 14:40:46 +0000576 {
Simon Kelley82a14af2014-04-13 20:48:57 +0100577 unsigned int domainlen = strlen(ipset_pos->domain);
578 char *matchstart = daemon->namebuff + namelen - domainlen;
579 if (namelen >= domainlen && hostname_isequal(matchstart, ipset_pos->domain) &&
580 (domainlen == 0 || namelen == domainlen || *(matchstart - 1) == '.' ) &&
581 domainlen >= matchlen)
582 {
583 matchlen = domainlen;
584 sets = ipset_pos->sets;
585 }
Simon Kelley6c0cb852014-01-17 14:40:46 +0000586 }
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000587 }
588#endif
589
Simon Kelley5bb88f02015-12-21 16:23:47 +0000590 if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign, NULL)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100591 {
Simon Kelleyed4c0762013-10-08 20:46:34 +0100592 if (check_subnet && !check_source(header, plen, pheader, query_source))
593 {
594 my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch"));
595 return 0;
596 }
Simon Kelley613ad152014-02-25 23:02:28 +0000597
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000598 if (!is_sign)
Simon Kelley613ad152014-02-25 23:02:28 +0000599 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000600 if (added_pheader)
601 {
602 /* client didn't send EDNS0, we added one, strip it off before returning answer. */
603 n = rrfilter(header, n, 0);
604 pheader = NULL;
605 }
606 else
607 {
Simon Kelley33702ab2015-12-28 23:17:15 +0000608 unsigned short udpsz;
609
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000610 /* If upstream is advertising a larger UDP packet size
611 than we allow, trim it so that we don't get overlarge
612 requests for the client. We can't do this for signed packets. */
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000613 GETSHORT(udpsz, sizep);
614 if (udpsz > daemon->edns_pktsz)
Simon Kelley33702ab2015-12-28 23:17:15 +0000615 {
616 sizep -= 2;
617 PUTSHORT(daemon->edns_pktsz, sizep);
618 }
619
620#ifdef HAVE_DNSSEC
621 /* If the client didn't set the do bit, but we did, reset it. */
622 if (option_bool(OPT_DNSSEC_VALID) && !do_bit)
623 {
624 unsigned short flags;
625 sizep += 2; /* skip RCODE */
626 GETSHORT(flags, sizep);
627 flags &= ~0x8000;
628 sizep -= 2;
629 PUTSHORT(flags, sizep);
630 }
631#endif
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000632 }
Simon Kelley613ad152014-02-25 23:02:28 +0000633 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100634 }
Simon Kelley83349b82014-02-10 21:02:01 +0000635
Simon Kelley28866e92011-02-14 20:19:14 +0000636 /* RFC 4035 sect 4.6 para 3 */
Giovanni Bajo237724c2012-04-05 02:46:52 +0200637 if (!is_sign && !option_bool(OPT_DNSSEC_PROXY))
Simon Kelley795501b2014-01-08 18:11:55 +0000638 header->hb4 &= ~HB4_AD;
Simon Kelley3a237152013-12-12 12:15:50 +0000639
Simon Kelley572b41e2011-02-18 18:11:18 +0000640 if (OPCODE(header) != QUERY || (RCODE(header) != NOERROR && RCODE(header) != NXDOMAIN))
Simon Kelley8938ae02014-05-01 17:46:25 +0100641 return resize_packet(header, n, pheader, plen);
Simon Kelley36717ee2004-09-20 19:20:58 +0100642
Simon Kelley0a852542005-03-23 20:28:59 +0000643 /* Complain loudly if the upstream server is non-recursive. */
Simon Kelley92be34a2016-01-16 18:39:54 +0000644 if (!(header->hb4 & HB4_RA) && RCODE(header) == NOERROR &&
Simon Kelley0a852542005-03-23 20:28:59 +0000645 server && !(server->flags & SERV_WARNED_RECURSIVE))
646 {
Simon Kelley3d8df262005-08-29 12:19:27 +0100647 prettyprint_addr(&server->addr, daemon->namebuff);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100648 my_syslog(LOG_WARNING, _("nameserver %s refused to do a recursive query"), daemon->namebuff);
Simon Kelley28866e92011-02-14 20:19:14 +0000649 if (!option_bool(OPT_LOG))
Simon Kelley0a852542005-03-23 20:28:59 +0000650 server->flags |= SERV_WARNED_RECURSIVE;
651 }
Giovanni Bajoe292e932012-04-22 14:32:02 +0200652
Simon Kelley572b41e2011-02-18 18:11:18 +0000653 if (daemon->bogus_addr && RCODE(header) != NXDOMAIN &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100654 check_for_bogus_wildcard(header, n, daemon->namebuff, daemon->bogus_addr, now))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100655 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100656 munged = 1;
Simon Kelley572b41e2011-02-18 18:11:18 +0000657 SET_RCODE(header, NXDOMAIN);
658 header->hb3 &= ~HB3_AA;
Simon Kelley6938f342014-01-26 22:47:39 +0000659 cache_secure = 0;
Simon Kelley36717ee2004-09-20 19:20:58 +0100660 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100661 else
Simon Kelley36717ee2004-09-20 19:20:58 +0100662 {
Simon Kelley6938f342014-01-26 22:47:39 +0000663 int doctored = 0;
664
Simon Kelley572b41e2011-02-18 18:11:18 +0000665 if (RCODE(header) == NXDOMAIN &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100666 extract_request(header, n, daemon->namebuff, NULL) &&
Simon Kelley5aabfc72007-08-29 11:24:47 +0100667 check_for_local_domain(daemon->namebuff, now))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100668 {
Simon Kelley36717ee2004-09-20 19:20:58 +0100669 /* if we forwarded a query for a locally known name (because it was for
670 an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
671 since we know that the domain exists, even if upstream doesn't */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100672 munged = 1;
Simon Kelley572b41e2011-02-18 18:11:18 +0000673 header->hb3 |= HB3_AA;
674 SET_RCODE(header, NOERROR);
Simon Kelley6938f342014-01-26 22:47:39 +0000675 cache_secure = 0;
Simon Kelley36717ee2004-09-20 19:20:58 +0100676 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000677
Simon Kelley6938f342014-01-26 22:47:39 +0000678 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 +0000679 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100680 my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
Simon Kelley824af852008-02-12 20:43:05 +0000681 munged = 1;
Simon Kelley6938f342014-01-26 22:47:39 +0000682 cache_secure = 0;
Simon Kelley824af852008-02-12 20:43:05 +0000683 }
Simon Kelley6938f342014-01-26 22:47:39 +0000684
685 if (doctored)
686 cache_secure = 0;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100687 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100688
Simon Kelleya25720a2014-01-14 23:13:55 +0000689#ifdef HAVE_DNSSEC
Simon Kelley33702ab2015-12-28 23:17:15 +0000690 if (bogusanswer && !(header->hb4 & HB4_CD) && !option_bool(OPT_DNSSEC_DEBUG))
Simon Kelleya25720a2014-01-14 23:13:55 +0000691 {
Simon Kelley33702ab2015-12-28 23:17:15 +0000692 /* Bogus reply, turn into SERVFAIL */
693 SET_RCODE(header, SERVFAIL);
694 munged = 1;
Simon Kelleya25720a2014-01-14 23:13:55 +0000695 }
Simon Kelley6938f342014-01-26 22:47:39 +0000696
697 if (option_bool(OPT_DNSSEC_VALID))
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000698 {
699 header->hb4 &= ~HB4_AD;
700
701 if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure)
702 header->hb4 |= HB4_AD;
703
704 /* If the requestor didn't set the DO bit, don't return DNSSEC info. */
705 if (!do_bit)
706 n = rrfilter(header, n, 1);
707 }
Simon Kelleya25720a2014-01-14 23:13:55 +0000708#endif
709
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100710 /* do this after extract_addresses. Ensure NODATA reply and remove
711 nameserver info. */
712
713 if (munged)
714 {
715 header->ancount = htons(0);
716 header->nscount = htons(0);
717 header->arcount = htons(0);
Simon Kelley150162b2015-03-27 09:58:26 +0000718 header->hb3 &= ~HB3_TC;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100719 }
720
Simon Kelley36717ee2004-09-20 19:20:58 +0100721 /* the bogus-nxdomain stuff, doctor and NXDOMAIN->NODATA munging can all elide
722 sections of the packet. Find the new length here and put back pseudoheader
723 if it was removed. */
724 return resize_packet(header, n, pheader, plen);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100725}
726
Simon Kelley3be34542004-09-11 19:12:13 +0100727/* sets new last_server */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100728void reply_query(int fd, int family, time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000729{
730 /* packet from peer server, extract data for cache, and send to
731 original requester */
Simon Kelley572b41e2011-02-18 18:11:18 +0000732 struct dns_header *header;
Simon Kelleyde379512004-06-22 20:23:33 +0100733 union mysockaddr serveraddr;
Simon Kelley832af0b2007-01-21 20:01:28 +0000734 struct frec *forward;
Simon Kelleyde379512004-06-22 20:23:33 +0100735 socklen_t addrlen = sizeof(serveraddr);
Simon Kelley60b68062014-01-08 12:10:28 +0000736 ssize_t n = recvfrom(fd, daemon->packet, daemon->packet_buff_sz, 0, &serveraddr.sa, &addrlen);
Simon Kelleycdeda282006-03-16 20:16:06 +0000737 size_t nn;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100738 struct server *server;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000739 void *hash;
740#ifndef HAVE_DNSSEC
741 unsigned int crc;
742#endif
743
Simon Kelleycdeda282006-03-16 20:16:06 +0000744 /* packet buffer overwritten */
745 daemon->srv_save = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +0000746
Simon Kelleyde379512004-06-22 20:23:33 +0100747 /* Determine the address of the server replying so that we can mark that as good */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100748 serveraddr.sa.sa_family = family;
Simon Kelleyde379512004-06-22 20:23:33 +0100749#ifdef HAVE_IPV6
750 if (serveraddr.sa.sa_family == AF_INET6)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100751 serveraddr.in6.sin6_flowinfo = 0;
Simon Kelleyde379512004-06-22 20:23:33 +0100752#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000753
Simon Kelley490f9072014-03-24 22:04:42 +0000754 header = (struct dns_header *)daemon->packet;
755
756 if (n < (int)sizeof(struct dns_header) || !(header->hb3 & HB3_QR))
757 return;
758
Simon Kelley1a6bca82008-07-11 11:11:42 +0100759 /* spoof check: answer must come from known server, */
760 for (server = daemon->servers; server; server = server->next)
761 if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) &&
762 sockaddr_isequal(&server->addr, &serveraddr))
763 break;
Simon Kelley490f9072014-03-24 22:04:42 +0000764
765 if (!server)
766 return;
767
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000768#ifdef HAVE_DNSSEC
769 hash = hash_questions(header, n, daemon->namebuff);
770#else
771 hash = &crc;
772 crc = questions_crc(header, n, daemon->namebuff);
773#endif
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100774
Simon Kelley490f9072014-03-24 22:04:42 +0000775 if (!(forward = lookup_frec(ntohs(header->id), hash)))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100776 return;
Simon Kelley490f9072014-03-24 22:04:42 +0000777
Simon Kelley25cf5e32015-01-09 15:53:03 +0000778 /* log_query gets called indirectly all over the place, so
779 pass these in global variables - sorry. */
780 daemon->log_display_id = forward->log_id;
781 daemon->log_source_addr = &forward->source;
782
Glen Huang32fc6db2014-12-27 15:28:12 +0000783 if (daemon->ignore_addr && RCODE(header) == NOERROR &&
784 check_for_ignored_address(header, n, daemon->ignore_addr))
785 return;
786
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000787 /* Note: if we send extra options in the EDNS0 header, we can't recreate
788 the query from the reply. */
Simon Kelley2ae195f2015-01-18 22:20:48 +0000789 if (RCODE(header) == REFUSED &&
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000790 forward->forwardall == 0 &&
791 !(forward->flags & FREC_HAS_EXTRADATA))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100792 /* for broken servers, attempt to send to another one. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000793 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100794 unsigned char *pheader;
795 size_t plen;
796 int is_sign;
Simon Kelley832af0b2007-01-21 20:01:28 +0000797
Simon Kelley1a6bca82008-07-11 11:11:42 +0100798 /* recreate query from reply */
Simon Kelley5bb88f02015-12-21 16:23:47 +0000799 pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100800 if (!is_sign)
Simon Kelley832af0b2007-01-21 20:01:28 +0000801 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100802 header->ancount = htons(0);
803 header->nscount = htons(0);
804 header->arcount = htons(0);
805 if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
806 {
swiggerbd7bfa22015-06-01 20:54:59 +0100807 header->hb3 &= ~(HB3_QR | HB3_AA | HB3_TC);
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000808 header->hb4 &= ~(HB4_RA | HB4_RCODE | HB4_CD | HB4_AD);
Simon Kelley1801a292016-01-17 21:53:57 +0000809 if (forward->flags & FREC_CHECKING_DISABLED)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000810 header->hb4 |= HB4_CD;
Simon Kelley1801a292016-01-17 21:53:57 +0000811 if (forward->flags & FREC_AD_QUESTION)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000812 header->hb4 |= HB4_AD;
813 if (forward->flags & FREC_DO_QUESTION)
Simon Kelley33702ab2015-12-28 23:17:15 +0000814 add_do_bit(header, nn, (unsigned char *)pheader + plen);
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000815 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 +0100816 return;
817 }
818 }
819 }
Simon Kelley3a237152013-12-12 12:15:50 +0000820
821 server = forward->sentto;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100822 if ((forward->sentto->flags & SERV_TYPE) == 0)
823 {
Simon Kelley51967f92014-03-25 21:07:00 +0000824 if (RCODE(header) == REFUSED)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100825 server = NULL;
826 else
827 {
828 struct server *last_server;
Simon Kelley832af0b2007-01-21 20:01:28 +0000829
Simon Kelley1a6bca82008-07-11 11:11:42 +0100830 /* find good server by address if possible, otherwise assume the last one we sent to */
831 for (last_server = daemon->servers; last_server; last_server = last_server->next)
832 if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) &&
833 sockaddr_isequal(&last_server->addr, &serveraddr))
834 {
835 server = last_server;
836 break;
837 }
838 }
Simon Kelley28866e92011-02-14 20:19:14 +0000839 if (!option_bool(OPT_ALL_SERVERS))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100840 daemon->last_server = server;
841 }
Simon Kelleya77cec82015-05-08 16:25:38 +0100842
843 /* We tried resending to this server with a smaller maximum size and got an answer.
Simon Kelley86fa1042015-05-10 13:50:59 +0100844 Make that permanent. To avoid reduxing the packet size for an single dropped packet,
845 only do this when we get a truncated answer, or one larger than the safe size. */
846 if (server && (forward->flags & FREC_TEST_PKTSZ) &&
847 ((header->hb3 & HB3_TC) || n >= SAFE_PKTSZ))
Simon Kelley22dee512017-10-13 22:54:00 +0100848 {
849 server->edns_pktsz = SAFE_PKTSZ;
850 prettyprint_addr(&server->addr, daemon->addrbuff);
851 my_syslog(LOG_WARNING, _("reducing DNS packet size for nameserver %s to %n"), daemon->addrbuff, SAFE_PKTSZ);
852 }
Simon Kelleya77cec82015-05-08 16:25:38 +0100853
Simon Kelley1a6bca82008-07-11 11:11:42 +0100854 /* If the answer is an error, keep the forward record in place in case
855 we get a good reply from another server. Kill it when we've
856 had replies from all to avoid filling the forwarding table when
857 everything is broken */
Baptiste Jonglez68f63122017-02-06 21:09:11 +0000858 if (forward->forwardall == 0 || --forward->forwardall == 1 ||
859 (RCODE(header) != REFUSED && RCODE(header) != SERVFAIL))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100860 {
Simon Kelleyfe3992f2015-04-03 21:25:05 +0100861 int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100862
Simon Kelley3a237152013-12-12 12:15:50 +0000863 if (option_bool(OPT_NO_REBIND))
864 check_rebind = !(forward->flags & FREC_NOREBIND);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100865
Simon Kelley3a237152013-12-12 12:15:50 +0000866 /* Don't cache replies where DNSSEC validation was turned off, either
867 the upstream server told us so, or the original query specified it. */
868 if ((header->hb4 & HB4_CD) || (forward->flags & FREC_CHECKING_DISABLED))
869 no_cache_dnssec = 1;
870
871#ifdef HAVE_DNSSEC
Simon Kelley367341f2016-01-12 15:58:23 +0000872 if (server && (server->flags & SERV_DO_DNSSEC) &&
Simon Kelley57573712016-01-11 22:50:00 +0000873 option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED))
Simon Kelley3a237152013-12-12 12:15:50 +0000874 {
Simon Kelley9a31b682015-12-15 10:20:39 +0000875 int status = 0;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000876
877 /* We've had a reply already, which we're validating. Ignore this duplicate */
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000878 if (forward->blocking_query)
Simon Kelley0fc2f312014-01-08 10:26:58 +0000879 return;
Simon Kelley9a31b682015-12-15 10:20:39 +0000880
881 /* Truncated answer can't be validated.
Simon Kelley09f3b2c2017-05-09 01:34:02 +0100882 If this is an answer to a DNSSEC-generated query, we still
883 need to get the client to retry over TCP, so return
884 an answer with the TC bit set, even if the actual answer fits.
885 */
Simon Kelley9a31b682015-12-15 10:20:39 +0000886 if (header->hb3 & HB3_TC)
887 status = STAT_TRUNCATED;
888
889 while (1)
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000890 {
Simon Kelley9a31b682015-12-15 10:20:39 +0000891 /* As soon as anything returns BOGUS, we stop and unwind, to do otherwise
892 would invite infinite loops, since the answers to DNSKEY and DS queries
893 will not be cached, so they'll be repeated. */
894 if (status != STAT_BOGUS && status != STAT_TRUNCATED && status != STAT_ABANDONED)
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000895 {
Simon Kelley9a31b682015-12-15 10:20:39 +0000896 if (forward->flags & FREC_DNSKEY_QUERY)
897 status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
898 else if (forward->flags & FREC_DS_QUERY)
899 status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000900 else
Simon Kelley9a31b682015-12-15 10:20:39 +0000901 status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class,
Simon Kelleyff19b1a2017-05-21 21:15:32 +0100902 option_bool(OPT_DNSSEC_NO_SIGN) && (server->flags & SERV_DO_DNSSEC), NULL, NULL);
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000903 }
Simon Kelley0fc2f312014-01-08 10:26:58 +0000904
Simon Kelley9a31b682015-12-15 10:20:39 +0000905 /* Can't validate, as we're missing key data. Put this
906 answer aside, whilst we get that. */
907 if (status == STAT_NEED_DS || status == STAT_NEED_KEY)
Simon Kelley3a237152013-12-12 12:15:50 +0000908 {
Simon Kelley9a31b682015-12-15 10:20:39 +0000909 struct frec *new, *orig;
Simon Kelley9d633042013-12-13 15:36:55 +0000910
Simon Kelley9a31b682015-12-15 10:20:39 +0000911 /* Free any saved query */
912 if (forward->stash)
913 blockdata_free(forward->stash);
914
915 /* Now save reply pending receipt of key data */
916 if (!(forward->stash = blockdata_alloc((char *)header, n)))
Simon Kelley97e618a2015-01-07 21:55:43 +0000917 return;
Simon Kelley9a31b682015-12-15 10:20:39 +0000918 forward->stash_len = n;
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000919
Simon Kelley9a31b682015-12-15 10:20:39 +0000920 /* Find the original query that started it all.... */
921 for (orig = forward; orig->dependent; orig = orig->dependent);
Simon Kelley7fa836e2014-02-10 20:11:24 +0000922
Simon Kelley9a31b682015-12-15 10:20:39 +0000923 if (--orig->work_counter == 0 || !(new = get_new_frec(now, NULL, 1)))
924 status = STAT_ABANDONED;
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000925 else
Simon Kelley3a237152013-12-12 12:15:50 +0000926 {
Simon Kelleyf344dbc2016-01-18 18:04:17 +0000927 int fd, type = SERV_DO_DNSSEC;
Simon Kelley9a31b682015-12-15 10:20:39 +0000928 struct frec *next = new->next;
Simon Kelley92be34a2016-01-16 18:39:54 +0000929 char *domain;
930
Simon Kelley9a31b682015-12-15 10:20:39 +0000931 *new = *forward; /* copy everything, then overwrite */
932 new->next = next;
933 new->blocking_query = NULL;
Simon Kelley92be34a2016-01-16 18:39:54 +0000934
935 /* Find server to forward to. This will normally be the
936 same as for the original query, but may be another if
937 servers for domains are involved. */
Simon Kelley09f3b2c2017-05-09 01:34:02 +0100938 if (search_servers(now, NULL, F_DNSSECOK, daemon->keyname, &type, &domain, NULL) == 0)
Simon Kelley92be34a2016-01-16 18:39:54 +0000939 {
Simon Kelleyf344dbc2016-01-18 18:04:17 +0000940 struct server *start = server, *new_server = NULL;
Simon Kelley09f3b2c2017-05-09 01:34:02 +0100941
942 while (1)
943 {
944 if (type == (start->flags & (SERV_TYPE | SERV_DO_DNSSEC)) &&
945 (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
946 !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
947 {
948 new_server = start;
949 if (server == start)
950 {
951 new_server = NULL;
952 break;
953 }
954 }
955
956 if (!(start = start->next))
957 start = daemon->servers;
958 if (start == server)
959 break;
960 }
961
962 if (new_server)
963 server = new_server;
Simon Kelley92be34a2016-01-16 18:39:54 +0000964 }
Simon Kelley09f3b2c2017-05-09 01:34:02 +0100965
Simon Kelley9a31b682015-12-15 10:20:39 +0000966 new->sentto = server;
967 new->rfd4 = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +0000968#ifdef HAVE_IPV6
Simon Kelley9a31b682015-12-15 10:20:39 +0000969 new->rfd6 = NULL;
Simon Kelley7fa836e2014-02-10 20:11:24 +0000970#endif
Simon Kelley9a31b682015-12-15 10:20:39 +0000971 new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY);
972
973 new->dependent = forward; /* to find query awaiting new one. */
974 forward->blocking_query = new; /* for garbage cleaning */
975 /* validate routines leave name of required record in daemon->keyname */
976 if (status == STAT_NEED_KEY)
Simon Kelley7fa836e2014-02-10 20:11:24 +0000977 {
Simon Kelley9a31b682015-12-15 10:20:39 +0000978 new->flags |= FREC_DNSKEY_QUERY;
Simon Kelley33702ab2015-12-28 23:17:15 +0000979 nn = dnssec_generate_query(header, ((unsigned char *) header) + server->edns_pktsz,
Simon Kelley9a31b682015-12-15 10:20:39 +0000980 daemon->keyname, forward->class, T_DNSKEY, &server->addr, server->edns_pktsz);
Simon Kelleyf1668d22014-01-08 16:53:27 +0000981 }
Simon Kelley9a31b682015-12-15 10:20:39 +0000982 else
983 {
984 new->flags |= FREC_DS_QUERY;
Simon Kelley33702ab2015-12-28 23:17:15 +0000985 nn = dnssec_generate_query(header,((unsigned char *) header) + server->edns_pktsz,
Simon Kelley9a31b682015-12-15 10:20:39 +0000986 daemon->keyname, forward->class, T_DS, &server->addr, server->edns_pktsz);
987 }
988 if ((hash = hash_questions(header, nn, daemon->namebuff)))
989 memcpy(new->hash, hash, HASH_SIZE);
990 new->new_id = get_id();
991 header->id = htons(new->new_id);
992 /* Save query for retransmission */
993 new->stash = blockdata_alloc((char *)header, nn);
994 new->stash_len = nn;
995
996 /* Don't resend this. */
997 daemon->srv_save = NULL;
998
999 if (server->sfd)
1000 fd = server->sfd->fd;
1001 else
1002 {
1003 fd = -1;
1004#ifdef HAVE_IPV6
1005 if (server->addr.sa.sa_family == AF_INET6)
1006 {
1007 if (new->rfd6 || (new->rfd6 = allocate_rfd(AF_INET6)))
1008 fd = new->rfd6->fd;
1009 }
1010 else
1011#endif
1012 {
1013 if (new->rfd4 || (new->rfd4 = allocate_rfd(AF_INET)))
1014 fd = new->rfd4->fd;
1015 }
1016 }
1017
1018 if (fd != -1)
1019 {
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001020#ifdef HAVE_CONNTRACK
1021 /* Copy connection mark of incoming query to outgoing connection. */
1022 if (option_bool(OPT_CONNTRACK))
1023 {
1024 unsigned int mark;
1025 if (get_incoming_mark(&orig->source, &orig->dest, 0, &mark))
1026 setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
1027 }
1028#endif
Simon Kelley9a31b682015-12-15 10:20:39 +00001029 while (retry_send(sendto(fd, (char *)header, nn, 0,
1030 &server->addr.sa,
1031 sa_len(&server->addr))));
1032 server->queries++;
1033 }
1034 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00001035 return;
Simon Kelley3a237152013-12-12 12:15:50 +00001036 }
Simon Kelley3a237152013-12-12 12:15:50 +00001037
Simon Kelley9a31b682015-12-15 10:20:39 +00001038 /* Validated original answer, all done. */
1039 if (!forward->dependent)
1040 break;
1041
Josh Soref730c6742017-02-06 16:14:04 +00001042 /* validated subsidiary query, (and cached result)
Simon Kelley9a31b682015-12-15 10:20:39 +00001043 pop that and return to the previous query we were working on. */
Simon Kelley0744ca62014-01-25 16:40:15 +00001044 struct frec *prev = forward->dependent;
1045 free_frec(forward);
1046 forward = prev;
1047 forward->blocking_query = NULL; /* already gone */
1048 blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
1049 n = forward->stash_len;
Simon Kelley3a237152013-12-12 12:15:50 +00001050 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001051
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001052
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001053 no_cache_dnssec = 0;
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001054
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001055 if (status == STAT_TRUNCATED)
Simon Kelley0744ca62014-01-25 16:40:15 +00001056 header->hb3 |= HB3_TC;
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001057 else
Simon Kelley7fa836e2014-02-10 20:11:24 +00001058 {
Simon Kelley554b5802015-04-17 22:50:20 +01001059 char *result, *domain = "result";
Simon Kelley7fa836e2014-02-10 20:11:24 +00001060
Simon Kelley9a31b682015-12-15 10:20:39 +00001061 if (status == STAT_ABANDONED)
Simon Kelley150162b2015-03-27 09:58:26 +00001062 {
1063 result = "ABANDONED";
1064 status = STAT_BOGUS;
1065 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00001066 else
1067 result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
1068
Simon Kelley554b5802015-04-17 22:50:20 +01001069 if (status == STAT_BOGUS && extract_request(header, n, daemon->namebuff, NULL))
1070 domain = daemon->namebuff;
Simon Kelley9a31b682015-12-15 10:20:39 +00001071
Simon Kelley554b5802015-04-17 22:50:20 +01001072 log_query(F_KEYTAG | F_SECSTAT, domain, NULL, result);
Simon Kelley7fa836e2014-02-10 20:11:24 +00001073 }
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001074
Simon Kelley3a237152013-12-12 12:15:50 +00001075 if (status == STAT_SECURE)
1076 cache_secure = 1;
Simon Kelley3a237152013-12-12 12:15:50 +00001077 else if (status == STAT_BOGUS)
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001078 {
1079 no_cache_dnssec = 1;
1080 bogusanswer = 1;
1081 }
Simon Kelley3a237152013-12-12 12:15:50 +00001082 }
Simon Kelley83349b82014-02-10 21:02:01 +00001083#endif
1084
1085 /* restore CD bit to the value in the query */
1086 if (forward->flags & FREC_CHECKING_DISABLED)
1087 header->hb4 |= HB4_CD;
1088 else
1089 header->hb4 &= ~HB4_CD;
Simon Kelley3a237152013-12-12 12:15:50 +00001090
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001091 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 +00001092 forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION,
1093 forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->source)))
Simon Kelley832af0b2007-01-21 20:01:28 +00001094 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001095 header->id = htons(forward->orig_id);
Simon Kelley572b41e2011-02-18 18:11:18 +00001096 header->hb4 |= HB4_RA; /* recursion if available */
Simon Kelley5aa5f0f2015-12-21 17:20:35 +00001097#ifdef HAVE_DNSSEC
1098 /* 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 +01001099 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 +00001100 header, the answer is still bigger than 512, truncate it and mark it so. The client then retries with TCP. */
1101 if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER) && (nn > PACKETSZ))
1102 {
1103 header->ancount = htons(0);
1104 header->nscount = htons(0);
1105 header->arcount = htons(0);
1106 header->hb3 |= HB3_TC;
1107 nn = resize_packet(header, nn, NULL, 0);
1108 }
1109#endif
Simon Kelley54dd3932012-06-20 11:23:38 +01001110 send_from(forward->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
Simon Kelley50303b12012-04-04 22:13:17 +01001111 &forward->source, &forward->dest, forward->iface);
Simon Kelley832af0b2007-01-21 20:01:28 +00001112 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001113 free_frec(forward); /* cancel */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001114 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001115}
Simon Kelley44a2a312004-03-10 20:04:35 +00001116
Simon Kelley1a6bca82008-07-11 11:11:42 +01001117
Simon Kelley5aabfc72007-08-29 11:24:47 +01001118void receive_query(struct listener *listen, time_t now)
Simon Kelley44a2a312004-03-10 20:04:35 +00001119{
Simon Kelley572b41e2011-02-18 18:11:18 +00001120 struct dns_header *header = (struct dns_header *)daemon->packet;
Simon Kelley44a2a312004-03-10 20:04:35 +00001121 union mysockaddr source_addr;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001122 unsigned char *pheader;
1123 unsigned short type, udp_size = PACKETSZ; /* default if no EDNS0 */
Simon Kelley44a2a312004-03-10 20:04:35 +00001124 struct all_addr dst_addr;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001125 struct in_addr netmask, dst_addr_4;
Simon Kelleycdeda282006-03-16 20:16:06 +00001126 size_t m;
1127 ssize_t n;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001128 int if_index = 0, auth_dns = 0, do_bit = 0, have_pseudoheader = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001129#ifdef HAVE_AUTH
1130 int local_auth = 0;
1131#endif
Simon Kelley44a2a312004-03-10 20:04:35 +00001132 struct iovec iov[1];
1133 struct msghdr msg;
1134 struct cmsghdr *cmptr;
Simon Kelley44a2a312004-03-10 20:04:35 +00001135 union {
1136 struct cmsghdr align; /* this ensures alignment */
1137#ifdef HAVE_IPV6
1138 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
1139#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001140#if defined(HAVE_LINUX_NETWORK)
Simon Kelley44a2a312004-03-10 20:04:35 +00001141 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
Simon Kelley824af852008-02-12 20:43:05 +00001142#elif defined(IP_RECVDSTADDR) && defined(HAVE_SOLARIS_NETWORK)
1143 char control[CMSG_SPACE(sizeof(struct in_addr)) +
1144 CMSG_SPACE(sizeof(unsigned int))];
Simon Kelley44a2a312004-03-10 20:04:35 +00001145#elif defined(IP_RECVDSTADDR)
1146 char control[CMSG_SPACE(sizeof(struct in_addr)) +
1147 CMSG_SPACE(sizeof(struct sockaddr_dl))];
1148#endif
1149 } control_u;
Simon Kelley2329bef2013-12-03 13:41:16 +00001150#ifdef HAVE_IPV6
1151 /* Can always get recvd interface for IPv6 */
1152 int check_dst = !option_bool(OPT_NOWILD) || listen->family == AF_INET6;
1153#else
1154 int check_dst = !option_bool(OPT_NOWILD);
1155#endif
1156
Simon Kelleycdeda282006-03-16 20:16:06 +00001157 /* packet buffer overwritten */
1158 daemon->srv_save = NULL;
1159
Hans Dedecker98906272014-12-09 22:22:53 +00001160 dst_addr_4.s_addr = dst_addr.addr.addr4.s_addr = 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001161 netmask.s_addr = 0;
1162
Simon Kelley7e5664b2013-04-05 16:57:41 +01001163 if (option_bool(OPT_NOWILD) && listen->iface)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001164 {
Simon Kelley4f7b3042012-11-28 21:27:02 +00001165 auth_dns = listen->iface->dns_auth;
1166
1167 if (listen->family == AF_INET)
1168 {
Hans Dedecker98906272014-12-09 22:22:53 +00001169 dst_addr_4 = dst_addr.addr.addr4 = listen->iface->addr.in.sin_addr;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001170 netmask = listen->iface->netmask;
1171 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001172 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00001173
Simon Kelley3be34542004-09-11 19:12:13 +01001174 iov[0].iov_base = daemon->packet;
1175 iov[0].iov_len = daemon->edns_pktsz;
Simon Kelley44a2a312004-03-10 20:04:35 +00001176
1177 msg.msg_control = control_u.control;
1178 msg.msg_controllen = sizeof(control_u);
1179 msg.msg_flags = 0;
1180 msg.msg_name = &source_addr;
1181 msg.msg_namelen = sizeof(source_addr);
1182 msg.msg_iov = iov;
1183 msg.msg_iovlen = 1;
1184
Simon Kelleyde379512004-06-22 20:23:33 +01001185 if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
Simon Kelley3be34542004-09-11 19:12:13 +01001186 return;
Simon Kelley44a2a312004-03-10 20:04:35 +00001187
Simon Kelley572b41e2011-02-18 18:11:18 +00001188 if (n < (int)sizeof(struct dns_header) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001189 (msg.msg_flags & MSG_TRUNC) ||
Simon Kelley572b41e2011-02-18 18:11:18 +00001190 (header->hb3 & HB3_QR))
Simon Kelley3be34542004-09-11 19:12:13 +01001191 return;
Simon Kelley63437ff2017-09-06 22:34:21 +01001192
1193 /* Clear buffer beyond request to avoid risk of
1194 information disclosure. */
1195 memset(daemon->packet + n, 0, daemon->edns_pktsz - n);
Simon Kelley44a2a312004-03-10 20:04:35 +00001196
Simon Kelley26128d22004-11-14 16:43:54 +00001197 source_addr.sa.sa_family = listen->family;
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001198
1199 if (listen->family == AF_INET)
1200 {
1201 /* Source-port == 0 is an error, we can't send back to that.
1202 http://www.ietf.org/mail-archive/web/dnsop/current/msg11441.html */
1203 if (source_addr.in.sin_port == 0)
1204 return;
1205 }
Simon Kelley26128d22004-11-14 16:43:54 +00001206#ifdef HAVE_IPV6
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001207 else
1208 {
1209 /* Source-port == 0 is an error, we can't send back to that. */
1210 if (source_addr.in6.sin6_port == 0)
1211 return;
1212 source_addr.in6.sin6_flowinfo = 0;
1213 }
Simon Kelley26128d22004-11-14 16:43:54 +00001214#endif
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001215
Simon Kelleyc8a80482014-03-05 14:29:54 +00001216 /* We can be configured to only accept queries from at-most-one-hop-away addresses. */
1217 if (option_bool(OPT_LOCAL_SERVICE))
1218 {
1219 struct addrlist *addr;
1220#ifdef HAVE_IPV6
1221 if (listen->family == AF_INET6)
1222 {
1223 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1224 if ((addr->flags & ADDRLIST_IPV6) &&
1225 is_same_net6(&addr->addr.addr.addr6, &source_addr.in6.sin6_addr, addr->prefixlen))
1226 break;
1227 }
1228 else
1229#endif
1230 {
1231 struct in_addr netmask;
1232 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1233 {
Richard Genoud15b1b7e2014-09-17 21:12:00 +01001234 netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
Simon Kelleyc8a80482014-03-05 14:29:54 +00001235 if (!(addr->flags & ADDRLIST_IPV6) &&
1236 is_same_net(addr->addr.addr.addr4, source_addr.in.sin_addr, netmask))
1237 break;
1238 }
1239 }
1240 if (!addr)
1241 {
Simon Kelley0c8584e2014-03-12 20:12:56 +00001242 static int warned = 0;
1243 if (!warned)
1244 {
1245 my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
1246 warned = 1;
1247 }
Simon Kelleyc8a80482014-03-05 14:29:54 +00001248 return;
1249 }
1250 }
1251
Simon Kelley2329bef2013-12-03 13:41:16 +00001252 if (check_dst)
Simon Kelley44a2a312004-03-10 20:04:35 +00001253 {
Simon Kelley8a911cc2004-03-16 18:35:52 +00001254 struct ifreq ifr;
1255
Simon Kelley26128d22004-11-14 16:43:54 +00001256 if (msg.msg_controllen < sizeof(struct cmsghdr))
1257 return;
1258
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001259#if defined(HAVE_LINUX_NETWORK)
Simon Kelley26128d22004-11-14 16:43:54 +00001260 if (listen->family == AF_INET)
1261 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelleyc72daea2012-01-05 21:33:27 +00001262 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
Simon Kelley26128d22004-11-14 16:43:54 +00001263 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001264 union {
1265 unsigned char *c;
1266 struct in_pktinfo *p;
1267 } p;
1268 p.c = CMSG_DATA(cmptr);
1269 dst_addr_4 = dst_addr.addr.addr4 = p.p->ipi_spec_dst;
1270 if_index = p.p->ipi_ifindex;
Simon Kelley26128d22004-11-14 16:43:54 +00001271 }
1272#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
1273 if (listen->family == AF_INET)
1274 {
1275 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001276 {
1277 union {
1278 unsigned char *c;
1279 unsigned int *i;
1280 struct in_addr *a;
1281#ifndef HAVE_SOLARIS_NETWORK
1282 struct sockaddr_dl *s;
Simon Kelley824af852008-02-12 20:43:05 +00001283#endif
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001284 } p;
1285 p.c = CMSG_DATA(cmptr);
1286 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
1287 dst_addr_4 = dst_addr.addr.addr4 = *(p.a);
1288 else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
1289#ifdef HAVE_SOLARIS_NETWORK
1290 if_index = *(p.i);
1291#else
1292 if_index = p.s->sdl_index;
1293#endif
1294 }
Simon Kelley26128d22004-11-14 16:43:54 +00001295 }
1296#endif
1297
1298#ifdef HAVE_IPV6
1299 if (listen->family == AF_INET6)
1300 {
1301 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelleyc72daea2012-01-05 21:33:27 +00001302 if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
Simon Kelley26128d22004-11-14 16:43:54 +00001303 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001304 union {
1305 unsigned char *c;
1306 struct in6_pktinfo *p;
1307 } p;
1308 p.c = CMSG_DATA(cmptr);
1309
1310 dst_addr.addr.addr6 = p.p->ipi6_addr;
1311 if_index = p.p->ipi6_ifindex;
Simon Kelley26128d22004-11-14 16:43:54 +00001312 }
1313 }
1314#endif
1315
1316 /* enforce available interface configuration */
1317
Simon Kelleye25db1f2013-01-29 22:10:26 +00001318 if (!indextoname(listen->fd, if_index, ifr.ifr_name))
Simon Kelley832af0b2007-01-21 20:01:28 +00001319 return;
1320
Simon Kelleye25db1f2013-01-29 22:10:26 +00001321 if (!iface_check(listen->family, &dst_addr, ifr.ifr_name, &auth_dns))
1322 {
1323 if (!option_bool(OPT_CLEVERBIND))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001324 enumerate_interfaces(0);
Simon Kelley3f2873d2013-05-14 11:28:47 +01001325 if (!loopback_exception(listen->fd, listen->family, &dst_addr, ifr.ifr_name) &&
1326 !label_exception(if_index, listen->family, &dst_addr))
Simon Kelleye25db1f2013-01-29 22:10:26 +00001327 return;
1328 }
1329
Simon Kelley552af8b2012-02-29 20:10:31 +00001330 if (listen->family == AF_INET && option_bool(OPT_LOCALISE))
1331 {
1332 struct irec *iface;
1333
Josh Soref730c6742017-02-06 16:14:04 +00001334 /* get the netmask of the interface which has the address we were sent to.
klemens43517fc2017-02-19 15:53:37 +00001335 This is no necessarily the interface we arrived on. */
Simon Kelley552af8b2012-02-29 20:10:31 +00001336
1337 for (iface = daemon->interfaces; iface; iface = iface->next)
1338 if (iface->addr.sa.sa_family == AF_INET &&
1339 iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
1340 break;
1341
1342 /* interface may be new */
Simon Kelleye25db1f2013-01-29 22:10:26 +00001343 if (!iface && !option_bool(OPT_CLEVERBIND))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001344 enumerate_interfaces(0);
Simon Kelley552af8b2012-02-29 20:10:31 +00001345
1346 for (iface = daemon->interfaces; iface; iface = iface->next)
1347 if (iface->addr.sa.sa_family == AF_INET &&
1348 iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
1349 break;
1350
1351 /* If we failed, abandon localisation */
1352 if (iface)
1353 netmask = iface->netmask;
1354 else
1355 dst_addr_4.s_addr = 0;
1356 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001357 }
Simon Kelley25cf5e32015-01-09 15:53:03 +00001358
1359 /* log_query gets called indirectly all over the place, so
1360 pass these in global variables - sorry. */
1361 daemon->log_display_id = ++daemon->log_id;
1362 daemon->log_source_addr = &source_addr;
Simon Kelley44a2a312004-03-10 20:04:35 +00001363
Simon Kelleycdeda282006-03-16 20:16:06 +00001364 if (extract_request(header, (size_t)n, daemon->namebuff, &type))
Simon Kelley44a2a312004-03-10 20:04:35 +00001365 {
Simon Kelleyb485ed92013-10-18 22:00:39 +01001366#ifdef HAVE_AUTH
1367 struct auth_zone *zone;
1368#endif
Simon Kelley610e7822014-02-06 14:45:17 +00001369 char *types = querystr(auth_dns ? "auth" : "query", type);
1370
Simon Kelley44a2a312004-03-10 20:04:35 +00001371 if (listen->family == AF_INET)
Simon Kelley3be34542004-09-11 19:12:13 +01001372 log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
Simon Kelley1a6bca82008-07-11 11:11:42 +01001373 (struct all_addr *)&source_addr.in.sin_addr, types);
Simon Kelley44a2a312004-03-10 20:04:35 +00001374#ifdef HAVE_IPV6
1375 else
Simon Kelley3be34542004-09-11 19:12:13 +01001376 log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
Simon Kelley1a6bca82008-07-11 11:11:42 +01001377 (struct all_addr *)&source_addr.in6.sin6_addr, types);
Simon Kelley44a2a312004-03-10 20:04:35 +00001378#endif
Simon Kelley44a2a312004-03-10 20:04:35 +00001379
Simon Kelley4820dce2012-12-18 18:30:30 +00001380#ifdef HAVE_AUTH
Simon Kelleyb485ed92013-10-18 22:00:39 +01001381 /* find queries for zones we're authoritative for, and answer them directly */
Simon Kelley3a3965a2015-08-09 17:45:06 +01001382 if (!auth_dns && !option_bool(OPT_LOCALISE))
Simon Kelley6008bdb2013-10-21 21:47:03 +01001383 for (zone = daemon->auth_zones; zone; zone = zone->next)
1384 if (in_zone(zone, daemon->namebuff, NULL))
1385 {
1386 auth_dns = 1;
1387 local_auth = 1;
1388 break;
1389 }
Simon Kelleyb485ed92013-10-18 22:00:39 +01001390#endif
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01001391
1392#ifdef HAVE_LOOP
1393 /* Check for forwarding loop */
1394 if (detect_loop(daemon->namebuff, type))
1395 return;
1396#endif
Simon Kelleyb485ed92013-10-18 22:00:39 +01001397 }
1398
Simon Kelley5bb88f02015-12-21 16:23:47 +00001399 if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL, NULL))
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001400 {
1401 unsigned short flags;
1402
1403 have_pseudoheader = 1;
1404 GETSHORT(udp_size, pheader);
1405 pheader += 2; /* ext_rcode */
1406 GETSHORT(flags, pheader);
1407
1408 if (flags & 0x8000)
1409 do_bit = 1;/* do bit */
1410
1411 /* If the client provides an EDNS0 UDP size, use that to limit our reply.
1412 (bounded by the maximum configured). If no EDNS0, then it
1413 defaults to 512 */
1414 if (udp_size > daemon->edns_pktsz)
1415 udp_size = daemon->edns_pktsz;
Simon Kelleya3303e12017-09-07 20:45:00 +01001416 else if (udp_size < PACKETSZ)
1417 udp_size = PACKETSZ; /* Sanity check - can't reduce below default. RFC 6891 6.2.3 */
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001418 }
1419
Simon Kelleyb485ed92013-10-18 22:00:39 +01001420#ifdef HAVE_AUTH
Simon Kelley4f7b3042012-11-28 21:27:02 +00001421 if (auth_dns)
Simon Kelley824af852008-02-12 20:43:05 +00001422 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001423 m = answer_auth(header, ((char *) header) + udp_size, (size_t)n, now, &source_addr,
1424 local_auth, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001425 if (m >= 1)
Simon Kelleyb485ed92013-10-18 22:00:39 +01001426 {
1427 send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
1428 (char *)header, m, &source_addr, &dst_addr, if_index);
1429 daemon->auth_answer++;
1430 }
Simon Kelley824af852008-02-12 20:43:05 +00001431 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001432 else
Simon Kelley4820dce2012-12-18 18:30:30 +00001433#endif
Simon Kelley4f7b3042012-11-28 21:27:02 +00001434 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001435 int ad_reqd = do_bit;
1436 /* RFC 6840 5.7 */
1437 if (header->hb4 & HB4_AD)
1438 ad_reqd = 1;
1439
1440 m = answer_request(header, ((char *) header) + udp_size, (size_t)n,
1441 dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001442
1443 if (m >= 1)
1444 {
1445 send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
1446 (char *)header, m, &source_addr, &dst_addr, if_index);
1447 daemon->local_answer++;
1448 }
1449 else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
Simon Kelley613ad152014-02-25 23:02:28 +00001450 header, (size_t)n, now, NULL, ad_reqd, do_bit))
Simon Kelley4f7b3042012-11-28 21:27:02 +00001451 daemon->queries_forwarded++;
1452 else
1453 daemon->local_answer++;
1454 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001455}
1456
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001457#ifdef HAVE_DNSSEC
Josh Soref730c6742017-02-06 16:14:04 +00001458/* Recurse up the key hierarchy */
Simon Kelley7fa836e2014-02-10 20:11:24 +00001459static int tcp_key_recurse(time_t now, int status, struct dns_header *header, size_t n,
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001460 int class, char *name, char *keyname, struct server *server,
1461 int have_mark, unsigned int mark, int *keycount)
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001462{
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001463 int new_status;
Simon Kelley9a31b682015-12-15 10:20:39 +00001464 unsigned char *packet = NULL;
Simon Kelley9a31b682015-12-15 10:20:39 +00001465 unsigned char *payload = NULL;
1466 struct dns_header *new_header = NULL;
1467 u16 *length = NULL;
Simon Kelley361dfe52017-02-10 21:12:30 +00001468
Simon Kelley9a31b682015-12-15 10:20:39 +00001469 while (1)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001470 {
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001471 int type = SERV_DO_DNSSEC;
1472 char *domain;
1473 size_t m;
1474 unsigned char c1, c2;
Simon Kelley361dfe52017-02-10 21:12:30 +00001475 struct server *firstsendto = NULL;
1476
Simon Kelley9a31b682015-12-15 10:20:39 +00001477 /* limit the amount of work we do, to avoid cycling forever on loops in the DNS */
1478 if (--(*keycount) == 0)
1479 new_status = STAT_ABANDONED;
1480 else if (status == STAT_NEED_KEY)
1481 new_status = dnssec_validate_by_ds(now, header, n, name, keyname, class);
1482 else if (status == STAT_NEED_DS)
1483 new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
1484 else
James Bottomleye33b4872017-03-17 21:44:10 +00001485 new_status = dnssec_validate_reply(now, header, n, name, keyname, &class,
Simon Kelleyff19b1a2017-05-21 21:15:32 +01001486 option_bool(OPT_DNSSEC_NO_SIGN) && (server->flags & SERV_DO_DNSSEC), NULL, NULL);
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001487
Simon Kelley9a31b682015-12-15 10:20:39 +00001488 if (new_status != STAT_NEED_DS && new_status != STAT_NEED_KEY)
1489 break;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001490
Simon Kelley9a31b682015-12-15 10:20:39 +00001491 /* Can't validate because we need a key/DS whose name now in keyname.
1492 Make query for same, and recurse to validate */
Simon Kelley7fa836e2014-02-10 20:11:24 +00001493 if (!packet)
Simon Kelley9a31b682015-12-15 10:20:39 +00001494 {
1495 packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
1496 payload = &packet[2];
1497 new_header = (struct dns_header *)payload;
1498 length = (u16 *)packet;
1499 }
1500
1501 if (!packet)
1502 {
1503 new_status = STAT_ABANDONED;
1504 break;
1505 }
1506
Simon Kelley33702ab2015-12-28 23:17:15 +00001507 m = dnssec_generate_query(new_header, ((unsigned char *) new_header) + 65536, keyname, class,
Simon Kelleya77cec82015-05-08 16:25:38 +01001508 new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS, &server->addr, server->edns_pktsz);
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001509
Simon Kelley7fa836e2014-02-10 20:11:24 +00001510 *length = htons(m);
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001511
1512 /* Find server to forward to. This will normally be the
1513 same as for the original query, but may be another if
1514 servers for domains are involved. */
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001515 if (search_servers(now, NULL, F_DNSSECOK, keyname, &type, &domain, NULL) != 0)
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001516 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001517 new_status = STAT_ABANDONED;
1518 break;
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001519 }
Simon Kelley361dfe52017-02-10 21:12:30 +00001520
Simon Kelley361dfe52017-02-10 21:12:30 +00001521 while (1)
1522 {
1523 if (!firstsendto)
1524 firstsendto = server;
1525 else
1526 {
1527 if (!(server = server->next))
1528 server = daemon->servers;
1529 if (server == firstsendto)
1530 {
1531 /* can't find server to accept our query. */
1532 new_status = STAT_ABANDONED;
1533 break;
1534 }
1535 }
1536
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001537 if (type != (server->flags & (SERV_TYPE | SERV_DO_DNSSEC)) ||
Simon Kelley361dfe52017-02-10 21:12:30 +00001538 (type == SERV_HAS_DOMAIN && !hostname_isequal(domain, server->domain)) ||
1539 (server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
1540 continue;
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001541
1542 retry:
1543 /* may need to make new connection. */
1544 if (server->tcpfd == -1)
1545 {
1546 if ((server->tcpfd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
Simon Kelley361dfe52017-02-10 21:12:30 +00001547 continue; /* No good, next server */
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001548
1549#ifdef HAVE_CONNTRACK
1550 /* Copy connection mark of incoming query to outgoing connection. */
1551 if (have_mark)
1552 setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
1553#endif
1554
Simon Kelley9d6918d2017-10-13 17:55:09 +01001555 if (!local_bind(server->tcpfd, &server->source_addr, server->interface, 0, 1) ||
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001556 connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) == -1)
1557 {
1558 close(server->tcpfd);
1559 server->tcpfd = -1;
1560 continue; /* No good, next server */
1561 }
1562
1563 server->flags &= ~SERV_GOT_TCP;
1564 }
Simon Kelley361dfe52017-02-10 21:12:30 +00001565
1566 if (!read_write(server->tcpfd, packet, m + sizeof(u16), 0) ||
1567 !read_write(server->tcpfd, &c1, 1, 1) ||
1568 !read_write(server->tcpfd, &c2, 1, 1) ||
1569 !read_write(server->tcpfd, payload, (c1 << 8) | c2, 1))
1570 {
1571 close(server->tcpfd);
1572 server->tcpfd = -1;
1573 /* We get data then EOF, reopen connection to same server,
1574 else try next. This avoids DoS from a server which accepts
1575 connections and then closes them. */
1576 if (server->flags & SERV_GOT_TCP)
1577 goto retry;
1578 else
1579 continue;
1580 }
1581
1582 server->flags |= SERV_GOT_TCP;
1583
1584 m = (c1 << 8) | c2;
1585 new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, have_mark, mark, keycount);
1586 break;
1587 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001588
1589 if (new_status != STAT_OK)
1590 break;
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001591 }
Simon Kelley361dfe52017-02-10 21:12:30 +00001592
Simon Kelley9a31b682015-12-15 10:20:39 +00001593 if (packet)
1594 free(packet);
1595
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001596 return new_status;
1597}
1598#endif
1599
1600
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001601/* The daemon forks before calling this: it should deal with one connection,
Josh Soref730c6742017-02-06 16:14:04 +00001602 blocking as necessary, and then return. Note, need to be a bit careful
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001603 about resources for debug mode, when the fork is suppressed: that's
1604 done by the caller. */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001605unsigned char *tcp_request(int confd, time_t now,
Simon Kelley4f7b3042012-11-28 21:27:02 +00001606 union mysockaddr *local_addr, struct in_addr netmask, int auth_dns)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001607{
Simon Kelley28866e92011-02-14 20:19:14 +00001608 size_t size = 0;
1609 int norebind = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001610#ifdef HAVE_AUTH
Simon Kelley19b16892013-10-20 10:19:39 +01001611 int local_auth = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001612#endif
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001613 int checking_disabled, do_bit, added_pheader = 0, have_pseudoheader = 0;
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001614 int check_subnet, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
Simon Kelleycdeda282006-03-16 20:16:06 +00001615 size_t m;
Simon Kelleyee86ce62012-12-07 11:54:46 +00001616 unsigned short qtype;
1617 unsigned int gotname;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001618 unsigned char c1, c2;
Simon Kelley4b5ea122013-04-22 10:18:26 +01001619 /* Max TCP packet + slop + size */
1620 unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
1621 unsigned char *payload = &packet[2];
1622 /* largest field in header is 16-bits, so this is still sufficiently aligned */
1623 struct dns_header *header = (struct dns_header *)payload;
1624 u16 *length = (u16 *)packet;
Simon Kelley3be34542004-09-11 19:12:13 +01001625 struct server *last_server;
Simon Kelley7de060b2011-08-26 17:24:52 +01001626 struct in_addr dst_addr_4;
1627 union mysockaddr peer_addr;
1628 socklen_t peer_len = sizeof(union mysockaddr);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001629 int query_count = 0;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001630 unsigned char *pheader;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001631 unsigned int mark = 0;
1632 int have_mark = 0;
Simon Kelley25cf5e32015-01-09 15:53:03 +00001633
Simon Kelleyd05dd582016-01-19 21:23:30 +00001634 (void)mark;
1635 (void)have_mark;
1636
Simon Kelley7de060b2011-08-26 17:24:52 +01001637 if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
1638 return packet;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001639
1640#ifdef HAVE_CONNTRACK
1641 /* Get connection mark of incoming query to set on outgoing connections. */
1642 if (option_bool(OPT_CONNTRACK))
1643 {
1644 struct all_addr local;
1645#ifdef HAVE_IPV6
1646 if (local_addr->sa.sa_family == AF_INET6)
1647 local.addr.addr6 = local_addr->in6.sin6_addr;
1648 else
1649#endif
1650 local.addr.addr4 = local_addr->in.sin_addr;
1651
1652 have_mark = get_incoming_mark(&peer_addr, &local, 1, &mark);
1653 }
1654#endif
1655
Simon Kelleyc8a80482014-03-05 14:29:54 +00001656 /* We can be configured to only accept queries from at-most-one-hop-away addresses. */
1657 if (option_bool(OPT_LOCAL_SERVICE))
1658 {
1659 struct addrlist *addr;
1660#ifdef HAVE_IPV6
1661 if (peer_addr.sa.sa_family == AF_INET6)
1662 {
1663 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1664 if ((addr->flags & ADDRLIST_IPV6) &&
1665 is_same_net6(&addr->addr.addr.addr6, &peer_addr.in6.sin6_addr, addr->prefixlen))
1666 break;
1667 }
1668 else
1669#endif
1670 {
1671 struct in_addr netmask;
1672 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1673 {
Richard Genoud15b1b7e2014-09-17 21:12:00 +01001674 netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
Simon Kelleyc8a80482014-03-05 14:29:54 +00001675 if (!(addr->flags & ADDRLIST_IPV6) &&
1676 is_same_net(addr->addr.addr.addr4, peer_addr.in.sin_addr, netmask))
1677 break;
1678 }
1679 }
1680 if (!addr)
1681 {
1682 my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
1683 return packet;
1684 }
1685 }
Simon Kelley7de060b2011-08-26 17:24:52 +01001686
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001687 while (1)
1688 {
Simon Kelley25cf5e32015-01-09 15:53:03 +00001689 if (query_count == TCP_MAX_QUERIES ||
1690 !packet ||
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001691 !read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
1692 !(size = c1 << 8 | c2) ||
Simon Kelley4b5ea122013-04-22 10:18:26 +01001693 !read_write(confd, payload, size, 1))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001694 return packet;
1695
Simon Kelley572b41e2011-02-18 18:11:18 +00001696 if (size < (int)sizeof(struct dns_header))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001697 continue;
Simon Kelley63437ff2017-09-06 22:34:21 +01001698
1699 /* Clear buffer beyond request to avoid risk of
1700 information disclosure. */
1701 memset(payload + size, 0, 65536 - size);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001702
Simon Kelley25cf5e32015-01-09 15:53:03 +00001703 query_count++;
1704
1705 /* log_query gets called indirectly all over the place, so
1706 pass these in global variables - sorry. */
1707 daemon->log_display_id = ++daemon->log_id;
1708 daemon->log_source_addr = &peer_addr;
1709
Simon Kelley28866e92011-02-14 20:19:14 +00001710 /* save state of "cd" flag in query */
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001711 if ((checking_disabled = header->hb4 & HB4_CD))
1712 no_cache_dnssec = 1;
Simon Kelley28866e92011-02-14 20:19:14 +00001713
Simon Kelley3be34542004-09-11 19:12:13 +01001714 if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001715 {
Simon Kelleyb485ed92013-10-18 22:00:39 +01001716#ifdef HAVE_AUTH
1717 struct auth_zone *zone;
1718#endif
Simon Kelley610e7822014-02-06 14:45:17 +00001719 char *types = querystr(auth_dns ? "auth" : "query", qtype);
Simon Kelley7de060b2011-08-26 17:24:52 +01001720
1721 if (peer_addr.sa.sa_family == AF_INET)
1722 log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
1723 (struct all_addr *)&peer_addr.in.sin_addr, types);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001724#ifdef HAVE_IPV6
Simon Kelley7de060b2011-08-26 17:24:52 +01001725 else
1726 log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
1727 (struct all_addr *)&peer_addr.in6.sin6_addr, types);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001728#endif
Simon Kelleyb485ed92013-10-18 22:00:39 +01001729
1730#ifdef HAVE_AUTH
1731 /* find queries for zones we're authoritative for, and answer them directly */
Simon Kelley3a3965a2015-08-09 17:45:06 +01001732 if (!auth_dns && !option_bool(OPT_LOCALISE))
Simon Kelley6008bdb2013-10-21 21:47:03 +01001733 for (zone = daemon->auth_zones; zone; zone = zone->next)
1734 if (in_zone(zone, daemon->namebuff, NULL))
1735 {
1736 auth_dns = 1;
1737 local_auth = 1;
1738 break;
1739 }
Simon Kelleyb485ed92013-10-18 22:00:39 +01001740#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001741 }
1742
Simon Kelley7de060b2011-08-26 17:24:52 +01001743 if (local_addr->sa.sa_family == AF_INET)
1744 dst_addr_4 = local_addr->in.sin_addr;
1745 else
1746 dst_addr_4.s_addr = 0;
1747
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001748 do_bit = 0;
1749
Simon Kelley5bb88f02015-12-21 16:23:47 +00001750 if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL, NULL))
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001751 {
1752 unsigned short flags;
1753
1754 have_pseudoheader = 1;
1755 pheader += 4; /* udp_size, ext_rcode */
1756 GETSHORT(flags, pheader);
1757
1758 if (flags & 0x8000)
Simon Kelley5bb88f02015-12-21 16:23:47 +00001759 do_bit = 1; /* do bit */
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001760 }
1761
Simon Kelley4820dce2012-12-18 18:30:30 +00001762#ifdef HAVE_AUTH
Simon Kelley4f7b3042012-11-28 21:27:02 +00001763 if (auth_dns)
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001764 m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr,
1765 local_auth, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001766 else
Simon Kelley4820dce2012-12-18 18:30:30 +00001767#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001768 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001769 int ad_reqd = do_bit;
1770 /* RFC 6840 5.7 */
1771 if (header->hb4 & HB4_AD)
1772 ad_reqd = 1;
1773
1774 /* m > 0 if answered from cache */
1775 m = answer_request(header, ((char *) header) + 65536, (size_t)size,
1776 dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001777
Simon Kelley4f7b3042012-11-28 21:27:02 +00001778 /* Do this by steam now we're not in the select() loop */
Simon Kelleyb842bc92015-07-12 21:09:11 +01001779 check_log_writer(1);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001780
1781 if (m == 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001782 {
Simon Kelley4f7b3042012-11-28 21:27:02 +00001783 unsigned int flags = 0;
1784 struct all_addr *addrp = NULL;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001785 int type = SERV_DO_DNSSEC;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001786 char *domain = NULL;
Simon Kelley6fd5d792017-10-13 22:26:40 +01001787 unsigned char *oph = find_pseudoheader(header, size, NULL, NULL, NULL, NULL);
Simon Kelleyed4c0762013-10-08 20:46:34 +01001788
Simon Kelley6fd5d792017-10-13 22:26:40 +01001789 size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet);
1790
Simon Kelley4f7b3042012-11-28 21:27:02 +00001791 if (gotname)
1792 flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
Simon Kelley6fd5d792017-10-13 22:26:40 +01001793
1794#ifdef HAVE_DNSSEC
1795 if (option_bool(OPT_DNSSEC_VALID) && (type & SERV_DO_DNSSEC))
1796 {
1797 size = add_do_bit(header, size, ((unsigned char *) header) + 65536);
1798
1799 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
1800 this allows it to select auth servers when one is returning bad data. */
1801 if (option_bool(OPT_DNSSEC_DEBUG))
1802 header->hb4 |= HB4_CD;
1803 }
1804#endif
1805
1806 /* Check if we added a pheader on forwarding - may need to
1807 strip it from the reply. */
1808 if (!oph && find_pseudoheader(header, size, NULL, NULL, NULL, NULL))
1809 added_pheader = 1;
1810
Simon Kelley367341f2016-01-12 15:58:23 +00001811 type &= ~SERV_DO_DNSSEC;
Simon Kelley367341f2016-01-12 15:58:23 +00001812
Simon Kelley4f7b3042012-11-28 21:27:02 +00001813 if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server)
1814 last_server = daemon->servers;
1815 else
1816 last_server = daemon->last_server;
1817
1818 if (!flags && last_server)
1819 {
1820 struct server *firstsendto = NULL;
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001821#ifdef HAVE_DNSSEC
Simon Kelley703c7ff2014-01-25 23:46:23 +00001822 unsigned char *newhash, hash[HASH_SIZE];
Simon Kelley63758382014-04-16 22:20:55 +01001823 if ((newhash = hash_questions(header, (unsigned int)size, daemon->namebuff)))
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001824 memcpy(hash, newhash, HASH_SIZE);
Tomas Hozzab37f8b92014-03-25 20:52:28 +00001825 else
1826 memset(hash, 0, HASH_SIZE);
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001827#else
Simon Kelley4f7b3042012-11-28 21:27:02 +00001828 unsigned int crc = questions_crc(header, (unsigned int)size, daemon->namebuff);
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001829#endif
Simon Kelley4f7b3042012-11-28 21:27:02 +00001830 /* Loop round available servers until we succeed in connecting to one.
Josh Soref730c6742017-02-06 16:14:04 +00001831 Note that this code subtly ensures that consecutive queries on this connection
Simon Kelley4f7b3042012-11-28 21:27:02 +00001832 which can go to the same server, do so. */
1833 while (1)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001834 {
Simon Kelley4f7b3042012-11-28 21:27:02 +00001835 if (!firstsendto)
1836 firstsendto = last_server;
1837 else
1838 {
1839 if (!(last_server = last_server->next))
1840 last_server = daemon->servers;
1841
1842 if (last_server == firstsendto)
1843 break;
1844 }
1845
1846 /* server for wrong domain */
1847 if (type != (last_server->flags & SERV_TYPE) ||
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01001848 (type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)) ||
1849 (last_server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
Simon Kelley7de060b2011-08-26 17:24:52 +01001850 continue;
Simon Kelley361dfe52017-02-10 21:12:30 +00001851
1852 retry:
Simon Kelley4f7b3042012-11-28 21:27:02 +00001853 if (last_server->tcpfd == -1)
1854 {
1855 if ((last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
1856 continue;
1857
Karl Vogele9828b62014-10-03 21:45:15 +01001858#ifdef HAVE_CONNTRACK
1859 /* Copy connection mark of incoming query to outgoing connection. */
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001860 if (have_mark)
1861 setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
Karl Vogele9828b62014-10-03 21:45:15 +01001862#endif
1863
Simon Kelley9d6918d2017-10-13 17:55:09 +01001864 if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 0, 1) ||
Simon Kelley4f7b3042012-11-28 21:27:02 +00001865 connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1))
1866 {
1867 close(last_server->tcpfd);
1868 last_server->tcpfd = -1;
1869 continue;
1870 }
1871
Simon Kelley361dfe52017-02-10 21:12:30 +00001872 last_server->flags &= ~SERV_GOT_TCP;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001873 }
1874
Simon Kelley4b5ea122013-04-22 10:18:26 +01001875 *length = htons(size);
Simon Kelley1fc02682014-04-29 12:30:18 +01001876
1877 /* get query name again for logging - may have been overwritten */
1878 if (!(gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
1879 strcpy(daemon->namebuff, "query");
Simon Kelley4f7b3042012-11-28 21:27:02 +00001880
Simon Kelley4b5ea122013-04-22 10:18:26 +01001881 if (!read_write(last_server->tcpfd, packet, size + sizeof(u16), 0) ||
Simon Kelley4f7b3042012-11-28 21:27:02 +00001882 !read_write(last_server->tcpfd, &c1, 1, 1) ||
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001883 !read_write(last_server->tcpfd, &c2, 1, 1) ||
1884 !read_write(last_server->tcpfd, payload, (c1 << 8) | c2, 1))
Simon Kelley7de060b2011-08-26 17:24:52 +01001885 {
1886 close(last_server->tcpfd);
1887 last_server->tcpfd = -1;
Simon Kelley361dfe52017-02-10 21:12:30 +00001888 /* We get data then EOF, reopen connection to same server,
1889 else try next. This avoids DoS from a server which accepts
1890 connections and then closes them. */
1891 if (last_server->flags & SERV_GOT_TCP)
1892 goto retry;
1893 else
1894 continue;
1895 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00001896
Simon Kelley361dfe52017-02-10 21:12:30 +00001897 last_server->flags |= SERV_GOT_TCP;
1898
Simon Kelley4f7b3042012-11-28 21:27:02 +00001899 m = (c1 << 8) | c2;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001900
Simon Kelley4f7b3042012-11-28 21:27:02 +00001901 if (last_server->addr.sa.sa_family == AF_INET)
1902 log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
1903 (struct all_addr *)&last_server->addr.in.sin_addr, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001904#ifdef HAVE_IPV6
Simon Kelley4f7b3042012-11-28 21:27:02 +00001905 else
1906 log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
1907 (struct all_addr *)&last_server->addr.in6.sin6_addr, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001908#endif
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001909
1910#ifdef HAVE_DNSSEC
Simon Kelley367341f2016-01-12 15:58:23 +00001911 if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled && (last_server->flags & SERV_DO_DNSSEC))
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001912 {
Simon Kelley7fa836e2014-02-10 20:11:24 +00001913 int keycount = DNSSEC_WORK; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001914 int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname,
1915 last_server, have_mark, mark, &keycount);
Simon Kelley554b5802015-04-17 22:50:20 +01001916 char *result, *domain = "result";
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001917
Simon Kelley9a31b682015-12-15 10:20:39 +00001918 if (status == STAT_ABANDONED)
Simon Kelley150162b2015-03-27 09:58:26 +00001919 {
1920 result = "ABANDONED";
1921 status = STAT_BOGUS;
1922 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00001923 else
1924 result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
Simon Kelleye66b4df2015-04-28 20:45:57 +01001925
1926 if (status == STAT_BOGUS && extract_request(header, m, daemon->namebuff, NULL))
1927 domain = daemon->namebuff;
Simon Kelley554b5802015-04-17 22:50:20 +01001928
1929 log_query(F_KEYTAG | F_SECSTAT, domain, NULL, result);
Simon Kelley7fa836e2014-02-10 20:11:24 +00001930
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001931 if (status == STAT_BOGUS)
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001932 {
1933 no_cache_dnssec = 1;
1934 bogusanswer = 1;
1935 }
1936
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001937 if (status == STAT_SECURE)
1938 cache_secure = 1;
1939 }
1940#endif
1941
1942 /* restore CD bit to the value in the query */
1943 if (checking_disabled)
1944 header->hb4 |= HB4_CD;
1945 else
1946 header->hb4 &= ~HB4_CD;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001947
1948 /* There's no point in updating the cache, since this process will exit and
1949 lose the information after a few queries. We make this call for the alias and
1950 bogus-nxdomain side-effects. */
1951 /* If the crc of the question section doesn't match the crc we sent, then
1952 someone might be attempting to insert bogus values into the cache by
1953 sending replies containing questions and bogus answers. */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001954#ifdef HAVE_DNSSEC
1955 newhash = hash_questions(header, (unsigned int)m, daemon->namebuff);
1956 if (!newhash || memcmp(hash, newhash, HASH_SIZE) != 0)
Simon Kelley703c7ff2014-01-25 23:46:23 +00001957 {
1958 m = 0;
1959 break;
1960 }
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001961#else
1962 if (crc != questions_crc(header, (unsigned int)m, daemon->namebuff))
Simon Kelley703c7ff2014-01-25 23:46:23 +00001963 {
1964 m = 0;
1965 break;
1966 }
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001967#endif
1968
1969 m = process_reply(header, now, last_server, (unsigned int)m,
Simon Kelleye66b4df2015-04-28 20:45:57 +01001970 option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001971 ad_reqd, do_bit, added_pheader, check_subnet, &peer_addr);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001972
1973 break;
1974 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001975 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00001976
1977 /* In case of local answer or no connections made. */
1978 if (m == 0)
1979 m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001980 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001981 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00001982
Simon Kelleyb842bc92015-07-12 21:09:11 +01001983 check_log_writer(1);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001984
Simon Kelley4b5ea122013-04-22 10:18:26 +01001985 *length = htons(m);
1986
1987 if (m == 0 || !read_write(confd, packet, m + sizeof(u16), 0))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001988 return packet;
1989 }
1990}
1991
Simon Kelley16972692006-10-16 20:04:18 +01001992static struct frec *allocate_frec(time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001993{
Simon Kelley16972692006-10-16 20:04:18 +01001994 struct frec *f;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001995
Simon Kelley5aabfc72007-08-29 11:24:47 +01001996 if ((f = (struct frec *)whine_malloc(sizeof(struct frec))))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001997 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001998 f->next = daemon->frec_list;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001999 f->time = now;
Simon Kelley832af0b2007-01-21 20:01:28 +00002000 f->sentto = NULL;
Simon Kelley1a6bca82008-07-11 11:11:42 +01002001 f->rfd4 = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +00002002 f->flags = 0;
Simon Kelley1a6bca82008-07-11 11:11:42 +01002003#ifdef HAVE_IPV6
2004 f->rfd6 = NULL;
2005#endif
Simon Kelley3a237152013-12-12 12:15:50 +00002006#ifdef HAVE_DNSSEC
Simon Kelley97bc7982014-01-31 10:19:52 +00002007 f->dependent = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002008 f->blocking_query = NULL;
Simon Kelley4619d942014-01-16 19:53:06 +00002009 f->stash = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002010#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +01002011 daemon->frec_list = f;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002012 }
Simon Kelley16972692006-10-16 20:04:18 +01002013
2014 return f;
2015}
2016
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002017struct randfd *allocate_rfd(int family)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002018{
2019 static int finger = 0;
2020 int i;
2021
2022 /* limit the number of sockets we have open to avoid starvation of
2023 (eg) TFTP. Once we have a reasonable number, randomness should be OK */
2024
2025 for (i = 0; i < RANDOM_SOCKS; i++)
Simon Kelley9009d742008-11-14 20:04:27 +00002026 if (daemon->randomsocks[i].refcount == 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002027 {
Simon Kelley9009d742008-11-14 20:04:27 +00002028 if ((daemon->randomsocks[i].fd = random_sock(family)) == -1)
2029 break;
2030
Simon Kelley1a6bca82008-07-11 11:11:42 +01002031 daemon->randomsocks[i].refcount = 1;
2032 daemon->randomsocks[i].family = family;
2033 return &daemon->randomsocks[i];
2034 }
2035
Simon Kelley9009d742008-11-14 20:04:27 +00002036 /* No free ones or cannot get new socket, grab an existing one */
Simon Kelley1a6bca82008-07-11 11:11:42 +01002037 for (i = 0; i < RANDOM_SOCKS; i++)
2038 {
2039 int j = (i+finger) % RANDOM_SOCKS;
Simon Kelley9009d742008-11-14 20:04:27 +00002040 if (daemon->randomsocks[j].refcount != 0 &&
2041 daemon->randomsocks[j].family == family &&
2042 daemon->randomsocks[j].refcount != 0xffff)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002043 {
2044 finger = j;
2045 daemon->randomsocks[j].refcount++;
2046 return &daemon->randomsocks[j];
2047 }
2048 }
2049
2050 return NULL; /* doom */
2051}
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002052
2053void free_rfd(struct randfd *rfd)
2054{
2055 if (rfd && --(rfd->refcount) == 0)
2056 close(rfd->fd);
2057}
2058
Simon Kelley1a6bca82008-07-11 11:11:42 +01002059static void free_frec(struct frec *f)
2060{
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002061 free_rfd(f->rfd4);
Simon Kelley1a6bca82008-07-11 11:11:42 +01002062 f->rfd4 = NULL;
2063 f->sentto = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +00002064 f->flags = 0;
Simon Kelley1a6bca82008-07-11 11:11:42 +01002065
2066#ifdef HAVE_IPV6
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002067 free_rfd(f->rfd6);
Simon Kelley1a6bca82008-07-11 11:11:42 +01002068 f->rfd6 = NULL;
2069#endif
Simon Kelley3a237152013-12-12 12:15:50 +00002070
2071#ifdef HAVE_DNSSEC
2072 if (f->stash)
Simon Kelley0fc2f312014-01-08 10:26:58 +00002073 {
2074 blockdata_free(f->stash);
2075 f->stash = NULL;
2076 }
Simon Kelley3a237152013-12-12 12:15:50 +00002077
2078 /* Anything we're waiting on is pointless now, too */
2079 if (f->blocking_query)
2080 free_frec(f->blocking_query);
2081 f->blocking_query = NULL;
Simon Kelley39048ad2014-01-21 17:33:58 +00002082 f->dependent = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002083#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +01002084}
2085
Simon Kelley09f3b2c2017-05-09 01:34:02 +01002086
2087
Simon Kelley16972692006-10-16 20:04:18 +01002088/* if wait==NULL return a free or older than TIMEOUT record.
2089 else return *wait zero if one available, or *wait is delay to
Simon Kelley1a6bca82008-07-11 11:11:42 +01002090 when the oldest in-use record will expire. Impose an absolute
Simon Kelley3a237152013-12-12 12:15:50 +00002091 limit of 4*TIMEOUT before we wipe things (for random sockets).
2092 If force is set, always return a result, even if we have
2093 to allocate above the limit. */
2094struct frec *get_new_frec(time_t now, int *wait, int force)
Simon Kelley16972692006-10-16 20:04:18 +01002095{
Simon Kelley1a6bca82008-07-11 11:11:42 +01002096 struct frec *f, *oldest, *target;
Simon Kelley16972692006-10-16 20:04:18 +01002097 int count;
2098
2099 if (wait)
2100 *wait = 0;
2101
Simon Kelley1a6bca82008-07-11 11:11:42 +01002102 for (f = daemon->frec_list, oldest = NULL, target = NULL, count = 0; f; f = f->next, count++)
Simon Kelley832af0b2007-01-21 20:01:28 +00002103 if (!f->sentto)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002104 target = f;
2105 else
Simon Kelley16972692006-10-16 20:04:18 +01002106 {
Simon Kelley9a31b682015-12-15 10:20:39 +00002107#ifdef HAVE_DNSSEC
2108 /* Don't free DNSSEC sub-queries here, as we may end up with
2109 dangling references to them. They'll go when their "real" query
2110 is freed. */
2111 if (!f->dependent)
2112#endif
2113 {
2114 if (difftime(now, f->time) >= 4*TIMEOUT)
2115 {
2116 free_frec(f);
2117 target = f;
2118 }
2119
2120
2121 if (!oldest || difftime(f->time, oldest->time) <= 0)
2122 oldest = f;
2123 }
Simon Kelley16972692006-10-16 20:04:18 +01002124 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01002125
2126 if (target)
2127 {
2128 target->time = now;
2129 return target;
2130 }
Simon Kelley16972692006-10-16 20:04:18 +01002131
2132 /* can't find empty one, use oldest if there is one
2133 and it's older than timeout */
Simon Kelley09f3b2c2017-05-09 01:34:02 +01002134 if (!force && oldest && ((int)difftime(now, oldest->time)) >= TIMEOUT)
Simon Kelley16972692006-10-16 20:04:18 +01002135 {
2136 /* keep stuff for twice timeout if we can by allocating a new
2137 record instead */
2138 if (difftime(now, oldest->time) < 2*TIMEOUT &&
2139 count <= daemon->ftabsize &&
2140 (f = allocate_frec(now)))
2141 return f;
2142
2143 if (!wait)
2144 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01002145 free_frec(oldest);
Simon Kelley16972692006-10-16 20:04:18 +01002146 oldest->time = now;
2147 }
2148 return oldest;
2149 }
2150
2151 /* none available, calculate time 'till oldest record expires */
Simon Kelley3a237152013-12-12 12:15:50 +00002152 if (!force && count > daemon->ftabsize)
Simon Kelley16972692006-10-16 20:04:18 +01002153 {
Marcelo Salhab Brogliato0da5e892013-05-31 11:49:06 +01002154 static time_t last_log = 0;
2155
Simon Kelley16972692006-10-16 20:04:18 +01002156 if (oldest && wait)
2157 *wait = oldest->time + (time_t)TIMEOUT - now;
Marcelo Salhab Brogliato0da5e892013-05-31 11:49:06 +01002158
2159 if ((int)difftime(now, last_log) > 5)
2160 {
2161 last_log = now;
2162 my_syslog(LOG_WARNING, _("Maximum number of concurrent DNS queries reached (max: %d)"), daemon->ftabsize);
2163 }
2164
Simon Kelley16972692006-10-16 20:04:18 +01002165 return NULL;
2166 }
2167
2168 if (!(f = allocate_frec(now)) && wait)
2169 /* wait one second on malloc failure */
2170 *wait = 1;
2171
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002172 return f; /* OK if malloc fails and this is NULL */
2173}
Simon Kelley09f3b2c2017-05-09 01:34:02 +01002174
Simon Kelley832af0b2007-01-21 20:01:28 +00002175/* crc is all-ones if not known. */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002176static struct frec *lookup_frec(unsigned short id, void *hash)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002177{
2178 struct frec *f;
2179
Simon Kelley1a6bca82008-07-11 11:11:42 +01002180 for(f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00002181 if (f->sentto && f->new_id == id &&
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002182 (!hash || memcmp(hash, f->hash, HASH_SIZE) == 0))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002183 return f;
2184
2185 return NULL;
2186}
2187
2188static struct frec *lookup_frec_by_sender(unsigned short id,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01002189 union mysockaddr *addr,
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002190 void *hash)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002191{
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002192 struct frec *f;
2193
Simon Kelley1a6bca82008-07-11 11:11:42 +01002194 for(f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00002195 if (f->sentto &&
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002196 f->orig_id == id &&
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002197 memcmp(hash, f->hash, HASH_SIZE) == 0 &&
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002198 sockaddr_isequal(&f->source, addr))
2199 return f;
2200
2201 return NULL;
2202}
Simon Kelley47a95162014-07-08 22:22:02 +01002203
2204/* Send query packet again, if we can. */
2205void resend_query()
2206{
2207 if (daemon->srv_save)
2208 {
2209 int fd;
2210
2211 if (daemon->srv_save->sfd)
2212 fd = daemon->srv_save->sfd->fd;
2213 else if (daemon->rfd_save && daemon->rfd_save->refcount != 0)
2214 fd = daemon->rfd_save->fd;
2215 else
2216 return;
2217
Simon Kelleyff841eb2015-03-11 21:36:30 +00002218 while(retry_send(sendto(fd, daemon->packet, daemon->packet_len, 0,
2219 &daemon->srv_save->addr.sa,
2220 sa_len(&daemon->srv_save->addr))));
Simon Kelley47a95162014-07-08 22:22:02 +01002221 }
2222}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002223
Simon Kelley849a8352006-06-09 21:02:31 +01002224/* A server record is going away, remove references to it */
Simon Kelley5aabfc72007-08-29 11:24:47 +01002225void server_gone(struct server *server)
Simon Kelley849a8352006-06-09 21:02:31 +01002226{
2227 struct frec *f;
2228
Simon Kelley1a6bca82008-07-11 11:11:42 +01002229 for (f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00002230 if (f->sentto && f->sentto == server)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002231 free_frec(f);
Simon Kelley849a8352006-06-09 21:02:31 +01002232
2233 if (daemon->last_server == server)
2234 daemon->last_server = NULL;
2235
2236 if (daemon->srv_save == server)
2237 daemon->srv_save = NULL;
2238}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002239
Simon Kelley316e2732010-01-22 20:16:09 +00002240/* return unique random ids. */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002241static unsigned short get_id(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002242{
2243 unsigned short ret = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +00002244
Simon Kelley316e2732010-01-22 20:16:09 +00002245 do
Simon Kelley832af0b2007-01-21 20:01:28 +00002246 ret = rand16();
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002247 while (lookup_frec(ret, NULL));
Simon Kelley832af0b2007-01-21 20:01:28 +00002248
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002249 return ret;
2250}
2251
2252
2253
2254
2255