1 /*
2  * packet.c	Generic packet manipulation functions.
3  *
4  * Version:	$Id: acba8d9f0172ab0cb8e06943904327bca953f0a2 $
5  *
6  *   This library is free software; you can redistribute it and/or
7  *   modify it under the terms of the GNU Lesser General Public
8  *   License as published by the Free Software Foundation; either
9  *   version 2.1 of the License, or (at your option) any later version.
10  *
11  *   This library is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  *   Lesser General Public License for more details.
15  *
16  *   You should have received a copy of the GNU Lesser General Public
17  *   License along with this library; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2000-2006  The FreeRADIUS server project
21  */
22 
23 RCSID("$Id: acba8d9f0172ab0cb8e06943904327bca953f0a2 $")
24 
25 #include	<freeradius-devel/libradius.h>
26 
27 #ifdef WITH_UDPFROMTO
28 #include	<freeradius-devel/udpfromto.h>
29 #endif
30 
31 #include <fcntl.h>
32 
33 /*
34  *	See if two packets are identical.
35  *
36  *	Note that we do NOT compare the authentication vectors.
37  *	That's because if the authentication vector is different,
38  *	it means that the NAS has given up on the earlier request.
39  */
fr_packet_cmp(RADIUS_PACKET const * a,RADIUS_PACKET const * b)40 int fr_packet_cmp(RADIUS_PACKET const *a, RADIUS_PACKET const *b)
41 {
42 	int rcode;
43 
44 	/*
45 	 *	256-way fanout.
46 	 */
47 	if (a->id < b->id) return -1;
48 	if (a->id > b->id) return +1;
49 
50 	if (a->sockfd < b->sockfd) return -1;
51 	if (a->sockfd > b->sockfd) return +1;
52 
53 	/*
54 	 *	Source ports are pretty much random.
55 	 */
56 	rcode = (int) a->src_port - (int) b->src_port;
57 	if (rcode != 0) return rcode;
58 
59 	/*
60 	 *	Usually many client IPs, and few server IPs
61 	 */
62 	rcode = fr_ipaddr_cmp(&a->src_ipaddr, &b->src_ipaddr);
63 	if (rcode != 0) return rcode;
64 
65 	/*
66 	 *	One socket can receive packets for multiple
67 	 *	destination IPs, so we check that before checking the
68 	 *	file descriptor.
69 	 */
70 	rcode = fr_ipaddr_cmp(&a->dst_ipaddr, &b->dst_ipaddr);
71 	if (rcode != 0) return rcode;
72 
73 	/*
74 	 *	At this point, the order of comparing socket FDs
75 	 *	and/or destination ports doesn't matter.  One of those
76 	 *	fields will make the socket unique, and the other is
77 	 *	pretty much redundant.
78 	 */
79 	rcode = (int) a->dst_port - (int) b->dst_port;
80 	return rcode;
81 }
82 
fr_inaddr_any(fr_ipaddr_t * ipaddr)83 int fr_inaddr_any(fr_ipaddr_t *ipaddr)
84 {
85 
86 	if (ipaddr->af == AF_INET) {
87 		if (ipaddr->ipaddr.ip4addr.s_addr == INADDR_ANY) {
88 			return 1;
89 		}
90 
91 #ifdef HAVE_STRUCT_SOCKADDR_IN6
92 	} else if (ipaddr->af == AF_INET6) {
93 		if (IN6_IS_ADDR_UNSPECIFIED(&(ipaddr->ipaddr.ip6addr))) {
94 			return 1;
95 		}
96 #endif
97 
98 	} else {
99 		fr_strerror_printf("Unknown address family");
100 		return -1;
101 	}
102 
103 	return 0;
104 }
105 
106 
107 /*
108  *	Create a fake "request" from a reply, for later lookup.
109  */
fr_request_from_reply(RADIUS_PACKET * request,RADIUS_PACKET const * reply)110 void fr_request_from_reply(RADIUS_PACKET *request,
111 			   RADIUS_PACKET const *reply)
112 {
113 	request->sockfd = reply->sockfd;
114 	request->id = reply->id;
115 #ifdef WITH_TCP
116 	request->proto = reply->proto;
117 #endif
118 	request->src_port = reply->dst_port;
119 	request->dst_port = reply->src_port;
120 	request->src_ipaddr = reply->dst_ipaddr;
121 	request->dst_ipaddr = reply->src_ipaddr;
122 }
123 
124 /*
125  *	Open a socket on the given IP and port.
126  */
fr_socket(fr_ipaddr_t * ipaddr,uint16_t port)127 int fr_socket(fr_ipaddr_t *ipaddr, uint16_t port)
128 {
129 	int sockfd;
130 	struct sockaddr_storage salocal;
131 	socklen_t	salen;
132 
133 	sockfd = socket(ipaddr->af, SOCK_DGRAM, 0);
134 	if (sockfd < 0) {
135 		fr_strerror_printf("cannot open socket: %s", fr_syserror(errno));
136 		return sockfd;
137 	}
138 
139 #ifdef WITH_UDPFROMTO
140 	/*
141 	 *	Initialize udpfromto for all sockets.
142 	 */
143 	if (udpfromto_init(sockfd) != 0) {
144 		close(sockfd);
145 		fr_strerror_printf("cannot initialize udpfromto: %s", fr_syserror(errno));
146 		return -1;
147 	}
148 #endif
149 
150 	if (!fr_ipaddr2sockaddr(ipaddr, port, &salocal, &salen)) {
151 		return sockfd;
152 	}
153 
154 #ifdef HAVE_STRUCT_SOCKADDR_IN6
155 	if (ipaddr->af == AF_INET6) {
156 		/*
157 		 *	Listening on '::' does NOT get you IPv4 to
158 		 *	IPv6 mapping.  You've got to listen on an IPv4
159 		 *	address, too.  This makes the rest of the server
160 		 *	design a little simpler.
161 		 */
162 #ifdef IPV6_V6ONLY
163 
164 		if (IN6_IS_ADDR_UNSPECIFIED(&ipaddr->ipaddr.ip6addr)) {
165 			int on = 1;
166 
167 			if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
168 				       (char *)&on, sizeof(on)) < 0) {
169 				close(sockfd);
170 				fr_strerror_printf("Failed setting sockopt "
171 						   "IPPROTO_IPV6 - IPV6_V6ONLY"
172 						   ": %s", fr_syserror(errno));
173 				return -1;
174 			}
175 		}
176 #endif /* IPV6_V6ONLY */
177 	}
178 #endif /* HAVE_STRUCT_SOCKADDR_IN6 */
179 
180 #if (defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)) || defined(IP_DONTFRAG)
181 	if (ipaddr->af == AF_INET) {
182 		int flag;
183 
184 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
185 
186 		/*
187 		 *	Disable PMTU discovery.  On Linux, this
188 		 *	also makes sure that the "don't fragment"
189 		 *	flag is zero.
190 		 */
191 		flag = IP_PMTUDISC_DONT;
192 		if (setsockopt(sockfd, IPPROTO_IP, IP_MTU_DISCOVER,
193 			       &flag, sizeof(flag)) < 0) {
194 			close(sockfd);
195 			fr_strerror_printf("Failed setting sockopt "
196 					   "IPPROTO_IP - IP_MTU_DISCOVER: %s",
197 					   fr_syserror(errno));
198 			return -1;
199 		}
200 #endif
201 
202 #if defined(IP_DONTFRAG)
203 		/*
204 		 *	Ensure that the "don't fragment" flag is zero.
205 		 */
206 		flag = 0;
207 		if (setsockopt(sockfd, IPPROTO_IP, IP_DONTFRAG,
208 			   &flag, sizeof(flag)) < 0) {
209 			close(sockfd);
210 			fr_strerror_printf("Failed setting sockopt "
211 					   "IPPROTO_IP - IP_DONTFRAG: %s",
212 					   fr_syserror(errno));
213 			return -1;
214 		}
215 #endif
216 	}
217 #endif
218 
219 	if (bind(sockfd, (struct sockaddr *) &salocal, salen) < 0) {
220 		close(sockfd);
221 		fr_strerror_printf("cannot bind socket: %s", fr_syserror(errno));
222 		return -1;
223 	}
224 
225 	return sockfd;
226 }
227 
228 
229 /*
230  *	We need to keep track of the socket & it's IP/port.
231  */
232 typedef struct fr_packet_socket_t {
233 	int		sockfd;
234 	void		*ctx;
235 
236 	uint32_t	num_outgoing;
237 
238 	int		src_any;
239 	fr_ipaddr_t	src_ipaddr;
240 	uint16_t	src_port;
241 
242 	int		dst_any;
243 	fr_ipaddr_t	dst_ipaddr;
244 	uint16_t	dst_port;
245 
246 	bool		dont_use;
247 
248 #ifdef WITH_TCP
249 	int		proto;
250 #endif
251 
252 	uint8_t		id[32];
253 } fr_packet_socket_t;
254 
255 
256 #define FNV_MAGIC_PRIME (0x01000193)
257 #define MAX_SOCKETS (1024)
258 #define SOCKOFFSET_MASK (MAX_SOCKETS - 1)
259 #define SOCK2OFFSET(sockfd) ((sockfd * FNV_MAGIC_PRIME) & SOCKOFFSET_MASK)
260 
261 /*
262  *	Structure defining a list of packets (incoming or outgoing)
263  *	that should be managed.
264  */
265 struct fr_packet_list_t {
266 	rbtree_t	*tree;
267 
268 	int		alloc_id;
269 	uint32_t	num_outgoing;
270 	int		last_recv;
271 	int		num_sockets;
272 
273 	fr_packet_socket_t sockets[MAX_SOCKETS];
274 };
275 
276 
277 /*
278  *	Ugh.  Doing this on every sent/received packet is not nice.
279  */
fr_socket_find(fr_packet_list_t * pl,int sockfd)280 static fr_packet_socket_t *fr_socket_find(fr_packet_list_t *pl,
281 					  int sockfd)
282 {
283 	int i, start;
284 
285 	i = start = SOCK2OFFSET(sockfd);
286 
287 	do {			/* make this hack slightly more efficient */
288 		if (pl->sockets[i].sockfd == sockfd) return &pl->sockets[i];
289 
290 		i = (i + 1) & SOCKOFFSET_MASK;
291 	} while (i != start);
292 
293 	return NULL;
294 }
295 
fr_packet_list_socket_freeze(fr_packet_list_t * pl,int sockfd)296 bool fr_packet_list_socket_freeze(fr_packet_list_t *pl, int sockfd)
297 {
298 	fr_packet_socket_t *ps;
299 
300 	if (!pl) {
301 		fr_strerror_printf("Invalid argument");
302 		return false;
303 	}
304 
305 	ps = fr_socket_find(pl, sockfd);
306 	if (!ps) {
307 		fr_strerror_printf("No such socket");
308 		return false;
309 	}
310 
311 	ps->dont_use = true;
312 	return true;
313 }
314 
fr_packet_list_socket_thaw(fr_packet_list_t * pl,int sockfd)315 bool fr_packet_list_socket_thaw(fr_packet_list_t *pl, int sockfd)
316 {
317 	fr_packet_socket_t *ps;
318 
319 	if (!pl) return false;
320 
321 	ps = fr_socket_find(pl, sockfd);
322 	if (!ps) return false;
323 
324 	ps->dont_use = false;
325 	return true;
326 }
327 
328 
fr_packet_list_socket_del(fr_packet_list_t * pl,int sockfd)329 bool fr_packet_list_socket_del(fr_packet_list_t *pl, int sockfd)
330 {
331 	fr_packet_socket_t *ps;
332 
333 	if (!pl) return false;
334 
335 	ps = fr_socket_find(pl, sockfd);
336 	if (!ps) return false;
337 
338 	if (ps->num_outgoing != 0) {
339 		fr_strerror_printf("socket is still in use");
340 		return false;
341 	}
342 
343 	ps->sockfd = -1;
344 	pl->num_sockets--;
345 
346 	return true;
347 }
348 
349 
fr_packet_list_socket_add(fr_packet_list_t * pl,int sockfd,int proto,fr_ipaddr_t * dst_ipaddr,uint16_t dst_port,void * ctx)350 bool fr_packet_list_socket_add(fr_packet_list_t *pl, int sockfd, int proto,
351 			      fr_ipaddr_t *dst_ipaddr, uint16_t dst_port,
352 			      void *ctx)
353 {
354 	int i, start;
355 	struct sockaddr_storage	src;
356 	socklen_t		sizeof_src;
357 	fr_packet_socket_t	*ps;
358 
359 	if (!pl || !dst_ipaddr || (dst_ipaddr->af == AF_UNSPEC)) {
360 		fr_strerror_printf("Invalid argument");
361 		return false;
362 	}
363 
364 	if (pl->num_sockets >= MAX_SOCKETS) {
365 		fr_strerror_printf("Too many open sockets");
366 		return false;
367 	}
368 
369 #ifndef WITH_TCP
370 	if (proto != IPPROTO_UDP) {
371 		fr_strerror_printf("only UDP is supported");
372 		return false;
373 	}
374 #endif
375 
376 	ps = NULL;
377 	i = start = SOCK2OFFSET(sockfd);
378 
379 	do {
380 		if (pl->sockets[i].sockfd == -1) {
381 			ps =  &pl->sockets[i];
382 			break;
383 		}
384 
385 		i = (i + 1) & SOCKOFFSET_MASK;
386 	} while (i != start);
387 
388 	if (!ps) {
389 		fr_strerror_printf("All socket entries are full");
390 		return false;
391 	}
392 
393 	memset(ps, 0, sizeof(*ps));
394 	ps->ctx = ctx;
395 #ifdef WITH_TCP
396 	ps->proto = proto;
397 #endif
398 
399 	/*
400 	 *	Get address family, etc. first, so we know if we
401 	 *	need to do udpfromto.
402 	 *
403 	 *	FIXME: udpfromto also does this, but it's not
404 	 *	a critical problem.
405 	 */
406 	sizeof_src = sizeof(src);
407 	memset(&src, 0, sizeof_src);
408 	if (getsockname(sockfd, (struct sockaddr *) &src,
409 			&sizeof_src) < 0) {
410 		fr_strerror_printf("%s", fr_syserror(errno));
411 		return false;
412 	}
413 
414 	if (!fr_sockaddr2ipaddr(&src, sizeof_src, &ps->src_ipaddr,
415 				&ps->src_port)) {
416 		fr_strerror_printf("Failed to get IP");
417 		return false;
418 	}
419 
420 	ps->dst_ipaddr = *dst_ipaddr;
421 	ps->dst_port = dst_port;
422 
423 	ps->src_any = fr_inaddr_any(&ps->src_ipaddr);
424 	if (ps->src_any < 0) return false;
425 
426 	ps->dst_any = fr_inaddr_any(&ps->dst_ipaddr);
427 	if (ps->dst_any < 0) return false;
428 
429 	/*
430 	 *	As the last step before returning.
431 	 */
432 	ps->sockfd = sockfd;
433 	pl->num_sockets++;
434 
435 	return true;
436 }
437 
packet_entry_cmp(void const * one,void const * two)438 static int packet_entry_cmp(void const *one, void const *two)
439 {
440 	RADIUS_PACKET const * const *a = one;
441 	RADIUS_PACKET const * const *b = two;
442 
443 	return fr_packet_cmp(*a, *b);
444 }
445 
fr_packet_list_free(fr_packet_list_t * pl)446 void fr_packet_list_free(fr_packet_list_t *pl)
447 {
448 	if (!pl) return;
449 
450 	rbtree_free(pl->tree);
451 	free(pl);
452 }
453 
454 
455 /*
456  *	Caller is responsible for managing the packet entries.
457  */
fr_packet_list_create(int alloc_id)458 fr_packet_list_t *fr_packet_list_create(int alloc_id)
459 {
460 	int i;
461 	fr_packet_list_t	*pl;
462 
463 	pl = malloc(sizeof(*pl));
464 	if (!pl) return NULL;
465 	memset(pl, 0, sizeof(*pl));
466 
467 	pl->tree = rbtree_create(NULL, packet_entry_cmp, NULL, 0);
468 	if (!pl->tree) {
469 		fr_packet_list_free(pl);
470 		return NULL;
471 	}
472 
473 	for (i = 0; i < MAX_SOCKETS; i++) {
474 		pl->sockets[i].sockfd = -1;
475 	}
476 
477 	pl->alloc_id = alloc_id;
478 
479 	return pl;
480 }
481 
482 
483 /*
484  *	If pl->alloc_id is set, then fr_packet_list_id_alloc() MUST
485  *	be called before inserting the packet into the list!
486  */
fr_packet_list_insert(fr_packet_list_t * pl,RADIUS_PACKET ** request_p)487 bool fr_packet_list_insert(fr_packet_list_t *pl,
488 			    RADIUS_PACKET **request_p)
489 {
490 	if (!pl || !request_p || !*request_p) return 0;
491 
492 	VERIFY_PACKET(*request_p);
493 
494 	return rbtree_insert(pl->tree, request_p);
495 }
496 
fr_packet_list_find(fr_packet_list_t * pl,RADIUS_PACKET * request)497 RADIUS_PACKET **fr_packet_list_find(fr_packet_list_t *pl,
498 				      RADIUS_PACKET *request)
499 {
500 	if (!pl || !request) return 0;
501 
502 	VERIFY_PACKET(request);
503 
504 	return rbtree_finddata(pl->tree, &request);
505 }
506 
507 
508 /*
509  *	This presumes that the reply has dst_ipaddr && dst_port set up
510  *	correctly (i.e. real IP, or "*").
511  */
fr_packet_list_find_byreply(fr_packet_list_t * pl,RADIUS_PACKET * reply)512 RADIUS_PACKET **fr_packet_list_find_byreply(fr_packet_list_t *pl,
513 					      RADIUS_PACKET *reply)
514 {
515 	RADIUS_PACKET my_request, *request;
516 	fr_packet_socket_t *ps;
517 
518 	if (!pl || !reply) return NULL;
519 
520 	VERIFY_PACKET(reply);
521 
522 	ps = fr_socket_find(pl, reply->sockfd);
523 	if (!ps) return NULL;
524 
525 	/*
526 	 *	Initialize request from reply, AND from the source
527 	 *	IP & port of this socket.  The client may have bound
528 	 *	the socket to 0, in which case it's some random port,
529 	 *	that is NOT in the original request->src_port.
530 	 */
531 	my_request.sockfd = reply->sockfd;
532 	my_request.id = reply->id;
533 
534 #ifdef WITH_TCP
535 	/*
536 	 *	TCP sockets are always bound to the correct src/dst IP/port
537 	 */
538 	if (ps->proto == IPPROTO_TCP) {
539 		reply->dst_ipaddr = ps->src_ipaddr;
540 		reply->dst_port = ps->src_port;
541 		reply->src_ipaddr = ps->dst_ipaddr;
542 		reply->src_port = ps->dst_port;
543 
544 		my_request.src_ipaddr = ps->src_ipaddr;
545 		my_request.src_port = ps->src_port;
546 		my_request.dst_ipaddr = ps->dst_ipaddr;
547 		my_request.dst_port = ps->dst_port;
548 
549 	} else
550 #endif
551 	{
552 		if (ps->src_any) {
553 			my_request.src_ipaddr = ps->src_ipaddr;
554 		} else {
555 			my_request.src_ipaddr = reply->dst_ipaddr;
556 		}
557 		my_request.src_port = ps->src_port;
558 
559 		my_request.dst_ipaddr = reply->src_ipaddr;
560 		my_request.dst_port = reply->src_port;
561 	}
562 
563 #ifdef WITH_TCP
564 	my_request.proto = reply->proto;
565 #endif
566 	request = &my_request;
567 
568 	return rbtree_finddata(pl->tree, &request);
569 }
570 
571 
fr_packet_list_yank(fr_packet_list_t * pl,RADIUS_PACKET * request)572 bool fr_packet_list_yank(fr_packet_list_t *pl, RADIUS_PACKET *request)
573 {
574 	rbnode_t *node;
575 
576 	if (!pl || !request) return false;
577 
578 	VERIFY_PACKET(request);
579 
580 	node = rbtree_find(pl->tree, &request);
581 	if (!node) return false;
582 
583 	rbtree_delete(pl->tree, node);
584 	return true;
585 }
586 
fr_packet_list_num_elements(fr_packet_list_t * pl)587 uint32_t fr_packet_list_num_elements(fr_packet_list_t *pl)
588 {
589 	if (!pl) return 0;
590 
591 	return rbtree_num_elements(pl->tree);
592 }
593 
594 
595 /*
596  *	1 == ID was allocated & assigned
597  *	0 == couldn't allocate ID.
598  *
599  *	Note that this ALSO assigns a socket to use, and updates
600  *	packet->request->src_ipaddr && packet->request->src_port
601  *
602  *	In multi-threaded systems, the calls to id_alloc && id_free
603  *	should be protected by a mutex.  This does NOT have to be
604  *	the same mutex as the one protecting the insert/find/yank
605  *	calls!
606  *
607  *	We assume that the packet has dst_ipaddr && dst_port
608  *	already initialized.  We will use those to find an
609  *	outgoing socket.  The request MAY also have src_ipaddr set.
610  *
611  *	We also assume that the sender doesn't care which protocol
612  *	should be used.
613  */
fr_packet_list_id_alloc(fr_packet_list_t * pl,int proto,RADIUS_PACKET ** request_p,void ** pctx)614 bool fr_packet_list_id_alloc(fr_packet_list_t *pl, int proto,
615 			    RADIUS_PACKET **request_p, void **pctx)
616 {
617 	int i, j, k, fd, id, start_i, start_j, start_k;
618 	int src_any = 0;
619 	fr_packet_socket_t *ps= NULL;
620 	RADIUS_PACKET *request = *request_p;
621 
622 	VERIFY_PACKET(request);
623 
624 	if ((request->dst_ipaddr.af == AF_UNSPEC) ||
625 	    (request->dst_port == 0)) {
626 		fr_strerror_printf("No destination address/port specified");
627 		return false;
628 	}
629 
630 #ifndef WITH_TCP
631 	if ((proto != 0) && (proto != IPPROTO_UDP)) {
632 		fr_strerror_printf("Invalid destination protocol");
633 		return false;
634 	}
635 #endif
636 
637 	/*
638 	 *	Special case: unspec == "don't care"
639 	 */
640 	if (request->src_ipaddr.af == AF_UNSPEC) {
641 		memset(&request->src_ipaddr, 0, sizeof(request->src_ipaddr));
642 		request->src_ipaddr.af = request->dst_ipaddr.af;
643 	}
644 
645 	src_any = fr_inaddr_any(&request->src_ipaddr);
646 	if (src_any < 0) {
647 		fr_strerror_printf("Can't check src_ipaddr");
648 		return false;
649 	}
650 
651 	/*
652 	 *	MUST specify a destination address.
653 	 */
654 	if (fr_inaddr_any(&request->dst_ipaddr) != 0) {
655 		fr_strerror_printf("Must specify a dst_ipaddr");
656 		return false;
657 	}
658 
659 	/*
660 	 *	FIXME: Go to an LRU system.  This prevents ID re-use
661 	 *	for as long as possible.  The main problem with that
662 	 *	approach is that it requires us to populate the
663 	 *	LRU/FIFO when we add a new socket, or a new destination,
664 	 *	which can be expensive.
665 	 *
666 	 *	The LRU can be avoided if the caller takes care to free
667 	 *	Id's only when all responses have been received, OR after
668 	 *	a timeout.
669 	 *
670 	 *	Right now, the random approach is almost OK... it's
671 	 *	brute-force over all of the available ID's, BUT using
672 	 *	random numbers for everything spreads the load a bit.
673 	 *
674 	 *	The old method had a hash lookup on allocation AND
675 	 *	on free.  The new method has brute-force on allocation,
676 	 *	and near-zero cost on free.
677 	 */
678 
679 	id = fd = -1;
680 	start_i = fr_rand() & SOCKOFFSET_MASK;
681 
682 #define ID_i ((i + start_i) & SOCKOFFSET_MASK)
683 	for (i = 0; i < MAX_SOCKETS; i++) {
684 		if (pl->sockets[ID_i].sockfd == -1) continue; /* paranoia */
685 
686 		ps = &(pl->sockets[ID_i]);
687 
688 		/*
689 		 *	This socket is marked as "don't use for new
690 		 *	packets".  But we can still receive packets
691 		 *	that are outstanding.
692 		 */
693 		if (ps->dont_use) continue;
694 
695 		/*
696 		 *	All IDs are allocated: ignore it.
697 		 */
698 		if (ps->num_outgoing == 256) continue;
699 
700 #ifdef WITH_TCP
701 		if (ps->proto != proto) continue;
702 #endif
703 
704 		/*
705 		 *	Address families don't match, skip it.
706 		 */
707 		if (ps->src_ipaddr.af != request->dst_ipaddr.af) continue;
708 
709 		/*
710 		 *	MUST match dst port, if we have one.
711 		 */
712 		if ((ps->dst_port != 0) &&
713 		    (ps->dst_port != request->dst_port)) continue;
714 
715 		/*
716 		 *	MUST match requested src port, if one has been given.
717 		 */
718 		if ((request->src_port != 0) &&
719 		    (ps->src_port != request->src_port)) continue;
720 
721 		/*
722 		 *	We don't care about the source IP, but this
723 		 *	socket is link local, and the requested
724 		 *	destination is not link local.  Ignore it.
725 		 */
726 		if (src_any && (ps->src_ipaddr.af == AF_INET) &&
727 		    (((ps->src_ipaddr.ipaddr.ip4addr.s_addr >> 24) & 0xff) == 127) &&
728 		    (((request->dst_ipaddr.ipaddr.ip4addr.s_addr >> 24) & 0xff) != 127)) continue;
729 
730 		/*
731 		 *	We're sourcing from *, and they asked for a
732 		 *	specific source address: ignore it.
733 		 */
734 		if (ps->src_any && !src_any) continue;
735 
736 		/*
737 		 *	We're sourcing from a specific IP, and they
738 		 *	asked for a source IP that isn't us: ignore
739 		 *	it.
740 		 */
741 		if (!ps->src_any && !src_any &&
742 		    (fr_ipaddr_cmp(&request->src_ipaddr,
743 				   &ps->src_ipaddr) != 0)) continue;
744 
745 		/*
746 		 *	UDP sockets are allowed to match
747 		 *	destination IPs exactly, OR a socket
748 		 *	with destination * is allowed to match
749 		 *	any requested destination.
750 		 *
751 		 *	TCP sockets must match the destination
752 		 *	exactly.  They *always* have dst_any=0,
753 		 *	so the first check always matches.
754 		 */
755 		if (!ps->dst_any &&
756 		    (fr_ipaddr_cmp(&request->dst_ipaddr,
757 				   &ps->dst_ipaddr) != 0)) continue;
758 
759 		/*
760 		 *	Otherwise, this socket is OK to use.
761 		 */
762 
763 		/*
764 		 *	Look for a free Id, starting from a random number.
765 		 */
766 		start_j = fr_rand() & 0x1f;
767 #define ID_j ((j + start_j) & 0x1f)
768 		for (j = 0; j < 32; j++) {
769 			if (ps->id[ID_j] == 0xff) continue;
770 
771 
772 			start_k = fr_rand() & 0x07;
773 #define ID_k ((k + start_k) & 0x07)
774 			for (k = 0; k < 8; k++) {
775 				if ((ps->id[ID_j] & (1 << ID_k)) != 0) continue;
776 
777 				ps->id[ID_j] |= (1 << ID_k);
778 				id = (ID_j * 8) + ID_k;
779 				fd = i;
780 				break;
781 			}
782 			if (fd >= 0) break;
783 		}
784 #undef ID_i
785 #undef ID_j
786 #undef ID_k
787 		if (fd >= 0) break;
788 	}
789 
790 	/*
791 	 *	Ask the caller to allocate a new ID.
792 	 */
793 	if (fd < 0) {
794 		fr_strerror_printf("Failed finding socket, caller must allocate a new one");
795 		return false;
796 	}
797 
798 	/*
799 	 *	Set the ID, source IP, and source port.
800 	 */
801 	request->id = id;
802 
803 	request->sockfd = ps->sockfd;
804 	request->src_ipaddr = ps->src_ipaddr;
805 	request->src_port = ps->src_port;
806 
807 	/*
808 	 *	If we managed to insert it, we're done.
809 	 */
810 	if (fr_packet_list_insert(pl, request_p)) {
811 		if (pctx) *pctx = ps->ctx;
812 		ps->num_outgoing++;
813 		pl->num_outgoing++;
814 		return true;
815 	}
816 
817 	/*
818 	 *	Mark the ID as free.  This is the one line from
819 	 *	id_free() that we care about here.
820 	 */
821 	ps->id[(request->id >> 3) & 0x1f] &= ~(1 << (request->id & 0x07));
822 
823 	request->id = -1;
824 	request->sockfd = -1;
825 	request->src_ipaddr.af = AF_UNSPEC;
826 	request->src_port = 0;
827 
828 	return false;
829 }
830 
831 /*
832  *	Should be called AFTER yanking it from the list, so that
833  *	any newly inserted entries don't collide with this one.
834  */
fr_packet_list_id_free(fr_packet_list_t * pl,RADIUS_PACKET * request,bool yank)835 bool fr_packet_list_id_free(fr_packet_list_t *pl,
836 			    RADIUS_PACKET *request, bool yank)
837 {
838 	fr_packet_socket_t *ps;
839 
840 	if (!pl || !request) return false;
841 
842 	VERIFY_PACKET(request);
843 
844 	if (yank && !fr_packet_list_yank(pl, request)) return false;
845 
846 	ps = fr_socket_find(pl, request->sockfd);
847 	if (!ps) return false;
848 
849 #if 0
850 	if (!ps->id[(request->id >> 3) & 0x1f] & (1 << (request->id & 0x07))) {
851 		fr_exit(1);
852 	}
853 #endif
854 
855 	ps->id[(request->id >> 3) & 0x1f] &= ~(1 << (request->id & 0x07));
856 
857 	ps->num_outgoing--;
858 	pl->num_outgoing--;
859 
860 	request->id = -1;
861 	request->src_ipaddr.af = AF_UNSPEC; /* id_alloc checks this */
862 	request->src_port = 0;
863 
864 	return true;
865 }
866 
867 /*
868  *	We always walk RBTREE_DELETE_ORDER, which is like RBTREE_IN_ORDER, except that
869  *	<0 means error, stop
870  *	0  means OK, continue
871  *	1  means delete current node and stop
872  *	2  means delete current node and continue
873  */
fr_packet_list_walk(fr_packet_list_t * pl,void * ctx,rb_walker_t callback)874 int fr_packet_list_walk(fr_packet_list_t *pl, void *ctx, rb_walker_t callback)
875 {
876 	if (!pl || !callback) return 0;
877 
878 	return rbtree_walk(pl->tree, RBTREE_DELETE_ORDER, callback, ctx);
879 }
880 
fr_packet_list_fd_set(fr_packet_list_t * pl,fd_set * set)881 int fr_packet_list_fd_set(fr_packet_list_t *pl, fd_set *set)
882 {
883 	int i, maxfd;
884 
885 	if (!pl || !set) return 0;
886 
887 	maxfd = -1;
888 
889 	for (i = 0; i < MAX_SOCKETS; i++) {
890 		if (pl->sockets[i].sockfd == -1) continue;
891 		FD_SET(pl->sockets[i].sockfd, set);
892 		if (pl->sockets[i].sockfd > maxfd) {
893 			maxfd = pl->sockets[i].sockfd;
894 		}
895 	}
896 
897 	if (maxfd < 0) return -1;
898 
899 	return maxfd + 1;
900 }
901 
902 /*
903  *	Round-robins the receivers, without priority.
904  *
905  *	FIXME: Add sockfd, if -1, do round-robin, else do sockfd
906  *		IF in fdset.
907  */
fr_packet_list_recv(fr_packet_list_t * pl,fd_set * set)908 RADIUS_PACKET *fr_packet_list_recv(fr_packet_list_t *pl, fd_set *set)
909 {
910 	int start;
911 	RADIUS_PACKET *packet;
912 
913 	if (!pl || !set) return NULL;
914 
915 	start = pl->last_recv;
916 	do {
917 		start++;
918 		start &= SOCKOFFSET_MASK;
919 
920 		if (pl->sockets[start].sockfd == -1) continue;
921 
922 		if (!FD_ISSET(pl->sockets[start].sockfd, set)) continue;
923 
924 #ifdef WITH_TCP
925 		if (pl->sockets[start].proto == IPPROTO_TCP) {
926 			packet = fr_tcp_recv(pl->sockets[start].sockfd, 0);
927 			if (!packet) {
928 				fr_strerror_printf("TCP connection has been closed");
929 				return NULL;
930 			}
931 
932 			/*
933 			 *	We always know src/dst ip/port for TCP
934 			 *	sockets.  So just fill them in.  Since
935 			 *	we read the packet from the TCP
936 			 *	socket, we invert src/dst.
937 			 */
938 			packet->dst_ipaddr = pl->sockets[start].src_ipaddr;
939 			packet->dst_port = pl->sockets[start].src_port;
940 			packet->src_ipaddr = pl->sockets[start].dst_ipaddr;
941 			packet->src_port = pl->sockets[start].dst_port;
942 
943 		} else
944 #endif
945 
946 		/*
947 		 *	Rely on rad_recv() to fill in the required
948 		 *	fields.
949 		 */
950 		packet = rad_recv(NULL, pl->sockets[start].sockfd, 0);
951 		if (!packet) continue;
952 
953 		/*
954 		 *	Call fr_packet_list_find_byreply().  If it
955 		 *	doesn't find anything, discard the reply.
956 		 */
957 
958 		pl->last_recv = start;
959 #ifdef WITH_TCP
960 		packet->proto = pl->sockets[start].proto;
961 #endif
962 		return packet;
963 	} while (start != pl->last_recv);
964 
965 	return NULL;
966 }
967 
fr_packet_list_num_incoming(fr_packet_list_t * pl)968 uint32_t fr_packet_list_num_incoming(fr_packet_list_t *pl)
969 {
970 	uint32_t num_elements;
971 
972 	if (!pl) return 0;
973 
974 	num_elements = rbtree_num_elements(pl->tree);
975 	if (num_elements < pl->num_outgoing) return 0; /* panic! */
976 
977 	return num_elements - pl->num_outgoing;
978 }
979 
fr_packet_list_num_outgoing(fr_packet_list_t * pl)980 uint32_t fr_packet_list_num_outgoing(fr_packet_list_t *pl)
981 {
982 	if (!pl) return 0;
983 
984 	return pl->num_outgoing;
985 }
986 
987 /*
988  *	Debug the packet if requested.
989  */
fr_packet_header_print(FILE * fp,RADIUS_PACKET * packet,bool received)990 void fr_packet_header_print(FILE *fp, RADIUS_PACKET *packet, bool received)
991 {
992 	char src_ipaddr[128];
993 	char dst_ipaddr[128];
994 
995 	if (!fp) return;
996 	if (!packet) return;
997 
998 	/*
999 	 *	Client-specific debugging re-prints the input
1000 	 *	packet into the client log.
1001 	 *
1002 	 *	This really belongs in a utility library
1003 	 */
1004 	if (is_radius_code(packet->code)) {
1005 		fprintf(fp, "%s %s Id %i from %s%s%s:%i to %s%s%s:%i length %zu\n",
1006 		        received ? "Received" : "Sent",
1007 		        fr_packet_codes[packet->code],
1008 		        packet->id,
1009 		        packet->src_ipaddr.af == AF_INET6 ? "[" : "",
1010 		        inet_ntop(packet->src_ipaddr.af,
1011 				  &packet->src_ipaddr.ipaddr,
1012 				  src_ipaddr, sizeof(src_ipaddr)),
1013 			packet->src_ipaddr.af == AF_INET6 ? "]" : "",
1014 		        packet->src_port,
1015 		        packet->dst_ipaddr.af == AF_INET6 ? "[" : "",
1016 		        inet_ntop(packet->dst_ipaddr.af,
1017 				  &packet->dst_ipaddr.ipaddr,
1018 				  dst_ipaddr, sizeof(dst_ipaddr)),
1019 		        packet->dst_ipaddr.af == AF_INET6 ? "]" : "",
1020 		        packet->dst_port,
1021 		        packet->data_len);
1022 	} else {
1023 		fprintf(fp, "%s code %u Id %i from %s%s%s:%i to %s%s%s:%i length %zu\n",
1024 		        received ? "Received" : "Sent",
1025 		        packet->code,
1026 		        packet->id,
1027 		        packet->src_ipaddr.af == AF_INET6 ? "[" : "",
1028 		        inet_ntop(packet->src_ipaddr.af,
1029 				  &packet->src_ipaddr.ipaddr,
1030 				  src_ipaddr, sizeof(src_ipaddr)),
1031 		        packet->src_ipaddr.af == AF_INET6 ? "]" : "",
1032 		        packet->src_port,
1033 		        packet->dst_ipaddr.af == AF_INET6 ? "[" : "",
1034 		        inet_ntop(packet->dst_ipaddr.af,
1035 				  &packet->dst_ipaddr.ipaddr,
1036 				  dst_ipaddr, sizeof(dst_ipaddr)),
1037 		        packet->dst_ipaddr.af == AF_INET6 ? "]" : "",
1038 		        packet->dst_port,
1039 		        packet->data_len);
1040 	}
1041 }
1042 
1043