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: 393b9b071b96aba948877f7a85f6039813dbe208 $
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: 393b9b071b96aba948877f7a85f6039813dbe208 $")
25 
26 #define LOG_PREFIX mctx->inst->name
27 
28 #include <freeradius-devel/server/base.h>
29 #include <freeradius-devel/server/module_rlm.h>
30 #include <freeradius-devel/util/cap.h>
31 #include <freeradius-devel/util/debug.h>
32 #include <freeradius-devel/unlang/xlat_func.h>
33 
34 #include <fcntl.h>
35 #include <unistd.h>
36 
37 /*
38  * Define a structure for our module configuration.
39  */
40 typedef struct {
41  char const *interface;
44 } rlm_icmp_t;
45 
46 typedef struct {
48  int fd;
49 
53 
58 
59 typedef struct {
60  fr_rb_node_t node; //!< Entry in the outstanding list of echo requests.
61  bool replied; //!< do we have a reply?
62  fr_value_box_t *ip; //!< the IP we're pinging
63  uint32_t counter; //!< for pinging the same IP multiple times
64  request_t *request; //!< so it can be resumed when we get the echo reply
66 
67 typedef struct CC_HINT(__packed__) {
73  uint32_t data; //!< another 32-bits of randomness
74  uint32_t counter; //!< so that requests for the same IP are unique
76 
77 #define ICMP_ECHOREPLY (0)
78 #define ICMP_ECHOREQUEST (8)
79 
80 #define ICMPV6_ECHOREQUEST (128)
81 #define ICMPV6_ECHOREPLY (129)
82 
83 /*
84  * Calculate the ICMP portion of the checksum
85  */
86 static uint16_t icmp_checksum(uint8_t *data, size_t data_len, uint16_t checksum)
87 {
88  uint8_t *p, *end;
89  uint64_t sum;
90 
91  sum = checksum;
92  data_len &= ~((size_t) 1); /* ensure it's always 16-bit aligned */
93 
94  p = data;
95  end = data + data_len;
96  while (p < end) {
97  sum += fr_nbo_to_uint16(p); /* type / code */
98  p += 2;
99  }
100 
101  while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16);
102 
103  return ((uint16_t) ~sum);
104 }
105 
106 static const conf_parser_t module_config[] = {
107  { FR_CONF_OFFSET("interface", rlm_icmp_t, interface) },
108  { FR_CONF_OFFSET_TYPE_FLAGS("src_ipaddr", FR_TYPE_COMBO_IP_ADDR, 0, rlm_icmp_t, src_ipaddr) },
109  { FR_CONF_OFFSET("timeout", rlm_icmp_t, timeout), .dflt = "1s" },
111 };
112 
114  xlat_ctx_t const *xctx,
115  UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
116 {
117  rlm_icmp_echo_t *echo = talloc_get_type_abort(xctx->rctx, rlm_icmp_echo_t);
118  rlm_icmp_thread_t *t = talloc_get_type_abort(xctx->mctx->thread, rlm_icmp_thread_t);
119  fr_value_box_t *vb;
120 
121  MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_BOOL, NULL));
122  vb->vb_bool = echo->replied;
123 
124  (void) fr_rb_delete(t->tree, echo);
125  talloc_free(echo);
126 
127  fr_dcursor_insert(out, vb);
128 
129  return XLAT_ACTION_DONE;
130 }
131 
132 static void xlat_icmp_cancel(xlat_ctx_t const *xctx, request_t *request, UNUSED fr_signal_t action)
133 {
134  rlm_icmp_echo_t *echo = talloc_get_type_abort(xctx->rctx, rlm_icmp_echo_t);
135  rlm_icmp_thread_t *t = talloc_get_type_abort(xctx->mctx->thread, rlm_icmp_thread_t);
136 
137  RDEBUG2("Cancelling ICMP request for %pV (counter=%d)", echo->ip, echo->counter);
138 
139  (void) fr_rb_delete(t->tree, echo);
140  talloc_free(echo);
141 }
142 
143 
144 static void _xlat_icmp_timeout(xlat_ctx_t const *xctx, request_t *request, UNUSED fr_time_t fired)
145 {
146  rlm_icmp_echo_t *echo = talloc_get_type_abort(xctx->rctx, rlm_icmp_echo_t);
147 
148  if (echo->replied) return; /* it MUST already have been marked resumable. */
149 
150  RDEBUG2("No response to ICMP request for %pV (counter=%d)", echo->ip, echo->counter);
151 
153 }
154 
156  { .required = true, .single = true, .type = FR_TYPE_STRING },
158 };
159 
160 /** Xlat to ping a specified ip address
161  *
162  * Example (ping 192.0.2.1):
163 @verbatim
164 %icmp(192.0.2.1)
165 @endverbatim
166  *
167  * @ingroup xlat_functions
168  */
169 static xlat_action_t xlat_icmp(TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out,
170  xlat_ctx_t const *xctx,
171  request_t *request, fr_value_box_list_t *in)
172 {
173  rlm_icmp_t *inst = talloc_get_type_abort(xctx->mctx->inst->data, rlm_icmp_t);
174  rlm_icmp_thread_t *t = talloc_get_type_abort(xctx->mctx->thread, rlm_icmp_thread_t);
176  icmp_header_t icmp;
177  uint16_t checksum;
178  ssize_t rcode;
179  socklen_t salen;
180  struct sockaddr_storage dst;
181  fr_value_box_t *in_head = fr_value_box_list_head(in);
182 
183  /*
184  * If there's no input, do we can't ping anything.
185  */
186  if (!in_head) return XLAT_ACTION_FAIL;
187 
188  if (fr_value_box_cast_in_place(ctx, in_head, t->ipaddr_type, NULL) < 0) {
189  RPEDEBUG("Failed casting result to IP address");
190  return XLAT_ACTION_FAIL;
191  }
192 
193  MEM(echo = talloc_zero(ctx, rlm_icmp_echo_t));
194  echo->ip = in_head;
195  echo->request = request;
196  echo->counter = t->counter++;
197 
198  /*
199  * Add the IP to the local tracking heap, so that the IO
200  * functions can find it.
201  *
202  * This insert will never fail, because of the unique
203  * counter above.
204  */
205  if (!fr_rb_insert(t->tree, echo)) {
206  RPEDEBUG("Failed inserting IP into tracking table");
207  talloc_free(echo);
208  return XLAT_ACTION_FAIL;
209  }
210 
212  fr_time_add(fr_time(), inst->timeout)) < 0) {
213  RPEDEBUG("Failed adding timeout");
214  (void) fr_rb_delete(t->tree, echo);
215  talloc_free(echo);
216  return XLAT_ACTION_FAIL;
217  }
218 
219  RDEBUG("Sending ICMP request to %pV (counter=%d)", echo->ip, echo->counter);
220 
221  icmp = (icmp_header_t) {
222  .type = t->request_type,
223  .ident = t->ident,
224  .data = t->data,
225  .counter = echo->counter
226  };
227 
228  (void) fr_ipaddr_to_sockaddr(&dst, &salen, &echo->ip->vb_ip, 0);
229 
230  /*
231  * Calculate the checksum
232  */
233  checksum = 0;
234 
235  /*
236  * Start off with the IPv6 pseudo-header checksum
237  */
238  if (t->ipaddr_type == FR_TYPE_IPV6_ADDR) {
239  checksum = fr_ip6_pesudo_header_checksum(&inst->src_ipaddr.addr.v6, &echo->ip->vb_ip.addr.v6,
240  sizeof(ip_header6_t) + sizeof(icmp), IPPROTO_ICMPV6);
241  }
242 
243  /*
244  * Followed by checksumming the actual ICMP packet.
245  */
246  icmp.checksum = htons(icmp_checksum((uint8_t *) &icmp, sizeof(icmp), checksum));
247 
248  rcode = sendto(t->fd, &icmp, sizeof(icmp), 0, (struct sockaddr *) &dst, salen);
249  if (rcode < 0) {
250  REDEBUG("Failed sending ICMP request to %pV: %s", echo->ip, fr_syserror(errno));
251  (void) fr_rb_delete(t->tree, echo);
252  talloc_free(echo);
253  return XLAT_ACTION_FAIL;
254  }
255 
256  if ((size_t) rcode < sizeof(icmp)) {
257  REDEBUG("Failed sending entire ICMP packet");
258  (void) fr_rb_delete(t->tree, echo);
259  talloc_free(echo);
260  return XLAT_ACTION_FAIL;
261  }
262 
263  return unlang_xlat_yield(request, xlat_icmp_resume, xlat_icmp_cancel, ~FR_SIGNAL_CANCEL, echo);
264 }
265 
266 static int8_t echo_cmp(void const *one, void const *two)
267 {
268  rlm_icmp_echo_t const *a = one;
269  rlm_icmp_echo_t const *b = two;
270 
271  /*
272  * No need to check IP, because "counter" is unique for each packet.
273  */
274  return CMP(a->counter, b->counter);
275 }
276 
277 static void mod_icmp_read(UNUSED fr_event_list_t *el, UNUSED int sockfd, UNUSED int flags, void *uctx)
278 {
279  module_thread_inst_ctx_t const *mctx = talloc_get_type_abort(uctx, module_thread_inst_ctx_t);
280  rlm_icmp_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_icmp_thread_t);
281 
282  ssize_t len;
283  icmp_header_t *icmp;
284  rlm_icmp_echo_t my_echo, *echo;
285  uint64_t buffer[256];
286 
287  len = read(t->fd, (char *) buffer, sizeof(buffer));
288  if (len <= 0) return;
289 
290  HEXDUMP4((uint8_t const *)buffer, len, "received icmp packet ");
291 
292  /*
293  * Ignore packets if we haven't sent any requests.
294  */
295  if (fr_rb_num_elements(t->tree) == 0) {
296  return;
297  }
298 
299  // buffer is actually the IP header + the ICMP packet
300  if (t->ipaddr_type == FR_TYPE_IPV4_ADDR) {
301  ip_header_t *ip = (ip_header_t *) buffer;
302 
303  if (IP_V(ip) != 4) {
304  return;
305  }
306 
307  if ((IP_HL(ip) + sizeof(*icmp)) > sizeof(buffer)) {
308  return;
309  }
310 
311  icmp = (icmp_header_t *) (((uint8_t *) buffer) + IP_HL(ip));
312  } else if (t->ipaddr_type == FR_TYPE_IPV6_ADDR) {
313  /*
314  * Outgoing packets automatically have an IPv6 header prepended to them
315  * (based on the destination address). ICMPv6 pseudo header checksum field
316  * (icmp6_cksum) will be filled automatically by the kernel. Incoming packets
317  * are received without the IPv6 header nor IPv6 extension headers.
318  *
319  * Note that this behavior is opposite from IPv4
320  * raw sockets and ICMPv4 sockets.
321  *
322  * Therefore, we don't have ip6 headers here. Only the icmp6 packet.
323  */
324  icmp = (icmp_header_t *) (((uint8_t *) buffer));
325  } else {
326  /*
327  * No idea. Ignore it.
328  */
329  return;
330  }
331 
332  /*
333  * Ignore packets which aren't an echo reply, or which
334  * weren't for us. This is done *before* looking packets
335  * up in the rbtree, as these checks ensure that the
336  * packet is for this specific thread.
337  */
338  if ((icmp->type != t->reply_type) ||
339  (icmp->ident != t->ident) || (icmp->data != t->data)) {
340  return;
341  }
342 
343  /*
344  * Look up the packet by the fields which determine *our* ICMP packets.
345  */
346  my_echo.counter = icmp->counter;
347  echo = fr_rb_find(t->tree, &my_echo);
348  if (!echo) {
349  DEBUG("Can't find packet counter=%d in tree", icmp->counter);
350  return;
351  }
352 
353  (void) fr_rb_delete(t->tree, echo);
354 
355  /*
356  * We have a reply!
357  */
358  echo->replied = true;
360 }
361 
362 static void mod_icmp_error(fr_event_list_t *el, UNUSED int sockfd, UNUSED int flags,
363  UNUSED int fd_errno, void *uctx)
364 {
365  module_ctx_t const *mctx = talloc_get_type_abort(uctx, module_ctx_t);
366  rlm_icmp_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_icmp_thread_t);
367 
368  ERROR("Failed reading from ICMP socket - Closing it");
369 
371  close(t->fd);
372  t->fd = -1;
373 }
374 
375 /** Instantiate thread data for the submodule.
376  *
377  */
379 {
380  module_thread_inst_ctx_t *our_mctx;
381  rlm_icmp_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_icmp_t);
382  rlm_icmp_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_icmp_thread_t);
383  fr_ipaddr_t ipaddr, *src;
384 
385  int fd, af, proto;
386 
387  /*
388  * Create a copy of the mctx on the heap that we can
389  * pass as the uctx to the io functions.
390  */
391  MEM(our_mctx = talloc_zero(t, module_thread_inst_ctx_t));
392  memcpy(our_mctx, mctx, sizeof(*our_mctx));
393 
394  MEM(t->tree = fr_rb_inline_alloc(t, rlm_icmp_echo_t, node, echo_cmp, NULL));
395 
396  /*
397  * Since these fields are random numbers, we don't care
398  * about network / host byte order. No one other than us
399  * will be interpreting these fields. As such, we can
400  * just treat them as host byte order.
401  *
402  * The only side effect of this choice is that this code
403  * will use (e.g.) 0xabcd for the ident, and Wireshark,
404  * tcpdump, etc. may show the ident as 0xcdab. That's
405  * fine.
406  */
407  t->data = fr_rand();
408  t->ident = fr_rand();
409 
410  af = inst->src_ipaddr.af;
411 
412  switch (af) {
413  default:
414  fr_strerror_const("Unsupported address family");
415  return -1;
416 
417  case AF_UNSPEC:
418  case AF_INET:
419  af = AF_INET;
420  proto = IPPROTO_ICMP;
424  break;
425 
426  case AF_INET6:
427  af = AF_INET6;
428  proto = IPPROTO_ICMPV6;
432  break;
433  }
434 
435  /*
436  * Try and open with SOCK_DGRAM.
437  * If we get permission denied, fall back to SOCK_RAW.
438  * For some reason with docker, even if we have all
439  * the capabilities opening a SOCK_DGRAM/IPPROTO_ICMP
440  * socket fails.
441  *
442  * We don't appear to need to specify the IP header
443  * and the xlat works fine. Very strange.
444  */
445  fd = socket(af, SOCK_DGRAM, proto);
446  if (fd < 0) fd = socket(af, SOCK_RAW, proto);
447  if (fd < 0) {
448  fr_strerror_printf("Failed opening socket (%s, %s): %s",
449  fr_table_str_by_value(fr_net_af_table, af, "<INVALID>"),
451  fr_syserror(errno));
452  return -1;
453  }
454 
455 #ifndef FD_CLOEXEC
456 #define FD_CLOEXEC (0)
457 #endif
458 
459  (void) fcntl(fd, F_SETFL, O_NONBLOCK | FD_CLOEXEC);
460 
461  if (inst->src_ipaddr.af != AF_UNSPEC) {
462  ipaddr = inst->src_ipaddr;
463  src = &ipaddr;
464  } else {
465  src = NULL;
466  }
467 
468  /*
469  * Only bind if we have a src and interface.
470  */
471  if (src && inst->interface && (fr_socket_bind(fd, inst->interface, src, NULL) < 0)) {
472  close(fd);
473  return -1;
474  }
475 
476  /*
477  * We assume that the outbound socket is always writable.
478  * If not, too bad. Packets will get lost.
479  */
480  if (fr_event_fd_insert(t, NULL, mctx->el, fd,
482  NULL,
484  our_mctx) < 0) {
485  fr_strerror_const_push("Failed adding socket to event loop");
486  close(fd);
487  return -1;
488  }
489  t->fd = fd;
490 
491  return 0;
492 }
493 
494 static int mod_bootstrap(module_inst_ctx_t const *mctx)
495 {
496  rlm_icmp_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_icmp_t);
497  xlat_t *xlat;
498 
501 
502  FR_TIME_DELTA_BOUND_CHECK("timeout", inst->timeout, >=, fr_time_delta_from_msec(100)); /* 1/10s minimum timeout */
503  FR_TIME_DELTA_BOUND_CHECK("timeout", inst->timeout, <=, fr_time_delta_from_sec(10));
504 
505 #ifdef __linux__
506 # ifndef HAVE_CAPABILITY_H
507  if ((geteuid() != 0)) PWARN("Server not built with cap interface, opening raw sockets will likely fail");
508 # else
509  /*
510  * Request RAW capabilities on Linux. On other systems this does nothing.
511  */
512  if ((fr_cap_enable(CAP_NET_RAW, CAP_EFFECTIVE) < 0) && (geteuid() != 0)) {
513  PERROR("Failed setting capabilities required to open ICMP socket");
514  return -1;
515  }
516 # endif
517 #endif
518 
519  return 0;
520 }
521 
522 
523 /** Destroy thread data for the submodule.
524  *
525  */
527 {
528  rlm_icmp_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_icmp_thread_t);
529 
530  if (t->fd < 0) return 0;
531 
532  (void) fr_event_fd_delete(mctx->el, t->fd, FR_EVENT_FILTER_IO);
533  close(t->fd);
534  t->fd = -1;
535 
536  return 0;
537 }
538 
539 /*
540  * The module name should be the only globally exported symbol.
541  * That is, everything else should be 'static'.
542  *
543  * If the module needs to temporarily modify it's instantiation
544  * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
545  * The server will then take care of ensuring that the module
546  * is single-threaded.
547  */
548 extern module_rlm_t rlm_icmp;
550  .common = {
551  .magic = MODULE_MAGIC_INIT,
552  .name = "icmp",
553  .flags = MODULE_TYPE_THREAD_SAFE,
554  .inst_size = sizeof(rlm_icmp_t),
556  .bootstrap = mod_bootstrap,
557  .thread_inst_size = sizeof(rlm_icmp_thread_t),
558  .thread_inst_type = "rlm_icmp_thread_t",
559  .thread_instantiate = mod_thread_instantiate,
560  .thread_detach = mod_thread_detach
561  }
562 };
static int const char char buffer[256]
Definition: acutest.h:574
#define RCSID(id)
Definition: build.h:444
#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:626
#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:497
#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:563
static int fr_dcursor_insert(fr_dcursor_t *cursor, void *v)
Insert directly after the current item.
Definition: dcursor.h:434
#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:645
void *_CONST data
Module instance's parsed configuration.
Definition: dl_module.h:165
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition: dl_module.h:65
#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:169
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:1378
IPv4/6 prefix.
Definition: merged_model.c:272
void unlang_interpret_mark_runnable(request_t *request)
Mark a request as resumable.
Definition: interpret.c:1340
#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:1253
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
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:63
dl_module_inst_t const * inst
Dynamic loader API handle for the module.
Definition: module_ctx.h:52
void * thread
Thread instance data.
Definition: module_ctx.h:62
dl_module_inst_t const * inst
Dynamic loader API handle for the module.
Definition: module_ctx.h:42
dl_module_inst_t const * inst
Dynamic loader API handle for the module.
Definition: module_ctx.h:59
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:51
Temporary structure to hold arguments for thread_instantiation calls.
Definition: module_ctx.h:58
module_t common
Common fields presented by all modules.
Definition: module_rlm.h:37
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:137
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:188
#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)
Return how many nodes there are in a tree.
Definition: rb.c:775
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
Definition: rb.c:624
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:736
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:576
#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
request_t * request
so it can be resumed when we get the echo reply
Definition: rlm_icmp.c:64
uint32_t data
Definition: rlm_icmp.c:50
fr_value_box_t * ip
the IP we're pinging
Definition: rlm_icmp.c:62
fr_ipaddr_t src_ipaddr
Definition: rlm_icmp.c:43
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:362
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:113
uint16_t ident
Definition: rlm_icmp.c:51
module_rlm_t rlm_icmp
Definition: rlm_icmp.c:549
uint8_t code
Definition: rlm_icmp.c:69
static void _xlat_icmp_timeout(xlat_ctx_t const *xctx, request_t *request, UNUSED fr_time_t fired)
Definition: rlm_icmp.c:144
uint32_t counter
so that requests for the same IP are unique
Definition: rlm_icmp.c:74
uint16_t sequence
Definition: rlm_icmp.c:72
#define ICMP_ECHOREQUEST
Definition: rlm_icmp.c:78
static void xlat_icmp_cancel(xlat_ctx_t const *xctx, request_t *request, UNUSED fr_signal_t action)
Definition: rlm_icmp.c:132
uint16_t ident
Definition: rlm_icmp.c:71
static int mod_bootstrap(module_inst_ctx_t const *mctx)
Definition: rlm_icmp.c:494
static uint16_t icmp_checksum(uint8_t *data, size_t data_len, uint16_t checksum)
Definition: rlm_icmp.c:86
#define FD_CLOEXEC
fr_time_delta_t timeout
Definition: rlm_icmp.c:42
static void mod_icmp_read(UNUSED fr_event_list_t *el, UNUSED int sockfd, UNUSED int flags, void *uctx)
Definition: rlm_icmp.c:277
#define ICMP_ECHOREPLY
Definition: rlm_icmp.c:77
fr_type_t ipaddr_type
Definition: rlm_icmp.c:54
static xlat_arg_parser_t const xlat_icmp_args[]
Definition: rlm_icmp.c:155
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
Instantiate thread data for the submodule.
Definition: rlm_icmp.c:378
uint8_t request_type
Definition: rlm_icmp.c:55
static int8_t echo_cmp(void const *one, void const *two)
Definition: rlm_icmp.c:266
uint8_t reply_type
Definition: rlm_icmp.c:56
fr_rb_tree_t * tree
Definition: rlm_icmp.c:47
fr_rb_node_t node
Entry in the outstanding list of echo requests.
Definition: rlm_icmp.c:60
static const conf_parser_t module_config[]
Definition: rlm_icmp.c:106
uint8_t type
Definition: rlm_icmp.c:68
char const * interface
Definition: rlm_icmp.c:41
bool replied
do we have a reply?
Definition: rlm_icmp.c:61
uint32_t counter
Definition: rlm_icmp.c:52
#define ICMPV6_ECHOREPLY
Definition: rlm_icmp.c:81
#define ICMPV6_ECHOREQUEST
Definition: rlm_icmp.c:80
uint16_t checksum
Definition: rlm_icmp.c:70
static int mod_thread_detach(module_thread_inst_ctx_t const *mctx)
Destroy thread data for the submodule.
Definition: rlm_icmp.c:526
uint32_t data
another 32-bits of randomness
Definition: rlm_icmp.c:73
uint32_t counter
for pinging the same IP multiple times
Definition: rlm_icmp.c:63
@ MODULE_TYPE_THREAD_SAFE
Module is threadsafe.
Definition: module.h:49
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:253
static fr_time_delta_t fr_time_delta_from_msec(int64_t msec)
Definition: time.h:573
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition: time.h:588
#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:3521
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition: value.h:608
static fr_slen_t data
Definition: value.h:1259
static size_t char ** out
Definition: value.h:984
void * rctx
Resume context.
Definition: xlat_ctx.h:47
module_ctx_t const * mctx
Synthesised module calling ctx.
Definition: xlat_ctx.h:45
An xlat calling ctx.
Definition: xlat_ctx.h:42
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
Definition: xlat_func.c:360
xlat_t * xlat_func_register_module(TALLOC_CTX *ctx, module_inst_ctx_t const *mctx, char const *name, xlat_func_t func, fr_type_t return_type)
Register an xlat function for a module.
Definition: xlat_func.c:274