commit bc4f65285083370f6796196481a39b9841d316a3 Author: Alexander Zubkov Date: Sun Jan 2 16:49:49 2022 +0100 Log: add udp log destination Add UDP log destination, which can be configured with: log udp ["hostname"|] [] ; diff --git a/lib/socket.h b/lib/socket.h index 96fedeeb..642a56ce 100644 --- a/lib/socket.h +++ b/lib/socket.h @@ -84,6 +84,7 @@ typedef struct birdsock { sock *sock_new(pool *); /* Allocate new socket */ #define sk_new(X) sock_new(X) /* Wrapper to avoid name collision with OpenSSL */ +int sk_hostname_autoresolv(sock *); /* Auto-resolve an IP address from a hostname */ int sk_open(sock *); /* Open socket */ int sk_rx_ready(sock *s); int sk_send(sock *, uint len); /* Send data, <0=err, >0=ok, 0=sleep */ diff --git a/sysdep/unix/config.Y b/sysdep/unix/config.Y index 5c4b5bef..3871878a 100644 --- a/sysdep/unix/config.Y +++ b/sysdep/unix/config.Y @@ -17,7 +17,7 @@ static struct log_config *this_log; CF_DECLS -CF_KEYWORDS(LOG, SYSLOG, ALL, DEBUG, TRACE, INFO, REMOTE, WARNING, ERROR, AUTH, FATAL, BUG, STDERR, SOFT) +CF_KEYWORDS(LOG, SYSLOG, UDP, ALL, DEBUG, TRACE, INFO, REMOTE, WARNING, ERROR, AUTH, FATAL, BUG, STDERR, SOFT) CF_KEYWORDS(NAME, CONFIRM, UNDO, CHECK, TIMEOUT, DEBUG, LATENCY, LIMIT, WATCHDOG, WARNING, STATUS) CF_KEYWORDS(GRACEFUL, RESTART) @@ -61,8 +61,34 @@ log_file: } | SYSLOG syslog_name { this_log->fh = NULL; new_config->syslog_name = $2; } | STDERR { this_log->fh = stderr; } + | UDP log_udp_host log_udp_port { + sock *sk = sk_new(new_config->pool); + sk->type = SK_UDP; + sk->daddr = this_log->ip; + sk->host = this_log->host; + sk->dport = this_log->port; + sk->flags = SKF_THREAD; + + this_log->rf = rf_open_sk(new_config->pool, sk); + if (!this_log->rf) + cf_error("Unable to open udp log"); + this_log->fh = rf_file(this_log->rf); + this_log->pos = -1; + this_log->filename = NULL; + } ; +log_udp_host: + /* empty */ { this_log->ip = ipa_build4(127, 0, 0, 1); } + | ipa { this_log->ip = $1; } + | text { this_log->host = $1; } + ; + +log_udp_port: + /* empty */ { this_log->port = 514; } + | NUM { check_u16($1); this_log->port = $1; } + ; + log_mask: ALL { $$ = ~0; } | '{' log_mask_list '}' { $$ = $2; } diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 3d67d0a7..800a9dcf 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "nest/bird.h" #include "lib/lists.h" @@ -55,6 +56,7 @@ this to gen small latencies */ #define MAX_RX_STEPS 4 +static int sk_connect(sock *); /* * Tracked Files @@ -103,6 +105,27 @@ rf_open(pool *p, const char *name, const char *mode) return r; } +struct rfile * +rf_open_sk(pool *p, sock *s) +{ + if (sk_hostname_autoresolv(s) < 0) + return NULL; + if (sk_open(s) < 0) + return NULL; + if (sk_connect(s) < 0) + return NULL; + + FILE *f = fdopen(s->fd, "a"); + if (!f) + return NULL; + + struct rfile *r = ralloc(p, &rf_class); + r->f = f; + s->fd = -1; + + return r; +} + void * rf_file(struct rfile *f) { @@ -1309,6 +1332,40 @@ sk_open_ssh(sock *s) } #endif +/* + * Resolve the hostname in case IP is not defined. + */ +int +sk_hostname_autoresolv(sock *s) +{ + if (ipa_zero(s->daddr) && s->host) + { + struct addrinfo *res; + struct addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_socktype = (s->type == SK_UDP) ? SOCK_DGRAM : SOCK_STREAM, + .ai_flags = AI_ADDRCONFIG, + }; + + int err_code = getaddrinfo(s->host, NULL, &hints, &res); + if (err_code != 0) + { + log(L_ERR "Cannot resolve hostname '%s': %s", + s->host, gai_strerror(err_code)); + return -1; + } + + ip_addr addr = IPA_NONE; + uint unused; + sockaddr_read((sockaddr *) res->ai_addr, res->ai_family, &addr, NULL, &unused); + freeaddrinfo(res); + + s->daddr = addr; + } + + return 0; +} + /** * sk_open - open a socket * @s: socket @@ -1448,8 +1505,7 @@ sk_open(sock *s) switch (s->type) { case SK_TCP_ACTIVE: - sockaddr_fill(&sa, s->af, s->daddr, s->iface, s->dport); - if (connect(fd, &sa.sa, SA_LEN(sa)) >= 0) + if (sk_connect(s) >= 0) sk_tcp_connected(s); else if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS && errno != ECONNREFUSED && errno != EHOSTUNREACH && errno != ENETUNREACH) @@ -1512,6 +1568,13 @@ sk_open_unix(sock *s, char *name) return 0; } +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)); +} #define CMSG_RX_SPACE MAX(CMSG4_SPACE_PKTINFO+CMSG4_SPACE_TTL, \ CMSG6_SPACE_PKTINFO+CMSG6_SPACE_TTL) @@ -1920,10 +1983,7 @@ sk_write(sock *s) { case SK_TCP_ACTIVE: { - sockaddr sa; - sockaddr_fill(&sa, s->af, s->daddr, s->iface, s->dport); - - if (connect(s->fd, &sa.sa, SA_LEN(sa)) >= 0 || errno == EISCONN) + if (sk_connect(s) >= 0 || errno == EISCONN) sk_tcp_connected(s); else if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS) s->err_hook(s, errno); diff --git a/sysdep/unix/unix.h b/sysdep/unix/unix.h index ad85d1ea..34acb4cf 100644 --- a/sysdep/unix/unix.h +++ b/sysdep/unix/unix.h @@ -109,6 +109,7 @@ void io_loop(void); void io_log_dump(void); 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_sk(struct pool *, struct birdsock *); void *rf_file(struct rfile *f); int rf_fileno(struct rfile *f); void test_old_bird(char *path); @@ -133,6 +134,9 @@ struct log_config { off_t pos; /* Position/size of current log */ off_t limit; /* Log size limit */ int terminal_flag; + ip_addr ip; /* UDP log dst IP address */ + const char *host; /* UDP log dst host name */ + uint port; /* UDP log dst port */ }; #endif