d4fa7bc13ccd968daf7cf0cc0ba22c091fb6d413
[strongswan.git] / src / pluto / log.c
1 /* error logging functions
2 * Copyright (C) 1997 Angelos D. Keromytis.
3 * Copyright (C) 1998-2001 D. Hugh Redelmeier.
4 * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <ctype.h>
20 #include <stdarg.h>
21 #include <syslog.h>
22 #include <errno.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <signal.h> /* used only if MSG_NOSIGNAL not defined */
26 #include <sys/queue.h>
27 #include <libgen.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30
31 #include <freeswan.h>
32 #include <library.h>
33 #include <debug.h>
34
35 #include "constants.h"
36 #include "defs.h"
37 #include "log.h"
38 #include "server.h"
39 #include "state.h"
40 #include "connections.h"
41 #include "kernel.h"
42 #include "whack.h" /* needs connections.h */
43 #include "timer.h"
44
45 /* close one per-peer log */
46 static void perpeer_logclose(struct connection *c); /* forward */
47
48
49 bool
50 log_to_stderr = TRUE, /* should log go to stderr? */
51 log_to_syslog = TRUE, /* should log go to syslog? */
52 log_to_perpeer= FALSE; /* should log go to per-IP file? */
53
54 bool
55 logged_txt_warning = FALSE; /* should we complain about finding KEY? */
56
57 /* should we complain when we find no local id */
58 bool
59 logged_myid_fqdn_txt_warning = FALSE,
60 logged_myid_ip_txt_warning = FALSE,
61 logged_myid_fqdn_key_warning = FALSE,
62 logged_myid_ip_key_warning = FALSE;
63
64 /* may include trailing / */
65 const char *base_perpeer_logdir = PERPEERLOGDIR;
66 static int perpeer_count = 0;
67
68 /* from sys/queue.h */
69 static TAILQ_HEAD(perpeer, connection) perpeer_list;
70
71
72 /* Context for logging.
73 *
74 * Global variables: must be carefully adjusted at transaction boundaries!
75 * If the context provides a whack file descriptor, messages
76 * should be copied to it -- see whack_log()
77 */
78 int whack_log_fd = NULL_FD; /* only set during whack_handle() */
79 struct state *cur_state = NULL; /* current state, for diagnostics */
80 struct connection *cur_connection = NULL; /* current connection, for diagnostics */
81 const ip_address *cur_from = NULL; /* source of current current message */
82 u_int16_t cur_from_port; /* host order */
83
84 /**
85 * pluto dbg function for libstrongswan
86 */
87 static void pluto_dbg(int level, char *fmt, ...)
88 {
89 int priority = LOG_INFO;
90 int debug_level;
91 char buffer[8192];
92 char *current = buffer, *next;
93 va_list args;
94
95 if (cur_debugging & DBG_PRIVATE)
96 {
97 debug_level = 4;
98 }
99 else if (cur_debugging & DBG_RAW)
100 {
101 debug_level = 3;
102 }
103 else if (cur_debugging & DBG_PARSING)
104 {
105 debug_level = 2;
106 }
107 else
108 {
109 debug_level = 1;
110 }
111
112 if (level <= debug_level)
113 {
114 va_start(args, fmt);
115
116 if (log_to_stderr)
117 {
118 if (level > 1)
119 {
120 fprintf(stderr, "| ");
121 }
122 vfprintf(stderr, fmt, args);
123 fprintf(stderr, "\n");
124 }
125 if (log_to_syslog)
126 {
127 /* write in memory buffer first */
128 vsnprintf(buffer, sizeof(buffer), fmt, args);
129
130 /* do a syslog with every line */
131 while (current)
132 {
133 next = strchr(current, '\n');
134 if (next)
135 {
136 *(next++) = '\0';
137 }
138 syslog(priority, "%s%s\n", (level > 1)? "| ":"", current);
139 current = next;
140 }
141 }
142 va_end(args);
143 }
144 }
145
146 void
147 init_log(const char *program)
148 {
149 /* enable pluto debugging hook for libstrongswan */
150 dbg = pluto_dbg;
151
152 if (log_to_stderr)
153 {
154 setbuf(stderr, NULL);
155 }
156 if (log_to_syslog)
157 {
158 openlog(program, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_AUTHPRIV);
159 }
160 TAILQ_INIT(&perpeer_list);
161 }
162
163 void
164 close_peerlog(void)
165 {
166 /* exit if the queue has not been initialized */
167 if (perpeer_list.tqh_first == NULL)
168 return;
169
170 /* end of queue is given by pointer to "HEAD" */
171 while (TAILQ_LAST(&perpeer_list, perpeer) != (void *)&perpeer_list)
172 perpeer_logclose(TAILQ_LAST(&perpeer_list, perpeer));
173 }
174
175 void
176 close_log(void)
177 {
178 if (log_to_syslog)
179 closelog();
180
181 close_peerlog();
182 }
183
184 /* Sanitize character string in situ: turns dangerous characters into \OOO.
185 * With a bit of work, we could use simpler reps for \\, \r, etc.,
186 * but this is only to protect against something that shouldn't be used.
187 * Truncate resulting string to what fits in buffer.
188 */
189 static size_t
190 sanitize(char *buf, size_t size)
191 {
192 # define UGLY_WIDTH 4 /* width for ugly character: \OOO */
193 size_t len;
194 size_t added = 0;
195 char *p;
196
197 passert(size >= UGLY_WIDTH); /* need room to swing cat */
198
199 /* find right side of string to be sanitized and count
200 * number of columns to be added. Stop on end of string
201 * or lack of room for more result.
202 */
203 for (p = buf; *p != '\0' && &p[added] < &buf[size - UGLY_WIDTH]; )
204 {
205 unsigned char c = *p++;
206
207 if (c == '\\' || !isprint(c))
208 added += UGLY_WIDTH - 1;
209 }
210
211 /* at this point, p points after last original character to be
212 * included. added is how many characters are added to sanitize.
213 * so p[added] will point after last sanitized character.
214 */
215
216 p[added] = '\0';
217 len = &p[added] - buf;
218
219 /* scan backwards, copying characters to their new home
220 * and inserting the expansions for ugly characters.
221 * It is finished when no more shifting is required.
222 * This is a predecrement loop.
223 */
224 while (added != 0)
225 {
226 char fmtd[UGLY_WIDTH + 1];
227 unsigned char c;
228
229 while ((c = *--p) != '\\' && isprint(c))
230 p[added] = c;
231 added -= UGLY_WIDTH - 1;
232 snprintf(fmtd, sizeof(fmtd), "\\%03o", c);
233 memcpy(p + added, fmtd, UGLY_WIDTH);
234 }
235 return len;
236 # undef UGLY_WIDTH
237 }
238
239 /* format a string for the log, with suitable prefixes.
240 * A format starting with ~ indicates that this is a reprocessing
241 * of the message, so prefixing and quoting is suppressed.
242 */
243 static void
244 fmt_log(char *buf, size_t buf_len, const char *fmt, va_list ap)
245 {
246 bool reproc = *fmt == '~';
247 size_t ps;
248 struct connection *c = cur_state != NULL ? cur_state->st_connection
249 : cur_connection;
250
251 buf[0] = '\0';
252 if (reproc)
253 fmt++; /* ~ at start of format suppresses this prefix */
254 else if (c != NULL)
255 {
256 /* start with name of connection */
257 char *const be = buf + buf_len;
258 char *bp = buf;
259
260 snprintf(bp, be - bp, "\"%s\"", c->name);
261 bp += strlen(bp);
262
263 /* if it fits, put in any connection instance information */
264 if (be - bp > CONN_INST_BUF)
265 {
266 fmt_conn_instance(c, bp);
267 bp += strlen(bp);
268 }
269
270 if (cur_state != NULL)
271 {
272 /* state number */
273 snprintf(bp, be - bp, " #%lu", cur_state->st_serialno);
274 bp += strlen(bp);
275 }
276 snprintf(bp, be - bp, ": ");
277 }
278 else if (cur_from != NULL)
279 {
280 /* peer's IP address */
281 /* Note: must not use ip_str() because our caller might! */
282 char ab[ADDRTOT_BUF];
283
284 (void) addrtot(cur_from, 0, ab, sizeof(ab));
285 snprintf(buf, buf_len, "packet from %s:%u: "
286 , ab, (unsigned)cur_from_port);
287 }
288
289 ps = strlen(buf);
290 vsnprintf(buf + ps, buf_len - ps, fmt, ap);
291 if (!reproc)
292 (void)sanitize(buf, buf_len);
293 }
294
295 static void
296 perpeer_logclose(struct connection *c)
297 {
298 /* only free/close things if we had used them! */
299 if (c->log_file != NULL)
300 {
301 passert(perpeer_count > 0);
302
303 TAILQ_REMOVE(&perpeer_list, c, log_link);
304 perpeer_count--;
305 fclose(c->log_file);
306 c->log_file=NULL;
307 }
308 }
309
310 void
311 perpeer_logfree(struct connection *c)
312 {
313 perpeer_logclose(c);
314 if (c->log_file_name != NULL)
315 {
316 free(c->log_file_name);
317 c->log_file_name = NULL;
318 c->log_file_err = FALSE;
319 }
320 }
321
322 /* open the per-peer log */
323 static void
324 open_peerlog(struct connection *c)
325 {
326 syslog(LOG_INFO, "opening log file for conn %s", c->name);
327
328 if (c->log_file_name == NULL)
329 {
330 char peername[ADDRTOT_BUF], dname[ADDRTOT_BUF];
331 int peernamelen, lf_len;
332
333 addrtot(&c->spd.that.host_addr, 'Q', peername, sizeof(peername));
334 peernamelen = strlen(peername);
335
336 /* copy IP address, turning : and . into / */
337 {
338 char c, *p, *q;
339
340 p = peername;
341 q = dname;
342 do {
343 c = *p++;
344 if (c == '.' || c == ':')
345 c = '/';
346 *q++ = c;
347 } while (c != '\0');
348 }
349
350 lf_len = peernamelen * 2
351 + strlen(base_perpeer_logdir)
352 + sizeof("//.log")
353 + 1;
354 c->log_file_name = malloc(lf_len);
355
356 fprintf(stderr, "base dir |%s| dname |%s| peername |%s|"
357 , base_perpeer_logdir, dname, peername);
358 snprintf(c->log_file_name, lf_len, "%s/%s/%s.log"
359 , base_perpeer_logdir, dname, peername);
360
361 syslog(LOG_DEBUG, "conn %s logfile is %s", c->name, c->log_file_name);
362 }
363
364 /* now open the file, creating directories if necessary */
365
366 { /* create the directory */
367 char *dname;
368 int bpl_len = strlen(base_perpeer_logdir);
369 char *slashloc;
370
371 dname = clone_str(c->log_file_name);
372 dname = dirname(dname);
373
374 if (access(dname, W_OK) != 0)
375 {
376 if (errno != ENOENT)
377 {
378 if (c->log_file_err)
379 {
380 syslog(LOG_CRIT, "can not write to %s: %s"
381 , dname, strerror(errno));
382 c->log_file_err = TRUE;
383 free(dname);
384 return;
385 }
386 }
387
388 /* directory does not exist, walk path creating dirs */
389 /* start at base_perpeer_logdir */
390 slashloc = dname + bpl_len;
391 slashloc++; /* since, by construction there is a slash
392 right there */
393
394 while (*slashloc != '\0')
395 {
396 char saveslash;
397
398 /* look for next slash */
399 while (*slashloc != '\0' && *slashloc != '/') slashloc++;
400
401 saveslash = *slashloc;
402
403 *slashloc = '\0';
404
405 if (mkdir(dname, 0750) != 0 && errno != EEXIST)
406 {
407 syslog(LOG_CRIT, "can not create dir %s: %s"
408 , dname, strerror(errno));
409 c->log_file_err = TRUE;
410 free(dname);
411 return;
412 }
413 syslog(LOG_DEBUG, "created new directory %s", dname);
414 *slashloc = saveslash;
415 slashloc++;
416 }
417 }
418 free(dname);
419 }
420
421 c->log_file = fopen(c->log_file_name, "a");
422 if (c->log_file == NULL)
423 {
424 if (c->log_file_err)
425 {
426 syslog(LOG_CRIT, "logging system can not open %s: %s"
427 , c->log_file_name, strerror(errno));
428 c->log_file_err = TRUE;
429 }
430 return;
431 }
432
433 /* look for a connection to close! */
434 while (perpeer_count >= MAX_PEERLOG_COUNT)
435 {
436 /* can not be NULL because perpeer_count > 0 */
437 passert(TAILQ_LAST(&perpeer_list, perpeer) != (void *)&perpeer_list);
438
439 perpeer_logclose(TAILQ_LAST(&perpeer_list, perpeer));
440 }
441
442 /* insert this into the list */
443 TAILQ_INSERT_HEAD(&perpeer_list, c, log_link);
444 passert(c->log_file != NULL);
445 perpeer_count++;
446 }
447
448 /* log a line to cur_connection's log */
449 static void
450 peerlog(const char *prefix, const char *m)
451 {
452 if (cur_connection == NULL)
453 {
454 /* we can not log it in this case. Oh well. */
455 return;
456 }
457
458 if (cur_connection->log_file == NULL)
459 {
460 open_peerlog(cur_connection);
461 }
462
463 /* despite our attempts above, we may not be able to open the file. */
464 if (cur_connection->log_file != NULL)
465 {
466 char datebuf[32];
467 time_t n;
468 struct tm *t;
469
470 time(&n);
471 t = localtime(&n);
472
473 strftime(datebuf, sizeof(datebuf), "%Y-%m-%d %T", t);
474 fprintf(cur_connection->log_file, "%s %s%s\n", datebuf, prefix, m);
475
476 /* now move it to the front of the list */
477 TAILQ_REMOVE(&perpeer_list, cur_connection, log_link);
478 TAILQ_INSERT_HEAD(&perpeer_list, cur_connection, log_link);
479 }
480 }
481
482 void
483 plog(const char *message, ...)
484 {
485 va_list args;
486 char m[LOG_WIDTH]; /* longer messages will be truncated */
487
488 va_start(args, message);
489 fmt_log(m, sizeof(m), message, args);
490 va_end(args);
491
492 if (log_to_stderr)
493 fprintf(stderr, "%s\n", m);
494 if (log_to_syslog)
495 syslog(LOG_WARNING, "%s", m);
496 if (log_to_perpeer)
497 peerlog("", m);
498
499 whack_log(RC_LOG, "~%s", m);
500 }
501
502 void
503 loglog(int mess_no, const char *message, ...)
504 {
505 va_list args;
506 char m[LOG_WIDTH]; /* longer messages will be truncated */
507
508 va_start(args, message);
509 fmt_log(m, sizeof(m), message, args);
510 va_end(args);
511
512 if (log_to_stderr)
513 fprintf(stderr, "%s\n", m);
514 if (log_to_syslog)
515 syslog(LOG_WARNING, "%s", m);
516 if (log_to_perpeer)
517 peerlog("", m);
518
519 whack_log(mess_no, "~%s", m);
520 }
521
522 void
523 log_errno_routine(int e, const char *message, ...)
524 {
525 va_list args;
526 char m[LOG_WIDTH]; /* longer messages will be truncated */
527
528 va_start(args, message);
529 fmt_log(m, sizeof(m), message, args);
530 va_end(args);
531
532 if (log_to_stderr)
533 fprintf(stderr, "ERROR: %s. Errno %d: %s\n", m, e, strerror(e));
534 if (log_to_syslog)
535 syslog(LOG_ERR, "ERROR: %s. Errno %d: %s", m, e, strerror(e));
536 if (log_to_perpeer)
537 {
538 peerlog(strerror(e), m);
539 }
540
541 whack_log(RC_LOG_SERIOUS
542 , "~ERROR: %s. Errno %d: %s", m, e, strerror(e));
543 }
544
545 void
546 exit_log(const char *message, ...)
547 {
548 va_list args;
549 char m[LOG_WIDTH]; /* longer messages will be truncated */
550
551 va_start(args, message);
552 fmt_log(m, sizeof(m), message, args);
553 va_end(args);
554
555 if (log_to_stderr)
556 fprintf(stderr, "FATAL ERROR: %s\n", m);
557 if (log_to_syslog)
558 syslog(LOG_ERR, "FATAL ERROR: %s", m);
559 if (log_to_perpeer)
560 peerlog("FATAL ERROR: ", m);
561
562 whack_log(RC_LOG_SERIOUS, "~FATAL ERROR: %s", m);
563
564 exit_pluto(1);
565 }
566
567 void
568 exit_log_errno_routine(int e, const char *message, ...)
569 {
570 va_list args;
571 char m[LOG_WIDTH]; /* longer messages will be truncated */
572
573 va_start(args, message);
574 fmt_log(m, sizeof(m), message, args);
575 va_end(args);
576
577 if (log_to_stderr)
578 fprintf(stderr, "FATAL ERROR: %s. Errno %d: %s\n", m, e, strerror(e));
579 if (log_to_syslog)
580 syslog(LOG_ERR, "FATAL ERROR: %s. Errno %d: %s", m, e, strerror(e));
581 if (log_to_perpeer)
582 peerlog(strerror(e), m);
583
584 whack_log(RC_LOG_SERIOUS
585 , "~FATAL ERROR: %s. Errno %d: %s", m, e, strerror(e));
586
587 exit_pluto(1);
588 }
589
590 /* emit message to whack.
591 * form is "ddd statename text" where
592 * - ddd is a decimal status code (RC_*) as described in whack.h
593 * - text is a human-readable annotation
594 */
595 #ifdef DEBUG
596 static volatile sig_atomic_t dying_breath = FALSE;
597 #endif
598
599 void
600 whack_log(int mess_no, const char *message, ...)
601 {
602 int wfd = whack_log_fd != NULL_FD ? whack_log_fd
603 : cur_state != NULL ? cur_state->st_whack_sock
604 : NULL_FD;
605
606 if (wfd != NULL_FD
607 #ifdef DEBUG
608 || dying_breath
609 #endif
610 )
611 {
612 va_list args;
613 char m[LOG_WIDTH]; /* longer messages will be truncated */
614 int prelen = snprintf(m, sizeof(m), "%03d ", mess_no);
615
616 passert(prelen >= 0);
617
618 va_start(args, message);
619 fmt_log(m+prelen, sizeof(m)-prelen, message, args);
620 va_end(args);
621
622 #if DEBUG
623 if (dying_breath)
624 {
625 /* status output copied to log */
626 if (log_to_stderr)
627 fprintf(stderr, "%s\n", m + prelen);
628 if (log_to_syslog)
629 syslog(LOG_WARNING, "%s", m + prelen);
630 if (log_to_perpeer)
631 peerlog("", m);
632 }
633 #endif
634
635 if (wfd != NULL_FD)
636 {
637 /* write to whack socket, but suppress possible SIGPIPE */
638 size_t len = strlen(m);
639 #ifdef MSG_NOSIGNAL /* depends on version of glibc??? */
640 m[len] = '\n'; /* don't need NUL, do need NL */
641 (void) send(wfd, m, len + 1, MSG_NOSIGNAL);
642 #else /* !MSG_NOSIGNAL */
643 int r;
644 struct sigaction act
645 , oldact;
646
647 m[len] = '\n'; /* don't need NUL, do need NL */
648 act.sa_handler = SIG_IGN;
649 sigemptyset(&act.sa_mask);
650 act.sa_flags = 0; /* no nothing */
651 r = sigaction(SIGPIPE, &act, &oldact);
652 passert(r == 0);
653
654 (void) write(wfd, m, len + 1);
655
656 r = sigaction(SIGPIPE, &oldact, NULL);
657 passert(r == 0);
658 #endif /* !MSG_NOSIGNAL */
659 }
660 }
661 }
662
663 /* Build up a diagnostic in a static buffer.
664 * Although this would be a generally useful function, it is very
665 * hard to come up with a discipline that prevents different uses
666 * from interfering. It is intended that by limiting it to building
667 * diagnostics, we will avoid this problem.
668 * Juggling is performed to allow an argument to be a previous
669 * result: the new string may safely depend on the old one. This
670 * restriction is not checked in any way: violators will produce
671 * confusing results (without crashing!).
672 */
673 char diag_space[sizeof(diag_space)];
674
675 err_t
676 builddiag(const char *fmt, ...)
677 {
678 static char diag_space[LOG_WIDTH]; /* longer messages will be truncated */
679 char t[sizeof(diag_space)]; /* build result here first */
680 va_list args;
681
682 va_start(args, fmt);
683 t[0] = '\0'; /* in case nothing terminates string */
684 vsnprintf(t, sizeof(t), fmt, args);
685 va_end(args);
686 strcpy(diag_space, t);
687 return diag_space;
688 }
689
690 /* Debugging message support */
691
692 #ifdef DEBUG
693
694 void
695 switch_fail(int n, const char *file_str, unsigned long line_no)
696 {
697 char buf[30];
698
699 snprintf(buf, sizeof(buf), "case %d unexpected", n);
700 passert_fail(buf, file_str, line_no);
701 }
702
703 void
704 passert_fail(const char *pred_str, const char *file_str, unsigned long line_no)
705 {
706 /* we will get a possibly unplanned prefix. Hope it works */
707 loglog(RC_LOG_SERIOUS, "ASSERTION FAILED at %s:%lu: %s", file_str, line_no, pred_str);
708 if (!dying_breath)
709 {
710 dying_breath = TRUE;
711 show_status(TRUE, NULL);
712 }
713 abort(); /* exiting correctly doesn't always work */
714 }
715
716 void
717 pexpect_log(const char *pred_str, const char *file_str, unsigned long line_no)
718 {
719 /* we will get a possibly unplanned prefix. Hope it works */
720 loglog(RC_LOG_SERIOUS, "EXPECTATION FAILED at %s:%lu: %s", file_str, line_no, pred_str);
721 }
722
723 lset_t
724 base_debugging = DBG_NONE, /* default to reporting nothing */
725 cur_debugging = DBG_NONE;
726
727 void
728 extra_debugging(const struct connection *c)
729 {
730 if(c == NULL)
731 {
732 reset_debugging();
733 return;
734 }
735
736 if (c!= NULL && c->extra_debugging != 0)
737 {
738 plog("enabling for connection: %s"
739 , bitnamesof(debug_bit_names, c->extra_debugging & ~cur_debugging));
740 cur_debugging |= c->extra_debugging;
741 }
742 }
743
744 /* log a debugging message (prefixed by "| ") */
745
746 void
747 DBG_log(const char *message, ...)
748 {
749 va_list args;
750 char m[LOG_WIDTH]; /* longer messages will be truncated */
751
752 va_start(args, message);
753 vsnprintf(m, sizeof(m), message, args);
754 va_end(args);
755
756 (void)sanitize(m, sizeof(m));
757
758 if (log_to_stderr)
759 fprintf(stderr, "| %s\n", m);
760 if (log_to_syslog)
761 syslog(LOG_DEBUG, "| %s", m);
762 if (log_to_perpeer)
763 peerlog("| ", m);
764 }
765
766 /* dump raw bytes in hex to stderr (for lack of any better destination) */
767
768 void
769 DBG_dump(const char *label, const void *p, size_t len)
770 {
771 # define DUMP_LABEL_WIDTH 20 /* arbitrary modest boundary */
772 # define DUMP_WIDTH (4 * (1 + 4 * 3) + 1)
773 char buf[DUMP_LABEL_WIDTH + DUMP_WIDTH];
774 char *bp;
775 const unsigned char *cp = p;
776
777 bp = buf;
778
779 if (label != NULL && label[0] != '\0')
780 {
781 /* Handle the label. Care must be taken to avoid buffer overrun. */
782 size_t llen = strlen(label);
783
784 if (llen + 1 > sizeof(buf))
785 {
786 DBG_log("%s", label);
787 }
788 else
789 {
790 strcpy(buf, label);
791 if (buf[llen-1] == '\n')
792 {
793 buf[llen-1] = '\0'; /* get rid of newline */
794 DBG_log("%s", buf);
795 }
796 else if (llen < DUMP_LABEL_WIDTH)
797 {
798 bp = buf + llen;
799 }
800 else
801 {
802 DBG_log("%s", buf);
803 }
804 }
805 }
806
807 do {
808 int i, j;
809
810 for (i = 0; len!=0 && i!=4; i++)
811 {
812 *bp++ = ' ';
813 for (j = 0; len!=0 && j!=4; len--, j++)
814 {
815 static const char hexdig[] = "0123456789abcdef";
816
817 *bp++ = ' ';
818 *bp++ = hexdig[(*cp >> 4) & 0xF];
819 *bp++ = hexdig[*cp & 0xF];
820 cp++;
821 }
822 }
823 *bp = '\0';
824 DBG_log("%s", buf);
825 bp = buf;
826 } while (len != 0);
827 # undef DUMP_LABEL_WIDTH
828 # undef DUMP_WIDTH
829 }
830
831 #endif /* DEBUG */
832
833 static void show_loaded_plugins()
834 {
835 char buf[BUF_LEN], *plugin;
836 int len = 0;
837 enumerator_t *enumerator;
838
839 buf[0] = '\0';
840 enumerator = lib->plugins->create_plugin_enumerator(lib->plugins);
841 while (len < BUF_LEN && enumerator->enumerate(enumerator, &plugin))
842 {
843 len += snprintf(&buf[len], BUF_LEN-len, "%s ", plugin);
844 }
845 enumerator->destroy(enumerator);
846 whack_log(RC_COMMENT, "loaded plugins: %s", buf);
847 }
848
849 void show_status(bool all, const char *name)
850 {
851 if (all)
852 {
853 whack_log(RC_COMMENT, "Daemon status (pluto "VERSION"):");
854 show_ifaces_status();
855 show_myid_status();
856 show_loaded_plugins();
857 show_debug_status();
858 whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */
859 }
860 show_connections_status(all, name);
861 show_states_status(all, name);
862 #ifdef KLIPS
863 show_shunt_status();
864 #endif
865 }
866
867 /* ip_str: a simple to use variant of addrtot.
868 * It stores its result in a static buffer.
869 * This means that newer calls overwrite the storage of older calls.
870 * Note: this is not used in any of the logging functions, so their
871 * callers may use it.
872 */
873 const char *
874 ip_str(const ip_address *src)
875 {
876 static char buf[ADDRTOT_BUF];
877
878 addrtot(src, 0, buf, sizeof(buf));
879 return buf;
880 }
881
882 /*
883 * a routine that attempts to schedule itself daily.
884 *
885 */
886
887 void
888 daily_log_reset(void)
889 {
890 /* now perform actions */
891 logged_txt_warning = FALSE;
892
893 logged_myid_fqdn_txt_warning = FALSE;
894 logged_myid_ip_txt_warning = FALSE;
895 logged_myid_fqdn_key_warning = FALSE;
896 logged_myid_ip_key_warning = FALSE;
897 }
898
899 void
900 daily_log_event(void)
901 {
902 struct tm lt;
903 time_t t, interval;
904
905 /* attempt to schedule oneself to midnight, local time
906 * do this by getting seconds in the day, and delaying
907 * by 86400 - 3600*hours - 60*minutes - seconds.
908 */
909 time(&t);
910 localtime_r(&t, &lt);
911 interval = 3600 * (24 - lt.tm_hour) - 60 * lt.tm_min - lt.tm_sec;
912
913 event_schedule(EVENT_LOG_DAILY, interval, NULL);
914 daily_log_reset();
915 }
916
917 /*
918 * Local Variables:
919 * c-basic-offset:4
920 * c-style: pluto
921 * End:
922 */