blob: 2ca3c86f2d295e3d52d4deed3fd8e5612c99e868 [file] [log] [blame]
Simon Kelleyaff33962015-01-31 20:13:40 +00001/* dnsmasq is Copyright (c) 2000-2015 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 Kelley28866e92011-02-14 20:19:14 +0000109static unsigned int search_servers(time_t now, struct all_addr **addrpp,
110 unsigned int qtype, 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 Kelleyfeba5c12004-07-27 20:28:58 +0100123 /* domain matches take priority over NODOTS matches */
Simon Kelley3d8df262005-08-29 12:19:27 +0100124 if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.') && namelen != 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100125 {
Simon Kelley28866e92011-02-14 20:19:14 +0000126 unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100127 *type = SERV_FOR_NODOTS;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100128 if (serv->flags & SERV_NO_ADDR)
Simon Kelley36717ee2004-09-20 19:20:58 +0100129 flags = F_NXDOMAIN;
130 else if (serv->flags & SERV_LITERAL_ADDRESS)
131 {
132 if (sflag & qtype)
133 {
134 flags = sflag;
135 if (serv->addr.sa.sa_family == AF_INET)
136 *addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100137#ifdef HAVE_IPV6
Simon Kelley36717ee2004-09-20 19:20:58 +0100138 else
139 *addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100140#endif
Simon Kelley36717ee2004-09-20 19:20:58 +0100141 }
Simon Kelley824af852008-02-12 20:43:05 +0000142 else if (!flags || (flags & F_NXDOMAIN))
Simon Kelley36717ee2004-09-20 19:20:58 +0100143 flags = F_NOERR;
144 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100145 }
146 else if (serv->flags & SERV_HAS_DOMAIN)
147 {
148 unsigned int domainlen = strlen(serv->domain);
Simon Kelleyb8187c82005-11-26 21:46:27 +0000149 char *matchstart = qdomain + namelen - domainlen;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100150 if (namelen >= domainlen &&
Simon Kelleyb8187c82005-11-26 21:46:27 +0000151 hostname_isequal(matchstart, serv->domain) &&
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100152 (domainlen == 0 || namelen == domainlen || *(matchstart-1) == '.' ))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100153 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100154 if (serv->flags & SERV_NO_REBIND)
155 *norebind = 1;
Simon Kelley28866e92011-02-14 20:19:14 +0000156 else
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100157 {
Simon Kelley28866e92011-02-14 20:19:14 +0000158 unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
159 /* implement priority rules for --address and --server for same domain.
160 --address wins if the address is for the correct AF
161 --server wins otherwise. */
162 if (domainlen != 0 && domainlen == matchlen)
Simon Kelley36717ee2004-09-20 19:20:58 +0100163 {
Simon Kelley28866e92011-02-14 20:19:14 +0000164 if ((serv->flags & SERV_LITERAL_ADDRESS))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100165 {
Simon Kelley28866e92011-02-14 20:19:14 +0000166 if (!(sflag & qtype) && flags == 0)
167 continue;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100168 }
Simon Kelley28866e92011-02-14 20:19:14 +0000169 else
170 {
171 if (flags & (F_IPV4 | F_IPV6))
172 continue;
173 }
Simon Kelley36717ee2004-09-20 19:20:58 +0100174 }
Simon Kelley28866e92011-02-14 20:19:14 +0000175
176 if (domainlen >= matchlen)
177 {
178 *type = serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_REBIND);
179 *domain = serv->domain;
180 matchlen = domainlen;
181 if (serv->flags & SERV_NO_ADDR)
182 flags = F_NXDOMAIN;
183 else if (serv->flags & SERV_LITERAL_ADDRESS)
184 {
185 if (sflag & qtype)
186 {
187 flags = sflag;
188 if (serv->addr.sa.sa_family == AF_INET)
189 *addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
190#ifdef HAVE_IPV6
191 else
192 *addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
193#endif
194 }
195 else if (!flags || (flags & F_NXDOMAIN))
196 flags = F_NOERR;
197 }
198 else
199 flags = 0;
200 }
201 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100202 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100203 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100204
Simon Kelley7de060b2011-08-26 17:24:52 +0100205 if (flags == 0 && !(qtype & F_QUERY) &&
Simon Kelley28866e92011-02-14 20:19:14 +0000206 option_bool(OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
Simon Kelley7de060b2011-08-26 17:24:52 +0100207 /* don't forward A or AAAA queries for simple names, except the empty name */
208 flags = F_NOERR;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100209
Simon Kelley5aabfc72007-08-29 11:24:47 +0100210 if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now))
Simon Kelleyc1bb8502004-08-11 18:40:17 +0100211 flags = F_NOERR;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100212
Simon Kelley824af852008-02-12 20:43:05 +0000213 if (flags)
214 {
215 int logflags = 0;
216
217 if (flags == F_NXDOMAIN || flags == F_NOERR)
218 logflags = F_NEG | qtype;
219
Simon Kelley1a6bca82008-07-11 11:11:42 +0100220 log_query(logflags | flags | F_CONFIG | F_FORWARD, qdomain, *addrpp, NULL);
Simon Kelley824af852008-02-12 20:43:05 +0000221 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100222 else if ((*type) & SERV_USE_RESOLV)
223 {
224 *type = 0; /* use normal servers for this domain */
225 *domain = NULL;
226 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100227 return flags;
228}
Simon Kelley44a2a312004-03-10 20:04:35 +0000229
Simon Kelley824af852008-02-12 20:43:05 +0000230static int forward_query(int udpfd, union mysockaddr *udpaddr,
231 struct all_addr *dst_addr, unsigned int dst_iface,
Simon Kelley83349b82014-02-10 21:02:01 +0000232 struct dns_header *header, size_t plen, time_t now,
Simon Kelley613ad152014-02-25 23:02:28 +0000233 struct frec *forward, int ad_reqd, int do_bit)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000234{
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000235 char *domain = NULL;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100236 int type = 0, norebind = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000237 struct all_addr *addrp = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +0000238 unsigned int flags = 0;
Simon Kelleyde379512004-06-22 20:23:33 +0100239 struct server *start = NULL;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000240#ifdef HAVE_DNSSEC
241 void *hash = hash_questions(header, plen, daemon->namebuff);
242#else
243 unsigned int crc = questions_crc(header, plen, daemon->namebuff);
244 void *hash = &crc;
245#endif
246 unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
247
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000248 (void)do_bit;
249
Simon Kelley3d8df262005-08-29 12:19:27 +0100250 /* may be no servers available. */
251 if (!daemon->servers)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000252 forward = NULL;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000253 else if (forward || (hash && (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash))))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000254 {
Simon Kelleya77cec82015-05-08 16:25:38 +0100255 /* If we didn't get an answer advertising a maximal packet in EDNS,
256 fall back to 1280, which should work everywhere on IPv6.
257 If that generates an answer, it will become the new default
258 for this server */
259 forward->flags |= FREC_TEST_PKTSZ;
260
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000261#ifdef HAVE_DNSSEC
Simon Kelleydac74312014-02-13 16:43:49 +0000262 /* If we've already got an answer to this query, but we're awaiting keys for validation,
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000263 there's no point retrying the query, retry the key query instead...... */
264 if (forward->blocking_query)
265 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000266 int fd, is_sign;
267 unsigned char *pheader;
Simon Kelleya77cec82015-05-08 16:25:38 +0100268
269 forward->flags &= ~FREC_TEST_PKTSZ;
270
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000271 while (forward->blocking_query)
272 forward = forward->blocking_query;
Simon Kelleya77cec82015-05-08 16:25:38 +0100273
274 forward->flags |= FREC_TEST_PKTSZ;
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000275
276 blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
277 plen = forward->stash_len;
278
Simon Kelley5bb88f02015-12-21 16:23:47 +0000279 if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000280 PUTSHORT(SAFE_PKTSZ, pheader);
Simon Kelleya77cec82015-05-08 16:25:38 +0100281
Simon Kelley2b291912014-03-21 11:13:55 +0000282 if (forward->sentto->addr.sa.sa_family == AF_INET)
Simon Kelley25cf5e32015-01-09 15:53:03 +0000283 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 +0000284#ifdef HAVE_IPV6
285 else
Simon Kelley25cf5e32015-01-09 15:53:03 +0000286 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 +0000287#endif
288
289 if (forward->sentto->sfd)
290 fd = forward->sentto->sfd->fd;
291 else
292 {
293#ifdef HAVE_IPV6
294 if (forward->sentto->addr.sa.sa_family == AF_INET6)
295 fd = forward->rfd6->fd;
296 else
297#endif
298 fd = forward->rfd4->fd;
299 }
300
Simon Kelleyff841eb2015-03-11 21:36:30 +0000301 while (retry_send( sendto(fd, (char *)header, plen, 0,
302 &forward->sentto->addr.sa,
303 sa_len(&forward->sentto->addr))));
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000304
305 return 1;
306 }
307#endif
308
Simon Kelleyde379512004-06-22 20:23:33 +0100309 /* retry on existing query, send to all available servers */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000310 domain = forward->sentto->domain;
Simon Kelley824af852008-02-12 20:43:05 +0000311 forward->sentto->failed_queries++;
Simon Kelley28866e92011-02-14 20:19:14 +0000312 if (!option_bool(OPT_ORDER))
Simon Kelleyde379512004-06-22 20:23:33 +0100313 {
Simon Kelley0a852542005-03-23 20:28:59 +0000314 forward->forwardall = 1;
Simon Kelley3be34542004-09-11 19:12:13 +0100315 daemon->last_server = NULL;
Simon Kelleyde379512004-06-22 20:23:33 +0100316 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000317 type = forward->sentto->flags & SERV_TYPE;
Simon Kelleyde379512004-06-22 20:23:33 +0100318 if (!(start = forward->sentto->next))
Simon Kelley3be34542004-09-11 19:12:13 +0100319 start = daemon->servers; /* at end of list, recycle */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000320 header->id = htons(forward->new_id);
321 }
322 else
323 {
324 if (gotname)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100325 flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000326
Simon Kelley3a237152013-12-12 12:15:50 +0000327 if (!flags && !(forward = get_new_frec(now, NULL, 0)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100328 /* table full - server failure. */
329 flags = F_NEG;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000330
331 if (forward)
332 {
Simon Kelley0a852542005-03-23 20:28:59 +0000333 forward->source = *udpaddr;
334 forward->dest = *dst_addr;
335 forward->iface = dst_iface;
Simon Kelley0a852542005-03-23 20:28:59 +0000336 forward->orig_id = ntohs(header->id);
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000337 forward->new_id = get_id();
Simon Kelley832af0b2007-01-21 20:01:28 +0000338 forward->fd = udpfd;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000339 memcpy(forward->hash, hash, HASH_SIZE);
Simon Kelley0a852542005-03-23 20:28:59 +0000340 forward->forwardall = 0;
Simon Kelleyed4c0762013-10-08 20:46:34 +0100341 forward->flags = 0;
Simon Kelley28866e92011-02-14 20:19:14 +0000342 if (norebind)
343 forward->flags |= FREC_NOREBIND;
Simon Kelley572b41e2011-02-18 18:11:18 +0000344 if (header->hb4 & HB4_CD)
Simon Kelley28866e92011-02-14 20:19:14 +0000345 forward->flags |= FREC_CHECKING_DISABLED;
Simon Kelley83349b82014-02-10 21:02:01 +0000346 if (ad_reqd)
347 forward->flags |= FREC_AD_QUESTION;
Simon Kelley7fa836e2014-02-10 20:11:24 +0000348#ifdef HAVE_DNSSEC
349 forward->work_counter = DNSSEC_WORK;
Simon Kelley613ad152014-02-25 23:02:28 +0000350 if (do_bit)
351 forward->flags |= FREC_DO_QUESTION;
Simon Kelley7fa836e2014-02-10 20:11:24 +0000352#endif
Simon Kelley613ad152014-02-25 23:02:28 +0000353
Simon Kelley28866e92011-02-14 20:19:14 +0000354 header->id = htons(forward->new_id);
355
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100356 /* In strict_order mode, always try servers in the order
357 specified in resolv.conf, if a domain is given
358 always try all the available servers,
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000359 otherwise, use the one last known to work. */
360
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100361 if (type == 0)
362 {
Simon Kelley28866e92011-02-14 20:19:14 +0000363 if (option_bool(OPT_ORDER))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100364 start = daemon->servers;
365 else if (!(start = daemon->last_server) ||
366 daemon->forwardcount++ > FORWARD_TEST ||
367 difftime(now, daemon->forwardtime) > FORWARD_TIME)
368 {
369 start = daemon->servers;
370 forward->forwardall = 1;
371 daemon->forwardcount = 0;
372 daemon->forwardtime = now;
373 }
374 }
375 else
Simon Kelleyde379512004-06-22 20:23:33 +0100376 {
Simon Kelley3be34542004-09-11 19:12:13 +0100377 start = daemon->servers;
Simon Kelley28866e92011-02-14 20:19:14 +0000378 if (!option_bool(OPT_ORDER))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100379 forward->forwardall = 1;
Simon Kelleyde379512004-06-22 20:23:33 +0100380 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000381 }
382 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100383
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000384 /* check for send errors here (no route to host)
385 if we fail to send to all nameservers, send back an error
386 packet straight away (helps modem users when offline) */
387
388 if (!flags && forward)
389 {
Simon Kelleyde379512004-06-22 20:23:33 +0100390 struct server *firstsentto = start;
391 int forwarded = 0;
Simon Kelley28866e92011-02-14 20:19:14 +0000392
Simon Kelley25cf5e32015-01-09 15:53:03 +0000393 /* If a query is retried, use the log_id for the retry when logging the answer. */
394 forward->log_id = daemon->log_id;
395
Giacomo Tazzari797a7af2013-04-22 13:16:37 +0100396 if (option_bool(OPT_ADD_MAC))
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000397 {
398 size_t new = add_mac(header, plen, ((char *) header) + daemon->packet_buff_sz, &forward->source);
399 if (new != plen)
400 {
401 plen = new;
402 forward->flags |= FREC_ADDED_PHEADER;
403 }
404 }
405
Simon Kelleyed4c0762013-10-08 20:46:34 +0100406 if (option_bool(OPT_CLIENT_SUBNET))
407 {
Simon Kelley60b68062014-01-08 12:10:28 +0000408 size_t new = add_source_addr(header, plen, ((char *) header) + daemon->packet_buff_sz, &forward->source);
Simon Kelleyed4c0762013-10-08 20:46:34 +0100409 if (new != plen)
410 {
411 plen = new;
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000412 forward->flags |= FREC_HAS_SUBNET | FREC_ADDED_PHEADER;
Simon Kelleyed4c0762013-10-08 20:46:34 +0100413 }
414 }
415
Simon Kelley3a237152013-12-12 12:15:50 +0000416#ifdef HAVE_DNSSEC
417 if (option_bool(OPT_DNSSEC_VALID))
Simon Kelley0fc2f312014-01-08 10:26:58 +0000418 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000419 size_t new = add_do_bit(header, plen, ((char *) header) + daemon->packet_buff_sz);
Simon Kelley613ad152014-02-25 23:02:28 +0000420
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000421 if (new != plen)
422 forward->flags |= FREC_ADDED_PHEADER;
423
424 plen = new;
425
Simon Kelley5b3bf922014-01-25 17:03:07 +0000426 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
427 this allows it to select auth servers when one is returning bad data. */
428 if (option_bool(OPT_DNSSEC_DEBUG))
429 header->hb4 |= HB4_CD;
Simon Kelley613ad152014-02-25 23:02:28 +0000430
Simon Kelley0fc2f312014-01-08 10:26:58 +0000431 }
Simon Kelley3a237152013-12-12 12:15:50 +0000432#endif
Simon Kelleya77cec82015-05-08 16:25:38 +0100433
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000434 while (1)
435 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000436 /* only send to servers dealing with our domain.
437 domain may be NULL, in which case server->domain
438 must be NULL also. */
439
Simon Kelleyde379512004-06-22 20:23:33 +0100440 if (type == (start->flags & SERV_TYPE) &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100441 (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +0100442 !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000443 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100444 int fd;
445
446 /* find server socket to use, may need to get random one. */
447 if (start->sfd)
448 fd = start->sfd->fd;
449 else
450 {
451#ifdef HAVE_IPV6
452 if (start->addr.sa.sa_family == AF_INET6)
453 {
454 if (!forward->rfd6 &&
455 !(forward->rfd6 = allocate_rfd(AF_INET6)))
456 break;
Simon Kelley3927da42008-07-20 15:10:39 +0100457 daemon->rfd_save = forward->rfd6;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100458 fd = forward->rfd6->fd;
459 }
460 else
461#endif
462 {
463 if (!forward->rfd4 &&
464 !(forward->rfd4 = allocate_rfd(AF_INET)))
465 break;
Simon Kelley3927da42008-07-20 15:10:39 +0100466 daemon->rfd_save = forward->rfd4;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100467 fd = forward->rfd4->fd;
468 }
Simon Kelley7de060b2011-08-26 17:24:52 +0100469
470#ifdef HAVE_CONNTRACK
471 /* Copy connection mark of incoming query to outgoing connection. */
472 if (option_bool(OPT_CONNTRACK))
473 {
474 unsigned int mark;
Giacomo Tazzari797a7af2013-04-22 13:16:37 +0100475 if (get_incoming_mark(&forward->source, &forward->dest, 0, &mark))
Simon Kelley7de060b2011-08-26 17:24:52 +0100476 setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
477 }
478#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +0100479 }
480
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000481#ifdef HAVE_DNSSEC
Simon Kelley5bb88f02015-12-21 16:23:47 +0000482 if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER))
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000483 {
484 /* Difficult one here. If our client didn't send EDNS0, we will have set the UDP
485 packet size to 512. But that won't provide space for the RRSIGS in many cases.
486 The RRSIGS will be stripped out before the answer goes back, so the packet should
487 shrink again. So, if we added a do-bit, bump the udp packet size to the value
488 known to be OK for this server. Maybe check returned size after stripping and set
489 the truncated bit? */
490 unsigned char *pheader;
491 int is_sign;
Simon Kelley5bb88f02015-12-21 16:23:47 +0000492 if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000493 PUTSHORT(start->edns_pktsz, pheader);
494 }
495#endif
496
Simon Kelleyff841eb2015-03-11 21:36:30 +0000497 if (retry_send(sendto(fd, (char *)header, plen, 0,
498 &start->addr.sa,
499 sa_len(&start->addr))))
500 continue;
501
502 if (errno == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000503 {
Simon Kelleycdeda282006-03-16 20:16:06 +0000504 /* Keep info in case we want to re-send this packet */
505 daemon->srv_save = start;
506 daemon->packet_len = plen;
507
Simon Kelleyde379512004-06-22 20:23:33 +0100508 if (!gotname)
Simon Kelley3be34542004-09-11 19:12:13 +0100509 strcpy(daemon->namebuff, "query");
Simon Kelleyde379512004-06-22 20:23:33 +0100510 if (start->addr.sa.sa_family == AF_INET)
Simon Kelley3be34542004-09-11 19:12:13 +0100511 log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
Simon Kelley1a6bca82008-07-11 11:11:42 +0100512 (struct all_addr *)&start->addr.in.sin_addr, NULL);
Simon Kelleyde379512004-06-22 20:23:33 +0100513#ifdef HAVE_IPV6
514 else
Simon Kelley3be34542004-09-11 19:12:13 +0100515 log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
Simon Kelley1a6bca82008-07-11 11:11:42 +0100516 (struct all_addr *)&start->addr.in6.sin6_addr, NULL);
Simon Kelleyde379512004-06-22 20:23:33 +0100517#endif
Simon Kelley824af852008-02-12 20:43:05 +0000518 start->queries++;
Simon Kelleyde379512004-06-22 20:23:33 +0100519 forwarded = 1;
520 forward->sentto = start;
Simon Kelley0a852542005-03-23 20:28:59 +0000521 if (!forward->forwardall)
Simon Kelleyde379512004-06-22 20:23:33 +0100522 break;
Simon Kelley0a852542005-03-23 20:28:59 +0000523 forward->forwardall++;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000524 }
525 }
526
Simon Kelleyde379512004-06-22 20:23:33 +0100527 if (!(start = start->next))
Simon Kelley3be34542004-09-11 19:12:13 +0100528 start = daemon->servers;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000529
Simon Kelleyde379512004-06-22 20:23:33 +0100530 if (start == firstsentto)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000531 break;
532 }
533
Simon Kelleyde379512004-06-22 20:23:33 +0100534 if (forwarded)
Simon Kelley824af852008-02-12 20:43:05 +0000535 return 1;
Simon Kelleyde379512004-06-22 20:23:33 +0100536
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000537 /* could not send on, prepare to return */
538 header->id = htons(forward->orig_id);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100539 free_frec(forward); /* cancel */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000540 }
541
542 /* could not send on, return empty answer or address if known for whole domain */
Simon Kelleyb8187c82005-11-26 21:46:27 +0000543 if (udpfd != -1)
544 {
Simon Kelleycdeda282006-03-16 20:16:06 +0000545 plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl);
Simon Kelley54dd3932012-06-20 11:23:38 +0100546 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 +0000547 }
548
Simon Kelley824af852008-02-12 20:43:05 +0000549 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000550}
551
Simon Kelleyed4c0762013-10-08 20:46:34 +0100552static 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 +0100553 int no_cache, int cache_secure, int bogusanswer, int ad_reqd, int do_bit, int added_pheader,
554 int check_subnet, union mysockaddr *query_source)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100555{
Simon Kelley36717ee2004-09-20 19:20:58 +0100556 unsigned char *pheader, *sizep;
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000557 char **sets = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +0000558 int munged = 0, is_sign;
Simon Kelleycdeda282006-03-16 20:16:06 +0000559 size_t plen;
560
Simon Kelley83349b82014-02-10 21:02:01 +0000561 (void)ad_reqd;
Simon Kelley982faf42015-04-03 21:42:30 +0100562 (void)do_bit;
563 (void)bogusanswer;
Simon Kelley83349b82014-02-10 21:02:01 +0000564
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000565#ifdef HAVE_IPSET
Simon Kelley82a14af2014-04-13 20:48:57 +0100566 if (daemon->ipsets && extract_request(header, n, daemon->namebuff, NULL))
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000567 {
Simon Kelley82a14af2014-04-13 20:48:57 +0100568 /* Similar algorithm to search_servers. */
569 struct ipsets *ipset_pos;
570 unsigned int namelen = strlen(daemon->namebuff);
571 unsigned int matchlen = 0;
572 for (ipset_pos = daemon->ipsets; ipset_pos; ipset_pos = ipset_pos->next)
Simon Kelley6c0cb852014-01-17 14:40:46 +0000573 {
Simon Kelley82a14af2014-04-13 20:48:57 +0100574 unsigned int domainlen = strlen(ipset_pos->domain);
575 char *matchstart = daemon->namebuff + namelen - domainlen;
576 if (namelen >= domainlen && hostname_isequal(matchstart, ipset_pos->domain) &&
577 (domainlen == 0 || namelen == domainlen || *(matchstart - 1) == '.' ) &&
578 domainlen >= matchlen)
579 {
580 matchlen = domainlen;
581 sets = ipset_pos->sets;
582 }
Simon Kelley6c0cb852014-01-17 14:40:46 +0000583 }
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000584 }
585#endif
586
Simon Kelley5bb88f02015-12-21 16:23:47 +0000587 if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign, NULL)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100588 {
Simon Kelleyed4c0762013-10-08 20:46:34 +0100589 if (check_subnet && !check_source(header, plen, pheader, query_source))
590 {
591 my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch"));
592 return 0;
593 }
Simon Kelley613ad152014-02-25 23:02:28 +0000594
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000595 if (!is_sign)
Simon Kelley613ad152014-02-25 23:02:28 +0000596 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000597 if (added_pheader)
598 {
599 /* client didn't send EDNS0, we added one, strip it off before returning answer. */
600 n = rrfilter(header, n, 0);
601 pheader = NULL;
602 }
603 else
604 {
605 /* If upstream is advertising a larger UDP packet size
606 than we allow, trim it so that we don't get overlarge
607 requests for the client. We can't do this for signed packets. */
608 unsigned short udpsz;
609 unsigned char *psave = sizep;
610
611 GETSHORT(udpsz, sizep);
612 if (udpsz > daemon->edns_pktsz)
613 PUTSHORT(daemon->edns_pktsz, psave);
614 }
Simon Kelley613ad152014-02-25 23:02:28 +0000615 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100616 }
Simon Kelley83349b82014-02-10 21:02:01 +0000617
Simon Kelley28866e92011-02-14 20:19:14 +0000618 /* RFC 4035 sect 4.6 para 3 */
Giovanni Bajo237724c2012-04-05 02:46:52 +0200619 if (!is_sign && !option_bool(OPT_DNSSEC_PROXY))
Simon Kelley795501b2014-01-08 18:11:55 +0000620 header->hb4 &= ~HB4_AD;
Simon Kelley3a237152013-12-12 12:15:50 +0000621
Simon Kelley572b41e2011-02-18 18:11:18 +0000622 if (OPCODE(header) != QUERY || (RCODE(header) != NOERROR && RCODE(header) != NXDOMAIN))
Simon Kelley8938ae02014-05-01 17:46:25 +0100623 return resize_packet(header, n, pheader, plen);
Simon Kelley36717ee2004-09-20 19:20:58 +0100624
Simon Kelley0a852542005-03-23 20:28:59 +0000625 /* Complain loudly if the upstream server is non-recursive. */
Simon Kelley572b41e2011-02-18 18:11:18 +0000626 if (!(header->hb4 & HB4_RA) && RCODE(header) == NOERROR && ntohs(header->ancount) == 0 &&
Simon Kelley0a852542005-03-23 20:28:59 +0000627 server && !(server->flags & SERV_WARNED_RECURSIVE))
628 {
Simon Kelley3d8df262005-08-29 12:19:27 +0100629 prettyprint_addr(&server->addr, daemon->namebuff);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100630 my_syslog(LOG_WARNING, _("nameserver %s refused to do a recursive query"), daemon->namebuff);
Simon Kelley28866e92011-02-14 20:19:14 +0000631 if (!option_bool(OPT_LOG))
Simon Kelley0a852542005-03-23 20:28:59 +0000632 server->flags |= SERV_WARNED_RECURSIVE;
633 }
Giovanni Bajoe292e932012-04-22 14:32:02 +0200634
Simon Kelley572b41e2011-02-18 18:11:18 +0000635 if (daemon->bogus_addr && RCODE(header) != NXDOMAIN &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100636 check_for_bogus_wildcard(header, n, daemon->namebuff, daemon->bogus_addr, now))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100637 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100638 munged = 1;
Simon Kelley572b41e2011-02-18 18:11:18 +0000639 SET_RCODE(header, NXDOMAIN);
640 header->hb3 &= ~HB3_AA;
Simon Kelley6938f342014-01-26 22:47:39 +0000641 cache_secure = 0;
Simon Kelley36717ee2004-09-20 19:20:58 +0100642 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100643 else
Simon Kelley36717ee2004-09-20 19:20:58 +0100644 {
Simon Kelley6938f342014-01-26 22:47:39 +0000645 int doctored = 0;
646
Simon Kelley572b41e2011-02-18 18:11:18 +0000647 if (RCODE(header) == NXDOMAIN &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100648 extract_request(header, n, daemon->namebuff, NULL) &&
Simon Kelley5aabfc72007-08-29 11:24:47 +0100649 check_for_local_domain(daemon->namebuff, now))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100650 {
Simon Kelley36717ee2004-09-20 19:20:58 +0100651 /* if we forwarded a query for a locally known name (because it was for
652 an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
653 since we know that the domain exists, even if upstream doesn't */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100654 munged = 1;
Simon Kelley572b41e2011-02-18 18:11:18 +0000655 header->hb3 |= HB3_AA;
656 SET_RCODE(header, NOERROR);
Simon Kelley6938f342014-01-26 22:47:39 +0000657 cache_secure = 0;
Simon Kelley36717ee2004-09-20 19:20:58 +0100658 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000659
Simon Kelley6938f342014-01-26 22:47:39 +0000660 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 +0000661 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100662 my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
Simon Kelley824af852008-02-12 20:43:05 +0000663 munged = 1;
Simon Kelley6938f342014-01-26 22:47:39 +0000664 cache_secure = 0;
Simon Kelley824af852008-02-12 20:43:05 +0000665 }
Simon Kelley6938f342014-01-26 22:47:39 +0000666
667 if (doctored)
668 cache_secure = 0;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100669 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100670
Simon Kelleya25720a2014-01-14 23:13:55 +0000671#ifdef HAVE_DNSSEC
Simon Kelleyfe3992f2015-04-03 21:25:05 +0100672 if (bogusanswer && !(header->hb4 & HB4_CD))
Simon Kelleya25720a2014-01-14 23:13:55 +0000673 {
Simon Kelley7d23a662014-01-26 09:33:21 +0000674 if (!option_bool(OPT_DNSSEC_DEBUG))
Simon Kelleya25720a2014-01-14 23:13:55 +0000675 {
676 /* Bogus reply, turn into SERVFAIL */
677 SET_RCODE(header, SERVFAIL);
678 munged = 1;
679 }
680 }
Simon Kelley6938f342014-01-26 22:47:39 +0000681
682 if (option_bool(OPT_DNSSEC_VALID))
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000683 {
684 header->hb4 &= ~HB4_AD;
685
686 if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure)
687 header->hb4 |= HB4_AD;
688
689 /* If the requestor didn't set the DO bit, don't return DNSSEC info. */
690 if (!do_bit)
691 n = rrfilter(header, n, 1);
692 }
Simon Kelleya25720a2014-01-14 23:13:55 +0000693#endif
694
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100695 /* do this after extract_addresses. Ensure NODATA reply and remove
696 nameserver info. */
697
698 if (munged)
699 {
700 header->ancount = htons(0);
701 header->nscount = htons(0);
702 header->arcount = htons(0);
Simon Kelley150162b2015-03-27 09:58:26 +0000703 header->hb3 &= ~HB3_TC;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100704 }
705
Simon Kelley36717ee2004-09-20 19:20:58 +0100706 /* the bogus-nxdomain stuff, doctor and NXDOMAIN->NODATA munging can all elide
707 sections of the packet. Find the new length here and put back pseudoheader
708 if it was removed. */
709 return resize_packet(header, n, pheader, plen);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100710}
711
Simon Kelley3be34542004-09-11 19:12:13 +0100712/* sets new last_server */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100713void reply_query(int fd, int family, time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000714{
715 /* packet from peer server, extract data for cache, and send to
716 original requester */
Simon Kelley572b41e2011-02-18 18:11:18 +0000717 struct dns_header *header;
Simon Kelleyde379512004-06-22 20:23:33 +0100718 union mysockaddr serveraddr;
Simon Kelley832af0b2007-01-21 20:01:28 +0000719 struct frec *forward;
Simon Kelleyde379512004-06-22 20:23:33 +0100720 socklen_t addrlen = sizeof(serveraddr);
Simon Kelley60b68062014-01-08 12:10:28 +0000721 ssize_t n = recvfrom(fd, daemon->packet, daemon->packet_buff_sz, 0, &serveraddr.sa, &addrlen);
Simon Kelleycdeda282006-03-16 20:16:06 +0000722 size_t nn;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100723 struct server *server;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000724 void *hash;
725#ifndef HAVE_DNSSEC
726 unsigned int crc;
727#endif
728
Simon Kelleycdeda282006-03-16 20:16:06 +0000729 /* packet buffer overwritten */
730 daemon->srv_save = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +0000731
Simon Kelleyde379512004-06-22 20:23:33 +0100732 /* Determine the address of the server replying so that we can mark that as good */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100733 serveraddr.sa.sa_family = family;
Simon Kelleyde379512004-06-22 20:23:33 +0100734#ifdef HAVE_IPV6
735 if (serveraddr.sa.sa_family == AF_INET6)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100736 serveraddr.in6.sin6_flowinfo = 0;
Simon Kelleyde379512004-06-22 20:23:33 +0100737#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000738
Simon Kelley490f9072014-03-24 22:04:42 +0000739 header = (struct dns_header *)daemon->packet;
740
741 if (n < (int)sizeof(struct dns_header) || !(header->hb3 & HB3_QR))
742 return;
743
Simon Kelley1a6bca82008-07-11 11:11:42 +0100744 /* spoof check: answer must come from known server, */
745 for (server = daemon->servers; server; server = server->next)
746 if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) &&
747 sockaddr_isequal(&server->addr, &serveraddr))
748 break;
Simon Kelley490f9072014-03-24 22:04:42 +0000749
750 if (!server)
751 return;
752
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000753#ifdef HAVE_DNSSEC
754 hash = hash_questions(header, n, daemon->namebuff);
755#else
756 hash = &crc;
757 crc = questions_crc(header, n, daemon->namebuff);
758#endif
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100759
Simon Kelley490f9072014-03-24 22:04:42 +0000760 if (!(forward = lookup_frec(ntohs(header->id), hash)))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100761 return;
Simon Kelley490f9072014-03-24 22:04:42 +0000762
Simon Kelley25cf5e32015-01-09 15:53:03 +0000763 /* log_query gets called indirectly all over the place, so
764 pass these in global variables - sorry. */
765 daemon->log_display_id = forward->log_id;
766 daemon->log_source_addr = &forward->source;
767
Glen Huang32fc6db2014-12-27 15:28:12 +0000768 if (daemon->ignore_addr && RCODE(header) == NOERROR &&
769 check_for_ignored_address(header, n, daemon->ignore_addr))
770 return;
771
Simon Kelley2ae195f2015-01-18 22:20:48 +0000772 if (RCODE(header) == REFUSED &&
Simon Kelley28866e92011-02-14 20:19:14 +0000773 !option_bool(OPT_ORDER) &&
Simon Kelley1a6bca82008-07-11 11:11:42 +0100774 forward->forwardall == 0)
775 /* for broken servers, attempt to send to another one. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000776 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100777 unsigned char *pheader;
778 size_t plen;
779 int is_sign;
Simon Kelley832af0b2007-01-21 20:01:28 +0000780
Simon Kelley1a6bca82008-07-11 11:11:42 +0100781 /* recreate query from reply */
Simon Kelley5bb88f02015-12-21 16:23:47 +0000782 pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100783 if (!is_sign)
Simon Kelley832af0b2007-01-21 20:01:28 +0000784 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100785 header->ancount = htons(0);
786 header->nscount = htons(0);
787 header->arcount = htons(0);
788 if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
789 {
swiggerbd7bfa22015-06-01 20:54:59 +0100790 header->hb3 &= ~(HB3_QR | HB3_AA | HB3_TC);
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000791 header->hb4 &= ~(HB4_RA | HB4_RCODE | HB4_CD | HB4_AD);
792 if (forward->flags |= FREC_CHECKING_DISABLED)
793 header->hb4 |= HB4_CD;
794 if (forward->flags |= FREC_AD_QUESTION)
795 header->hb4 |= HB4_AD;
796 if (forward->flags & FREC_DO_QUESTION)
797 add_do_bit(header, nn, (char *)pheader + plen);
798 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 +0100799 return;
800 }
801 }
802 }
Simon Kelley3a237152013-12-12 12:15:50 +0000803
804 server = forward->sentto;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100805 if ((forward->sentto->flags & SERV_TYPE) == 0)
806 {
Simon Kelley51967f92014-03-25 21:07:00 +0000807 if (RCODE(header) == REFUSED)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100808 server = NULL;
809 else
810 {
811 struct server *last_server;
Simon Kelley832af0b2007-01-21 20:01:28 +0000812
Simon Kelley1a6bca82008-07-11 11:11:42 +0100813 /* find good server by address if possible, otherwise assume the last one we sent to */
814 for (last_server = daemon->servers; last_server; last_server = last_server->next)
815 if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) &&
816 sockaddr_isequal(&last_server->addr, &serveraddr))
817 {
818 server = last_server;
819 break;
820 }
821 }
Simon Kelley28866e92011-02-14 20:19:14 +0000822 if (!option_bool(OPT_ALL_SERVERS))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100823 daemon->last_server = server;
824 }
Simon Kelleya77cec82015-05-08 16:25:38 +0100825
826 /* We tried resending to this server with a smaller maximum size and got an answer.
Simon Kelley86fa1042015-05-10 13:50:59 +0100827 Make that permanent. To avoid reduxing the packet size for an single dropped packet,
828 only do this when we get a truncated answer, or one larger than the safe size. */
829 if (server && (forward->flags & FREC_TEST_PKTSZ) &&
830 ((header->hb3 & HB3_TC) || n >= SAFE_PKTSZ))
Simon Kelleya77cec82015-05-08 16:25:38 +0100831 server->edns_pktsz = SAFE_PKTSZ;
832
Simon Kelley1a6bca82008-07-11 11:11:42 +0100833 /* If the answer is an error, keep the forward record in place in case
834 we get a good reply from another server. Kill it when we've
835 had replies from all to avoid filling the forwarding table when
836 everything is broken */
Simon Kelley51967f92014-03-25 21:07:00 +0000837 if (forward->forwardall == 0 || --forward->forwardall == 1 || RCODE(header) != SERVFAIL)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100838 {
Simon Kelleyfe3992f2015-04-03 21:25:05 +0100839 int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100840
Simon Kelley3a237152013-12-12 12:15:50 +0000841 if (option_bool(OPT_NO_REBIND))
842 check_rebind = !(forward->flags & FREC_NOREBIND);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100843
Simon Kelley3a237152013-12-12 12:15:50 +0000844 /* Don't cache replies where DNSSEC validation was turned off, either
845 the upstream server told us so, or the original query specified it. */
846 if ((header->hb4 & HB4_CD) || (forward->flags & FREC_CHECKING_DISABLED))
847 no_cache_dnssec = 1;
848
849#ifdef HAVE_DNSSEC
Simon Kelley51967f92014-03-25 21:07:00 +0000850 if (server && option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED))
Simon Kelley3a237152013-12-12 12:15:50 +0000851 {
Simon Kelley9a31b682015-12-15 10:20:39 +0000852 int status = 0;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000853
854 /* We've had a reply already, which we're validating. Ignore this duplicate */
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000855 if (forward->blocking_query)
Simon Kelley0fc2f312014-01-08 10:26:58 +0000856 return;
Simon Kelley9a31b682015-12-15 10:20:39 +0000857
858 /* Truncated answer can't be validated.
Simon Kelley5d3b87a2014-01-20 11:57:23 +0000859 If this is an answer to a DNSSEC-generated query, we still
860 need to get the client to retry over TCP, so return
861 an answer with the TC bit set, even if the actual answer fits.
862 */
Simon Kelley9a31b682015-12-15 10:20:39 +0000863 if (header->hb3 & HB3_TC)
864 status = STAT_TRUNCATED;
865
866 while (1)
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000867 {
Simon Kelley9a31b682015-12-15 10:20:39 +0000868 /* As soon as anything returns BOGUS, we stop and unwind, to do otherwise
869 would invite infinite loops, since the answers to DNSKEY and DS queries
870 will not be cached, so they'll be repeated. */
871 if (status != STAT_BOGUS && status != STAT_TRUNCATED && status != STAT_ABANDONED)
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000872 {
Simon Kelley9a31b682015-12-15 10:20:39 +0000873 if (forward->flags & FREC_DNSKEY_QUERY)
874 status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
875 else if (forward->flags & FREC_DS_QUERY)
876 status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000877 else
Simon Kelley9a31b682015-12-15 10:20:39 +0000878 status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class,
879 option_bool(OPT_DNSSEC_NO_SIGN), NULL, NULL);
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000880 }
Simon Kelley0fc2f312014-01-08 10:26:58 +0000881
Simon Kelley9a31b682015-12-15 10:20:39 +0000882 /* Can't validate, as we're missing key data. Put this
883 answer aside, whilst we get that. */
884 if (status == STAT_NEED_DS || status == STAT_NEED_KEY)
Simon Kelley3a237152013-12-12 12:15:50 +0000885 {
Simon Kelley9a31b682015-12-15 10:20:39 +0000886 struct frec *new, *orig;
Simon Kelley9d633042013-12-13 15:36:55 +0000887
Simon Kelley9a31b682015-12-15 10:20:39 +0000888 /* Free any saved query */
889 if (forward->stash)
890 blockdata_free(forward->stash);
891
892 /* Now save reply pending receipt of key data */
893 if (!(forward->stash = blockdata_alloc((char *)header, n)))
Simon Kelley97e618a2015-01-07 21:55:43 +0000894 return;
Simon Kelley9a31b682015-12-15 10:20:39 +0000895 forward->stash_len = n;
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000896
Simon Kelley9a31b682015-12-15 10:20:39 +0000897 /* Find the original query that started it all.... */
898 for (orig = forward; orig->dependent; orig = orig->dependent);
Simon Kelley7fa836e2014-02-10 20:11:24 +0000899
Simon Kelley9a31b682015-12-15 10:20:39 +0000900 if (--orig->work_counter == 0 || !(new = get_new_frec(now, NULL, 1)))
901 status = STAT_ABANDONED;
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000902 else
Simon Kelley3a237152013-12-12 12:15:50 +0000903 {
Simon Kelley9a31b682015-12-15 10:20:39 +0000904 int fd;
905 struct frec *next = new->next;
906 *new = *forward; /* copy everything, then overwrite */
907 new->next = next;
908 new->blocking_query = NULL;
909 new->sentto = server;
910 new->rfd4 = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +0000911#ifdef HAVE_IPV6
Simon Kelley9a31b682015-12-15 10:20:39 +0000912 new->rfd6 = NULL;
Simon Kelley7fa836e2014-02-10 20:11:24 +0000913#endif
Simon Kelley9a31b682015-12-15 10:20:39 +0000914 new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY);
915
916 new->dependent = forward; /* to find query awaiting new one. */
917 forward->blocking_query = new; /* for garbage cleaning */
918 /* validate routines leave name of required record in daemon->keyname */
919 if (status == STAT_NEED_KEY)
Simon Kelley7fa836e2014-02-10 20:11:24 +0000920 {
Simon Kelley9a31b682015-12-15 10:20:39 +0000921 new->flags |= FREC_DNSKEY_QUERY;
922 nn = dnssec_generate_query(header, ((char *) header) + daemon->packet_buff_sz,
923 daemon->keyname, forward->class, T_DNSKEY, &server->addr, server->edns_pktsz);
Simon Kelleyf1668d22014-01-08 16:53:27 +0000924 }
Simon Kelley9a31b682015-12-15 10:20:39 +0000925 else
926 {
927 new->flags |= FREC_DS_QUERY;
928 nn = dnssec_generate_query(header,((char *) header) + daemon->packet_buff_sz,
929 daemon->keyname, forward->class, T_DS, &server->addr, server->edns_pktsz);
930 }
931 if ((hash = hash_questions(header, nn, daemon->namebuff)))
932 memcpy(new->hash, hash, HASH_SIZE);
933 new->new_id = get_id();
934 header->id = htons(new->new_id);
935 /* Save query for retransmission */
936 new->stash = blockdata_alloc((char *)header, nn);
937 new->stash_len = nn;
938
939 /* Don't resend this. */
940 daemon->srv_save = NULL;
941
942 if (server->sfd)
943 fd = server->sfd->fd;
944 else
945 {
946 fd = -1;
947#ifdef HAVE_IPV6
948 if (server->addr.sa.sa_family == AF_INET6)
949 {
950 if (new->rfd6 || (new->rfd6 = allocate_rfd(AF_INET6)))
951 fd = new->rfd6->fd;
952 }
953 else
954#endif
955 {
956 if (new->rfd4 || (new->rfd4 = allocate_rfd(AF_INET)))
957 fd = new->rfd4->fd;
958 }
959 }
960
961 if (fd != -1)
962 {
963 while (retry_send(sendto(fd, (char *)header, nn, 0,
964 &server->addr.sa,
965 sa_len(&server->addr))));
966 server->queries++;
967 }
968 }
Simon Kelley7fa836e2014-02-10 20:11:24 +0000969 return;
Simon Kelley3a237152013-12-12 12:15:50 +0000970 }
Simon Kelley3a237152013-12-12 12:15:50 +0000971
Simon Kelley9a31b682015-12-15 10:20:39 +0000972 /* Validated original answer, all done. */
973 if (!forward->dependent)
974 break;
975
976 /* validated subsdiary query, (and cached result)
977 pop that and return to the previous query we were working on. */
Simon Kelley0744ca62014-01-25 16:40:15 +0000978 struct frec *prev = forward->dependent;
979 free_frec(forward);
980 forward = prev;
981 forward->blocking_query = NULL; /* already gone */
982 blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
983 n = forward->stash_len;
Simon Kelley3a237152013-12-12 12:15:50 +0000984 }
Simon Kelley9a31b682015-12-15 10:20:39 +0000985
Simon Kelley5d3b87a2014-01-20 11:57:23 +0000986
Simon Kelleyfe3992f2015-04-03 21:25:05 +0100987 no_cache_dnssec = 0;
Simon Kelleyfe3992f2015-04-03 21:25:05 +0100988
Simon Kelley5d3b87a2014-01-20 11:57:23 +0000989 if (status == STAT_TRUNCATED)
Simon Kelley0744ca62014-01-25 16:40:15 +0000990 header->hb3 |= HB3_TC;
Simon Kelley5d3b87a2014-01-20 11:57:23 +0000991 else
Simon Kelley7fa836e2014-02-10 20:11:24 +0000992 {
Simon Kelley554b5802015-04-17 22:50:20 +0100993 char *result, *domain = "result";
Simon Kelley7fa836e2014-02-10 20:11:24 +0000994
Simon Kelley9a31b682015-12-15 10:20:39 +0000995 if (status == STAT_ABANDONED)
Simon Kelley150162b2015-03-27 09:58:26 +0000996 {
997 result = "ABANDONED";
998 status = STAT_BOGUS;
999 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00001000 else
1001 result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
1002
Simon Kelley554b5802015-04-17 22:50:20 +01001003 if (status == STAT_BOGUS && extract_request(header, n, daemon->namebuff, NULL))
1004 domain = daemon->namebuff;
Simon Kelley9a31b682015-12-15 10:20:39 +00001005
Simon Kelley554b5802015-04-17 22:50:20 +01001006 log_query(F_KEYTAG | F_SECSTAT, domain, NULL, result);
Simon Kelley7fa836e2014-02-10 20:11:24 +00001007 }
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001008
Simon Kelley3a237152013-12-12 12:15:50 +00001009 if (status == STAT_SECURE)
1010 cache_secure = 1;
Simon Kelley3a237152013-12-12 12:15:50 +00001011 else if (status == STAT_BOGUS)
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001012 {
1013 no_cache_dnssec = 1;
1014 bogusanswer = 1;
1015 }
Simon Kelley3a237152013-12-12 12:15:50 +00001016 }
Simon Kelley83349b82014-02-10 21:02:01 +00001017#endif
1018
1019 /* restore CD bit to the value in the query */
1020 if (forward->flags & FREC_CHECKING_DISABLED)
1021 header->hb4 |= HB4_CD;
1022 else
1023 header->hb4 &= ~HB4_CD;
Simon Kelley3a237152013-12-12 12:15:50 +00001024
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001025 if ((nn = process_reply(header, now, server, (size_t)n, check_rebind, no_cache_dnssec, cache_secure, bogusanswer,
Simon Kelley613ad152014-02-25 23:02:28 +00001026 forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION,
1027 forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->source)))
Simon Kelley832af0b2007-01-21 20:01:28 +00001028 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001029 header->id = htons(forward->orig_id);
Simon Kelley572b41e2011-02-18 18:11:18 +00001030 header->hb4 |= HB4_RA; /* recursion if available */
Simon Kelley54dd3932012-06-20 11:23:38 +01001031 send_from(forward->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
Simon Kelley50303b12012-04-04 22:13:17 +01001032 &forward->source, &forward->dest, forward->iface);
Simon Kelley832af0b2007-01-21 20:01:28 +00001033 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001034 free_frec(forward); /* cancel */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001035 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001036}
Simon Kelley44a2a312004-03-10 20:04:35 +00001037
Simon Kelley1a6bca82008-07-11 11:11:42 +01001038
Simon Kelley5aabfc72007-08-29 11:24:47 +01001039void receive_query(struct listener *listen, time_t now)
Simon Kelley44a2a312004-03-10 20:04:35 +00001040{
Simon Kelley572b41e2011-02-18 18:11:18 +00001041 struct dns_header *header = (struct dns_header *)daemon->packet;
Simon Kelley44a2a312004-03-10 20:04:35 +00001042 union mysockaddr source_addr;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001043 unsigned char *pheader;
1044 unsigned short type, udp_size = PACKETSZ; /* default if no EDNS0 */
Simon Kelley44a2a312004-03-10 20:04:35 +00001045 struct all_addr dst_addr;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001046 struct in_addr netmask, dst_addr_4;
Simon Kelleycdeda282006-03-16 20:16:06 +00001047 size_t m;
1048 ssize_t n;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001049 int if_index = 0, auth_dns = 0, do_bit = 0, have_pseudoheader = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001050#ifdef HAVE_AUTH
1051 int local_auth = 0;
1052#endif
Simon Kelley44a2a312004-03-10 20:04:35 +00001053 struct iovec iov[1];
1054 struct msghdr msg;
1055 struct cmsghdr *cmptr;
Simon Kelley44a2a312004-03-10 20:04:35 +00001056 union {
1057 struct cmsghdr align; /* this ensures alignment */
1058#ifdef HAVE_IPV6
1059 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
1060#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001061#if defined(HAVE_LINUX_NETWORK)
Simon Kelley44a2a312004-03-10 20:04:35 +00001062 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
Simon Kelley824af852008-02-12 20:43:05 +00001063#elif defined(IP_RECVDSTADDR) && defined(HAVE_SOLARIS_NETWORK)
1064 char control[CMSG_SPACE(sizeof(struct in_addr)) +
1065 CMSG_SPACE(sizeof(unsigned int))];
Simon Kelley44a2a312004-03-10 20:04:35 +00001066#elif defined(IP_RECVDSTADDR)
1067 char control[CMSG_SPACE(sizeof(struct in_addr)) +
1068 CMSG_SPACE(sizeof(struct sockaddr_dl))];
1069#endif
1070 } control_u;
Simon Kelley2329bef2013-12-03 13:41:16 +00001071#ifdef HAVE_IPV6
1072 /* Can always get recvd interface for IPv6 */
1073 int check_dst = !option_bool(OPT_NOWILD) || listen->family == AF_INET6;
1074#else
1075 int check_dst = !option_bool(OPT_NOWILD);
1076#endif
1077
Simon Kelleycdeda282006-03-16 20:16:06 +00001078 /* packet buffer overwritten */
1079 daemon->srv_save = NULL;
1080
Hans Dedecker98906272014-12-09 22:22:53 +00001081 dst_addr_4.s_addr = dst_addr.addr.addr4.s_addr = 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001082 netmask.s_addr = 0;
1083
Simon Kelley7e5664b2013-04-05 16:57:41 +01001084 if (option_bool(OPT_NOWILD) && listen->iface)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001085 {
Simon Kelley4f7b3042012-11-28 21:27:02 +00001086 auth_dns = listen->iface->dns_auth;
1087
1088 if (listen->family == AF_INET)
1089 {
Hans Dedecker98906272014-12-09 22:22:53 +00001090 dst_addr_4 = dst_addr.addr.addr4 = listen->iface->addr.in.sin_addr;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001091 netmask = listen->iface->netmask;
1092 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001093 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00001094
Simon Kelley3be34542004-09-11 19:12:13 +01001095 iov[0].iov_base = daemon->packet;
1096 iov[0].iov_len = daemon->edns_pktsz;
Simon Kelley44a2a312004-03-10 20:04:35 +00001097
1098 msg.msg_control = control_u.control;
1099 msg.msg_controllen = sizeof(control_u);
1100 msg.msg_flags = 0;
1101 msg.msg_name = &source_addr;
1102 msg.msg_namelen = sizeof(source_addr);
1103 msg.msg_iov = iov;
1104 msg.msg_iovlen = 1;
1105
Simon Kelleyde379512004-06-22 20:23:33 +01001106 if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
Simon Kelley3be34542004-09-11 19:12:13 +01001107 return;
Simon Kelley44a2a312004-03-10 20:04:35 +00001108
Simon Kelley572b41e2011-02-18 18:11:18 +00001109 if (n < (int)sizeof(struct dns_header) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001110 (msg.msg_flags & MSG_TRUNC) ||
Simon Kelley572b41e2011-02-18 18:11:18 +00001111 (header->hb3 & HB3_QR))
Simon Kelley3be34542004-09-11 19:12:13 +01001112 return;
Simon Kelley44a2a312004-03-10 20:04:35 +00001113
Simon Kelley26128d22004-11-14 16:43:54 +00001114 source_addr.sa.sa_family = listen->family;
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001115
1116 if (listen->family == AF_INET)
1117 {
1118 /* Source-port == 0 is an error, we can't send back to that.
1119 http://www.ietf.org/mail-archive/web/dnsop/current/msg11441.html */
1120 if (source_addr.in.sin_port == 0)
1121 return;
1122 }
Simon Kelley26128d22004-11-14 16:43:54 +00001123#ifdef HAVE_IPV6
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001124 else
1125 {
1126 /* Source-port == 0 is an error, we can't send back to that. */
1127 if (source_addr.in6.sin6_port == 0)
1128 return;
1129 source_addr.in6.sin6_flowinfo = 0;
1130 }
Simon Kelley26128d22004-11-14 16:43:54 +00001131#endif
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001132
Simon Kelleyc8a80482014-03-05 14:29:54 +00001133 /* We can be configured to only accept queries from at-most-one-hop-away addresses. */
1134 if (option_bool(OPT_LOCAL_SERVICE))
1135 {
1136 struct addrlist *addr;
1137#ifdef HAVE_IPV6
1138 if (listen->family == AF_INET6)
1139 {
1140 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1141 if ((addr->flags & ADDRLIST_IPV6) &&
1142 is_same_net6(&addr->addr.addr.addr6, &source_addr.in6.sin6_addr, addr->prefixlen))
1143 break;
1144 }
1145 else
1146#endif
1147 {
1148 struct in_addr netmask;
1149 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1150 {
Richard Genoud15b1b7e2014-09-17 21:12:00 +01001151 netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
Simon Kelleyc8a80482014-03-05 14:29:54 +00001152 if (!(addr->flags & ADDRLIST_IPV6) &&
1153 is_same_net(addr->addr.addr.addr4, source_addr.in.sin_addr, netmask))
1154 break;
1155 }
1156 }
1157 if (!addr)
1158 {
Simon Kelley0c8584e2014-03-12 20:12:56 +00001159 static int warned = 0;
1160 if (!warned)
1161 {
1162 my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
1163 warned = 1;
1164 }
Simon Kelleyc8a80482014-03-05 14:29:54 +00001165 return;
1166 }
1167 }
1168
Simon Kelley2329bef2013-12-03 13:41:16 +00001169 if (check_dst)
Simon Kelley44a2a312004-03-10 20:04:35 +00001170 {
Simon Kelley8a911cc2004-03-16 18:35:52 +00001171 struct ifreq ifr;
1172
Simon Kelley26128d22004-11-14 16:43:54 +00001173 if (msg.msg_controllen < sizeof(struct cmsghdr))
1174 return;
1175
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001176#if defined(HAVE_LINUX_NETWORK)
Simon Kelley26128d22004-11-14 16:43:54 +00001177 if (listen->family == AF_INET)
1178 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelleyc72daea2012-01-05 21:33:27 +00001179 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
Simon Kelley26128d22004-11-14 16:43:54 +00001180 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001181 union {
1182 unsigned char *c;
1183 struct in_pktinfo *p;
1184 } p;
1185 p.c = CMSG_DATA(cmptr);
1186 dst_addr_4 = dst_addr.addr.addr4 = p.p->ipi_spec_dst;
1187 if_index = p.p->ipi_ifindex;
Simon Kelley26128d22004-11-14 16:43:54 +00001188 }
1189#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
1190 if (listen->family == AF_INET)
1191 {
1192 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001193 {
1194 union {
1195 unsigned char *c;
1196 unsigned int *i;
1197 struct in_addr *a;
1198#ifndef HAVE_SOLARIS_NETWORK
1199 struct sockaddr_dl *s;
Simon Kelley824af852008-02-12 20:43:05 +00001200#endif
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001201 } p;
1202 p.c = CMSG_DATA(cmptr);
1203 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
1204 dst_addr_4 = dst_addr.addr.addr4 = *(p.a);
1205 else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
1206#ifdef HAVE_SOLARIS_NETWORK
1207 if_index = *(p.i);
1208#else
1209 if_index = p.s->sdl_index;
1210#endif
1211 }
Simon Kelley26128d22004-11-14 16:43:54 +00001212 }
1213#endif
1214
1215#ifdef HAVE_IPV6
1216 if (listen->family == AF_INET6)
1217 {
1218 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelleyc72daea2012-01-05 21:33:27 +00001219 if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
Simon Kelley26128d22004-11-14 16:43:54 +00001220 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001221 union {
1222 unsigned char *c;
1223 struct in6_pktinfo *p;
1224 } p;
1225 p.c = CMSG_DATA(cmptr);
1226
1227 dst_addr.addr.addr6 = p.p->ipi6_addr;
1228 if_index = p.p->ipi6_ifindex;
Simon Kelley26128d22004-11-14 16:43:54 +00001229 }
1230 }
1231#endif
1232
1233 /* enforce available interface configuration */
1234
Simon Kelleye25db1f2013-01-29 22:10:26 +00001235 if (!indextoname(listen->fd, if_index, ifr.ifr_name))
Simon Kelley832af0b2007-01-21 20:01:28 +00001236 return;
1237
Simon Kelleye25db1f2013-01-29 22:10:26 +00001238 if (!iface_check(listen->family, &dst_addr, ifr.ifr_name, &auth_dns))
1239 {
1240 if (!option_bool(OPT_CLEVERBIND))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001241 enumerate_interfaces(0);
Simon Kelley3f2873d2013-05-14 11:28:47 +01001242 if (!loopback_exception(listen->fd, listen->family, &dst_addr, ifr.ifr_name) &&
1243 !label_exception(if_index, listen->family, &dst_addr))
Simon Kelleye25db1f2013-01-29 22:10:26 +00001244 return;
1245 }
1246
Simon Kelley552af8b2012-02-29 20:10:31 +00001247 if (listen->family == AF_INET && option_bool(OPT_LOCALISE))
1248 {
1249 struct irec *iface;
1250
1251 /* get the netmask of the interface whch has the address we were sent to.
1252 This is no neccessarily the interface we arrived on. */
1253
1254 for (iface = daemon->interfaces; iface; iface = iface->next)
1255 if (iface->addr.sa.sa_family == AF_INET &&
1256 iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
1257 break;
1258
1259 /* interface may be new */
Simon Kelleye25db1f2013-01-29 22:10:26 +00001260 if (!iface && !option_bool(OPT_CLEVERBIND))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001261 enumerate_interfaces(0);
Simon Kelley552af8b2012-02-29 20:10:31 +00001262
1263 for (iface = daemon->interfaces; iface; iface = iface->next)
1264 if (iface->addr.sa.sa_family == AF_INET &&
1265 iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
1266 break;
1267
1268 /* If we failed, abandon localisation */
1269 if (iface)
1270 netmask = iface->netmask;
1271 else
1272 dst_addr_4.s_addr = 0;
1273 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001274 }
Simon Kelley25cf5e32015-01-09 15:53:03 +00001275
1276 /* log_query gets called indirectly all over the place, so
1277 pass these in global variables - sorry. */
1278 daemon->log_display_id = ++daemon->log_id;
1279 daemon->log_source_addr = &source_addr;
Simon Kelley44a2a312004-03-10 20:04:35 +00001280
Simon Kelleycdeda282006-03-16 20:16:06 +00001281 if (extract_request(header, (size_t)n, daemon->namebuff, &type))
Simon Kelley44a2a312004-03-10 20:04:35 +00001282 {
Simon Kelleyb485ed92013-10-18 22:00:39 +01001283#ifdef HAVE_AUTH
1284 struct auth_zone *zone;
1285#endif
Simon Kelley610e7822014-02-06 14:45:17 +00001286 char *types = querystr(auth_dns ? "auth" : "query", type);
1287
Simon Kelley44a2a312004-03-10 20:04:35 +00001288 if (listen->family == AF_INET)
Simon Kelley3be34542004-09-11 19:12:13 +01001289 log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
Simon Kelley1a6bca82008-07-11 11:11:42 +01001290 (struct all_addr *)&source_addr.in.sin_addr, types);
Simon Kelley44a2a312004-03-10 20:04:35 +00001291#ifdef HAVE_IPV6
1292 else
Simon Kelley3be34542004-09-11 19:12:13 +01001293 log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
Simon Kelley1a6bca82008-07-11 11:11:42 +01001294 (struct all_addr *)&source_addr.in6.sin6_addr, types);
Simon Kelley44a2a312004-03-10 20:04:35 +00001295#endif
Simon Kelley44a2a312004-03-10 20:04:35 +00001296
Simon Kelley4820dce2012-12-18 18:30:30 +00001297#ifdef HAVE_AUTH
Simon Kelleyb485ed92013-10-18 22:00:39 +01001298 /* find queries for zones we're authoritative for, and answer them directly */
Simon Kelley3a3965a2015-08-09 17:45:06 +01001299 if (!auth_dns && !option_bool(OPT_LOCALISE))
Simon Kelley6008bdb2013-10-21 21:47:03 +01001300 for (zone = daemon->auth_zones; zone; zone = zone->next)
1301 if (in_zone(zone, daemon->namebuff, NULL))
1302 {
1303 auth_dns = 1;
1304 local_auth = 1;
1305 break;
1306 }
Simon Kelleyb485ed92013-10-18 22:00:39 +01001307#endif
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01001308
1309#ifdef HAVE_LOOP
1310 /* Check for forwarding loop */
1311 if (detect_loop(daemon->namebuff, type))
1312 return;
1313#endif
Simon Kelleyb485ed92013-10-18 22:00:39 +01001314 }
1315
Simon Kelley5bb88f02015-12-21 16:23:47 +00001316 if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL, NULL))
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001317 {
1318 unsigned short flags;
1319
1320 have_pseudoheader = 1;
1321 GETSHORT(udp_size, pheader);
1322 pheader += 2; /* ext_rcode */
1323 GETSHORT(flags, pheader);
1324
1325 if (flags & 0x8000)
1326 do_bit = 1;/* do bit */
1327
1328 /* If the client provides an EDNS0 UDP size, use that to limit our reply.
1329 (bounded by the maximum configured). If no EDNS0, then it
1330 defaults to 512 */
1331 if (udp_size > daemon->edns_pktsz)
1332 udp_size = daemon->edns_pktsz;
1333 }
1334
Simon Kelleyb485ed92013-10-18 22:00:39 +01001335#ifdef HAVE_AUTH
Simon Kelley4f7b3042012-11-28 21:27:02 +00001336 if (auth_dns)
Simon Kelley824af852008-02-12 20:43:05 +00001337 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001338 m = answer_auth(header, ((char *) header) + udp_size, (size_t)n, now, &source_addr,
1339 local_auth, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001340 if (m >= 1)
Simon Kelleyb485ed92013-10-18 22:00:39 +01001341 {
1342 send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
1343 (char *)header, m, &source_addr, &dst_addr, if_index);
1344 daemon->auth_answer++;
1345 }
Simon Kelley824af852008-02-12 20:43:05 +00001346 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001347 else
Simon Kelley4820dce2012-12-18 18:30:30 +00001348#endif
Simon Kelley4f7b3042012-11-28 21:27:02 +00001349 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001350 int ad_reqd = do_bit;
1351 /* RFC 6840 5.7 */
1352 if (header->hb4 & HB4_AD)
1353 ad_reqd = 1;
1354
1355 m = answer_request(header, ((char *) header) + udp_size, (size_t)n,
1356 dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001357
1358 if (m >= 1)
1359 {
1360 send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
1361 (char *)header, m, &source_addr, &dst_addr, if_index);
1362 daemon->local_answer++;
1363 }
1364 else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
Simon Kelley613ad152014-02-25 23:02:28 +00001365 header, (size_t)n, now, NULL, ad_reqd, do_bit))
Simon Kelley4f7b3042012-11-28 21:27:02 +00001366 daemon->queries_forwarded++;
1367 else
1368 daemon->local_answer++;
1369 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001370}
1371
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001372#ifdef HAVE_DNSSEC
Simon Kelley7fa836e2014-02-10 20:11:24 +00001373static int tcp_key_recurse(time_t now, int status, struct dns_header *header, size_t n,
1374 int class, char *name, char *keyname, struct server *server, int *keycount)
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001375{
1376 /* Recurse up the key heirarchy */
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001377 int new_status;
Simon Kelley9a31b682015-12-15 10:20:39 +00001378 unsigned char *packet = NULL;
1379 size_t m;
1380 unsigned char *payload = NULL;
1381 struct dns_header *new_header = NULL;
1382 u16 *length = NULL;
1383 unsigned char c1, c2;
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001384
Simon Kelley9a31b682015-12-15 10:20:39 +00001385 while (1)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001386 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001387 /* limit the amount of work we do, to avoid cycling forever on loops in the DNS */
1388 if (--(*keycount) == 0)
1389 new_status = STAT_ABANDONED;
1390 else if (status == STAT_NEED_KEY)
1391 new_status = dnssec_validate_by_ds(now, header, n, name, keyname, class);
1392 else if (status == STAT_NEED_DS)
1393 new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
1394 else
1395 new_status = dnssec_validate_reply(now, header, n, name, keyname, &class, option_bool(OPT_DNSSEC_NO_SIGN), NULL, NULL);
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001396
Simon Kelley9a31b682015-12-15 10:20:39 +00001397 if (new_status != STAT_NEED_DS && new_status != STAT_NEED_KEY)
1398 break;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001399
Simon Kelley9a31b682015-12-15 10:20:39 +00001400 /* Can't validate because we need a key/DS whose name now in keyname.
1401 Make query for same, and recurse to validate */
Simon Kelley7fa836e2014-02-10 20:11:24 +00001402 if (!packet)
Simon Kelley9a31b682015-12-15 10:20:39 +00001403 {
1404 packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
1405 payload = &packet[2];
1406 new_header = (struct dns_header *)payload;
1407 length = (u16 *)packet;
1408 }
1409
1410 if (!packet)
1411 {
1412 new_status = STAT_ABANDONED;
1413 break;
1414 }
1415
Simon Kelley7fa836e2014-02-10 20:11:24 +00001416 m = dnssec_generate_query(new_header, ((char *) new_header) + 65536, keyname, class,
Simon Kelleya77cec82015-05-08 16:25:38 +01001417 new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS, &server->addr, server->edns_pktsz);
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001418
Simon Kelley7fa836e2014-02-10 20:11:24 +00001419 *length = htons(m);
1420
1421 if (!read_write(server->tcpfd, packet, m + sizeof(u16), 0) ||
1422 !read_write(server->tcpfd, &c1, 1, 1) ||
1423 !read_write(server->tcpfd, &c2, 1, 1) ||
1424 !read_write(server->tcpfd, payload, (c1 << 8) | c2, 1))
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001425 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001426 new_status = STAT_ABANDONED;
1427 break;
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001428 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001429
1430 m = (c1 << 8) | c2;
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001431
Simon Kelley9a31b682015-12-15 10:20:39 +00001432 new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, keycount);
1433
1434 if (new_status != STAT_OK)
1435 break;
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001436 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001437
1438 if (packet)
1439 free(packet);
1440
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001441 return new_status;
1442}
1443#endif
1444
1445
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001446/* The daemon forks before calling this: it should deal with one connection,
1447 blocking as neccessary, and then return. Note, need to be a bit careful
1448 about resources for debug mode, when the fork is suppressed: that's
1449 done by the caller. */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001450unsigned char *tcp_request(int confd, time_t now,
Simon Kelley4f7b3042012-11-28 21:27:02 +00001451 union mysockaddr *local_addr, struct in_addr netmask, int auth_dns)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001452{
Simon Kelley28866e92011-02-14 20:19:14 +00001453 size_t size = 0;
1454 int norebind = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001455#ifdef HAVE_AUTH
Simon Kelley19b16892013-10-20 10:19:39 +01001456 int local_auth = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001457#endif
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001458 int checking_disabled, do_bit, added_pheader = 0, have_pseudoheader = 0;
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001459 int check_subnet, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
Simon Kelleycdeda282006-03-16 20:16:06 +00001460 size_t m;
Simon Kelleyee86ce62012-12-07 11:54:46 +00001461 unsigned short qtype;
1462 unsigned int gotname;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001463 unsigned char c1, c2;
Simon Kelley4b5ea122013-04-22 10:18:26 +01001464 /* Max TCP packet + slop + size */
1465 unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
1466 unsigned char *payload = &packet[2];
1467 /* largest field in header is 16-bits, so this is still sufficiently aligned */
1468 struct dns_header *header = (struct dns_header *)payload;
1469 u16 *length = (u16 *)packet;
Simon Kelley3be34542004-09-11 19:12:13 +01001470 struct server *last_server;
Simon Kelley7de060b2011-08-26 17:24:52 +01001471 struct in_addr dst_addr_4;
1472 union mysockaddr peer_addr;
1473 socklen_t peer_len = sizeof(union mysockaddr);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001474 int query_count = 0;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001475 unsigned char *pheader;
Simon Kelley25cf5e32015-01-09 15:53:03 +00001476
Simon Kelley7de060b2011-08-26 17:24:52 +01001477 if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
1478 return packet;
Simon Kelleyc8a80482014-03-05 14:29:54 +00001479
1480 /* We can be configured to only accept queries from at-most-one-hop-away addresses. */
1481 if (option_bool(OPT_LOCAL_SERVICE))
1482 {
1483 struct addrlist *addr;
1484#ifdef HAVE_IPV6
1485 if (peer_addr.sa.sa_family == AF_INET6)
1486 {
1487 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1488 if ((addr->flags & ADDRLIST_IPV6) &&
1489 is_same_net6(&addr->addr.addr.addr6, &peer_addr.in6.sin6_addr, addr->prefixlen))
1490 break;
1491 }
1492 else
1493#endif
1494 {
1495 struct in_addr netmask;
1496 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1497 {
Richard Genoud15b1b7e2014-09-17 21:12:00 +01001498 netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
Simon Kelleyc8a80482014-03-05 14:29:54 +00001499 if (!(addr->flags & ADDRLIST_IPV6) &&
1500 is_same_net(addr->addr.addr.addr4, peer_addr.in.sin_addr, netmask))
1501 break;
1502 }
1503 }
1504 if (!addr)
1505 {
1506 my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
1507 return packet;
1508 }
1509 }
Simon Kelley7de060b2011-08-26 17:24:52 +01001510
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001511 while (1)
1512 {
Simon Kelley25cf5e32015-01-09 15:53:03 +00001513 if (query_count == TCP_MAX_QUERIES ||
1514 !packet ||
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001515 !read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
1516 !(size = c1 << 8 | c2) ||
Simon Kelley4b5ea122013-04-22 10:18:26 +01001517 !read_write(confd, payload, size, 1))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001518 return packet;
1519
Simon Kelley572b41e2011-02-18 18:11:18 +00001520 if (size < (int)sizeof(struct dns_header))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001521 continue;
1522
Simon Kelley25cf5e32015-01-09 15:53:03 +00001523 query_count++;
1524
1525 /* log_query gets called indirectly all over the place, so
1526 pass these in global variables - sorry. */
1527 daemon->log_display_id = ++daemon->log_id;
1528 daemon->log_source_addr = &peer_addr;
1529
Simon Kelleyed4c0762013-10-08 20:46:34 +01001530 check_subnet = 0;
1531
Simon Kelley28866e92011-02-14 20:19:14 +00001532 /* save state of "cd" flag in query */
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001533 if ((checking_disabled = header->hb4 & HB4_CD))
1534 no_cache_dnssec = 1;
Simon Kelley28866e92011-02-14 20:19:14 +00001535
Simon Kelley3be34542004-09-11 19:12:13 +01001536 if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001537 {
Simon Kelleyb485ed92013-10-18 22:00:39 +01001538#ifdef HAVE_AUTH
1539 struct auth_zone *zone;
1540#endif
Simon Kelley610e7822014-02-06 14:45:17 +00001541 char *types = querystr(auth_dns ? "auth" : "query", qtype);
Simon Kelley7de060b2011-08-26 17:24:52 +01001542
1543 if (peer_addr.sa.sa_family == AF_INET)
1544 log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
1545 (struct all_addr *)&peer_addr.in.sin_addr, types);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001546#ifdef HAVE_IPV6
Simon Kelley7de060b2011-08-26 17:24:52 +01001547 else
1548 log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
1549 (struct all_addr *)&peer_addr.in6.sin6_addr, types);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001550#endif
Simon Kelleyb485ed92013-10-18 22:00:39 +01001551
1552#ifdef HAVE_AUTH
1553 /* find queries for zones we're authoritative for, and answer them directly */
Simon Kelley3a3965a2015-08-09 17:45:06 +01001554 if (!auth_dns && !option_bool(OPT_LOCALISE))
Simon Kelley6008bdb2013-10-21 21:47:03 +01001555 for (zone = daemon->auth_zones; zone; zone = zone->next)
1556 if (in_zone(zone, daemon->namebuff, NULL))
1557 {
1558 auth_dns = 1;
1559 local_auth = 1;
1560 break;
1561 }
Simon Kelleyb485ed92013-10-18 22:00:39 +01001562#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001563 }
1564
Simon Kelley7de060b2011-08-26 17:24:52 +01001565 if (local_addr->sa.sa_family == AF_INET)
1566 dst_addr_4 = local_addr->in.sin_addr;
1567 else
1568 dst_addr_4.s_addr = 0;
1569
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001570 do_bit = 0;
1571
Simon Kelley5bb88f02015-12-21 16:23:47 +00001572 if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL, NULL))
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001573 {
1574 unsigned short flags;
1575
1576 have_pseudoheader = 1;
1577 pheader += 4; /* udp_size, ext_rcode */
1578 GETSHORT(flags, pheader);
1579
1580 if (flags & 0x8000)
Simon Kelley5bb88f02015-12-21 16:23:47 +00001581 do_bit = 1; /* do bit */
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001582 }
1583
Simon Kelley4820dce2012-12-18 18:30:30 +00001584#ifdef HAVE_AUTH
Simon Kelley4f7b3042012-11-28 21:27:02 +00001585 if (auth_dns)
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001586 m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr,
1587 local_auth, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001588 else
Simon Kelley4820dce2012-12-18 18:30:30 +00001589#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001590 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001591 int ad_reqd = do_bit;
1592 /* RFC 6840 5.7 */
1593 if (header->hb4 & HB4_AD)
1594 ad_reqd = 1;
1595
1596 /* m > 0 if answered from cache */
1597 m = answer_request(header, ((char *) header) + 65536, (size_t)size,
1598 dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001599
Simon Kelley4f7b3042012-11-28 21:27:02 +00001600 /* Do this by steam now we're not in the select() loop */
Simon Kelleyb842bc92015-07-12 21:09:11 +01001601 check_log_writer(1);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001602
1603 if (m == 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001604 {
Simon Kelley4f7b3042012-11-28 21:27:02 +00001605 unsigned int flags = 0;
1606 struct all_addr *addrp = NULL;
1607 int type = 0;
1608 char *domain = NULL;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001609
Simon Kelley4f7b3042012-11-28 21:27:02 +00001610 if (option_bool(OPT_ADD_MAC))
1611 size = add_mac(header, size, ((char *) header) + 65536, &peer_addr);
Simon Kelleyed4c0762013-10-08 20:46:34 +01001612
1613 if (option_bool(OPT_CLIENT_SUBNET))
1614 {
1615 size_t new = add_source_addr(header, size, ((char *) header) + 65536, &peer_addr);
1616 if (size != new)
1617 {
1618 size = new;
1619 check_subnet = 1;
1620 }
1621 }
1622
Simon Kelley4f7b3042012-11-28 21:27:02 +00001623 if (gotname)
1624 flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
1625
1626 if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server)
1627 last_server = daemon->servers;
1628 else
1629 last_server = daemon->last_server;
1630
1631 if (!flags && last_server)
1632 {
1633 struct server *firstsendto = NULL;
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001634#ifdef HAVE_DNSSEC
Simon Kelley703c7ff2014-01-25 23:46:23 +00001635 unsigned char *newhash, hash[HASH_SIZE];
Simon Kelley63758382014-04-16 22:20:55 +01001636 if ((newhash = hash_questions(header, (unsigned int)size, daemon->namebuff)))
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001637 memcpy(hash, newhash, HASH_SIZE);
Tomas Hozzab37f8b92014-03-25 20:52:28 +00001638 else
1639 memset(hash, 0, HASH_SIZE);
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001640#else
Simon Kelley4f7b3042012-11-28 21:27:02 +00001641 unsigned int crc = questions_crc(header, (unsigned int)size, daemon->namebuff);
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001642#endif
Simon Kelley4f7b3042012-11-28 21:27:02 +00001643 /* Loop round available servers until we succeed in connecting to one.
1644 Note that this code subtley ensures that consecutive queries on this connection
1645 which can go to the same server, do so. */
1646 while (1)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001647 {
Simon Kelley4f7b3042012-11-28 21:27:02 +00001648 if (!firstsendto)
1649 firstsendto = last_server;
1650 else
1651 {
1652 if (!(last_server = last_server->next))
1653 last_server = daemon->servers;
1654
1655 if (last_server == firstsendto)
1656 break;
1657 }
1658
1659 /* server for wrong domain */
1660 if (type != (last_server->flags & SERV_TYPE) ||
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01001661 (type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)) ||
1662 (last_server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
Simon Kelley7de060b2011-08-26 17:24:52 +01001663 continue;
1664
Simon Kelley4f7b3042012-11-28 21:27:02 +00001665 if (last_server->tcpfd == -1)
1666 {
1667 if ((last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
1668 continue;
1669
Karl Vogele9828b62014-10-03 21:45:15 +01001670#ifdef HAVE_CONNTRACK
1671 /* Copy connection mark of incoming query to outgoing connection. */
1672 if (option_bool(OPT_CONNTRACK))
1673 {
1674 unsigned int mark;
1675 struct all_addr local;
1676#ifdef HAVE_IPV6
1677 if (local_addr->sa.sa_family == AF_INET6)
1678 local.addr.addr6 = local_addr->in6.sin6_addr;
1679 else
1680#endif
1681 local.addr.addr4 = local_addr->in.sin_addr;
1682
1683 if (get_incoming_mark(&peer_addr, &local, 1, &mark))
1684 setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
1685 }
1686#endif
1687
Simon Kelley4f7b3042012-11-28 21:27:02 +00001688 if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 1) ||
1689 connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1))
1690 {
1691 close(last_server->tcpfd);
1692 last_server->tcpfd = -1;
1693 continue;
1694 }
1695
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001696#ifdef HAVE_DNSSEC
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001697 added_pheader = 0;
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001698 if (option_bool(OPT_DNSSEC_VALID))
1699 {
Simon Kelley613ad152014-02-25 23:02:28 +00001700 size_t new_size = add_do_bit(header, size, ((char *) header) + 65536);
1701
Simon Kelley2ecd9bd2014-02-13 16:42:02 +00001702 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
1703 this allows it to select auth servers when one is returning bad data. */
1704 if (option_bool(OPT_DNSSEC_DEBUG))
1705 header->hb4 |= HB4_CD;
Simon Kelley613ad152014-02-25 23:02:28 +00001706
1707 if (size != new_size)
1708 added_pheader = 1;
1709
1710 size = new_size;
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001711 }
1712#endif
Simon Kelley4f7b3042012-11-28 21:27:02 +00001713 }
1714
Simon Kelley4b5ea122013-04-22 10:18:26 +01001715 *length = htons(size);
Simon Kelley1fc02682014-04-29 12:30:18 +01001716
1717 /* get query name again for logging - may have been overwritten */
1718 if (!(gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
1719 strcpy(daemon->namebuff, "query");
Simon Kelley4f7b3042012-11-28 21:27:02 +00001720
Simon Kelley4b5ea122013-04-22 10:18:26 +01001721 if (!read_write(last_server->tcpfd, packet, size + sizeof(u16), 0) ||
Simon Kelley4f7b3042012-11-28 21:27:02 +00001722 !read_write(last_server->tcpfd, &c1, 1, 1) ||
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001723 !read_write(last_server->tcpfd, &c2, 1, 1) ||
1724 !read_write(last_server->tcpfd, payload, (c1 << 8) | c2, 1))
Simon Kelley7de060b2011-08-26 17:24:52 +01001725 {
1726 close(last_server->tcpfd);
1727 last_server->tcpfd = -1;
1728 continue;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001729 }
1730
1731 m = (c1 << 8) | c2;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001732
Simon Kelley4f7b3042012-11-28 21:27:02 +00001733 if (last_server->addr.sa.sa_family == AF_INET)
1734 log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
1735 (struct all_addr *)&last_server->addr.in.sin_addr, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001736#ifdef HAVE_IPV6
Simon Kelley4f7b3042012-11-28 21:27:02 +00001737 else
1738 log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
1739 (struct all_addr *)&last_server->addr.in6.sin6_addr, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001740#endif
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001741
1742#ifdef HAVE_DNSSEC
1743 if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled)
1744 {
Simon Kelley7fa836e2014-02-10 20:11:24 +00001745 int keycount = DNSSEC_WORK; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
Simon Kelley9a31b682015-12-15 10:20:39 +00001746 int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname, last_server, &keycount);
Simon Kelley554b5802015-04-17 22:50:20 +01001747 char *result, *domain = "result";
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001748
Simon Kelley9a31b682015-12-15 10:20:39 +00001749 if (status == STAT_ABANDONED)
Simon Kelley150162b2015-03-27 09:58:26 +00001750 {
1751 result = "ABANDONED";
1752 status = STAT_BOGUS;
1753 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00001754 else
1755 result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
Simon Kelleye66b4df2015-04-28 20:45:57 +01001756
1757 if (status == STAT_BOGUS && extract_request(header, m, daemon->namebuff, NULL))
1758 domain = daemon->namebuff;
Simon Kelley554b5802015-04-17 22:50:20 +01001759
1760 log_query(F_KEYTAG | F_SECSTAT, domain, NULL, result);
Simon Kelley7fa836e2014-02-10 20:11:24 +00001761
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001762 if (status == STAT_BOGUS)
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001763 {
1764 no_cache_dnssec = 1;
1765 bogusanswer = 1;
1766 }
1767
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001768 if (status == STAT_SECURE)
1769 cache_secure = 1;
1770 }
1771#endif
1772
1773 /* restore CD bit to the value in the query */
1774 if (checking_disabled)
1775 header->hb4 |= HB4_CD;
1776 else
1777 header->hb4 &= ~HB4_CD;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001778
1779 /* There's no point in updating the cache, since this process will exit and
1780 lose the information after a few queries. We make this call for the alias and
1781 bogus-nxdomain side-effects. */
1782 /* If the crc of the question section doesn't match the crc we sent, then
1783 someone might be attempting to insert bogus values into the cache by
1784 sending replies containing questions and bogus answers. */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001785#ifdef HAVE_DNSSEC
1786 newhash = hash_questions(header, (unsigned int)m, daemon->namebuff);
1787 if (!newhash || memcmp(hash, newhash, HASH_SIZE) != 0)
Simon Kelley703c7ff2014-01-25 23:46:23 +00001788 {
1789 m = 0;
1790 break;
1791 }
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001792#else
1793 if (crc != questions_crc(header, (unsigned int)m, daemon->namebuff))
Simon Kelley703c7ff2014-01-25 23:46:23 +00001794 {
1795 m = 0;
1796 break;
1797 }
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001798#endif
1799
1800 m = process_reply(header, now, last_server, (unsigned int)m,
Simon Kelleye66b4df2015-04-28 20:45:57 +01001801 option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001802 ad_reqd, do_bit, added_pheader, check_subnet, &peer_addr);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001803
1804 break;
1805 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001806 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00001807
1808 /* In case of local answer or no connections made. */
1809 if (m == 0)
1810 m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001811 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001812 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00001813
Simon Kelleyb842bc92015-07-12 21:09:11 +01001814 check_log_writer(1);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001815
Simon Kelley4b5ea122013-04-22 10:18:26 +01001816 *length = htons(m);
1817
1818 if (m == 0 || !read_write(confd, packet, m + sizeof(u16), 0))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001819 return packet;
1820 }
1821}
1822
Simon Kelley16972692006-10-16 20:04:18 +01001823static struct frec *allocate_frec(time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001824{
Simon Kelley16972692006-10-16 20:04:18 +01001825 struct frec *f;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001826
Simon Kelley5aabfc72007-08-29 11:24:47 +01001827 if ((f = (struct frec *)whine_malloc(sizeof(struct frec))))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001828 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001829 f->next = daemon->frec_list;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001830 f->time = now;
Simon Kelley832af0b2007-01-21 20:01:28 +00001831 f->sentto = NULL;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001832 f->rfd4 = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +00001833 f->flags = 0;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001834#ifdef HAVE_IPV6
1835 f->rfd6 = NULL;
1836#endif
Simon Kelley3a237152013-12-12 12:15:50 +00001837#ifdef HAVE_DNSSEC
Simon Kelley97bc7982014-01-31 10:19:52 +00001838 f->dependent = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00001839 f->blocking_query = NULL;
Simon Kelley4619d942014-01-16 19:53:06 +00001840 f->stash = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00001841#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +01001842 daemon->frec_list = f;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001843 }
Simon Kelley16972692006-10-16 20:04:18 +01001844
1845 return f;
1846}
1847
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01001848struct randfd *allocate_rfd(int family)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001849{
1850 static int finger = 0;
1851 int i;
1852
1853 /* limit the number of sockets we have open to avoid starvation of
1854 (eg) TFTP. Once we have a reasonable number, randomness should be OK */
1855
1856 for (i = 0; i < RANDOM_SOCKS; i++)
Simon Kelley9009d742008-11-14 20:04:27 +00001857 if (daemon->randomsocks[i].refcount == 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001858 {
Simon Kelley9009d742008-11-14 20:04:27 +00001859 if ((daemon->randomsocks[i].fd = random_sock(family)) == -1)
1860 break;
1861
Simon Kelley1a6bca82008-07-11 11:11:42 +01001862 daemon->randomsocks[i].refcount = 1;
1863 daemon->randomsocks[i].family = family;
1864 return &daemon->randomsocks[i];
1865 }
1866
Simon Kelley9009d742008-11-14 20:04:27 +00001867 /* No free ones or cannot get new socket, grab an existing one */
Simon Kelley1a6bca82008-07-11 11:11:42 +01001868 for (i = 0; i < RANDOM_SOCKS; i++)
1869 {
1870 int j = (i+finger) % RANDOM_SOCKS;
Simon Kelley9009d742008-11-14 20:04:27 +00001871 if (daemon->randomsocks[j].refcount != 0 &&
1872 daemon->randomsocks[j].family == family &&
1873 daemon->randomsocks[j].refcount != 0xffff)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001874 {
1875 finger = j;
1876 daemon->randomsocks[j].refcount++;
1877 return &daemon->randomsocks[j];
1878 }
1879 }
1880
1881 return NULL; /* doom */
1882}
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01001883
1884void free_rfd(struct randfd *rfd)
1885{
1886 if (rfd && --(rfd->refcount) == 0)
1887 close(rfd->fd);
1888}
1889
Simon Kelley1a6bca82008-07-11 11:11:42 +01001890static void free_frec(struct frec *f)
1891{
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01001892 free_rfd(f->rfd4);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001893 f->rfd4 = NULL;
1894 f->sentto = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +00001895 f->flags = 0;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001896
1897#ifdef HAVE_IPV6
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01001898 free_rfd(f->rfd6);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001899 f->rfd6 = NULL;
1900#endif
Simon Kelley3a237152013-12-12 12:15:50 +00001901
1902#ifdef HAVE_DNSSEC
1903 if (f->stash)
Simon Kelley0fc2f312014-01-08 10:26:58 +00001904 {
1905 blockdata_free(f->stash);
1906 f->stash = NULL;
1907 }
Simon Kelley3a237152013-12-12 12:15:50 +00001908
1909 /* Anything we're waiting on is pointless now, too */
1910 if (f->blocking_query)
1911 free_frec(f->blocking_query);
1912 f->blocking_query = NULL;
Simon Kelley39048ad2014-01-21 17:33:58 +00001913 f->dependent = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00001914#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +01001915}
1916
Simon Kelley16972692006-10-16 20:04:18 +01001917/* if wait==NULL return a free or older than TIMEOUT record.
1918 else return *wait zero if one available, or *wait is delay to
Simon Kelley1a6bca82008-07-11 11:11:42 +01001919 when the oldest in-use record will expire. Impose an absolute
Simon Kelley3a237152013-12-12 12:15:50 +00001920 limit of 4*TIMEOUT before we wipe things (for random sockets).
1921 If force is set, always return a result, even if we have
1922 to allocate above the limit. */
1923struct frec *get_new_frec(time_t now, int *wait, int force)
Simon Kelley16972692006-10-16 20:04:18 +01001924{
Simon Kelley1a6bca82008-07-11 11:11:42 +01001925 struct frec *f, *oldest, *target;
Simon Kelley16972692006-10-16 20:04:18 +01001926 int count;
1927
1928 if (wait)
1929 *wait = 0;
1930
Simon Kelley1a6bca82008-07-11 11:11:42 +01001931 for (f = daemon->frec_list, oldest = NULL, target = NULL, count = 0; f; f = f->next, count++)
Simon Kelley832af0b2007-01-21 20:01:28 +00001932 if (!f->sentto)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001933 target = f;
1934 else
Simon Kelley16972692006-10-16 20:04:18 +01001935 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001936#ifdef HAVE_DNSSEC
1937 /* Don't free DNSSEC sub-queries here, as we may end up with
1938 dangling references to them. They'll go when their "real" query
1939 is freed. */
1940 if (!f->dependent)
1941#endif
1942 {
1943 if (difftime(now, f->time) >= 4*TIMEOUT)
1944 {
1945 free_frec(f);
1946 target = f;
1947 }
1948
1949
1950 if (!oldest || difftime(f->time, oldest->time) <= 0)
1951 oldest = f;
1952 }
Simon Kelley16972692006-10-16 20:04:18 +01001953 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001954
1955 if (target)
1956 {
1957 target->time = now;
1958 return target;
1959 }
Simon Kelley16972692006-10-16 20:04:18 +01001960
1961 /* can't find empty one, use oldest if there is one
1962 and it's older than timeout */
1963 if (oldest && ((int)difftime(now, oldest->time)) >= TIMEOUT)
1964 {
1965 /* keep stuff for twice timeout if we can by allocating a new
1966 record instead */
1967 if (difftime(now, oldest->time) < 2*TIMEOUT &&
1968 count <= daemon->ftabsize &&
1969 (f = allocate_frec(now)))
1970 return f;
1971
1972 if (!wait)
1973 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001974 free_frec(oldest);
Simon Kelley16972692006-10-16 20:04:18 +01001975 oldest->time = now;
1976 }
1977 return oldest;
1978 }
1979
1980 /* none available, calculate time 'till oldest record expires */
Simon Kelley3a237152013-12-12 12:15:50 +00001981 if (!force && count > daemon->ftabsize)
Simon Kelley16972692006-10-16 20:04:18 +01001982 {
Marcelo Salhab Brogliato0da5e892013-05-31 11:49:06 +01001983 static time_t last_log = 0;
1984
Simon Kelley16972692006-10-16 20:04:18 +01001985 if (oldest && wait)
1986 *wait = oldest->time + (time_t)TIMEOUT - now;
Marcelo Salhab Brogliato0da5e892013-05-31 11:49:06 +01001987
1988 if ((int)difftime(now, last_log) > 5)
1989 {
1990 last_log = now;
1991 my_syslog(LOG_WARNING, _("Maximum number of concurrent DNS queries reached (max: %d)"), daemon->ftabsize);
1992 }
1993
Simon Kelley16972692006-10-16 20:04:18 +01001994 return NULL;
1995 }
1996
1997 if (!(f = allocate_frec(now)) && wait)
1998 /* wait one second on malloc failure */
1999 *wait = 1;
2000
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002001 return f; /* OK if malloc fails and this is NULL */
2002}
2003
Simon Kelley832af0b2007-01-21 20:01:28 +00002004/* crc is all-ones if not known. */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002005static struct frec *lookup_frec(unsigned short id, void *hash)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002006{
2007 struct frec *f;
2008
Simon Kelley1a6bca82008-07-11 11:11:42 +01002009 for(f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00002010 if (f->sentto && f->new_id == id &&
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002011 (!hash || memcmp(hash, f->hash, HASH_SIZE) == 0))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002012 return f;
2013
2014 return NULL;
2015}
2016
2017static struct frec *lookup_frec_by_sender(unsigned short id,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01002018 union mysockaddr *addr,
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002019 void *hash)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002020{
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002021 struct frec *f;
2022
Simon Kelley1a6bca82008-07-11 11:11:42 +01002023 for(f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00002024 if (f->sentto &&
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002025 f->orig_id == id &&
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002026 memcmp(hash, f->hash, HASH_SIZE) == 0 &&
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002027 sockaddr_isequal(&f->source, addr))
2028 return f;
2029
2030 return NULL;
2031}
Simon Kelley47a95162014-07-08 22:22:02 +01002032
2033/* Send query packet again, if we can. */
2034void resend_query()
2035{
2036 if (daemon->srv_save)
2037 {
2038 int fd;
2039
2040 if (daemon->srv_save->sfd)
2041 fd = daemon->srv_save->sfd->fd;
2042 else if (daemon->rfd_save && daemon->rfd_save->refcount != 0)
2043 fd = daemon->rfd_save->fd;
2044 else
2045 return;
2046
Simon Kelleyff841eb2015-03-11 21:36:30 +00002047 while(retry_send(sendto(fd, daemon->packet, daemon->packet_len, 0,
2048 &daemon->srv_save->addr.sa,
2049 sa_len(&daemon->srv_save->addr))));
Simon Kelley47a95162014-07-08 22:22:02 +01002050 }
2051}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002052
Simon Kelley849a8352006-06-09 21:02:31 +01002053/* A server record is going away, remove references to it */
Simon Kelley5aabfc72007-08-29 11:24:47 +01002054void server_gone(struct server *server)
Simon Kelley849a8352006-06-09 21:02:31 +01002055{
2056 struct frec *f;
2057
Simon Kelley1a6bca82008-07-11 11:11:42 +01002058 for (f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00002059 if (f->sentto && f->sentto == server)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002060 free_frec(f);
Simon Kelley849a8352006-06-09 21:02:31 +01002061
2062 if (daemon->last_server == server)
2063 daemon->last_server = NULL;
2064
2065 if (daemon->srv_save == server)
2066 daemon->srv_save = NULL;
2067}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002068
Simon Kelley316e2732010-01-22 20:16:09 +00002069/* return unique random ids. */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002070static unsigned short get_id(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002071{
2072 unsigned short ret = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +00002073
Simon Kelley316e2732010-01-22 20:16:09 +00002074 do
Simon Kelley832af0b2007-01-21 20:01:28 +00002075 ret = rand16();
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002076 while (lookup_frec(ret, NULL));
Simon Kelley832af0b2007-01-21 20:01:28 +00002077
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002078 return ret;
2079}
2080
2081
2082
2083
2084