blob: 71bc4953698c544e5c291b1b0cd2d100bc570887 [file] [log] [blame]
Simon Kelleyd1ced3a2018-01-01 22:18:03 +00001/* dnsmasq is Copyright (c) 2000-2018 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;
Simon Kelleya6004d72017-10-25 17:48:19 +0100563
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 Kelley373e9172017-12-01 22:40:56 +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 Kelleyef3d1372017-12-05 22:37:29 +0000797
798 /* In strict order mode, there must be a server later in the chain
799 left to send to, otherwise without the forwardall mechanism,
800 code further on will cycle around the list forwever if they
801 all return REFUSED. Note that server is always non-NULL before
802 this executes. */
803 if (option_bool(OPT_ORDER))
804 for (server = forward->sentto->next; server; server = server->next)
805 if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR | SERV_LOOP)))
806 break;
807
Simon Kelley1a6bca82008-07-11 11:11:42 +0100808 /* recreate query from reply */
Simon Kelley5bb88f02015-12-21 16:23:47 +0000809 pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign, NULL);
Simon Kelleyef3d1372017-12-05 22:37:29 +0000810 if (!is_sign && server)
Simon Kelley832af0b2007-01-21 20:01:28 +0000811 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100812 header->ancount = htons(0);
813 header->nscount = htons(0);
814 header->arcount = htons(0);
815 if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
816 {
swiggerbd7bfa22015-06-01 20:54:59 +0100817 header->hb3 &= ~(HB3_QR | HB3_AA | HB3_TC);
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000818 header->hb4 &= ~(HB4_RA | HB4_RCODE | HB4_CD | HB4_AD);
Simon Kelley1801a292016-01-17 21:53:57 +0000819 if (forward->flags & FREC_CHECKING_DISABLED)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000820 header->hb4 |= HB4_CD;
Simon Kelley1801a292016-01-17 21:53:57 +0000821 if (forward->flags & FREC_AD_QUESTION)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000822 header->hb4 |= HB4_AD;
823 if (forward->flags & FREC_DO_QUESTION)
Simon Kelley33702ab2015-12-28 23:17:15 +0000824 add_do_bit(header, nn, (unsigned char *)pheader + plen);
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000825 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 +0100826 return;
827 }
828 }
829 }
Simon Kelley3a237152013-12-12 12:15:50 +0000830
831 server = forward->sentto;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100832 if ((forward->sentto->flags & SERV_TYPE) == 0)
833 {
Simon Kelley51967f92014-03-25 21:07:00 +0000834 if (RCODE(header) == REFUSED)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100835 server = NULL;
836 else
837 {
838 struct server *last_server;
Simon Kelley832af0b2007-01-21 20:01:28 +0000839
Simon Kelley1a6bca82008-07-11 11:11:42 +0100840 /* find good server by address if possible, otherwise assume the last one we sent to */
841 for (last_server = daemon->servers; last_server; last_server = last_server->next)
842 if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) &&
843 sockaddr_isequal(&last_server->addr, &serveraddr))
844 {
845 server = last_server;
846 break;
847 }
848 }
Simon Kelley28866e92011-02-14 20:19:14 +0000849 if (!option_bool(OPT_ALL_SERVERS))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100850 daemon->last_server = server;
851 }
Simon Kelleya77cec82015-05-08 16:25:38 +0100852
853 /* We tried resending to this server with a smaller maximum size and got an answer.
Ville Skyttäfaaf3062018-01-14 17:32:52 +0000854 Make that permanent. To avoid reduxing the packet size for a single dropped packet,
Simon Kelley86fa1042015-05-10 13:50:59 +0100855 only do this when we get a truncated answer, or one larger than the safe size. */
856 if (server && (forward->flags & FREC_TEST_PKTSZ) &&
857 ((header->hb3 & HB3_TC) || n >= SAFE_PKTSZ))
Simon Kelley22dee512017-10-13 22:54:00 +0100858 {
859 server->edns_pktsz = SAFE_PKTSZ;
860 prettyprint_addr(&server->addr, daemon->addrbuff);
Simon Kelleyebedcba2017-10-29 20:54:17 +0000861 my_syslog(LOG_WARNING, _("reducing DNS packet size for nameserver %s to %d"), daemon->addrbuff, SAFE_PKTSZ);
Simon Kelley22dee512017-10-13 22:54:00 +0100862 }
Simon Kelleya77cec82015-05-08 16:25:38 +0100863
Simon Kelley1a6bca82008-07-11 11:11:42 +0100864 /* If the answer is an error, keep the forward record in place in case
865 we get a good reply from another server. Kill it when we've
866 had replies from all to avoid filling the forwarding table when
867 everything is broken */
Baptiste Jonglez68f63122017-02-06 21:09:11 +0000868 if (forward->forwardall == 0 || --forward->forwardall == 1 ||
869 (RCODE(header) != REFUSED && RCODE(header) != SERVFAIL))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100870 {
Simon Kelleyfe3992f2015-04-03 21:25:05 +0100871 int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
Simon Kelleya6004d72017-10-25 17:48:19 +0100872
Simon Kelley3a237152013-12-12 12:15:50 +0000873 if (option_bool(OPT_NO_REBIND))
874 check_rebind = !(forward->flags & FREC_NOREBIND);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100875
Simon Kelley3a237152013-12-12 12:15:50 +0000876 /* Don't cache replies where DNSSEC validation was turned off, either
877 the upstream server told us so, or the original query specified it. */
878 if ((header->hb4 & HB4_CD) || (forward->flags & FREC_CHECKING_DISABLED))
879 no_cache_dnssec = 1;
880
881#ifdef HAVE_DNSSEC
Simon Kelley367341f2016-01-12 15:58:23 +0000882 if (server && (server->flags & SERV_DO_DNSSEC) &&
Simon Kelley57573712016-01-11 22:50:00 +0000883 option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED))
Simon Kelley3a237152013-12-12 12:15:50 +0000884 {
Simon Kelley9a31b682015-12-15 10:20:39 +0000885 int status = 0;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000886
887 /* We've had a reply already, which we're validating. Ignore this duplicate */
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000888 if (forward->blocking_query)
Simon Kelley0fc2f312014-01-08 10:26:58 +0000889 return;
Simon Kelley9a31b682015-12-15 10:20:39 +0000890
891 /* Truncated answer can't be validated.
Simon Kelley09f3b2c2017-05-09 01:34:02 +0100892 If this is an answer to a DNSSEC-generated query, we still
893 need to get the client to retry over TCP, so return
894 an answer with the TC bit set, even if the actual answer fits.
895 */
Simon Kelley9a31b682015-12-15 10:20:39 +0000896 if (header->hb3 & HB3_TC)
897 status = STAT_TRUNCATED;
898
899 while (1)
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000900 {
Simon Kelley9a31b682015-12-15 10:20:39 +0000901 /* As soon as anything returns BOGUS, we stop and unwind, to do otherwise
902 would invite infinite loops, since the answers to DNSKEY and DS queries
903 will not be cached, so they'll be repeated. */
904 if (status != STAT_BOGUS && status != STAT_TRUNCATED && status != STAT_ABANDONED)
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000905 {
Simon Kelley9a31b682015-12-15 10:20:39 +0000906 if (forward->flags & FREC_DNSKEY_QUERY)
907 status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
908 else if (forward->flags & FREC_DS_QUERY)
909 status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000910 else
Simon Kelley9a31b682015-12-15 10:20:39 +0000911 status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class,
Simon Kelleya6004d72017-10-25 17:48:19 +0100912 option_bool(OPT_DNSSEC_NO_SIGN) && (server->flags & SERV_DO_DNSSEC),
Simon Kelley373e9172017-12-01 22:40:56 +0000913 NULL, NULL);
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000914 }
Simon Kelley0fc2f312014-01-08 10:26:58 +0000915
Simon Kelley9a31b682015-12-15 10:20:39 +0000916 /* Can't validate, as we're missing key data. Put this
917 answer aside, whilst we get that. */
918 if (status == STAT_NEED_DS || status == STAT_NEED_KEY)
Simon Kelley3a237152013-12-12 12:15:50 +0000919 {
Simon Kelley9a31b682015-12-15 10:20:39 +0000920 struct frec *new, *orig;
Simon Kelley9d633042013-12-13 15:36:55 +0000921
Simon Kelley9a31b682015-12-15 10:20:39 +0000922 /* Free any saved query */
923 if (forward->stash)
924 blockdata_free(forward->stash);
925
926 /* Now save reply pending receipt of key data */
927 if (!(forward->stash = blockdata_alloc((char *)header, n)))
Simon Kelley97e618a2015-01-07 21:55:43 +0000928 return;
Simon Kelley9a31b682015-12-15 10:20:39 +0000929 forward->stash_len = n;
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000930
Simon Kelley9a31b682015-12-15 10:20:39 +0000931 /* Find the original query that started it all.... */
932 for (orig = forward; orig->dependent; orig = orig->dependent);
Simon Kelley7fa836e2014-02-10 20:11:24 +0000933
Simon Kelley9a31b682015-12-15 10:20:39 +0000934 if (--orig->work_counter == 0 || !(new = get_new_frec(now, NULL, 1)))
935 status = STAT_ABANDONED;
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000936 else
Simon Kelley3a237152013-12-12 12:15:50 +0000937 {
Simon Kelleyf344dbc2016-01-18 18:04:17 +0000938 int fd, type = SERV_DO_DNSSEC;
Simon Kelley9a31b682015-12-15 10:20:39 +0000939 struct frec *next = new->next;
Simon Kelley92be34a2016-01-16 18:39:54 +0000940 char *domain;
941
Simon Kelley9a31b682015-12-15 10:20:39 +0000942 *new = *forward; /* copy everything, then overwrite */
943 new->next = next;
944 new->blocking_query = NULL;
Simon Kelley92be34a2016-01-16 18:39:54 +0000945
946 /* Find server to forward to. This will normally be the
947 same as for the original query, but may be another if
948 servers for domains are involved. */
Simon Kelley09f3b2c2017-05-09 01:34:02 +0100949 if (search_servers(now, NULL, F_DNSSECOK, daemon->keyname, &type, &domain, NULL) == 0)
Simon Kelley92be34a2016-01-16 18:39:54 +0000950 {
Simon Kelleyf344dbc2016-01-18 18:04:17 +0000951 struct server *start = server, *new_server = NULL;
Simon Kelley09f3b2c2017-05-09 01:34:02 +0100952
953 while (1)
954 {
955 if (type == (start->flags & (SERV_TYPE | SERV_DO_DNSSEC)) &&
956 (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
957 !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
958 {
959 new_server = start;
960 if (server == start)
961 {
962 new_server = NULL;
963 break;
964 }
965 }
966
967 if (!(start = start->next))
968 start = daemon->servers;
969 if (start == server)
970 break;
971 }
972
973 if (new_server)
974 server = new_server;
Simon Kelley92be34a2016-01-16 18:39:54 +0000975 }
Simon Kelley09f3b2c2017-05-09 01:34:02 +0100976
Simon Kelley9a31b682015-12-15 10:20:39 +0000977 new->sentto = server;
978 new->rfd4 = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +0000979#ifdef HAVE_IPV6
Simon Kelley9a31b682015-12-15 10:20:39 +0000980 new->rfd6 = NULL;
Simon Kelley7fa836e2014-02-10 20:11:24 +0000981#endif
Simon Kelley9a31b682015-12-15 10:20:39 +0000982 new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY);
983
984 new->dependent = forward; /* to find query awaiting new one. */
985 forward->blocking_query = new; /* for garbage cleaning */
986 /* validate routines leave name of required record in daemon->keyname */
987 if (status == STAT_NEED_KEY)
Simon Kelley7fa836e2014-02-10 20:11:24 +0000988 {
Simon Kelley9a31b682015-12-15 10:20:39 +0000989 new->flags |= FREC_DNSKEY_QUERY;
Simon Kelley33702ab2015-12-28 23:17:15 +0000990 nn = dnssec_generate_query(header, ((unsigned char *) header) + server->edns_pktsz,
Simon Kelley9a31b682015-12-15 10:20:39 +0000991 daemon->keyname, forward->class, T_DNSKEY, &server->addr, server->edns_pktsz);
Simon Kelleyf1668d22014-01-08 16:53:27 +0000992 }
Simon Kelley9a31b682015-12-15 10:20:39 +0000993 else
994 {
995 new->flags |= FREC_DS_QUERY;
Simon Kelley33702ab2015-12-28 23:17:15 +0000996 nn = dnssec_generate_query(header,((unsigned char *) header) + server->edns_pktsz,
Simon Kelley9a31b682015-12-15 10:20:39 +0000997 daemon->keyname, forward->class, T_DS, &server->addr, server->edns_pktsz);
998 }
999 if ((hash = hash_questions(header, nn, daemon->namebuff)))
1000 memcpy(new->hash, hash, HASH_SIZE);
1001 new->new_id = get_id();
1002 header->id = htons(new->new_id);
1003 /* Save query for retransmission */
1004 new->stash = blockdata_alloc((char *)header, nn);
1005 new->stash_len = nn;
1006
1007 /* Don't resend this. */
1008 daemon->srv_save = NULL;
1009
1010 if (server->sfd)
1011 fd = server->sfd->fd;
1012 else
1013 {
1014 fd = -1;
1015#ifdef HAVE_IPV6
1016 if (server->addr.sa.sa_family == AF_INET6)
1017 {
1018 if (new->rfd6 || (new->rfd6 = allocate_rfd(AF_INET6)))
1019 fd = new->rfd6->fd;
1020 }
1021 else
1022#endif
1023 {
1024 if (new->rfd4 || (new->rfd4 = allocate_rfd(AF_INET)))
1025 fd = new->rfd4->fd;
1026 }
1027 }
1028
1029 if (fd != -1)
1030 {
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001031#ifdef HAVE_CONNTRACK
1032 /* Copy connection mark of incoming query to outgoing connection. */
1033 if (option_bool(OPT_CONNTRACK))
1034 {
1035 unsigned int mark;
1036 if (get_incoming_mark(&orig->source, &orig->dest, 0, &mark))
1037 setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
1038 }
1039#endif
Simon Kelley9a31b682015-12-15 10:20:39 +00001040 while (retry_send(sendto(fd, (char *)header, nn, 0,
1041 &server->addr.sa,
1042 sa_len(&server->addr))));
1043 server->queries++;
1044 }
1045 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00001046 return;
Simon Kelley3a237152013-12-12 12:15:50 +00001047 }
Simon Kelley3a237152013-12-12 12:15:50 +00001048
Simon Kelley9a31b682015-12-15 10:20:39 +00001049 /* Validated original answer, all done. */
1050 if (!forward->dependent)
1051 break;
1052
Josh Soref730c6742017-02-06 16:14:04 +00001053 /* validated subsidiary query, (and cached result)
Simon Kelley9a31b682015-12-15 10:20:39 +00001054 pop that and return to the previous query we were working on. */
Simon Kelley0744ca62014-01-25 16:40:15 +00001055 struct frec *prev = forward->dependent;
1056 free_frec(forward);
1057 forward = prev;
1058 forward->blocking_query = NULL; /* already gone */
1059 blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
1060 n = forward->stash_len;
Simon Kelley3a237152013-12-12 12:15:50 +00001061 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001062
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001063
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001064 no_cache_dnssec = 0;
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001065
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001066 if (status == STAT_TRUNCATED)
Simon Kelley0744ca62014-01-25 16:40:15 +00001067 header->hb3 |= HB3_TC;
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001068 else
Simon Kelley7fa836e2014-02-10 20:11:24 +00001069 {
Simon Kelley554b5802015-04-17 22:50:20 +01001070 char *result, *domain = "result";
Simon Kelley7fa836e2014-02-10 20:11:24 +00001071
Simon Kelley9a31b682015-12-15 10:20:39 +00001072 if (status == STAT_ABANDONED)
Simon Kelley150162b2015-03-27 09:58:26 +00001073 {
1074 result = "ABANDONED";
1075 status = STAT_BOGUS;
1076 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00001077 else
1078 result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
1079
Simon Kelley554b5802015-04-17 22:50:20 +01001080 if (status == STAT_BOGUS && extract_request(header, n, daemon->namebuff, NULL))
1081 domain = daemon->namebuff;
Simon Kelley9a31b682015-12-15 10:20:39 +00001082
Simon Kelley554b5802015-04-17 22:50:20 +01001083 log_query(F_KEYTAG | F_SECSTAT, domain, NULL, result);
Simon Kelley7fa836e2014-02-10 20:11:24 +00001084 }
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001085
Simon Kelley3a237152013-12-12 12:15:50 +00001086 if (status == STAT_SECURE)
1087 cache_secure = 1;
Simon Kelley3a237152013-12-12 12:15:50 +00001088 else if (status == STAT_BOGUS)
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001089 {
1090 no_cache_dnssec = 1;
1091 bogusanswer = 1;
1092 }
Simon Kelley3a237152013-12-12 12:15:50 +00001093 }
Simon Kelley83349b82014-02-10 21:02:01 +00001094#endif
1095
1096 /* restore CD bit to the value in the query */
1097 if (forward->flags & FREC_CHECKING_DISABLED)
1098 header->hb4 |= HB4_CD;
1099 else
1100 header->hb4 &= ~HB4_CD;
Simon Kelley3a237152013-12-12 12:15:50 +00001101
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001102 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 +00001103 forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION,
1104 forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->source)))
Simon Kelley832af0b2007-01-21 20:01:28 +00001105 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001106 header->id = htons(forward->orig_id);
Simon Kelley572b41e2011-02-18 18:11:18 +00001107 header->hb4 |= HB4_RA; /* recursion if available */
Simon Kelley5aa5f0f2015-12-21 17:20:35 +00001108#ifdef HAVE_DNSSEC
1109 /* 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 +01001110 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 +00001111 header, the answer is still bigger than 512, truncate it and mark it so. The client then retries with TCP. */
1112 if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER) && (nn > PACKETSZ))
1113 {
1114 header->ancount = htons(0);
1115 header->nscount = htons(0);
1116 header->arcount = htons(0);
1117 header->hb3 |= HB3_TC;
1118 nn = resize_packet(header, nn, NULL, 0);
1119 }
1120#endif
Simon Kelley54dd3932012-06-20 11:23:38 +01001121 send_from(forward->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
Simon Kelley50303b12012-04-04 22:13:17 +01001122 &forward->source, &forward->dest, forward->iface);
Simon Kelley832af0b2007-01-21 20:01:28 +00001123 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001124 free_frec(forward); /* cancel */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001125 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001126}
Simon Kelley44a2a312004-03-10 20:04:35 +00001127
Simon Kelley1a6bca82008-07-11 11:11:42 +01001128
Simon Kelley5aabfc72007-08-29 11:24:47 +01001129void receive_query(struct listener *listen, time_t now)
Simon Kelley44a2a312004-03-10 20:04:35 +00001130{
Simon Kelley572b41e2011-02-18 18:11:18 +00001131 struct dns_header *header = (struct dns_header *)daemon->packet;
Simon Kelley44a2a312004-03-10 20:04:35 +00001132 union mysockaddr source_addr;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001133 unsigned char *pheader;
1134 unsigned short type, udp_size = PACKETSZ; /* default if no EDNS0 */
Simon Kelley44a2a312004-03-10 20:04:35 +00001135 struct all_addr dst_addr;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001136 struct in_addr netmask, dst_addr_4;
Simon Kelleycdeda282006-03-16 20:16:06 +00001137 size_t m;
1138 ssize_t n;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001139 int if_index = 0, auth_dns = 0, do_bit = 0, have_pseudoheader = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001140#ifdef HAVE_AUTH
1141 int local_auth = 0;
1142#endif
Simon Kelley44a2a312004-03-10 20:04:35 +00001143 struct iovec iov[1];
1144 struct msghdr msg;
1145 struct cmsghdr *cmptr;
Simon Kelley44a2a312004-03-10 20:04:35 +00001146 union {
1147 struct cmsghdr align; /* this ensures alignment */
1148#ifdef HAVE_IPV6
1149 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
1150#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001151#if defined(HAVE_LINUX_NETWORK)
Simon Kelley44a2a312004-03-10 20:04:35 +00001152 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
Simon Kelley824af852008-02-12 20:43:05 +00001153#elif defined(IP_RECVDSTADDR) && defined(HAVE_SOLARIS_NETWORK)
1154 char control[CMSG_SPACE(sizeof(struct in_addr)) +
1155 CMSG_SPACE(sizeof(unsigned int))];
Simon Kelley44a2a312004-03-10 20:04:35 +00001156#elif defined(IP_RECVDSTADDR)
1157 char control[CMSG_SPACE(sizeof(struct in_addr)) +
1158 CMSG_SPACE(sizeof(struct sockaddr_dl))];
1159#endif
1160 } control_u;
Simon Kelley2329bef2013-12-03 13:41:16 +00001161#ifdef HAVE_IPV6
1162 /* Can always get recvd interface for IPv6 */
1163 int check_dst = !option_bool(OPT_NOWILD) || listen->family == AF_INET6;
1164#else
1165 int check_dst = !option_bool(OPT_NOWILD);
1166#endif
1167
Simon Kelleycdeda282006-03-16 20:16:06 +00001168 /* packet buffer overwritten */
1169 daemon->srv_save = NULL;
1170
Hans Dedecker98906272014-12-09 22:22:53 +00001171 dst_addr_4.s_addr = dst_addr.addr.addr4.s_addr = 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001172 netmask.s_addr = 0;
1173
Simon Kelley7e5664b2013-04-05 16:57:41 +01001174 if (option_bool(OPT_NOWILD) && listen->iface)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001175 {
Simon Kelley4f7b3042012-11-28 21:27:02 +00001176 auth_dns = listen->iface->dns_auth;
1177
1178 if (listen->family == AF_INET)
1179 {
Hans Dedecker98906272014-12-09 22:22:53 +00001180 dst_addr_4 = dst_addr.addr.addr4 = listen->iface->addr.in.sin_addr;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001181 netmask = listen->iface->netmask;
1182 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001183 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00001184
Simon Kelley3be34542004-09-11 19:12:13 +01001185 iov[0].iov_base = daemon->packet;
1186 iov[0].iov_len = daemon->edns_pktsz;
Simon Kelley44a2a312004-03-10 20:04:35 +00001187
1188 msg.msg_control = control_u.control;
1189 msg.msg_controllen = sizeof(control_u);
1190 msg.msg_flags = 0;
1191 msg.msg_name = &source_addr;
1192 msg.msg_namelen = sizeof(source_addr);
1193 msg.msg_iov = iov;
1194 msg.msg_iovlen = 1;
1195
Simon Kelleyde379512004-06-22 20:23:33 +01001196 if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
Simon Kelley3be34542004-09-11 19:12:13 +01001197 return;
Simon Kelley44a2a312004-03-10 20:04:35 +00001198
Simon Kelley572b41e2011-02-18 18:11:18 +00001199 if (n < (int)sizeof(struct dns_header) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001200 (msg.msg_flags & MSG_TRUNC) ||
Simon Kelley572b41e2011-02-18 18:11:18 +00001201 (header->hb3 & HB3_QR))
Simon Kelley3be34542004-09-11 19:12:13 +01001202 return;
Simon Kelley63437ff2017-09-06 22:34:21 +01001203
1204 /* Clear buffer beyond request to avoid risk of
1205 information disclosure. */
1206 memset(daemon->packet + n, 0, daemon->edns_pktsz - n);
Simon Kelley44a2a312004-03-10 20:04:35 +00001207
Simon Kelley26128d22004-11-14 16:43:54 +00001208 source_addr.sa.sa_family = listen->family;
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001209
1210 if (listen->family == AF_INET)
1211 {
1212 /* Source-port == 0 is an error, we can't send back to that.
1213 http://www.ietf.org/mail-archive/web/dnsop/current/msg11441.html */
1214 if (source_addr.in.sin_port == 0)
1215 return;
1216 }
Simon Kelley26128d22004-11-14 16:43:54 +00001217#ifdef HAVE_IPV6
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001218 else
1219 {
1220 /* Source-port == 0 is an error, we can't send back to that. */
1221 if (source_addr.in6.sin6_port == 0)
1222 return;
1223 source_addr.in6.sin6_flowinfo = 0;
1224 }
Simon Kelley26128d22004-11-14 16:43:54 +00001225#endif
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001226
Simon Kelleyc8a80482014-03-05 14:29:54 +00001227 /* We can be configured to only accept queries from at-most-one-hop-away addresses. */
1228 if (option_bool(OPT_LOCAL_SERVICE))
1229 {
1230 struct addrlist *addr;
1231#ifdef HAVE_IPV6
1232 if (listen->family == AF_INET6)
1233 {
1234 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1235 if ((addr->flags & ADDRLIST_IPV6) &&
1236 is_same_net6(&addr->addr.addr.addr6, &source_addr.in6.sin6_addr, addr->prefixlen))
1237 break;
1238 }
1239 else
1240#endif
1241 {
1242 struct in_addr netmask;
1243 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1244 {
Richard Genoud15b1b7e2014-09-17 21:12:00 +01001245 netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
Simon Kelleyc8a80482014-03-05 14:29:54 +00001246 if (!(addr->flags & ADDRLIST_IPV6) &&
1247 is_same_net(addr->addr.addr.addr4, source_addr.in.sin_addr, netmask))
1248 break;
1249 }
1250 }
1251 if (!addr)
1252 {
Simon Kelley0c8584e2014-03-12 20:12:56 +00001253 static int warned = 0;
1254 if (!warned)
1255 {
1256 my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
1257 warned = 1;
1258 }
Simon Kelleyc8a80482014-03-05 14:29:54 +00001259 return;
1260 }
1261 }
1262
Simon Kelley2329bef2013-12-03 13:41:16 +00001263 if (check_dst)
Simon Kelley44a2a312004-03-10 20:04:35 +00001264 {
Simon Kelley8a911cc2004-03-16 18:35:52 +00001265 struct ifreq ifr;
1266
Simon Kelley26128d22004-11-14 16:43:54 +00001267 if (msg.msg_controllen < sizeof(struct cmsghdr))
1268 return;
1269
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001270#if defined(HAVE_LINUX_NETWORK)
Simon Kelley26128d22004-11-14 16:43:54 +00001271 if (listen->family == AF_INET)
1272 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelleyc72daea2012-01-05 21:33:27 +00001273 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
Simon Kelley26128d22004-11-14 16:43:54 +00001274 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001275 union {
1276 unsigned char *c;
1277 struct in_pktinfo *p;
1278 } p;
1279 p.c = CMSG_DATA(cmptr);
1280 dst_addr_4 = dst_addr.addr.addr4 = p.p->ipi_spec_dst;
1281 if_index = p.p->ipi_ifindex;
Simon Kelley26128d22004-11-14 16:43:54 +00001282 }
1283#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
1284 if (listen->family == AF_INET)
1285 {
1286 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001287 {
1288 union {
1289 unsigned char *c;
1290 unsigned int *i;
1291 struct in_addr *a;
1292#ifndef HAVE_SOLARIS_NETWORK
1293 struct sockaddr_dl *s;
Simon Kelley824af852008-02-12 20:43:05 +00001294#endif
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001295 } p;
1296 p.c = CMSG_DATA(cmptr);
1297 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
1298 dst_addr_4 = dst_addr.addr.addr4 = *(p.a);
1299 else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
1300#ifdef HAVE_SOLARIS_NETWORK
1301 if_index = *(p.i);
1302#else
1303 if_index = p.s->sdl_index;
1304#endif
1305 }
Simon Kelley26128d22004-11-14 16:43:54 +00001306 }
1307#endif
1308
1309#ifdef HAVE_IPV6
1310 if (listen->family == AF_INET6)
1311 {
1312 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelleyc72daea2012-01-05 21:33:27 +00001313 if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
Simon Kelley26128d22004-11-14 16:43:54 +00001314 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001315 union {
1316 unsigned char *c;
1317 struct in6_pktinfo *p;
1318 } p;
1319 p.c = CMSG_DATA(cmptr);
1320
1321 dst_addr.addr.addr6 = p.p->ipi6_addr;
1322 if_index = p.p->ipi6_ifindex;
Simon Kelley26128d22004-11-14 16:43:54 +00001323 }
1324 }
1325#endif
1326
1327 /* enforce available interface configuration */
1328
Simon Kelleye25db1f2013-01-29 22:10:26 +00001329 if (!indextoname(listen->fd, if_index, ifr.ifr_name))
Simon Kelley832af0b2007-01-21 20:01:28 +00001330 return;
1331
Simon Kelleye25db1f2013-01-29 22:10:26 +00001332 if (!iface_check(listen->family, &dst_addr, ifr.ifr_name, &auth_dns))
1333 {
1334 if (!option_bool(OPT_CLEVERBIND))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001335 enumerate_interfaces(0);
Simon Kelley3f2873d2013-05-14 11:28:47 +01001336 if (!loopback_exception(listen->fd, listen->family, &dst_addr, ifr.ifr_name) &&
1337 !label_exception(if_index, listen->family, &dst_addr))
Simon Kelleye25db1f2013-01-29 22:10:26 +00001338 return;
1339 }
1340
Simon Kelley552af8b2012-02-29 20:10:31 +00001341 if (listen->family == AF_INET && option_bool(OPT_LOCALISE))
1342 {
1343 struct irec *iface;
1344
Josh Soref730c6742017-02-06 16:14:04 +00001345 /* get the netmask of the interface which has the address we were sent to.
klemens43517fc2017-02-19 15:53:37 +00001346 This is no necessarily the interface we arrived on. */
Simon Kelley552af8b2012-02-29 20:10:31 +00001347
1348 for (iface = daemon->interfaces; iface; iface = iface->next)
1349 if (iface->addr.sa.sa_family == AF_INET &&
1350 iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
1351 break;
1352
1353 /* interface may be new */
Simon Kelleye25db1f2013-01-29 22:10:26 +00001354 if (!iface && !option_bool(OPT_CLEVERBIND))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001355 enumerate_interfaces(0);
Simon Kelley552af8b2012-02-29 20:10:31 +00001356
1357 for (iface = daemon->interfaces; iface; iface = iface->next)
1358 if (iface->addr.sa.sa_family == AF_INET &&
1359 iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
1360 break;
1361
1362 /* If we failed, abandon localisation */
1363 if (iface)
1364 netmask = iface->netmask;
1365 else
1366 dst_addr_4.s_addr = 0;
1367 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001368 }
Simon Kelley25cf5e32015-01-09 15:53:03 +00001369
1370 /* log_query gets called indirectly all over the place, so
1371 pass these in global variables - sorry. */
1372 daemon->log_display_id = ++daemon->log_id;
1373 daemon->log_source_addr = &source_addr;
Simon Kelley44a2a312004-03-10 20:04:35 +00001374
Simon Kelleycdeda282006-03-16 20:16:06 +00001375 if (extract_request(header, (size_t)n, daemon->namebuff, &type))
Simon Kelley44a2a312004-03-10 20:04:35 +00001376 {
Simon Kelleyb485ed92013-10-18 22:00:39 +01001377#ifdef HAVE_AUTH
1378 struct auth_zone *zone;
1379#endif
Simon Kelley610e7822014-02-06 14:45:17 +00001380 char *types = querystr(auth_dns ? "auth" : "query", type);
1381
Simon Kelley44a2a312004-03-10 20:04:35 +00001382 if (listen->family == AF_INET)
Simon Kelley3be34542004-09-11 19:12:13 +01001383 log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
Simon Kelley1a6bca82008-07-11 11:11:42 +01001384 (struct all_addr *)&source_addr.in.sin_addr, types);
Simon Kelley44a2a312004-03-10 20:04:35 +00001385#ifdef HAVE_IPV6
1386 else
Simon Kelley3be34542004-09-11 19:12:13 +01001387 log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
Simon Kelley1a6bca82008-07-11 11:11:42 +01001388 (struct all_addr *)&source_addr.in6.sin6_addr, types);
Simon Kelley44a2a312004-03-10 20:04:35 +00001389#endif
Simon Kelley44a2a312004-03-10 20:04:35 +00001390
Simon Kelley4820dce2012-12-18 18:30:30 +00001391#ifdef HAVE_AUTH
Simon Kelleyb485ed92013-10-18 22:00:39 +01001392 /* find queries for zones we're authoritative for, and answer them directly */
Simon Kelley3a3965a2015-08-09 17:45:06 +01001393 if (!auth_dns && !option_bool(OPT_LOCALISE))
Simon Kelley6008bdb2013-10-21 21:47:03 +01001394 for (zone = daemon->auth_zones; zone; zone = zone->next)
1395 if (in_zone(zone, daemon->namebuff, NULL))
1396 {
1397 auth_dns = 1;
1398 local_auth = 1;
1399 break;
1400 }
Simon Kelleyb485ed92013-10-18 22:00:39 +01001401#endif
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01001402
1403#ifdef HAVE_LOOP
1404 /* Check for forwarding loop */
1405 if (detect_loop(daemon->namebuff, type))
1406 return;
1407#endif
Simon Kelleyb485ed92013-10-18 22:00:39 +01001408 }
1409
Simon Kelley5bb88f02015-12-21 16:23:47 +00001410 if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL, NULL))
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001411 {
1412 unsigned short flags;
1413
1414 have_pseudoheader = 1;
1415 GETSHORT(udp_size, pheader);
1416 pheader += 2; /* ext_rcode */
1417 GETSHORT(flags, pheader);
1418
1419 if (flags & 0x8000)
1420 do_bit = 1;/* do bit */
1421
1422 /* If the client provides an EDNS0 UDP size, use that to limit our reply.
1423 (bounded by the maximum configured). If no EDNS0, then it
1424 defaults to 512 */
1425 if (udp_size > daemon->edns_pktsz)
1426 udp_size = daemon->edns_pktsz;
Simon Kelleya3303e12017-09-07 20:45:00 +01001427 else if (udp_size < PACKETSZ)
1428 udp_size = PACKETSZ; /* Sanity check - can't reduce below default. RFC 6891 6.2.3 */
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001429 }
1430
Simon Kelleyb485ed92013-10-18 22:00:39 +01001431#ifdef HAVE_AUTH
Simon Kelley4f7b3042012-11-28 21:27:02 +00001432 if (auth_dns)
Simon Kelley824af852008-02-12 20:43:05 +00001433 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001434 m = answer_auth(header, ((char *) header) + udp_size, (size_t)n, now, &source_addr,
1435 local_auth, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001436 if (m >= 1)
Simon Kelleyb485ed92013-10-18 22:00:39 +01001437 {
1438 send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
1439 (char *)header, m, &source_addr, &dst_addr, if_index);
1440 daemon->auth_answer++;
1441 }
Simon Kelley824af852008-02-12 20:43:05 +00001442 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001443 else
Simon Kelley4820dce2012-12-18 18:30:30 +00001444#endif
Simon Kelley4f7b3042012-11-28 21:27:02 +00001445 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001446 int ad_reqd = do_bit;
1447 /* RFC 6840 5.7 */
1448 if (header->hb4 & HB4_AD)
1449 ad_reqd = 1;
1450
1451 m = answer_request(header, ((char *) header) + udp_size, (size_t)n,
1452 dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001453
1454 if (m >= 1)
1455 {
1456 send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
1457 (char *)header, m, &source_addr, &dst_addr, if_index);
1458 daemon->local_answer++;
1459 }
1460 else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
Simon Kelley613ad152014-02-25 23:02:28 +00001461 header, (size_t)n, now, NULL, ad_reqd, do_bit))
Simon Kelley4f7b3042012-11-28 21:27:02 +00001462 daemon->queries_forwarded++;
1463 else
1464 daemon->local_answer++;
1465 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001466}
1467
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001468#ifdef HAVE_DNSSEC
Josh Soref730c6742017-02-06 16:14:04 +00001469/* Recurse up the key hierarchy */
Simon Kelley7fa836e2014-02-10 20:11:24 +00001470static int tcp_key_recurse(time_t now, int status, struct dns_header *header, size_t n,
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001471 int class, char *name, char *keyname, struct server *server,
1472 int have_mark, unsigned int mark, int *keycount)
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001473{
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001474 int new_status;
Simon Kelley9a31b682015-12-15 10:20:39 +00001475 unsigned char *packet = NULL;
Simon Kelley9a31b682015-12-15 10:20:39 +00001476 unsigned char *payload = NULL;
1477 struct dns_header *new_header = NULL;
1478 u16 *length = NULL;
Simon Kelley361dfe52017-02-10 21:12:30 +00001479
Simon Kelley9a31b682015-12-15 10:20:39 +00001480 while (1)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001481 {
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001482 int type = SERV_DO_DNSSEC;
1483 char *domain;
1484 size_t m;
1485 unsigned char c1, c2;
Simon Kelley361dfe52017-02-10 21:12:30 +00001486 struct server *firstsendto = NULL;
1487
Simon Kelley9a31b682015-12-15 10:20:39 +00001488 /* limit the amount of work we do, to avoid cycling forever on loops in the DNS */
1489 if (--(*keycount) == 0)
1490 new_status = STAT_ABANDONED;
1491 else if (status == STAT_NEED_KEY)
1492 new_status = dnssec_validate_by_ds(now, header, n, name, keyname, class);
1493 else if (status == STAT_NEED_DS)
1494 new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
1495 else
James Bottomleye33b4872017-03-17 21:44:10 +00001496 new_status = dnssec_validate_reply(now, header, n, name, keyname, &class,
Simon Kelleya6004d72017-10-25 17:48:19 +01001497 option_bool(OPT_DNSSEC_NO_SIGN) && (server->flags & SERV_DO_DNSSEC),
Simon Kelley373e9172017-12-01 22:40:56 +00001498 NULL, NULL);
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001499
Simon Kelley9a31b682015-12-15 10:20:39 +00001500 if (new_status != STAT_NEED_DS && new_status != STAT_NEED_KEY)
1501 break;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001502
Simon Kelley9a31b682015-12-15 10:20:39 +00001503 /* Can't validate because we need a key/DS whose name now in keyname.
1504 Make query for same, and recurse to validate */
Simon Kelley7fa836e2014-02-10 20:11:24 +00001505 if (!packet)
Simon Kelley9a31b682015-12-15 10:20:39 +00001506 {
1507 packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
1508 payload = &packet[2];
1509 new_header = (struct dns_header *)payload;
1510 length = (u16 *)packet;
1511 }
1512
1513 if (!packet)
1514 {
1515 new_status = STAT_ABANDONED;
1516 break;
1517 }
1518
Simon Kelley33702ab2015-12-28 23:17:15 +00001519 m = dnssec_generate_query(new_header, ((unsigned char *) new_header) + 65536, keyname, class,
Simon Kelleya77cec82015-05-08 16:25:38 +01001520 new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS, &server->addr, server->edns_pktsz);
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001521
Simon Kelley7fa836e2014-02-10 20:11:24 +00001522 *length = htons(m);
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001523
1524 /* Find server to forward to. This will normally be the
1525 same as for the original query, but may be another if
1526 servers for domains are involved. */
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001527 if (search_servers(now, NULL, F_DNSSECOK, keyname, &type, &domain, NULL) != 0)
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001528 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001529 new_status = STAT_ABANDONED;
1530 break;
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001531 }
Simon Kelley361dfe52017-02-10 21:12:30 +00001532
Simon Kelley361dfe52017-02-10 21:12:30 +00001533 while (1)
1534 {
1535 if (!firstsendto)
1536 firstsendto = server;
1537 else
1538 {
1539 if (!(server = server->next))
1540 server = daemon->servers;
1541 if (server == firstsendto)
1542 {
1543 /* can't find server to accept our query. */
1544 new_status = STAT_ABANDONED;
1545 break;
1546 }
1547 }
1548
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001549 if (type != (server->flags & (SERV_TYPE | SERV_DO_DNSSEC)) ||
Simon Kelley361dfe52017-02-10 21:12:30 +00001550 (type == SERV_HAS_DOMAIN && !hostname_isequal(domain, server->domain)) ||
1551 (server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
1552 continue;
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001553
1554 retry:
1555 /* may need to make new connection. */
1556 if (server->tcpfd == -1)
1557 {
1558 if ((server->tcpfd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
Simon Kelley361dfe52017-02-10 21:12:30 +00001559 continue; /* No good, next server */
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001560
1561#ifdef HAVE_CONNTRACK
1562 /* Copy connection mark of incoming query to outgoing connection. */
1563 if (have_mark)
1564 setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
1565#endif
1566
Simon Kelley9d6918d2017-10-13 17:55:09 +01001567 if (!local_bind(server->tcpfd, &server->source_addr, server->interface, 0, 1) ||
Simon Kelley09f3b2c2017-05-09 01:34:02 +01001568 connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) == -1)
1569 {
1570 close(server->tcpfd);
1571 server->tcpfd = -1;
1572 continue; /* No good, next server */
1573 }
1574
1575 server->flags &= ~SERV_GOT_TCP;
1576 }
Simon Kelley361dfe52017-02-10 21:12:30 +00001577
1578 if (!read_write(server->tcpfd, packet, m + sizeof(u16), 0) ||
1579 !read_write(server->tcpfd, &c1, 1, 1) ||
1580 !read_write(server->tcpfd, &c2, 1, 1) ||
1581 !read_write(server->tcpfd, payload, (c1 << 8) | c2, 1))
1582 {
1583 close(server->tcpfd);
1584 server->tcpfd = -1;
1585 /* We get data then EOF, reopen connection to same server,
1586 else try next. This avoids DoS from a server which accepts
1587 connections and then closes them. */
1588 if (server->flags & SERV_GOT_TCP)
1589 goto retry;
1590 else
1591 continue;
1592 }
1593
1594 server->flags |= SERV_GOT_TCP;
1595
1596 m = (c1 << 8) | c2;
1597 new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, have_mark, mark, keycount);
1598 break;
1599 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001600
1601 if (new_status != STAT_OK)
1602 break;
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001603 }
Simon Kelley361dfe52017-02-10 21:12:30 +00001604
Simon Kelley9a31b682015-12-15 10:20:39 +00001605 if (packet)
1606 free(packet);
1607
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001608 return new_status;
1609}
1610#endif
1611
1612
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001613/* The daemon forks before calling this: it should deal with one connection,
Josh Soref730c6742017-02-06 16:14:04 +00001614 blocking as necessary, and then return. Note, need to be a bit careful
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001615 about resources for debug mode, when the fork is suppressed: that's
1616 done by the caller. */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001617unsigned char *tcp_request(int confd, time_t now,
Simon Kelley4f7b3042012-11-28 21:27:02 +00001618 union mysockaddr *local_addr, struct in_addr netmask, int auth_dns)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001619{
Simon Kelley28866e92011-02-14 20:19:14 +00001620 size_t size = 0;
1621 int norebind = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001622#ifdef HAVE_AUTH
Simon Kelley19b16892013-10-20 10:19:39 +01001623 int local_auth = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001624#endif
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001625 int checking_disabled, do_bit, added_pheader = 0, have_pseudoheader = 0;
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001626 int check_subnet, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
Simon Kelleycdeda282006-03-16 20:16:06 +00001627 size_t m;
Simon Kelleyee86ce62012-12-07 11:54:46 +00001628 unsigned short qtype;
1629 unsigned int gotname;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001630 unsigned char c1, c2;
Simon Kelley4b5ea122013-04-22 10:18:26 +01001631 /* Max TCP packet + slop + size */
1632 unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
1633 unsigned char *payload = &packet[2];
1634 /* largest field in header is 16-bits, so this is still sufficiently aligned */
1635 struct dns_header *header = (struct dns_header *)payload;
1636 u16 *length = (u16 *)packet;
Simon Kelley3be34542004-09-11 19:12:13 +01001637 struct server *last_server;
Simon Kelley7de060b2011-08-26 17:24:52 +01001638 struct in_addr dst_addr_4;
1639 union mysockaddr peer_addr;
1640 socklen_t peer_len = sizeof(union mysockaddr);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001641 int query_count = 0;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001642 unsigned char *pheader;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001643 unsigned int mark = 0;
1644 int have_mark = 0;
Simon Kelley25cf5e32015-01-09 15:53:03 +00001645
Simon Kelleyd05dd582016-01-19 21:23:30 +00001646 (void)mark;
1647 (void)have_mark;
1648
Simon Kelley7de060b2011-08-26 17:24:52 +01001649 if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
1650 return packet;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001651
1652#ifdef HAVE_CONNTRACK
1653 /* Get connection mark of incoming query to set on outgoing connections. */
1654 if (option_bool(OPT_CONNTRACK))
1655 {
1656 struct all_addr local;
1657#ifdef HAVE_IPV6
1658 if (local_addr->sa.sa_family == AF_INET6)
1659 local.addr.addr6 = local_addr->in6.sin6_addr;
1660 else
1661#endif
1662 local.addr.addr4 = local_addr->in.sin_addr;
1663
1664 have_mark = get_incoming_mark(&peer_addr, &local, 1, &mark);
1665 }
1666#endif
1667
Simon Kelleyc8a80482014-03-05 14:29:54 +00001668 /* We can be configured to only accept queries from at-most-one-hop-away addresses. */
1669 if (option_bool(OPT_LOCAL_SERVICE))
1670 {
1671 struct addrlist *addr;
1672#ifdef HAVE_IPV6
1673 if (peer_addr.sa.sa_family == AF_INET6)
1674 {
1675 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1676 if ((addr->flags & ADDRLIST_IPV6) &&
1677 is_same_net6(&addr->addr.addr.addr6, &peer_addr.in6.sin6_addr, addr->prefixlen))
1678 break;
1679 }
1680 else
1681#endif
1682 {
1683 struct in_addr netmask;
1684 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1685 {
Richard Genoud15b1b7e2014-09-17 21:12:00 +01001686 netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
Simon Kelleyc8a80482014-03-05 14:29:54 +00001687 if (!(addr->flags & ADDRLIST_IPV6) &&
1688 is_same_net(addr->addr.addr.addr4, peer_addr.in.sin_addr, netmask))
1689 break;
1690 }
1691 }
1692 if (!addr)
1693 {
1694 my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
1695 return packet;
1696 }
1697 }
Simon Kelley7de060b2011-08-26 17:24:52 +01001698
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001699 while (1)
1700 {
Simon Kelley25cf5e32015-01-09 15:53:03 +00001701 if (query_count == TCP_MAX_QUERIES ||
1702 !packet ||
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001703 !read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
1704 !(size = c1 << 8 | c2) ||
Simon Kelley4b5ea122013-04-22 10:18:26 +01001705 !read_write(confd, payload, size, 1))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001706 return packet;
1707
Simon Kelley572b41e2011-02-18 18:11:18 +00001708 if (size < (int)sizeof(struct dns_header))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001709 continue;
Simon Kelley63437ff2017-09-06 22:34:21 +01001710
1711 /* Clear buffer beyond request to avoid risk of
1712 information disclosure. */
1713 memset(payload + size, 0, 65536 - size);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001714
Simon Kelley25cf5e32015-01-09 15:53:03 +00001715 query_count++;
1716
1717 /* log_query gets called indirectly all over the place, so
1718 pass these in global variables - sorry. */
1719 daemon->log_display_id = ++daemon->log_id;
1720 daemon->log_source_addr = &peer_addr;
1721
Simon Kelley28866e92011-02-14 20:19:14 +00001722 /* save state of "cd" flag in query */
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001723 if ((checking_disabled = header->hb4 & HB4_CD))
1724 no_cache_dnssec = 1;
Simon Kelley28866e92011-02-14 20:19:14 +00001725
Simon Kelley3be34542004-09-11 19:12:13 +01001726 if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001727 {
Simon Kelleyb485ed92013-10-18 22:00:39 +01001728#ifdef HAVE_AUTH
1729 struct auth_zone *zone;
1730#endif
Simon Kelley610e7822014-02-06 14:45:17 +00001731 char *types = querystr(auth_dns ? "auth" : "query", qtype);
Simon Kelley7de060b2011-08-26 17:24:52 +01001732
1733 if (peer_addr.sa.sa_family == AF_INET)
1734 log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
1735 (struct all_addr *)&peer_addr.in.sin_addr, types);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001736#ifdef HAVE_IPV6
Simon Kelley7de060b2011-08-26 17:24:52 +01001737 else
1738 log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
1739 (struct all_addr *)&peer_addr.in6.sin6_addr, types);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001740#endif
Simon Kelleyb485ed92013-10-18 22:00:39 +01001741
1742#ifdef HAVE_AUTH
1743 /* find queries for zones we're authoritative for, and answer them directly */
Simon Kelley3a3965a2015-08-09 17:45:06 +01001744 if (!auth_dns && !option_bool(OPT_LOCALISE))
Simon Kelley6008bdb2013-10-21 21:47:03 +01001745 for (zone = daemon->auth_zones; zone; zone = zone->next)
1746 if (in_zone(zone, daemon->namebuff, NULL))
1747 {
1748 auth_dns = 1;
1749 local_auth = 1;
1750 break;
1751 }
Simon Kelleyb485ed92013-10-18 22:00:39 +01001752#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001753 }
1754
Simon Kelley7de060b2011-08-26 17:24:52 +01001755 if (local_addr->sa.sa_family == AF_INET)
1756 dst_addr_4 = local_addr->in.sin_addr;
1757 else
1758 dst_addr_4.s_addr = 0;
1759
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001760 do_bit = 0;
1761
Simon Kelley5bb88f02015-12-21 16:23:47 +00001762 if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL, NULL))
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001763 {
1764 unsigned short flags;
1765
1766 have_pseudoheader = 1;
1767 pheader += 4; /* udp_size, ext_rcode */
1768 GETSHORT(flags, pheader);
1769
1770 if (flags & 0x8000)
Simon Kelley5bb88f02015-12-21 16:23:47 +00001771 do_bit = 1; /* do bit */
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001772 }
1773
Simon Kelley4820dce2012-12-18 18:30:30 +00001774#ifdef HAVE_AUTH
Simon Kelley4f7b3042012-11-28 21:27:02 +00001775 if (auth_dns)
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001776 m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr,
1777 local_auth, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001778 else
Simon Kelley4820dce2012-12-18 18:30:30 +00001779#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001780 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001781 int ad_reqd = do_bit;
1782 /* RFC 6840 5.7 */
1783 if (header->hb4 & HB4_AD)
1784 ad_reqd = 1;
1785
1786 /* m > 0 if answered from cache */
1787 m = answer_request(header, ((char *) header) + 65536, (size_t)size,
1788 dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001789
Simon Kelley4f7b3042012-11-28 21:27:02 +00001790 /* Do this by steam now we're not in the select() loop */
Simon Kelleyb842bc92015-07-12 21:09:11 +01001791 check_log_writer(1);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001792
1793 if (m == 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001794 {
Simon Kelley4f7b3042012-11-28 21:27:02 +00001795 unsigned int flags = 0;
1796 struct all_addr *addrp = NULL;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001797 int type = SERV_DO_DNSSEC;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001798 char *domain = NULL;
Simon Kelley6fd5d792017-10-13 22:26:40 +01001799 unsigned char *oph = find_pseudoheader(header, size, NULL, NULL, NULL, NULL);
Simon Kelleyed4c0762013-10-08 20:46:34 +01001800
Simon Kelley6fd5d792017-10-13 22:26:40 +01001801 size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet);
1802
Simon Kelley4f7b3042012-11-28 21:27:02 +00001803 if (gotname)
1804 flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
Simon Kelley6fd5d792017-10-13 22:26:40 +01001805
1806#ifdef HAVE_DNSSEC
1807 if (option_bool(OPT_DNSSEC_VALID) && (type & SERV_DO_DNSSEC))
1808 {
1809 size = add_do_bit(header, size, ((unsigned char *) header) + 65536);
1810
1811 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
1812 this allows it to select auth servers when one is returning bad data. */
1813 if (option_bool(OPT_DNSSEC_DEBUG))
1814 header->hb4 |= HB4_CD;
1815 }
1816#endif
1817
1818 /* Check if we added a pheader on forwarding - may need to
1819 strip it from the reply. */
1820 if (!oph && find_pseudoheader(header, size, NULL, NULL, NULL, NULL))
1821 added_pheader = 1;
1822
Simon Kelley367341f2016-01-12 15:58:23 +00001823 type &= ~SERV_DO_DNSSEC;
Simon Kelley367341f2016-01-12 15:58:23 +00001824
Simon Kelley4f7b3042012-11-28 21:27:02 +00001825 if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server)
1826 last_server = daemon->servers;
1827 else
1828 last_server = daemon->last_server;
1829
1830 if (!flags && last_server)
1831 {
1832 struct server *firstsendto = NULL;
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001833#ifdef HAVE_DNSSEC
Simon Kelley703c7ff2014-01-25 23:46:23 +00001834 unsigned char *newhash, hash[HASH_SIZE];
Simon Kelley63758382014-04-16 22:20:55 +01001835 if ((newhash = hash_questions(header, (unsigned int)size, daemon->namebuff)))
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001836 memcpy(hash, newhash, HASH_SIZE);
Tomas Hozzab37f8b92014-03-25 20:52:28 +00001837 else
1838 memset(hash, 0, HASH_SIZE);
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001839#else
Simon Kelley4f7b3042012-11-28 21:27:02 +00001840 unsigned int crc = questions_crc(header, (unsigned int)size, daemon->namebuff);
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001841#endif
Simon Kelley4f7b3042012-11-28 21:27:02 +00001842 /* Loop round available servers until we succeed in connecting to one.
Josh Soref730c6742017-02-06 16:14:04 +00001843 Note that this code subtly ensures that consecutive queries on this connection
Simon Kelley4f7b3042012-11-28 21:27:02 +00001844 which can go to the same server, do so. */
1845 while (1)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001846 {
Simon Kelley4f7b3042012-11-28 21:27:02 +00001847 if (!firstsendto)
1848 firstsendto = last_server;
1849 else
1850 {
1851 if (!(last_server = last_server->next))
1852 last_server = daemon->servers;
1853
1854 if (last_server == firstsendto)
1855 break;
1856 }
1857
1858 /* server for wrong domain */
1859 if (type != (last_server->flags & SERV_TYPE) ||
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01001860 (type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)) ||
1861 (last_server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
Simon Kelley7de060b2011-08-26 17:24:52 +01001862 continue;
Simon Kelley361dfe52017-02-10 21:12:30 +00001863
1864 retry:
Simon Kelley4f7b3042012-11-28 21:27:02 +00001865 if (last_server->tcpfd == -1)
1866 {
1867 if ((last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
1868 continue;
1869
Karl Vogele9828b62014-10-03 21:45:15 +01001870#ifdef HAVE_CONNTRACK
1871 /* Copy connection mark of incoming query to outgoing connection. */
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001872 if (have_mark)
1873 setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
Karl Vogele9828b62014-10-03 21:45:15 +01001874#endif
1875
Simon Kelley9d6918d2017-10-13 17:55:09 +01001876 if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 0, 1) ||
Simon Kelley4f7b3042012-11-28 21:27:02 +00001877 connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1))
1878 {
1879 close(last_server->tcpfd);
1880 last_server->tcpfd = -1;
1881 continue;
1882 }
1883
Simon Kelley361dfe52017-02-10 21:12:30 +00001884 last_server->flags &= ~SERV_GOT_TCP;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001885 }
1886
Simon Kelley4b5ea122013-04-22 10:18:26 +01001887 *length = htons(size);
Simon Kelley1fc02682014-04-29 12:30:18 +01001888
1889 /* get query name again for logging - may have been overwritten */
1890 if (!(gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
1891 strcpy(daemon->namebuff, "query");
Simon Kelley4f7b3042012-11-28 21:27:02 +00001892
Simon Kelley4b5ea122013-04-22 10:18:26 +01001893 if (!read_write(last_server->tcpfd, packet, size + sizeof(u16), 0) ||
Simon Kelley4f7b3042012-11-28 21:27:02 +00001894 !read_write(last_server->tcpfd, &c1, 1, 1) ||
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001895 !read_write(last_server->tcpfd, &c2, 1, 1) ||
1896 !read_write(last_server->tcpfd, payload, (c1 << 8) | c2, 1))
Simon Kelley7de060b2011-08-26 17:24:52 +01001897 {
1898 close(last_server->tcpfd);
1899 last_server->tcpfd = -1;
Simon Kelley361dfe52017-02-10 21:12:30 +00001900 /* We get data then EOF, reopen connection to same server,
1901 else try next. This avoids DoS from a server which accepts
1902 connections and then closes them. */
1903 if (last_server->flags & SERV_GOT_TCP)
1904 goto retry;
1905 else
1906 continue;
1907 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00001908
Simon Kelley361dfe52017-02-10 21:12:30 +00001909 last_server->flags |= SERV_GOT_TCP;
1910
Simon Kelley4f7b3042012-11-28 21:27:02 +00001911 m = (c1 << 8) | c2;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001912
Simon Kelley4f7b3042012-11-28 21:27:02 +00001913 if (last_server->addr.sa.sa_family == AF_INET)
1914 log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
1915 (struct all_addr *)&last_server->addr.in.sin_addr, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001916#ifdef HAVE_IPV6
Simon Kelley4f7b3042012-11-28 21:27:02 +00001917 else
1918 log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
1919 (struct all_addr *)&last_server->addr.in6.sin6_addr, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001920#endif
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001921
1922#ifdef HAVE_DNSSEC
Simon Kelley367341f2016-01-12 15:58:23 +00001923 if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled && (last_server->flags & SERV_DO_DNSSEC))
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001924 {
Simon Kelley7fa836e2014-02-10 20:11:24 +00001925 int keycount = DNSSEC_WORK; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
Simon Kelleyf344dbc2016-01-18 18:04:17 +00001926 int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname,
1927 last_server, have_mark, mark, &keycount);
Simon Kelley554b5802015-04-17 22:50:20 +01001928 char *result, *domain = "result";
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001929
Simon Kelley9a31b682015-12-15 10:20:39 +00001930 if (status == STAT_ABANDONED)
Simon Kelley150162b2015-03-27 09:58:26 +00001931 {
1932 result = "ABANDONED";
1933 status = STAT_BOGUS;
1934 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00001935 else
1936 result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
Simon Kelleye66b4df2015-04-28 20:45:57 +01001937
1938 if (status == STAT_BOGUS && extract_request(header, m, daemon->namebuff, NULL))
1939 domain = daemon->namebuff;
Simon Kelley554b5802015-04-17 22:50:20 +01001940
1941 log_query(F_KEYTAG | F_SECSTAT, domain, NULL, result);
Simon Kelley7fa836e2014-02-10 20:11:24 +00001942
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001943 if (status == STAT_BOGUS)
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001944 {
1945 no_cache_dnssec = 1;
1946 bogusanswer = 1;
1947 }
1948
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001949 if (status == STAT_SECURE)
1950 cache_secure = 1;
1951 }
1952#endif
1953
1954 /* restore CD bit to the value in the query */
1955 if (checking_disabled)
1956 header->hb4 |= HB4_CD;
1957 else
1958 header->hb4 &= ~HB4_CD;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001959
1960 /* There's no point in updating the cache, since this process will exit and
1961 lose the information after a few queries. We make this call for the alias and
1962 bogus-nxdomain side-effects. */
1963 /* If the crc of the question section doesn't match the crc we sent, then
1964 someone might be attempting to insert bogus values into the cache by
1965 sending replies containing questions and bogus answers. */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001966#ifdef HAVE_DNSSEC
1967 newhash = hash_questions(header, (unsigned int)m, daemon->namebuff);
1968 if (!newhash || memcmp(hash, newhash, HASH_SIZE) != 0)
Simon Kelley703c7ff2014-01-25 23:46:23 +00001969 {
1970 m = 0;
1971 break;
1972 }
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001973#else
1974 if (crc != questions_crc(header, (unsigned int)m, daemon->namebuff))
Simon Kelley703c7ff2014-01-25 23:46:23 +00001975 {
1976 m = 0;
1977 break;
1978 }
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001979#endif
1980
1981 m = process_reply(header, now, last_server, (unsigned int)m,
Simon Kelleye66b4df2015-04-28 20:45:57 +01001982 option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001983 ad_reqd, do_bit, added_pheader, check_subnet, &peer_addr);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001984
1985 break;
1986 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001987 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00001988
1989 /* In case of local answer or no connections made. */
1990 if (m == 0)
1991 m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001992 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001993 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00001994
Simon Kelleyb842bc92015-07-12 21:09:11 +01001995 check_log_writer(1);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001996
Simon Kelley4b5ea122013-04-22 10:18:26 +01001997 *length = htons(m);
1998
1999 if (m == 0 || !read_write(confd, packet, m + sizeof(u16), 0))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002000 return packet;
2001 }
2002}
2003
Simon Kelley16972692006-10-16 20:04:18 +01002004static struct frec *allocate_frec(time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002005{
Simon Kelley16972692006-10-16 20:04:18 +01002006 struct frec *f;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002007
Simon Kelley5aabfc72007-08-29 11:24:47 +01002008 if ((f = (struct frec *)whine_malloc(sizeof(struct frec))))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002009 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01002010 f->next = daemon->frec_list;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002011 f->time = now;
Simon Kelley832af0b2007-01-21 20:01:28 +00002012 f->sentto = NULL;
Simon Kelley1a6bca82008-07-11 11:11:42 +01002013 f->rfd4 = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +00002014 f->flags = 0;
Simon Kelley1a6bca82008-07-11 11:11:42 +01002015#ifdef HAVE_IPV6
2016 f->rfd6 = NULL;
2017#endif
Simon Kelley3a237152013-12-12 12:15:50 +00002018#ifdef HAVE_DNSSEC
Simon Kelley97bc7982014-01-31 10:19:52 +00002019 f->dependent = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002020 f->blocking_query = NULL;
Simon Kelley4619d942014-01-16 19:53:06 +00002021 f->stash = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002022#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +01002023 daemon->frec_list = f;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002024 }
Simon Kelley16972692006-10-16 20:04:18 +01002025
2026 return f;
2027}
2028
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002029struct randfd *allocate_rfd(int family)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002030{
2031 static int finger = 0;
2032 int i;
2033
2034 /* limit the number of sockets we have open to avoid starvation of
2035 (eg) TFTP. Once we have a reasonable number, randomness should be OK */
2036
2037 for (i = 0; i < RANDOM_SOCKS; i++)
Simon Kelley9009d742008-11-14 20:04:27 +00002038 if (daemon->randomsocks[i].refcount == 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002039 {
Simon Kelley9009d742008-11-14 20:04:27 +00002040 if ((daemon->randomsocks[i].fd = random_sock(family)) == -1)
2041 break;
2042
Simon Kelley1a6bca82008-07-11 11:11:42 +01002043 daemon->randomsocks[i].refcount = 1;
2044 daemon->randomsocks[i].family = family;
2045 return &daemon->randomsocks[i];
2046 }
2047
Simon Kelley9009d742008-11-14 20:04:27 +00002048 /* No free ones or cannot get new socket, grab an existing one */
Simon Kelley1a6bca82008-07-11 11:11:42 +01002049 for (i = 0; i < RANDOM_SOCKS; i++)
2050 {
2051 int j = (i+finger) % RANDOM_SOCKS;
Simon Kelley9009d742008-11-14 20:04:27 +00002052 if (daemon->randomsocks[j].refcount != 0 &&
2053 daemon->randomsocks[j].family == family &&
2054 daemon->randomsocks[j].refcount != 0xffff)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002055 {
2056 finger = j;
2057 daemon->randomsocks[j].refcount++;
2058 return &daemon->randomsocks[j];
2059 }
2060 }
2061
2062 return NULL; /* doom */
2063}
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002064
2065void free_rfd(struct randfd *rfd)
2066{
2067 if (rfd && --(rfd->refcount) == 0)
2068 close(rfd->fd);
2069}
2070
Simon Kelley1a6bca82008-07-11 11:11:42 +01002071static void free_frec(struct frec *f)
2072{
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002073 free_rfd(f->rfd4);
Simon Kelley1a6bca82008-07-11 11:11:42 +01002074 f->rfd4 = NULL;
2075 f->sentto = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +00002076 f->flags = 0;
Simon Kelley1a6bca82008-07-11 11:11:42 +01002077
2078#ifdef HAVE_IPV6
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002079 free_rfd(f->rfd6);
Simon Kelley1a6bca82008-07-11 11:11:42 +01002080 f->rfd6 = NULL;
2081#endif
Simon Kelley3a237152013-12-12 12:15:50 +00002082
2083#ifdef HAVE_DNSSEC
2084 if (f->stash)
Simon Kelley0fc2f312014-01-08 10:26:58 +00002085 {
2086 blockdata_free(f->stash);
2087 f->stash = NULL;
2088 }
Simon Kelley3a237152013-12-12 12:15:50 +00002089
2090 /* Anything we're waiting on is pointless now, too */
2091 if (f->blocking_query)
2092 free_frec(f->blocking_query);
2093 f->blocking_query = NULL;
Simon Kelley39048ad2014-01-21 17:33:58 +00002094 f->dependent = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002095#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +01002096}
2097
Simon Kelley09f3b2c2017-05-09 01:34:02 +01002098
2099
Simon Kelley16972692006-10-16 20:04:18 +01002100/* if wait==NULL return a free or older than TIMEOUT record.
2101 else return *wait zero if one available, or *wait is delay to
Simon Kelley1a6bca82008-07-11 11:11:42 +01002102 when the oldest in-use record will expire. Impose an absolute
Simon Kelley3a237152013-12-12 12:15:50 +00002103 limit of 4*TIMEOUT before we wipe things (for random sockets).
2104 If force is set, always return a result, even if we have
2105 to allocate above the limit. */
2106struct frec *get_new_frec(time_t now, int *wait, int force)
Simon Kelley16972692006-10-16 20:04:18 +01002107{
Simon Kelley1a6bca82008-07-11 11:11:42 +01002108 struct frec *f, *oldest, *target;
Simon Kelley16972692006-10-16 20:04:18 +01002109 int count;
2110
2111 if (wait)
2112 *wait = 0;
2113
Simon Kelley1a6bca82008-07-11 11:11:42 +01002114 for (f = daemon->frec_list, oldest = NULL, target = NULL, count = 0; f; f = f->next, count++)
Simon Kelley832af0b2007-01-21 20:01:28 +00002115 if (!f->sentto)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002116 target = f;
2117 else
Simon Kelley16972692006-10-16 20:04:18 +01002118 {
Simon Kelley9a31b682015-12-15 10:20:39 +00002119#ifdef HAVE_DNSSEC
2120 /* Don't free DNSSEC sub-queries here, as we may end up with
2121 dangling references to them. They'll go when their "real" query
2122 is freed. */
2123 if (!f->dependent)
2124#endif
2125 {
2126 if (difftime(now, f->time) >= 4*TIMEOUT)
2127 {
2128 free_frec(f);
2129 target = f;
2130 }
2131
2132
2133 if (!oldest || difftime(f->time, oldest->time) <= 0)
2134 oldest = f;
2135 }
Simon Kelley16972692006-10-16 20:04:18 +01002136 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01002137
2138 if (target)
2139 {
2140 target->time = now;
2141 return target;
2142 }
Simon Kelley16972692006-10-16 20:04:18 +01002143
2144 /* can't find empty one, use oldest if there is one
2145 and it's older than timeout */
Simon Kelley09f3b2c2017-05-09 01:34:02 +01002146 if (!force && oldest && ((int)difftime(now, oldest->time)) >= TIMEOUT)
Simon Kelley16972692006-10-16 20:04:18 +01002147 {
2148 /* keep stuff for twice timeout if we can by allocating a new
2149 record instead */
2150 if (difftime(now, oldest->time) < 2*TIMEOUT &&
2151 count <= daemon->ftabsize &&
2152 (f = allocate_frec(now)))
2153 return f;
2154
2155 if (!wait)
2156 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01002157 free_frec(oldest);
Simon Kelley16972692006-10-16 20:04:18 +01002158 oldest->time = now;
2159 }
2160 return oldest;
2161 }
2162
2163 /* none available, calculate time 'till oldest record expires */
Simon Kelley3a237152013-12-12 12:15:50 +00002164 if (!force && count > daemon->ftabsize)
Simon Kelley16972692006-10-16 20:04:18 +01002165 {
Marcelo Salhab Brogliato0da5e892013-05-31 11:49:06 +01002166 static time_t last_log = 0;
2167
Simon Kelley16972692006-10-16 20:04:18 +01002168 if (oldest && wait)
2169 *wait = oldest->time + (time_t)TIMEOUT - now;
Marcelo Salhab Brogliato0da5e892013-05-31 11:49:06 +01002170
2171 if ((int)difftime(now, last_log) > 5)
2172 {
2173 last_log = now;
2174 my_syslog(LOG_WARNING, _("Maximum number of concurrent DNS queries reached (max: %d)"), daemon->ftabsize);
2175 }
2176
Simon Kelley16972692006-10-16 20:04:18 +01002177 return NULL;
2178 }
2179
2180 if (!(f = allocate_frec(now)) && wait)
2181 /* wait one second on malloc failure */
2182 *wait = 1;
2183
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002184 return f; /* OK if malloc fails and this is NULL */
2185}
Simon Kelley09f3b2c2017-05-09 01:34:02 +01002186
Simon Kelley832af0b2007-01-21 20:01:28 +00002187/* crc is all-ones if not known. */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002188static struct frec *lookup_frec(unsigned short id, void *hash)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002189{
2190 struct frec *f;
2191
Simon Kelley1a6bca82008-07-11 11:11:42 +01002192 for(f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00002193 if (f->sentto && f->new_id == id &&
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002194 (!hash || memcmp(hash, f->hash, HASH_SIZE) == 0))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002195 return f;
2196
2197 return NULL;
2198}
2199
2200static struct frec *lookup_frec_by_sender(unsigned short id,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01002201 union mysockaddr *addr,
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002202 void *hash)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002203{
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002204 struct frec *f;
2205
Simon Kelley1a6bca82008-07-11 11:11:42 +01002206 for(f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00002207 if (f->sentto &&
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002208 f->orig_id == id &&
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002209 memcmp(hash, f->hash, HASH_SIZE) == 0 &&
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002210 sockaddr_isequal(&f->source, addr))
2211 return f;
2212
2213 return NULL;
2214}
Simon Kelley47a95162014-07-08 22:22:02 +01002215
2216/* Send query packet again, if we can. */
2217void resend_query()
2218{
2219 if (daemon->srv_save)
2220 {
2221 int fd;
2222
2223 if (daemon->srv_save->sfd)
2224 fd = daemon->srv_save->sfd->fd;
2225 else if (daemon->rfd_save && daemon->rfd_save->refcount != 0)
2226 fd = daemon->rfd_save->fd;
2227 else
2228 return;
2229
Simon Kelleyff841eb2015-03-11 21:36:30 +00002230 while(retry_send(sendto(fd, daemon->packet, daemon->packet_len, 0,
2231 &daemon->srv_save->addr.sa,
2232 sa_len(&daemon->srv_save->addr))));
Simon Kelley47a95162014-07-08 22:22:02 +01002233 }
2234}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002235
Simon Kelley849a8352006-06-09 21:02:31 +01002236/* A server record is going away, remove references to it */
Simon Kelley5aabfc72007-08-29 11:24:47 +01002237void server_gone(struct server *server)
Simon Kelley849a8352006-06-09 21:02:31 +01002238{
2239 struct frec *f;
2240
Simon Kelley1a6bca82008-07-11 11:11:42 +01002241 for (f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00002242 if (f->sentto && f->sentto == server)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002243 free_frec(f);
Simon Kelley849a8352006-06-09 21:02:31 +01002244
2245 if (daemon->last_server == server)
2246 daemon->last_server = NULL;
2247
2248 if (daemon->srv_save == server)
2249 daemon->srv_save = NULL;
2250}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002251
Simon Kelley316e2732010-01-22 20:16:09 +00002252/* return unique random ids. */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002253static unsigned short get_id(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002254{
2255 unsigned short ret = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +00002256
Simon Kelley316e2732010-01-22 20:16:09 +00002257 do
Simon Kelley832af0b2007-01-21 20:01:28 +00002258 ret = rand16();
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002259 while (lookup_frec(ret, NULL));
Simon Kelley832af0b2007-01-21 20:01:28 +00002260
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002261 return ret;
2262}
2263
2264
2265
2266
2267