blob: 5bda32cf1f7a547997be07f8feba131daeeda873 [file] [log] [blame]
Simon Kelley9009d742008-11-14 20:04:27 +00001/* dnsmasq is Copyright (c) 2000-2008 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
13 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 Kelley832af0b2007-01-21 20:01:28 +000019static struct frec *lookup_frec(unsigned short id, unsigned int crc);
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,
22 unsigned int crc);
Simon Kelley832af0b2007-01-21 20:01:28 +000023static unsigned short get_id(int force, unsigned short force_id, unsigned int crc);
Simon Kelley1a6bca82008-07-11 11:11:42 +010024static void free_frec(struct frec *f);
25static struct randfd *allocate_rfd(int family);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000026
Simon Kelley824af852008-02-12 20:43:05 +000027/* Send a UDP packet with its source address set as "source"
Simon Kelley44a2a312004-03-10 20:04:35 +000028 unless nowild is true, when we just send it with the kernel default */
Simon Kelleycdeda282006-03-16 20:16:06 +000029static void send_from(int fd, int nowild, char *packet, size_t len,
Simon Kelleydfa666f2004-08-02 18:27:27 +010030 union mysockaddr *to, struct all_addr *source,
31 unsigned int iface)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000032{
Simon Kelley44a2a312004-03-10 20:04:35 +000033 struct msghdr msg;
34 struct iovec iov[1];
Simon Kelley44a2a312004-03-10 20:04:35 +000035 union {
36 struct cmsghdr align; /* this ensures alignment */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010037#if defined(HAVE_LINUX_NETWORK)
Simon Kelley44a2a312004-03-10 20:04:35 +000038 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
39#elif defined(IP_SENDSRCADDR)
40 char control[CMSG_SPACE(sizeof(struct in_addr))];
41#endif
42#ifdef HAVE_IPV6
43 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
44#endif
45 } control_u;
Simon Kelleyfeba5c12004-07-27 20:28:58 +010046
Simon Kelley44a2a312004-03-10 20:04:35 +000047 iov[0].iov_base = packet;
48 iov[0].iov_len = len;
49
Simon Kelleyfeba5c12004-07-27 20:28:58 +010050 msg.msg_control = NULL;
51 msg.msg_controllen = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +000052 msg.msg_flags = 0;
53 msg.msg_name = to;
54 msg.msg_namelen = sa_len(to);
55 msg.msg_iov = iov;
56 msg.msg_iovlen = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +010057
Simon Kelley26128d22004-11-14 16:43:54 +000058 if (!nowild)
Simon Kelleyfeba5c12004-07-27 20:28:58 +010059 {
Simon Kelley26128d22004-11-14 16:43:54 +000060 struct cmsghdr *cmptr;
Simon Kelleyfeba5c12004-07-27 20:28:58 +010061 msg.msg_control = &control_u;
62 msg.msg_controllen = sizeof(control_u);
Simon Kelley26128d22004-11-14 16:43:54 +000063 cmptr = CMSG_FIRSTHDR(&msg);
Simon Kelley44a2a312004-03-10 20:04:35 +000064
Simon Kelley26128d22004-11-14 16:43:54 +000065 if (to->sa.sa_family == AF_INET)
66 {
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010067#if defined(HAVE_LINUX_NETWORK)
Simon Kelley26128d22004-11-14 16:43:54 +000068 struct in_pktinfo *pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
69 pkt->ipi_ifindex = 0;
70 pkt->ipi_spec_dst = source->addr.addr4;
71 msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
72 cmptr->cmsg_level = SOL_IP;
73 cmptr->cmsg_type = IP_PKTINFO;
74#elif defined(IP_SENDSRCADDR)
75 struct in_addr *a = (struct in_addr *)CMSG_DATA(cmptr);
76 *a = source->addr.addr4;
77 msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
78 cmptr->cmsg_level = IPPROTO_IP;
79 cmptr->cmsg_type = IP_SENDSRCADDR;
Simon Kelley44a2a312004-03-10 20:04:35 +000080#endif
Simon Kelley26128d22004-11-14 16:43:54 +000081 }
Simon Kelley26128d22004-11-14 16:43:54 +000082 else
Simon Kelleyb8187c82005-11-26 21:46:27 +000083#ifdef HAVE_IPV6
Simon Kelley26128d22004-11-14 16:43:54 +000084 {
85 struct in6_pktinfo *pkt = (struct in6_pktinfo *)CMSG_DATA(cmptr);
86 pkt->ipi6_ifindex = iface; /* Need iface for IPv6 to handle link-local addrs */
87 pkt->ipi6_addr = source->addr.addr6;
88 msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
89 cmptr->cmsg_type = IPV6_PKTINFO;
90 cmptr->cmsg_level = IPV6_LEVEL;
91 }
Simon Kelley3d8df262005-08-29 12:19:27 +010092#else
93 iface = 0; /* eliminate warning */
Simon Kelley26128d22004-11-14 16:43:54 +000094#endif
95 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +010096
Simon Kelleyfd9fa482004-10-21 20:24:00 +010097 retry:
98 if (sendmsg(fd, &msg, 0) == -1)
Simon Kelleyfeba5c12004-07-27 20:28:58 +010099 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100100 /* certain Linux kernels seem to object to setting the source address in the IPv6 stack
101 by returning EINVAL from sendmsg. In that case, try again without setting the
102 source address, since it will nearly alway be correct anyway. IPv6 stinks. */
103 if (errno == EINVAL && msg.msg_controllen)
104 {
105 msg.msg_controllen = 0;
106 goto retry;
107 }
108 if (retry_send())
109 goto retry;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100110 }
Simon Kelley44a2a312004-03-10 20:04:35 +0000111}
112
Simon Kelley5aabfc72007-08-29 11:24:47 +0100113static unsigned short search_servers(time_t now, struct all_addr **addrpp,
Simon Kelley36717ee2004-09-20 19:20:58 +0100114 unsigned short qtype, char *qdomain, int *type, char **domain)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100115
116{
117 /* If the query ends in the domain in one of our servers, set
118 domain to point to that name. We find the largest match to allow both
119 domain.org and sub.domain.org to exist. */
120
121 unsigned int namelen = strlen(qdomain);
122 unsigned int matchlen = 0;
123 struct server *serv;
124 unsigned short flags = 0;
125
Simon Kelley3be34542004-09-11 19:12:13 +0100126 for (serv = daemon->servers; serv; serv=serv->next)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100127 /* domain matches take priority over NODOTS matches */
Simon Kelley3d8df262005-08-29 12:19:27 +0100128 if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.') && namelen != 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100129 {
130 unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
131 *type = SERV_FOR_NODOTS;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100132 if (serv->flags & SERV_NO_ADDR)
Simon Kelley36717ee2004-09-20 19:20:58 +0100133 flags = F_NXDOMAIN;
134 else if (serv->flags & SERV_LITERAL_ADDRESS)
135 {
136 if (sflag & qtype)
137 {
138 flags = sflag;
139 if (serv->addr.sa.sa_family == AF_INET)
140 *addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100141#ifdef HAVE_IPV6
Simon Kelley36717ee2004-09-20 19:20:58 +0100142 else
143 *addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100144#endif
Simon Kelley36717ee2004-09-20 19:20:58 +0100145 }
Simon Kelley824af852008-02-12 20:43:05 +0000146 else if (!flags || (flags & F_NXDOMAIN))
Simon Kelley36717ee2004-09-20 19:20:58 +0100147 flags = F_NOERR;
148 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100149 }
150 else if (serv->flags & SERV_HAS_DOMAIN)
151 {
152 unsigned int domainlen = strlen(serv->domain);
Simon Kelleyb8187c82005-11-26 21:46:27 +0000153 char *matchstart = qdomain + namelen - domainlen;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100154 if (namelen >= domainlen &&
Simon Kelleyb8187c82005-11-26 21:46:27 +0000155 hostname_isequal(matchstart, serv->domain) &&
156 domainlen >= matchlen &&
Simon Kelleycdeda282006-03-16 20:16:06 +0000157 (domainlen == 0 || namelen == domainlen || *(serv->domain) == '.' || *(matchstart-1) == '.' ))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100158 {
159 unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
160 *type = SERV_HAS_DOMAIN;
161 *domain = serv->domain;
162 matchlen = domainlen;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100163 if (serv->flags & SERV_NO_ADDR)
Simon Kelley36717ee2004-09-20 19:20:58 +0100164 flags = F_NXDOMAIN;
165 else if (serv->flags & SERV_LITERAL_ADDRESS)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100166 {
Simon Kelley824af852008-02-12 20:43:05 +0000167 if (sflag & qtype)
Simon Kelley36717ee2004-09-20 19:20:58 +0100168 {
Simon Kelley824af852008-02-12 20:43:05 +0000169 flags = sflag;
Simon Kelley36717ee2004-09-20 19:20:58 +0100170 if (serv->addr.sa.sa_family == AF_INET)
171 *addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100172#ifdef HAVE_IPV6
Simon Kelley36717ee2004-09-20 19:20:58 +0100173 else
174 *addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100175#endif
Simon Kelley36717ee2004-09-20 19:20:58 +0100176 }
Simon Kelley824af852008-02-12 20:43:05 +0000177 else if (!flags || (flags & F_NXDOMAIN))
Simon Kelley36717ee2004-09-20 19:20:58 +0100178 flags = F_NOERR;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100179 }
180 }
181 }
182
Simon Kelley824af852008-02-12 20:43:05 +0000183 if (flags == 0 && !(qtype & F_BIGNAME) &&
184 (daemon->options & OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
185 /* don't forward simple names, make exception for NS queries and empty name. */
Simon Kelley36717ee2004-09-20 19:20:58 +0100186 flags = F_NXDOMAIN;
187
Simon Kelley5aabfc72007-08-29 11:24:47 +0100188 if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now))
Simon Kelleyc1bb8502004-08-11 18:40:17 +0100189 flags = F_NOERR;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100190
Simon Kelley824af852008-02-12 20:43:05 +0000191 if (flags)
192 {
193 int logflags = 0;
194
195 if (flags == F_NXDOMAIN || flags == F_NOERR)
196 logflags = F_NEG | qtype;
197
Simon Kelley1a6bca82008-07-11 11:11:42 +0100198 log_query(logflags | flags | F_CONFIG | F_FORWARD, qdomain, *addrpp, NULL);
Simon Kelley824af852008-02-12 20:43:05 +0000199 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100200
201 return flags;
202}
Simon Kelley44a2a312004-03-10 20:04:35 +0000203
Simon Kelley824af852008-02-12 20:43:05 +0000204static int forward_query(int udpfd, union mysockaddr *udpaddr,
205 struct all_addr *dst_addr, unsigned int dst_iface,
206 HEADER *header, size_t plen, time_t now, struct frec *forward)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000207{
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000208 char *domain = NULL;
Simon Kelley0a852542005-03-23 20:28:59 +0000209 int type = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000210 struct all_addr *addrp = NULL;
Simon Kelleycdeda282006-03-16 20:16:06 +0000211 unsigned int crc = questions_crc(header, plen, daemon->namebuff);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000212 unsigned short flags = 0;
Simon Kelleycdeda282006-03-16 20:16:06 +0000213 unsigned short gotname = extract_request(header, plen, daemon->namebuff, NULL);
Simon Kelleyde379512004-06-22 20:23:33 +0100214 struct server *start = NULL;
Simon Kelley3d8df262005-08-29 12:19:27 +0100215
216 /* may be no servers available. */
217 if (!daemon->servers)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000218 forward = NULL;
Simon Kelleyb8187c82005-11-26 21:46:27 +0000219 else if (forward || (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, crc)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000220 {
Simon Kelleyde379512004-06-22 20:23:33 +0100221 /* retry on existing query, send to all available servers */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000222 domain = forward->sentto->domain;
Simon Kelley824af852008-02-12 20:43:05 +0000223 forward->sentto->failed_queries++;
Simon Kelley3be34542004-09-11 19:12:13 +0100224 if (!(daemon->options & OPT_ORDER))
Simon Kelleyde379512004-06-22 20:23:33 +0100225 {
Simon Kelley0a852542005-03-23 20:28:59 +0000226 forward->forwardall = 1;
Simon Kelley3be34542004-09-11 19:12:13 +0100227 daemon->last_server = NULL;
Simon Kelleyde379512004-06-22 20:23:33 +0100228 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000229 type = forward->sentto->flags & SERV_TYPE;
Simon Kelleyde379512004-06-22 20:23:33 +0100230 if (!(start = forward->sentto->next))
Simon Kelley3be34542004-09-11 19:12:13 +0100231 start = daemon->servers; /* at end of list, recycle */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000232 header->id = htons(forward->new_id);
233 }
234 else
235 {
236 if (gotname)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100237 flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000238
Simon Kelley5aabfc72007-08-29 11:24:47 +0100239 if (!flags && !(forward = get_new_frec(now, NULL)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100240 /* table full - server failure. */
241 flags = F_NEG;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000242
243 if (forward)
244 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000245 /* force unchanging id for signed packets */
246 int is_sign;
247 find_pseudoheader(header, plen, NULL, NULL, &is_sign);
248
Simon Kelley0a852542005-03-23 20:28:59 +0000249 forward->source = *udpaddr;
250 forward->dest = *dst_addr;
251 forward->iface = dst_iface;
Simon Kelley0a852542005-03-23 20:28:59 +0000252 forward->orig_id = ntohs(header->id);
Simon Kelley832af0b2007-01-21 20:01:28 +0000253 forward->new_id = get_id(is_sign, forward->orig_id, crc);
254 forward->fd = udpfd;
Simon Kelley0a852542005-03-23 20:28:59 +0000255 forward->crc = crc;
256 forward->forwardall = 0;
257 header->id = htons(forward->new_id);
258
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000259 /* In strict_order mode, or when using domain specific servers
260 always try servers in the order specified in resolv.conf,
261 otherwise, use the one last known to work. */
262
Simon Kelley3be34542004-09-11 19:12:13 +0100263 if (type != 0 || (daemon->options & OPT_ORDER))
264 start = daemon->servers;
265 else if (!(start = daemon->last_server))
Simon Kelleyde379512004-06-22 20:23:33 +0100266 {
Simon Kelley3be34542004-09-11 19:12:13 +0100267 start = daemon->servers;
Simon Kelley0a852542005-03-23 20:28:59 +0000268 forward->forwardall = 1;
Simon Kelleyde379512004-06-22 20:23:33 +0100269 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000270 }
271 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100272
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000273 /* check for send errors here (no route to host)
274 if we fail to send to all nameservers, send back an error
275 packet straight away (helps modem users when offline) */
276
277 if (!flags && forward)
278 {
Simon Kelleyde379512004-06-22 20:23:33 +0100279 struct server *firstsentto = start;
280 int forwarded = 0;
281
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000282 while (1)
283 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000284 /* only send to servers dealing with our domain.
285 domain may be NULL, in which case server->domain
286 must be NULL also. */
287
Simon Kelleyde379512004-06-22 20:23:33 +0100288 if (type == (start->flags & SERV_TYPE) &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100289 (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
290 !(start->flags & SERV_LITERAL_ADDRESS))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000291 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100292 int fd;
293
294 /* find server socket to use, may need to get random one. */
295 if (start->sfd)
296 fd = start->sfd->fd;
297 else
298 {
299#ifdef HAVE_IPV6
300 if (start->addr.sa.sa_family == AF_INET6)
301 {
302 if (!forward->rfd6 &&
303 !(forward->rfd6 = allocate_rfd(AF_INET6)))
304 break;
Simon Kelley3927da42008-07-20 15:10:39 +0100305 daemon->rfd_save = forward->rfd6;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100306 fd = forward->rfd6->fd;
307 }
308 else
309#endif
310 {
311 if (!forward->rfd4 &&
312 !(forward->rfd4 = allocate_rfd(AF_INET)))
313 break;
Simon Kelley3927da42008-07-20 15:10:39 +0100314 daemon->rfd_save = forward->rfd4;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100315 fd = forward->rfd4->fd;
316 }
317 }
318
319 if (sendto(fd, (char *)header, plen, 0,
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100320 &start->addr.sa,
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100321 sa_len(&start->addr)) == -1)
322 {
323 if (retry_send())
324 continue;
325 }
326 else
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000327 {
Simon Kelleycdeda282006-03-16 20:16:06 +0000328 /* Keep info in case we want to re-send this packet */
329 daemon->srv_save = start;
330 daemon->packet_len = plen;
331
Simon Kelleyde379512004-06-22 20:23:33 +0100332 if (!gotname)
Simon Kelley3be34542004-09-11 19:12:13 +0100333 strcpy(daemon->namebuff, "query");
Simon Kelleyde379512004-06-22 20:23:33 +0100334 if (start->addr.sa.sa_family == AF_INET)
Simon Kelley3be34542004-09-11 19:12:13 +0100335 log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
Simon Kelley1a6bca82008-07-11 11:11:42 +0100336 (struct all_addr *)&start->addr.in.sin_addr, NULL);
Simon Kelleyde379512004-06-22 20:23:33 +0100337#ifdef HAVE_IPV6
338 else
Simon Kelley3be34542004-09-11 19:12:13 +0100339 log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
Simon Kelley1a6bca82008-07-11 11:11:42 +0100340 (struct all_addr *)&start->addr.in6.sin6_addr, NULL);
Simon Kelleyde379512004-06-22 20:23:33 +0100341#endif
Simon Kelley824af852008-02-12 20:43:05 +0000342 start->queries++;
Simon Kelleyde379512004-06-22 20:23:33 +0100343 forwarded = 1;
344 forward->sentto = start;
Simon Kelley0a852542005-03-23 20:28:59 +0000345 if (!forward->forwardall)
Simon Kelleyde379512004-06-22 20:23:33 +0100346 break;
Simon Kelley0a852542005-03-23 20:28:59 +0000347 forward->forwardall++;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000348 }
349 }
350
Simon Kelleyde379512004-06-22 20:23:33 +0100351 if (!(start = start->next))
Simon Kelley3be34542004-09-11 19:12:13 +0100352 start = daemon->servers;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000353
Simon Kelleyde379512004-06-22 20:23:33 +0100354 if (start == firstsentto)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000355 break;
356 }
357
Simon Kelleyde379512004-06-22 20:23:33 +0100358 if (forwarded)
Simon Kelley824af852008-02-12 20:43:05 +0000359 return 1;
Simon Kelleyde379512004-06-22 20:23:33 +0100360
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000361 /* could not send on, prepare to return */
362 header->id = htons(forward->orig_id);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100363 free_frec(forward); /* cancel */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000364 }
365
366 /* could not send on, return empty answer or address if known for whole domain */
Simon Kelleyb8187c82005-11-26 21:46:27 +0000367 if (udpfd != -1)
368 {
Simon Kelleycdeda282006-03-16 20:16:06 +0000369 plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl);
Simon Kelleyb8187c82005-11-26 21:46:27 +0000370 send_from(udpfd, daemon->options & OPT_NOWILD, (char *)header, plen, udpaddr, dst_addr, dst_iface);
371 }
372
Simon Kelley824af852008-02-12 20:43:05 +0000373 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000374}
375
Simon Kelley5aabfc72007-08-29 11:24:47 +0100376static size_t process_reply(HEADER *header, time_t now,
Simon Kelley832af0b2007-01-21 20:01:28 +0000377 struct server *server, size_t n)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100378{
Simon Kelley36717ee2004-09-20 19:20:58 +0100379 unsigned char *pheader, *sizep;
Simon Kelley832af0b2007-01-21 20:01:28 +0000380 int munged = 0, is_sign;
Simon Kelleycdeda282006-03-16 20:16:06 +0000381 size_t plen;
382
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100383 /* If upstream is advertising a larger UDP packet size
Simon Kelley9009d742008-11-14 20:04:27 +0000384 than we allow, trim it so that we don't get overlarge
385 requests for the client. We can't do this for signed packets. */
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100386
Simon Kelley832af0b2007-01-21 20:01:28 +0000387 if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign)) && !is_sign)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100388 {
389 unsigned short udpsz;
Simon Kelley36717ee2004-09-20 19:20:58 +0100390 unsigned char *psave = sizep;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100391
Simon Kelley36717ee2004-09-20 19:20:58 +0100392 GETSHORT(udpsz, sizep);
Simon Kelley3be34542004-09-11 19:12:13 +0100393 if (udpsz > daemon->edns_pktsz)
394 PUTSHORT(daemon->edns_pktsz, psave);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100395 }
396
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000397 if (header->opcode != QUERY || (header->rcode != NOERROR && header->rcode != NXDOMAIN))
Simon Kelley36717ee2004-09-20 19:20:58 +0100398 return n;
399
Simon Kelley0a852542005-03-23 20:28:59 +0000400 /* Complain loudly if the upstream server is non-recursive. */
401 if (!header->ra && header->rcode == NOERROR && ntohs(header->ancount) == 0 &&
402 server && !(server->flags & SERV_WARNED_RECURSIVE))
403 {
Simon Kelley3d8df262005-08-29 12:19:27 +0100404 prettyprint_addr(&server->addr, daemon->namebuff);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100405 my_syslog(LOG_WARNING, _("nameserver %s refused to do a recursive query"), daemon->namebuff);
Simon Kelley0a852542005-03-23 20:28:59 +0000406 if (!(daemon->options & OPT_LOG))
407 server->flags |= SERV_WARNED_RECURSIVE;
408 }
409
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100410 if (daemon->bogus_addr && header->rcode != NXDOMAIN &&
411 check_for_bogus_wildcard(header, n, daemon->namebuff, daemon->bogus_addr, now))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100412 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100413 munged = 1;
414 header->rcode = NXDOMAIN;
415 header->aa = 0;
Simon Kelley36717ee2004-09-20 19:20:58 +0100416 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100417 else
Simon Kelley36717ee2004-09-20 19:20:58 +0100418 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100419 if (header->rcode == NXDOMAIN &&
420 extract_request(header, n, daemon->namebuff, NULL) &&
Simon Kelley5aabfc72007-08-29 11:24:47 +0100421 check_for_local_domain(daemon->namebuff, now))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100422 {
Simon Kelley36717ee2004-09-20 19:20:58 +0100423 /* if we forwarded a query for a locally known name (because it was for
424 an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
425 since we know that the domain exists, even if upstream doesn't */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100426 munged = 1;
427 header->aa = 1;
428 header->rcode = NOERROR;
Simon Kelley36717ee2004-09-20 19:20:58 +0100429 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000430
Simon Kelley824af852008-02-12 20:43:05 +0000431 if (extract_addresses(header, n, daemon->namebuff, now))
432 {
433 my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected"));
434 munged = 1;
435 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100436 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100437
438 /* do this after extract_addresses. Ensure NODATA reply and remove
439 nameserver info. */
440
441 if (munged)
442 {
443 header->ancount = htons(0);
444 header->nscount = htons(0);
445 header->arcount = htons(0);
446 }
447
Simon Kelley36717ee2004-09-20 19:20:58 +0100448 /* the bogus-nxdomain stuff, doctor and NXDOMAIN->NODATA munging can all elide
449 sections of the packet. Find the new length here and put back pseudoheader
450 if it was removed. */
451 return resize_packet(header, n, pheader, plen);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100452}
453
Simon Kelley3be34542004-09-11 19:12:13 +0100454/* sets new last_server */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100455void reply_query(int fd, int family, time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000456{
457 /* packet from peer server, extract data for cache, and send to
458 original requester */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000459 HEADER *header;
Simon Kelleyde379512004-06-22 20:23:33 +0100460 union mysockaddr serveraddr;
Simon Kelley832af0b2007-01-21 20:01:28 +0000461 struct frec *forward;
Simon Kelleyde379512004-06-22 20:23:33 +0100462 socklen_t addrlen = sizeof(serveraddr);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100463 ssize_t n = recvfrom(fd, daemon->packet, daemon->edns_pktsz, 0, &serveraddr.sa, &addrlen);
Simon Kelleycdeda282006-03-16 20:16:06 +0000464 size_t nn;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100465 struct server *server;
466
Simon Kelleycdeda282006-03-16 20:16:06 +0000467 /* packet buffer overwritten */
468 daemon->srv_save = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +0000469
Simon Kelleyde379512004-06-22 20:23:33 +0100470 /* Determine the address of the server replying so that we can mark that as good */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100471 serveraddr.sa.sa_family = family;
Simon Kelleyde379512004-06-22 20:23:33 +0100472#ifdef HAVE_IPV6
473 if (serveraddr.sa.sa_family == AF_INET6)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100474 serveraddr.in6.sin6_flowinfo = 0;
Simon Kelleyde379512004-06-22 20:23:33 +0100475#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000476
Simon Kelley1a6bca82008-07-11 11:11:42 +0100477 /* spoof check: answer must come from known server, */
478 for (server = daemon->servers; server; server = server->next)
479 if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) &&
480 sockaddr_isequal(&server->addr, &serveraddr))
481 break;
482
Simon Kelley3be34542004-09-11 19:12:13 +0100483 header = (HEADER *)daemon->packet;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100484
Simon Kelley1a6bca82008-07-11 11:11:42 +0100485 if (!server ||
486 n < (int)sizeof(HEADER) || !header->qr ||
487 !(forward = lookup_frec(ntohs(header->id), questions_crc(header, n, daemon->namebuff))))
488 return;
489
490 server = forward->sentto;
491
492 if ((header->rcode == SERVFAIL || header->rcode == REFUSED) &&
493 !(daemon->options & OPT_ORDER) &&
494 forward->forwardall == 0)
495 /* for broken servers, attempt to send to another one. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000496 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100497 unsigned char *pheader;
498 size_t plen;
499 int is_sign;
Simon Kelley832af0b2007-01-21 20:01:28 +0000500
Simon Kelley1a6bca82008-07-11 11:11:42 +0100501 /* recreate query from reply */
502 pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign);
503 if (!is_sign)
Simon Kelley832af0b2007-01-21 20:01:28 +0000504 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100505 header->ancount = htons(0);
506 header->nscount = htons(0);
507 header->arcount = htons(0);
508 if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
509 {
510 header->qr = 0;
511 header->tc = 0;
512 forward_query(-1, NULL, NULL, 0, header, nn, now, forward);
513 return;
514 }
515 }
516 }
517
518 if ((forward->sentto->flags & SERV_TYPE) == 0)
519 {
520 if (header->rcode == SERVFAIL || header->rcode == REFUSED)
521 server = NULL;
522 else
523 {
524 struct server *last_server;
Simon Kelley832af0b2007-01-21 20:01:28 +0000525
Simon Kelley1a6bca82008-07-11 11:11:42 +0100526 /* find good server by address if possible, otherwise assume the last one we sent to */
527 for (last_server = daemon->servers; last_server; last_server = last_server->next)
528 if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) &&
529 sockaddr_isequal(&last_server->addr, &serveraddr))
530 {
531 server = last_server;
532 break;
533 }
534 }
535 if (!(daemon->options & OPT_ALL_SERVERS))
536 daemon->last_server = server;
537 }
538
539 /* If the answer is an error, keep the forward record in place in case
540 we get a good reply from another server. Kill it when we've
541 had replies from all to avoid filling the forwarding table when
542 everything is broken */
543 if (forward->forwardall == 0 || --forward->forwardall == 1 ||
544 (header->rcode != REFUSED && header->rcode != SERVFAIL))
545 {
546 if ((nn = process_reply(header, now, server, (size_t)n)))
Simon Kelley832af0b2007-01-21 20:01:28 +0000547 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100548 header->id = htons(forward->orig_id);
549 header->ra = 1; /* recursion if available */
550 send_from(forward->fd, daemon->options & OPT_NOWILD, daemon->packet, nn,
551 &forward->source, &forward->dest, forward->iface);
Simon Kelley832af0b2007-01-21 20:01:28 +0000552 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100553 free_frec(forward); /* cancel */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000554 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000555}
Simon Kelley44a2a312004-03-10 20:04:35 +0000556
Simon Kelley1a6bca82008-07-11 11:11:42 +0100557
Simon Kelley5aabfc72007-08-29 11:24:47 +0100558void receive_query(struct listener *listen, time_t now)
Simon Kelley44a2a312004-03-10 20:04:35 +0000559{
Simon Kelley3be34542004-09-11 19:12:13 +0100560 HEADER *header = (HEADER *)daemon->packet;
Simon Kelley44a2a312004-03-10 20:04:35 +0000561 union mysockaddr source_addr;
Simon Kelleyc1bb8502004-08-11 18:40:17 +0100562 unsigned short type;
Simon Kelley44a2a312004-03-10 20:04:35 +0000563 struct all_addr dst_addr;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000564 struct in_addr netmask, dst_addr_4;
Simon Kelleycdeda282006-03-16 20:16:06 +0000565 size_t m;
566 ssize_t n;
567 int if_index = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +0000568 struct iovec iov[1];
569 struct msghdr msg;
570 struct cmsghdr *cmptr;
Simon Kelley44a2a312004-03-10 20:04:35 +0000571 union {
572 struct cmsghdr align; /* this ensures alignment */
573#ifdef HAVE_IPV6
574 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
575#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100576#if defined(HAVE_LINUX_NETWORK)
Simon Kelley44a2a312004-03-10 20:04:35 +0000577 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
Simon Kelley824af852008-02-12 20:43:05 +0000578#elif defined(IP_RECVDSTADDR) && defined(HAVE_SOLARIS_NETWORK)
579 char control[CMSG_SPACE(sizeof(struct in_addr)) +
580 CMSG_SPACE(sizeof(unsigned int))];
Simon Kelley44a2a312004-03-10 20:04:35 +0000581#elif defined(IP_RECVDSTADDR)
582 char control[CMSG_SPACE(sizeof(struct in_addr)) +
583 CMSG_SPACE(sizeof(struct sockaddr_dl))];
584#endif
585 } control_u;
586
Simon Kelleycdeda282006-03-16 20:16:06 +0000587 /* packet buffer overwritten */
588 daemon->srv_save = NULL;
589
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000590 if (listen->family == AF_INET && (daemon->options & OPT_NOWILD))
591 {
592 dst_addr_4 = listen->iface->addr.in.sin_addr;
593 netmask = listen->iface->netmask;
594 }
595 else
Simon Kelley3d8df262005-08-29 12:19:27 +0100596 {
597 dst_addr_4.s_addr = 0;
598 netmask.s_addr = 0;
599 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000600
Simon Kelley3be34542004-09-11 19:12:13 +0100601 iov[0].iov_base = daemon->packet;
602 iov[0].iov_len = daemon->edns_pktsz;
Simon Kelley44a2a312004-03-10 20:04:35 +0000603
604 msg.msg_control = control_u.control;
605 msg.msg_controllen = sizeof(control_u);
606 msg.msg_flags = 0;
607 msg.msg_name = &source_addr;
608 msg.msg_namelen = sizeof(source_addr);
609 msg.msg_iov = iov;
610 msg.msg_iovlen = 1;
611
Simon Kelleyde379512004-06-22 20:23:33 +0100612 if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
Simon Kelley3be34542004-09-11 19:12:13 +0100613 return;
Simon Kelley44a2a312004-03-10 20:04:35 +0000614
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100615 if (n < (int)sizeof(HEADER) ||
616 (msg.msg_flags & MSG_TRUNC) ||
617 header->qr)
Simon Kelley3be34542004-09-11 19:12:13 +0100618 return;
Simon Kelley44a2a312004-03-10 20:04:35 +0000619
Simon Kelley26128d22004-11-14 16:43:54 +0000620 source_addr.sa.sa_family = listen->family;
621#ifdef HAVE_IPV6
622 if (listen->family == AF_INET6)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100623 source_addr.in6.sin6_flowinfo = 0;
Simon Kelley26128d22004-11-14 16:43:54 +0000624#endif
625
626 if (!(daemon->options & OPT_NOWILD))
Simon Kelley44a2a312004-03-10 20:04:35 +0000627 {
Simon Kelley8a911cc2004-03-16 18:35:52 +0000628 struct ifreq ifr;
629
Simon Kelley26128d22004-11-14 16:43:54 +0000630 if (msg.msg_controllen < sizeof(struct cmsghdr))
631 return;
632
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100633#if defined(HAVE_LINUX_NETWORK)
Simon Kelley26128d22004-11-14 16:43:54 +0000634 if (listen->family == AF_INET)
635 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
636 if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
637 {
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000638 dst_addr_4 = dst_addr.addr.addr4 = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_spec_dst;
Simon Kelley26128d22004-11-14 16:43:54 +0000639 if_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
640 }
641#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
642 if (listen->family == AF_INET)
643 {
644 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
645 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000646 dst_addr_4 = dst_addr.addr.addr4 = *((struct in_addr *)CMSG_DATA(cmptr));
Simon Kelley26128d22004-11-14 16:43:54 +0000647 else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
Simon Kelley824af852008-02-12 20:43:05 +0000648#ifdef HAVE_SOLARIS_NETWORK
649 if_index = *((unsigned int *)CMSG_DATA(cmptr));
650#else
Simon Kelley26128d22004-11-14 16:43:54 +0000651 if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
Simon Kelley824af852008-02-12 20:43:05 +0000652#endif
Simon Kelley26128d22004-11-14 16:43:54 +0000653 }
654#endif
655
656#ifdef HAVE_IPV6
657 if (listen->family == AF_INET6)
658 {
659 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
660 if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == IPV6_PKTINFO)
661 {
662 dst_addr.addr.addr6 = ((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_addr;
663 if_index =((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_ifindex;
664 }
665 }
666#endif
667
668 /* enforce available interface configuration */
669
Simon Kelley8a911cc2004-03-16 18:35:52 +0000670 if (if_index == 0)
Simon Kelley3be34542004-09-11 19:12:13 +0100671 return;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000672
Simon Kelley8a911cc2004-03-16 18:35:52 +0000673#ifdef SIOCGIFNAME
Simon Kelley832af0b2007-01-21 20:01:28 +0000674 ifr.ifr_ifindex = if_index;
675 if (ioctl(listen->fd, SIOCGIFNAME, &ifr) == -1)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100676 return;
Simon Kelley832af0b2007-01-21 20:01:28 +0000677#else
678 if (!if_indextoname(if_index, ifr.ifr_name))
679 return;
680#endif
681
Simon Kelley5aabfc72007-08-29 11:24:47 +0100682 if (!iface_check(listen->family, &dst_addr, &ifr, &if_index))
Simon Kelley832af0b2007-01-21 20:01:28 +0000683 return;
684
685 if (listen->family == AF_INET &&
686 (daemon->options & OPT_LOCALISE) &&
687 ioctl(listen->fd, SIOCGIFNETMASK, &ifr) == -1)
688 return;
689
690 netmask = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
Simon Kelley44a2a312004-03-10 20:04:35 +0000691 }
692
Simon Kelleycdeda282006-03-16 20:16:06 +0000693 if (extract_request(header, (size_t)n, daemon->namebuff, &type))
Simon Kelley44a2a312004-03-10 20:04:35 +0000694 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100695 char types[20];
696
697 querystr(types, type);
698
Simon Kelley44a2a312004-03-10 20:04:35 +0000699 if (listen->family == AF_INET)
Simon Kelley3be34542004-09-11 19:12:13 +0100700 log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
Simon Kelley1a6bca82008-07-11 11:11:42 +0100701 (struct all_addr *)&source_addr.in.sin_addr, types);
Simon Kelley44a2a312004-03-10 20:04:35 +0000702#ifdef HAVE_IPV6
703 else
Simon Kelley3be34542004-09-11 19:12:13 +0100704 log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
Simon Kelley1a6bca82008-07-11 11:11:42 +0100705 (struct all_addr *)&source_addr.in6.sin6_addr, types);
Simon Kelley44a2a312004-03-10 20:04:35 +0000706#endif
707 }
708
Simon Kelley5aabfc72007-08-29 11:24:47 +0100709 m = answer_request (header, ((char *) header) + PACKETSZ, (size_t)n,
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000710 dst_addr_4, netmask, now);
Simon Kelley44a2a312004-03-10 20:04:35 +0000711 if (m >= 1)
Simon Kelley824af852008-02-12 20:43:05 +0000712 {
713 send_from(listen->fd, daemon->options & OPT_NOWILD, (char *)header,
714 m, &source_addr, &dst_addr, if_index);
715 daemon->local_answer++;
716 }
717 else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
718 header, (size_t)n, now, NULL))
719 daemon->queries_forwarded++;
Simon Kelley44a2a312004-03-10 20:04:35 +0000720 else
Simon Kelley824af852008-02-12 20:43:05 +0000721 daemon->local_answer++;
Simon Kelley44a2a312004-03-10 20:04:35 +0000722}
723
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100724/* The daemon forks before calling this: it should deal with one connection,
725 blocking as neccessary, and then return. Note, need to be a bit careful
726 about resources for debug mode, when the fork is suppressed: that's
727 done by the caller. */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100728unsigned char *tcp_request(int confd, time_t now,
Simon Kelley3d8df262005-08-29 12:19:27 +0100729 struct in_addr local_addr, struct in_addr netmask)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100730{
Simon Kelleycdeda282006-03-16 20:16:06 +0000731 int size = 0;
732 size_t m;
Simon Kelleyc1bb8502004-08-11 18:40:17 +0100733 unsigned short qtype, gotname;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100734 unsigned char c1, c2;
735 /* Max TCP packet + slop */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100736 unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100737 HEADER *header;
Simon Kelley3be34542004-09-11 19:12:13 +0100738 struct server *last_server;
739
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100740 while (1)
741 {
742 if (!packet ||
743 !read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
744 !(size = c1 << 8 | c2) ||
745 !read_write(confd, packet, size, 1))
746 return packet;
747
748 if (size < (int)sizeof(HEADER))
749 continue;
750
751 header = (HEADER *)packet;
752
Simon Kelley3be34542004-09-11 19:12:13 +0100753 if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100754 {
755 union mysockaddr peer_addr;
756 socklen_t peer_len = sizeof(union mysockaddr);
757
758 if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) != -1)
759 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100760 char types[20];
761
762 querystr(types, qtype);
763
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100764 if (peer_addr.sa.sa_family == AF_INET)
Simon Kelley3be34542004-09-11 19:12:13 +0100765 log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
Simon Kelley1a6bca82008-07-11 11:11:42 +0100766 (struct all_addr *)&peer_addr.in.sin_addr, types);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100767#ifdef HAVE_IPV6
768 else
Simon Kelley3be34542004-09-11 19:12:13 +0100769 log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
Simon Kelley1a6bca82008-07-11 11:11:42 +0100770 (struct all_addr *)&peer_addr.in6.sin6_addr, types);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100771#endif
772 }
773 }
774
775 /* m > 0 if answered from cache */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100776 m = answer_request(header, ((char *) header) + 65536, (unsigned int)size,
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000777 local_addr, netmask, now);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100778
779 /* Do this by steam now we're not in the select() loop */
780 check_log_writer(NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100781
782 if (m == 0)
783 {
784 unsigned short flags = 0;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100785 struct all_addr *addrp = NULL;
786 int type = 0;
787 char *domain = NULL;
788
789 if (gotname)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100790 flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100791
Simon Kelley3be34542004-09-11 19:12:13 +0100792 if (type != 0 || (daemon->options & OPT_ORDER) || !daemon->last_server)
793 last_server = daemon->servers;
794 else
795 last_server = daemon->last_server;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100796
797 if (!flags && last_server)
798 {
799 struct server *firstsendto = NULL;
Simon Kelley0a852542005-03-23 20:28:59 +0000800 unsigned int crc = questions_crc(header, (unsigned int)size, daemon->namebuff);
801
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100802 /* Loop round available servers until we succeed in connecting to one.
803 Note that this code subtley ensures that consecutive queries on this connection
804 which can go to the same server, do so. */
805 while (1)
806 {
807 if (!firstsendto)
808 firstsendto = last_server;
809 else
810 {
811 if (!(last_server = last_server->next))
Simon Kelley3be34542004-09-11 19:12:13 +0100812 last_server = daemon->servers;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100813
814 if (last_server == firstsendto)
815 break;
816 }
817
818 /* server for wrong domain */
819 if (type != (last_server->flags & SERV_TYPE) ||
820 (type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)))
821 continue;
822
823 if ((last_server->tcpfd == -1) &&
824 (last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) != -1 &&
Simon Kelley824af852008-02-12 20:43:05 +0000825 (!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 1) ||
826 connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100827 {
828 close(last_server->tcpfd);
829 last_server->tcpfd = -1;
830 }
831
832 if (last_server->tcpfd == -1)
833 continue;
Simon Kelley824af852008-02-12 20:43:05 +0000834
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100835 c1 = size >> 8;
836 c2 = size;
837
838 if (!read_write(last_server->tcpfd, &c1, 1, 0) ||
839 !read_write(last_server->tcpfd, &c2, 1, 0) ||
840 !read_write(last_server->tcpfd, packet, size, 0) ||
841 !read_write(last_server->tcpfd, &c1, 1, 1) ||
842 !read_write(last_server->tcpfd, &c2, 1, 1))
843 {
844 close(last_server->tcpfd);
845 last_server->tcpfd = -1;
846 continue;
847 }
Simon Kelley824af852008-02-12 20:43:05 +0000848
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100849 m = (c1 << 8) | c2;
850 if (!read_write(last_server->tcpfd, packet, m, 1))
851 return packet;
852
853 if (!gotname)
Simon Kelley3be34542004-09-11 19:12:13 +0100854 strcpy(daemon->namebuff, "query");
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100855 if (last_server->addr.sa.sa_family == AF_INET)
Simon Kelley3be34542004-09-11 19:12:13 +0100856 log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
Simon Kelley1a6bca82008-07-11 11:11:42 +0100857 (struct all_addr *)&last_server->addr.in.sin_addr, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100858#ifdef HAVE_IPV6
859 else
Simon Kelley3be34542004-09-11 19:12:13 +0100860 log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
Simon Kelley1a6bca82008-07-11 11:11:42 +0100861 (struct all_addr *)&last_server->addr.in6.sin6_addr, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100862#endif
863
864 /* There's no point in updating the cache, since this process will exit and
Simon Kelley832af0b2007-01-21 20:01:28 +0000865 lose the information after a few queries. We make this call for the alias and
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100866 bogus-nxdomain side-effects. */
Simon Kelley832af0b2007-01-21 20:01:28 +0000867 /* If the crc of the question section doesn't match the crc we sent, then
868 someone might be attempting to insert bogus values into the cache by
869 sending replies containing questions and bogus answers. */
870 if (crc == questions_crc(header, (unsigned int)m, daemon->namebuff))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100871 m = process_reply(header, now, last_server, (unsigned int)m);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100872
873 break;
874 }
875 }
876
877 /* In case of local answer or no connections made. */
878 if (m == 0)
Simon Kelley3be34542004-09-11 19:12:13 +0100879 m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100880 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100881
882 check_log_writer(NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100883
884 c1 = m>>8;
885 c2 = m;
886 if (!read_write(confd, &c1, 1, 0) ||
887 !read_write(confd, &c2, 1, 0) ||
888 !read_write(confd, packet, m, 0))
889 return packet;
890 }
891}
892
Simon Kelley16972692006-10-16 20:04:18 +0100893static struct frec *allocate_frec(time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000894{
Simon Kelley16972692006-10-16 20:04:18 +0100895 struct frec *f;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000896
Simon Kelley5aabfc72007-08-29 11:24:47 +0100897 if ((f = (struct frec *)whine_malloc(sizeof(struct frec))))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000898 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100899 f->next = daemon->frec_list;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000900 f->time = now;
Simon Kelley832af0b2007-01-21 20:01:28 +0000901 f->sentto = NULL;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100902 f->rfd4 = NULL;
903#ifdef HAVE_IPV6
904 f->rfd6 = NULL;
905#endif
906 daemon->frec_list = f;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000907 }
Simon Kelley16972692006-10-16 20:04:18 +0100908
909 return f;
910}
911
Simon Kelley1a6bca82008-07-11 11:11:42 +0100912static struct randfd *allocate_rfd(int family)
913{
914 static int finger = 0;
915 int i;
916
917 /* limit the number of sockets we have open to avoid starvation of
918 (eg) TFTP. Once we have a reasonable number, randomness should be OK */
919
920 for (i = 0; i < RANDOM_SOCKS; i++)
Simon Kelley9009d742008-11-14 20:04:27 +0000921 if (daemon->randomsocks[i].refcount == 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100922 {
Simon Kelley9009d742008-11-14 20:04:27 +0000923 if ((daemon->randomsocks[i].fd = random_sock(family)) == -1)
924 break;
925
Simon Kelley1a6bca82008-07-11 11:11:42 +0100926 daemon->randomsocks[i].refcount = 1;
927 daemon->randomsocks[i].family = family;
928 return &daemon->randomsocks[i];
929 }
930
Simon Kelley9009d742008-11-14 20:04:27 +0000931 /* No free ones or cannot get new socket, grab an existing one */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100932 for (i = 0; i < RANDOM_SOCKS; i++)
933 {
934 int j = (i+finger) % RANDOM_SOCKS;
Simon Kelley9009d742008-11-14 20:04:27 +0000935 if (daemon->randomsocks[j].refcount != 0 &&
936 daemon->randomsocks[j].family == family &&
937 daemon->randomsocks[j].refcount != 0xffff)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100938 {
939 finger = j;
940 daemon->randomsocks[j].refcount++;
941 return &daemon->randomsocks[j];
942 }
943 }
944
945 return NULL; /* doom */
946}
947
948static void free_frec(struct frec *f)
949{
950 if (f->rfd4 && --(f->rfd4->refcount) == 0)
951 close(f->rfd4->fd);
952
953 f->rfd4 = NULL;
954 f->sentto = NULL;
955
956#ifdef HAVE_IPV6
957 if (f->rfd6 && --(f->rfd6->refcount) == 0)
958 close(f->rfd6->fd);
959
960 f->rfd6 = NULL;
961#endif
962}
963
Simon Kelley16972692006-10-16 20:04:18 +0100964/* if wait==NULL return a free or older than TIMEOUT record.
965 else return *wait zero if one available, or *wait is delay to
Simon Kelley1a6bca82008-07-11 11:11:42 +0100966 when the oldest in-use record will expire. Impose an absolute
967 limit of 4*TIMEOUT before we wipe things (for random sockets) */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100968struct frec *get_new_frec(time_t now, int *wait)
Simon Kelley16972692006-10-16 20:04:18 +0100969{
Simon Kelley1a6bca82008-07-11 11:11:42 +0100970 struct frec *f, *oldest, *target;
Simon Kelley16972692006-10-16 20:04:18 +0100971 int count;
972
973 if (wait)
974 *wait = 0;
975
Simon Kelley1a6bca82008-07-11 11:11:42 +0100976 for (f = daemon->frec_list, oldest = NULL, target = NULL, count = 0; f; f = f->next, count++)
Simon Kelley832af0b2007-01-21 20:01:28 +0000977 if (!f->sentto)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100978 target = f;
979 else
Simon Kelley16972692006-10-16 20:04:18 +0100980 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100981 if (difftime(now, f->time) >= 4*TIMEOUT)
982 {
983 free_frec(f);
984 target = f;
985 }
986
987 if (!oldest || difftime(f->time, oldest->time) <= 0)
988 oldest = f;
Simon Kelley16972692006-10-16 20:04:18 +0100989 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100990
991 if (target)
992 {
993 target->time = now;
994 return target;
995 }
Simon Kelley16972692006-10-16 20:04:18 +0100996
997 /* can't find empty one, use oldest if there is one
998 and it's older than timeout */
999 if (oldest && ((int)difftime(now, oldest->time)) >= TIMEOUT)
1000 {
1001 /* keep stuff for twice timeout if we can by allocating a new
1002 record instead */
1003 if (difftime(now, oldest->time) < 2*TIMEOUT &&
1004 count <= daemon->ftabsize &&
1005 (f = allocate_frec(now)))
1006 return f;
1007
1008 if (!wait)
1009 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001010 free_frec(oldest);
Simon Kelley16972692006-10-16 20:04:18 +01001011 oldest->time = now;
1012 }
1013 return oldest;
1014 }
1015
1016 /* none available, calculate time 'till oldest record expires */
1017 if (count > daemon->ftabsize)
1018 {
1019 if (oldest && wait)
1020 *wait = oldest->time + (time_t)TIMEOUT - now;
1021 return NULL;
1022 }
1023
1024 if (!(f = allocate_frec(now)) && wait)
1025 /* wait one second on malloc failure */
1026 *wait = 1;
1027
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001028 return f; /* OK if malloc fails and this is NULL */
1029}
1030
Simon Kelley832af0b2007-01-21 20:01:28 +00001031/* crc is all-ones if not known. */
1032static struct frec *lookup_frec(unsigned short id, unsigned int crc)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001033{
1034 struct frec *f;
1035
Simon Kelley1a6bca82008-07-11 11:11:42 +01001036 for(f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00001037 if (f->sentto && f->new_id == id &&
1038 (f->crc == crc || crc == 0xffffffff))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001039 return f;
1040
1041 return NULL;
1042}
1043
1044static struct frec *lookup_frec_by_sender(unsigned short id,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001045 union mysockaddr *addr,
1046 unsigned int crc)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001047{
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001048 struct frec *f;
1049
Simon Kelley1a6bca82008-07-11 11:11:42 +01001050 for(f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00001051 if (f->sentto &&
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001052 f->orig_id == id &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001053 f->crc == crc &&
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001054 sockaddr_isequal(&f->source, addr))
1055 return f;
1056
1057 return NULL;
1058}
1059
Simon Kelley849a8352006-06-09 21:02:31 +01001060/* A server record is going away, remove references to it */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001061void server_gone(struct server *server)
Simon Kelley849a8352006-06-09 21:02:31 +01001062{
1063 struct frec *f;
1064
Simon Kelley1a6bca82008-07-11 11:11:42 +01001065 for (f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00001066 if (f->sentto && f->sentto == server)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001067 free_frec(f);
Simon Kelley849a8352006-06-09 21:02:31 +01001068
1069 if (daemon->last_server == server)
1070 daemon->last_server = NULL;
1071
1072 if (daemon->srv_save == server)
1073 daemon->srv_save = NULL;
1074}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001075
Simon Kelley832af0b2007-01-21 20:01:28 +00001076/* return unique random ids.
1077 For signed packets we can't change the ID without breaking the
1078 signing, so we keep the same one. In this case force is set, and this
1079 routine degenerates into killing any conflicting forward record. */
1080static unsigned short get_id(int force, unsigned short force_id, unsigned int crc)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001081{
1082 unsigned short ret = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +00001083
1084 if (force)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001085 {
Simon Kelley832af0b2007-01-21 20:01:28 +00001086 struct frec *f = lookup_frec(force_id, crc);
1087 if (f)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001088 free_frec(f); /* free */
Simon Kelley832af0b2007-01-21 20:01:28 +00001089 ret = force_id;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001090 }
Simon Kelley832af0b2007-01-21 20:01:28 +00001091 else do
1092 ret = rand16();
1093 while (lookup_frec(ret, crc));
1094
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001095 return ret;
1096}
1097
1098
1099
1100
1101