The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
list.c
Go to the documentation of this file.
1/*
2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2.1 of the License, or (at your option) any later version.
6 *
7 * This library 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 GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with this library; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: ab15108eea328b709a49969ad465ce5d3a491efb $
19 *
20 * @file protocols/radius/list.c
21 * @brief Functions to deal with outgoing lists / sets of packets.
22 *
23 * @copyright 2000-2017 The FreeRADIUS server project
24 */
25
26RCSID("$Id: ab15108eea328b709a49969ad465ce5d3a491efb $")
27
28#include "radius.h"
29#include "tcp.h"
30#include "list.h"
31
32#include <fcntl.h>
33#include <freeradius-devel/util/udp.h>
34#include <freeradius-devel/util/syserror.h>
35
36/*
37 * See if two packets are identical.
38 *
39 * Note that we do NOT compare the authentication vectors.
40 * That's because if the authentication vector is different,
41 * it means that the NAS has given up on the earlier request.
42 */
43int8_t fr_packet_cmp(void const *a_v, void const *b_v)
44{
45 fr_packet_t const *a = a_v, *b = b_v;
46 int8_t ret;
47
48 /*
49 * 256-way fanout for RADIUS IDs, then by FD. And then
50 * since there are sometimes multiple clients for one FD,
51 * source port. The comparison on dst_port is largely
52 * redundant with the comparison on FD, but it's not
53 * _completely_ redundant.
54 */
55 CMP_RETURN(a, b, id);
56 CMP_RETURN(a, b, socket.fd);
57 CMP_RETURN(a, b, socket.inet.src_port);
58 CMP_RETURN(a, b, socket.inet.dst_port);
59
60 /*
61 * Usually many client IPs, and few server IPs
62 */
63 ret = fr_ipaddr_cmp(&a->socket.inet.src_ipaddr, &b->socket.inet.src_ipaddr);
64 if (ret != 0) return ret;
65
66 return fr_ipaddr_cmp(&a->socket.inet.dst_ipaddr, &b->socket.inet.dst_ipaddr);
67}
68
69/*
70 * Create a fake "request" from a reply, for later lookup.
71 */
73 fr_packet_t const *reply)
74{
75 fr_socket_addr_swap(&request->socket, &reply->socket);
76 request->id = reply->id;
77}
78
79/*
80 * We need to keep track of the socket & it's IP/port.
81 */
82typedef struct {
84
87 void *ctx;
88
90
92
93 uint8_t id[32];
95
96
97#define FNV_MAGIC_PRIME (0x01000193)
98#define MAX_SOCKETS (256)
99#define SOCKOFFSET_MASK (MAX_SOCKETS - 1)
100#define SOCK2OFFSET(_sockfd) ((_sockfd * FNV_MAGIC_PRIME) & SOCKOFFSET_MASK)
101
102/*
103 * Structure defining a list of packets (incoming or outgoing)
104 * that should be managed.
105 */
116
117
118/*
119 * Ugh. Doing this on every sent/received packet is not nice.
120 */
122{
123 int i, start;
124
125 i = start = SOCK2OFFSET(sockfd);
126
127 do { /* make this hack slightly more efficient */
128 if (pl->sockets[i].socket.fd == sockfd) return &pl->sockets[i];
129
130 i = (i + 1) & SOCKOFFSET_MASK;
131 } while (i != start);
132
133 return NULL;
134}
135
137{
139
140 if (!pl) {
141 fr_strerror_const("Invalid argument");
142 return false;
143 }
144
145 ps = fr_socket_find(pl, sockfd);
146 if (!ps) {
147 fr_strerror_const("No such socket");
148 return false;
149 }
150
151 ps->dont_use = true;
152 return true;
153}
154
156{
158
159 if (!pl) return false;
160
161 ps = fr_socket_find(pl, sockfd);
162 if (!ps) return false;
163
164 ps->dont_use = false;
165 return true;
166}
167
168
170{
172
173 if (!pl) return false;
174
175 ps = fr_socket_find(pl, sockfd);
176 if (!ps) return false;
177
178 if (ps->num_outgoing != 0) return false;
179
180 ps->socket.fd = -1;
181 pl->num_sockets--;
182
183 return true;
184}
185
186
188 fr_ipaddr_t *dst_ipaddr, uint16_t dst_port,
189 void *ctx)
190{
191 int i, start;
192 struct sockaddr_storage src;
193 socklen_t sizeof_src;
195
196 if (!pl || !dst_ipaddr || (dst_ipaddr->af == AF_UNSPEC)) {
197 fr_strerror_const("Invalid argument");
198 return false;
199 }
200
201 if (pl->num_sockets >= MAX_SOCKETS) {
202 fr_strerror_const("Too many open sockets");
203 return false;
204 }
205
206 ps = NULL;
207 i = start = SOCK2OFFSET(sockfd);
208
209 do {
210 if (pl->sockets[i].socket.fd == -1) {
211 ps = &pl->sockets[i];
212 break;
213 }
214
215 i = (i + 1) & SOCKOFFSET_MASK;
216 } while (i != start);
217
218 if (!ps) {
219 fr_strerror_const("All socket entries are full");
220 return false;
221 }
222
223 memset(ps, 0, sizeof(*ps));
224 ps->ctx = ctx;
225 ps->socket.type = (proto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM;
226
227 /*
228 * Get address family, etc. first, so we know if we
229 * need to do udpfromto.
230 *
231 * FIXME: udpfromto also does this, but it's not
232 * a critical problem.
233 */
234 sizeof_src = sizeof(src);
235 memset(&src, 0, sizeof_src);
236 if (getsockname(sockfd, (struct sockaddr *) &src, &sizeof_src) < 0) {
237 fr_strerror_printf("%s", fr_syserror(errno));
238 return false;
239 }
240
241 if (fr_ipaddr_from_sockaddr(&ps->socket.inet.src_ipaddr, &ps->socket.inet.src_port, &src, sizeof_src) < 0) {
242 fr_strerror_const("Failed to get IP");
243 return false;
244 }
245
246 ps->socket.inet.dst_ipaddr = *dst_ipaddr;
247 ps->socket.inet.dst_port = dst_port;
248
249 ps->src_any = fr_ipaddr_is_inaddr_any(&ps->socket.inet.src_ipaddr);
250 if (ps->src_any < 0) return false;
251
252 ps->dst_any = fr_ipaddr_is_inaddr_any(&ps->socket.inet.dst_ipaddr);
253 if (ps->dst_any < 0) return false;
254
255 /*
256 * As the last step before returning.
257 */
258 ps->socket.fd = sockfd;
259 pl->num_sockets++;
260
261 return true;
262}
263
265{
266 if (!pl) return;
267
268 talloc_free(pl->tree);
269 talloc_free(pl);
270}
271
272
273/*
274 * Caller is responsible for managing the packet entries.
275 */
277{
278 int i;
280
281 pl = talloc_zero(NULL, fr_packet_list_t);
282 if (!pl) return NULL;
283 pl->tree = fr_rb_inline_alloc(pl, fr_packet_t, node, fr_packet_cmp, NULL); /* elements not talloc safe */
284 if (!pl->tree) {
286 return NULL;
287 }
288
289 for (i = 0; i < MAX_SOCKETS; i++) {
290 pl->sockets[i].socket.fd = -1;
291 }
292
293 pl->alloc_id = alloc_id;
294
295 return pl;
296}
297
298
299/*
300 * If pl->alloc_id is set, then fr_packet_list_id_alloc() MUST
301 * be called before inserting the packet into the list!
302 */
304 fr_packet_t *request)
305{
306 if (!pl || !request) return 0;
307
308 return fr_rb_insert(pl->tree, request);
309}
310
312{
313 if (!pl || !request) return 0;
314
315 return fr_rb_find(pl->tree, request);
316}
317
318
319/*
320 * This presumes that the reply has dst_ipaddr && dst_port set up
321 * correctly (i.e. real IP, or "*").
322 */
324{
325 fr_packet_t my_request, *request;
327
328 if (!pl || !reply) return NULL;
329
330 ps = fr_socket_find(pl, reply->socket.fd);
331 if (!ps) return NULL;
332
333 /*
334 * TCP sockets are always bound to the correct src/dst IP/port
335 */
336 if (ps->socket.type == SOCK_STREAM) {
337 fr_socket_addr_swap(&reply->socket, &ps->socket);
338 my_request.socket = ps->socket;
339 } else {
340 my_request.socket = ps->socket;
341
342 if (!ps->src_any) my_request.socket.inet.src_ipaddr = reply->socket.inet.dst_ipaddr;
343 my_request.socket.inet.dst_ipaddr = reply->socket.inet.src_ipaddr;
344 my_request.socket.inet.dst_port = reply->socket.inet.src_port;
345 }
346
347 /*
348 * Initialize request from reply, AND from the source
349 * IP & port of this socket. The client may have bound
350 * the socket to 0, in which case it's some random port,
351 * that is NOT in the original request->socket.inet.src_port.
352 */
353 my_request.socket.fd = reply->socket.fd;
354 my_request.id = reply->id;
355 request = &my_request;
356
357 return fr_rb_find(pl->tree, request);
358}
359
360
362{
363 if (!pl || !request) return false;
364
365 return fr_rb_delete(pl->tree, request);
366}
367
369{
370 if (!pl) return 0;
371
372 return fr_rb_num_elements(pl->tree);
373}
374
375
376/*
377 * 1 == ID was allocated & assigned
378 * 0 == couldn't allocate ID.
379 *
380 * Note that this ALSO assigns a socket to use, and updates
381 * packet->request->socket.inet.src_ipaddr && packet->request->socket.inet.src_port
382 *
383 * In multi-threaded systems, the calls to id_alloc && id_free
384 * should be protected by a mutex. This does NOT have to be
385 * the same mutex as the one protecting the insert/find/yank
386 * calls!
387 *
388 * We assume that the packet has dst_ipaddr && dst_port
389 * already initialized. We will use those to find an
390 * outgoing socket. The request MAY also have src_ipaddr set.
391 *
392 * We also assume that the sender doesn't care which protocol
393 * should be used.
394 */
396 fr_packet_t *request, void **pctx)
397{
398 int i, j, k, fd, id, start_i, start_j, start_k;
399 int src_any = 0;
400 int type;
401 fr_packet_socket_t *ps= NULL;
402
403 if ((request->socket.inet.dst_ipaddr.af == AF_UNSPEC) ||
404 (request->socket.inet.dst_port == 0)) {
405 fr_strerror_const("No destination address/port specified");
406 return false;
407 }
408
409 /*
410 * Special case: unspec == "don't care"
411 */
412 if (request->socket.inet.src_ipaddr.af == AF_UNSPEC) {
413 memset(&request->socket.inet.src_ipaddr, 0, sizeof(request->socket.inet.src_ipaddr));
414 request->socket.inet.src_ipaddr.af = request->socket.inet.dst_ipaddr.af;
415 }
416
417 src_any = fr_ipaddr_is_inaddr_any(&request->socket.inet.src_ipaddr);
418 if (src_any < 0) {
419 fr_strerror_const("Can't check src_ipaddr");
420 return false;
421 }
422
423 /*
424 * MUST specify a destination address.
425 */
426 if (fr_ipaddr_is_inaddr_any(&request->socket.inet.dst_ipaddr) != 0) {
427 fr_strerror_const("Must specify a dst_ipaddr");
428 return false;
429 }
430
431 /*
432 * FIXME: Go to an LRU system. This prevents ID reuse
433 * for as long as possible. The main problem with that
434 * approach is that it requires us to populate the
435 * LRU/FIFO when we add a new socket, or a new destination,
436 * which can be expensive.
437 *
438 * The LRU can be avoided if the caller takes care to free
439 * Id's only when all responses have been received, OR after
440 * a timeout.
441 *
442 * Right now, the random approach is almost OK... it's
443 * brute-force over all of the available ID's, BUT using
444 * random numbers for everything spreads the load a bit.
445 *
446 * The old method had a hash lookup on allocation AND
447 * on free. The new method has brute-force on allocation,
448 * and near-zero cost on free.
449 */
450
451 id = fd = -1;
452 if (request->id >= 0 && request->id < 256)
453 id = request->id;
454 start_i = fr_rand() & SOCKOFFSET_MASK;
455
456 type = (proto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM;
457
458#define ID_i ((i + start_i) & SOCKOFFSET_MASK)
459 for (i = 0; i < MAX_SOCKETS; i++) {
460 if (pl->sockets[ID_i].socket.fd == -1) continue; /* paranoia */
461
462 ps = &(pl->sockets[ID_i]);
463
464 /*
465 * This socket is marked as "don't use for new
466 * packets". But we can still receive packets
467 * that are outstanding.
468 */
469 if (ps->dont_use) continue;
470
471 /*
472 * All IDs are allocated: ignore it.
473 */
474 if (ps->num_outgoing == 256) continue;
475
476 if (ps->socket.type != type) continue;
477
478 /*
479 * Address families don't match, skip it.
480 */
481 if (ps->socket.inet.src_ipaddr.af != request->socket.inet.dst_ipaddr.af) continue;
482
483 /*
484 * MUST match dst port, if we have one.
485 */
486 if ((ps->socket.inet.dst_port != 0) &&
487 (ps->socket.inet.dst_port != request->socket.inet.dst_port)) continue;
488
489 /*
490 * MUST match requested src port, if one has been given.
491 */
492 if ((request->socket.inet.src_port != 0) &&
493 (ps->socket.inet.src_port != request->socket.inet.src_port)) continue;
494
495 /*
496 * We don't care about the source IP, but this
497 * socket is link local, and the requested
498 * destination is not link local. Ignore it.
499 */
500 if (src_any && (ps->socket.inet.src_ipaddr.af == AF_INET) &&
501 (((ps->socket.inet.src_ipaddr.addr.v4.s_addr >> 24) & 0xff) == 127) &&
502 (((request->socket.inet.dst_ipaddr.addr.v4.s_addr >> 24) & 0xff) != 127)) continue;
503
504 /*
505 * We're sourcing from *, and they asked for a
506 * specific source address: ignore it.
507 */
508 if (ps->src_any && !src_any) continue;
509
510 /*
511 * We're sourcing from a specific IP, and they
512 * asked for a source IP that isn't us: ignore
513 * it.
514 */
515 if (!ps->src_any && !src_any &&
516 (fr_ipaddr_cmp(&request->socket.inet.src_ipaddr,
517 &ps->socket.inet.src_ipaddr) != 0)) continue;
518
519 /*
520 * UDP sockets are allowed to match
521 * destination IPs exactly, OR a socket
522 * with destination * is allowed to match
523 * any requested destination.
524 *
525 * TCP sockets must match the destination
526 * exactly. They *always* have dst_any=0,
527 * so the first check always matches.
528 */
529 if (!ps->dst_any &&
530 (fr_ipaddr_cmp(&request->socket.inet.dst_ipaddr,
531 &ps->socket.inet.dst_ipaddr) != 0)) continue;
532
533 /*
534 * Otherwise, this socket is OK to use.
535 */
536
537 /*
538 * An explicit ID was requested
539 */
540
541 if (id != -1) {
542 if ((ps->id[(id >> 3) & 0x1f] & (1 << (id & 0x07))) != 0) continue;
543
544 ps->id[(id >> 3) & 0x1f] |= (1 << (id & 0x07));
545 fd = i;
546 break;
547 }
548
549 /*
550 * Look for a free Id, starting from a random number.
551 */
552 start_j = fr_rand() & 0x1f;
553#define ID_j ((j + start_j) & 0x1f)
554 for (j = 0; j < 32; j++) {
555 if (ps->id[ID_j] == 0xff) continue;
556
557
558 start_k = fr_rand() & 0x07;
559#define ID_k ((k + start_k) & 0x07)
560 for (k = 0; k < 8; k++) {
561 if ((ps->id[ID_j] & (1 << ID_k)) != 0) continue;
562
563 ps->id[ID_j] |= (1 << ID_k);
564 id = (ID_j * 8) + ID_k;
565 fd = i;
566 break;
567 }
568 if (fd >= 0) break;
569 }
570#undef ID_i
571#undef ID_j
572#undef ID_k
573 break;
574 }
575
576 /*
577 * Ask the caller to allocate a new ID.
578 */
579 if (fd < 0) {
580 fr_strerror_const("Failed finding socket, caller must allocate a new one");
581 return false;
582 }
583
584 /*
585 * Set the ID, source IP, and source port.
586 */
587 request->id = id;
588
589 request->socket.fd = ps->socket.fd;
590 request->socket.inet.src_ipaddr = ps->socket.inet.src_ipaddr;
591 request->socket.inet.src_port = ps->socket.inet.src_port;
592
593 /*
594 * If we managed to insert it, we're done.
595 */
596 if (fr_packet_list_insert(pl, request)) {
597 if (pctx) *pctx = ps->ctx;
598 ps->num_outgoing++;
599 pl->num_outgoing++;
600 return true;
601 }
602
603 /*
604 * Mark the ID as free. This is the one line from
605 * id_free() that we care about here.
606 */
607 ps->id[(request->id >> 3) & 0x1f] &= ~(1 << (request->id & 0x07));
608
609 request->id = -1;
610 request->socket.fd = -1;
611 request->socket.inet.src_ipaddr.af = AF_UNSPEC;
612 request->socket.inet.src_port = 0;
613
614 return false;
615}
616
617/*
618 * Should be called AFTER yanking it from the list, so that
619 * any newly inserted entries don't collide with this one.
620 */
622 fr_packet_t *request, bool yank)
623{
625
626 if (!pl || !request) return false;
627
628 if (yank && !fr_packet_list_yank(pl, request)) return false;
629
630 ps = fr_socket_find(pl, request->socket.fd);
631 if (!ps) return false;
632
633 ps->id[(request->id >> 3) & 0x1f] &= ~(1 << (request->id & 0x07));
634
635 ps->num_outgoing--;
636 pl->num_outgoing--;
637
638 request->id = -1;
639 request->socket.inet.src_ipaddr.af = AF_UNSPEC; /* id_alloc checks this */
640 request->socket.inet.src_port = 0;
641
642 return true;
643}
644
646{
647 int i, maxfd;
648
649 if (!pl || !set) return 0;
650
651 maxfd = -1;
652
653 for (i = 0; i < MAX_SOCKETS; i++) {
654 if (pl->sockets[i].socket.fd == -1) continue;
655 FD_SET(pl->sockets[i].socket.fd, set);
656 if (pl->sockets[i].socket.fd > maxfd) {
657 maxfd = pl->sockets[i].socket.fd;
658 }
659 }
660
661 if (maxfd < 0) return -1;
662
663 return maxfd + 1;
664}
665
666/*
667 * Round-robins the receivers, without priority.
668 *
669 * FIXME: Add socket.fd, if -1, do round-robin, else do socket.fd
670 * IF in fdset.
671 */
672fr_packet_t *fr_packet_list_recv(fr_packet_list_t *pl, fd_set *set, uint32_t max_attributes, bool require_message_authenticator)
673{
674 int start;
675 fr_packet_t *packet;
676
677 if (!pl || !set) return NULL;
678
679 start = pl->last_recv;
680 do {
681 start++;
682 start &= SOCKOFFSET_MASK;
683
684 if (pl->sockets[start].socket.fd == -1) continue;
685
686 if (!FD_ISSET(pl->sockets[start].socket.fd, set)) continue;
687
688 if (pl->sockets[start].socket.type == SOCK_STREAM) {
689 packet = fr_tcp_recv(pl->sockets[start].socket.fd, false);
690 } else
691 packet = fr_packet_recv(NULL, pl->sockets[start].socket.fd, UDP_FLAGS_NONE,
692 max_attributes, require_message_authenticator);
693 if (!packet) continue;
694
695 /*
696 * Call fr_packet_list_find_byreply(). If it
697 * doesn't find anything, discard the reply.
698 */
699
700 pl->last_recv = start;
701 packet->socket.type = pl->sockets[start].socket.type;
702 return packet;
703 } while (start != pl->last_recv);
704
705 return NULL;
706}
707
709{
710 uint32_t num_elements;
711
712 if (!pl) return 0;
713
714 num_elements = fr_rb_num_elements(pl->tree);
715 if (num_elements < pl->num_outgoing) return 0; /* panic! */
716
717 return num_elements - pl->num_outgoing;
718}
719
721{
722 if (!pl) return 0;
723
724 return pl->num_outgoing;
725}
#define RCSID(id)
Definition build.h:483
#define CMP_RETURN(_a, _b, _field)
Return if the comparison is not 0 (is unequal)
Definition build.h:121
static int sockfd
Definition dhcpclient.c:56
int fr_ipaddr_from_sockaddr(fr_ipaddr_t *ipaddr, uint16_t *port, struct sockaddr_storage const *sa, socklen_t salen)
Convert sockaddr to our internal ip address representation.
Definition inet.c:1441
int fr_ipaddr_is_inaddr_any(fr_ipaddr_t const *ipaddr)
Determine if an address is the INADDR_ANY address for its address family.
Definition inet.c:62
int8_t fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
Compare two ip addresses.
Definition inet.c:1346
int af
Address family.
Definition inet.h:64
IPv4/6 prefix.
talloc_free(reap)
fr_packet_t * fr_packet_list_find_byreply(fr_packet_list_t *pl, fr_packet_t *reply)
Definition list.c:323
#define ID_k
uint32_t fr_packet_list_num_incoming(fr_packet_list_t *pl)
Definition list.c:708
void fr_packet_list_free(fr_packet_list_t *pl)
Definition list.c:264
uint32_t fr_packet_list_num_outgoing(fr_packet_list_t *pl)
Definition list.c:720
fr_packet_t * fr_packet_list_recv(fr_packet_list_t *pl, fd_set *set, uint32_t max_attributes, bool require_message_authenticator)
Definition list.c:672
int8_t fr_packet_cmp(void const *a_v, void const *b_v)
Definition list.c:43
static fr_packet_socket_t * fr_socket_find(fr_packet_list_t *pl, int sockfd)
Definition list.c:121
bool fr_packet_list_socket_del(fr_packet_list_t *pl, int sockfd)
Definition list.c:169
#define ID_i
#define ID_j
fr_packet_socket_t sockets[MAX_SOCKETS]
Definition list.c:114
bool fr_packet_list_socket_freeze(fr_packet_list_t *pl, int sockfd)
Definition list.c:136
int num_sockets
Definition list.c:112
uint8_t id[32]
Definition list.c:93
fr_packet_t * fr_packet_list_find(fr_packet_list_t *pl, fr_packet_t *request)
Definition list.c:311
#define SOCK2OFFSET(_sockfd)
Definition list.c:100
fr_packet_list_t * fr_packet_list_create(int alloc_id)
Definition list.c:276
bool fr_packet_list_socket_thaw(fr_packet_list_t *pl, int sockfd)
Definition list.c:155
uint32_t num_outgoing
Definition list.c:110
bool fr_packet_list_id_alloc(fr_packet_list_t *pl, int proto, fr_packet_t *request, void **pctx)
Definition list.c:395
bool fr_packet_list_yank(fr_packet_list_t *pl, fr_packet_t *request)
Definition list.c:361
#define MAX_SOCKETS
Definition list.c:98
fr_socket_t socket
Definition list.c:83
bool 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)
Definition list.c:187
void fr_request_from_reply(fr_packet_t *request, fr_packet_t const *reply)
Definition list.c:72
bool fr_packet_list_insert(fr_packet_list_t *pl, fr_packet_t *request)
Definition list.c:303
uint32_t fr_packet_list_num_elements(fr_packet_list_t *pl)
Definition list.c:368
uint32_t num_outgoing
Definition list.c:89
fr_rb_tree_t * tree
Definition list.c:107
int fr_packet_list_fd_set(fr_packet_list_t *pl, fd_set *set)
Definition list.c:645
#define SOCKOFFSET_MASK
Definition list.c:99
bool fr_packet_list_id_free(fr_packet_list_t *pl, fr_packet_t *request, bool yank)
Definition list.c:621
Constants for the RADIUS protocol.
unsigned short uint16_t
unsigned int uint32_t
unsigned char uint8_t
fr_packet_t * fr_packet_recv(TALLOC_CTX *ctx, int fd, int flags, uint32_t max_attributes, bool require_message_authenticator)
Receive UDP client requests, and fill in the basics of a fr_packet_t structure.
Definition packet.c:205
static char const * proto(int id, int porttype)
Definition radwho.c:85
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition rand.c:105
uint32_t fr_rb_num_elements(fr_rb_tree_t *tree)
Return how many nodes there are in a tree.
Definition rb.c:781
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
Find an element in the tree, returning the data, not the node.
Definition rb.c:577
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
Definition rb.c:626
bool fr_rb_delete(fr_rb_tree_t *tree, void const *data)
Remove node and free data (if a free function was specified)
Definition rb.c:741
#define fr_rb_inline_alloc(_ctx, _type, _field, _data_cmp, _data_free)
Allocs a red black tree.
Definition rb.h:271
The main red black tree structure.
Definition rb.h:73
fr_aka_sim_id_type_t type
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
fr_packet_t * fr_tcp_recv(int sockfd, int flags)
Definition tcp.c:31
RADIUS over TCP.
#define UDP_FLAGS_NONE
Definition udp.h:37
fr_socket_t socket
This packet was received on.
Definition packet.h:57
int id
Packet ID (used to link requests/responses).
Definition packet.h:60
int af
AF_INET, AF_INET6, or AF_UNIX.
Definition socket.h:78
int fd
File descriptor if this is a live socket.
Definition socket.h:81
int type
SOCK_STREAM, SOCK_DGRAM, etc.
Definition socket.h:79
static void fr_socket_addr_swap(fr_socket_t *dst, fr_socket_t const *src)
Swap src/dst information of a fr_socket_t.
Definition socket.h:121
Holds information necessary for binding or connecting to a socket.
Definition socket.h:63
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223