blob: c0e4d9aa31813703838115aaff03e396dc44c3da [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 Kelleyd3a8b392015-12-23 12:27:37 +0000392 size_t edns0_len;
393
Simon Kelley25cf5e32015-01-09 15:53:03 +0000394 /* If a query is retried, use the log_id for the retry when logging the answer. */
395 forward->log_id = daemon->log_id;
396
Giacomo Tazzari797a7af2013-04-22 13:16:37 +0100397 if (option_bool(OPT_ADD_MAC))
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000398 {
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000399 size_t new = add_mac(header, plen, ((char *) header) + PACKETSZ, &forward->source);
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000400 if (new != plen)
401 {
402 plen = new;
403 forward->flags |= FREC_ADDED_PHEADER;
404 }
405 }
406
Simon Kelleyed4c0762013-10-08 20:46:34 +0100407 if (option_bool(OPT_CLIENT_SUBNET))
408 {
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000409 size_t new = add_source_addr(header, plen, ((char *) header) + PACKETSZ, &forward->source);
Simon Kelleyed4c0762013-10-08 20:46:34 +0100410 if (new != plen)
411 {
412 plen = new;
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000413 forward->flags |= FREC_HAS_SUBNET | FREC_ADDED_PHEADER;
Simon Kelleyed4c0762013-10-08 20:46:34 +0100414 }
415 }
416
Simon Kelley3a237152013-12-12 12:15:50 +0000417#ifdef HAVE_DNSSEC
418 if (option_bool(OPT_DNSSEC_VALID))
Simon Kelley0fc2f312014-01-08 10:26:58 +0000419 {
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000420 size_t new = add_do_bit(header, plen, ((char *) header) + PACKETSZ);
Simon Kelley613ad152014-02-25 23:02:28 +0000421
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000422 if (new != plen)
423 forward->flags |= FREC_ADDED_PHEADER;
424
425 plen = new;
426
Simon Kelley5b3bf922014-01-25 17:03:07 +0000427 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
428 this allows it to select auth servers when one is returning bad data. */
429 if (option_bool(OPT_DNSSEC_DEBUG))
430 header->hb4 |= HB4_CD;
Simon Kelley613ad152014-02-25 23:02:28 +0000431
Simon Kelley0fc2f312014-01-08 10:26:58 +0000432 }
Simon Kelley3a237152013-12-12 12:15:50 +0000433#endif
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000434
435 /* If we're sending an EDNS0 with any options, we can't recreate the query from a reply. */
436 if (find_pseudoheader(header, plen, &edns0_len, NULL, NULL, NULL) && edns0_len > 11)
437 forward->flags |= FREC_HAS_EXTRADATA;
Simon Kelleya77cec82015-05-08 16:25:38 +0100438
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000439 while (1)
440 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000441 /* only send to servers dealing with our domain.
442 domain may be NULL, in which case server->domain
443 must be NULL also. */
444
Simon Kelleyde379512004-06-22 20:23:33 +0100445 if (type == (start->flags & SERV_TYPE) &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100446 (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +0100447 !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000448 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100449 int fd;
450
451 /* find server socket to use, may need to get random one. */
452 if (start->sfd)
453 fd = start->sfd->fd;
454 else
455 {
456#ifdef HAVE_IPV6
457 if (start->addr.sa.sa_family == AF_INET6)
458 {
459 if (!forward->rfd6 &&
460 !(forward->rfd6 = allocate_rfd(AF_INET6)))
461 break;
Simon Kelley3927da42008-07-20 15:10:39 +0100462 daemon->rfd_save = forward->rfd6;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100463 fd = forward->rfd6->fd;
464 }
465 else
466#endif
467 {
468 if (!forward->rfd4 &&
469 !(forward->rfd4 = allocate_rfd(AF_INET)))
470 break;
Simon Kelley3927da42008-07-20 15:10:39 +0100471 daemon->rfd_save = forward->rfd4;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100472 fd = forward->rfd4->fd;
473 }
Simon Kelley7de060b2011-08-26 17:24:52 +0100474
475#ifdef HAVE_CONNTRACK
476 /* Copy connection mark of incoming query to outgoing connection. */
477 if (option_bool(OPT_CONNTRACK))
478 {
479 unsigned int mark;
Giacomo Tazzari797a7af2013-04-22 13:16:37 +0100480 if (get_incoming_mark(&forward->source, &forward->dest, 0, &mark))
Simon Kelley7de060b2011-08-26 17:24:52 +0100481 setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
482 }
483#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +0100484 }
485
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000486#ifdef HAVE_DNSSEC
Simon Kelley5bb88f02015-12-21 16:23:47 +0000487 if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER))
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000488 {
489 /* Difficult one here. If our client didn't send EDNS0, we will have set the UDP
490 packet size to 512. But that won't provide space for the RRSIGS in many cases.
491 The RRSIGS will be stripped out before the answer goes back, so the packet should
492 shrink again. So, if we added a do-bit, bump the udp packet size to the value
Simon Kelley5aa5f0f2015-12-21 17:20:35 +0000493 known to be OK for this server. We check returned size after stripping and set
494 the truncated bit if it's still too big. */
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000495 unsigned char *pheader;
496 int is_sign;
Simon Kelley5bb88f02015-12-21 16:23:47 +0000497 if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000498 PUTSHORT(start->edns_pktsz, pheader);
499 }
500#endif
501
Simon Kelleyff841eb2015-03-11 21:36:30 +0000502 if (retry_send(sendto(fd, (char *)header, plen, 0,
503 &start->addr.sa,
504 sa_len(&start->addr))))
505 continue;
506
507 if (errno == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000508 {
Simon Kelleycdeda282006-03-16 20:16:06 +0000509 /* Keep info in case we want to re-send this packet */
510 daemon->srv_save = start;
511 daemon->packet_len = plen;
512
Simon Kelleyde379512004-06-22 20:23:33 +0100513 if (!gotname)
Simon Kelley3be34542004-09-11 19:12:13 +0100514 strcpy(daemon->namebuff, "query");
Simon Kelleyde379512004-06-22 20:23:33 +0100515 if (start->addr.sa.sa_family == AF_INET)
Simon Kelley3be34542004-09-11 19:12:13 +0100516 log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
Simon Kelley1a6bca82008-07-11 11:11:42 +0100517 (struct all_addr *)&start->addr.in.sin_addr, NULL);
Simon Kelleyde379512004-06-22 20:23:33 +0100518#ifdef HAVE_IPV6
519 else
Simon Kelley3be34542004-09-11 19:12:13 +0100520 log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
Simon Kelley1a6bca82008-07-11 11:11:42 +0100521 (struct all_addr *)&start->addr.in6.sin6_addr, NULL);
Simon Kelleyde379512004-06-22 20:23:33 +0100522#endif
Simon Kelley824af852008-02-12 20:43:05 +0000523 start->queries++;
Simon Kelleyde379512004-06-22 20:23:33 +0100524 forwarded = 1;
525 forward->sentto = start;
Simon Kelley0a852542005-03-23 20:28:59 +0000526 if (!forward->forwardall)
Simon Kelleyde379512004-06-22 20:23:33 +0100527 break;
Simon Kelley0a852542005-03-23 20:28:59 +0000528 forward->forwardall++;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000529 }
530 }
531
Simon Kelleyde379512004-06-22 20:23:33 +0100532 if (!(start = start->next))
Simon Kelley3be34542004-09-11 19:12:13 +0100533 start = daemon->servers;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000534
Simon Kelleyde379512004-06-22 20:23:33 +0100535 if (start == firstsentto)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000536 break;
537 }
538
Simon Kelleyde379512004-06-22 20:23:33 +0100539 if (forwarded)
Simon Kelley824af852008-02-12 20:43:05 +0000540 return 1;
Simon Kelleyde379512004-06-22 20:23:33 +0100541
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000542 /* could not send on, prepare to return */
543 header->id = htons(forward->orig_id);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100544 free_frec(forward); /* cancel */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000545 }
546
547 /* could not send on, return empty answer or address if known for whole domain */
Simon Kelleyb8187c82005-11-26 21:46:27 +0000548 if (udpfd != -1)
549 {
Simon Kelleycdeda282006-03-16 20:16:06 +0000550 plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl);
Simon Kelley54dd3932012-06-20 11:23:38 +0100551 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 +0000552 }
553
Simon Kelley824af852008-02-12 20:43:05 +0000554 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000555}
556
Simon Kelleyed4c0762013-10-08 20:46:34 +0100557static 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 +0100558 int no_cache, int cache_secure, int bogusanswer, int ad_reqd, int do_bit, int added_pheader,
559 int check_subnet, union mysockaddr *query_source)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100560{
Simon Kelley36717ee2004-09-20 19:20:58 +0100561 unsigned char *pheader, *sizep;
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000562 char **sets = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +0000563 int munged = 0, is_sign;
Simon Kelleycdeda282006-03-16 20:16:06 +0000564 size_t plen;
565
Simon Kelley83349b82014-02-10 21:02:01 +0000566 (void)ad_reqd;
Simon Kelley982faf42015-04-03 21:42:30 +0100567 (void)do_bit;
568 (void)bogusanswer;
Simon Kelley83349b82014-02-10 21:02:01 +0000569
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000570#ifdef HAVE_IPSET
Simon Kelley82a14af2014-04-13 20:48:57 +0100571 if (daemon->ipsets && extract_request(header, n, daemon->namebuff, NULL))
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000572 {
Simon Kelley82a14af2014-04-13 20:48:57 +0100573 /* Similar algorithm to search_servers. */
574 struct ipsets *ipset_pos;
575 unsigned int namelen = strlen(daemon->namebuff);
576 unsigned int matchlen = 0;
577 for (ipset_pos = daemon->ipsets; ipset_pos; ipset_pos = ipset_pos->next)
Simon Kelley6c0cb852014-01-17 14:40:46 +0000578 {
Simon Kelley82a14af2014-04-13 20:48:57 +0100579 unsigned int domainlen = strlen(ipset_pos->domain);
580 char *matchstart = daemon->namebuff + namelen - domainlen;
581 if (namelen >= domainlen && hostname_isequal(matchstart, ipset_pos->domain) &&
582 (domainlen == 0 || namelen == domainlen || *(matchstart - 1) == '.' ) &&
583 domainlen >= matchlen)
584 {
585 matchlen = domainlen;
586 sets = ipset_pos->sets;
587 }
Simon Kelley6c0cb852014-01-17 14:40:46 +0000588 }
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000589 }
590#endif
591
Simon Kelley5bb88f02015-12-21 16:23:47 +0000592 if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign, NULL)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100593 {
Simon Kelleyed4c0762013-10-08 20:46:34 +0100594 if (check_subnet && !check_source(header, plen, pheader, query_source))
595 {
596 my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch"));
597 return 0;
598 }
Simon Kelley613ad152014-02-25 23:02:28 +0000599
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000600 if (!is_sign)
Simon Kelley613ad152014-02-25 23:02:28 +0000601 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000602 if (added_pheader)
603 {
604 /* client didn't send EDNS0, we added one, strip it off before returning answer. */
605 n = rrfilter(header, n, 0);
606 pheader = NULL;
607 }
608 else
609 {
610 /* If upstream is advertising a larger UDP packet size
611 than we allow, trim it so that we don't get overlarge
612 requests for the client. We can't do this for signed packets. */
613 unsigned short udpsz;
614 unsigned char *psave = sizep;
615
616 GETSHORT(udpsz, sizep);
617 if (udpsz > daemon->edns_pktsz)
618 PUTSHORT(daemon->edns_pktsz, psave);
619 }
Simon Kelley613ad152014-02-25 23:02:28 +0000620 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100621 }
Simon Kelley83349b82014-02-10 21:02:01 +0000622
Simon Kelley28866e92011-02-14 20:19:14 +0000623 /* RFC 4035 sect 4.6 para 3 */
Giovanni Bajo237724c2012-04-05 02:46:52 +0200624 if (!is_sign && !option_bool(OPT_DNSSEC_PROXY))
Simon Kelley795501b2014-01-08 18:11:55 +0000625 header->hb4 &= ~HB4_AD;
Simon Kelley3a237152013-12-12 12:15:50 +0000626
Simon Kelley572b41e2011-02-18 18:11:18 +0000627 if (OPCODE(header) != QUERY || (RCODE(header) != NOERROR && RCODE(header) != NXDOMAIN))
Simon Kelley8938ae02014-05-01 17:46:25 +0100628 return resize_packet(header, n, pheader, plen);
Simon Kelley36717ee2004-09-20 19:20:58 +0100629
Simon Kelley0a852542005-03-23 20:28:59 +0000630 /* Complain loudly if the upstream server is non-recursive. */
Simon Kelley572b41e2011-02-18 18:11:18 +0000631 if (!(header->hb4 & HB4_RA) && RCODE(header) == NOERROR && ntohs(header->ancount) == 0 &&
Simon Kelley0a852542005-03-23 20:28:59 +0000632 server && !(server->flags & SERV_WARNED_RECURSIVE))
633 {
Simon Kelley3d8df262005-08-29 12:19:27 +0100634 prettyprint_addr(&server->addr, daemon->namebuff);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100635 my_syslog(LOG_WARNING, _("nameserver %s refused to do a recursive query"), daemon->namebuff);
Simon Kelley28866e92011-02-14 20:19:14 +0000636 if (!option_bool(OPT_LOG))
Simon Kelley0a852542005-03-23 20:28:59 +0000637 server->flags |= SERV_WARNED_RECURSIVE;
638 }
Giovanni Bajoe292e932012-04-22 14:32:02 +0200639
Simon Kelley572b41e2011-02-18 18:11:18 +0000640 if (daemon->bogus_addr && RCODE(header) != NXDOMAIN &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100641 check_for_bogus_wildcard(header, n, daemon->namebuff, daemon->bogus_addr, now))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100642 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100643 munged = 1;
Simon Kelley572b41e2011-02-18 18:11:18 +0000644 SET_RCODE(header, NXDOMAIN);
645 header->hb3 &= ~HB3_AA;
Simon Kelley6938f342014-01-26 22:47:39 +0000646 cache_secure = 0;
Simon Kelley36717ee2004-09-20 19:20:58 +0100647 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100648 else
Simon Kelley36717ee2004-09-20 19:20:58 +0100649 {
Simon Kelley6938f342014-01-26 22:47:39 +0000650 int doctored = 0;
651
Simon Kelley572b41e2011-02-18 18:11:18 +0000652 if (RCODE(header) == NXDOMAIN &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100653 extract_request(header, n, daemon->namebuff, NULL) &&
Simon Kelley5aabfc72007-08-29 11:24:47 +0100654 check_for_local_domain(daemon->namebuff, now))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100655 {
Simon Kelley36717ee2004-09-20 19:20:58 +0100656 /* if we forwarded a query for a locally known name (because it was for
657 an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
658 since we know that the domain exists, even if upstream doesn't */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100659 munged = 1;
Simon Kelley572b41e2011-02-18 18:11:18 +0000660 header->hb3 |= HB3_AA;
661 SET_RCODE(header, NOERROR);
Simon Kelley6938f342014-01-26 22:47:39 +0000662 cache_secure = 0;
Simon Kelley36717ee2004-09-20 19:20:58 +0100663 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000664
Simon Kelley6938f342014-01-26 22:47:39 +0000665 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 +0000666 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100667 my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
Simon Kelley824af852008-02-12 20:43:05 +0000668 munged = 1;
Simon Kelley6938f342014-01-26 22:47:39 +0000669 cache_secure = 0;
Simon Kelley824af852008-02-12 20:43:05 +0000670 }
Simon Kelley6938f342014-01-26 22:47:39 +0000671
672 if (doctored)
673 cache_secure = 0;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100674 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100675
Simon Kelleya25720a2014-01-14 23:13:55 +0000676#ifdef HAVE_DNSSEC
Simon Kelleyfe3992f2015-04-03 21:25:05 +0100677 if (bogusanswer && !(header->hb4 & HB4_CD))
Simon Kelleya25720a2014-01-14 23:13:55 +0000678 {
Simon Kelley7d23a662014-01-26 09:33:21 +0000679 if (!option_bool(OPT_DNSSEC_DEBUG))
Simon Kelleya25720a2014-01-14 23:13:55 +0000680 {
681 /* Bogus reply, turn into SERVFAIL */
682 SET_RCODE(header, SERVFAIL);
683 munged = 1;
684 }
685 }
Simon Kelley6938f342014-01-26 22:47:39 +0000686
687 if (option_bool(OPT_DNSSEC_VALID))
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000688 {
689 header->hb4 &= ~HB4_AD;
690
691 if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure)
692 header->hb4 |= HB4_AD;
693
694 /* If the requestor didn't set the DO bit, don't return DNSSEC info. */
695 if (!do_bit)
696 n = rrfilter(header, n, 1);
697 }
Simon Kelleya25720a2014-01-14 23:13:55 +0000698#endif
699
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100700 /* do this after extract_addresses. Ensure NODATA reply and remove
701 nameserver info. */
702
703 if (munged)
704 {
705 header->ancount = htons(0);
706 header->nscount = htons(0);
707 header->arcount = htons(0);
Simon Kelley150162b2015-03-27 09:58:26 +0000708 header->hb3 &= ~HB3_TC;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100709 }
710
Simon Kelley36717ee2004-09-20 19:20:58 +0100711 /* the bogus-nxdomain stuff, doctor and NXDOMAIN->NODATA munging can all elide
712 sections of the packet. Find the new length here and put back pseudoheader
713 if it was removed. */
714 return resize_packet(header, n, pheader, plen);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100715}
716
Simon Kelley3be34542004-09-11 19:12:13 +0100717/* sets new last_server */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100718void reply_query(int fd, int family, time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000719{
720 /* packet from peer server, extract data for cache, and send to
721 original requester */
Simon Kelley572b41e2011-02-18 18:11:18 +0000722 struct dns_header *header;
Simon Kelleyde379512004-06-22 20:23:33 +0100723 union mysockaddr serveraddr;
Simon Kelley832af0b2007-01-21 20:01:28 +0000724 struct frec *forward;
Simon Kelleyde379512004-06-22 20:23:33 +0100725 socklen_t addrlen = sizeof(serveraddr);
Simon Kelley60b68062014-01-08 12:10:28 +0000726 ssize_t n = recvfrom(fd, daemon->packet, daemon->packet_buff_sz, 0, &serveraddr.sa, &addrlen);
Simon Kelleycdeda282006-03-16 20:16:06 +0000727 size_t nn;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100728 struct server *server;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000729 void *hash;
730#ifndef HAVE_DNSSEC
731 unsigned int crc;
732#endif
733
Simon Kelleycdeda282006-03-16 20:16:06 +0000734 /* packet buffer overwritten */
735 daemon->srv_save = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +0000736
Simon Kelleyde379512004-06-22 20:23:33 +0100737 /* Determine the address of the server replying so that we can mark that as good */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100738 serveraddr.sa.sa_family = family;
Simon Kelleyde379512004-06-22 20:23:33 +0100739#ifdef HAVE_IPV6
740 if (serveraddr.sa.sa_family == AF_INET6)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100741 serveraddr.in6.sin6_flowinfo = 0;
Simon Kelleyde379512004-06-22 20:23:33 +0100742#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000743
Simon Kelley490f9072014-03-24 22:04:42 +0000744 header = (struct dns_header *)daemon->packet;
745
746 if (n < (int)sizeof(struct dns_header) || !(header->hb3 & HB3_QR))
747 return;
748
Simon Kelley1a6bca82008-07-11 11:11:42 +0100749 /* spoof check: answer must come from known server, */
750 for (server = daemon->servers; server; server = server->next)
751 if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) &&
752 sockaddr_isequal(&server->addr, &serveraddr))
753 break;
Simon Kelley490f9072014-03-24 22:04:42 +0000754
755 if (!server)
756 return;
757
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000758#ifdef HAVE_DNSSEC
759 hash = hash_questions(header, n, daemon->namebuff);
760#else
761 hash = &crc;
762 crc = questions_crc(header, n, daemon->namebuff);
763#endif
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100764
Simon Kelley490f9072014-03-24 22:04:42 +0000765 if (!(forward = lookup_frec(ntohs(header->id), hash)))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100766 return;
Simon Kelley490f9072014-03-24 22:04:42 +0000767
Simon Kelley25cf5e32015-01-09 15:53:03 +0000768 /* log_query gets called indirectly all over the place, so
769 pass these in global variables - sorry. */
770 daemon->log_display_id = forward->log_id;
771 daemon->log_source_addr = &forward->source;
772
Glen Huang32fc6db2014-12-27 15:28:12 +0000773 if (daemon->ignore_addr && RCODE(header) == NOERROR &&
774 check_for_ignored_address(header, n, daemon->ignore_addr))
775 return;
776
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000777 /* Note: if we send extra options in the EDNS0 header, we can't recreate
778 the query from the reply. */
Simon Kelley2ae195f2015-01-18 22:20:48 +0000779 if (RCODE(header) == REFUSED &&
Simon Kelley28866e92011-02-14 20:19:14 +0000780 !option_bool(OPT_ORDER) &&
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000781 forward->forwardall == 0 &&
782 !(forward->flags & FREC_HAS_EXTRADATA))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100783 /* for broken servers, attempt to send to another one. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000784 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100785 unsigned char *pheader;
786 size_t plen;
787 int is_sign;
Simon Kelley832af0b2007-01-21 20:01:28 +0000788
Simon Kelley1a6bca82008-07-11 11:11:42 +0100789 /* recreate query from reply */
Simon Kelley5bb88f02015-12-21 16:23:47 +0000790 pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100791 if (!is_sign)
Simon Kelley832af0b2007-01-21 20:01:28 +0000792 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100793 header->ancount = htons(0);
794 header->nscount = htons(0);
795 header->arcount = htons(0);
796 if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
797 {
swiggerbd7bfa22015-06-01 20:54:59 +0100798 header->hb3 &= ~(HB3_QR | HB3_AA | HB3_TC);
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000799 header->hb4 &= ~(HB4_RA | HB4_RCODE | HB4_CD | HB4_AD);
800 if (forward->flags |= FREC_CHECKING_DISABLED)
801 header->hb4 |= HB4_CD;
802 if (forward->flags |= FREC_AD_QUESTION)
803 header->hb4 |= HB4_AD;
804 if (forward->flags & FREC_DO_QUESTION)
805 add_do_bit(header, nn, (char *)pheader + plen);
806 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 +0100807 return;
808 }
809 }
810 }
Simon Kelley3a237152013-12-12 12:15:50 +0000811
812 server = forward->sentto;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100813 if ((forward->sentto->flags & SERV_TYPE) == 0)
814 {
Simon Kelley51967f92014-03-25 21:07:00 +0000815 if (RCODE(header) == REFUSED)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100816 server = NULL;
817 else
818 {
819 struct server *last_server;
Simon Kelley832af0b2007-01-21 20:01:28 +0000820
Simon Kelley1a6bca82008-07-11 11:11:42 +0100821 /* find good server by address if possible, otherwise assume the last one we sent to */
822 for (last_server = daemon->servers; last_server; last_server = last_server->next)
823 if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) &&
824 sockaddr_isequal(&last_server->addr, &serveraddr))
825 {
826 server = last_server;
827 break;
828 }
829 }
Simon Kelley28866e92011-02-14 20:19:14 +0000830 if (!option_bool(OPT_ALL_SERVERS))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100831 daemon->last_server = server;
832 }
Simon Kelleya77cec82015-05-08 16:25:38 +0100833
834 /* We tried resending to this server with a smaller maximum size and got an answer.
Simon Kelley86fa1042015-05-10 13:50:59 +0100835 Make that permanent. To avoid reduxing the packet size for an single dropped packet,
836 only do this when we get a truncated answer, or one larger than the safe size. */
837 if (server && (forward->flags & FREC_TEST_PKTSZ) &&
838 ((header->hb3 & HB3_TC) || n >= SAFE_PKTSZ))
Simon Kelleya77cec82015-05-08 16:25:38 +0100839 server->edns_pktsz = SAFE_PKTSZ;
840
Simon Kelley1a6bca82008-07-11 11:11:42 +0100841 /* If the answer is an error, keep the forward record in place in case
842 we get a good reply from another server. Kill it when we've
843 had replies from all to avoid filling the forwarding table when
844 everything is broken */
Simon Kelley51967f92014-03-25 21:07:00 +0000845 if (forward->forwardall == 0 || --forward->forwardall == 1 || RCODE(header) != SERVFAIL)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100846 {
Simon Kelleyfe3992f2015-04-03 21:25:05 +0100847 int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100848
Simon Kelley3a237152013-12-12 12:15:50 +0000849 if (option_bool(OPT_NO_REBIND))
850 check_rebind = !(forward->flags & FREC_NOREBIND);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100851
Simon Kelley3a237152013-12-12 12:15:50 +0000852 /* Don't cache replies where DNSSEC validation was turned off, either
853 the upstream server told us so, or the original query specified it. */
854 if ((header->hb4 & HB4_CD) || (forward->flags & FREC_CHECKING_DISABLED))
855 no_cache_dnssec = 1;
856
857#ifdef HAVE_DNSSEC
Simon Kelley51967f92014-03-25 21:07:00 +0000858 if (server && option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED))
Simon Kelley3a237152013-12-12 12:15:50 +0000859 {
Simon Kelley9a31b682015-12-15 10:20:39 +0000860 int status = 0;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000861
862 /* We've had a reply already, which we're validating. Ignore this duplicate */
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000863 if (forward->blocking_query)
Simon Kelley0fc2f312014-01-08 10:26:58 +0000864 return;
Simon Kelley9a31b682015-12-15 10:20:39 +0000865
866 /* Truncated answer can't be validated.
Simon Kelley5d3b87a2014-01-20 11:57:23 +0000867 If this is an answer to a DNSSEC-generated query, we still
868 need to get the client to retry over TCP, so return
869 an answer with the TC bit set, even if the actual answer fits.
870 */
Simon Kelley9a31b682015-12-15 10:20:39 +0000871 if (header->hb3 & HB3_TC)
872 status = STAT_TRUNCATED;
873
874 while (1)
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000875 {
Simon Kelley9a31b682015-12-15 10:20:39 +0000876 /* As soon as anything returns BOGUS, we stop and unwind, to do otherwise
877 would invite infinite loops, since the answers to DNSKEY and DS queries
878 will not be cached, so they'll be repeated. */
879 if (status != STAT_BOGUS && status != STAT_TRUNCATED && status != STAT_ABANDONED)
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000880 {
Simon Kelley9a31b682015-12-15 10:20:39 +0000881 if (forward->flags & FREC_DNSKEY_QUERY)
882 status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
883 else if (forward->flags & FREC_DS_QUERY)
884 status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000885 else
Simon Kelley9a31b682015-12-15 10:20:39 +0000886 status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class,
887 option_bool(OPT_DNSSEC_NO_SIGN), NULL, NULL);
Simon Kelley00a5b5d2014-02-28 18:10:55 +0000888 }
Simon Kelley0fc2f312014-01-08 10:26:58 +0000889
Simon Kelley9a31b682015-12-15 10:20:39 +0000890 /* Can't validate, as we're missing key data. Put this
891 answer aside, whilst we get that. */
892 if (status == STAT_NEED_DS || status == STAT_NEED_KEY)
Simon Kelley3a237152013-12-12 12:15:50 +0000893 {
Simon Kelley9a31b682015-12-15 10:20:39 +0000894 struct frec *new, *orig;
Simon Kelley9d633042013-12-13 15:36:55 +0000895
Simon Kelley9a31b682015-12-15 10:20:39 +0000896 /* Free any saved query */
897 if (forward->stash)
898 blockdata_free(forward->stash);
899
900 /* Now save reply pending receipt of key data */
901 if (!(forward->stash = blockdata_alloc((char *)header, n)))
Simon Kelley97e618a2015-01-07 21:55:43 +0000902 return;
Simon Kelley9a31b682015-12-15 10:20:39 +0000903 forward->stash_len = n;
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000904
Simon Kelley9a31b682015-12-15 10:20:39 +0000905 /* Find the original query that started it all.... */
906 for (orig = forward; orig->dependent; orig = orig->dependent);
Simon Kelley7fa836e2014-02-10 20:11:24 +0000907
Simon Kelley9a31b682015-12-15 10:20:39 +0000908 if (--orig->work_counter == 0 || !(new = get_new_frec(now, NULL, 1)))
909 status = STAT_ABANDONED;
Simon Kelleye0c0ad32014-01-16 22:42:07 +0000910 else
Simon Kelley3a237152013-12-12 12:15:50 +0000911 {
Simon Kelley9a31b682015-12-15 10:20:39 +0000912 int fd;
913 struct frec *next = new->next;
914 *new = *forward; /* copy everything, then overwrite */
915 new->next = next;
916 new->blocking_query = NULL;
917 new->sentto = server;
918 new->rfd4 = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +0000919#ifdef HAVE_IPV6
Simon Kelley9a31b682015-12-15 10:20:39 +0000920 new->rfd6 = NULL;
Simon Kelley7fa836e2014-02-10 20:11:24 +0000921#endif
Simon Kelley9a31b682015-12-15 10:20:39 +0000922 new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY);
923
924 new->dependent = forward; /* to find query awaiting new one. */
925 forward->blocking_query = new; /* for garbage cleaning */
926 /* validate routines leave name of required record in daemon->keyname */
927 if (status == STAT_NEED_KEY)
Simon Kelley7fa836e2014-02-10 20:11:24 +0000928 {
Simon Kelley9a31b682015-12-15 10:20:39 +0000929 new->flags |= FREC_DNSKEY_QUERY;
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000930 nn = dnssec_generate_query(header, ((char *) header) + server->edns_pktsz,
Simon Kelley9a31b682015-12-15 10:20:39 +0000931 daemon->keyname, forward->class, T_DNSKEY, &server->addr, server->edns_pktsz);
Simon Kelleyf1668d22014-01-08 16:53:27 +0000932 }
Simon Kelley9a31b682015-12-15 10:20:39 +0000933 else
934 {
935 new->flags |= FREC_DS_QUERY;
Simon Kelleyd3a8b392015-12-23 12:27:37 +0000936 nn = dnssec_generate_query(header,((char *) header) + server->edns_pktsz,
Simon Kelley9a31b682015-12-15 10:20:39 +0000937 daemon->keyname, forward->class, T_DS, &server->addr, server->edns_pktsz);
938 }
939 if ((hash = hash_questions(header, nn, daemon->namebuff)))
940 memcpy(new->hash, hash, HASH_SIZE);
941 new->new_id = get_id();
942 header->id = htons(new->new_id);
943 /* Save query for retransmission */
944 new->stash = blockdata_alloc((char *)header, nn);
945 new->stash_len = nn;
946
947 /* Don't resend this. */
948 daemon->srv_save = NULL;
949
950 if (server->sfd)
951 fd = server->sfd->fd;
952 else
953 {
954 fd = -1;
955#ifdef HAVE_IPV6
956 if (server->addr.sa.sa_family == AF_INET6)
957 {
958 if (new->rfd6 || (new->rfd6 = allocate_rfd(AF_INET6)))
959 fd = new->rfd6->fd;
960 }
961 else
962#endif
963 {
964 if (new->rfd4 || (new->rfd4 = allocate_rfd(AF_INET)))
965 fd = new->rfd4->fd;
966 }
967 }
968
969 if (fd != -1)
970 {
971 while (retry_send(sendto(fd, (char *)header, nn, 0,
972 &server->addr.sa,
973 sa_len(&server->addr))));
974 server->queries++;
975 }
976 }
Simon Kelley7fa836e2014-02-10 20:11:24 +0000977 return;
Simon Kelley3a237152013-12-12 12:15:50 +0000978 }
Simon Kelley3a237152013-12-12 12:15:50 +0000979
Simon Kelley9a31b682015-12-15 10:20:39 +0000980 /* Validated original answer, all done. */
981 if (!forward->dependent)
982 break;
983
984 /* validated subsdiary query, (and cached result)
985 pop that and return to the previous query we were working on. */
Simon Kelley0744ca62014-01-25 16:40:15 +0000986 struct frec *prev = forward->dependent;
987 free_frec(forward);
988 forward = prev;
989 forward->blocking_query = NULL; /* already gone */
990 blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
991 n = forward->stash_len;
Simon Kelley3a237152013-12-12 12:15:50 +0000992 }
Simon Kelley9a31b682015-12-15 10:20:39 +0000993
Simon Kelley5d3b87a2014-01-20 11:57:23 +0000994
Simon Kelleyfe3992f2015-04-03 21:25:05 +0100995 no_cache_dnssec = 0;
Simon Kelleyfe3992f2015-04-03 21:25:05 +0100996
Simon Kelley5d3b87a2014-01-20 11:57:23 +0000997 if (status == STAT_TRUNCATED)
Simon Kelley0744ca62014-01-25 16:40:15 +0000998 header->hb3 |= HB3_TC;
Simon Kelley5d3b87a2014-01-20 11:57:23 +0000999 else
Simon Kelley7fa836e2014-02-10 20:11:24 +00001000 {
Simon Kelley554b5802015-04-17 22:50:20 +01001001 char *result, *domain = "result";
Simon Kelley7fa836e2014-02-10 20:11:24 +00001002
Simon Kelley9a31b682015-12-15 10:20:39 +00001003 if (status == STAT_ABANDONED)
Simon Kelley150162b2015-03-27 09:58:26 +00001004 {
1005 result = "ABANDONED";
1006 status = STAT_BOGUS;
1007 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00001008 else
1009 result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
1010
Simon Kelley554b5802015-04-17 22:50:20 +01001011 if (status == STAT_BOGUS && extract_request(header, n, daemon->namebuff, NULL))
1012 domain = daemon->namebuff;
Simon Kelley9a31b682015-12-15 10:20:39 +00001013
Simon Kelley554b5802015-04-17 22:50:20 +01001014 log_query(F_KEYTAG | F_SECSTAT, domain, NULL, result);
Simon Kelley7fa836e2014-02-10 20:11:24 +00001015 }
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001016
Simon Kelley3a237152013-12-12 12:15:50 +00001017 if (status == STAT_SECURE)
1018 cache_secure = 1;
Simon Kelley3a237152013-12-12 12:15:50 +00001019 else if (status == STAT_BOGUS)
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001020 {
1021 no_cache_dnssec = 1;
1022 bogusanswer = 1;
1023 }
Simon Kelley3a237152013-12-12 12:15:50 +00001024 }
Simon Kelley83349b82014-02-10 21:02:01 +00001025#endif
1026
1027 /* restore CD bit to the value in the query */
1028 if (forward->flags & FREC_CHECKING_DISABLED)
1029 header->hb4 |= HB4_CD;
1030 else
1031 header->hb4 &= ~HB4_CD;
Simon Kelley3a237152013-12-12 12:15:50 +00001032
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001033 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 +00001034 forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION,
1035 forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->source)))
Simon Kelley832af0b2007-01-21 20:01:28 +00001036 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001037 header->id = htons(forward->orig_id);
Simon Kelley572b41e2011-02-18 18:11:18 +00001038 header->hb4 |= HB4_RA; /* recursion if available */
Simon Kelley5aa5f0f2015-12-21 17:20:35 +00001039#ifdef HAVE_DNSSEC
1040 /* We added an EDNSO header for the purpose of getting DNSSEC RRs, and set the value of the UDP payload size
1041 greater than the no-EDNS0-implied 512 to have if space for the RRSIGS. If, having stripped them and the EDNS0
1042 header, the answer is still bigger than 512, truncate it and mark it so. The client then retries with TCP. */
1043 if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER) && (nn > PACKETSZ))
1044 {
1045 header->ancount = htons(0);
1046 header->nscount = htons(0);
1047 header->arcount = htons(0);
1048 header->hb3 |= HB3_TC;
1049 nn = resize_packet(header, nn, NULL, 0);
1050 }
1051#endif
Simon Kelley54dd3932012-06-20 11:23:38 +01001052 send_from(forward->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
Simon Kelley50303b12012-04-04 22:13:17 +01001053 &forward->source, &forward->dest, forward->iface);
Simon Kelley832af0b2007-01-21 20:01:28 +00001054 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001055 free_frec(forward); /* cancel */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001056 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001057}
Simon Kelley44a2a312004-03-10 20:04:35 +00001058
Simon Kelley1a6bca82008-07-11 11:11:42 +01001059
Simon Kelley5aabfc72007-08-29 11:24:47 +01001060void receive_query(struct listener *listen, time_t now)
Simon Kelley44a2a312004-03-10 20:04:35 +00001061{
Simon Kelley572b41e2011-02-18 18:11:18 +00001062 struct dns_header *header = (struct dns_header *)daemon->packet;
Simon Kelley44a2a312004-03-10 20:04:35 +00001063 union mysockaddr source_addr;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001064 unsigned char *pheader;
1065 unsigned short type, udp_size = PACKETSZ; /* default if no EDNS0 */
Simon Kelley44a2a312004-03-10 20:04:35 +00001066 struct all_addr dst_addr;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001067 struct in_addr netmask, dst_addr_4;
Simon Kelleycdeda282006-03-16 20:16:06 +00001068 size_t m;
1069 ssize_t n;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001070 int if_index = 0, auth_dns = 0, do_bit = 0, have_pseudoheader = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001071#ifdef HAVE_AUTH
1072 int local_auth = 0;
1073#endif
Simon Kelley44a2a312004-03-10 20:04:35 +00001074 struct iovec iov[1];
1075 struct msghdr msg;
1076 struct cmsghdr *cmptr;
Simon Kelley44a2a312004-03-10 20:04:35 +00001077 union {
1078 struct cmsghdr align; /* this ensures alignment */
1079#ifdef HAVE_IPV6
1080 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
1081#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001082#if defined(HAVE_LINUX_NETWORK)
Simon Kelley44a2a312004-03-10 20:04:35 +00001083 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
Simon Kelley824af852008-02-12 20:43:05 +00001084#elif defined(IP_RECVDSTADDR) && defined(HAVE_SOLARIS_NETWORK)
1085 char control[CMSG_SPACE(sizeof(struct in_addr)) +
1086 CMSG_SPACE(sizeof(unsigned int))];
Simon Kelley44a2a312004-03-10 20:04:35 +00001087#elif defined(IP_RECVDSTADDR)
1088 char control[CMSG_SPACE(sizeof(struct in_addr)) +
1089 CMSG_SPACE(sizeof(struct sockaddr_dl))];
1090#endif
1091 } control_u;
Simon Kelley2329bef2013-12-03 13:41:16 +00001092#ifdef HAVE_IPV6
1093 /* Can always get recvd interface for IPv6 */
1094 int check_dst = !option_bool(OPT_NOWILD) || listen->family == AF_INET6;
1095#else
1096 int check_dst = !option_bool(OPT_NOWILD);
1097#endif
1098
Simon Kelleycdeda282006-03-16 20:16:06 +00001099 /* packet buffer overwritten */
1100 daemon->srv_save = NULL;
1101
Hans Dedecker98906272014-12-09 22:22:53 +00001102 dst_addr_4.s_addr = dst_addr.addr.addr4.s_addr = 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001103 netmask.s_addr = 0;
1104
Simon Kelley7e5664b2013-04-05 16:57:41 +01001105 if (option_bool(OPT_NOWILD) && listen->iface)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001106 {
Simon Kelley4f7b3042012-11-28 21:27:02 +00001107 auth_dns = listen->iface->dns_auth;
1108
1109 if (listen->family == AF_INET)
1110 {
Hans Dedecker98906272014-12-09 22:22:53 +00001111 dst_addr_4 = dst_addr.addr.addr4 = listen->iface->addr.in.sin_addr;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001112 netmask = listen->iface->netmask;
1113 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001114 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00001115
Simon Kelley3be34542004-09-11 19:12:13 +01001116 iov[0].iov_base = daemon->packet;
1117 iov[0].iov_len = daemon->edns_pktsz;
Simon Kelley44a2a312004-03-10 20:04:35 +00001118
1119 msg.msg_control = control_u.control;
1120 msg.msg_controllen = sizeof(control_u);
1121 msg.msg_flags = 0;
1122 msg.msg_name = &source_addr;
1123 msg.msg_namelen = sizeof(source_addr);
1124 msg.msg_iov = iov;
1125 msg.msg_iovlen = 1;
1126
Simon Kelleyde379512004-06-22 20:23:33 +01001127 if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
Simon Kelley3be34542004-09-11 19:12:13 +01001128 return;
Simon Kelley44a2a312004-03-10 20:04:35 +00001129
Simon Kelley572b41e2011-02-18 18:11:18 +00001130 if (n < (int)sizeof(struct dns_header) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001131 (msg.msg_flags & MSG_TRUNC) ||
Simon Kelley572b41e2011-02-18 18:11:18 +00001132 (header->hb3 & HB3_QR))
Simon Kelley3be34542004-09-11 19:12:13 +01001133 return;
Simon Kelley44a2a312004-03-10 20:04:35 +00001134
Simon Kelley26128d22004-11-14 16:43:54 +00001135 source_addr.sa.sa_family = listen->family;
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001136
1137 if (listen->family == AF_INET)
1138 {
1139 /* Source-port == 0 is an error, we can't send back to that.
1140 http://www.ietf.org/mail-archive/web/dnsop/current/msg11441.html */
1141 if (source_addr.in.sin_port == 0)
1142 return;
1143 }
Simon Kelley26128d22004-11-14 16:43:54 +00001144#ifdef HAVE_IPV6
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001145 else
1146 {
1147 /* Source-port == 0 is an error, we can't send back to that. */
1148 if (source_addr.in6.sin6_port == 0)
1149 return;
1150 source_addr.in6.sin6_flowinfo = 0;
1151 }
Simon Kelley26128d22004-11-14 16:43:54 +00001152#endif
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001153
Simon Kelleyc8a80482014-03-05 14:29:54 +00001154 /* We can be configured to only accept queries from at-most-one-hop-away addresses. */
1155 if (option_bool(OPT_LOCAL_SERVICE))
1156 {
1157 struct addrlist *addr;
1158#ifdef HAVE_IPV6
1159 if (listen->family == AF_INET6)
1160 {
1161 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1162 if ((addr->flags & ADDRLIST_IPV6) &&
1163 is_same_net6(&addr->addr.addr.addr6, &source_addr.in6.sin6_addr, addr->prefixlen))
1164 break;
1165 }
1166 else
1167#endif
1168 {
1169 struct in_addr netmask;
1170 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1171 {
Richard Genoud15b1b7e2014-09-17 21:12:00 +01001172 netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
Simon Kelleyc8a80482014-03-05 14:29:54 +00001173 if (!(addr->flags & ADDRLIST_IPV6) &&
1174 is_same_net(addr->addr.addr.addr4, source_addr.in.sin_addr, netmask))
1175 break;
1176 }
1177 }
1178 if (!addr)
1179 {
Simon Kelley0c8584e2014-03-12 20:12:56 +00001180 static int warned = 0;
1181 if (!warned)
1182 {
1183 my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
1184 warned = 1;
1185 }
Simon Kelleyc8a80482014-03-05 14:29:54 +00001186 return;
1187 }
1188 }
1189
Simon Kelley2329bef2013-12-03 13:41:16 +00001190 if (check_dst)
Simon Kelley44a2a312004-03-10 20:04:35 +00001191 {
Simon Kelley8a911cc2004-03-16 18:35:52 +00001192 struct ifreq ifr;
1193
Simon Kelley26128d22004-11-14 16:43:54 +00001194 if (msg.msg_controllen < sizeof(struct cmsghdr))
1195 return;
1196
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001197#if defined(HAVE_LINUX_NETWORK)
Simon Kelley26128d22004-11-14 16:43:54 +00001198 if (listen->family == AF_INET)
1199 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelleyc72daea2012-01-05 21:33:27 +00001200 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
Simon Kelley26128d22004-11-14 16:43:54 +00001201 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001202 union {
1203 unsigned char *c;
1204 struct in_pktinfo *p;
1205 } p;
1206 p.c = CMSG_DATA(cmptr);
1207 dst_addr_4 = dst_addr.addr.addr4 = p.p->ipi_spec_dst;
1208 if_index = p.p->ipi_ifindex;
Simon Kelley26128d22004-11-14 16:43:54 +00001209 }
1210#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
1211 if (listen->family == AF_INET)
1212 {
1213 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001214 {
1215 union {
1216 unsigned char *c;
1217 unsigned int *i;
1218 struct in_addr *a;
1219#ifndef HAVE_SOLARIS_NETWORK
1220 struct sockaddr_dl *s;
Simon Kelley824af852008-02-12 20:43:05 +00001221#endif
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001222 } p;
1223 p.c = CMSG_DATA(cmptr);
1224 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
1225 dst_addr_4 = dst_addr.addr.addr4 = *(p.a);
1226 else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
1227#ifdef HAVE_SOLARIS_NETWORK
1228 if_index = *(p.i);
1229#else
1230 if_index = p.s->sdl_index;
1231#endif
1232 }
Simon Kelley26128d22004-11-14 16:43:54 +00001233 }
1234#endif
1235
1236#ifdef HAVE_IPV6
1237 if (listen->family == AF_INET6)
1238 {
1239 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelleyc72daea2012-01-05 21:33:27 +00001240 if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
Simon Kelley26128d22004-11-14 16:43:54 +00001241 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001242 union {
1243 unsigned char *c;
1244 struct in6_pktinfo *p;
1245 } p;
1246 p.c = CMSG_DATA(cmptr);
1247
1248 dst_addr.addr.addr6 = p.p->ipi6_addr;
1249 if_index = p.p->ipi6_ifindex;
Simon Kelley26128d22004-11-14 16:43:54 +00001250 }
1251 }
1252#endif
1253
1254 /* enforce available interface configuration */
1255
Simon Kelleye25db1f2013-01-29 22:10:26 +00001256 if (!indextoname(listen->fd, if_index, ifr.ifr_name))
Simon Kelley832af0b2007-01-21 20:01:28 +00001257 return;
1258
Simon Kelleye25db1f2013-01-29 22:10:26 +00001259 if (!iface_check(listen->family, &dst_addr, ifr.ifr_name, &auth_dns))
1260 {
1261 if (!option_bool(OPT_CLEVERBIND))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001262 enumerate_interfaces(0);
Simon Kelley3f2873d2013-05-14 11:28:47 +01001263 if (!loopback_exception(listen->fd, listen->family, &dst_addr, ifr.ifr_name) &&
1264 !label_exception(if_index, listen->family, &dst_addr))
Simon Kelleye25db1f2013-01-29 22:10:26 +00001265 return;
1266 }
1267
Simon Kelley552af8b2012-02-29 20:10:31 +00001268 if (listen->family == AF_INET && option_bool(OPT_LOCALISE))
1269 {
1270 struct irec *iface;
1271
1272 /* get the netmask of the interface whch has the address we were sent to.
1273 This is no neccessarily the interface we arrived on. */
1274
1275 for (iface = daemon->interfaces; iface; iface = iface->next)
1276 if (iface->addr.sa.sa_family == AF_INET &&
1277 iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
1278 break;
1279
1280 /* interface may be new */
Simon Kelleye25db1f2013-01-29 22:10:26 +00001281 if (!iface && !option_bool(OPT_CLEVERBIND))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001282 enumerate_interfaces(0);
Simon Kelley552af8b2012-02-29 20:10:31 +00001283
1284 for (iface = daemon->interfaces; iface; iface = iface->next)
1285 if (iface->addr.sa.sa_family == AF_INET &&
1286 iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
1287 break;
1288
1289 /* If we failed, abandon localisation */
1290 if (iface)
1291 netmask = iface->netmask;
1292 else
1293 dst_addr_4.s_addr = 0;
1294 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001295 }
Simon Kelley25cf5e32015-01-09 15:53:03 +00001296
1297 /* log_query gets called indirectly all over the place, so
1298 pass these in global variables - sorry. */
1299 daemon->log_display_id = ++daemon->log_id;
1300 daemon->log_source_addr = &source_addr;
Simon Kelley44a2a312004-03-10 20:04:35 +00001301
Simon Kelleycdeda282006-03-16 20:16:06 +00001302 if (extract_request(header, (size_t)n, daemon->namebuff, &type))
Simon Kelley44a2a312004-03-10 20:04:35 +00001303 {
Simon Kelleyb485ed92013-10-18 22:00:39 +01001304#ifdef HAVE_AUTH
1305 struct auth_zone *zone;
1306#endif
Simon Kelley610e7822014-02-06 14:45:17 +00001307 char *types = querystr(auth_dns ? "auth" : "query", type);
1308
Simon Kelley44a2a312004-03-10 20:04:35 +00001309 if (listen->family == AF_INET)
Simon Kelley3be34542004-09-11 19:12:13 +01001310 log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
Simon Kelley1a6bca82008-07-11 11:11:42 +01001311 (struct all_addr *)&source_addr.in.sin_addr, types);
Simon Kelley44a2a312004-03-10 20:04:35 +00001312#ifdef HAVE_IPV6
1313 else
Simon Kelley3be34542004-09-11 19:12:13 +01001314 log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
Simon Kelley1a6bca82008-07-11 11:11:42 +01001315 (struct all_addr *)&source_addr.in6.sin6_addr, types);
Simon Kelley44a2a312004-03-10 20:04:35 +00001316#endif
Simon Kelley44a2a312004-03-10 20:04:35 +00001317
Simon Kelley4820dce2012-12-18 18:30:30 +00001318#ifdef HAVE_AUTH
Simon Kelleyb485ed92013-10-18 22:00:39 +01001319 /* find queries for zones we're authoritative for, and answer them directly */
Simon Kelley3a3965a2015-08-09 17:45:06 +01001320 if (!auth_dns && !option_bool(OPT_LOCALISE))
Simon Kelley6008bdb2013-10-21 21:47:03 +01001321 for (zone = daemon->auth_zones; zone; zone = zone->next)
1322 if (in_zone(zone, daemon->namebuff, NULL))
1323 {
1324 auth_dns = 1;
1325 local_auth = 1;
1326 break;
1327 }
Simon Kelleyb485ed92013-10-18 22:00:39 +01001328#endif
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01001329
1330#ifdef HAVE_LOOP
1331 /* Check for forwarding loop */
1332 if (detect_loop(daemon->namebuff, type))
1333 return;
1334#endif
Simon Kelleyb485ed92013-10-18 22:00:39 +01001335 }
1336
Simon Kelley5bb88f02015-12-21 16:23:47 +00001337 if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL, NULL))
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001338 {
1339 unsigned short flags;
1340
1341 have_pseudoheader = 1;
1342 GETSHORT(udp_size, pheader);
1343 pheader += 2; /* ext_rcode */
1344 GETSHORT(flags, pheader);
1345
1346 if (flags & 0x8000)
1347 do_bit = 1;/* do bit */
1348
1349 /* If the client provides an EDNS0 UDP size, use that to limit our reply.
1350 (bounded by the maximum configured). If no EDNS0, then it
1351 defaults to 512 */
1352 if (udp_size > daemon->edns_pktsz)
1353 udp_size = daemon->edns_pktsz;
1354 }
1355
Simon Kelleyb485ed92013-10-18 22:00:39 +01001356#ifdef HAVE_AUTH
Simon Kelley4f7b3042012-11-28 21:27:02 +00001357 if (auth_dns)
Simon Kelley824af852008-02-12 20:43:05 +00001358 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001359 m = answer_auth(header, ((char *) header) + udp_size, (size_t)n, now, &source_addr,
1360 local_auth, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001361 if (m >= 1)
Simon Kelleyb485ed92013-10-18 22:00:39 +01001362 {
1363 send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
1364 (char *)header, m, &source_addr, &dst_addr, if_index);
1365 daemon->auth_answer++;
1366 }
Simon Kelley824af852008-02-12 20:43:05 +00001367 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001368 else
Simon Kelley4820dce2012-12-18 18:30:30 +00001369#endif
Simon Kelley4f7b3042012-11-28 21:27:02 +00001370 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001371 int ad_reqd = do_bit;
1372 /* RFC 6840 5.7 */
1373 if (header->hb4 & HB4_AD)
1374 ad_reqd = 1;
1375
1376 m = answer_request(header, ((char *) header) + udp_size, (size_t)n,
1377 dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001378
1379 if (m >= 1)
1380 {
1381 send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
1382 (char *)header, m, &source_addr, &dst_addr, if_index);
1383 daemon->local_answer++;
1384 }
1385 else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
Simon Kelley613ad152014-02-25 23:02:28 +00001386 header, (size_t)n, now, NULL, ad_reqd, do_bit))
Simon Kelley4f7b3042012-11-28 21:27:02 +00001387 daemon->queries_forwarded++;
1388 else
1389 daemon->local_answer++;
1390 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001391}
1392
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001393#ifdef HAVE_DNSSEC
Simon Kelley7fa836e2014-02-10 20:11:24 +00001394static int tcp_key_recurse(time_t now, int status, struct dns_header *header, size_t n,
1395 int class, char *name, char *keyname, struct server *server, int *keycount)
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001396{
1397 /* Recurse up the key heirarchy */
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001398 int new_status;
Simon Kelley9a31b682015-12-15 10:20:39 +00001399 unsigned char *packet = NULL;
1400 size_t m;
1401 unsigned char *payload = NULL;
1402 struct dns_header *new_header = NULL;
1403 u16 *length = NULL;
1404 unsigned char c1, c2;
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001405
Simon Kelley9a31b682015-12-15 10:20:39 +00001406 while (1)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001407 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001408 /* limit the amount of work we do, to avoid cycling forever on loops in the DNS */
1409 if (--(*keycount) == 0)
1410 new_status = STAT_ABANDONED;
1411 else if (status == STAT_NEED_KEY)
1412 new_status = dnssec_validate_by_ds(now, header, n, name, keyname, class);
1413 else if (status == STAT_NEED_DS)
1414 new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
1415 else
1416 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 +00001417
Simon Kelley9a31b682015-12-15 10:20:39 +00001418 if (new_status != STAT_NEED_DS && new_status != STAT_NEED_KEY)
1419 break;
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001420
Simon Kelley9a31b682015-12-15 10:20:39 +00001421 /* Can't validate because we need a key/DS whose name now in keyname.
1422 Make query for same, and recurse to validate */
Simon Kelley7fa836e2014-02-10 20:11:24 +00001423 if (!packet)
Simon Kelley9a31b682015-12-15 10:20:39 +00001424 {
1425 packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
1426 payload = &packet[2];
1427 new_header = (struct dns_header *)payload;
1428 length = (u16 *)packet;
1429 }
1430
1431 if (!packet)
1432 {
1433 new_status = STAT_ABANDONED;
1434 break;
1435 }
1436
Simon Kelley7fa836e2014-02-10 20:11:24 +00001437 m = dnssec_generate_query(new_header, ((char *) new_header) + 65536, keyname, class,
Simon Kelleya77cec82015-05-08 16:25:38 +01001438 new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS, &server->addr, server->edns_pktsz);
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001439
Simon Kelley7fa836e2014-02-10 20:11:24 +00001440 *length = htons(m);
1441
1442 if (!read_write(server->tcpfd, packet, m + sizeof(u16), 0) ||
1443 !read_write(server->tcpfd, &c1, 1, 1) ||
1444 !read_write(server->tcpfd, &c2, 1, 1) ||
1445 !read_write(server->tcpfd, payload, (c1 << 8) | c2, 1))
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001446 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001447 new_status = STAT_ABANDONED;
1448 break;
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001449 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001450
1451 m = (c1 << 8) | c2;
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001452
Simon Kelley9a31b682015-12-15 10:20:39 +00001453 new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, keycount);
1454
1455 if (new_status != STAT_OK)
1456 break;
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001457 }
Simon Kelley9a31b682015-12-15 10:20:39 +00001458
1459 if (packet)
1460 free(packet);
1461
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001462 return new_status;
1463}
1464#endif
1465
1466
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001467/* The daemon forks before calling this: it should deal with one connection,
1468 blocking as neccessary, and then return. Note, need to be a bit careful
1469 about resources for debug mode, when the fork is suppressed: that's
1470 done by the caller. */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001471unsigned char *tcp_request(int confd, time_t now,
Simon Kelley4f7b3042012-11-28 21:27:02 +00001472 union mysockaddr *local_addr, struct in_addr netmask, int auth_dns)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001473{
Simon Kelley28866e92011-02-14 20:19:14 +00001474 size_t size = 0;
1475 int norebind = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001476#ifdef HAVE_AUTH
Simon Kelley19b16892013-10-20 10:19:39 +01001477 int local_auth = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001478#endif
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001479 int checking_disabled, do_bit, added_pheader = 0, have_pseudoheader = 0;
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001480 int check_subnet, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
Simon Kelleycdeda282006-03-16 20:16:06 +00001481 size_t m;
Simon Kelleyee86ce62012-12-07 11:54:46 +00001482 unsigned short qtype;
1483 unsigned int gotname;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001484 unsigned char c1, c2;
Simon Kelley4b5ea122013-04-22 10:18:26 +01001485 /* Max TCP packet + slop + size */
1486 unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
1487 unsigned char *payload = &packet[2];
1488 /* largest field in header is 16-bits, so this is still sufficiently aligned */
1489 struct dns_header *header = (struct dns_header *)payload;
1490 u16 *length = (u16 *)packet;
Simon Kelley3be34542004-09-11 19:12:13 +01001491 struct server *last_server;
Simon Kelley7de060b2011-08-26 17:24:52 +01001492 struct in_addr dst_addr_4;
1493 union mysockaddr peer_addr;
1494 socklen_t peer_len = sizeof(union mysockaddr);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001495 int query_count = 0;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001496 unsigned char *pheader;
Simon Kelley25cf5e32015-01-09 15:53:03 +00001497
Simon Kelley7de060b2011-08-26 17:24:52 +01001498 if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
1499 return packet;
Simon Kelleyc8a80482014-03-05 14:29:54 +00001500
1501 /* We can be configured to only accept queries from at-most-one-hop-away addresses. */
1502 if (option_bool(OPT_LOCAL_SERVICE))
1503 {
1504 struct addrlist *addr;
1505#ifdef HAVE_IPV6
1506 if (peer_addr.sa.sa_family == AF_INET6)
1507 {
1508 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1509 if ((addr->flags & ADDRLIST_IPV6) &&
1510 is_same_net6(&addr->addr.addr.addr6, &peer_addr.in6.sin6_addr, addr->prefixlen))
1511 break;
1512 }
1513 else
1514#endif
1515 {
1516 struct in_addr netmask;
1517 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1518 {
Richard Genoud15b1b7e2014-09-17 21:12:00 +01001519 netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
Simon Kelleyc8a80482014-03-05 14:29:54 +00001520 if (!(addr->flags & ADDRLIST_IPV6) &&
1521 is_same_net(addr->addr.addr.addr4, peer_addr.in.sin_addr, netmask))
1522 break;
1523 }
1524 }
1525 if (!addr)
1526 {
1527 my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
1528 return packet;
1529 }
1530 }
Simon Kelley7de060b2011-08-26 17:24:52 +01001531
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001532 while (1)
1533 {
Simon Kelley25cf5e32015-01-09 15:53:03 +00001534 if (query_count == TCP_MAX_QUERIES ||
1535 !packet ||
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001536 !read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
1537 !(size = c1 << 8 | c2) ||
Simon Kelley4b5ea122013-04-22 10:18:26 +01001538 !read_write(confd, payload, size, 1))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001539 return packet;
1540
Simon Kelley572b41e2011-02-18 18:11:18 +00001541 if (size < (int)sizeof(struct dns_header))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001542 continue;
1543
Simon Kelley25cf5e32015-01-09 15:53:03 +00001544 query_count++;
1545
1546 /* log_query gets called indirectly all over the place, so
1547 pass these in global variables - sorry. */
1548 daemon->log_display_id = ++daemon->log_id;
1549 daemon->log_source_addr = &peer_addr;
1550
Simon Kelleyed4c0762013-10-08 20:46:34 +01001551 check_subnet = 0;
1552
Simon Kelley28866e92011-02-14 20:19:14 +00001553 /* save state of "cd" flag in query */
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001554 if ((checking_disabled = header->hb4 & HB4_CD))
1555 no_cache_dnssec = 1;
Simon Kelley28866e92011-02-14 20:19:14 +00001556
Simon Kelley3be34542004-09-11 19:12:13 +01001557 if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001558 {
Simon Kelleyb485ed92013-10-18 22:00:39 +01001559#ifdef HAVE_AUTH
1560 struct auth_zone *zone;
1561#endif
Simon Kelley610e7822014-02-06 14:45:17 +00001562 char *types = querystr(auth_dns ? "auth" : "query", qtype);
Simon Kelley7de060b2011-08-26 17:24:52 +01001563
1564 if (peer_addr.sa.sa_family == AF_INET)
1565 log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
1566 (struct all_addr *)&peer_addr.in.sin_addr, types);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001567#ifdef HAVE_IPV6
Simon Kelley7de060b2011-08-26 17:24:52 +01001568 else
1569 log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
1570 (struct all_addr *)&peer_addr.in6.sin6_addr, types);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001571#endif
Simon Kelleyb485ed92013-10-18 22:00:39 +01001572
1573#ifdef HAVE_AUTH
1574 /* find queries for zones we're authoritative for, and answer them directly */
Simon Kelley3a3965a2015-08-09 17:45:06 +01001575 if (!auth_dns && !option_bool(OPT_LOCALISE))
Simon Kelley6008bdb2013-10-21 21:47:03 +01001576 for (zone = daemon->auth_zones; zone; zone = zone->next)
1577 if (in_zone(zone, daemon->namebuff, NULL))
1578 {
1579 auth_dns = 1;
1580 local_auth = 1;
1581 break;
1582 }
Simon Kelleyb485ed92013-10-18 22:00:39 +01001583#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001584 }
1585
Simon Kelley7de060b2011-08-26 17:24:52 +01001586 if (local_addr->sa.sa_family == AF_INET)
1587 dst_addr_4 = local_addr->in.sin_addr;
1588 else
1589 dst_addr_4.s_addr = 0;
1590
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001591 do_bit = 0;
1592
Simon Kelley5bb88f02015-12-21 16:23:47 +00001593 if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL, NULL))
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001594 {
1595 unsigned short flags;
1596
1597 have_pseudoheader = 1;
1598 pheader += 4; /* udp_size, ext_rcode */
1599 GETSHORT(flags, pheader);
1600
1601 if (flags & 0x8000)
Simon Kelley5bb88f02015-12-21 16:23:47 +00001602 do_bit = 1; /* do bit */
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001603 }
1604
Simon Kelley4820dce2012-12-18 18:30:30 +00001605#ifdef HAVE_AUTH
Simon Kelley4f7b3042012-11-28 21:27:02 +00001606 if (auth_dns)
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001607 m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr,
1608 local_auth, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001609 else
Simon Kelley4820dce2012-12-18 18:30:30 +00001610#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001611 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001612 int ad_reqd = do_bit;
1613 /* RFC 6840 5.7 */
1614 if (header->hb4 & HB4_AD)
1615 ad_reqd = 1;
1616
1617 /* m > 0 if answered from cache */
1618 m = answer_request(header, ((char *) header) + 65536, (size_t)size,
1619 dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001620
Simon Kelley4f7b3042012-11-28 21:27:02 +00001621 /* Do this by steam now we're not in the select() loop */
Simon Kelleyb842bc92015-07-12 21:09:11 +01001622 check_log_writer(1);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001623
1624 if (m == 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001625 {
Simon Kelley4f7b3042012-11-28 21:27:02 +00001626 unsigned int flags = 0;
1627 struct all_addr *addrp = NULL;
1628 int type = 0;
1629 char *domain = NULL;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001630
Simon Kelley4f7b3042012-11-28 21:27:02 +00001631 if (option_bool(OPT_ADD_MAC))
1632 size = add_mac(header, size, ((char *) header) + 65536, &peer_addr);
Simon Kelleyed4c0762013-10-08 20:46:34 +01001633
1634 if (option_bool(OPT_CLIENT_SUBNET))
1635 {
1636 size_t new = add_source_addr(header, size, ((char *) header) + 65536, &peer_addr);
1637 if (size != new)
1638 {
1639 size = new;
1640 check_subnet = 1;
1641 }
1642 }
1643
Simon Kelley4f7b3042012-11-28 21:27:02 +00001644 if (gotname)
1645 flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
1646
1647 if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server)
1648 last_server = daemon->servers;
1649 else
1650 last_server = daemon->last_server;
1651
1652 if (!flags && last_server)
1653 {
1654 struct server *firstsendto = NULL;
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001655#ifdef HAVE_DNSSEC
Simon Kelley703c7ff2014-01-25 23:46:23 +00001656 unsigned char *newhash, hash[HASH_SIZE];
Simon Kelley63758382014-04-16 22:20:55 +01001657 if ((newhash = hash_questions(header, (unsigned int)size, daemon->namebuff)))
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001658 memcpy(hash, newhash, HASH_SIZE);
Tomas Hozzab37f8b92014-03-25 20:52:28 +00001659 else
1660 memset(hash, 0, HASH_SIZE);
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001661#else
Simon Kelley4f7b3042012-11-28 21:27:02 +00001662 unsigned int crc = questions_crc(header, (unsigned int)size, daemon->namebuff);
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001663#endif
Simon Kelley4f7b3042012-11-28 21:27:02 +00001664 /* Loop round available servers until we succeed in connecting to one.
1665 Note that this code subtley ensures that consecutive queries on this connection
1666 which can go to the same server, do so. */
1667 while (1)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001668 {
Simon Kelley4f7b3042012-11-28 21:27:02 +00001669 if (!firstsendto)
1670 firstsendto = last_server;
1671 else
1672 {
1673 if (!(last_server = last_server->next))
1674 last_server = daemon->servers;
1675
1676 if (last_server == firstsendto)
1677 break;
1678 }
1679
1680 /* server for wrong domain */
1681 if (type != (last_server->flags & SERV_TYPE) ||
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01001682 (type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)) ||
1683 (last_server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
Simon Kelley7de060b2011-08-26 17:24:52 +01001684 continue;
1685
Simon Kelley4f7b3042012-11-28 21:27:02 +00001686 if (last_server->tcpfd == -1)
1687 {
1688 if ((last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
1689 continue;
1690
Karl Vogele9828b62014-10-03 21:45:15 +01001691#ifdef HAVE_CONNTRACK
1692 /* Copy connection mark of incoming query to outgoing connection. */
1693 if (option_bool(OPT_CONNTRACK))
1694 {
1695 unsigned int mark;
1696 struct all_addr local;
1697#ifdef HAVE_IPV6
1698 if (local_addr->sa.sa_family == AF_INET6)
1699 local.addr.addr6 = local_addr->in6.sin6_addr;
1700 else
1701#endif
1702 local.addr.addr4 = local_addr->in.sin_addr;
1703
1704 if (get_incoming_mark(&peer_addr, &local, 1, &mark))
1705 setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
1706 }
1707#endif
1708
Simon Kelley4f7b3042012-11-28 21:27:02 +00001709 if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 1) ||
1710 connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1))
1711 {
1712 close(last_server->tcpfd);
1713 last_server->tcpfd = -1;
1714 continue;
1715 }
1716
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001717#ifdef HAVE_DNSSEC
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001718 added_pheader = 0;
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001719 if (option_bool(OPT_DNSSEC_VALID))
1720 {
Simon Kelley613ad152014-02-25 23:02:28 +00001721 size_t new_size = add_do_bit(header, size, ((char *) header) + 65536);
1722
Simon Kelley2ecd9bd2014-02-13 16:42:02 +00001723 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
1724 this allows it to select auth servers when one is returning bad data. */
1725 if (option_bool(OPT_DNSSEC_DEBUG))
1726 header->hb4 |= HB4_CD;
Simon Kelley613ad152014-02-25 23:02:28 +00001727
1728 if (size != new_size)
1729 added_pheader = 1;
1730
1731 size = new_size;
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001732 }
1733#endif
Simon Kelley4f7b3042012-11-28 21:27:02 +00001734 }
1735
Simon Kelley4b5ea122013-04-22 10:18:26 +01001736 *length = htons(size);
Simon Kelley1fc02682014-04-29 12:30:18 +01001737
1738 /* get query name again for logging - may have been overwritten */
1739 if (!(gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
1740 strcpy(daemon->namebuff, "query");
Simon Kelley4f7b3042012-11-28 21:27:02 +00001741
Simon Kelley4b5ea122013-04-22 10:18:26 +01001742 if (!read_write(last_server->tcpfd, packet, size + sizeof(u16), 0) ||
Simon Kelley4f7b3042012-11-28 21:27:02 +00001743 !read_write(last_server->tcpfd, &c1, 1, 1) ||
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001744 !read_write(last_server->tcpfd, &c2, 1, 1) ||
1745 !read_write(last_server->tcpfd, payload, (c1 << 8) | c2, 1))
Simon Kelley7de060b2011-08-26 17:24:52 +01001746 {
1747 close(last_server->tcpfd);
1748 last_server->tcpfd = -1;
1749 continue;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001750 }
1751
1752 m = (c1 << 8) | c2;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001753
Simon Kelley4f7b3042012-11-28 21:27:02 +00001754 if (last_server->addr.sa.sa_family == AF_INET)
1755 log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
1756 (struct all_addr *)&last_server->addr.in.sin_addr, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001757#ifdef HAVE_IPV6
Simon Kelley4f7b3042012-11-28 21:27:02 +00001758 else
1759 log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
1760 (struct all_addr *)&last_server->addr.in6.sin6_addr, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001761#endif
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001762
1763#ifdef HAVE_DNSSEC
1764 if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled)
1765 {
Simon Kelley7fa836e2014-02-10 20:11:24 +00001766 int keycount = DNSSEC_WORK; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
Simon Kelley9a31b682015-12-15 10:20:39 +00001767 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 +01001768 char *result, *domain = "result";
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001769
Simon Kelley9a31b682015-12-15 10:20:39 +00001770 if (status == STAT_ABANDONED)
Simon Kelley150162b2015-03-27 09:58:26 +00001771 {
1772 result = "ABANDONED";
1773 status = STAT_BOGUS;
1774 }
Simon Kelley7fa836e2014-02-10 20:11:24 +00001775 else
1776 result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
Simon Kelleye66b4df2015-04-28 20:45:57 +01001777
1778 if (status == STAT_BOGUS && extract_request(header, m, daemon->namebuff, NULL))
1779 domain = daemon->namebuff;
Simon Kelley554b5802015-04-17 22:50:20 +01001780
1781 log_query(F_KEYTAG | F_SECSTAT, domain, NULL, result);
Simon Kelley7fa836e2014-02-10 20:11:24 +00001782
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001783 if (status == STAT_BOGUS)
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001784 {
1785 no_cache_dnssec = 1;
1786 bogusanswer = 1;
1787 }
1788
Simon Kelley7d7b7b32014-01-08 15:53:35 +00001789 if (status == STAT_SECURE)
1790 cache_secure = 1;
1791 }
1792#endif
1793
1794 /* restore CD bit to the value in the query */
1795 if (checking_disabled)
1796 header->hb4 |= HB4_CD;
1797 else
1798 header->hb4 &= ~HB4_CD;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001799
1800 /* There's no point in updating the cache, since this process will exit and
1801 lose the information after a few queries. We make this call for the alias and
1802 bogus-nxdomain side-effects. */
1803 /* If the crc of the question section doesn't match the crc we sent, then
1804 someone might be attempting to insert bogus values into the cache by
1805 sending replies containing questions and bogus answers. */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001806#ifdef HAVE_DNSSEC
1807 newhash = hash_questions(header, (unsigned int)m, daemon->namebuff);
1808 if (!newhash || memcmp(hash, newhash, HASH_SIZE) != 0)
Simon Kelley703c7ff2014-01-25 23:46:23 +00001809 {
1810 m = 0;
1811 break;
1812 }
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001813#else
1814 if (crc != questions_crc(header, (unsigned int)m, daemon->namebuff))
Simon Kelley703c7ff2014-01-25 23:46:23 +00001815 {
1816 m = 0;
1817 break;
1818 }
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001819#endif
1820
1821 m = process_reply(header, now, last_server, (unsigned int)m,
Simon Kelleye66b4df2015-04-28 20:45:57 +01001822 option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001823 ad_reqd, do_bit, added_pheader, check_subnet, &peer_addr);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001824
1825 break;
1826 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001827 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00001828
1829 /* In case of local answer or no connections made. */
1830 if (m == 0)
1831 m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001832 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001833 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00001834
Simon Kelleyb842bc92015-07-12 21:09:11 +01001835 check_log_writer(1);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001836
Simon Kelley4b5ea122013-04-22 10:18:26 +01001837 *length = htons(m);
1838
1839 if (m == 0 || !read_write(confd, packet, m + sizeof(u16), 0))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001840 return packet;
1841 }
1842}
1843
Simon Kelley16972692006-10-16 20:04:18 +01001844static struct frec *allocate_frec(time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001845{
Simon Kelley16972692006-10-16 20:04:18 +01001846 struct frec *f;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001847
Simon Kelley5aabfc72007-08-29 11:24:47 +01001848 if ((f = (struct frec *)whine_malloc(sizeof(struct frec))))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001849 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001850 f->next = daemon->frec_list;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001851 f->time = now;
Simon Kelley832af0b2007-01-21 20:01:28 +00001852 f->sentto = NULL;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001853 f->rfd4 = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +00001854 f->flags = 0;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001855#ifdef HAVE_IPV6
1856 f->rfd6 = NULL;
1857#endif
Simon Kelley3a237152013-12-12 12:15:50 +00001858#ifdef HAVE_DNSSEC
Simon Kelley97bc7982014-01-31 10:19:52 +00001859 f->dependent = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00001860 f->blocking_query = NULL;
Simon Kelley4619d942014-01-16 19:53:06 +00001861 f->stash = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00001862#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +01001863 daemon->frec_list = f;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001864 }
Simon Kelley16972692006-10-16 20:04:18 +01001865
1866 return f;
1867}
1868
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01001869struct randfd *allocate_rfd(int family)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001870{
1871 static int finger = 0;
1872 int i;
1873
1874 /* limit the number of sockets we have open to avoid starvation of
1875 (eg) TFTP. Once we have a reasonable number, randomness should be OK */
1876
1877 for (i = 0; i < RANDOM_SOCKS; i++)
Simon Kelley9009d742008-11-14 20:04:27 +00001878 if (daemon->randomsocks[i].refcount == 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001879 {
Simon Kelley9009d742008-11-14 20:04:27 +00001880 if ((daemon->randomsocks[i].fd = random_sock(family)) == -1)
1881 break;
1882
Simon Kelley1a6bca82008-07-11 11:11:42 +01001883 daemon->randomsocks[i].refcount = 1;
1884 daemon->randomsocks[i].family = family;
1885 return &daemon->randomsocks[i];
1886 }
1887
Simon Kelley9009d742008-11-14 20:04:27 +00001888 /* No free ones or cannot get new socket, grab an existing one */
Simon Kelley1a6bca82008-07-11 11:11:42 +01001889 for (i = 0; i < RANDOM_SOCKS; i++)
1890 {
1891 int j = (i+finger) % RANDOM_SOCKS;
Simon Kelley9009d742008-11-14 20:04:27 +00001892 if (daemon->randomsocks[j].refcount != 0 &&
1893 daemon->randomsocks[j].family == family &&
1894 daemon->randomsocks[j].refcount != 0xffff)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001895 {
1896 finger = j;
1897 daemon->randomsocks[j].refcount++;
1898 return &daemon->randomsocks[j];
1899 }
1900 }
1901
1902 return NULL; /* doom */
1903}
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01001904
1905void free_rfd(struct randfd *rfd)
1906{
1907 if (rfd && --(rfd->refcount) == 0)
1908 close(rfd->fd);
1909}
1910
Simon Kelley1a6bca82008-07-11 11:11:42 +01001911static void free_frec(struct frec *f)
1912{
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01001913 free_rfd(f->rfd4);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001914 f->rfd4 = NULL;
1915 f->sentto = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +00001916 f->flags = 0;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001917
1918#ifdef HAVE_IPV6
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01001919 free_rfd(f->rfd6);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001920 f->rfd6 = NULL;
1921#endif
Simon Kelley3a237152013-12-12 12:15:50 +00001922
1923#ifdef HAVE_DNSSEC
1924 if (f->stash)
Simon Kelley0fc2f312014-01-08 10:26:58 +00001925 {
1926 blockdata_free(f->stash);
1927 f->stash = NULL;
1928 }
Simon Kelley3a237152013-12-12 12:15:50 +00001929
1930 /* Anything we're waiting on is pointless now, too */
1931 if (f->blocking_query)
1932 free_frec(f->blocking_query);
1933 f->blocking_query = NULL;
Simon Kelley39048ad2014-01-21 17:33:58 +00001934 f->dependent = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00001935#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +01001936}
1937
Simon Kelley16972692006-10-16 20:04:18 +01001938/* if wait==NULL return a free or older than TIMEOUT record.
1939 else return *wait zero if one available, or *wait is delay to
Simon Kelley1a6bca82008-07-11 11:11:42 +01001940 when the oldest in-use record will expire. Impose an absolute
Simon Kelley3a237152013-12-12 12:15:50 +00001941 limit of 4*TIMEOUT before we wipe things (for random sockets).
1942 If force is set, always return a result, even if we have
1943 to allocate above the limit. */
1944struct frec *get_new_frec(time_t now, int *wait, int force)
Simon Kelley16972692006-10-16 20:04:18 +01001945{
Simon Kelley1a6bca82008-07-11 11:11:42 +01001946 struct frec *f, *oldest, *target;
Simon Kelley16972692006-10-16 20:04:18 +01001947 int count;
1948
1949 if (wait)
1950 *wait = 0;
1951
Simon Kelley1a6bca82008-07-11 11:11:42 +01001952 for (f = daemon->frec_list, oldest = NULL, target = NULL, count = 0; f; f = f->next, count++)
Simon Kelley832af0b2007-01-21 20:01:28 +00001953 if (!f->sentto)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001954 target = f;
1955 else
Simon Kelley16972692006-10-16 20:04:18 +01001956 {
Simon Kelley9a31b682015-12-15 10:20:39 +00001957#ifdef HAVE_DNSSEC
1958 /* Don't free DNSSEC sub-queries here, as we may end up with
1959 dangling references to them. They'll go when their "real" query
1960 is freed. */
1961 if (!f->dependent)
1962#endif
1963 {
1964 if (difftime(now, f->time) >= 4*TIMEOUT)
1965 {
1966 free_frec(f);
1967 target = f;
1968 }
1969
1970
1971 if (!oldest || difftime(f->time, oldest->time) <= 0)
1972 oldest = f;
1973 }
Simon Kelley16972692006-10-16 20:04:18 +01001974 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001975
1976 if (target)
1977 {
1978 target->time = now;
1979 return target;
1980 }
Simon Kelley16972692006-10-16 20:04:18 +01001981
1982 /* can't find empty one, use oldest if there is one
1983 and it's older than timeout */
1984 if (oldest && ((int)difftime(now, oldest->time)) >= TIMEOUT)
1985 {
1986 /* keep stuff for twice timeout if we can by allocating a new
1987 record instead */
1988 if (difftime(now, oldest->time) < 2*TIMEOUT &&
1989 count <= daemon->ftabsize &&
1990 (f = allocate_frec(now)))
1991 return f;
1992
1993 if (!wait)
1994 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001995 free_frec(oldest);
Simon Kelley16972692006-10-16 20:04:18 +01001996 oldest->time = now;
1997 }
1998 return oldest;
1999 }
2000
2001 /* none available, calculate time 'till oldest record expires */
Simon Kelley3a237152013-12-12 12:15:50 +00002002 if (!force && count > daemon->ftabsize)
Simon Kelley16972692006-10-16 20:04:18 +01002003 {
Marcelo Salhab Brogliato0da5e892013-05-31 11:49:06 +01002004 static time_t last_log = 0;
2005
Simon Kelley16972692006-10-16 20:04:18 +01002006 if (oldest && wait)
2007 *wait = oldest->time + (time_t)TIMEOUT - now;
Marcelo Salhab Brogliato0da5e892013-05-31 11:49:06 +01002008
2009 if ((int)difftime(now, last_log) > 5)
2010 {
2011 last_log = now;
2012 my_syslog(LOG_WARNING, _("Maximum number of concurrent DNS queries reached (max: %d)"), daemon->ftabsize);
2013 }
2014
Simon Kelley16972692006-10-16 20:04:18 +01002015 return NULL;
2016 }
2017
2018 if (!(f = allocate_frec(now)) && wait)
2019 /* wait one second on malloc failure */
2020 *wait = 1;
2021
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002022 return f; /* OK if malloc fails and this is NULL */
2023}
2024
Simon Kelley832af0b2007-01-21 20:01:28 +00002025/* crc is all-ones if not known. */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002026static struct frec *lookup_frec(unsigned short id, void *hash)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002027{
2028 struct frec *f;
2029
Simon Kelley1a6bca82008-07-11 11:11:42 +01002030 for(f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00002031 if (f->sentto && f->new_id == id &&
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002032 (!hash || memcmp(hash, f->hash, HASH_SIZE) == 0))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002033 return f;
2034
2035 return NULL;
2036}
2037
2038static struct frec *lookup_frec_by_sender(unsigned short id,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01002039 union mysockaddr *addr,
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002040 void *hash)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002041{
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002042 struct frec *f;
2043
Simon Kelley1a6bca82008-07-11 11:11:42 +01002044 for(f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00002045 if (f->sentto &&
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002046 f->orig_id == id &&
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002047 memcmp(hash, f->hash, HASH_SIZE) == 0 &&
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002048 sockaddr_isequal(&f->source, addr))
2049 return f;
2050
2051 return NULL;
2052}
Simon Kelley47a95162014-07-08 22:22:02 +01002053
2054/* Send query packet again, if we can. */
2055void resend_query()
2056{
2057 if (daemon->srv_save)
2058 {
2059 int fd;
2060
2061 if (daemon->srv_save->sfd)
2062 fd = daemon->srv_save->sfd->fd;
2063 else if (daemon->rfd_save && daemon->rfd_save->refcount != 0)
2064 fd = daemon->rfd_save->fd;
2065 else
2066 return;
2067
Simon Kelleyff841eb2015-03-11 21:36:30 +00002068 while(retry_send(sendto(fd, daemon->packet, daemon->packet_len, 0,
2069 &daemon->srv_save->addr.sa,
2070 sa_len(&daemon->srv_save->addr))));
Simon Kelley47a95162014-07-08 22:22:02 +01002071 }
2072}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002073
Simon Kelley849a8352006-06-09 21:02:31 +01002074/* A server record is going away, remove references to it */
Simon Kelley5aabfc72007-08-29 11:24:47 +01002075void server_gone(struct server *server)
Simon Kelley849a8352006-06-09 21:02:31 +01002076{
2077 struct frec *f;
2078
Simon Kelley1a6bca82008-07-11 11:11:42 +01002079 for (f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00002080 if (f->sentto && f->sentto == server)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002081 free_frec(f);
Simon Kelley849a8352006-06-09 21:02:31 +01002082
2083 if (daemon->last_server == server)
2084 daemon->last_server = NULL;
2085
2086 if (daemon->srv_save == server)
2087 daemon->srv_save = NULL;
2088}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002089
Simon Kelley316e2732010-01-22 20:16:09 +00002090/* return unique random ids. */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002091static unsigned short get_id(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002092{
2093 unsigned short ret = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +00002094
Simon Kelley316e2732010-01-22 20:16:09 +00002095 do
Simon Kelley832af0b2007-01-21 20:01:28 +00002096 ret = rand16();
Simon Kelley8a9be9e2014-01-25 23:17:21 +00002097 while (lookup_frec(ret, NULL));
Simon Kelley832af0b2007-01-21 20:01:28 +00002098
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002099 return ret;
2100}
2101
2102
2103
2104
2105