The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rlm_icmp.c
Go to the documentation of this file.
1/*
2 * This program is is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or (at
5 * your option) any later version.
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 * You should have received a copy of the GNU General Public License
13 * along with this program; 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: fc972abb18b9dcbdb4595c20d9d9870bae0b13fb $
19 * @file rlm_icmp.c
20 * @brief Send ICMP echo requests.
21 *
22 * @copyright 2020 Network RADIUS SAS (legal@networkradius.com)
23 */
24RCSID("$Id: fc972abb18b9dcbdb4595c20d9d9870bae0b13fb $")
25
26#include <freeradius-devel/server/base.h>
27#include <freeradius-devel/server/module_rlm.h>
28#include <freeradius-devel/util/cap.h>
29#include <freeradius-devel/util/debug.h>
30#include <freeradius-devel/unlang/xlat_func.h>
31
32#include <fcntl.h>
33#include <unistd.h>
34
35/*
36 * Define a structure for our module configuration.
37 */
43
56
57typedef struct {
58 fr_rb_node_t node; //!< Entry in the outstanding list of echo requests.
59 bool replied; //!< do we have a reply?
60 fr_value_box_t *ip; //!< the IP we're pinging
61 uint32_t counter; //!< for pinging the same IP multiple times
62 request_t *request; //!< so it can be resumed when we get the echo reply
64
65typedef struct CC_HINT(__packed__) {
71 uint32_t data; //!< another 32-bits of randomness
72 uint32_t counter; //!< so that requests for the same IP are unique
74
75#define ICMP_ECHOREPLY (0)
76#define ICMP_ECHOREQUEST (8)
77
78#define ICMPV6_ECHOREQUEST (128)
79#define ICMPV6_ECHOREPLY (129)
80
81/*
82 * Calculate the ICMP portion of the checksum
83 */
84static uint16_t icmp_checksum(uint8_t *data, size_t data_len, uint16_t checksum)
85{
86 uint8_t *p, *end;
87 uint64_t sum;
88
89 sum = checksum;
90 data_len &= ~((size_t) 1); /* ensure it's always 16-bit aligned */
91
92 p = data;
93 end = data + data_len;
94 while (p < end) {
95 sum += fr_nbo_to_uint16(p); /* type / code */
96 p += 2;
97 }
98
99 while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16);
100
101 return ((uint16_t) ~sum);
102}
103
104static const conf_parser_t module_config[] = {
105 { FR_CONF_OFFSET("interface", rlm_icmp_t, interface) },
106 { FR_CONF_OFFSET_TYPE_FLAGS("src_ipaddr", FR_TYPE_COMBO_IP_ADDR, 0, rlm_icmp_t, src_ipaddr) },
107 { FR_CONF_OFFSET("timeout", rlm_icmp_t, timeout), .dflt = "1s" },
109};
110
112 xlat_ctx_t const *xctx,
113 UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
114{
115 rlm_icmp_echo_t *echo = talloc_get_type_abort(xctx->rctx, rlm_icmp_echo_t);
116 rlm_icmp_thread_t *t = talloc_get_type_abort(xctx->mctx->thread, rlm_icmp_thread_t);
117 fr_value_box_t *vb;
118
119 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_BOOL, NULL));
120 vb->vb_bool = echo->replied;
121
122 (void) fr_rb_delete(t->tree, echo);
123 talloc_free(echo);
124
126
127 return XLAT_ACTION_DONE;
128}
129
130static void xlat_icmp_cancel(xlat_ctx_t const *xctx, request_t *request, UNUSED fr_signal_t action)
131{
132 rlm_icmp_echo_t *echo = talloc_get_type_abort(xctx->rctx, rlm_icmp_echo_t);
133 rlm_icmp_thread_t *t = talloc_get_type_abort(xctx->mctx->thread, rlm_icmp_thread_t);
134
135 RDEBUG2("Cancelling ICMP request for %pV (counter=%d)", echo->ip, echo->counter);
136
137 (void) fr_rb_delete(t->tree, echo);
138 talloc_free(echo);
139}
140
141
142static void _xlat_icmp_timeout(xlat_ctx_t const *xctx, request_t *request, UNUSED fr_time_t fired)
143{
144 rlm_icmp_echo_t *echo = talloc_get_type_abort(xctx->rctx, rlm_icmp_echo_t);
145
146 if (echo->replied) return; /* it MUST already have been marked resumable. */
147
148 RDEBUG2("No response to ICMP request for %pV (counter=%d)", echo->ip, echo->counter);
149
151}
152
154 { .required = true, .single = true, .type = FR_TYPE_STRING },
156};
157
158/** Xlat to ping a specified ip address
159 *
160 * Example (ping 192.0.2.1):
161@verbatim
162%icmp(192.0.2.1)
163@endverbatim
164 *
165 * @ingroup xlat_functions
166 */
168 xlat_ctx_t const *xctx,
169 request_t *request, fr_value_box_list_t *in)
170{
171 rlm_icmp_t *inst = talloc_get_type_abort(xctx->mctx->mi->data, rlm_icmp_t);
172 rlm_icmp_thread_t *t = talloc_get_type_abort(xctx->mctx->thread, rlm_icmp_thread_t);
173 rlm_icmp_echo_t *echo;
174 icmp_header_t icmp;
175 uint16_t checksum;
176 ssize_t rcode;
177 socklen_t salen;
178 struct sockaddr_storage dst;
179 fr_value_box_t *in_head = fr_value_box_list_head(in);
180
181 /*
182 * If there's no input, do we can't ping anything.
183 */
184 if (!in_head) return XLAT_ACTION_FAIL;
185
186 if (fr_value_box_cast_in_place(ctx, in_head, t->ipaddr_type, NULL) < 0) {
187 RPEDEBUG("Failed casting result to IP address");
188 return XLAT_ACTION_FAIL;
189 }
190
191 MEM(echo = talloc_zero(ctx, rlm_icmp_echo_t));
192 echo->ip = in_head;
193 echo->request = request;
194 echo->counter = t->counter++;
195
196 /*
197 * Add the IP to the local tracking heap, so that the IO
198 * functions can find it.
199 *
200 * This insert will never fail, because of the unique
201 * counter above.
202 */
203 if (!fr_rb_insert(t->tree, echo)) {
204 RPEDEBUG("Failed inserting IP into tracking table");
205 talloc_free(echo);
206 return XLAT_ACTION_FAIL;
207 }
208
210 fr_time_add(fr_time(), inst->timeout)) < 0) {
211 RPEDEBUG("Failed adding timeout");
212 (void) fr_rb_delete(t->tree, echo);
213 talloc_free(echo);
214 return XLAT_ACTION_FAIL;
215 }
216
217 RDEBUG("Sending ICMP request to %pV (counter=%d)", echo->ip, echo->counter);
218
219 icmp = (icmp_header_t) {
220 .type = t->request_type,
221 .ident = t->ident,
222 .data = t->data,
223 .counter = echo->counter
224 };
225
226 (void) fr_ipaddr_to_sockaddr(&dst, &salen, &echo->ip->vb_ip, 0);
227
228 /*
229 * Calculate the checksum
230 */
231 checksum = 0;
232
233 /*
234 * Start off with the IPv6 pseudo-header checksum
235 */
236 if (t->ipaddr_type == FR_TYPE_IPV6_ADDR) {
237 checksum = fr_ip6_pesudo_header_checksum(&inst->src_ipaddr.addr.v6, &echo->ip->vb_ip.addr.v6,
238 sizeof(ip_header6_t) + sizeof(icmp), IPPROTO_ICMPV6);
239 }
240
241 /*
242 * Followed by checksumming the actual ICMP packet.
243 */
244 icmp.checksum = htons(icmp_checksum((uint8_t *) &icmp, sizeof(icmp), checksum));
245
246 rcode = sendto(t->fd, &icmp, sizeof(icmp), 0, (struct sockaddr *) &dst, salen);
247 if (rcode < 0) {
248 REDEBUG("Failed sending ICMP request to %pV: %s", echo->ip, fr_syserror(errno));
249 (void) fr_rb_delete(t->tree, echo);
250 talloc_free(echo);
251 return XLAT_ACTION_FAIL;
252 }
253
254 if ((size_t) rcode < sizeof(icmp)) {
255 REDEBUG("Failed sending entire ICMP packet");
256 (void) fr_rb_delete(t->tree, echo);
257 talloc_free(echo);
258 return XLAT_ACTION_FAIL;
259 }
260
262}
263
264static int8_t echo_cmp(void const *one, void const *two)
265{
266 rlm_icmp_echo_t const *a = one;
267 rlm_icmp_echo_t const *b = two;
268
269 /*
270 * No need to check IP, because "counter" is unique for each packet.
271 */
272 return CMP(a->counter, b->counter);
273}
274
275static void mod_icmp_read(UNUSED fr_event_list_t *el, UNUSED int sockfd, UNUSED int flags, void *uctx)
276{
277 module_thread_inst_ctx_t const *mctx = talloc_get_type_abort(uctx, module_thread_inst_ctx_t);
278 rlm_icmp_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_icmp_thread_t);
279
280 ssize_t len;
281 icmp_header_t *icmp;
282 rlm_icmp_echo_t my_echo, *echo;
283 uint64_t buffer[256];
284
285 len = read(t->fd, (char *) buffer, sizeof(buffer));
286 if (len <= 0) return;
287
288 HEXDUMP4((uint8_t const *)buffer, len, "received icmp packet ");
289
290 /*
291 * Ignore packets if we haven't sent any requests.
292 */
293 if (fr_rb_num_elements(t->tree) == 0) {
294 return;
295 }
296
297 // buffer is actually the IP header + the ICMP packet
298 if (t->ipaddr_type == FR_TYPE_IPV4_ADDR) {
300
301 if (IP_V(ip) != 4) {
302 return;
303 }
304
305 if ((IP_HL(ip) + sizeof(*icmp)) > sizeof(buffer)) {
306 return;
307 }
308
309 icmp = (icmp_header_t *) (((uint8_t *) buffer) + IP_HL(ip));
310 } else if (t->ipaddr_type == FR_TYPE_IPV6_ADDR) {
311 /*
312 * Outgoing packets automatically have an IPv6 header prepended to them
313 * (based on the destination address). ICMPv6 pseudo header checksum field
314 * (icmp6_cksum) will be filled automatically by the kernel. Incoming packets
315 * are received without the IPv6 header nor IPv6 extension headers.
316 *
317 * Note that this behavior is opposite from IPv4
318 * raw sockets and ICMPv4 sockets.
319 *
320 * Therefore, we don't have ip6 headers here. Only the icmp6 packet.
321 */
322 icmp = (icmp_header_t *) (((uint8_t *) buffer));
323 } else {
324 /*
325 * No idea. Ignore it.
326 */
327 return;
328 }
329
330 /*
331 * Ignore packets which aren't an echo reply, or which
332 * weren't for us. This is done *before* looking packets
333 * up in the rbtree, as these checks ensure that the
334 * packet is for this specific thread.
335 */
336 if ((icmp->type != t->reply_type) ||
337 (icmp->ident != t->ident) || (icmp->data != t->data)) {
338 return;
339 }
340
341 /*
342 * Look up the packet by the fields which determine *our* ICMP packets.
343 */
344 my_echo.counter = icmp->counter;
345 echo = fr_rb_find(t->tree, &my_echo);
346 if (!echo) {
347 DEBUG("%s - Can't find packet counter=%d in tree", mctx->mi->name, icmp->counter);
348 return;
349 }
350
351 (void) fr_rb_delete(t->tree, echo);
352
353 /*
354 * We have a reply!
355 */
356 echo->replied = true;
358}
359
361 UNUSED int fd_errno, void *uctx)
362{
363 module_ctx_t const *mctx = talloc_get_type_abort(uctx, module_ctx_t);
364 rlm_icmp_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_icmp_thread_t);
365
366 ERROR("%s - Failed reading from ICMP socket - Closing it", mctx->mi->name);
367
369 close(t->fd);
370 t->fd = -1;
371}
372
373/** Destroy thread data for the submodule.
374 *
375 */
377{
378 rlm_icmp_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_icmp_thread_t);
379
380 if (t->fd < 0) return 0;
381
382 (void) fr_event_fd_delete(mctx->el, t->fd, FR_EVENT_FILTER_IO);
383 close(t->fd);
384 t->fd = -1;
385
386 return 0;
387}
388
389/** Instantiate thread data for the submodule.
390 *
391 */
393{
394 module_thread_inst_ctx_t *our_mctx;
395 rlm_icmp_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_icmp_t);
396 rlm_icmp_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_icmp_thread_t);
397 fr_ipaddr_t ipaddr, *src;
398
399 int fd, af, proto;
400
401 /*
402 * Create a copy of the mctx on the heap that we can
403 * pass as the uctx to the io functions.
404 */
405 MEM(our_mctx = talloc_zero(t, module_thread_inst_ctx_t));
406 memcpy(our_mctx, mctx, sizeof(*our_mctx));
407
408 MEM(t->tree = fr_rb_inline_alloc(t, rlm_icmp_echo_t, node, echo_cmp, NULL));
409
410 /*
411 * Since these fields are random numbers, we don't care
412 * about network / host byte order. No one other than us
413 * will be interpreting these fields. As such, we can
414 * just treat them as host byte order.
415 *
416 * The only side effect of this choice is that this code
417 * will use (e.g.) 0xabcd for the ident, and Wireshark,
418 * tcpdump, etc. may show the ident as 0xcdab. That's
419 * fine.
420 */
421 t->data = fr_rand();
422 t->ident = fr_rand();
423
424 af = inst->src_ipaddr.af;
425
426 switch (af) {
427 default:
428 fr_strerror_const("Unsupported address family");
429 return -1;
430
431 case AF_UNSPEC:
432 case AF_INET:
433 af = AF_INET;
434 proto = IPPROTO_ICMP;
438 break;
439
440 case AF_INET6:
441 af = AF_INET6;
442 proto = IPPROTO_ICMPV6;
446 break;
447 }
448
449 /*
450 * Try and open with SOCK_DGRAM.
451 * If we get permission denied, fall back to SOCK_RAW.
452 * For some reason with docker, even if we have all
453 * the capabilities opening a SOCK_DGRAM/IPPROTO_ICMP
454 * socket fails.
455 *
456 * We don't appear to need to specify the IP header
457 * and the xlat works fine. Very strange.
458 */
459 fd = socket(af, SOCK_DGRAM, proto);
460 if (fd < 0) fd = socket(af, SOCK_RAW, proto);
461 if (fd < 0) {
462 fr_strerror_printf("Failed opening socket (%s, %s): %s",
463 fr_table_str_by_value(fr_net_af_table, af, "<INVALID>"),
465 fr_syserror(errno));
466 return -1;
467 }
468
469#ifndef FD_CLOEXEC
470#define FD_CLOEXEC (0)
471#endif
472
473 (void) fcntl(fd, F_SETFL, O_NONBLOCK | FD_CLOEXEC);
474
475 if (inst->src_ipaddr.af != AF_UNSPEC) {
476 ipaddr = inst->src_ipaddr;
477 src = &ipaddr;
478 } else {
479 src = NULL;
480 }
481
482 /*
483 * Only bind if we have a src and interface.
484 */
485 if (src && inst->interface && (fr_socket_bind(fd, inst->interface, src, NULL) < 0)) {
486 close(fd);
487 return -1;
488 }
489
490 /*
491 * We assume that the outbound socket is always writable.
492 * If not, too bad. Packets will get lost.
493 */
494 if (fr_event_fd_insert(t, NULL, mctx->el, fd,
496 NULL,
498 our_mctx) < 0) {
499 fr_strerror_const_push("Failed adding socket to event loop");
500 close(fd);
501 return -1;
502 }
503 t->fd = fd;
504
505 return 0;
506}
507
508static int mod_instantiate(module_inst_ctx_t const *mctx)
509{
510 rlm_icmp_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_icmp_t);
511
512 FR_TIME_DELTA_BOUND_CHECK("timeout", inst->timeout, >=, fr_time_delta_from_msec(100)); /* 1/10s minimum timeout */
513 FR_TIME_DELTA_BOUND_CHECK("timeout", inst->timeout, <=, fr_time_delta_from_sec(10));
514
515 return 0;
516}
517
518static int mod_bootstrap(module_inst_ctx_t const *mctx)
519{
520 xlat_t *xlat;
521
522 xlat = module_rlm_xlat_register(mctx->mi->boot, mctx, NULL, xlat_icmp, FR_TYPE_BOOL);
524
525 return 0;
526}
527
528static int mod_load(void)
529{
530#ifdef __linux__
531# ifndef HAVE_CAPABILITY_H
532 if ((geteuid() != 0)) PWARN("Server not built with cap interface, opening raw sockets will likely fail");
533# else
534 /*
535 * Request RAW capabilities on Linux. On other systems this does nothing.
536 */
537 if ((fr_cap_enable(CAP_NET_RAW, CAP_EFFECTIVE) < 0) && (geteuid() != 0)) {
538 PERROR("Failed setting capabilities required to open ICMP socket");
539 return -1;
540 }
541# endif
542#endif
543
544 return 0;
545}
546
547
548/*
549 * The module name should be the only globally exported symbol.
550 * That is, everything else should be 'static'.
551 *
552 * If the module needs to temporarily modify it's instantiation
553 * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
554 * The server will then take care of ensuring that the module
555 * is single-threaded.
556 */
559 .common = {
560 .magic = MODULE_MAGIC_INIT,
561 .name = "icmp",
562 .inst_size = sizeof(rlm_icmp_t),
564 .onload = mod_load,
565 .bootstrap = mod_bootstrap,
567 .thread_inst_size = sizeof(rlm_icmp_thread_t),
568 .thread_inst_type = "rlm_icmp_thread_t",
569 .thread_instantiate = mod_thread_instantiate,
570 .thread_detach = mod_thread_detach
571 }
572};
static int const char char buffer[256]
Definition acutest.h:576
#define RCSID(id)
Definition build.h:483
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
Definition build.h:112
#define UNUSED
Definition build.h:315
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:642
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:268
#define FR_TIME_DELTA_BOUND_CHECK(_name, _var, _op, _bound)
Definition cf_parse.h:513
#define FR_CONF_OFFSET_TYPE_FLAGS(_name, _type, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:241
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:579
static int fr_dcursor_insert(fr_dcursor_t *cursor, void *v)
Insert directly after the current item.
Definition dcursor.h:435
#define MEM(x)
Definition debug.h:36
#define ERROR(fmt,...)
Definition dhcpclient.c:41
static int sockfd
Definition dhcpclient.c:56
#define DEBUG(fmt,...)
Definition dhcpclient.c:39
static fr_slen_t in
Definition dict.h:824
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
#define fr_event_fd_insert(...)
Definition event.h:232
@ FR_EVENT_FILTER_IO
Combined filter for read/write functions/.
Definition event.h:62
static xlat_action_t xlat_icmp(TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Xlat to ping a specified ip address.
Definition rlm_icmp.c:167
int fr_ipaddr_to_sockaddr(struct sockaddr_storage *sa, socklen_t *salen, fr_ipaddr_t const *ipaddr, uint16_t port)
Convert our internal ip address representation to a sockaddr.
Definition inet.c:1392
IPv4/6 prefix.
void unlang_interpret_mark_runnable(request_t *request)
Mark a request as resumable.
Definition interpret.c:1359
#define PERROR(_fmt,...)
Definition log.h:228
#define PWARN(_fmt,...)
Definition log.h:227
#define RPEDEBUG(fmt,...)
Definition log.h:376
#define HEXDUMP4(_data, _len, _fmt,...)
Definition log.h:724
talloc_free(reap)
int fr_event_fd_delete(fr_event_list_t *el, int fd, fr_event_filter_t filter)
Remove a file descriptor from the event loop.
Definition event.c:1260
Stores all information relating to an event list.
Definition event.c:411
static int mod_instantiate(module_inst_ctx_t const *mctx)
Definition master.c:2670
unsigned short uint16_t
fr_type_t
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_COMBO_IP_ADDR
IPv4 or IPv6 address depending on length.
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
unsigned long int size_t
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:42
void * thread
Thread specific instance data.
Definition module_ctx.h:43
fr_event_list_t * el
Event list to register any IO handlers and timers against.
Definition module_ctx.h:68
void * thread
Thread instance data.
Definition module_ctx.h:67
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:64
module_instance_t * mi
Instance of the module being instantiated.
Definition module_ctx.h:51
Temporary structure to hold arguments for module calls.
Definition module_ctx.h:41
Temporary structure to hold arguments for instantiation calls.
Definition module_ctx.h:50
Temporary structure to hold arguments for thread_instantiation calls.
Definition module_ctx.h:63
xlat_t * module_rlm_xlat_register(TALLOC_CTX *ctx, module_inst_ctx_t const *mctx, char const *name, xlat_func_t func, fr_type_t return_type)
Definition module_rlm.c:257
module_t common
Common fields presented by all modules.
Definition module_rlm.h:39
static uint16_t fr_nbo_to_uint16(uint8_t const data[static sizeof(uint16_t)])
Read an unsigned 16bit integer from wire format (big endian)
Definition nbo.h:146
uint16_t fr_ip6_pesudo_header_checksum(struct in6_addr const *src, struct in6_addr const *dst, uint16_t ip_len, uint8_t ip_next)
Definition net.c:169
fr_table_num_sorted_t const fr_net_ip_proto_table[]
Strings for L4 protocols.
Definition net.c:28
fr_table_num_sorted_t const fr_net_af_table[]
Strings for address families.
Definition net.c:48
#define IP_HL(ip)
Definition net.h:93
#define IP_V(ip)
Definition net.h:92
static const conf_parser_t config[]
Definition base.c:183
static int mod_load(void)
Definition proto_arp.c:243
#define REDEBUG(fmt,...)
Definition radclient.h:52
#define RDEBUG2(fmt,...)
Definition radclient.h:54
#define RDEBUG(fmt,...)
Definition radclient.h:53
static char const * proto(int id, int porttype)
Definition radwho.c:85
static const conf_parser_t module_config[]
Definition radwho.c:59
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
static int mod_bootstrap(module_inst_ctx_t const *mctx)
Definition rlm_always.c:173
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
static int mod_thread_detach(module_thread_inst_ctx_t const *mctx)
static int mod_load(void)
Definition rlm_icmp.c:528
request_t * request
so it can be resumed when we get the echo reply
Definition rlm_icmp.c:62
uint32_t data
Definition rlm_icmp.c:48
fr_value_box_t * ip
the IP we're pinging
Definition rlm_icmp.c:60
fr_ipaddr_t src_ipaddr
Definition rlm_icmp.c:41
static void mod_icmp_error(fr_event_list_t *el, UNUSED int sockfd, UNUSED int flags, UNUSED int fd_errno, void *uctx)
Definition rlm_icmp.c:360
static xlat_action_t xlat_icmp_resume(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
Definition rlm_icmp.c:111
uint16_t ident
Definition rlm_icmp.c:49
module_rlm_t rlm_icmp
Definition rlm_icmp.c:558
uint8_t code
Definition rlm_icmp.c:67
static void _xlat_icmp_timeout(xlat_ctx_t const *xctx, request_t *request, UNUSED fr_time_t fired)
Definition rlm_icmp.c:142
uint32_t counter
so that requests for the same IP are unique
Definition rlm_icmp.c:72
uint16_t sequence
Definition rlm_icmp.c:70
#define ICMP_ECHOREQUEST
Definition rlm_icmp.c:76
static void xlat_icmp_cancel(xlat_ctx_t const *xctx, request_t *request, UNUSED fr_signal_t action)
Definition rlm_icmp.c:130
uint16_t ident
Definition rlm_icmp.c:69
static int mod_bootstrap(module_inst_ctx_t const *mctx)
Definition rlm_icmp.c:518
static uint16_t icmp_checksum(uint8_t *data, size_t data_len, uint16_t checksum)
Definition rlm_icmp.c:84
#define FD_CLOEXEC
fr_time_delta_t timeout
Definition rlm_icmp.c:40
static void mod_icmp_read(UNUSED fr_event_list_t *el, UNUSED int sockfd, UNUSED int flags, void *uctx)
Definition rlm_icmp.c:275
#define ICMP_ECHOREPLY
Definition rlm_icmp.c:75
fr_type_t ipaddr_type
Definition rlm_icmp.c:52
static xlat_arg_parser_t const xlat_icmp_args[]
Definition rlm_icmp.c:153
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
Instantiate thread data for the submodule.
Definition rlm_icmp.c:392
uint8_t request_type
Definition rlm_icmp.c:53
static int8_t echo_cmp(void const *one, void const *two)
Definition rlm_icmp.c:264
uint8_t reply_type
Definition rlm_icmp.c:54
fr_rb_tree_t * tree
Definition rlm_icmp.c:45
fr_rb_node_t node
Entry in the outstanding list of echo requests.
Definition rlm_icmp.c:58
static const conf_parser_t module_config[]
Definition rlm_icmp.c:104
uint8_t type
Definition rlm_icmp.c:66
char const * interface
Definition rlm_icmp.c:39
bool replied
do we have a reply?
Definition rlm_icmp.c:59
uint32_t counter
Definition rlm_icmp.c:50
#define ICMPV6_ECHOREPLY
Definition rlm_icmp.c:79
#define ICMPV6_ECHOREQUEST
Definition rlm_icmp.c:78
uint16_t checksum
Definition rlm_icmp.c:68
static int mod_thread_detach(module_thread_inst_ctx_t const *mctx)
Destroy thread data for the submodule.
Definition rlm_icmp.c:376
static int mod_instantiate(module_inst_ctx_t const *mctx)
Definition rlm_icmp.c:508
uint32_t data
another 32-bits of randomness
Definition rlm_icmp.c:71
uint32_t counter
for pinging the same IP multiple times
Definition rlm_icmp.c:61
static int instantiate(module_inst_ctx_t const *mctx)
Definition rlm_rest.c:1310
char const * name
Instance name e.g. user_database.
Definition module.h:335
size_t inst_size
Size of the module's instance data.
Definition module.h:203
void * data
Module's instance data.
Definition module.h:271
void * boot
Data allocated during the boostrap phase.
Definition module.h:274
fr_signal_t
Signals that can be generated/processed by request signal handlers.
Definition signal.h:38
@ FR_SIGNAL_CANCEL
Request has been cancelled.
Definition signal.h:40
int fr_socket_bind(int sockfd, char const *ifname, fr_ipaddr_t *src_ipaddr, uint16_t *src_port)
Bind a UDP/TCP v4/v6 socket to a given ipaddr src port, and interface.
Definition socket.c:229
eap_aka_sim_process_conf_t * inst
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition state_test.c:8
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:772
static fr_time_delta_t fr_time_delta_from_msec(int64_t msec)
Definition time.h:575
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition time.h:590
#define fr_time_add(_a, _b)
Add a time/time delta together.
Definition time.h:196
A time delta, a difference in time measured in nanoseconds.
Definition time.h:80
"server local" time.
Definition time.h:69
close(uq->fd)
static fr_event_list_t * el
xlat_action_t unlang_xlat_yield(request_t *request, xlat_func_t resume, xlat_func_signal_t signal, fr_signal_t sigmask, void *rctx)
Yield a request back to the interpreter from within a module.
Definition xlat.c:573
int unlang_xlat_timeout_add(request_t *request, fr_unlang_xlat_timeout_t callback, void const *rctx, fr_time_t when)
Add a timeout for an xlat handler.
Definition xlat.c:152
bool required
Argument must be present, and non-empty.
Definition xlat.h:148
#define XLAT_ARG_PARSER_TERMINATOR
Definition xlat.h:168
xlat_action_t
Definition xlat.h:37
@ XLAT_ACTION_FAIL
An xlat function failed.
Definition xlat.h:44
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition xlat.h:43
Definition for a single argument consumend by an xlat function.
Definition xlat.h:147
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const_push(_msg)
Definition strerror.h:227
#define fr_strerror_const(_msg)
Definition strerror.h:223
int fr_value_box_cast_in_place(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv)
Convert one type of fr_value_box_t to another in place.
Definition value.c:3572
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition value.h:621
static fr_slen_t data
Definition value.h:1265
static size_t char ** out
Definition value.h:997
void * rctx
Resume context.
Definition xlat_ctx.h:54
module_ctx_t const * mctx
Synthesised module calling ctx.
Definition xlat_ctx.h:52
An xlat calling ctx.
Definition xlat_ctx.h:49
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
Definition xlat_func.c:365