mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 09:41:54 +00:00
Log: Add support for UDP logging
Add support for UDP logging, using RFC 3164 syslog protocol. Based on the patch from Alexander Zubkov <green@qrator.net>, thanks!
This commit is contained in:
parent
8cf1be6f67
commit
2c7555cf2a
@ -543,11 +543,12 @@ ipv6 table
|
|||||||
include "tablename.conf";;
|
include "tablename.conf";;
|
||||||
</code>
|
</code>
|
||||||
|
|
||||||
<tag><label id="opt-log">log "<m/filename/" [<m/limit/ "<m/backup/"] | syslog [name <m/name/] | stderr all|{ <m/list of classes/ }</tag>
|
<tag><label id="opt-log">log "<m/filename/" [<m/limit/ "<m/backup/"] | syslog [name <m/name/] | stderr | udp <m/address/ [port <m/port/] all|{ <m/list of classes/ }</tag>
|
||||||
Set logging of messages having the given class (either <cf/all/ or <cf>{
|
Set logging of messages having the given class (either <cf/all/ or <cf>{
|
||||||
error|trace [, <m/.../] }</cf> etc.) into selected destination - a file
|
error|trace [, <m/.../] }</cf> etc.) into selected destination - a file
|
||||||
specified as a filename string (with optional log rotation information),
|
specified as a filename string (with optional log rotation information),
|
||||||
syslog (with optional name argument), or the stderr output.
|
syslog (with optional name argument), the stderr output, or as a UDP
|
||||||
|
message (in <rfc id="3164"> syslog format).
|
||||||
|
|
||||||
Classes are:
|
Classes are:
|
||||||
<cf/info/, <cf/warning/, <cf/error/ and <cf/fatal/ for messages about local problems,
|
<cf/info/, <cf/warning/, <cf/error/ and <cf/fatal/ for messages about local problems,
|
||||||
|
@ -124,6 +124,7 @@ extern int sk_priority_control; /* Suggested priority for control traffic, shou
|
|||||||
#define SKF_BIND 0x10 /* Bind datagram socket to given source address */
|
#define SKF_BIND 0x10 /* Bind datagram socket to given source address */
|
||||||
#define SKF_HIGH_PORT 0x20 /* Choose port from high range if possible */
|
#define SKF_HIGH_PORT 0x20 /* Choose port from high range if possible */
|
||||||
#define SKF_FREEBIND 0x40 /* Allow socket to bind to a nonlocal address */
|
#define SKF_FREEBIND 0x40 /* Allow socket to bind to a nonlocal address */
|
||||||
|
#define SKF_CONNECT 0x80 /* Connect datagram socket to given dst address/port */
|
||||||
|
|
||||||
#define SKF_THREAD 0x100 /* Socked used in thread, Do not add to main loop */
|
#define SKF_THREAD 0x100 /* Socked used in thread, Do not add to main loop */
|
||||||
#define SKF_TRUNCATED 0x200 /* Received packet was truncated, set by IO layer */
|
#define SKF_TRUNCATED 0x200 /* Received packet was truncated, set by IO layer */
|
||||||
|
@ -17,9 +17,9 @@ static struct log_config *this_log;
|
|||||||
|
|
||||||
CF_DECLS
|
CF_DECLS
|
||||||
|
|
||||||
CF_KEYWORDS(LOG, SYSLOG, ALL, DEBUG, TRACE, INFO, REMOTE, WARNING, ERROR, AUTH, FATAL, BUG, STDERR, SOFT)
|
CF_KEYWORDS(LOG, SYSLOG, NAME, STDERR, UDP, PORT)
|
||||||
CF_KEYWORDS(NAME, CONFIRM, UNDO, CHECK, TIMEOUT, DEBUG, LATENCY, LIMIT, WATCHDOG, WARNING, STATUS)
|
CF_KEYWORDS(ALL, DEBUG, TRACE, INFO, REMOTE, WARNING, ERROR, AUTH, FATAL, BUG)
|
||||||
CF_KEYWORDS(GRACEFUL, RESTART, THREADS)
|
CF_KEYWORDS(DEBUG, LATENCY, LIMIT, WATCHDOG, WARNING, TIMEOUT, THREADS)
|
||||||
|
|
||||||
%type <i> log_mask log_mask_list log_cat cfg_timeout
|
%type <i> log_mask log_mask_list log_cat cfg_timeout
|
||||||
%type <t> cfg_name
|
%type <t> cfg_name
|
||||||
@ -64,8 +64,28 @@ log_file:
|
|||||||
}
|
}
|
||||||
| SYSLOG syslog_name { this_log->fh = NULL; new_config->syslog_name = $2; }
|
| SYSLOG syslog_name { this_log->fh = NULL; new_config->syslog_name = $2; }
|
||||||
| STDERR { this_log->fh = stderr; }
|
| STDERR { this_log->fh = stderr; }
|
||||||
|
| UDP log_udp_host log_udp_port {
|
||||||
|
this_log->udp_flag = 1;
|
||||||
|
|
||||||
|
if (!parse_and_exit)
|
||||||
|
log_open_udp(this_log, new_config->pool);
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
log_udp_host: text_or_ipa
|
||||||
|
{
|
||||||
|
if ($1.type == T_STRING)
|
||||||
|
this_log->host = $1.val.s;
|
||||||
|
else if ($1.type == T_IP)
|
||||||
|
this_log->ip = $1.val.ip;
|
||||||
|
else bug("Bad text_or_ipa");
|
||||||
|
};
|
||||||
|
|
||||||
|
log_udp_port:
|
||||||
|
/* empty */ { this_log->port = 514; }
|
||||||
|
| PORT NUM { check_u16($2); this_log->port = $2; }
|
||||||
|
;
|
||||||
|
|
||||||
log_mask:
|
log_mask:
|
||||||
ALL { $$ = ~0; }
|
ALL { $$ = ~0; }
|
||||||
| '{' log_mask_list '}' { $$ = $2; }
|
| '{' log_mask_list '}' { $$ = $2; }
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
#include <netinet/udp.h>
|
#include <netinet/udp.h>
|
||||||
#include <netinet/icmp6.h>
|
#include <netinet/icmp6.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
|
||||||
#include "nest/bird.h"
|
#include "nest/bird.h"
|
||||||
#include "lib/lists.h"
|
#include "lib/lists.h"
|
||||||
@ -94,12 +95,25 @@ struct rfile *
|
|||||||
rf_open(pool *p, const char *name, const char *mode)
|
rf_open(pool *p, const char *name, const char *mode)
|
||||||
{
|
{
|
||||||
FILE *f = fopen(name, mode);
|
FILE *f = fopen(name, mode);
|
||||||
|
|
||||||
if (!f)
|
if (!f)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
struct rfile *r = ralloc(p, &rf_class);
|
struct rfile *r = ralloc(p, &rf_class);
|
||||||
r->f = f;
|
r->f = f;
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct rfile *
|
||||||
|
rf_fdopen(pool *p, int fd, const char *mode)
|
||||||
|
{
|
||||||
|
FILE *f = fdopen(fd, mode);
|
||||||
|
if (!f)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
struct rfile *r = ralloc(p, &rf_class);
|
||||||
|
r->f = f;
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1048,6 +1062,14 @@ sk_insert(sock *s)
|
|||||||
add_tail(&sock_list, &s->n);
|
add_tail(&sock_list, &s->n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sk_connect(sock *s)
|
||||||
|
{
|
||||||
|
sockaddr sa;
|
||||||
|
sockaddr_fill(&sa, s->af, s->daddr, s->iface, s->dport);
|
||||||
|
return connect(s->fd, &sa.sa, SA_LEN(sa));
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sk_tcp_connected(sock *s)
|
sk_tcp_connected(sock *s)
|
||||||
{
|
{
|
||||||
@ -1465,8 +1487,7 @@ sk_open(sock *s)
|
|||||||
switch (s->type)
|
switch (s->type)
|
||||||
{
|
{
|
||||||
case SK_TCP_ACTIVE:
|
case SK_TCP_ACTIVE:
|
||||||
sockaddr_fill(&sa, s->af, s->daddr, s->iface, s->dport);
|
if (sk_connect(s) >= 0)
|
||||||
if (connect(fd, &sa.sa, SA_LEN(sa)) >= 0)
|
|
||||||
sk_tcp_connected(s);
|
sk_tcp_connected(s);
|
||||||
else if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS &&
|
else if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS &&
|
||||||
errno != ECONNREFUSED && errno != EHOSTUNREACH && errno != ENETUNREACH)
|
errno != ECONNREFUSED && errno != EHOSTUNREACH && errno != ENETUNREACH)
|
||||||
@ -1478,6 +1499,14 @@ sk_open(sock *s)
|
|||||||
ERR2("listen");
|
ERR2("listen");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SK_UDP:
|
||||||
|
if (s->flags & SKF_CONNECT)
|
||||||
|
if (sk_connect(s) < 0)
|
||||||
|
ERR2("connect");
|
||||||
|
|
||||||
|
sk_alloc_bufs(s);
|
||||||
|
break;
|
||||||
|
|
||||||
case SK_SSH_ACTIVE:
|
case SK_SSH_ACTIVE:
|
||||||
case SK_MAGIC:
|
case SK_MAGIC:
|
||||||
break;
|
break;
|
||||||
@ -1945,10 +1974,7 @@ sk_write_noflush(sock *s)
|
|||||||
{
|
{
|
||||||
case SK_TCP_ACTIVE:
|
case SK_TCP_ACTIVE:
|
||||||
{
|
{
|
||||||
sockaddr sa;
|
if (sk_connect(s) >= 0 || errno == EISCONN)
|
||||||
sockaddr_fill(&sa, s->af, s->daddr, s->iface, s->dport);
|
|
||||||
|
|
||||||
if (connect(s->fd, &sa.sa, SA_LEN(sa)) >= 0 || errno == EISCONN)
|
|
||||||
sk_tcp_connected(s);
|
sk_tcp_connected(s);
|
||||||
else if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS)
|
else if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS)
|
||||||
s->err_hook(s, errno);
|
s->err_hook(s, errno);
|
||||||
@ -2418,3 +2444,36 @@ test_old_bird(char *path)
|
|||||||
die("I found another BIRD running.");
|
die("I found another BIRD running.");
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DNS resolver
|
||||||
|
*/
|
||||||
|
|
||||||
|
ip_addr
|
||||||
|
resolve_hostname(const char *host, int type, const char **err_msg)
|
||||||
|
{
|
||||||
|
struct addrinfo *res;
|
||||||
|
struct addrinfo hints = {
|
||||||
|
.ai_family = AF_UNSPEC,
|
||||||
|
.ai_socktype = (type == SK_UDP) ? SOCK_DGRAM : SOCK_STREAM,
|
||||||
|
.ai_flags = AI_ADDRCONFIG,
|
||||||
|
};
|
||||||
|
|
||||||
|
*err_msg = NULL;
|
||||||
|
|
||||||
|
int err_code = getaddrinfo(host, NULL, &hints, &res);
|
||||||
|
if (err_code != 0)
|
||||||
|
{
|
||||||
|
*err_msg = gai_strerror(err_code);
|
||||||
|
return IPA_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_addr addr = IPA_NONE;
|
||||||
|
uint unused;
|
||||||
|
|
||||||
|
sockaddr_read((sockaddr *) res->ai_addr, res->ai_family, &addr, NULL, &unused);
|
||||||
|
freeaddrinfo(res);
|
||||||
|
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include "conf/conf.h"
|
#include "conf/conf.h"
|
||||||
#include "lib/string.h"
|
#include "lib/string.h"
|
||||||
#include "lib/lists.h"
|
#include "lib/lists.h"
|
||||||
|
#include "lib/socket.h"
|
||||||
#include "sysdep/unix/unix.h"
|
#include "sysdep/unix/unix.h"
|
||||||
|
|
||||||
static int dbg_fd = -1;
|
static int dbg_fd = -1;
|
||||||
@ -138,6 +139,55 @@ log_rotate(struct log_config *l)
|
|||||||
return log_open(l);
|
return log_open(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Expected to be called during config parsing */
|
||||||
|
int
|
||||||
|
log_open_udp(struct log_config *l, pool *p)
|
||||||
|
{
|
||||||
|
ASSERT(l->host || ipa_nonzero(l->ip));
|
||||||
|
|
||||||
|
if (l->host && ipa_zero(l->ip))
|
||||||
|
{
|
||||||
|
const char *err_msg;
|
||||||
|
l->ip = resolve_hostname(l->host, SK_UDP, &err_msg);
|
||||||
|
|
||||||
|
if (ipa_zero(l->ip))
|
||||||
|
{
|
||||||
|
cf_warn("Cannot resolve hostname '%s': %s", l->host, err_msg);
|
||||||
|
goto err0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sock *sk = sk_new(p);
|
||||||
|
sk->type = SK_UDP;
|
||||||
|
sk->daddr = l->ip;
|
||||||
|
sk->dport = l->port;
|
||||||
|
sk->flags = SKF_CONNECT | SKF_THREAD;
|
||||||
|
|
||||||
|
if (sk_open(sk) < 0)
|
||||||
|
{
|
||||||
|
cf_warn("Cannot open UDP log socket: %s%#m", sk->err);
|
||||||
|
goto err1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Move fd from sk resource to rf resource */
|
||||||
|
l->rf = rf_fdopen(p, sk->fd, "a");
|
||||||
|
if (!l->rf)
|
||||||
|
goto err1;
|
||||||
|
|
||||||
|
l->fh = rf_file(l->rf);
|
||||||
|
|
||||||
|
sk->fd = -1;
|
||||||
|
rfree(sk);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err1:
|
||||||
|
rfree(sk);
|
||||||
|
err0:
|
||||||
|
l->mask = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* log_commit - commit a log message
|
* log_commit - commit a log message
|
||||||
* @class: message class information (%L_DEBUG to %L_BUG, see |lib/birdlib.h|)
|
* @class: message class information (%L_DEBUG to %L_BUG, see |lib/birdlib.h|)
|
||||||
@ -168,6 +218,18 @@ log_commit(int class, buffer *buf)
|
|||||||
{
|
{
|
||||||
if (l->terminal_flag)
|
if (l->terminal_flag)
|
||||||
fputs("bird: ", l->fh);
|
fputs("bird: ", l->fh);
|
||||||
|
else if (l->udp_flag)
|
||||||
|
{
|
||||||
|
int pri = LOG_DAEMON | syslog_priorities[class];
|
||||||
|
char tbuf[TM_DATETIME_BUFFER_SIZE];
|
||||||
|
const char *hostname = (config && config->hostname) ? config->hostname : "<none>";
|
||||||
|
const char *fmt = "%b %d %T.%6f";
|
||||||
|
if (!tm_format_real_time(tbuf, sizeof(tbuf), fmt, current_real_time()))
|
||||||
|
strcpy(tbuf, "<error>");
|
||||||
|
|
||||||
|
/* Legacy RFC 3164 format, but with us precision */
|
||||||
|
fprintf(l->fh, "<%d>%s %s %s: ", pri, tbuf, hostname, bird_name);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
byte tbuf[TM_DATETIME_BUFFER_SIZE];
|
byte tbuf[TM_DATETIME_BUFFER_SIZE];
|
||||||
@ -400,7 +462,7 @@ log_switch(int initial, list *logs, const char *new_syslog_name)
|
|||||||
/* Close the logs to avoid pinning them on disk when deleted */
|
/* Close the logs to avoid pinning them on disk when deleted */
|
||||||
if (current_log_list)
|
if (current_log_list)
|
||||||
WALK_LIST(l, *current_log_list)
|
WALK_LIST(l, *current_log_list)
|
||||||
if (l->rf)
|
if (l->filename && l->rf)
|
||||||
log_close(l);
|
log_close(l);
|
||||||
|
|
||||||
/* Reopen the logs, needed for 'configure undo' */
|
/* Reopen the logs, needed for 'configure undo' */
|
||||||
|
@ -109,9 +109,11 @@ void io_loop(void);
|
|||||||
void io_log_dump(void);
|
void io_log_dump(void);
|
||||||
int sk_open_unix(struct birdsock *s, char *name);
|
int sk_open_unix(struct birdsock *s, char *name);
|
||||||
struct rfile *rf_open(struct pool *, const char *name, const char *mode);
|
struct rfile *rf_open(struct pool *, const char *name, const char *mode);
|
||||||
|
struct rfile *rf_fdopen(pool *p, int fd, const char *mode);
|
||||||
void *rf_file(struct rfile *f);
|
void *rf_file(struct rfile *f);
|
||||||
int rf_fileno(struct rfile *f);
|
int rf_fileno(struct rfile *f);
|
||||||
void test_old_bird(char *path);
|
void test_old_bird(char *path);
|
||||||
|
ip_addr resolve_hostname(const char *host, int type, const char **err_msg);
|
||||||
|
|
||||||
/* krt.c bits */
|
/* krt.c bits */
|
||||||
|
|
||||||
@ -133,6 +135,12 @@ struct log_config {
|
|||||||
off_t pos; /* Position/size of current log */
|
off_t pos; /* Position/size of current log */
|
||||||
off_t limit; /* Log size limit */
|
off_t limit; /* Log size limit */
|
||||||
int terminal_flag;
|
int terminal_flag;
|
||||||
|
int udp_flag;
|
||||||
|
const char *host; /* UDP log dst host name */
|
||||||
|
ip_addr ip; /* UDP log dst IP address */
|
||||||
|
uint port; /* UDP log dst port */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int log_open_udp(struct log_config *l, pool *p);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user