blob: 1f4ad0fafdfd62e8c20ed56e1164116cd60a3588 [file] [log] [blame]
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001/* 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
Simon Kelley44a2a312004-03-10 20:04:35 +000036/* 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)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000040{
Simon Kelley44a2a312004-03-10 20:04:35 +000041 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;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000055
Simon Kelley44a2a312004-03-10 20:04:35 +000056 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);
76
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;
Simon Kelley44a2a312004-03-10 20:04:35 +0000107 }
108#endif
109
110 sendmsg(fd, &msg, 0);
111}
112
113
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000114/* returns new last_server */
Simon Kelley44a2a312004-03-10 20:04:35 +0000115static 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)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000120{
121 struct frec *forward;
122 char *domain = NULL;
123 int type = 0;
124 struct server *serv;
125 struct all_addr *addrp = NULL;
126 unsigned short flags = 0;
127 unsigned short gotname = extract_request(header, (unsigned int)plen, dnamebuff);
128
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 {
134 /* retry on existing query, send to next server */
135 domain = forward->sentto->domain;
136 type = forward->sentto->flags & SERV_TYPE;
137 if (!(forward->sentto = forward->sentto->next))
138 forward->sentto = servers; /* at end of list, recycle */
139 header->id = htons(forward->new_id);
140 }
141 else
142 {
143 if (gotname)
144 {
145 /* If the query ends in the domain in one of our servers, set
146 domain to point to that name. We find the largest match to allow both
147 domain.org and sub.domain.org to exist. */
148
149 unsigned int namelen = strlen(dnamebuff);
150 unsigned int matchlen = 0;
151
152 for (serv=servers; serv; serv=serv->next)
153 /* domain matches take priority over NODOTS matches */
154 if ((serv->flags & SERV_FOR_NODOTS) && type != SERV_HAS_DOMAIN && !strchr(dnamebuff, '.'))
155 {
156 if (serv->flags & SERV_LITERAL_ADDRESS)
157 {
158 /* flags gets set if server is in fact an answer */
159 unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
160 if (sflag & gotname) /* only OK if addrfamily == query */
161 {
162 type = SERV_FOR_NODOTS;
163 flags = sflag;
164 if (serv->addr.sa.sa_family == AF_INET)
165 addrp = (struct all_addr *)&serv->addr.in.sin_addr;
166#ifdef HAVE_IPV6
167 else
168 addrp = (struct all_addr *)&serv->addr.in6.sin6_addr;
169#endif
170 }
171 }
172 else
173 flags = 0;
174 }
175 else if (serv->flags & SERV_HAS_DOMAIN)
176 {
177 unsigned int domainlen = strlen(serv->domain);
178 if (namelen >= domainlen &&
179 hostname_isequal(dnamebuff + namelen - domainlen, serv->domain) &&
180 domainlen > matchlen)
181 {
182 if (serv->flags & SERV_LITERAL_ADDRESS)
183 { /* flags gets set if server is in fact an answer */
184 unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
Simon Kelley44a2a312004-03-10 20:04:35 +0000185 if ((sflag | F_QUERY ) & gotname) /* only OK if addrfamily == query */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000186 {
187 type = SERV_HAS_DOMAIN;
Simon Kelley44a2a312004-03-10 20:04:35 +0000188 flags = gotname;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000189 domain = serv->domain;
190 matchlen = domainlen;
191 if (serv->addr.sa.sa_family == AF_INET)
192 addrp = (struct all_addr *)&serv->addr.in.sin_addr;
193#ifdef HAVE_IPV6
194 else
195 addrp = (struct all_addr *)&serv->addr.in6.sin6_addr;
196#endif
197 }
198 }
199 else
200 {
201 flags = 0; /* may be better match from previous literal */
202 domain = serv->domain;
203 matchlen = domainlen;
Simon Kelley1ab84e22004-01-29 16:48:35 +0000204 type = SERV_HAS_DOMAIN;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000205 }
206 }
207 }
208 }
209
210 if (flags) /* flags set here means a literal found */
Simon Kelley44a2a312004-03-10 20:04:35 +0000211 {
212 if (flags & F_QUERY)
213 log_query(F_CONFIG | F_FORWARD | F_NEG, dnamebuff, NULL);
214 else
215 log_query(F_CONFIG | F_FORWARD | flags, dnamebuff, addrp);
216 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000217 else
218 {
219 /* we may by policy not forward names without a domain part */
220 if (gotname && (options & OPT_NODOTS_LOCAL) && !strchr(dnamebuff, '.'))
221 flags = F_NXDOMAIN;
222 else if (!(forward = get_new_frec(now)))
223 /* table full - server failure. */
224 flags = F_NEG;
225 }
226
227 if (forward)
228 {
229 /* In strict_order mode, or when using domain specific servers
230 always try servers in the order specified in resolv.conf,
231 otherwise, use the one last known to work. */
232
233 if (type != 0 || (options & OPT_ORDER))
234 forward->sentto = servers;
235 else
236 forward->sentto = last_server;
237
238 forward->source = *udpaddr;
Simon Kelley44a2a312004-03-10 20:04:35 +0000239 forward->dest = *dst_addr;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000240 forward->new_id = get_id();
241 forward->fd = udpfd;
242 forward->orig_id = ntohs(header->id);
243 header->id = htons(forward->new_id);
244 }
245 }
246
247 /* check for send errors here (no route to host)
248 if we fail to send to all nameservers, send back an error
249 packet straight away (helps modem users when offline) */
250
251 if (!flags && forward)
252 {
253 struct server *firstsentto = forward->sentto;
254
255 while (1)
256 {
257 int logflags = 0;
258
259 if (forward->sentto->addr.sa.sa_family == AF_INET)
260 {
261 logflags = F_SERVER | F_IPV4 | F_FORWARD;
262 addrp = (struct all_addr *)&forward->sentto->addr.in.sin_addr;
263 }
264#ifdef HAVE_IPV6
265 else
266 {
267 logflags = F_SERVER | F_IPV6 | F_FORWARD;
268 addrp = (struct all_addr *)&forward->sentto->addr.in6.sin6_addr;
269 }
270#endif
271 /* only send to servers dealing with our domain.
272 domain may be NULL, in which case server->domain
273 must be NULL also. */
274
275 if (type == (forward->sentto->flags & SERV_TYPE) &&
276 (type != SERV_HAS_DOMAIN || hostname_isequal(domain, forward->sentto->domain)))
277 {
278 if (forward->sentto->flags & SERV_NO_ADDR)
279 flags = F_NOERR; /* NULL servers are OK. */
280 else if (!(forward->sentto->flags & SERV_LITERAL_ADDRESS) &&
281 sendto(forward->sentto->sfd->fd, (char *)header, plen, 0,
282 &forward->sentto->addr.sa,
283 sa_len(&forward->sentto->addr)) != -1)
284 {
285 log_query(logflags, gotname ? dnamebuff : "query", addrp);
286 /* for no-domain, don't update last_server */
287 return domain ? last_server : (forward->sentto->next ? forward->sentto->next : servers);
288 }
289 }
290
291 if (!(forward->sentto = forward->sentto->next))
292 forward->sentto = servers;
293
294 /* check if we tried all without success */
295 if (forward->sentto == firstsentto)
296 break;
297 }
298
299 /* could not send on, prepare to return */
300 header->id = htons(forward->orig_id);
301 forward->new_id = 0; /* cancel */
302 }
303
304 /* could not send on, return empty answer or address if known for whole domain */
305 plen = setup_reply(header, (unsigned int)plen, addrp, flags, local_ttl);
Simon Kelley44a2a312004-03-10 20:04:35 +0000306 send_from(udpfd, options & OPT_NOWILD, (char *)header, plen, udpaddr, dst_addr);
307
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000308 if (flags & (F_NOERR | F_NXDOMAIN))
309 log_query(F_CONFIG | F_FORWARD | F_NEG | gotname | (flags & F_NXDOMAIN), dnamebuff, NULL);
310
311 return last_server;
312}
313
314/* returns new last_server */
315struct server *reply_query(int fd, int options, char *packet, time_t now,
Simon Kelley1cff1662004-03-12 08:12:58 +0000316 char *dnamebuff, struct server *last_server,
317 struct bogus_addr *bogus_nxdomain, struct doctor *doctors)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000318{
319 /* packet from peer server, extract data for cache, and send to
320 original requester */
321 struct frec *forward;
322 HEADER *header;
323 int n = recv(fd, packet, PACKETSZ, 0);
324
325 header = (HEADER *)packet;
326 if (n >= (int)sizeof(HEADER) && header->qr)
327 {
328 if ((forward = lookup_frec(ntohs(header->id))))
329 {
330 if (header->rcode == NOERROR || header->rcode == NXDOMAIN)
331 {
332 if (!forward->sentto->domain)
333 last_server = forward->sentto; /* known good */
334 if (header->opcode == QUERY)
335 {
336 if (!(bogus_nxdomain &&
337 header->rcode == NOERROR &&
338 check_for_bogus_wildcard(header, (unsigned int)n, dnamebuff, bogus_nxdomain, now)))
339 {
340 if (header->rcode == NOERROR && ntohs(header->ancount) != 0)
Simon Kelley1cff1662004-03-12 08:12:58 +0000341 extract_addresses(header, (unsigned int)n, dnamebuff, now, doctors);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000342 else if (!(options & OPT_NO_NEG))
343 extract_neg_addrs(header, (unsigned int)n, dnamebuff, now);
344 }
345 }
346 }
347 header->id = htons(forward->orig_id);
348 /* There's no point returning an upstream reply marked as truncated,
349 since that will prod the resolver into moving to TCP - which we
350 don't support. */
351 header->tc = 0; /* goodbye truncate */
Simon Kelley44a2a312004-03-10 20:04:35 +0000352 send_from(forward->fd, options & OPT_NOWILD, packet, n, &forward->source, &forward->dest);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000353 forward->new_id = 0; /* cancel */
354 }
355 }
356
357 return last_server;
358}
Simon Kelley44a2a312004-03-10 20:04:35 +0000359
360struct server *receive_query(struct listener *listen, char *packet, char *mxname,
361 char *mxtarget, unsigned int options, time_t now,
362 unsigned long local_ttl, char *namebuff,
363 struct iname *names, struct iname *addrs, struct iname *except,
364 struct server *last_server, struct server *servers)
365{
366 HEADER *header = (HEADER *)packet;
367 union mysockaddr source_addr;
368 struct iname *tmp;
369 struct all_addr dst_addr;
Simon Kelley8a911cc2004-03-16 18:35:52 +0000370 int m, n, if_index = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +0000371 struct iovec iov[1];
372 struct msghdr msg;
373 struct cmsghdr *cmptr;
Simon Kelley44a2a312004-03-10 20:04:35 +0000374 union {
375 struct cmsghdr align; /* this ensures alignment */
376#ifdef HAVE_IPV6
377 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
378#endif
379#if defined(IP_PKTINFO)
380 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
381#elif defined(IP_RECVDSTADDR)
382 char control[CMSG_SPACE(sizeof(struct in_addr)) +
383 CMSG_SPACE(sizeof(struct sockaddr_dl))];
384#endif
385 } control_u;
386
387 iov[0].iov_base = packet;
388 iov[0].iov_len = PACKETSZ;
389
390 msg.msg_control = control_u.control;
391 msg.msg_controllen = sizeof(control_u);
392 msg.msg_flags = 0;
393 msg.msg_name = &source_addr;
394 msg.msg_namelen = sizeof(source_addr);
395 msg.msg_iov = iov;
396 msg.msg_iovlen = 1;
397
398 n = recvmsg(listen->fd, &msg, 0);
399
400 source_addr.sa.sa_family = listen->family;
401#ifdef HAVE_IPV6
402 if (listen->family == AF_INET6)
403 source_addr.in6.sin6_flowinfo = htonl(0);
404#endif
405
406 if (!(options & OPT_NOWILD) && msg.msg_controllen < sizeof(struct cmsghdr))
407 return last_server;
408
409#if defined(IP_PKTINFO)
410 if (!(options & OPT_NOWILD) && listen->family == AF_INET)
411 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
412 if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
413 {
414 dst_addr.addr.addr4 = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_spec_dst;
Simon Kelley8a911cc2004-03-16 18:35:52 +0000415 if_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
Simon Kelley44a2a312004-03-10 20:04:35 +0000416 }
417#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
418 if (!(options & OPT_NOWILD) && listen->family == AF_INET)
419 {
420 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
421 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
Simon Kelley8a911cc2004-03-16 18:35:52 +0000422 dst_addr.addr.addr4 = *((struct in_addr *)CMSG_DATA(cmptr));
Simon Kelley44a2a312004-03-10 20:04:35 +0000423 else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
Simon Kelley8a911cc2004-03-16 18:35:52 +0000424 if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
Simon Kelley44a2a312004-03-10 20:04:35 +0000425 }
426#endif
427
428#ifdef HAVE_IPV6
429 if (!(options & OPT_NOWILD) && listen->family == AF_INET6)
430 {
431 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
432 if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == IPV6_PKTINFO)
433 {
434 dst_addr.addr.addr6 = ((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_addr;
Simon Kelley8a911cc2004-03-16 18:35:52 +0000435 if_index =((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_ifindex;
Simon Kelley44a2a312004-03-10 20:04:35 +0000436 }
437 }
438#endif
439
440 if (n < (int)sizeof(HEADER) || header->qr)
441 return last_server;
442
443 /* enforce available interface configuration */
444 if (!(options & OPT_NOWILD))
445 {
Simon Kelley8a911cc2004-03-16 18:35:52 +0000446 struct ifreq ifr;
447
448 if (if_index == 0)
Simon Kelley44a2a312004-03-10 20:04:35 +0000449 return last_server;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000450
Simon Kelley8a911cc2004-03-16 18:35:52 +0000451 if (except || names)
452 {
453#ifdef SIOCGIFNAME
454 ifr.ifr_ifindex = if_index;
455 if (ioctl(listen->fd, SIOCGIFNAME, &ifr) == -1)
456 return last_server;
457#else
458 if (!if_indextoname(if_index, ifr.ifr_name))
459 return last_server;
460#endif
461 }
462
Simon Kelley44a2a312004-03-10 20:04:35 +0000463 for (tmp = except; tmp; tmp = tmp->next)
Simon Kelley8a911cc2004-03-16 18:35:52 +0000464 if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
Simon Kelley44a2a312004-03-10 20:04:35 +0000465 return last_server;
466
467 if (names || addrs)
468 {
469 for (tmp = names; tmp; tmp = tmp->next)
Simon Kelley8a911cc2004-03-16 18:35:52 +0000470 if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
Simon Kelley44a2a312004-03-10 20:04:35 +0000471 break;
472 if (!tmp)
473 for (tmp = addrs; tmp; tmp = tmp->next)
474 if (tmp->addr.sa.sa_family == listen->family)
475 {
476 if (tmp->addr.sa.sa_family == AF_INET &&
477 tmp->addr.in.sin_addr.s_addr == dst_addr.addr.addr4.s_addr)
478 break;
479#ifdef HAVE_IPV6
480 else if (tmp->addr.sa.sa_family == AF_INET6 &&
481 memcmp(&tmp->addr.in6.sin6_addr,
482 &dst_addr.addr.addr6,
483 sizeof(struct in6_addr)) == 0)
484 break;
485#endif
486 }
487 if (!tmp)
488 return last_server;
489 }
490 }
491
492 if (extract_request(header, (unsigned int)n, namebuff))
493 {
494 if (listen->family == AF_INET)
495 log_query(F_QUERY | F_IPV4 | F_FORWARD, namebuff,
496 (struct all_addr *)&source_addr.in.sin_addr);
497#ifdef HAVE_IPV6
498 else
499 log_query(F_QUERY | F_IPV6 | F_FORWARD, namebuff,
500 (struct all_addr *)&source_addr.in6.sin6_addr);
501#endif
502 }
503
504 m = answer_request (header, ((char *) header) + PACKETSZ, (unsigned int)n,
505 mxname, mxtarget, options, now, local_ttl, namebuff);
506 if (m >= 1)
507 send_from(listen->fd, options & OPT_NOWILD, (char *)header, m, &source_addr, &dst_addr);
508 else
509 last_server = forward_query(listen->fd, &source_addr, &dst_addr,
510 header, n, options, namebuff, servers,
511 last_server, now, local_ttl);
512 return last_server;
513}
514
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000515static struct frec *get_new_frec(time_t now)
516{
517 struct frec *f = frec_list, *oldest = NULL;
518 time_t oldtime = now;
519 int count = 0;
520 static time_t warntime = 0;
521
522 while (f)
523 {
524 if (f->new_id == 0)
525 {
526 f->time = now;
527 return f;
528 }
529
530 if (difftime(f->time, oldtime) <= 0)
531 {
532 oldtime = f->time;
533 oldest = f;
534 }
535
536 count++;
537 f = f->next;
538 }
539
540 /* can't find empty one, use oldest if there is one
541 and it's older than timeout */
542 if (oldest && difftime(now, oldtime) > TIMEOUT)
543 {
544 oldest->time = now;
545 return oldest;
546 }
547
548 if (count > FTABSIZ)
549 { /* limit logging rate so syslog isn't DOSed either */
550 if (!warntime || difftime(now, warntime) > LOGRATE)
551 {
552 warntime = now;
553 syslog(LOG_WARNING, "forwarding table overflow: check for server loops.");
554 }
555 return NULL;
556 }
557
558 if ((f = (struct frec *)malloc(sizeof(struct frec))))
559 {
560 f->next = frec_list;
561 f->time = now;
562 frec_list = f;
563 }
564 return f; /* OK if malloc fails and this is NULL */
565}
566
567static struct frec *lookup_frec(unsigned short id)
568{
569 struct frec *f;
570
571 for(f = frec_list; f; f = f->next)
572 if (f->new_id == id)
573 return f;
574
575 return NULL;
576}
577
578static struct frec *lookup_frec_by_sender(unsigned short id,
579 union mysockaddr *addr)
580{
581 struct frec *f;
582
583 for(f = frec_list; f; f = f->next)
584 if (f->new_id &&
585 f->orig_id == id &&
586 sockaddr_isequal(&f->source, addr))
587 return f;
588
589 return NULL;
590}
591
592
593/* return unique random ids between 1 and 65535 */
594static unsigned short get_id(void)
595{
596 unsigned short ret = 0;
597
598 while (ret == 0)
599 {
600 ret = rand16();
601
602 /* scrap ids already in use */
603 if ((ret != 0) && lookup_frec(ret))
604 ret = 0;
605 }
606
607 return ret;
608}
609
610
611
612
613