]> git.ipfire.org Git - people/ms/dnsmasq.git/blame - src/forward.c
import of dnsmasq-2.9.tar.gz
[people/ms/dnsmasq.git] / src / forward.c
CommitLineData
9e4abcb5
SK
1/* dnsmasq is Copyright (c) 2000 - 2003 Simon Kelley
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
5 the Free Software Foundation; version 2 dated June, 1991.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11*/
12
13/* Author's email: simon@thekelleys.org.uk */
14
15#include "dnsmasq.h"
16
17static struct frec *frec_list;
18
19static struct frec *get_new_frec(time_t now);
20static struct frec *lookup_frec(unsigned short id);
21static struct frec *lookup_frec_by_sender(unsigned short id,
22 union mysockaddr *addr);
23static unsigned short get_id(void);
24
25/* May be called more than once. */
26void forward_init(int first)
27{
28 struct frec *f;
29
30 if (first)
31 frec_list = NULL;
32 for (f = frec_list; f; f = f->next)
33 f->new_id = 0;
34}
35
44a2a316
SK
36/* Send a UDP packet with it's source address set as "source"
37 unless nowild is true, when we just send it with the kernel default */
38static void send_from(int fd, int nowild, char *packet, int len,
39 union mysockaddr *to, struct all_addr *source)
9e4abcb5 40{
44a2a316
SK
41 struct msghdr msg;
42 struct iovec iov[1];
43 struct cmsghdr *cmptr;
44 union {
45 struct cmsghdr align; /* this ensures alignment */
46#if defined(IP_PKTINFO)
47 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
48#elif defined(IP_SENDSRCADDR)
49 char control[CMSG_SPACE(sizeof(struct in_addr))];
50#endif
51#ifdef HAVE_IPV6
52 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
53#endif
54 } control_u;
55
56 iov[0].iov_base = packet;
57 iov[0].iov_len = len;
58
59 if (nowild)
60 {
61 msg.msg_control = NULL;
62 msg.msg_controllen = 0;
63 }
64 else
65 {
66 msg.msg_control = &control_u;
67 msg.msg_controllen = sizeof(control_u);
68 }
69 msg.msg_flags = 0;
70 msg.msg_name = to;
71 msg.msg_namelen = sa_len(to);
72 msg.msg_iov = iov;
73 msg.msg_iovlen = 1;
74
75 cmptr = CMSG_FIRSTHDR(&msg);
9e4abcb5 76
44a2a316
SK
77#if defined(IP_PKTINFO)
78 if (!nowild && to->sa.sa_family == AF_INET)
79 {
80 struct in_pktinfo *pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
81 pkt->ipi_ifindex = 0;
82 pkt->ipi_spec_dst = source->addr.addr4;
83 msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
84 cmptr->cmsg_level = SOL_IP;
85 cmptr->cmsg_type = IP_PKTINFO;
86 }
87#elif defined(IP_SENDSRCADDR)
88 if (!nowild && to->sa.sa_family == AF_INET)
89 {
90 struct in_addr *a = (struct in_addr *)CMSG_DATA(cmptr);
91 *a = source->addr.addr4;
92 msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
93 cmptr->cmsg_level = IPPROTO_IP;
94 cmptr->cmsg_type = IP_SENDSRCADDR;
95 }
96#endif
97
98#ifdef HAVE_IPV6
99 if (!nowild && to->sa.sa_family == AF_INET6)
100 {
101 struct in6_pktinfo *pkt = (struct in6_pktinfo *)CMSG_DATA(cmptr);
102 pkt->ipi6_ifindex = 0;
103 pkt->ipi6_addr = source->addr.addr6;
104 msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
105 cmptr->cmsg_type = IPV6_PKTINFO;
106 cmptr->cmsg_level = IPV6_LEVEL;
44a2a316
SK
107 }
108#endif
109
110 sendmsg(fd, &msg, 0);
9e4abcb5 111}
44a2a316
SK
112
113
9e4abcb5 114/* returns new last_server */
44a2a316
SK
115static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
116 struct all_addr *dst_addr, HEADER *header,
117 int plen, unsigned int options, char *dnamebuff,
118 struct server *servers, struct server *last_server,
119 time_t now, unsigned long local_ttl)
9e4abcb5
SK
120{
121 struct frec *forward;
122 char *domain = NULL;
de37951c 123 int forwardall = 0, type = 0;
9e4abcb5
SK
124 struct all_addr *addrp = NULL;
125 unsigned short flags = 0;
126 unsigned short gotname = extract_request(header, (unsigned int)plen, dnamebuff);
de37951c
SK
127 struct server *start = NULL;
128
9e4abcb5
SK
129 /* may be recursion not speced or no servers available. */
130 if (!header->rd || !servers)
131 forward = NULL;
132 else if ((forward = lookup_frec_by_sender(ntohs(header->id), udpaddr)))
133 {
de37951c 134 /* retry on existing query, send to all available servers */
9e4abcb5 135 domain = forward->sentto->domain;
de37951c
SK
136 if (!(options & OPT_ORDER))
137 {
138 forwardall = 1;
139 last_server = NULL;
140 }
9e4abcb5 141 type = forward->sentto->flags & SERV_TYPE;
de37951c
SK
142 if (!(start = forward->sentto->next))
143 start = servers; /* at end of list, recycle */
9e4abcb5
SK
144 header->id = htons(forward->new_id);
145 }
146 else
147 {
148 if (gotname)
149 {
150 /* If the query ends in the domain in one of our servers, set
151 domain to point to that name. We find the largest match to allow both
152 domain.org and sub.domain.org to exist. */
153
154 unsigned int namelen = strlen(dnamebuff);
155 unsigned int matchlen = 0;
de37951c
SK
156 struct server *serv;
157
9e4abcb5
SK
158 for (serv=servers; serv; serv=serv->next)
159 /* domain matches take priority over NODOTS matches */
160 if ((serv->flags & SERV_FOR_NODOTS) && type != SERV_HAS_DOMAIN && !strchr(dnamebuff, '.'))
161 {
de37951c
SK
162 unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
163 type = SERV_FOR_NODOTS;
164 flags = 0;
165 if ((serv->flags & SERV_LITERAL_ADDRESS) && (sflag & gotname))
9e4abcb5 166 {
de37951c
SK
167 flags = sflag;
168 if (serv->addr.sa.sa_family == AF_INET)
169 addrp = (struct all_addr *)&serv->addr.in.sin_addr;
9e4abcb5 170#ifdef HAVE_IPV6
de37951c
SK
171 else
172 addrp = (struct all_addr *)&serv->addr.in6.sin6_addr;
9e4abcb5 173#endif
9e4abcb5 174 }
9e4abcb5
SK
175 }
176 else if (serv->flags & SERV_HAS_DOMAIN)
177 {
178 unsigned int domainlen = strlen(serv->domain);
179 if (namelen >= domainlen &&
180 hostname_isequal(dnamebuff + namelen - domainlen, serv->domain) &&
a222641c 181 domainlen >= matchlen)
9e4abcb5 182 {
de37951c
SK
183 unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
184 type = SERV_HAS_DOMAIN;
185 domain = serv->domain;
186 matchlen = domainlen;
187 flags = 0;
188 if ((serv->flags & SERV_LITERAL_ADDRESS) && ((sflag | F_QUERY ) & gotname))
189 {
190 flags = gotname;
191 if (serv->addr.sa.sa_family == AF_INET)
192 addrp = (struct all_addr *)&serv->addr.in.sin_addr;
9e4abcb5 193#ifdef HAVE_IPV6
de37951c
SK
194 else
195 addrp = (struct all_addr *)&serv->addr.in6.sin6_addr;
9e4abcb5 196#endif
9e4abcb5
SK
197 }
198 }
199 }
200 }
201
202 if (flags) /* flags set here means a literal found */
44a2a316
SK
203 {
204 if (flags & F_QUERY)
205 log_query(F_CONFIG | F_FORWARD | F_NEG, dnamebuff, NULL);
206 else
207 log_query(F_CONFIG | F_FORWARD | flags, dnamebuff, addrp);
208 }
9e4abcb5
SK
209 else
210 {
211 /* we may by policy not forward names without a domain part */
212 if (gotname && (options & OPT_NODOTS_LOCAL) && !strchr(dnamebuff, '.'))
213 flags = F_NXDOMAIN;
214 else if (!(forward = get_new_frec(now)))
215 /* table full - server failure. */
216 flags = F_NEG;
217 }
218
219 if (forward)
220 {
221 /* In strict_order mode, or when using domain specific servers
222 always try servers in the order specified in resolv.conf,
223 otherwise, use the one last known to work. */
224
225 if (type != 0 || (options & OPT_ORDER))
de37951c
SK
226 start = servers;
227 else if (!(start = last_server))
228 {
229 start = servers;
230 forwardall = 1;
231 }
232
9e4abcb5 233 forward->source = *udpaddr;
44a2a316 234 forward->dest = *dst_addr;
9e4abcb5
SK
235 forward->new_id = get_id();
236 forward->fd = udpfd;
237 forward->orig_id = ntohs(header->id);
238 header->id = htons(forward->new_id);
239 }
240 }
241
242 /* check for send errors here (no route to host)
243 if we fail to send to all nameservers, send back an error
244 packet straight away (helps modem users when offline) */
245
246 if (!flags && forward)
247 {
de37951c
SK
248 struct server *firstsentto = start;
249 int forwarded = 0;
250
9e4abcb5
SK
251 while (1)
252 {
9e4abcb5
SK
253 /* only send to servers dealing with our domain.
254 domain may be NULL, in which case server->domain
255 must be NULL also. */
256
de37951c
SK
257 if (type == (start->flags & SERV_TYPE) &&
258 (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)))
9e4abcb5 259 {
de37951c 260 if (start->flags & SERV_NO_ADDR)
9e4abcb5 261 flags = F_NOERR; /* NULL servers are OK. */
de37951c
SK
262 else if (!(start->flags & SERV_LITERAL_ADDRESS) &&
263 sendto(start->sfd->fd, (char *)header, plen, 0,
264 &start->addr.sa,
265 sa_len(&start->addr)) != -1)
9e4abcb5 266 {
de37951c
SK
267 if (!gotname)
268 strcpy(dnamebuff, "query");
269 if (start->addr.sa.sa_family == AF_INET)
270 log_query(F_SERVER | F_IPV4 | F_FORWARD, dnamebuff,
271 (struct all_addr *)&start->addr.in.sin_addr);
272#ifdef HAVE_IPV6
273 else
274 log_query(F_SERVER | F_IPV6 | F_FORWARD, dnamebuff,
275 (struct all_addr *)&start->addr.in6.sin6_addr);
276#endif
277 forwarded = 1;
278 forward->sentto = start;
279 if (!forwardall)
280 break;
9e4abcb5
SK
281 }
282 }
283
de37951c
SK
284 if (!(start = start->next))
285 start = servers;
9e4abcb5 286
de37951c 287 if (start == firstsentto)
9e4abcb5
SK
288 break;
289 }
290
de37951c
SK
291 if (forwarded)
292 return last_server;
293
9e4abcb5
SK
294 /* could not send on, prepare to return */
295 header->id = htons(forward->orig_id);
296 forward->new_id = 0; /* cancel */
297 }
298
299 /* could not send on, return empty answer or address if known for whole domain */
300 plen = setup_reply(header, (unsigned int)plen, addrp, flags, local_ttl);
44a2a316
SK
301 send_from(udpfd, options & OPT_NOWILD, (char *)header, plen, udpaddr, dst_addr);
302
9e4abcb5
SK
303 if (flags & (F_NOERR | F_NXDOMAIN))
304 log_query(F_CONFIG | F_FORWARD | F_NEG | gotname | (flags & F_NXDOMAIN), dnamebuff, NULL);
305
306 return last_server;
307}
308
309/* returns new last_server */
de37951c
SK
310struct server *reply_query(struct serverfd *sfd, int options, char *packet, time_t now,
311 char *dnamebuff, struct server *servers, struct server *last_server,
1cff166d 312 struct bogus_addr *bogus_nxdomain, struct doctor *doctors)
9e4abcb5
SK
313{
314 /* packet from peer server, extract data for cache, and send to
315 original requester */
316 struct frec *forward;
317 HEADER *header;
de37951c
SK
318 union mysockaddr serveraddr;
319 socklen_t addrlen = sizeof(serveraddr);
320 int n = recvfrom(sfd->fd, packet, PACKETSZ, 0, &serveraddr.sa, &addrlen);
321
322 /* Determine the address of the server replying so that we can mark that as good */
323 serveraddr.sa.sa_family = sfd->source_addr.sa.sa_family;
324#ifdef HAVE_IPV6
325 if (serveraddr.sa.sa_family == AF_INET6)
326 serveraddr.in6.sin6_flowinfo = htonl(0);
327#endif
9e4abcb5
SK
328
329 header = (HEADER *)packet;
de37951c 330 if (n >= (int)sizeof(HEADER) && header->qr && (forward = lookup_frec(ntohs(header->id))))
9e4abcb5 331 {
de37951c
SK
332 /* find good server by address if possible, otherwise assume the last one we sent to */
333 if ((forward->sentto->flags & SERV_TYPE) == 0)
334 {
335 for (last_server = servers; last_server; last_server = last_server->next)
336 if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) &&
337 sockaddr_isequal(&last_server->addr, &serveraddr))
338 break;
339 if (!last_server)
340 last_server = forward->sentto;
341 }
342
343 /* Complain loudly if the upstream server is non-recursive. */
344 if (!header->ra && header->rcode == NOERROR && ntohs(header->ancount) == 0)
9e4abcb5 345 {
de37951c
SK
346 char addrbuff[ADDRSTRLEN];
347#ifdef HAVE_IPV6
348 if (serveraddr.sa.sa_family == AF_INET)
349 inet_ntop(AF_INET, &serveraddr.in.sin_addr, addrbuff, ADDRSTRLEN);
350 else if (serveraddr.sa.sa_family == AF_INET6)
351 inet_ntop(AF_INET6, &serveraddr.in6.sin6_addr, addrbuff, ADDRSTRLEN);
352#else
353 strcpy(addrbuff, inet_ntoa(serveraddr.in.sin_addr));
354#endif
355 syslog(LOG_WARNING, "nameserver %s refused to do a recursive query", addrbuff);
356 return NULL;
357 }
358
359 if ((header->rcode == NOERROR || header->rcode == NXDOMAIN) && header->opcode == QUERY)
360 {
361 if (!(bogus_nxdomain &&
362 header->rcode == NOERROR &&
363 check_for_bogus_wildcard(header, (unsigned int)n, dnamebuff, bogus_nxdomain, now)))
9e4abcb5 364 {
de37951c
SK
365 if (header->rcode == NOERROR && ntohs(header->ancount) != 0)
366 extract_addresses(header, (unsigned int)n, dnamebuff, now, doctors);
367 else if (!(options & OPT_NO_NEG))
368 extract_neg_addrs(header, (unsigned int)n, dnamebuff, now);
9e4abcb5 369 }
9e4abcb5 370 }
de37951c
SK
371
372 header->id = htons(forward->orig_id);
373 /* There's no point returning an upstream reply marked as truncated,
374 since that will prod the resolver into moving to TCP - which we
375 don't support. */
376 header->tc = 0; /* goodbye truncate */
377 send_from(forward->fd, options & OPT_NOWILD, packet, n, &forward->source, &forward->dest);
378 forward->new_id = 0; /* cancel */
9e4abcb5 379 }
de37951c 380
9e4abcb5
SK
381 return last_server;
382}
44a2a316 383
de37951c 384struct server *receive_query(struct listener *listen, char *packet, struct mx_record *mxnames,
44a2a316
SK
385 char *mxtarget, unsigned int options, time_t now,
386 unsigned long local_ttl, char *namebuff,
387 struct iname *names, struct iname *addrs, struct iname *except,
388 struct server *last_server, struct server *servers)
389{
390 HEADER *header = (HEADER *)packet;
391 union mysockaddr source_addr;
392 struct iname *tmp;
393 struct all_addr dst_addr;
8a911ccc 394 int m, n, if_index = 0;
44a2a316
SK
395 struct iovec iov[1];
396 struct msghdr msg;
397 struct cmsghdr *cmptr;
44a2a316
SK
398 union {
399 struct cmsghdr align; /* this ensures alignment */
400#ifdef HAVE_IPV6
401 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
402#endif
403#if defined(IP_PKTINFO)
404 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
405#elif defined(IP_RECVDSTADDR)
406 char control[CMSG_SPACE(sizeof(struct in_addr)) +
407 CMSG_SPACE(sizeof(struct sockaddr_dl))];
408#endif
409 } control_u;
410
411 iov[0].iov_base = packet;
412 iov[0].iov_len = PACKETSZ;
413
414 msg.msg_control = control_u.control;
415 msg.msg_controllen = sizeof(control_u);
416 msg.msg_flags = 0;
417 msg.msg_name = &source_addr;
418 msg.msg_namelen = sizeof(source_addr);
419 msg.msg_iov = iov;
420 msg.msg_iovlen = 1;
421
de37951c
SK
422 if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
423 return last_server;
44a2a316
SK
424
425 source_addr.sa.sa_family = listen->family;
426#ifdef HAVE_IPV6
427 if (listen->family == AF_INET6)
428 source_addr.in6.sin6_flowinfo = htonl(0);
429#endif
430
431 if (!(options & OPT_NOWILD) && msg.msg_controllen < sizeof(struct cmsghdr))
432 return last_server;
433
434#if defined(IP_PKTINFO)
435 if (!(options & OPT_NOWILD) && listen->family == AF_INET)
436 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
437 if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
438 {
439 dst_addr.addr.addr4 = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_spec_dst;
8a911ccc 440 if_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
44a2a316
SK
441 }
442#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
443 if (!(options & OPT_NOWILD) && listen->family == AF_INET)
444 {
445 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
446 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
8a911ccc 447 dst_addr.addr.addr4 = *((struct in_addr *)CMSG_DATA(cmptr));
44a2a316 448 else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
8a911ccc 449 if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
44a2a316
SK
450 }
451#endif
452
453#ifdef HAVE_IPV6
454 if (!(options & OPT_NOWILD) && listen->family == AF_INET6)
455 {
456 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
457 if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == IPV6_PKTINFO)
458 {
459 dst_addr.addr.addr6 = ((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_addr;
8a911ccc 460 if_index =((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_ifindex;
44a2a316
SK
461 }
462 }
463#endif
464
465 if (n < (int)sizeof(HEADER) || header->qr)
466 return last_server;
467
468 /* enforce available interface configuration */
469 if (!(options & OPT_NOWILD))
470 {
8a911ccc
SK
471 struct ifreq ifr;
472
473 if (if_index == 0)
44a2a316
SK
474 return last_server;
475
8a911ccc
SK
476 if (except || names)
477 {
478#ifdef SIOCGIFNAME
479 ifr.ifr_ifindex = if_index;
480 if (ioctl(listen->fd, SIOCGIFNAME, &ifr) == -1)
481 return last_server;
482#else
483 if (!if_indextoname(if_index, ifr.ifr_name))
484 return last_server;
485#endif
486 }
487
44a2a316 488 for (tmp = except; tmp; tmp = tmp->next)
8a911ccc 489 if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
44a2a316 490 return last_server;
9e4abcb5 491
44a2a316
SK
492 if (names || addrs)
493 {
494 for (tmp = names; tmp; tmp = tmp->next)
8a911ccc 495 if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
44a2a316
SK
496 break;
497 if (!tmp)
498 for (tmp = addrs; tmp; tmp = tmp->next)
499 if (tmp->addr.sa.sa_family == listen->family)
500 {
501 if (tmp->addr.sa.sa_family == AF_INET &&
502 tmp->addr.in.sin_addr.s_addr == dst_addr.addr.addr4.s_addr)
503 break;
504#ifdef HAVE_IPV6
505 else if (tmp->addr.sa.sa_family == AF_INET6 &&
506 memcmp(&tmp->addr.in6.sin6_addr,
507 &dst_addr.addr.addr6,
508 sizeof(struct in6_addr)) == 0)
509 break;
510#endif
511 }
512 if (!tmp)
513 return last_server;
514 }
515 }
516
517 if (extract_request(header, (unsigned int)n, namebuff))
518 {
519 if (listen->family == AF_INET)
520 log_query(F_QUERY | F_IPV4 | F_FORWARD, namebuff,
521 (struct all_addr *)&source_addr.in.sin_addr);
522#ifdef HAVE_IPV6
523 else
524 log_query(F_QUERY | F_IPV6 | F_FORWARD, namebuff,
525 (struct all_addr *)&source_addr.in6.sin6_addr);
526#endif
527 }
528
529 m = answer_request (header, ((char *) header) + PACKETSZ, (unsigned int)n,
de37951c 530 mxnames, mxtarget, options, now, local_ttl, namebuff);
44a2a316
SK
531 if (m >= 1)
532 send_from(listen->fd, options & OPT_NOWILD, (char *)header, m, &source_addr, &dst_addr);
533 else
534 last_server = forward_query(listen->fd, &source_addr, &dst_addr,
535 header, n, options, namebuff, servers,
536 last_server, now, local_ttl);
537 return last_server;
538}
539
9e4abcb5
SK
540static struct frec *get_new_frec(time_t now)
541{
542 struct frec *f = frec_list, *oldest = NULL;
543 time_t oldtime = now;
544 int count = 0;
545 static time_t warntime = 0;
546
547 while (f)
548 {
549 if (f->new_id == 0)
550 {
551 f->time = now;
552 return f;
553 }
554
555 if (difftime(f->time, oldtime) <= 0)
556 {
557 oldtime = f->time;
558 oldest = f;
559 }
560
561 count++;
562 f = f->next;
563 }
564
565 /* can't find empty one, use oldest if there is one
566 and it's older than timeout */
567 if (oldest && difftime(now, oldtime) > TIMEOUT)
568 {
569 oldest->time = now;
570 return oldest;
571 }
572
573 if (count > FTABSIZ)
574 { /* limit logging rate so syslog isn't DOSed either */
575 if (!warntime || difftime(now, warntime) > LOGRATE)
576 {
577 warntime = now;
578 syslog(LOG_WARNING, "forwarding table overflow: check for server loops.");
579 }
580 return NULL;
581 }
582
583 if ((f = (struct frec *)malloc(sizeof(struct frec))))
584 {
585 f->next = frec_list;
586 f->time = now;
587 frec_list = f;
588 }
589 return f; /* OK if malloc fails and this is NULL */
590}
591
592static struct frec *lookup_frec(unsigned short id)
593{
594 struct frec *f;
595
596 for(f = frec_list; f; f = f->next)
597 if (f->new_id == id)
598 return f;
599
600 return NULL;
601}
602
603static struct frec *lookup_frec_by_sender(unsigned short id,
604 union mysockaddr *addr)
605{
606 struct frec *f;
607
608 for(f = frec_list; f; f = f->next)
609 if (f->new_id &&
610 f->orig_id == id &&
611 sockaddr_isequal(&f->source, addr))
612 return f;
613
614 return NULL;
615}
616
617
618/* return unique random ids between 1 and 65535 */
619static unsigned short get_id(void)
620{
621 unsigned short ret = 0;
622
623 while (ret == 0)
624 {
625 ret = rand16();
626
627 /* scrap ids already in use */
628 if ((ret != 0) && lookup_frec(ret))
629 ret = 0;
630 }
631
632 return ret;
633}
634
635
636
637
638