]> git.ipfire.org Git - people/ms/dnsmasq.git/blame - src/forward.c
Tiny makefile tweak.
[people/ms/dnsmasq.git] / src / forward.c
CommitLineData
59546085 1/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
9e4abcb5
SK
2
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
824af85b
SK
5 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
9e4abcb5
SK
8 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.
824af85b 12
73a08a24
SK
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/>.
9e4abcb5
SK
15*/
16
9e4abcb5
SK
17#include "dnsmasq.h"
18
832af0ba 19static struct frec *lookup_frec(unsigned short id, unsigned int crc);
9e4abcb5 20static struct frec *lookup_frec_by_sender(unsigned short id,
fd9fa481
SK
21 union mysockaddr *addr,
22 unsigned int crc);
316e2730 23static unsigned short get_id(unsigned int crc);
1a6bca81
SK
24static void free_frec(struct frec *f);
25static struct randfd *allocate_rfd(int family);
9e4abcb5 26
824af85b 27/* Send a UDP packet with its source address set as "source"
44a2a316 28 unless nowild is true, when we just send it with the kernel default */
c72daea8
SK
29void send_from(int fd, int nowild, char *packet, size_t len,
30 union mysockaddr *to, struct all_addr *source,
31 unsigned int iface)
9e4abcb5 32{
44a2a316
SK
33 struct msghdr msg;
34 struct iovec iov[1];
44a2a316
SK
35 union {
36 struct cmsghdr align; /* this ensures alignment */
5e9e0efb 37#if defined(HAVE_LINUX_NETWORK)
44a2a316
SK
38 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;
feba5c1d 46
44a2a316
SK
47 iov[0].iov_base = packet;
48 iov[0].iov_len = len;
49
feba5c1d
SK
50 msg.msg_control = NULL;
51 msg.msg_controllen = 0;
44a2a316
SK
52 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;
feba5c1d 57
26128d27 58 if (!nowild)
44a2a316 59 {
26128d27 60 struct cmsghdr *cmptr;
feba5c1d
SK
61 msg.msg_control = &control_u;
62 msg.msg_controllen = sizeof(control_u);
26128d27
SK
63 cmptr = CMSG_FIRSTHDR(&msg);
64
65 if (to->sa.sa_family == AF_INET)
66 {
5e9e0efb 67#if defined(HAVE_LINUX_NETWORK)
8ef5ada2
SK
68 struct in_pktinfo p;
69 p.ipi_ifindex = 0;
70 p.ipi_spec_dst = source->addr.addr4;
71 memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
26128d27 72 msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
c72daea8 73 cmptr->cmsg_level = IPPROTO_IP;
26128d27 74 cmptr->cmsg_type = IP_PKTINFO;
44a2a316 75#elif defined(IP_SENDSRCADDR)
8ef5ada2 76 memcpy(CMSG_DATA(cmptr), &(source->addr.addr4), sizeof(source->addr.addr4));
26128d27
SK
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;
44a2a316 80#endif
26128d27 81 }
26128d27 82 else
b8187c80 83#ifdef HAVE_IPV6
26128d27 84 {
8ef5ada2
SK
85 struct in6_pktinfo p;
86 p.ipi6_ifindex = iface; /* Need iface for IPv6 to handle link-local addrs */
87 p.ipi6_addr = source->addr.addr6;
88 memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
26128d27 89 msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
316e2730 90 cmptr->cmsg_type = daemon->v6pktinfo;
c72daea8 91 cmptr->cmsg_level = IPPROTO_IPV6;
26128d27 92 }
3d8df260 93#else
c72daea8 94 (void)iface; /* eliminate warning */
44a2a316 95#endif
26128d27 96 }
feba5c1d 97
fd9fa481
SK
98 retry:
99 if (sendmsg(fd, &msg, 0) == -1)
feba5c1d 100 {
fd9fa481
SK
101 /* certain Linux kernels seem to object to setting the source address in the IPv6 stack
102 by returning EINVAL from sendmsg. In that case, try again without setting the
103 source address, since it will nearly alway be correct anyway. IPv6 stinks. */
104 if (errno == EINVAL && msg.msg_controllen)
105 {
106 msg.msg_controllen = 0;
107 goto retry;
108 }
22d904db 109
fd9fa481
SK
110 if (retry_send())
111 goto retry;
22d904db
SK
112
113 my_syslog(LOG_ERR, _("failed to send packet: %s"), strerror(errno));
feba5c1d 114 }
9e4abcb5 115}
44a2a316 116
28866e95
SK
117static unsigned int search_servers(time_t now, struct all_addr **addrpp,
118 unsigned int qtype, char *qdomain, int *type, char **domain, int *norebind)
feba5c1d
SK
119
120{
121 /* If the query ends in the domain in one of our servers, set
122 domain to point to that name. We find the largest match to allow both
123 domain.org and sub.domain.org to exist. */
124
125 unsigned int namelen = strlen(qdomain);
126 unsigned int matchlen = 0;
127 struct server *serv;
28866e95 128 unsigned int flags = 0;
feba5c1d 129
3be34541 130 for (serv = daemon->servers; serv; serv=serv->next)
feba5c1d 131 /* domain matches take priority over NODOTS matches */
3d8df260 132 if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.') && namelen != 0)
feba5c1d 133 {
28866e95 134 unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
feba5c1d 135 *type = SERV_FOR_NODOTS;
feba5c1d 136 if (serv->flags & SERV_NO_ADDR)
36717eee
SK
137 flags = F_NXDOMAIN;
138 else if (serv->flags & SERV_LITERAL_ADDRESS)
139 {
140 if (sflag & qtype)
141 {
142 flags = sflag;
143 if (serv->addr.sa.sa_family == AF_INET)
144 *addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
feba5c1d 145#ifdef HAVE_IPV6
36717eee
SK
146 else
147 *addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
feba5c1d 148#endif
36717eee 149 }
824af85b 150 else if (!flags || (flags & F_NXDOMAIN))
36717eee
SK
151 flags = F_NOERR;
152 }
feba5c1d
SK
153 }
154 else if (serv->flags & SERV_HAS_DOMAIN)
155 {
156 unsigned int domainlen = strlen(serv->domain);
b8187c80 157 char *matchstart = qdomain + namelen - domainlen;
feba5c1d 158 if (namelen >= domainlen &&
b8187c80 159 hostname_isequal(matchstart, serv->domain) &&
8ef5ada2 160 (domainlen == 0 || namelen == domainlen || *(matchstart-1) == '.' ))
feba5c1d 161 {
8ef5ada2
SK
162 if (serv->flags & SERV_NO_REBIND)
163 *norebind = 1;
28866e95 164 else
feba5c1d 165 {
28866e95
SK
166 unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
167 /* implement priority rules for --address and --server for same domain.
168 --address wins if the address is for the correct AF
169 --server wins otherwise. */
170 if (domainlen != 0 && domainlen == matchlen)
36717eee 171 {
28866e95 172 if ((serv->flags & SERV_LITERAL_ADDRESS))
8ef5ada2 173 {
28866e95
SK
174 if (!(sflag & qtype) && flags == 0)
175 continue;
176 }
177 else
178 {
179 if (flags & (F_IPV4 | F_IPV6))
180 continue;
181 }
182 }
183
184 if (domainlen >= matchlen)
185 {
186 *type = serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_REBIND);
187 *domain = serv->domain;
188 matchlen = domainlen;
189 if (serv->flags & SERV_NO_ADDR)
190 flags = F_NXDOMAIN;
191 else if (serv->flags & SERV_LITERAL_ADDRESS)
192 {
193 if (sflag & qtype)
194 {
195 flags = sflag;
196 if (serv->addr.sa.sa_family == AF_INET)
197 *addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
feba5c1d 198#ifdef HAVE_IPV6
28866e95
SK
199 else
200 *addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
feba5c1d 201#endif
28866e95
SK
202 }
203 else if (!flags || (flags & F_NXDOMAIN))
204 flags = F_NOERR;
8ef5ada2 205 }
28866e95
SK
206 else
207 flags = 0;
208 }
209 }
8ef5ada2 210 }
feba5c1d 211 }
8ef5ada2 212
7de060b0 213 if (flags == 0 && !(qtype & F_QUERY) &&
28866e95 214 option_bool(OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
7de060b0
SK
215 /* don't forward A or AAAA queries for simple names, except the empty name */
216 flags = F_NOERR;
8ef5ada2 217
5aabfc78 218 if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now))
c1bb8504 219 flags = F_NOERR;
feba5c1d 220
824af85b
SK
221 if (flags)
222 {
223 int logflags = 0;
224
225 if (flags == F_NXDOMAIN || flags == F_NOERR)
226 logflags = F_NEG | qtype;
227
1a6bca81 228 log_query(logflags | flags | F_CONFIG | F_FORWARD, qdomain, *addrpp, NULL);
824af85b 229 }
8ef5ada2
SK
230 else if ((*type) & SERV_USE_RESOLV)
231 {
232 *type = 0; /* use normal servers for this domain */
233 *domain = NULL;
234 }
feba5c1d
SK
235 return flags;
236}
44a2a316 237
824af85b
SK
238static int forward_query(int udpfd, union mysockaddr *udpaddr,
239 struct all_addr *dst_addr, unsigned int dst_iface,
572b41eb 240 struct dns_header *header, size_t plen, time_t now, struct frec *forward)
9e4abcb5 241{
9e4abcb5 242 char *domain = NULL;
8ef5ada2 243 int type = 0, norebind = 0;
9e4abcb5 244 struct all_addr *addrp = NULL;
cdeda28f 245 unsigned int crc = questions_crc(header, plen, daemon->namebuff);
28866e95
SK
246 unsigned int flags = 0;
247 unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
de37951c 248 struct server *start = NULL;
7de060b0 249
28866e95 250 /* RFC 4035: sect 4.6 para 2 */
572b41eb
SK
251 header->hb4 &= ~HB4_AD;
252
3d8df260
SK
253 /* may be no servers available. */
254 if (!daemon->servers)
9e4abcb5 255 forward = NULL;
b8187c80 256 else if (forward || (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, crc)))
9e4abcb5 257 {
de37951c 258 /* retry on existing query, send to all available servers */
9e4abcb5 259 domain = forward->sentto->domain;
824af85b 260 forward->sentto->failed_queries++;
28866e95 261 if (!option_bool(OPT_ORDER))
de37951c 262 {
0a852541 263 forward->forwardall = 1;
3be34541 264 daemon->last_server = NULL;
de37951c 265 }
9e4abcb5 266 type = forward->sentto->flags & SERV_TYPE;
de37951c 267 if (!(start = forward->sentto->next))
3be34541 268 start = daemon->servers; /* at end of list, recycle */
9e4abcb5
SK
269 header->id = htons(forward->new_id);
270 }
271 else
272 {
273 if (gotname)
8ef5ada2 274 flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
9e4abcb5 275
5aabfc78 276 if (!flags && !(forward = get_new_frec(now, NULL)))
feba5c1d
SK
277 /* table full - server failure. */
278 flags = F_NEG;
9e4abcb5
SK
279
280 if (forward)
281 {
0a852541
SK
282 forward->source = *udpaddr;
283 forward->dest = *dst_addr;
284 forward->iface = dst_iface;
0a852541 285 forward->orig_id = ntohs(header->id);
316e2730 286 forward->new_id = get_id(crc);
832af0ba 287 forward->fd = udpfd;
0a852541
SK
288 forward->crc = crc;
289 forward->forwardall = 0;
28866e95
SK
290 if (norebind)
291 forward->flags |= FREC_NOREBIND;
572b41eb 292 if (header->hb4 & HB4_CD)
28866e95 293 forward->flags |= FREC_CHECKING_DISABLED;
0a852541 294
28866e95
SK
295 header->id = htons(forward->new_id);
296
8ef5ada2
SK
297 /* In strict_order mode, always try servers in the order
298 specified in resolv.conf, if a domain is given
299 always try all the available servers,
9e4abcb5
SK
300 otherwise, use the one last known to work. */
301
8ef5ada2
SK
302 if (type == 0)
303 {
28866e95 304 if (option_bool(OPT_ORDER))
8ef5ada2
SK
305 start = daemon->servers;
306 else if (!(start = daemon->last_server) ||
307 daemon->forwardcount++ > FORWARD_TEST ||
308 difftime(now, daemon->forwardtime) > FORWARD_TIME)
309 {
310 start = daemon->servers;
311 forward->forwardall = 1;
312 daemon->forwardcount = 0;
313 daemon->forwardtime = now;
314 }
315 }
316 else
de37951c 317 {
3be34541 318 start = daemon->servers;
28866e95 319 if (!option_bool(OPT_ORDER))
8ef5ada2 320 forward->forwardall = 1;
de37951c 321 }
9e4abcb5
SK
322 }
323 }
feba5c1d 324
9e4abcb5
SK
325 /* check for send errors here (no route to host)
326 if we fail to send to all nameservers, send back an error
327 packet straight away (helps modem users when offline) */
328
329 if (!flags && forward)
330 {
de37951c
SK
331 struct server *firstsentto = start;
332 int forwarded = 0;
28866e95
SK
333
334 if (udpaddr && option_bool(OPT_ADD_MAC))
335 plen = add_mac(header, plen, ((char *) header) + PACKETSZ, udpaddr);
336
9e4abcb5
SK
337 while (1)
338 {
9e4abcb5
SK
339 /* only send to servers dealing with our domain.
340 domain may be NULL, in which case server->domain
341 must be NULL also. */
342
de37951c 343 if (type == (start->flags & SERV_TYPE) &&
fd9fa481
SK
344 (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
345 !(start->flags & SERV_LITERAL_ADDRESS))
9e4abcb5 346 {
1a6bca81
SK
347 int fd;
348
349 /* find server socket to use, may need to get random one. */
350 if (start->sfd)
351 fd = start->sfd->fd;
352 else
353 {
354#ifdef HAVE_IPV6
355 if (start->addr.sa.sa_family == AF_INET6)
356 {
357 if (!forward->rfd6 &&
358 !(forward->rfd6 = allocate_rfd(AF_INET6)))
359 break;
3927da46 360 daemon->rfd_save = forward->rfd6;
1a6bca81
SK
361 fd = forward->rfd6->fd;
362 }
363 else
364#endif
365 {
366 if (!forward->rfd4 &&
367 !(forward->rfd4 = allocate_rfd(AF_INET)))
368 break;
3927da46 369 daemon->rfd_save = forward->rfd4;
1a6bca81
SK
370 fd = forward->rfd4->fd;
371 }
7de060b0
SK
372
373#ifdef HAVE_CONNTRACK
374 /* Copy connection mark of incoming query to outgoing connection. */
375 if (option_bool(OPT_CONNTRACK))
376 {
377 unsigned int mark;
378 if (get_incoming_mark(udpaddr, dst_addr, 0, &mark))
379 setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
380 }
381#endif
1a6bca81
SK
382 }
383
384 if (sendto(fd, (char *)header, plen, 0,
feba5c1d 385 &start->addr.sa,
fd9fa481
SK
386 sa_len(&start->addr)) == -1)
387 {
388 if (retry_send())
389 continue;
390 }
391 else
9e4abcb5 392 {
cdeda28f
SK
393 /* Keep info in case we want to re-send this packet */
394 daemon->srv_save = start;
395 daemon->packet_len = plen;
396
de37951c 397 if (!gotname)
3be34541 398 strcpy(daemon->namebuff, "query");
de37951c 399 if (start->addr.sa.sa_family == AF_INET)
3be34541 400 log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
1a6bca81 401 (struct all_addr *)&start->addr.in.sin_addr, NULL);
de37951c
SK
402#ifdef HAVE_IPV6
403 else
3be34541 404 log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
1a6bca81 405 (struct all_addr *)&start->addr.in6.sin6_addr, NULL);
de37951c 406#endif
824af85b 407 start->queries++;
de37951c
SK
408 forwarded = 1;
409 forward->sentto = start;
0a852541 410 if (!forward->forwardall)
de37951c 411 break;
0a852541 412 forward->forwardall++;
9e4abcb5
SK
413 }
414 }
415
de37951c 416 if (!(start = start->next))
3be34541 417 start = daemon->servers;
9e4abcb5 418
de37951c 419 if (start == firstsentto)
9e4abcb5
SK
420 break;
421 }
422
de37951c 423 if (forwarded)
824af85b 424 return 1;
de37951c 425
9e4abcb5
SK
426 /* could not send on, prepare to return */
427 header->id = htons(forward->orig_id);
1a6bca81 428 free_frec(forward); /* cancel */
9e4abcb5
SK
429 }
430
431 /* could not send on, return empty answer or address if known for whole domain */
b8187c80
SK
432 if (udpfd != -1)
433 {
cdeda28f 434 plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl);
28866e95 435 send_from(udpfd, option_bool(OPT_NOWILD), (char *)header, plen, udpaddr, dst_addr, dst_iface);
b8187c80
SK
436 }
437
824af85b 438 return 0;
9e4abcb5
SK
439}
440
572b41eb 441static size_t process_reply(struct dns_header *header, time_t now,
28866e95 442 struct server *server, size_t n, int check_rebind, int checking_disabled)
feba5c1d 443{
36717eee 444 unsigned char *pheader, *sizep;
832af0ba 445 int munged = 0, is_sign;
cdeda28f
SK
446 size_t plen;
447
feba5c1d 448 /* If upstream is advertising a larger UDP packet size
9009d746
SK
449 than we allow, trim it so that we don't get overlarge
450 requests for the client. We can't do this for signed packets. */
feba5c1d 451
832af0ba 452 if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign)) && !is_sign)
feba5c1d
SK
453 {
454 unsigned short udpsz;
36717eee 455 unsigned char *psave = sizep;
feba5c1d 456
36717eee 457 GETSHORT(udpsz, sizep);
3be34541
SK
458 if (udpsz > daemon->edns_pktsz)
459 PUTSHORT(daemon->edns_pktsz, psave);
feba5c1d
SK
460 }
461
28866e95
SK
462 /* RFC 4035 sect 4.6 para 3 */
463 if (!is_sign && !option_bool(OPT_DNSSEC))
572b41eb 464 header->hb4 &= ~HB4_AD;
28866e95 465
572b41eb 466 if (OPCODE(header) != QUERY || (RCODE(header) != NOERROR && RCODE(header) != NXDOMAIN))
0a852541
SK
467 return n;
468
feba5c1d 469 /* Complain loudly if the upstream server is non-recursive. */
572b41eb 470 if (!(header->hb4 & HB4_RA) && RCODE(header) == NOERROR && ntohs(header->ancount) == 0 &&
0a852541 471 server && !(server->flags & SERV_WARNED_RECURSIVE))
feba5c1d 472 {
3d8df260 473 prettyprint_addr(&server->addr, daemon->namebuff);
f2621c7f 474 my_syslog(LOG_WARNING, _("nameserver %s refused to do a recursive query"), daemon->namebuff);
28866e95 475 if (!option_bool(OPT_LOG))
0a852541
SK
476 server->flags |= SERV_WARNED_RECURSIVE;
477 }
478
572b41eb 479 if (daemon->bogus_addr && RCODE(header) != NXDOMAIN &&
fd9fa481 480 check_for_bogus_wildcard(header, n, daemon->namebuff, daemon->bogus_addr, now))
feba5c1d 481 {
fd9fa481 482 munged = 1;
572b41eb
SK
483 SET_RCODE(header, NXDOMAIN);
484 header->hb3 &= ~HB3_AA;
36717eee 485 }
fd9fa481 486 else
36717eee 487 {
572b41eb 488 if (RCODE(header) == NXDOMAIN &&
fd9fa481 489 extract_request(header, n, daemon->namebuff, NULL) &&
5aabfc78 490 check_for_local_domain(daemon->namebuff, now))
36717eee
SK
491 {
492 /* if we forwarded a query for a locally known name (because it was for
493 an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
494 since we know that the domain exists, even if upstream doesn't */
fd9fa481 495 munged = 1;
572b41eb
SK
496 header->hb3 |= HB3_AA;
497 SET_RCODE(header, NOERROR);
feba5c1d 498 }
832af0ba 499
28866e95 500 if (extract_addresses(header, n, daemon->namebuff, now, is_sign, check_rebind, checking_disabled))
824af85b 501 {
8ef5ada2 502 my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
824af85b
SK
503 munged = 1;
504 }
feba5c1d 505 }
fd9fa481
SK
506
507 /* do this after extract_addresses. Ensure NODATA reply and remove
508 nameserver info. */
509
510 if (munged)
511 {
512 header->ancount = htons(0);
513 header->nscount = htons(0);
514 header->arcount = htons(0);
515 }
516
36717eee
SK
517 /* the bogus-nxdomain stuff, doctor and NXDOMAIN->NODATA munging can all elide
518 sections of the packet. Find the new length here and put back pseudoheader
519 if it was removed. */
520 return resize_packet(header, n, pheader, plen);
feba5c1d
SK
521}
522
3be34541 523/* sets new last_server */
1a6bca81 524void reply_query(int fd, int family, time_t now)
9e4abcb5
SK
525{
526 /* packet from peer server, extract data for cache, and send to
527 original requester */
572b41eb 528 struct dns_header *header;
de37951c 529 union mysockaddr serveraddr;
832af0ba 530 struct frec *forward;
de37951c 531 socklen_t addrlen = sizeof(serveraddr);
1a6bca81 532 ssize_t n = recvfrom(fd, daemon->packet, daemon->edns_pktsz, 0, &serveraddr.sa, &addrlen);
cdeda28f 533 size_t nn;
1a6bca81
SK
534 struct server *server;
535
cdeda28f
SK
536 /* packet buffer overwritten */
537 daemon->srv_save = NULL;
832af0ba 538
de37951c 539 /* Determine the address of the server replying so that we can mark that as good */
1a6bca81 540 serveraddr.sa.sa_family = family;
de37951c
SK
541#ifdef HAVE_IPV6
542 if (serveraddr.sa.sa_family == AF_INET6)
5e9e0efb 543 serveraddr.in6.sin6_flowinfo = 0;
de37951c 544#endif
9e4abcb5 545
1a6bca81
SK
546 /* spoof check: answer must come from known server, */
547 for (server = daemon->servers; server; server = server->next)
548 if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) &&
549 sockaddr_isequal(&server->addr, &serveraddr))
550 break;
551
572b41eb 552 header = (struct dns_header *)daemon->packet;
fd9fa481 553
1a6bca81 554 if (!server ||
572b41eb 555 n < (int)sizeof(struct dns_header) || !(header->hb3 & HB3_QR) ||
1a6bca81
SK
556 !(forward = lookup_frec(ntohs(header->id), questions_crc(header, n, daemon->namebuff))))
557 return;
558
559 server = forward->sentto;
560
572b41eb 561 if ((RCODE(header) == SERVFAIL || RCODE(header) == REFUSED) &&
28866e95 562 !option_bool(OPT_ORDER) &&
1a6bca81
SK
563 forward->forwardall == 0)
564 /* for broken servers, attempt to send to another one. */
9e4abcb5 565 {
1a6bca81
SK
566 unsigned char *pheader;
567 size_t plen;
568 int is_sign;
832af0ba 569
1a6bca81
SK
570 /* recreate query from reply */
571 pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign);
572 if (!is_sign)
832af0ba 573 {
1a6bca81
SK
574 header->ancount = htons(0);
575 header->nscount = htons(0);
576 header->arcount = htons(0);
577 if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
832af0ba 578 {
572b41eb 579 header->hb3 &= ~(HB3_QR | HB3_TC);
1a6bca81
SK
580 forward_query(-1, NULL, NULL, 0, header, nn, now, forward);
581 return;
832af0ba 582 }
832af0ba 583 }
1a6bca81
SK
584 }
585
586 if ((forward->sentto->flags & SERV_TYPE) == 0)
587 {
572b41eb 588 if (RCODE(header) == SERVFAIL || RCODE(header) == REFUSED)
1a6bca81
SK
589 server = NULL;
590 else
b8187c80 591 {
1a6bca81
SK
592 struct server *last_server;
593
594 /* find good server by address if possible, otherwise assume the last one we sent to */
595 for (last_server = daemon->servers; last_server; last_server = last_server->next)
596 if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) &&
597 sockaddr_isequal(&last_server->addr, &serveraddr))
598 {
599 server = last_server;
600 break;
601 }
602 }
28866e95 603 if (!option_bool(OPT_ALL_SERVERS))
1a6bca81
SK
604 daemon->last_server = server;
605 }
606
607 /* If the answer is an error, keep the forward record in place in case
608 we get a good reply from another server. Kill it when we've
609 had replies from all to avoid filling the forwarding table when
610 everything is broken */
611 if (forward->forwardall == 0 || --forward->forwardall == 1 ||
572b41eb 612 (RCODE(header) != REFUSED && RCODE(header) != SERVFAIL))
1a6bca81 613 {
28866e95 614 int check_rebind = !(forward->flags & FREC_NOREBIND);
8ef5ada2 615
28866e95 616 if (!option_bool(OPT_NO_REBIND))
8ef5ada2
SK
617 check_rebind = 0;
618
28866e95 619 if ((nn = process_reply(header, now, server, (size_t)n, check_rebind, forward->flags & FREC_CHECKING_DISABLED)))
1a6bca81
SK
620 {
621 header->id = htons(forward->orig_id);
572b41eb 622 header->hb4 |= HB4_RA; /* recursion if available */
28866e95 623 send_from(forward->fd, option_bool(OPT_NOWILD), daemon->packet, nn,
1a6bca81 624 &forward->source, &forward->dest, forward->iface);
b8187c80 625 }
1a6bca81 626 free_frec(forward); /* cancel */
9e4abcb5 627 }
9e4abcb5 628}
44a2a316 629
1a6bca81 630
5aabfc78 631void receive_query(struct listener *listen, time_t now)
44a2a316 632{
572b41eb 633 struct dns_header *header = (struct dns_header *)daemon->packet;
44a2a316 634 union mysockaddr source_addr;
c1bb8504 635 unsigned short type;
44a2a316 636 struct all_addr dst_addr;
f6b7dc47 637 struct in_addr netmask, dst_addr_4;
cdeda28f
SK
638 size_t m;
639 ssize_t n;
640 int if_index = 0;
44a2a316
SK
641 struct iovec iov[1];
642 struct msghdr msg;
643 struct cmsghdr *cmptr;
44a2a316
SK
644 union {
645 struct cmsghdr align; /* this ensures alignment */
646#ifdef HAVE_IPV6
647 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
648#endif
5e9e0efb 649#if defined(HAVE_LINUX_NETWORK)
44a2a316 650 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
824af85b
SK
651#elif defined(IP_RECVDSTADDR) && defined(HAVE_SOLARIS_NETWORK)
652 char control[CMSG_SPACE(sizeof(struct in_addr)) +
653 CMSG_SPACE(sizeof(unsigned int))];
44a2a316
SK
654#elif defined(IP_RECVDSTADDR)
655 char control[CMSG_SPACE(sizeof(struct in_addr)) +
656 CMSG_SPACE(sizeof(struct sockaddr_dl))];
657#endif
658 } control_u;
659
cdeda28f
SK
660 /* packet buffer overwritten */
661 daemon->srv_save = NULL;
662
28866e95 663 if (listen->family == AF_INET && option_bool(OPT_NOWILD))
f6b7dc47
SK
664 {
665 dst_addr_4 = listen->iface->addr.in.sin_addr;
666 netmask = listen->iface->netmask;
667 }
668 else
3d8df260
SK
669 {
670 dst_addr_4.s_addr = 0;
671 netmask.s_addr = 0;
672 }
f6b7dc47 673
3be34541
SK
674 iov[0].iov_base = daemon->packet;
675 iov[0].iov_len = daemon->edns_pktsz;
44a2a316
SK
676
677 msg.msg_control = control_u.control;
678 msg.msg_controllen = sizeof(control_u);
679 msg.msg_flags = 0;
680 msg.msg_name = &source_addr;
681 msg.msg_namelen = sizeof(source_addr);
682 msg.msg_iov = iov;
683 msg.msg_iovlen = 1;
684
de37951c 685 if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
3be34541 686 return;
44a2a316 687
572b41eb 688 if (n < (int)sizeof(struct dns_header) ||
5e9e0efb 689 (msg.msg_flags & MSG_TRUNC) ||
572b41eb 690 (header->hb3 & HB3_QR))
26128d27
SK
691 return;
692
44a2a316
SK
693 source_addr.sa.sa_family = listen->family;
694#ifdef HAVE_IPV6
695 if (listen->family == AF_INET6)
5e9e0efb 696 source_addr.in6.sin6_flowinfo = 0;
44a2a316 697#endif
28866e95
SK
698
699 if (!option_bool(OPT_NOWILD))
26128d27
SK
700 {
701 struct ifreq ifr;
702
703 if (msg.msg_controllen < sizeof(struct cmsghdr))
704 return;
44a2a316 705
5e9e0efb 706#if defined(HAVE_LINUX_NETWORK)
26128d27
SK
707 if (listen->family == AF_INET)
708 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
c72daea8 709 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
26128d27 710 {
8ef5ada2
SK
711 union {
712 unsigned char *c;
713 struct in_pktinfo *p;
714 } p;
715 p.c = CMSG_DATA(cmptr);
716 dst_addr_4 = dst_addr.addr.addr4 = p.p->ipi_spec_dst;
717 if_index = p.p->ipi_ifindex;
26128d27
SK
718 }
719#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
720 if (listen->family == AF_INET)
44a2a316 721 {
26128d27 722 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
8ef5ada2
SK
723 {
724 union {
725 unsigned char *c;
726 unsigned int *i;
727 struct in_addr *a;
728#ifndef HAVE_SOLARIS_NETWORK
729 struct sockaddr_dl *s;
730#endif
731 } p;
732 p.c = CMSG_DATA(cmptr);
733 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
734 dst_addr_4 = dst_addr.addr.addr4 = *(p.a);
735 else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
824af85b 736#ifdef HAVE_SOLARIS_NETWORK
8ef5ada2 737 if_index = *(p.i);
824af85b 738#else
8ef5ada2 739 if_index = p.s->sdl_index;
824af85b 740#endif
8ef5ada2 741 }
44a2a316 742 }
44a2a316 743#endif
26128d27 744
44a2a316 745#ifdef HAVE_IPV6
26128d27
SK
746 if (listen->family == AF_INET6)
747 {
748 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
c72daea8 749 if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
26128d27 750 {
8ef5ada2
SK
751 union {
752 unsigned char *c;
753 struct in6_pktinfo *p;
754 } p;
755 p.c = CMSG_DATA(cmptr);
756
757 dst_addr.addr.addr6 = p.p->ipi6_addr;
758 if_index = p.p->ipi6_ifindex;
26128d27
SK
759 }
760 }
44a2a316 761#endif
26128d27
SK
762
763 /* enforce available interface configuration */
764
7622fc06 765 if (!indextoname(listen->fd, if_index, ifr.ifr_name) ||
c72daea8 766 !iface_check(listen->family, &dst_addr, ifr.ifr_name))
5e9e0efb 767 return;
832af0ba
SK
768
769 if (listen->family == AF_INET &&
28866e95 770 option_bool(OPT_LOCALISE) &&
832af0ba
SK
771 ioctl(listen->fd, SIOCGIFNETMASK, &ifr) == -1)
772 return;
773
774 netmask = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
44a2a316
SK
775 }
776
cdeda28f 777 if (extract_request(header, (size_t)n, daemon->namebuff, &type))
44a2a316 778 {
1a6bca81
SK
779 char types[20];
780
781 querystr(types, type);
782
44a2a316 783 if (listen->family == AF_INET)
3be34541 784 log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
1a6bca81 785 (struct all_addr *)&source_addr.in.sin_addr, types);
44a2a316
SK
786#ifdef HAVE_IPV6
787 else
3be34541 788 log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
1a6bca81 789 (struct all_addr *)&source_addr.in6.sin6_addr, types);
44a2a316
SK
790#endif
791 }
792
5aabfc78 793 m = answer_request (header, ((char *) header) + PACKETSZ, (size_t)n,
f6b7dc47 794 dst_addr_4, netmask, now);
44a2a316 795 if (m >= 1)
824af85b 796 {
28866e95 797 send_from(listen->fd, option_bool(OPT_NOWILD), (char *)header,
824af85b
SK
798 m, &source_addr, &dst_addr, if_index);
799 daemon->local_answer++;
800 }
801 else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
802 header, (size_t)n, now, NULL))
803 daemon->queries_forwarded++;
44a2a316 804 else
824af85b 805 daemon->local_answer++;
44a2a316
SK
806}
807
feba5c1d
SK
808/* The daemon forks before calling this: it should deal with one connection,
809 blocking as neccessary, and then return. Note, need to be a bit careful
810 about resources for debug mode, when the fork is suppressed: that's
811 done by the caller. */
5aabfc78 812unsigned char *tcp_request(int confd, time_t now,
7de060b0 813 union mysockaddr *local_addr, struct in_addr netmask)
feba5c1d 814{
28866e95
SK
815 size_t size = 0;
816 int norebind = 0;
817 int checking_disabled;
cdeda28f 818 size_t m;
c1bb8504 819 unsigned short qtype, gotname;
feba5c1d
SK
820 unsigned char c1, c2;
821 /* Max TCP packet + slop */
5aabfc78 822 unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ);
572b41eb 823 struct dns_header *header;
3be34541 824 struct server *last_server;
7de060b0
SK
825 struct in_addr dst_addr_4;
826 union mysockaddr peer_addr;
827 socklen_t peer_len = sizeof(union mysockaddr);
3be34541 828
7de060b0
SK
829 if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
830 return packet;
831
feba5c1d
SK
832 while (1)
833 {
834 if (!packet ||
835 !read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
836 !(size = c1 << 8 | c2) ||
837 !read_write(confd, packet, size, 1))
838 return packet;
839
572b41eb 840 if (size < (int)sizeof(struct dns_header))
feba5c1d
SK
841 continue;
842
572b41eb 843 header = (struct dns_header *)packet;
28866e95
SK
844
845 /* save state of "cd" flag in query */
572b41eb 846 checking_disabled = header->hb4 & HB4_CD;
28866e95
SK
847
848 /* RFC 4035: sect 4.6 para 2 */
572b41eb 849 header->hb4 &= ~HB4_AD;
feba5c1d 850
3be34541 851 if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
feba5c1d 852 {
7de060b0 853 char types[20];
feba5c1d 854
7de060b0
SK
855 querystr(types, qtype);
856
857 if (peer_addr.sa.sa_family == AF_INET)
858 log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
859 (struct all_addr *)&peer_addr.in.sin_addr, types);
feba5c1d 860#ifdef HAVE_IPV6
7de060b0
SK
861 else
862 log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
863 (struct all_addr *)&peer_addr.in6.sin6_addr, types);
feba5c1d 864#endif
feba5c1d
SK
865 }
866
7de060b0
SK
867 if (local_addr->sa.sa_family == AF_INET)
868 dst_addr_4 = local_addr->in.sin_addr;
869 else
870 dst_addr_4.s_addr = 0;
871
feba5c1d 872 /* m > 0 if answered from cache */
5aabfc78 873 m = answer_request(header, ((char *) header) + 65536, (unsigned int)size,
7de060b0 874 dst_addr_4, netmask, now);
5aabfc78
SK
875
876 /* Do this by steam now we're not in the select() loop */
877 check_log_writer(NULL);
feba5c1d
SK
878
879 if (m == 0)
880 {
28866e95 881 unsigned int flags = 0;
feba5c1d
SK
882 struct all_addr *addrp = NULL;
883 int type = 0;
884 char *domain = NULL;
28866e95
SK
885
886 if (option_bool(OPT_ADD_MAC))
7de060b0
SK
887 size = add_mac(header, size, ((char *) header) + 65536, &peer_addr);
888
feba5c1d 889 if (gotname)
8ef5ada2 890 flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
feba5c1d 891
28866e95 892 if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server)
3be34541
SK
893 last_server = daemon->servers;
894 else
895 last_server = daemon->last_server;
feba5c1d
SK
896
897 if (!flags && last_server)
898 {
899 struct server *firstsendto = NULL;
0a852541
SK
900 unsigned int crc = questions_crc(header, (unsigned int)size, daemon->namebuff);
901
feba5c1d
SK
902 /* Loop round available servers until we succeed in connecting to one.
903 Note that this code subtley ensures that consecutive queries on this connection
904 which can go to the same server, do so. */
905 while (1)
8ef5ada2 906 {
feba5c1d
SK
907 if (!firstsendto)
908 firstsendto = last_server;
909 else
910 {
911 if (!(last_server = last_server->next))
3be34541 912 last_server = daemon->servers;
feba5c1d
SK
913
914 if (last_server == firstsendto)
915 break;
916 }
917
918 /* server for wrong domain */
919 if (type != (last_server->flags & SERV_TYPE) ||
920 (type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)))
921 continue;
7de060b0
SK
922
923 if (last_server->tcpfd == -1)
feba5c1d 924 {
7de060b0
SK
925 if ((last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
926 continue;
927
928 if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 1) ||
929 connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1))
930 {
931 close(last_server->tcpfd);
932 last_server->tcpfd = -1;
933 continue;
934 }
935
936#ifdef HAVE_CONNTRACK
937 /* Copy connection mark of incoming query to outgoing connection. */
938 if (option_bool(OPT_CONNTRACK))
939 {
940 unsigned int mark;
941 struct all_addr local;
942#ifdef HAVE_IPV6
943 if (local_addr->sa.sa_family == AF_INET6)
944 local.addr.addr6 = local_addr->in6.sin6_addr;
945 else
946#endif
947 local.addr.addr4 = local_addr->in.sin_addr;
948
949 if (get_incoming_mark(&peer_addr, &local, 1, &mark))
950 setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
951 }
952#endif
feba5c1d 953 }
824af85b 954
feba5c1d
SK
955 c1 = size >> 8;
956 c2 = size;
957
958 if (!read_write(last_server->tcpfd, &c1, 1, 0) ||
959 !read_write(last_server->tcpfd, &c2, 1, 0) ||
960 !read_write(last_server->tcpfd, packet, size, 0) ||
961 !read_write(last_server->tcpfd, &c1, 1, 1) ||
962 !read_write(last_server->tcpfd, &c2, 1, 1))
963 {
964 close(last_server->tcpfd);
965 last_server->tcpfd = -1;
966 continue;
967 }
824af85b 968
feba5c1d
SK
969 m = (c1 << 8) | c2;
970 if (!read_write(last_server->tcpfd, packet, m, 1))
971 return packet;
972
973 if (!gotname)
3be34541 974 strcpy(daemon->namebuff, "query");
feba5c1d 975 if (last_server->addr.sa.sa_family == AF_INET)
3be34541 976 log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
1a6bca81 977 (struct all_addr *)&last_server->addr.in.sin_addr, NULL);
feba5c1d
SK
978#ifdef HAVE_IPV6
979 else
3be34541 980 log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
1a6bca81 981 (struct all_addr *)&last_server->addr.in6.sin6_addr, NULL);
feba5c1d
SK
982#endif
983
984 /* There's no point in updating the cache, since this process will exit and
832af0ba 985 lose the information after a few queries. We make this call for the alias and
feba5c1d 986 bogus-nxdomain side-effects. */
832af0ba
SK
987 /* If the crc of the question section doesn't match the crc we sent, then
988 someone might be attempting to insert bogus values into the cache by
989 sending replies containing questions and bogus answers. */
990 if (crc == questions_crc(header, (unsigned int)m, daemon->namebuff))
28866e95
SK
991 m = process_reply(header, now, last_server, (unsigned int)m,
992 option_bool(OPT_NO_REBIND) && !norebind, checking_disabled);
feba5c1d
SK
993
994 break;
995 }
996 }
997
998 /* In case of local answer or no connections made. */
999 if (m == 0)
3be34541 1000 m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl);
feba5c1d 1001 }
5aabfc78
SK
1002
1003 check_log_writer(NULL);
feba5c1d
SK
1004
1005 c1 = m>>8;
1006 c2 = m;
1007 if (!read_write(confd, &c1, 1, 0) ||
1008 !read_write(confd, &c2, 1, 0) ||
1009 !read_write(confd, packet, m, 0))
1010 return packet;
1011 }
1012}
1013
1697269c 1014static struct frec *allocate_frec(time_t now)
9e4abcb5 1015{
1697269c
SK
1016 struct frec *f;
1017
5aabfc78 1018 if ((f = (struct frec *)whine_malloc(sizeof(struct frec))))
9e4abcb5 1019 {
1a6bca81 1020 f->next = daemon->frec_list;
1697269c 1021 f->time = now;
832af0ba 1022 f->sentto = NULL;
1a6bca81 1023 f->rfd4 = NULL;
28866e95 1024 f->flags = 0;
1a6bca81
SK
1025#ifdef HAVE_IPV6
1026 f->rfd6 = NULL;
1027#endif
1028 daemon->frec_list = f;
1697269c 1029 }
9e4abcb5 1030
1697269c
SK
1031 return f;
1032}
9e4abcb5 1033
1a6bca81
SK
1034static struct randfd *allocate_rfd(int family)
1035{
1036 static int finger = 0;
1037 int i;
1038
1039 /* limit the number of sockets we have open to avoid starvation of
1040 (eg) TFTP. Once we have a reasonable number, randomness should be OK */
1041
1042 for (i = 0; i < RANDOM_SOCKS; i++)
9009d746 1043 if (daemon->randomsocks[i].refcount == 0)
1a6bca81 1044 {
9009d746
SK
1045 if ((daemon->randomsocks[i].fd = random_sock(family)) == -1)
1046 break;
1047
1a6bca81
SK
1048 daemon->randomsocks[i].refcount = 1;
1049 daemon->randomsocks[i].family = family;
1050 return &daemon->randomsocks[i];
1051 }
1052
9009d746 1053 /* No free ones or cannot get new socket, grab an existing one */
1a6bca81
SK
1054 for (i = 0; i < RANDOM_SOCKS; i++)
1055 {
1056 int j = (i+finger) % RANDOM_SOCKS;
9009d746
SK
1057 if (daemon->randomsocks[j].refcount != 0 &&
1058 daemon->randomsocks[j].family == family &&
1059 daemon->randomsocks[j].refcount != 0xffff)
1a6bca81
SK
1060 {
1061 finger = j;
1062 daemon->randomsocks[j].refcount++;
1063 return &daemon->randomsocks[j];
1064 }
1065 }
1066
1067 return NULL; /* doom */
1068}
1069
1070static void free_frec(struct frec *f)
1071{
1072 if (f->rfd4 && --(f->rfd4->refcount) == 0)
1073 close(f->rfd4->fd);
1074
1075 f->rfd4 = NULL;
1076 f->sentto = NULL;
28866e95 1077 f->flags = 0;
1a6bca81
SK
1078
1079#ifdef HAVE_IPV6
1080 if (f->rfd6 && --(f->rfd6->refcount) == 0)
1081 close(f->rfd6->fd);
1082
1083 f->rfd6 = NULL;
1084#endif
1085}
1086
1697269c
SK
1087/* if wait==NULL return a free or older than TIMEOUT record.
1088 else return *wait zero if one available, or *wait is delay to
1a6bca81
SK
1089 when the oldest in-use record will expire. Impose an absolute
1090 limit of 4*TIMEOUT before we wipe things (for random sockets) */
5aabfc78 1091struct frec *get_new_frec(time_t now, int *wait)
1697269c 1092{
1a6bca81 1093 struct frec *f, *oldest, *target;
1697269c
SK
1094 int count;
1095
1096 if (wait)
1097 *wait = 0;
1098
1a6bca81 1099 for (f = daemon->frec_list, oldest = NULL, target = NULL, count = 0; f; f = f->next, count++)
832af0ba 1100 if (!f->sentto)
1a6bca81
SK
1101 target = f;
1102 else
1697269c 1103 {
1a6bca81
SK
1104 if (difftime(now, f->time) >= 4*TIMEOUT)
1105 {
1106 free_frec(f);
1107 target = f;
1108 }
1109
1110 if (!oldest || difftime(f->time, oldest->time) <= 0)
1111 oldest = f;
1697269c 1112 }
1a6bca81
SK
1113
1114 if (target)
1115 {
1116 target->time = now;
1117 return target;
1118 }
9e4abcb5
SK
1119
1120 /* can't find empty one, use oldest if there is one
1121 and it's older than timeout */
1697269c 1122 if (oldest && ((int)difftime(now, oldest->time)) >= TIMEOUT)
9e4abcb5 1123 {
1697269c
SK
1124 /* keep stuff for twice timeout if we can by allocating a new
1125 record instead */
1126 if (difftime(now, oldest->time) < 2*TIMEOUT &&
1127 count <= daemon->ftabsize &&
1128 (f = allocate_frec(now)))
1129 return f;
1130
1131 if (!wait)
1132 {
1a6bca81 1133 free_frec(oldest);
1697269c
SK
1134 oldest->time = now;
1135 }
9e4abcb5
SK
1136 return oldest;
1137 }
1138
1697269c 1139 /* none available, calculate time 'till oldest record expires */
208b65c5 1140 if (count > daemon->ftabsize)
1697269c
SK
1141 {
1142 if (oldest && wait)
1143 *wait = oldest->time + (time_t)TIMEOUT - now;
9e4abcb5
SK
1144 return NULL;
1145 }
1697269c
SK
1146
1147 if (!(f = allocate_frec(now)) && wait)
1148 /* wait one second on malloc failure */
1149 *wait = 1;
9e4abcb5 1150
9e4abcb5
SK
1151 return f; /* OK if malloc fails and this is NULL */
1152}
1153
832af0ba
SK
1154/* crc is all-ones if not known. */
1155static struct frec *lookup_frec(unsigned short id, unsigned int crc)
9e4abcb5
SK
1156{
1157 struct frec *f;
1158
1a6bca81 1159 for(f = daemon->frec_list; f; f = f->next)
832af0ba
SK
1160 if (f->sentto && f->new_id == id &&
1161 (f->crc == crc || crc == 0xffffffff))
9e4abcb5
SK
1162 return f;
1163
1164 return NULL;
1165}
1166
1167static struct frec *lookup_frec_by_sender(unsigned short id,
fd9fa481
SK
1168 union mysockaddr *addr,
1169 unsigned int crc)
9e4abcb5 1170{
feba5c1d
SK
1171 struct frec *f;
1172
1a6bca81 1173 for(f = daemon->frec_list; f; f = f->next)
832af0ba 1174 if (f->sentto &&
9e4abcb5 1175 f->orig_id == id &&
fd9fa481 1176 f->crc == crc &&
9e4abcb5
SK
1177 sockaddr_isequal(&f->source, addr))
1178 return f;
1179
1180 return NULL;
1181}
1182
849a8357 1183/* A server record is going away, remove references to it */
5aabfc78 1184void server_gone(struct server *server)
849a8357
SK
1185{
1186 struct frec *f;
1187
1a6bca81 1188 for (f = daemon->frec_list; f; f = f->next)
832af0ba 1189 if (f->sentto && f->sentto == server)
1a6bca81 1190 free_frec(f);
849a8357
SK
1191
1192 if (daemon->last_server == server)
1193 daemon->last_server = NULL;
1194
1195 if (daemon->srv_save == server)
1196 daemon->srv_save = NULL;
1197}
9e4abcb5 1198
316e2730
SK
1199/* return unique random ids. */
1200static unsigned short get_id(unsigned int crc)
9e4abcb5
SK
1201{
1202 unsigned short ret = 0;
832af0ba 1203
316e2730 1204 do
832af0ba
SK
1205 ret = rand16();
1206 while (lookup_frec(ret, crc));
1207
9e4abcb5
SK
1208 return ret;
1209}
1210
1211
1212
1213
1214