The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
proto_cron_crontab.c
Go to the documentation of this file.
1 /*
2  * This program 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
5  * (at 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: 03d6dfd8cf276253d36f3a0d802c61ad14cbb0ed $
19  * @file proto_cron_crontab.c
20  * @brief Generate crontab events.
21  *
22  * @copyright 2021 Network RADIUS SAS (legal@networkradius.com)
23  */
24 #include <netdb.h>
25 #include <fcntl.h>
26 #include <freeradius-devel/server/protocol.h>
27 #include <freeradius-devel/io/application.h>
28 #include <freeradius-devel/io/listen.h>
29 #include <freeradius-devel/io/schedule.h>
30 
31 #include "proto_cron.h"
32 
34 
36 
37 typedef struct {
38  fr_event_list_t *el; //!< event list
39  fr_network_t *nr; //!< network handler
40 
41  char const *name; //!< socket name
42 
44 
45  fr_event_timer_t const *ev; //!< for writing statistics
46 
47  fr_listen_t *parent; //!< master IO handler
48 
49  fr_time_t recv_time; //!< when the timer hit.
50 
51  bool suspended; //!< we suspend reading from the FD.
52  bool bootstrap; //!< get it started
54 
55 typedef struct {
56  unsigned int min;
57  unsigned int max;
58 
59  bool wildcard;
60  size_t offset;
61 
62  uint64_t fields;
63 } cron_tab_t;
64 
67 
68  CONF_SECTION *cs; //!< our configuration
69 
70  char const *filename; //!< where to read input packet from
71  fr_pair_list_t pair_list; //!< for input packet
72 
73  int code;
74  char const *spec; //!< crontab spec
75 
77 
78  fr_client_t *client; //!< static client
79 };
80 
81 
82 static int time_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
83 
86 
88  .func = time_parse },
89 
91 };
92 
93 /*
94  * Parse a basic field with sanity checks.
95  */
96 static int parse_field(CONF_ITEM *ci, char const **start, char const *name,
97  cron_tab_t *tab, unsigned int min, unsigned int max, size_t offset)
98 {
99  char const *p;
100  char *end = NULL;
101  unsigned int num, next, step, last = 0;
102  bool last_is_set = false;
103  bool wildcard = false;
104  unsigned int i;
105  uint64_t fields = 0;
106 
107  p = *start;
109 
110  if (!*p) {
111  cf_log_err(ci, "Missing field for %s", name);
112  return -1;
113  }
114 
115  tab->min = min;
116  tab->max = max;
117  tab->offset = offset;
118  tab->fields = 0;
119 
120  /*
121  * See 'man 5 crontab' for the format.
122  */
123  while (p) {
124  /*
125  * Allow wildcards, but only once.
126  */
127  if (*p == '*') {
128  if (wildcard) {
129  cf_log_err(ci, "Cannot use two wildcards for %s at %s", name, p);
130  return -1;
131  }
132 
133  end = UNCONST(char *, p) + 1;
134  wildcard = true;
135  num = min;
136  next = max;
137  goto check_step;
138  }
139 
140  /*
141  * If there's already a "*", we can't have another one.
142  */
143  if (wildcard) {
144  cf_log_err(ci, "Cannot use wildcard and numbers for %s at %s", name, p);
145  return -1;
146  }
147 
148  /*
149  * If it's not a wildcard, it MUST be a number,
150  * which is between min and max.
151  */
152  num = strtoul(p, &end, 10);
153  if ((num < min) || (num > max)) {
154  cf_log_err(ci, "Number is invalid or out of bounds (%d..%d) for %s at %s",
155  min, max, name, p);
156  return -1;
157  }
158 
159  /*
160  * Don't allow the same number to be specified
161  * multiple times.
162  */
163  if (!last_is_set) {
164  last_is_set = true;
165 
166  } else if (num <= last) {
167  cf_log_err(ci, "Number overlaps with previous value of %u, for %s at %s",
168  last, name, p);
169  return -1;
170  }
171  last = num;
172 
173  /*
174  * Ranges are allowed, with potential steps
175  */
176  if (*end == '-') {
177  p = end + 1;
178  next = strtoul(p, &end, 10);
179  if (next <= num) {
180  cf_log_err(ci, "End of range number overlaps with previous value of %u, for %s at %s",
181  num, name, p);
182  return -1;
183  }
184 
185  if (next > max) {
186  cf_log_err(ci, "End of range number is invalid or out of bounds (%d..%d) for %s at %s",
187  min, max, name, p);
188  return -1;
189  }
190 
191  check_step:
192  last = next;
193 
194  /*
195  * Allow /N
196  */
197  if (*end == '/') {
198  p = end + 1;
199 
200  step = strtoul(p, &end, 10);
201  if (step >= max) {
202  cf_log_err(ci, "Step value is invalid or out of bounds for %s at %s", name, p);
203  return -1;
204  }
205  } else {
206  step = 1;
207  }
208 
209  /*
210  * Set the necessary bits.
211  */
212  for (i = num; i <= next; i += step) {
213  fields |= ((uint64_t) 1) << i;
214  }
215  } /* end of range specifier */
216 
217  /*
218  * We can specify multiple fields, separated by a comma.
219  */
220  if (*end == ',') {
221  fields |= ((uint64_t) 1) << num;
222  p = end + 1;
223  continue;
224  }
225 
226  /*
227  * EOS or space is end of field.
228  */
229  if (!(!*end || isspace((uint8_t) *end))) {
230  cf_log_err(ci, "Unexpected text for %s at %s", name, end);
231  return -1;
232  }
233 
234  /*
235  * We're at the end of the field, stop.
236  */
237  break;
238  }
239 
240  /*
241  * Set a wildcard, so we can skip a lot of the later
242  * logic.
243  */
244  tab->wildcard = true;
245  for (i = min; i <= max; i++) {
246  if ((fields & (((uint64_t) 1) << i)) == 0) {
247  tab->wildcard = false;
248  break;
249  }
250  }
251 
252  tab->fields = fields;
253  *start = end;
254  return 0;
255 }
256 
257 /*
258  * Special names, including our own extensions.
259  */
261  { L("annually"), "0 0 1 1 *" },
262  { L("daily"), "0 0 * * *" },
263  { L("hourly"), "0 * * * *" },
264  { L("midnight"), "0 0 * * *" },
265  { L("monthly"), "0 0 1 * *" },
266 // { L("reboot"), "+" },
267  { L("weekly"), "0 0 * * 0" },
268  { L("yearly"), "0 0 1 1 *" },
269 };
271 
272 /** Wrapper around dl_instance which checks the syntax of a cron job
273  *
274  * @param[in] ctx to allocate data in (instance of proto_cron).
275  * @param[out] out Where to write a dl_module_inst_t containing the module handle and instance.
276  * @param[in] parent Base structure address.
277  * @param[in] ci #CONF_PAIR specifying the name of the type module.
278  * @param[in] rule unused.
279  * @return
280  * - 0 on success.
281  * - -1 on failure.
282  */
283 static int time_parse(UNUSED TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
284 {
285  proto_cron_crontab_t *inst = talloc_get_type_abort(parent, proto_cron_crontab_t);
286  CONF_PAIR *cp = cf_item_to_pair(ci);
287  char const *value = cf_pair_value(cp);
288  char const *p;
289 
290  p = value;
291 
292  /*
293  * Check for special names.
294  */
295  if (*p == '@') {
296  p = fr_table_value_by_str(time_names, p + 1, NULL);
297  if (!p) {
298  cf_log_err(ci, "Invalid time name '%s'", value);
299  return -1;
300  }
301 
302  /*
303  * Over-write the special names with standard
304  * ones, so that the rest of the parser is simpler.
305  */
306  *((char const **) out) = p;
307  return 0;
308  }
309 
310  *((char const **) out) = value;
311 
312  if (parse_field(ci, &p, "minute", &inst->tab[0], 0, 59, offsetof(struct tm, tm_min)) < 0) return -1;
313  if (parse_field(ci, &p, "hour", &inst->tab[1], 0, 59, offsetof(struct tm, tm_hour)) < 0) return -1;
314  if (parse_field(ci, &p, "day of month", &inst->tab[2], 1, 31, offsetof(struct tm, tm_mday)) < 0) return -1;
315  if (parse_field(ci, &p, "month", &inst->tab[3], 1,12, offsetof(struct tm, tm_mon)) < 0) return -1;
316  if (parse_field(ci, &p, "day of week", &inst->tab[4], 0, 6, offsetof(struct tm, tm_wday)) < 0) return -1;
317 
319 
320  if (*p) {
321  cf_log_err(ci, "Unexpected text after cron time specification");
322  return -1;
323  }
324 
325  return 0;
326 }
327 
328 static ssize_t mod_read(fr_listen_t *li, void **packet_ctx, fr_time_t *recv_time_p, uint8_t *buffer, size_t buffer_len, size_t *leftover)
329 {
331  proto_cron_crontab_thread_t *thread = talloc_get_type_abort(li->thread_instance, proto_cron_crontab_thread_t);
332  fr_io_address_t *address, **address_p;
333 
334  *leftover = 0;
335 
336  /*
337  * Suspend all activity on the FD, because we let the
338  * timers do their work.
339  */
340  if (!thread->suspended) {
341  static fr_event_update_t const pause_read[] = {
343  { 0 }
344  };
345 
346  if (fr_event_filter_update(thread->el, li->fd, FR_EVENT_FILTER_IO, pause_read) < 0) {
347  fr_assert(0);
348  }
349 
350  /*
351  * Don't read from it the first time.
352  */
353  thread->suspended = true;
354  return 0;
355  }
356 
357  /*
358  * Where the addresses should go. This is a special case
359  * for proto_radius.
360  */
361  address_p = (fr_io_address_t **) packet_ctx;
362  address = *address_p;
363 
364  memset(address, 0, sizeof(*address));
365  address->socket.inet.src_ipaddr.af = AF_INET;
366  address->socket.inet.dst_ipaddr.af = AF_INET;
367  address->radclient = inst->client;
368 
369  *recv_time_p = thread->recv_time;
370 
371  if (buffer_len < 1) {
372  DEBUG2("proto_cron_tab read buffer is too small for input packet");
373  return 0;
374  }
375 
376  buffer[0] = 0;
377 
378  /*
379  * Print out what we received.
380  */
381  DEBUG2("proto_cron_crontab - reading packet for %s",
382  thread->name);
383 
384  return 1;
385 }
386 
387 
388 static ssize_t mod_write(UNUSED fr_listen_t *li, UNUSED void *packet_ctx, UNUSED fr_time_t request_time,
389  UNUSED uint8_t *buffer, size_t buffer_len, UNUSED size_t written)
390 {
391  return buffer_len;
392 }
393 
394 
395 /** Open a crontab listener
396  *
397  */
398 static int mod_open(fr_listen_t *li)
399 {
401  proto_cron_crontab_thread_t *thread = talloc_get_type_abort(li->thread_instance, proto_cron_crontab_thread_t);
402 
403  fr_ipaddr_t ipaddr;
404 
405  /*
406  * We never read or write to this file, but we need a
407  * readable FD in order to bootstrap the process.
408  */
409  if (inst->filename == NULL) return -1;
410  li->fd = open(inst->filename, O_RDONLY);
411 
412  memset(&ipaddr, 0, sizeof(ipaddr));
413  ipaddr.af = AF_INET;
414  li->app_io_addr = fr_socket_addr_alloc_inet_src(li, IPPROTO_UDP, 0, &ipaddr, 0);
415 
416  fr_assert((cf_parent(inst->cs) != NULL) && (cf_parent(cf_parent(inst->cs)) != NULL)); /* listen { ... } */
417 
418  thread->name = talloc_typed_asprintf(thread, "cron_crontab from filename %s", inst->filename);
419  thread->parent = talloc_parent(li);
420 
421  return 0;
422 }
423 
424 
425 /** Decode the packet
426  *
427  */
428 static int mod_decode(void const *instance, request_t *request, UNUSED uint8_t *const data, UNUSED size_t data_len)
429 {
431  fr_io_track_t const *track = talloc_get_type_abort_const(request->async->packet_ctx, fr_io_track_t);
432  fr_io_address_t const *address = track->address;
433 
434  /*
435  * Set the request dictionary so that we can do
436  * generic->protocol attribute conversions as
437  * the request runs through the server.
438  */
439  request->dict = inst->parent->dict;
440 
441  /*
442  * Hacks for now until we have a lower-level decode routine.
443  */
444  if (inst->code) request->packet->code = inst->code;
445  request->packet->id = fr_rand() & 0xff;
446  request->reply->id = request->packet->id;
447  memset(request->packet->vector, 0, sizeof(request->packet->vector));
448 
449  request->packet->data = talloc_zero_array(request->packet, uint8_t, 1);
450  request->packet->data_len = 1;
451 
452  (void) fr_pair_list_copy(request->request_ctx, &request->request_pairs, &inst->pair_list);
453 
454  /*
455  * Set the rest of the fields.
456  */
457  request->client = UNCONST(fr_client_t *, address->radclient);
458 
459  request->packet->socket = address->socket;
460  fr_socket_addr_swap(&request->reply->socket, &address->socket);
461 
462  REQUEST_VERIFY(request);
463 
464  return 0;
465 }
466 
467 /*
468  * Get the next time interval.
469  *
470  * Set the relevant "struct tm" field to its next value, and
471  * return "true"
472  *
473  * Set the relevant "struct tm" field to its minimum value, and
474  * return "false".
475  */
476 static bool get_next(struct tm *tm, cron_tab_t const *tab)
477 {
478  unsigned int i, num = *(int *) (((uint8_t *) tm) + tab->offset);
479 
480  num++;
481 
482  /*
483  * Simplified process for "do each thing".
484  */
485  if (tab->wildcard) {
486  if (num < tab->max) goto done;
487  goto next;
488  }
489 
490  /*
491  * See when the next time interval is.
492  */
493  for (i = num; i <= tab->max; i++) {
494  if ((tab->fields & (((uint64_t) 1) << i)) != 0) {
495  num = i;
496  break;
497  }
498  }
499 
500  /*
501  * We ran out of time intervals. Reset this field to the
502  * minimum, and ask the caller to go to the next
503  * interval.
504  */
505  if (i > tab->max) {
506  next:
507  *(int *) (((uint8_t *) tm) + tab->offset) = tab->min;
508  return false;
509  }
510 
511 done:
512  *(int *) (((uint8_t *) tm) + tab->offset) = num;
513  return true;
514 }
515 
516 /*
517  * Called when tm.tm_sec == 0. If it isn't zero, then it means
518  * that the timer is late, and we treat it as if tm.tm_sec == 0.
519  */
520 static void do_cron(fr_event_list_t *el, fr_time_t now, void *uctx)
521 {
522  proto_cron_crontab_thread_t *thread = uctx;
523  struct tm tm;
524  time_t start = time(NULL), end;
525 
526  thread->recv_time = now;
527 
528  localtime_r(&start, &tm);
529 
530  /*
531  * For now, ignore "day of week". If the "day of week"
532  * is a wildcard, then ignore it. Otherwise, calculate
533  * next based on "day of month" and also "day of week",
534  * and then return the time which is closer.
535  */
536  tm.tm_sec = 0;
537  if (get_next(&tm, &thread->inst->tab[0])) goto set; /* minutes */
538  if (get_next(&tm, &thread->inst->tab[1])) goto set; /* hours */
539 
540  /*
541  * If we're running it every day of the week, just pay
542  * attention to the day of the month.
543  */
544  if (thread->inst->tab[4].wildcard) {
545  if (get_next(&tm, &thread->inst->tab[2])) goto set; /* days */
546 
547  if (get_next(&tm, &thread->inst->tab[3])) goto set; /* month */
548 
549  /*
550  * We ran out of months, so we have to go to the next year.
551  */
552  tm.tm_year++;
553 
554  } else {
555  /*
556  * Pick the earliest of "day of month" and "day of week".
557  */
558  struct tm m_tm = tm;
559  struct tm w_tm = tm;
560  int tm_wday = tm.tm_wday;
561  bool m_day = get_next(&m_tm, &thread->inst->tab[2]);
562  bool w_day = get_next(&w_tm, &thread->inst->tab[4]);
563  time_t m_time;
564  time_t w_time;
565 
566  /*
567  * No more days this week. Go to the
568  * start of the next week.
569  */
570  if (!w_day) {
571  w_tm = tm;
572  w_tm.tm_mday += (6 - tm_wday);
573 
574  (void) mktime(&w_tm); /* normalize it */
575 
576  tm_wday = w_tm.tm_wday;
577 #ifndef NDEBUG
578  w_day = get_next(&w_tm, &thread->inst->tab[4]);
579  fr_assert(w_day);
580 #else
581  (void) get_next(&w_tm, &thread->inst->tab[4]);
582 #endif
583  }
584 
585  /*
586  * Next weekday is ignored by mktime(), so we
587  * have to update the day of the month with the
588  * new value.
589  *
590  * Note that mktime() will also normalize the
591  * values, so we can just add "28 + 5" for a day
592  * of the month, and mktime() will normalize that
593  * to the correct day for the next month.
594  */
595  fr_assert(tm.tm_wday > tm_wday);
596  w_tm.tm_mday += tm.tm_wday - tm_wday;
597 
598  /*
599  * No more days this month, go to the next month,
600  * and potentially the next year.
601  */
602  if (!m_day && !get_next(&m_tm, &thread->inst->tab[3])) m_tm.tm_year++;
603 
604  /*
605  * We now have 2 times, one for "day of month"
606  * and another for "day of week". Pick the
607  * earliest one.
608  */
609  m_time = mktime(&m_tm);
610  w_time = mktime(&w_tm);
611 
612  if (m_time < w_time) {
613  end = m_time;
614  } else {
615  end = w_time;
616  }
617 
618  goto use_time;
619  }
620 
621 set:
622  end = mktime(&tm);
623  fr_assert(end >= start);
624 
625 use_time:
626  if (DEBUG_ENABLED2) {
627  char buffer[256];
628 
629  ctime_r(&end, buffer);
630  DEBUG("TIMER - virtual server %s next cron is at %s, in %ld seconds",
631  cf_section_name2(thread->inst->parent->server_cs), buffer, end - start);
632  }
633 
634  if (fr_event_timer_at(thread, el, &thread->ev, fr_time_add(now, fr_time_delta_from_sec(end - start)),
635  do_cron, thread) < 0) {
636  fr_assert(0);
637  }
638 
639  /*
640  * Don't run the event the first time.
641  */
642  if (thread->bootstrap) {
643  thread->bootstrap = false;
644  return;
645  }
646 
647  /*
648  * Now that we've set the timer, tell the network side to
649  * call our read routine.
650  */
651  fr_network_listen_read(thread->nr, thread->parent);
652 }
653 
654 /** Set the event list for a new socket
655  *
656  * @param[in] li the listener
657  * @param[in] el the event list
658  * @param[in] nr context from the network side
659  */
660 static void mod_event_list_set(fr_listen_t *li, fr_event_list_t *el, void *nr)
661 {
663  proto_cron_crontab_thread_t *thread = talloc_get_type_abort(li->thread_instance, proto_cron_crontab_thread_t);
664 
665  thread->el = el;
666  thread->nr = nr;
667  thread->inst = inst;
668  thread->bootstrap = true;
669 
670  do_cron(el, fr_time(), thread);
671 }
672 
673 static char const *mod_name(fr_listen_t *li)
674 {
675  proto_cron_crontab_thread_t *thread = talloc_get_type_abort(li->thread_instance, proto_cron_crontab_thread_t);
676 
677  return thread->name;
678 }
679 
680 
681 static int mod_bootstrap(module_inst_ctx_t const *mctx)
682 {
683  proto_cron_crontab_t *inst = talloc_get_type_abort(mctx->inst->data, proto_cron_crontab_t);
684  CONF_SECTION *conf = mctx->inst->data;
685  dl_module_inst_t const *dl_inst;
686 
687  /*
688  * Find the dl_module_inst_t holding our instance data
689  * so we can find out what the parent of our instance
690  * was.
691  */
692  dl_inst = dl_module_instance_by_data(inst);
693  fr_assert(dl_inst);
694 
695  inst->parent = talloc_get_type_abort(dl_inst->parent->data, proto_cron_t);
696 
697  inst->cs = conf;
698 
699  return 0;
700 }
701 
703 {
705 
706  return inst->client;
707 }
708 
709 
710 static int mod_instantiate(module_inst_ctx_t const *mctx)
711 {
712  proto_cron_crontab_t *inst = talloc_get_type_abort(mctx->inst->data, proto_cron_crontab_t);
713  CONF_SECTION *conf = mctx->inst->data;
714  fr_client_t *client;
715  fr_pair_t *vp;
716  FILE *fp;
717  bool done = false;
718 
719  fr_pair_list_init(&inst->pair_list);
720  inst->client = client = talloc_zero(inst, fr_client_t);
721  if (!inst->client) return 0;
722 
723  client->ipaddr.af = AF_INET;
724  client->src_ipaddr = client->ipaddr;
725 
726  client->longname = client->shortname = inst->filename;
727  client->secret = talloc_strdup(client, "testing123");
728  client->nas_type = talloc_strdup(client, "load");
729  client->use_connected = false;
730 
731  fp = fopen(inst->filename, "r");
732  if (!fp) {
733  cf_log_err(conf, "Failed opening %s - %s",
734  inst->filename, fr_syserror(errno));
735  return -1;
736  }
737 
738  if (fr_pair_list_afrom_file(inst, inst->parent->dict, &inst->pair_list, fp, &done) < 0) {
739  cf_log_perr(conf, "Failed reading %s", inst->filename);
740  fclose(fp);
741  return -1;
742  }
743 
744  fclose(fp);
745 
746  vp = fr_pair_find_by_da(&inst->pair_list, NULL, inst->parent->attr_packet_type);
747  if (vp) inst->code = vp->vp_uint32;
748 
749  return 0;
750 }
751 
753  .common = {
754  .magic = MODULE_MAGIC_INIT,
755  .name = "cron_crontab",
756  .config = crontab_listen_config,
757  .inst_size = sizeof(proto_cron_crontab_t),
758  .thread_inst_size = sizeof(proto_cron_crontab_thread_t),
759  .bootstrap = mod_bootstrap,
760  .instantiate = mod_instantiate
761  },
762  .default_message_size = 4096,
763  .track_duplicates = false,
764 
765  .open = mod_open,
766  .read = mod_read,
767  .write = mod_write,
768  .event_list_set = mod_event_list_set,
769  .client_find = mod_client_find,
770  .get_name = mod_name,
771 
772  .decode = mod_decode,
773 };
static int const char char buffer[256]
Definition: acutest.h:574
module_t common
Common fields to all loadable modules.
Definition: app_io.h:34
Public structure describing an I/O path for a protocol.
Definition: app_io.h:33
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition: build.h:165
#define L(_str)
Helper for initialising arrays of string literals.
Definition: build.h:207
#define UNUSED
Definition: build.h:313
#define NUM_ELEMENTS(_t)
Definition: build.h:335
#define CONF_PARSER_TERMINATOR
Definition: cf_parse.h:626
#define FR_CONF_OFFSET_FLAGS(_name, _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:256
@ CONF_FLAG_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
Definition: cf_parse.h:406
@ CONF_FLAG_FILE_INPUT
File matching value must exist, and must be readable.
Definition: cf_parse.h:412
@ CONF_FLAG_NOT_EMPTY
CONF_PAIR is required to have a non zero length value.
Definition: cf_parse.h:421
Defines a CONF_PAIR to C data type mapping.
Definition: cf_parse.h:563
Common header for all CONF_* types.
Definition: cf_priv.h:49
Configuration AVP similar to a fr_pair_t.
Definition: cf_priv.h:70
A section grouping multiple CONF_PAIR.
Definition: cf_priv.h:89
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition: cf_util.c:629
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition: cf_util.c:1126
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition: cf_util.c:1511
#define cf_log_err(_cf, _fmt,...)
Definition: cf_util.h:265
#define cf_parent(_cf)
Definition: cf_util.h:98
#define cf_log_perr(_cf, _fmt,...)
Definition: cf_util.h:272
#define DEBUG(fmt,...)
Definition: dhcpclient.c:39
Test enumeration values.
Definition: dict_test.h:92
dl_module_inst_t const * dl_module_instance_by_data(void const *data)
Lookup a dl_module_inst_t via instance data.
Definition: dl_module.c:215
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
dl_module_inst_t const *_CONST parent
Parent module's instance (if any).
Definition: dl_module.h:167
A module/inst tuple.
Definition: dl_module.h:162
@ FR_EVENT_FILTER_IO
Combined filter for read/write functions/.
Definition: event.h:62
#define fr_event_filter_update(...)
Definition: event.h:224
#define FR_EVENT_SUSPEND(_s, _f)
Temporarily remove the filter for a func from kevent.
Definition: event.h:94
#define fr_event_timer_at(...)
Definition: event.h:250
Callbacks for the FR_EVENT_FILTER_IO filter.
Definition: event.h:173
Structure describing a modification to a filter's state.
Definition: event.h:75
int af
Address family.
Definition: inet.h:64
IPv4/6 prefix.
Definition: merged_model.c:272
fr_socket_t socket
src/dst ip and port.
Definition: base.h:336
fr_client_t const * radclient
old-style client definition
Definition: base.h:338
fr_socket_t * app_io_addr
for tracking duplicate sockets
Definition: listen.h:35
void const * app_io_instance
I/O path configuration context.
Definition: listen.h:32
void * thread_instance
thread / socket context
Definition: listen.h:33
int fd
file descriptor for this socket - set by open
Definition: listen.h:28
void fr_network_listen_read(fr_network_t *nr, fr_listen_t *li)
Signal the network to read from a listener.
Definition: network.c:311
fr_ipaddr_t ipaddr
IPv4/IPv6 address of the host.
Definition: client.h:80
char const * secret
Secret PSK.
Definition: client.h:87
fr_ipaddr_t src_ipaddr
IPv4/IPv6 address to send responses from (family must match ipaddr).
Definition: client.h:81
char const * nas_type
Type of client (arbitrary).
Definition: client.h:99
char const * longname
Client identifier.
Definition: client.h:84
char const * shortname
Client nickname.
Definition: client.h:85
bool use_connected
do we use connected sockets for this client
Definition: client.h:92
Describes a host allowed to send packets to the server.
Definition: client.h:77
#define DEBUG_ENABLED2
True if global debug level 1-2 messages are enabled.
Definition: log.h:258
Stores all information relating to an event list.
Definition: event.c:411
A timer event.
Definition: event.c:102
static fr_event_update_t pause_read[]
Definition: master.c:154
fr_io_address_t const * address
of this packet.. shared between multiple packets
Definition: master.h:54
long int ssize_t
Definition: merged_model.c:24
unsigned char uint8_t
Definition: merged_model.c:30
#define fr_skip_whitespace(_p)
Skip whitespace ('\t', '\n', '\v', '\f', '\r', ' ')
Definition: misc.h:59
char * ctime_r(time_t const *l_clock, char *l_buf)
Definition: missing.c:182
struct tm * localtime_r(time_t const *l_clock, struct tm *result)
Definition: missing.c:163
dl_module_inst_t const * inst
Dynamic loader API handle for the module.
Definition: module_ctx.h:52
Temporary structure to hold arguments for instantiation calls.
Definition: module_ctx.h:51
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
Definition: pair.c:688
int fr_pair_list_copy(TALLOC_CTX *ctx, fr_pair_list_t *to, fr_pair_list_t const *from)
Duplicate a list of pairs.
Definition: pair.c:2316
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition: pair.c:46
int fr_pair_list_afrom_file(TALLOC_CTX *ctx, fr_dict_t const *dict, fr_pair_list_t *out, FILE *fp, bool *pfiledone)
Read valuepairs from the fp up to End-Of-File.
Definition: pair_legacy.c:572
Cron master protocol handler.
CONF_SECTION * server_cs
server CS for this listener
Definition: proto_cron.h:38
static const conf_parser_t crontab_listen_config[]
fr_event_timer_t const * ev
for writing statistics
bool wildcard
Definition: cron.h:7
fr_client_t * client
static client
char const * name
socket name
static ssize_t mod_read(fr_listen_t *li, void **packet_ctx, fr_time_t *recv_time_p, uint8_t *buffer, size_t buffer_len, size_t *leftover)
static int mod_decode(void const *instance, request_t *request, UNUSED uint8_t *const data, UNUSED size_t data_len)
Decode the packet.
static size_t time_names_len
char const * filename
where to read input packet from
fr_time_t recv_time
when the timer hit.
fr_event_list_t * el
event list
proto_cron_t * parent
unsigned int max
Definition: cron.h:5
struct proto_cron_tab_s proto_cron_crontab_t
static int mod_bootstrap(module_inst_ctx_t const *mctx)
static int time_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
static ssize_t mod_write(UNUSED fr_listen_t *li, UNUSED void *packet_ctx, UNUSED fr_time_t request_time, UNUSED uint8_t *buffer, size_t buffer_len, UNUSED size_t written)
fr_listen_t * parent
master IO handler
unsigned int min
Definition: cron.h:4
static void mod_event_list_set(fr_listen_t *li, fr_event_list_t *el, void *nr)
Set the event list for a new socket.
static int mod_open(fr_listen_t *li)
Open a crontab listener.
uint64_t fields
Definition: cron.h:10
static char const * mod_name(fr_listen_t *li)
fr_app_io_t proto_cron_crontab
bool suspended
we suspend reading from the FD.
static bool get_next(struct tm *tm, cron_tab_t const *tab)
static int parse_field(CONF_ITEM *ci, char const **start, char const *name, cron_tab_t *tab, unsigned int min, unsigned int max, size_t offset)
CONF_SECTION * cs
our configuration
char const * spec
crontab spec
size_t offset
Definition: cron.h:8
proto_cron_crontab_t const * inst
static fr_client_t * mod_client_find(fr_listen_t *li, UNUSED fr_ipaddr_t const *ipaddr, UNUSED int ipproto)
static int mod_instantiate(module_inst_ctx_t const *mctx)
fr_network_t * nr
network handler
static fr_table_ptr_sorted_t time_names[]
static void do_cron(fr_event_list_t *el, fr_time_t now, void *uctx)
fr_pair_list_t pair_list
for input packet
Definition: cron.h:3
static int ipproto
Definition: radclient-ng.c:94
static bool done
Definition: radclient.c:80
#define DEBUG2(fmt,...)
Definition: radclient.h:43
static rs_t * conf
Definition: radsniff.c:53
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition: rand.c:106
#define REQUEST_VERIFY(_x)
Definition: request.h:275
static char const * name
static size_t min(size_t x, size_t y)
Definition: sbuff.c:135
fr_assert(0)
eap_aka_sim_process_conf_t * inst
fr_pair_t * vp
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition: state_test.c:8
Stores an attribute, a value and various bits of other data.
Definition: pair.h:68
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition: syserror.c:243
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
Definition: table.h:134
An element in a lexicographically sorted array of name to ptr mappings.
Definition: table.h:61
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
Definition: talloc.c:380
#define talloc_get_type_abort_const
Definition: talloc.h:270
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
"server local" time.
Definition: time.h:69
static fr_event_list_t * el
static fr_slen_t parent
Definition: pair.h:844
static fr_socket_t * fr_socket_addr_alloc_inet_src(TALLOC_CTX *ctx, int proto, int ifindex, fr_ipaddr_t const *ipaddr, int port)
A variant of fr_socket_addr_init_inet_src will also allocates a fr_socket_t.
Definition: socket.h:244
int af
AF_INET, AF_INET6, or AF_UNIX.
Definition: socket.h:78
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
static fr_slen_t data
Definition: value.h:1259
static size_t char ** out
Definition: value.h:984