The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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  */
24 RCSID("$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  */
38 typedef struct {
39  char const *interface;
42 } rlm_icmp_t;
43 
44 typedef struct {
46  int fd;
47 
51 
56 
57 typedef 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 
65 typedef 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  */
84 static 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 
104 static 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 
125  fr_dcursor_insert(out, vb);
126 
127  return XLAT_ACTION_DONE;
128 }
129 
130 static 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 
142 static 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  */
167 static xlat_action_t xlat_icmp(TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out,
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);
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 
261  return unlang_xlat_yield(request, xlat_icmp_resume, xlat_icmp_cancel, ~FR_SIGNAL_CANCEL, echo);
262 }
263 
264 static 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 
275 static 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) {
299  ip_header_t *ip = (ip_header_t *) buffer;
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 
360 static void mod_icmp_error(fr_event_list_t *el, UNUSED int sockfd, UNUSED int flags,
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 
508 static 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 
518 static 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 
528 static 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  */
557 extern module_rlm_t rlm_icmp;
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:574
#define RCSID(id)
Definition: build.h:481
#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:110
#define UNUSED
Definition: build.h:313
#define CONF_PARSER_TERMINATOR
Definition: cf_parse.h:627
#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:498
#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:564
static int fr_dcursor_insert(fr_dcursor_t *cursor, void *v)
Insert directly after the current item.
Definition: dcursor.h:435
fr_dcursor_eval_t void const * uctx
Definition: dcursor.h:546
#define ERROR(fmt,...)
Definition: dhcpclient.c:41
static int sockfd
Definition: dhcpclient.c:56
#define DEBUG(fmt,...)
Definition: dhcpclient.c:39
static fr_time_delta_t timeout
Definition: dhcpclient.c:54
static fr_slen_t in
Definition: dict.h:821
#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.
Definition: merged_model.c:272
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 bool echo
Main radmin state.
Definition: radmin.c:134
unsigned short uint16_t
Definition: merged_model.c:31
fr_type_t
Definition: merged_model.c:80
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
Definition: merged_model.c:86
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
Definition: merged_model.c:88
@ FR_TYPE_BOOL
A truth value.
Definition: merged_model.c:95
@ FR_TYPE_COMBO_IP_ADDR
IPv4 or IPv6 address depending on length.
Definition: merged_model.c:91
unsigned int uint32_t
Definition: merged_model.c:33
long int ssize_t
Definition: merged_model.c:24
unsigned char uint8_t
Definition: merged_model.c:30
unsigned long int size_t
Definition: merged_model.c:25
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:144
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
#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
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition: rand.c:106
uint32_t fr_rb_num_elements(fr_rb_tree_t *tree)
#define fr_rb_inline_alloc(_ctx, _type, _field, _data_cmp, _data_free)
Allocs a red black tree.
Definition: rb.h:271
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
bool fr_rb_delete(fr_rb_tree_t *tree, void const *data)
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
The main red black tree structure.
Definition: rb.h:73
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:1302
char const * name
Instance name e.g. user_database.
Definition: module.h:335
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
Definition: signal.h:48
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
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
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:561
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:140
bool required
Argument must be present, and non-empty.
Definition: xlat.h:146
#define XLAT_ARG_PARSER_TERMINATOR
Definition: xlat.h:166
xlat_action_t
Definition: xlat.h:35
@ XLAT_ACTION_FAIL
An xlat function failed.
Definition: xlat.h:42
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition: xlat.h:41
Definition for a single argument consumend by an xlat function.
Definition: xlat.h:145
#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