923 lines
21 KiB
C
923 lines
21 KiB
C
/* error logging functions
|
|
* Copyright (C) 1997 Angelos D. Keromytis.
|
|
* Copyright (C) 1998-2001 D. Hugh Redelmeier.
|
|
* Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation; either version 2 of the License, or (at your
|
|
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* for more details.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#include <stdarg.h>
|
|
#include <syslog.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <signal.h> /* used only if MSG_NOSIGNAL not defined */
|
|
#include <sys/queue.h>
|
|
#include <libgen.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
|
|
#include <freeswan.h>
|
|
#include <library.h>
|
|
#include <debug.h>
|
|
|
|
#include "constants.h"
|
|
#include "defs.h"
|
|
#include "log.h"
|
|
#include "server.h"
|
|
#include "state.h"
|
|
#include "connections.h"
|
|
#include "kernel.h"
|
|
#include "whack.h" /* needs connections.h */
|
|
#include "timer.h"
|
|
|
|
/* close one per-peer log */
|
|
static void perpeer_logclose(struct connection *c); /* forward */
|
|
|
|
|
|
bool
|
|
log_to_stderr = TRUE, /* should log go to stderr? */
|
|
log_to_syslog = TRUE, /* should log go to syslog? */
|
|
log_to_perpeer= FALSE; /* should log go to per-IP file? */
|
|
|
|
bool
|
|
logged_txt_warning = FALSE; /* should we complain about finding KEY? */
|
|
|
|
/* should we complain when we find no local id */
|
|
bool
|
|
logged_myid_fqdn_txt_warning = FALSE,
|
|
logged_myid_ip_txt_warning = FALSE,
|
|
logged_myid_fqdn_key_warning = FALSE,
|
|
logged_myid_ip_key_warning = FALSE;
|
|
|
|
/* may include trailing / */
|
|
const char *base_perpeer_logdir = PERPEERLOGDIR;
|
|
static int perpeer_count = 0;
|
|
|
|
/* from sys/queue.h */
|
|
static TAILQ_HEAD(perpeer, connection) perpeer_list;
|
|
|
|
|
|
/* Context for logging.
|
|
*
|
|
* Global variables: must be carefully adjusted at transaction boundaries!
|
|
* If the context provides a whack file descriptor, messages
|
|
* should be copied to it -- see whack_log()
|
|
*/
|
|
int whack_log_fd = NULL_FD; /* only set during whack_handle() */
|
|
struct state *cur_state = NULL; /* current state, for diagnostics */
|
|
struct connection *cur_connection = NULL; /* current connection, for diagnostics */
|
|
const ip_address *cur_from = NULL; /* source of current current message */
|
|
u_int16_t cur_from_port; /* host order */
|
|
|
|
/**
|
|
* pluto dbg function for libstrongswan
|
|
*/
|
|
static void pluto_dbg(int level, char *fmt, ...)
|
|
{
|
|
int priority = LOG_INFO;
|
|
int debug_level;
|
|
char buffer[8192];
|
|
char *current = buffer, *next;
|
|
va_list args;
|
|
|
|
if (cur_debugging & DBG_PRIVATE)
|
|
{
|
|
debug_level = 4;
|
|
}
|
|
else if (cur_debugging & DBG_RAW)
|
|
{
|
|
debug_level = 3;
|
|
}
|
|
else if (cur_debugging & DBG_PARSING)
|
|
{
|
|
debug_level = 2;
|
|
}
|
|
else
|
|
{
|
|
debug_level = 1;
|
|
}
|
|
|
|
if (level <= debug_level)
|
|
{
|
|
va_start(args, fmt);
|
|
|
|
if (log_to_stderr)
|
|
{
|
|
if (level > 1)
|
|
{
|
|
fprintf(stderr, "| ");
|
|
}
|
|
vfprintf(stderr, fmt, args);
|
|
fprintf(stderr, "\n");
|
|
}
|
|
if (log_to_syslog)
|
|
{
|
|
/* write in memory buffer first */
|
|
vsnprintf(buffer, sizeof(buffer), fmt, args);
|
|
|
|
/* do a syslog with every line */
|
|
while (current)
|
|
{
|
|
next = strchr(current, '\n');
|
|
if (next)
|
|
{
|
|
*(next++) = '\0';
|
|
}
|
|
syslog(priority, "%s%s\n", (level > 1)? "| ":"", current);
|
|
current = next;
|
|
}
|
|
}
|
|
va_end(args);
|
|
}
|
|
}
|
|
|
|
void
|
|
init_log(const char *program)
|
|
{
|
|
/* enable pluto debugging hook for libstrongswan */
|
|
dbg = pluto_dbg;
|
|
|
|
if (log_to_stderr)
|
|
{
|
|
setbuf(stderr, NULL);
|
|
}
|
|
if (log_to_syslog)
|
|
{
|
|
openlog(program, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_AUTHPRIV);
|
|
}
|
|
TAILQ_INIT(&perpeer_list);
|
|
}
|
|
|
|
void
|
|
close_peerlog(void)
|
|
{
|
|
/* exit if the queue has not been initialized */
|
|
if (perpeer_list.tqh_first == NULL)
|
|
return;
|
|
|
|
/* end of queue is given by pointer to "HEAD" */
|
|
while (TAILQ_LAST(&perpeer_list, perpeer) != (void *)&perpeer_list)
|
|
perpeer_logclose(TAILQ_LAST(&perpeer_list, perpeer));
|
|
}
|
|
|
|
void
|
|
close_log(void)
|
|
{
|
|
if (log_to_syslog)
|
|
closelog();
|
|
|
|
close_peerlog();
|
|
}
|
|
|
|
/* Sanitize character string in situ: turns dangerous characters into \OOO.
|
|
* With a bit of work, we could use simpler reps for \\, \r, etc.,
|
|
* but this is only to protect against something that shouldn't be used.
|
|
* Truncate resulting string to what fits in buffer.
|
|
*/
|
|
static size_t
|
|
sanitize(char *buf, size_t size)
|
|
{
|
|
# define UGLY_WIDTH 4 /* width for ugly character: \OOO */
|
|
size_t len;
|
|
size_t added = 0;
|
|
char *p;
|
|
|
|
passert(size >= UGLY_WIDTH); /* need room to swing cat */
|
|
|
|
/* find right side of string to be sanitized and count
|
|
* number of columns to be added. Stop on end of string
|
|
* or lack of room for more result.
|
|
*/
|
|
for (p = buf; *p != '\0' && &p[added] < &buf[size - UGLY_WIDTH]; )
|
|
{
|
|
unsigned char c = *p++;
|
|
|
|
if (c == '\\' || !isprint(c))
|
|
added += UGLY_WIDTH - 1;
|
|
}
|
|
|
|
/* at this point, p points after last original character to be
|
|
* included. added is how many characters are added to sanitize.
|
|
* so p[added] will point after last sanitized character.
|
|
*/
|
|
|
|
p[added] = '\0';
|
|
len = &p[added] - buf;
|
|
|
|
/* scan backwards, copying characters to their new home
|
|
* and inserting the expansions for ugly characters.
|
|
* It is finished when no more shifting is required.
|
|
* This is a predecrement loop.
|
|
*/
|
|
while (added != 0)
|
|
{
|
|
char fmtd[UGLY_WIDTH + 1];
|
|
unsigned char c;
|
|
|
|
while ((c = *--p) != '\\' && isprint(c))
|
|
p[added] = c;
|
|
added -= UGLY_WIDTH - 1;
|
|
snprintf(fmtd, sizeof(fmtd), "\\%03o", c);
|
|
memcpy(p + added, fmtd, UGLY_WIDTH);
|
|
}
|
|
return len;
|
|
# undef UGLY_WIDTH
|
|
}
|
|
|
|
/* format a string for the log, with suitable prefixes.
|
|
* A format starting with ~ indicates that this is a reprocessing
|
|
* of the message, so prefixing and quoting is suppressed.
|
|
*/
|
|
static void
|
|
fmt_log(char *buf, size_t buf_len, const char *fmt, va_list ap)
|
|
{
|
|
bool reproc = *fmt == '~';
|
|
size_t ps;
|
|
struct connection *c = cur_state != NULL ? cur_state->st_connection
|
|
: cur_connection;
|
|
|
|
buf[0] = '\0';
|
|
if (reproc)
|
|
fmt++; /* ~ at start of format suppresses this prefix */
|
|
else if (c != NULL)
|
|
{
|
|
/* start with name of connection */
|
|
char *const be = buf + buf_len;
|
|
char *bp = buf;
|
|
|
|
snprintf(bp, be - bp, "\"%s\"", c->name);
|
|
bp += strlen(bp);
|
|
|
|
/* if it fits, put in any connection instance information */
|
|
if (be - bp > CONN_INST_BUF)
|
|
{
|
|
fmt_conn_instance(c, bp);
|
|
bp += strlen(bp);
|
|
}
|
|
|
|
if (cur_state != NULL)
|
|
{
|
|
/* state number */
|
|
snprintf(bp, be - bp, " #%lu", cur_state->st_serialno);
|
|
bp += strlen(bp);
|
|
}
|
|
snprintf(bp, be - bp, ": ");
|
|
}
|
|
else if (cur_from != NULL)
|
|
{
|
|
/* peer's IP address */
|
|
/* Note: must not use ip_str() because our caller might! */
|
|
char ab[ADDRTOT_BUF];
|
|
|
|
(void) addrtot(cur_from, 0, ab, sizeof(ab));
|
|
snprintf(buf, buf_len, "packet from %s:%u: "
|
|
, ab, (unsigned)cur_from_port);
|
|
}
|
|
|
|
ps = strlen(buf);
|
|
vsnprintf(buf + ps, buf_len - ps, fmt, ap);
|
|
if (!reproc)
|
|
(void)sanitize(buf, buf_len);
|
|
}
|
|
|
|
static void
|
|
perpeer_logclose(struct connection *c)
|
|
{
|
|
/* only free/close things if we had used them! */
|
|
if (c->log_file != NULL)
|
|
{
|
|
passert(perpeer_count > 0);
|
|
|
|
TAILQ_REMOVE(&perpeer_list, c, log_link);
|
|
perpeer_count--;
|
|
fclose(c->log_file);
|
|
c->log_file=NULL;
|
|
}
|
|
}
|
|
|
|
void
|
|
perpeer_logfree(struct connection *c)
|
|
{
|
|
perpeer_logclose(c);
|
|
if (c->log_file_name != NULL)
|
|
{
|
|
free(c->log_file_name);
|
|
c->log_file_name = NULL;
|
|
c->log_file_err = FALSE;
|
|
}
|
|
}
|
|
|
|
/* open the per-peer log */
|
|
static void
|
|
open_peerlog(struct connection *c)
|
|
{
|
|
syslog(LOG_INFO, "opening log file for conn %s", c->name);
|
|
|
|
if (c->log_file_name == NULL)
|
|
{
|
|
char peername[ADDRTOT_BUF], dname[ADDRTOT_BUF];
|
|
int peernamelen, lf_len;
|
|
|
|
addrtot(&c->spd.that.host_addr, 'Q', peername, sizeof(peername));
|
|
peernamelen = strlen(peername);
|
|
|
|
/* copy IP address, turning : and . into / */
|
|
{
|
|
char c, *p, *q;
|
|
|
|
p = peername;
|
|
q = dname;
|
|
do {
|
|
c = *p++;
|
|
if (c == '.' || c == ':')
|
|
c = '/';
|
|
*q++ = c;
|
|
} while (c != '\0');
|
|
}
|
|
|
|
lf_len = peernamelen * 2
|
|
+ strlen(base_perpeer_logdir)
|
|
+ sizeof("//.log")
|
|
+ 1;
|
|
c->log_file_name = malloc(lf_len);
|
|
|
|
fprintf(stderr, "base dir |%s| dname |%s| peername |%s|"
|
|
, base_perpeer_logdir, dname, peername);
|
|
snprintf(c->log_file_name, lf_len, "%s/%s/%s.log"
|
|
, base_perpeer_logdir, dname, peername);
|
|
|
|
syslog(LOG_DEBUG, "conn %s logfile is %s", c->name, c->log_file_name);
|
|
}
|
|
|
|
/* now open the file, creating directories if necessary */
|
|
|
|
{ /* create the directory */
|
|
char *dname;
|
|
int bpl_len = strlen(base_perpeer_logdir);
|
|
char *slashloc;
|
|
|
|
dname = clone_str(c->log_file_name);
|
|
dname = dirname(dname);
|
|
|
|
if (access(dname, W_OK) != 0)
|
|
{
|
|
if (errno != ENOENT)
|
|
{
|
|
if (c->log_file_err)
|
|
{
|
|
syslog(LOG_CRIT, "can not write to %s: %s"
|
|
, dname, strerror(errno));
|
|
c->log_file_err = TRUE;
|
|
free(dname);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* directory does not exist, walk path creating dirs */
|
|
/* start at base_perpeer_logdir */
|
|
slashloc = dname + bpl_len;
|
|
slashloc++; /* since, by construction there is a slash
|
|
right there */
|
|
|
|
while (*slashloc != '\0')
|
|
{
|
|
char saveslash;
|
|
|
|
/* look for next slash */
|
|
while (*slashloc != '\0' && *slashloc != '/') slashloc++;
|
|
|
|
saveslash = *slashloc;
|
|
|
|
*slashloc = '\0';
|
|
|
|
if (mkdir(dname, 0750) != 0 && errno != EEXIST)
|
|
{
|
|
syslog(LOG_CRIT, "can not create dir %s: %s"
|
|
, dname, strerror(errno));
|
|
c->log_file_err = TRUE;
|
|
free(dname);
|
|
return;
|
|
}
|
|
syslog(LOG_DEBUG, "created new directory %s", dname);
|
|
*slashloc = saveslash;
|
|
slashloc++;
|
|
}
|
|
}
|
|
free(dname);
|
|
}
|
|
|
|
c->log_file = fopen(c->log_file_name, "a");
|
|
if (c->log_file == NULL)
|
|
{
|
|
if (c->log_file_err)
|
|
{
|
|
syslog(LOG_CRIT, "logging system can not open %s: %s"
|
|
, c->log_file_name, strerror(errno));
|
|
c->log_file_err = TRUE;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* look for a connection to close! */
|
|
while (perpeer_count >= MAX_PEERLOG_COUNT)
|
|
{
|
|
/* can not be NULL because perpeer_count > 0 */
|
|
passert(TAILQ_LAST(&perpeer_list, perpeer) != (void *)&perpeer_list);
|
|
|
|
perpeer_logclose(TAILQ_LAST(&perpeer_list, perpeer));
|
|
}
|
|
|
|
/* insert this into the list */
|
|
TAILQ_INSERT_HEAD(&perpeer_list, c, log_link);
|
|
passert(c->log_file != NULL);
|
|
perpeer_count++;
|
|
}
|
|
|
|
/* log a line to cur_connection's log */
|
|
static void
|
|
peerlog(const char *prefix, const char *m)
|
|
{
|
|
if (cur_connection == NULL)
|
|
{
|
|
/* we can not log it in this case. Oh well. */
|
|
return;
|
|
}
|
|
|
|
if (cur_connection->log_file == NULL)
|
|
{
|
|
open_peerlog(cur_connection);
|
|
}
|
|
|
|
/* despite our attempts above, we may not be able to open the file. */
|
|
if (cur_connection->log_file != NULL)
|
|
{
|
|
char datebuf[32];
|
|
time_t n;
|
|
struct tm *t;
|
|
|
|
time(&n);
|
|
t = localtime(&n);
|
|
|
|
strftime(datebuf, sizeof(datebuf), "%Y-%m-%d %T", t);
|
|
fprintf(cur_connection->log_file, "%s %s%s\n", datebuf, prefix, m);
|
|
|
|
/* now move it to the front of the list */
|
|
TAILQ_REMOVE(&perpeer_list, cur_connection, log_link);
|
|
TAILQ_INSERT_HEAD(&perpeer_list, cur_connection, log_link);
|
|
}
|
|
}
|
|
|
|
void
|
|
plog(const char *message, ...)
|
|
{
|
|
va_list args;
|
|
char m[LOG_WIDTH]; /* longer messages will be truncated */
|
|
|
|
va_start(args, message);
|
|
fmt_log(m, sizeof(m), message, args);
|
|
va_end(args);
|
|
|
|
if (log_to_stderr)
|
|
fprintf(stderr, "%s\n", m);
|
|
if (log_to_syslog)
|
|
syslog(LOG_WARNING, "%s", m);
|
|
if (log_to_perpeer)
|
|
peerlog("", m);
|
|
|
|
whack_log(RC_LOG, "~%s", m);
|
|
}
|
|
|
|
void
|
|
loglog(int mess_no, const char *message, ...)
|
|
{
|
|
va_list args;
|
|
char m[LOG_WIDTH]; /* longer messages will be truncated */
|
|
|
|
va_start(args, message);
|
|
fmt_log(m, sizeof(m), message, args);
|
|
va_end(args);
|
|
|
|
if (log_to_stderr)
|
|
fprintf(stderr, "%s\n", m);
|
|
if (log_to_syslog)
|
|
syslog(LOG_WARNING, "%s", m);
|
|
if (log_to_perpeer)
|
|
peerlog("", m);
|
|
|
|
whack_log(mess_no, "~%s", m);
|
|
}
|
|
|
|
void
|
|
log_errno_routine(int e, const char *message, ...)
|
|
{
|
|
va_list args;
|
|
char m[LOG_WIDTH]; /* longer messages will be truncated */
|
|
|
|
va_start(args, message);
|
|
fmt_log(m, sizeof(m), message, args);
|
|
va_end(args);
|
|
|
|
if (log_to_stderr)
|
|
fprintf(stderr, "ERROR: %s. Errno %d: %s\n", m, e, strerror(e));
|
|
if (log_to_syslog)
|
|
syslog(LOG_ERR, "ERROR: %s. Errno %d: %s", m, e, strerror(e));
|
|
if (log_to_perpeer)
|
|
{
|
|
peerlog(strerror(e), m);
|
|
}
|
|
|
|
whack_log(RC_LOG_SERIOUS
|
|
, "~ERROR: %s. Errno %d: %s", m, e, strerror(e));
|
|
}
|
|
|
|
void
|
|
exit_log(const char *message, ...)
|
|
{
|
|
va_list args;
|
|
char m[LOG_WIDTH]; /* longer messages will be truncated */
|
|
|
|
va_start(args, message);
|
|
fmt_log(m, sizeof(m), message, args);
|
|
va_end(args);
|
|
|
|
if (log_to_stderr)
|
|
fprintf(stderr, "FATAL ERROR: %s\n", m);
|
|
if (log_to_syslog)
|
|
syslog(LOG_ERR, "FATAL ERROR: %s", m);
|
|
if (log_to_perpeer)
|
|
peerlog("FATAL ERROR: ", m);
|
|
|
|
whack_log(RC_LOG_SERIOUS, "~FATAL ERROR: %s", m);
|
|
|
|
exit_pluto(1);
|
|
}
|
|
|
|
void
|
|
exit_log_errno_routine(int e, const char *message, ...)
|
|
{
|
|
va_list args;
|
|
char m[LOG_WIDTH]; /* longer messages will be truncated */
|
|
|
|
va_start(args, message);
|
|
fmt_log(m, sizeof(m), message, args);
|
|
va_end(args);
|
|
|
|
if (log_to_stderr)
|
|
fprintf(stderr, "FATAL ERROR: %s. Errno %d: %s\n", m, e, strerror(e));
|
|
if (log_to_syslog)
|
|
syslog(LOG_ERR, "FATAL ERROR: %s. Errno %d: %s", m, e, strerror(e));
|
|
if (log_to_perpeer)
|
|
peerlog(strerror(e), m);
|
|
|
|
whack_log(RC_LOG_SERIOUS
|
|
, "~FATAL ERROR: %s. Errno %d: %s", m, e, strerror(e));
|
|
|
|
exit_pluto(1);
|
|
}
|
|
|
|
/* emit message to whack.
|
|
* form is "ddd statename text" where
|
|
* - ddd is a decimal status code (RC_*) as described in whack.h
|
|
* - text is a human-readable annotation
|
|
*/
|
|
#ifdef DEBUG
|
|
static volatile sig_atomic_t dying_breath = FALSE;
|
|
#endif
|
|
|
|
void
|
|
whack_log(int mess_no, const char *message, ...)
|
|
{
|
|
int wfd = whack_log_fd != NULL_FD ? whack_log_fd
|
|
: cur_state != NULL ? cur_state->st_whack_sock
|
|
: NULL_FD;
|
|
|
|
if (wfd != NULL_FD
|
|
#ifdef DEBUG
|
|
|| dying_breath
|
|
#endif
|
|
)
|
|
{
|
|
va_list args;
|
|
char m[LOG_WIDTH]; /* longer messages will be truncated */
|
|
int prelen = snprintf(m, sizeof(m), "%03d ", mess_no);
|
|
|
|
passert(prelen >= 0);
|
|
|
|
va_start(args, message);
|
|
fmt_log(m+prelen, sizeof(m)-prelen, message, args);
|
|
va_end(args);
|
|
|
|
#if DEBUG
|
|
if (dying_breath)
|
|
{
|
|
/* status output copied to log */
|
|
if (log_to_stderr)
|
|
fprintf(stderr, "%s\n", m + prelen);
|
|
if (log_to_syslog)
|
|
syslog(LOG_WARNING, "%s", m + prelen);
|
|
if (log_to_perpeer)
|
|
peerlog("", m);
|
|
}
|
|
#endif
|
|
|
|
if (wfd != NULL_FD)
|
|
{
|
|
/* write to whack socket, but suppress possible SIGPIPE */
|
|
size_t len = strlen(m);
|
|
#ifdef MSG_NOSIGNAL /* depends on version of glibc??? */
|
|
m[len] = '\n'; /* don't need NUL, do need NL */
|
|
(void) send(wfd, m, len + 1, MSG_NOSIGNAL);
|
|
#else /* !MSG_NOSIGNAL */
|
|
int r;
|
|
struct sigaction act
|
|
, oldact;
|
|
|
|
m[len] = '\n'; /* don't need NUL, do need NL */
|
|
act.sa_handler = SIG_IGN;
|
|
sigemptyset(&act.sa_mask);
|
|
act.sa_flags = 0; /* no nothing */
|
|
r = sigaction(SIGPIPE, &act, &oldact);
|
|
passert(r == 0);
|
|
|
|
(void) write(wfd, m, len + 1);
|
|
|
|
r = sigaction(SIGPIPE, &oldact, NULL);
|
|
passert(r == 0);
|
|
#endif /* !MSG_NOSIGNAL */
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Build up a diagnostic in a static buffer.
|
|
* Although this would be a generally useful function, it is very
|
|
* hard to come up with a discipline that prevents different uses
|
|
* from interfering. It is intended that by limiting it to building
|
|
* diagnostics, we will avoid this problem.
|
|
* Juggling is performed to allow an argument to be a previous
|
|
* result: the new string may safely depend on the old one. This
|
|
* restriction is not checked in any way: violators will produce
|
|
* confusing results (without crashing!).
|
|
*/
|
|
char diag_space[sizeof(diag_space)];
|
|
|
|
err_t
|
|
builddiag(const char *fmt, ...)
|
|
{
|
|
static char diag_space[LOG_WIDTH]; /* longer messages will be truncated */
|
|
char t[sizeof(diag_space)]; /* build result here first */
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
t[0] = '\0'; /* in case nothing terminates string */
|
|
vsnprintf(t, sizeof(t), fmt, args);
|
|
va_end(args);
|
|
strcpy(diag_space, t);
|
|
return diag_space;
|
|
}
|
|
|
|
/* Debugging message support */
|
|
|
|
#ifdef DEBUG
|
|
|
|
void
|
|
switch_fail(int n, const char *file_str, unsigned long line_no)
|
|
{
|
|
char buf[30];
|
|
|
|
snprintf(buf, sizeof(buf), "case %d unexpected", n);
|
|
passert_fail(buf, file_str, line_no);
|
|
}
|
|
|
|
void
|
|
passert_fail(const char *pred_str, const char *file_str, unsigned long line_no)
|
|
{
|
|
/* we will get a possibly unplanned prefix. Hope it works */
|
|
loglog(RC_LOG_SERIOUS, "ASSERTION FAILED at %s:%lu: %s", file_str, line_no, pred_str);
|
|
if (!dying_breath)
|
|
{
|
|
dying_breath = TRUE;
|
|
show_status(TRUE, NULL);
|
|
}
|
|
abort(); /* exiting correctly doesn't always work */
|
|
}
|
|
|
|
void
|
|
pexpect_log(const char *pred_str, const char *file_str, unsigned long line_no)
|
|
{
|
|
/* we will get a possibly unplanned prefix. Hope it works */
|
|
loglog(RC_LOG_SERIOUS, "EXPECTATION FAILED at %s:%lu: %s", file_str, line_no, pred_str);
|
|
}
|
|
|
|
lset_t
|
|
base_debugging = DBG_NONE, /* default to reporting nothing */
|
|
cur_debugging = DBG_NONE;
|
|
|
|
void
|
|
extra_debugging(const struct connection *c)
|
|
{
|
|
if(c == NULL)
|
|
{
|
|
reset_debugging();
|
|
return;
|
|
}
|
|
|
|
if (c!= NULL && c->extra_debugging != 0)
|
|
{
|
|
plog("enabling for connection: %s"
|
|
, bitnamesof(debug_bit_names, c->extra_debugging & ~cur_debugging));
|
|
cur_debugging |= c->extra_debugging;
|
|
}
|
|
}
|
|
|
|
/* log a debugging message (prefixed by "| ") */
|
|
|
|
void
|
|
DBG_log(const char *message, ...)
|
|
{
|
|
va_list args;
|
|
char m[LOG_WIDTH]; /* longer messages will be truncated */
|
|
|
|
va_start(args, message);
|
|
vsnprintf(m, sizeof(m), message, args);
|
|
va_end(args);
|
|
|
|
(void)sanitize(m, sizeof(m));
|
|
|
|
if (log_to_stderr)
|
|
fprintf(stderr, "| %s\n", m);
|
|
if (log_to_syslog)
|
|
syslog(LOG_DEBUG, "| %s", m);
|
|
if (log_to_perpeer)
|
|
peerlog("| ", m);
|
|
}
|
|
|
|
/* dump raw bytes in hex to stderr (for lack of any better destination) */
|
|
|
|
void
|
|
DBG_dump(const char *label, const void *p, size_t len)
|
|
{
|
|
# define DUMP_LABEL_WIDTH 20 /* arbitrary modest boundary */
|
|
# define DUMP_WIDTH (4 * (1 + 4 * 3) + 1)
|
|
char buf[DUMP_LABEL_WIDTH + DUMP_WIDTH];
|
|
char *bp;
|
|
const unsigned char *cp = p;
|
|
|
|
bp = buf;
|
|
|
|
if (label != NULL && label[0] != '\0')
|
|
{
|
|
/* Handle the label. Care must be taken to avoid buffer overrun. */
|
|
size_t llen = strlen(label);
|
|
|
|
if (llen + 1 > sizeof(buf))
|
|
{
|
|
DBG_log("%s", label);
|
|
}
|
|
else
|
|
{
|
|
strcpy(buf, label);
|
|
if (buf[llen-1] == '\n')
|
|
{
|
|
buf[llen-1] = '\0'; /* get rid of newline */
|
|
DBG_log("%s", buf);
|
|
}
|
|
else if (llen < DUMP_LABEL_WIDTH)
|
|
{
|
|
bp = buf + llen;
|
|
}
|
|
else
|
|
{
|
|
DBG_log("%s", buf);
|
|
}
|
|
}
|
|
}
|
|
|
|
do {
|
|
int i, j;
|
|
|
|
for (i = 0; len!=0 && i!=4; i++)
|
|
{
|
|
*bp++ = ' ';
|
|
for (j = 0; len!=0 && j!=4; len--, j++)
|
|
{
|
|
static const char hexdig[] = "0123456789abcdef";
|
|
|
|
*bp++ = ' ';
|
|
*bp++ = hexdig[(*cp >> 4) & 0xF];
|
|
*bp++ = hexdig[*cp & 0xF];
|
|
cp++;
|
|
}
|
|
}
|
|
*bp = '\0';
|
|
DBG_log("%s", buf);
|
|
bp = buf;
|
|
} while (len != 0);
|
|
# undef DUMP_LABEL_WIDTH
|
|
# undef DUMP_WIDTH
|
|
}
|
|
|
|
#endif /* DEBUG */
|
|
|
|
static void show_loaded_plugins()
|
|
{
|
|
char buf[BUF_LEN], *plugin;
|
|
int len = 0;
|
|
enumerator_t *enumerator;
|
|
|
|
buf[0] = '\0';
|
|
enumerator = lib->plugins->create_plugin_enumerator(lib->plugins);
|
|
while (len < BUF_LEN && enumerator->enumerate(enumerator, &plugin))
|
|
{
|
|
len += snprintf(&buf[len], BUF_LEN-len, "%s ", plugin);
|
|
}
|
|
enumerator->destroy(enumerator);
|
|
whack_log(RC_COMMENT, "loaded plugins: %s", buf);
|
|
}
|
|
|
|
void show_status(bool all, const char *name)
|
|
{
|
|
if (all)
|
|
{
|
|
whack_log(RC_COMMENT, "Status of IKEv1 pluto daemon (strongSwan "VERSION"):");
|
|
show_ifaces_status();
|
|
show_myid_status();
|
|
show_loaded_plugins();
|
|
show_debug_status();
|
|
whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */
|
|
}
|
|
show_connections_status(all, name);
|
|
show_states_status(all, name);
|
|
#ifdef KLIPS
|
|
show_shunt_status();
|
|
#endif
|
|
}
|
|
|
|
/* ip_str: a simple to use variant of addrtot.
|
|
* It stores its result in a static buffer.
|
|
* This means that newer calls overwrite the storage of older calls.
|
|
* Note: this is not used in any of the logging functions, so their
|
|
* callers may use it.
|
|
*/
|
|
const char *
|
|
ip_str(const ip_address *src)
|
|
{
|
|
static char buf[ADDRTOT_BUF];
|
|
|
|
addrtot(src, 0, buf, sizeof(buf));
|
|
return buf;
|
|
}
|
|
|
|
/*
|
|
* a routine that attempts to schedule itself daily.
|
|
*
|
|
*/
|
|
|
|
void
|
|
daily_log_reset(void)
|
|
{
|
|
/* now perform actions */
|
|
logged_txt_warning = FALSE;
|
|
|
|
logged_myid_fqdn_txt_warning = FALSE;
|
|
logged_myid_ip_txt_warning = FALSE;
|
|
logged_myid_fqdn_key_warning = FALSE;
|
|
logged_myid_ip_key_warning = FALSE;
|
|
}
|
|
|
|
void
|
|
daily_log_event(void)
|
|
{
|
|
struct tm lt;
|
|
time_t t, interval;
|
|
|
|
/* attempt to schedule oneself to midnight, local time
|
|
* do this by getting seconds in the day, and delaying
|
|
* by 86400 - 3600*hours - 60*minutes - seconds.
|
|
*/
|
|
time(&t);
|
|
localtime_r(&t, <);
|
|
interval = 3600 * (24 - lt.tm_hour) - 60 * lt.tm_min - lt.tm_sec;
|
|
|
|
event_schedule(EVENT_LOG_DAILY, interval, NULL);
|
|
daily_log_reset();
|
|
}
|
|
|
|
/*
|
|
* Local Variables:
|
|
* c-basic-offset:4
|
|
* c-style: pluto
|
|
* End:
|
|
*/
|