All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
rlm_unbound.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: 08c990916f14c6044b6c9ee8058f1923821634c1 $
19  * @file rlm_unbound.c
20  * @brief DNS services via libunbound.
21  *
22  * @copyright 2013 The FreeRADIUS server project
23  * @copyright 2013 Brian S. Julin <bjulin@clarku.edu>
24  */
25 RCSID("$Id: 08c990916f14c6044b6c9ee8058f1923821634c1 $")
26 
27 #include <freeradius-devel/radiusd.h>
28 #include <freeradius-devel/modules.h>
29 #include <freeradius-devel/log.h>
30 #include <fcntl.h>
31 #include <unbound.h>
32 
33 typedef struct rlm_unbound_t {
34  struct ub_ctx *ub; /* This must come first. Do not move */
35  fr_event_list_t *el; /* This must come second. Do not move. */
36 
37  char const *name;
38  char const *xlat_a_name;
39  char const *xlat_aaaa_name;
40  char const *xlat_ptr_name;
41 
42  uint32_t timeout;
43 
44  char const *filename;
45 
46  int log_fd;
47  FILE *log_stream;
48 
49  int log_pipe[2];
50  FILE *log_pipe_stream[2];
53 
54 /*
55  * A mapping of configuration file names to internal variables.
56  */
57 static const CONF_PARSER module_config[] = {
58  { FR_CONF_OFFSET("filename", PW_TYPE_FILE_INPUT | PW_TYPE_REQUIRED, rlm_unbound_t, filename), .dflt = "${modconfdir}/unbound/default.conf" },
59  { FR_CONF_OFFSET("timeout", PW_TYPE_INTEGER, rlm_unbound_t, timeout), .dflt = "3000" },
61 };
62 
63 /*
64  * Callback sent to libunbound for xlat functions. Simply links the
65  * new ub_result via a pointer that has been allocated from the heap.
66  * This pointer has been pre-initialized to a magic value.
67  */
68 static void link_ubres(void* my_arg, int err, struct ub_result* result)
69 {
70  struct ub_result **ubres = (struct ub_result **)my_arg;
71 
72  /*
73  * Note that while result will be NULL on error, we are explicit
74  * here because that is actually a behavior that is suboptimal
75  * and only documented in the examples. It could change.
76  */
77  if (err) {
78  ERROR("rlm_unbound: %s", ub_strerror(err));
79  *ubres = NULL;
80  } else {
81  *ubres = result;
82  }
83 }
84 
85 /*
86  * Convert labels as found in a DNS result to a NULL terminated string.
87  *
88  * Result is written to memory pointed to by "out" but no result will
89  * be written unless it and its terminating NULL character fit in "left"
90  * bytes. Returns the number of bytes written excluding the terminating
91  * NULL, or -1 if nothing was written because it would not fit or due
92  * to a violation in the labels format.
93  */
94 static int rrlabels_tostr(char *out, char *rr, size_t left)
95 {
96  int offset = 0;
97 
98  /*
99  * TODO: verify that unbound results (will) always use this label
100  * format, and review the specs on this label format for nuances.
101  */
102 
103  if (!left) {
104  return -1;
105  }
106  if (left > 253) {
107  left = 253; /* DNS length limit */
108  }
109  /* As a whole this should be "NULL terminated" by the 0-length label */
110  if (strnlen(rr, left) > left - 1) {
111  return -1;
112  }
113 
114  /* It will fit, but does it it look well formed? */
115  while (1) {
116  size_t count;
117 
118  count = *((unsigned char *)(rr + offset));
119  if (!count) break;
120 
121  offset++;
122  if (count > 63 || strlen(rr + offset) < count) {
123  return -1;
124  }
125  offset += count;
126  }
127 
128  /* Data is valid and fits. Copy it. */
129  offset = 0;
130  while (1) {
131  int count;
132 
133  count = *((unsigned char *)(rr));
134  if (!count) break;
135 
136  if (offset) {
137  *(out + offset) = '.';
138  offset++;
139  }
140 
141  rr++;
142  memcpy(out + offset, rr, count);
143  rr += count;
144  offset += count;
145  }
146 
147  *(out + offset) = '\0';
148  return offset;
149 }
150 
151 static int ub_common_wait(rlm_unbound_t const *inst, REQUEST *request, char const *tag, struct ub_result **ub, int async_id)
152 {
153  useconds_t iv, waited;
154 
155  iv = inst->timeout > 64 ? 64000 : inst->timeout * 1000;
156  ub_process(inst->ub);
157 
158  for (waited = 0; (void const *)*ub == (void const *)inst; waited += iv, iv *= 2) {
159 
160  if (waited + iv > (useconds_t)inst->timeout * 1000) {
161  usleep(inst->timeout * 1000 - waited);
162  ub_process(inst->ub);
163  break;
164  }
165 
166  usleep(iv);
167 
168  /* Check if already handled by event loop */
169  if ((void const *)*ub != (void const *)inst) {
170  break;
171  }
172 
173  /* In case we are running single threaded */
174  ub_process(inst->ub);
175  }
176 
177  if ((void const *)*ub == (void const *)inst) {
178  int res;
179 
180  RDEBUG("rlm_unbound (%s): DNS took too long", tag);
181 
182  res = ub_cancel(inst->ub, async_id);
183  if (res) {
184  REDEBUG("rlm_unbound (%s): ub_cancel: %s",
185  tag, ub_strerror(res));
186  }
187  return -1;
188  }
189 
190  return 0;
191 }
192 
193 static int ub_common_fail(REQUEST *request, char const *tag, struct ub_result *ub)
194 {
195  if (ub->bogus) {
196  RWDEBUG("rlm_unbound (%s): Bogus DNS response", tag);
197  return -1;
198  }
199 
200  if (ub->nxdomain) {
201  RDEBUG("rlm_unbound (%s): NXDOMAIN", tag);
202  return -1;
203  }
204 
205  if (!ub->havedata) {
206  RDEBUG("rlm_unbound (%s): empty result", tag);
207  return -1;
208  }
209 
210  return 0;
211 }
212 
213 static ssize_t xlat_a(char **out, size_t outlen,
214  void const *mod_inst, UNUSED void const *xlat_inst,
215  REQUEST *request, char const *fmt)
216 {
217  rlm_unbound_t const *inst = mod_inst;
218  struct ub_result **ubres;
219  int async_id;
220  char *fmt2; /* For const warnings. Keep till new libunbound ships. */
221 
222  /* This has to be on the heap, because threads. */
223  ubres = talloc(inst, struct ub_result *);
224 
225  /* Used and thus impossible value from heap to designate incomplete */
226  memcpy(ubres, &mod_inst, sizeof(*ubres));
227 
228  fmt2 = talloc_typed_strdup(inst, fmt);
229  ub_resolve_async(inst->ub, fmt2, 1, 1, ubres, link_ubres, &async_id);
230  talloc_free(fmt2);
231 
232  if (ub_common_wait(inst, request, inst->xlat_a_name, ubres, async_id)) {
233  goto error0;
234  }
235 
236  if (*ubres) {
237  if (ub_common_fail(request, inst->xlat_a_name, *ubres)) {
238  goto error1;
239  }
240 
241  if (!inet_ntop(AF_INET, (*ubres)->data[0], *out, outlen)) {
242  goto error1;
243  };
244 
245  ub_resolve_free(*ubres);
246  talloc_free(ubres);
247  return strlen(*out);
248  }
249 
250  RWDEBUG("rlm_unbound (%s): no result", inst->xlat_a_name);
251 
252  error1:
253  ub_resolve_free(*ubres); /* Handles NULL gracefully */
254 
255  error0:
256  talloc_free(ubres);
257  return -1;
258 }
259 
260 static ssize_t xlat_aaaa(char **out, size_t outlen,
261  void const *mod_inst, UNUSED void const *xlat_inst,
262  REQUEST *request, char const *fmt)
263 {
264  rlm_unbound_t const *inst = mod_inst;
265  struct ub_result **ubres;
266  int async_id;
267  char *fmt2; /* For const warnings. Keep till new libunbound ships. */
268 
269  /* This has to be on the heap, because threads. */
270  ubres = talloc(inst, struct ub_result *);
271 
272  /* Used and thus impossible value from heap to designate incomplete */
273  memcpy(ubres, &mod_inst, sizeof(*ubres));
274 
275  fmt2 = talloc_typed_strdup(inst, fmt);
276  ub_resolve_async(inst->ub, fmt2, 28, 1, ubres, link_ubres, &async_id);
277  talloc_free(fmt2);
278 
279  if (ub_common_wait(inst, request, inst->xlat_aaaa_name, ubres, async_id)) {
280  goto error0;
281  }
282 
283  if (*ubres) {
284  if (ub_common_fail(request, inst->xlat_aaaa_name, *ubres)) {
285  goto error1;
286  }
287  if (!inet_ntop(AF_INET6, (*ubres)->data[0], *out, outlen)) {
288  goto error1;
289  };
290  ub_resolve_free(*ubres);
291  talloc_free(ubres);
292  return strlen(*out);
293  }
294 
295  RWDEBUG("rlm_unbound (%s): no result", inst->xlat_aaaa_name);
296 
297 error1:
298  ub_resolve_free(*ubres); /* Handles NULL gracefully */
299 
300 error0:
301  talloc_free(ubres);
302  return -1;
303 }
304 
305 static ssize_t xlat_ptr(char **out, size_t outlen,
306  void const *mod_inst, UNUSED void const *xlat_inst,
307  REQUEST *request, char const *fmt)
308 {
309  rlm_unbound_t const *inst = mod_inst;
310  struct ub_result **ubres;
311  int async_id;
312  char *fmt2; /* For const warnings. Keep till new libunbound ships. */
313 
314  /* This has to be on the heap, because threads. */
315  ubres = talloc(inst, struct ub_result *);
316 
317  /* Used and thus impossible value from heap to designate incomplete */
318  memcpy(ubres, &mod_inst, sizeof(*ubres));;
319 
320  fmt2 = talloc_typed_strdup(inst, fmt);
321  ub_resolve_async(inst->ub, fmt2, 12, 1, ubres, link_ubres, &async_id);
322  talloc_free(fmt2);
323 
324  if (ub_common_wait(inst, request, inst->xlat_ptr_name,
325  ubres, async_id)) {
326  goto error0;
327  }
328 
329  if (*ubres) {
330  if (ub_common_fail(request, inst->xlat_ptr_name, *ubres)) {
331  goto error1;
332  }
333  if (rrlabels_tostr(*out, (*ubres)->data[0], outlen) < 0) {
334  goto error1;
335  }
336  ub_resolve_free(*ubres);
337  talloc_free(ubres);
338  return strlen(*out);
339  }
340 
341  RWDEBUG("rlm_unbound (%s): no result", inst->xlat_ptr_name);
342 
343 error1:
344  ub_resolve_free(*ubres); /* Handles NULL gracefully */
345 
346 error0:
347  talloc_free(ubres);
348  return -1;
349 }
350 
351 /*
352  * Even when run in asyncronous mode, callbacks sent to libunbound still
353  * must be run in an application-side thread (via ub_process.) This is
354  * probably to keep the API usage consistent across threaded and forked
355  * embedded client modes. This callback function lets an event loop call
356  * ub_process when the instance's file descriptor becomes ready.
357  */
358 static void ub_fd_handler(UNUSED fr_event_list_t *el, UNUSED int sock, void *ctx)
359 {
360  rlm_unbound_t *inst = ctx;
361  int err;
362 
363  err = ub_process(inst->ub);
364  if (err) {
365  ERROR("rlm_unbound (%s) async ub_process: %s",
366  inst->name, ub_strerror(err));
367  }
368 }
369 
370 #ifndef HAVE_PTHREAD_H
371 
372 /* If we have to use a pipe to redirect logging, this does the work. */
373 static void log_spew(UNUSED fr_event_list_t *el, UNUSED int sock, void *ctx)
374 {
375  rlm_unbound_t *inst = ctx;
376  char line[1024];
377 
378  /*
379  * This works for pipes from processes, but not from threads
380  * right now. The latter is hinky and will require some fancy
381  * blocking/nonblocking trickery which is not figured out yet,
382  * since selecting on a pipe from a thread in the same process
383  * seems to behave differently. It will likely preclude the use
384  * of fgets and streams. Left for now since some unbound logging
385  * infrastructure is still global across multiple contexts. Maybe
386  * we can get unbound folks to provide a ub_ctx_debugout_async that
387  * takes a function hook instead to just bypass the piping when
388  * used in threaded mode.
389  */
390  while (fgets(line, 1024, inst->log_pipe_stream[0])) {
391  DEBUG("rlm_unbound (%s): %s", inst->name, line);
392  }
393 }
394 
395 #endif
396 
397 static int mod_bootstrap(CONF_SECTION *conf, void *instance)
398 {
399  rlm_unbound_t *inst = instance;
400 
401  inst->name = cf_section_name2(conf);
402  if (!inst->name) {
403  inst->name = cf_section_name1(conf);
404  }
405 
406  if (inst->timeout > 10000) {
407  cf_log_err_cs(conf, "timeout must be 0 to 10000");
408  return -1;
409  }
410 
411  MEM(inst->xlat_a_name = talloc_typed_asprintf(inst, "%s-a", inst->name));
412  MEM(inst->xlat_aaaa_name = talloc_typed_asprintf(inst, "%s-aaaa", inst->name));
413  MEM(inst->xlat_ptr_name = talloc_typed_asprintf(inst, "%s-ptr", inst->name));
414 
415  if (xlat_register(inst, inst->xlat_a_name, xlat_a, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN) ||
416  xlat_register(inst, inst->xlat_aaaa_name, xlat_aaaa, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN) ||
417  xlat_register(inst, inst->xlat_ptr_name, xlat_ptr, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN)) {
418  cf_log_err_cs(conf, "Failed registering xlats");
419  return -1;
420  }
421 
422  return 0;
423 }
424 
425 static int mod_instantiate(CONF_SECTION *conf, void *instance)
426 {
427  rlm_unbound_t *inst = instance;
428  int res;
429  char *optval;
430 
432  int log_level;
433  int log_fd = -1;
434 
435  char k[64]; /* To silence const warns until newer unbound in distros */
436 
438  inst->log_pipe_stream[0] = NULL;
439  inst->log_pipe_stream[1] = NULL;
440  inst->log_fd = -1;
441  inst->log_pipe_in_use = false;
442 
443  inst->ub = ub_ctx_create();
444  if (!inst->ub) {
445  cf_log_err_cs(conf, "ub_ctx_create failed");
446  return -1;
447  }
448 
449 #ifdef HAVE_PTHREAD_H
450  /*
451  * Note unbound threads WILL happen with -s option, if it matters.
452  * We cannot tell from here whether that option is in effect.
453  */
454  res = ub_ctx_async(inst->ub, 1);
455 #else
456  /*
457  * Uses forked subprocesses instead.
458  */
459  res = ub_ctx_async(inst->ub, 0);
460 #endif
461 
462  if (res) goto error;
463 
464  /* Glean some default settings to match the main server. */
465  /* TODO: debug_level can be changed at runtime. */
466  /* TODO: log until fork when stdout or stderr and !rad_debug_lvl. */
467  log_level = 0;
468 
469  if (rad_debug_lvl > 0) {
470  log_level = rad_debug_lvl;
471 
472  } else if (main_config.debug_level > 0) {
473  log_level = main_config.debug_level;
474  }
475 
476  switch (log_level) {
477  /* TODO: This will need some tweaking */
478  case 0:
479  case 1:
480  break;
481 
482  case 2:
483  log_level = 1;
484  break;
485 
486  case 3:
487  case 4:
488  log_level = 2; /* mid-to-heavy levels of output */
489  break;
490 
491  case 5:
492  case 6:
493  case 7:
494  case 8:
495  log_level = 3; /* Pretty crazy amounts of output */
496  break;
497 
498  default:
499  log_level = 4; /* Insane amounts of output including crypts */
500  break;
501  }
502 
503  res = ub_ctx_debuglevel(inst->ub, log_level);
504  if (res) goto error;
505 
506  switch (default_log.dst) {
507  case L_DST_STDOUT:
508  if (!rad_debug_lvl) {
509  log_dst = L_DST_NULL;
510  break;
511  }
512  log_dst = L_DST_STDOUT;
513  log_fd = dup(STDOUT_FILENO);
514  break;
515 
516  case L_DST_STDERR:
517  if (!rad_debug_lvl) {
518  log_dst = L_DST_NULL;
519  break;
520  }
521  log_dst = L_DST_STDOUT;
522  log_fd = dup(STDERR_FILENO);
523  break;
524 
525  case L_DST_FILES:
526  if (main_config.log_file) {
527  char *log_file;
528 
529  strcpy(k, "logfile:");
530  /* 3rd argument isn't const'd in libunbounds API */
531  memcpy(&log_file, &main_config.log_file, sizeof(log_file));
532  res = ub_ctx_set_option(inst->ub, k, log_file);
533  if (res) {
534  goto error;
535  }
536  log_dst = L_DST_FILES;
537  break;
538  }
539  /* FALL-THROUGH */
540 
541  case L_DST_NULL:
542  log_dst = L_DST_NULL;
543  break;
544 
545  default:
546  log_dst = L_DST_SYSLOG;
547  break;
548  }
549 
550  /* Now load the config file, which can override gleaned settings. */
551  {
552  char *file;
553 
554  memcpy(&file, &inst->filename, sizeof(file));
555  res = ub_ctx_config(inst->ub, file);
556  if (res) goto error;
557  }
558 
559  /*
560  * Check if the config file tried to use syslog. Unbound
561  * does not share syslog gracefully.
562  */
563  strcpy(k, "use-syslog");
564  res = ub_ctx_get_option(inst->ub, k, &optval);
565  if (res || !optval) goto error;
566 
567  if (!strcmp(optval, "yes")) {
568  char v[3];
569 
570  free(optval);
571 
572  WARN("rlm_unbound (%s): Overriding syslog settings.", inst->name);
573  strcpy(k, "use-syslog:");
574  strcpy(v, "no");
575  res = ub_ctx_set_option(inst->ub, k, v);
576  if (res) goto error;
577 
578  if (log_dst == L_DST_FILES) {
579  char *log_file;
580 
581  /* Reinstate the log file name JIC */
582  strcpy(k, "logfile:");
583  /* 3rd argument isn't const'd in libunbounds API */
584  memcpy(&log_file, &main_config.log_file, sizeof(log_file));
585  res = ub_ctx_set_option(inst->ub, k, log_file);
586  if (res) goto error;
587  }
588 
589  } else {
590  if (optval) free(optval);
591  strcpy(k, "logfile");
592 
593  res = ub_ctx_get_option(inst->ub, k, &optval);
594  if (res) goto error;
595 
596  if (optval && strlen(optval)) {
597  log_dst = L_DST_FILES;
598 
599  } else if (!rad_debug_lvl) {
600  log_dst = L_DST_NULL;
601  }
602 
603  if (optval) free(optval);
604  }
605 
606  switch (log_dst) {
607  case L_DST_STDOUT:
608  /*
609  * We have an fd to log to. And we've already attempted to
610  * dup it so libunbound doesn't close it on us.
611  */
612  if (log_fd == -1) {
613  cf_log_err_cs(conf, "Could not dup fd");
614  goto error_nores;
615  }
616 
617  inst->log_stream = fdopen(log_fd, "w");
618  if (!inst->log_stream) {
619  cf_log_err_cs(conf, "error setting up log stream");
620  goto error_nores;
621  }
622 
623  res = ub_ctx_debugout(inst->ub, inst->log_stream);
624  if (res) goto error;
625  break;
626 
627  case L_DST_FILES:
628  /* We gave libunbound a filename. It is on its own now. */
629  break;
630 
631  case L_DST_NULL:
632  /* We tell libunbound not to log at all. */
633  res = ub_ctx_debugout(inst->ub, NULL);
634  if (res) goto error;
635  break;
636 
637  case L_DST_SYSLOG:
638 #ifdef HAVE_PTHREAD_H
639  /*
640  * Currently this wreaks havoc when running threaded, so just
641  * turn logging off until that gets figured out.
642  */
643  res = ub_ctx_debugout(inst->ub, NULL);
644  if (res) goto error;
645  break;
646 #else
647  /*
648  * We need to create a pipe, because libunbound does not
649  * share syslog nicely. Or the core added some new logsink.
650  */
651  if (pipe(inst->log_pipe)) {
652  error_pipe:
653  cf_log_err_cs(conf, "Error setting up log pipes");
654  goto error_nores;
655  }
656 
657  if ((fcntl(inst->log_pipe[0], F_SETFL, O_NONBLOCK) < 0) ||
658  (fcntl(inst->log_pipe[0], F_SETFD, FD_CLOEXEC) < 0)) {
659  goto error_pipe;
660  }
661 
662  /* Opaque to us when this can be closed, so we do not. */
663  if (fcntl(inst->log_pipe[1], F_SETFL, O_NONBLOCK) < 0) {
664  goto error_pipe;
665  }
666 
667  inst->log_pipe_stream[0] = fdopen(inst->log_pipe[0], "r");
668  inst->log_pipe_stream[1] = fdopen(inst->log_pipe[1], "w");
669 
670  if (!inst->log_pipe_stream[0] || !inst->log_pipe_stream[1]) {
671  if (!inst->log_pipe_stream[1]) {
672  close(inst->log_pipe[1]);
673  }
674 
675  if (!inst->log_pipe_stream[0]) {
676  close(inst->log_pipe[0]);
677  }
678  cf_log_err_cs(conf, "Error setting up log stream");
679  goto error_nores;
680  }
681 
682  res = ub_ctx_debugout(inst->ub, inst->log_pipe_stream[1]);
683  if (res) goto error;
684 
685  if (!fr_event_fd_insert(inst->el, 0, inst->log_pipe[0], log_spew, inst)) {
686  cf_log_err_cs(conf, "could not insert log fd");
687  goto error_nores;
688  }
689 
690  inst->log_pipe_in_use = true;
691 #endif
692  default:
693  break;
694  }
695 
696  /*
697  * Now we need to finalize the context.
698  *
699  * There's no clean API to just finalize the context made public
700  * in libunbound. But we can trick it by trying to delete data
701  * which as it happens fails quickly and quietly even though the
702  * data did not exist.
703  */
704  strcpy(k, "notar33lsite.foo123.nottld A 127.0.0.1");
705  ub_ctx_data_remove(inst->ub, k);
706 
707  inst->log_fd = ub_fd(inst->ub);
708  if (inst->log_fd >= 0) {
709  if (!fr_event_fd_insert(inst->el, 0, inst->log_fd, ub_fd_handler, inst)) {
710  cf_log_err_cs(conf, "could not insert async fd");
711  inst->log_fd = -1;
712  goto error_nores;
713  }
714 
715  }
716 
717  return 0;
718 
719  error:
720  cf_log_err_cs(conf, "%s", ub_strerror(res));
721 
722  error_nores:
723  if (log_fd > -1) close(log_fd);
724 
725  return -1;
726 }
727 
728 static int mod_detach(UNUSED void *instance)
729 {
730  rlm_unbound_t *inst = instance;
731 
732  if (inst->log_fd >= 0) {
733  fr_event_fd_delete(inst->el, 0, inst->log_fd);
734  if (inst->ub) {
735  ub_process(inst->ub);
736  /* This can hang/leave zombies currently
737  * see upstream bug #519
738  * ...so expect valgrind to complain with -m
739  */
740 #if 0
741  ub_ctx_delete(inst->ub);
742 #endif
743  }
744  }
745 
746  if (inst->log_pipe_stream[1]) {
747  fclose(inst->log_pipe_stream[1]);
748  }
749 
750  if (inst->log_pipe_stream[0]) {
751  if (inst->log_pipe_in_use) {
752  fr_event_fd_delete(inst->el, 0, inst->log_pipe[0]);
753  }
754  fclose(inst->log_pipe_stream[0]);
755  }
756 
757  if (inst->log_stream) {
758  fclose(inst->log_stream);
759  }
760 
761  return 0;
762 }
763 
764 extern module_t rlm_unbound;
765 module_t rlm_unbound = {
767  .name = "unbound",
768  .type = RLM_TYPE_THREAD_SAFE,
769  .inst_size = sizeof(rlm_unbound_t),
770  .config = module_config,
771  .bootstrap = mod_bootstrap,
772  .instantiate = mod_instantiate,
773  .detach = mod_detach
774 };
#define PW_TYPE_FILE_INPUT
File matching value must exist, and must be readable.
Definition: conffile.h:204
bool log_pipe_in_use
Definition: rlm_unbound.c:51
int xlat_register(void *mod_inst, char const *name, xlat_func_t func, xlat_escape_t escape, xlat_instantiate_t instantiate, size_t inst_size, size_t buf_len)
Register an xlat function.
Definition: xlat.c:717
static int ub_common_wait(rlm_unbound_t const *inst, REQUEST *request, char const *tag, struct ub_result **ub, int async_id)
Definition: rlm_unbound.c:151
Main server configuration.
Definition: radiusd.h:108
int fr_event_fd_delete(fr_event_list_t *el, int type, int fd)
Definition: event.c:444
static fr_event_list_t * el
Definition: process.c:54
Metadata exported by the module.
Definition: modules.h:134
uint32_t debug_level
Definition: radiusd.h:138
int log_pipe[2]
Definition: rlm_unbound.c:49
#define MEM(x)
Definition: radiusd.h:396
#define RLM_TYPE_THREAD_SAFE
Module is threadsafe.
Definition: modules.h:75
Log to syslog.
Definition: log.h:60
#define UNUSED
Definition: libradius.h:134
#define RLM_MODULE_INIT
Definition: modules.h:86
FILE * log_stream
Definition: rlm_unbound.c:47
static int mod_detach(UNUSED void *instance)
Definition: rlm_unbound.c:728
char const * filename
Definition: rlm_unbound.c:44
fr_event_list_t * radius_event_list_corral(event_corral_t hint)
#define CONF_PARSER_TERMINATOR
Definition: conffile.h:289
char const * inet_ntop(int af, void const *src, char *dst, size_t cnt)
Definition: missing.c:538
log_dst
Definition: log.h:57
static float timeout
Definition: radclient.c:43
char const * name
Definition: rlm_unbound.c:37
#define inst
fr_log_t default_log
Definition: log.c:216
static void ub_fd_handler(UNUSED fr_event_list_t *el, UNUSED int sock, void *ctx)
Definition: rlm_unbound.c:358
static ssize_t xlat_ptr(char **out, size_t outlen, void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Definition: rlm_unbound.c:305
#define XLAT_DEFAULT_BUF_LEN
Definition: xlat.h:89
char const * log_file
Definition: radiusd.h:139
int fr_event_fd_insert(fr_event_list_t *el, int type, int fd, fr_event_fd_handler_t handler, void *ctx)
Definition: event.c:324
Defines a CONF_PAIR to C data type mapping.
Definition: conffile.h:267
fr_event_list_t * el
Definition: rlm_unbound.c:35
struct rlm_unbound_t rlm_unbound_t
static int mod_bootstrap(CONF_SECTION *conf, void *instance)
Definition: rlm_unbound.c:397
#define DEBUG(fmt,...)
Definition: log.h:175
static int ub_common_fail(REQUEST *request, char const *tag, struct ub_result *ub)
Definition: rlm_unbound.c:193
Log to stderr.
Definition: log.h:61
char const * xlat_ptr_name
Definition: rlm_unbound.c:40
static int rrlabels_tostr(char *out, char *rr, size_t left)
Definition: rlm_unbound.c:94
char * talloc_typed_asprintf(void const *t, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
Definition: missing.c:611
void void cf_log_err_cs(CONF_SECTION const *cs, char const *fmt,...) CC_HINT(format(printf
32 Bit unsigned integer.
Definition: radius.h:34
static rs_t * conf
Definition: radsniff.c:46
static void link_ubres(void *my_arg, int err, struct ub_result *result)
Definition: rlm_unbound.c:68
char const * cf_section_name1(CONF_SECTION const *cs)
Definition: conffile.c:3592
char const * xlat_a_name
Definition: rlm_unbound.c:38
static int mod_instantiate(CONF_SECTION *conf, void *instance)
Definition: rlm_unbound.c:425
Log to a file on disk.
Definition: log.h:59
static ssize_t xlat_a(char **out, size_t outlen, void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Definition: rlm_unbound.c:213
module_t rlm_unbound
Definition: rlm_unbound.c:765
uint64_t magic
Used to validate module struct.
Definition: modules.h:135
enum log_dst log_dst_t
#define FR_CONF_OFFSET(_n, _t, _s, _f)
Definition: conffile.h:168
log_lvl_t rad_debug_lvl
Global debugging level.
Definition: log.c:49
struct ub_ctx * ub
Definition: rlm_unbound.c:34
static const CONF_PARSER module_config[]
Definition: rlm_unbound.c:57
#define WARN(fmt,...)
Definition: log.h:144
#define REDEBUG(fmt,...)
Definition: log.h:254
uint32_t timeout
Definition: rlm_unbound.c:42
#define PW_TYPE_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
Definition: conffile.h:200
Discard log messages.
Definition: log.h:63
static ssize_t xlat_aaaa(char **out, size_t outlen, void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Definition: rlm_unbound.c:260
log_dst_t dst
Log destination.
Definition: log.h:72
Maybe main thread or one shared by modules.
Definition: radiusd.h:589
Log to stdout.
Definition: log.h:58
#define RWDEBUG(fmt,...)
Definition: log.h:251
#define RCSID(id)
Definition: build.h:135
char * talloc_typed_strdup(void const *t, char const *p)
Call talloc strdup, setting the type on the new chunk correctly.
Definition: missing.c:588
#define RDEBUG(fmt,...)
Definition: log.h:243
#define ERROR(fmt,...)
Definition: log.h:145
char const * xlat_aaaa_name
Definition: rlm_unbound.c:39
static void log_spew(UNUSED fr_event_list_t *el, UNUSED int sock, void *ctx)
Definition: rlm_unbound.c:373
FILE * log_pipe_stream[2]
Definition: rlm_unbound.c:50
char const * cf_section_name2(CONF_SECTION const *cs)
Definition: conffile.c:3601