X-Git-Url: https://git.proxmox.com/?p=pve-firewall.git;a=blobdiff_plain;f=src%2Fpvefw-logger.c;h=181d5f1e8b7520b008b7761943ce9d04f6e3b6cc;hp=3b79ed1ad08ea7fbd9fd01e5711a2ecc775e9c6b;hb=98bd53b6dc624a8d98e5e54bdf6c8d278a3c8e32;hpb=f275107a595aaf0a70d898f1a224831cd0b6f4a3 diff --git a/src/pvefw-logger.c b/src/pvefw-logger.c index 3b79ed1..181d5f1 100644 --- a/src/pvefw-logger.c +++ b/src/pvefw-logger.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -53,10 +54,12 @@ static struct nflog_handle *logh = NULL; static struct nlif_handle *nlifh = NULL; +static struct nfct_handle *nfcth = NULL; GMainLoop *main_loop; gboolean foreground = FALSE; gboolean debug = FALSE; +gboolean conntrack = FALSE; /* @@ -76,6 +79,7 @@ Example: #define LOCKFILE "/var/lock/pvefw-logger.lck" #define PIDFILE "/var/run/pvefw-logger.pid" +#define LOG_CONNTRACK_FILE "/var/lib/pve-firewall/log_nf_conntrack" #define LQ_LEN 512 #define LE_MAX (512 - 4) // try to fit into 512 bytes @@ -192,8 +196,7 @@ queue_log_entry(struct log_entry *le) static void log_status_message(guint loglevel, const char *fmt, ...) { - va_list ap; - va_start(ap, fmt); + va_list ap, ap2; if (loglevel > 7 ) loglevel = 7; // syslog defines level 0-7 @@ -203,7 +206,10 @@ log_status_message(guint loglevel, const char *fmt, ...) LEPRINTTIME(time(NULL)); + va_start(ap, fmt); + va_copy(ap2, ap); le->len += vsnprintf(le->buf + le->len, LE_MAX - le->len, fmt, ap); + va_end(ap); LEPRINTF("\n"); @@ -211,7 +217,8 @@ log_status_message(guint loglevel, const char *fmt, ...) // also log to syslog - vsyslog(loglevel, fmt, ap); + vsyslog(loglevel, fmt, ap2); + va_end(ap2); } static int @@ -568,6 +575,7 @@ print_nexthdr(struct log_entry *le, char *hdr, int payload_len, u_int8_t proto) return 0; struct ip6_ext *exthdr = (struct ip6_ext*)hdr; + int ext_len = 0; switch (proto) { /* protocols (these return) */ @@ -594,6 +602,7 @@ print_nexthdr(struct log_entry *le, char *hdr, int payload_len, u_int8_t proto) return -1; if (print_fragment(le, (struct ip6_frag*)hdr, payload_len) < 0) return -1; + ext_len = sizeof(struct ip6_frag); break; case IPPROTO_HOPOPTS: LEPRINTF("NEXTHDR=HOPOPTS "); @@ -621,8 +630,12 @@ print_nexthdr(struct log_entry *le, char *hdr, int payload_len, u_int8_t proto) /* next header: */ if (check_ip6ext(le, exthdr, payload_len) < 0) return -1; - hdr += exthdr->ip6e_len; - payload_len -= exthdr->ip6e_len; + if(ext_len == 0) { + ext_len = (exthdr->ip6e_len+1) * 8; + } + hdr += ext_len; + payload_len -= ext_len; + proto = exthdr->ip6e_nxt; } } @@ -753,9 +766,11 @@ static int print_pkt(struct log_entry *le, struct nflog_data *ldata, u_int8_t fa LEPRINTF("%s ", chain_name); struct timeval ts; - nflog_get_timestamp(ldata, &ts); - - LEPRINTTIME(ts.tv_sec); + if (nflog_get_timestamp(ldata, &ts) == 0) { + LEPRINTTIME(ts.tv_sec); + } else { + LEPRINTTIME(time(NULL)); + } if (prefix != NULL) { LEPRINTF("%s", prefix); @@ -915,6 +930,46 @@ signal_read_cb(GIOChannel *source, return TRUE; } +static int +nfct_cb(const struct nlmsghdr *nlh, + enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data) +{ + struct log_entry *le = g_new0(struct log_entry, 1); + int len = nfct_snprintf(&le->buf[le->len], LE_MAX - le->len, + ct, type, NFCT_O_DEFAULT, + NFCT_OF_SHOW_LAYER3|NFCT_OF_TIMESTAMP); + le->len += len; + + if (le->len == LE_MAX) { + le->buf[le->len-1] = '\n'; + } else { // le->len < LE_MAX + le->buf[le->len++] = '\n'; + } + + queue_log_entry(le); + + return NFCT_CB_STOP; +} + +static gboolean +nfct_read_cb(GIOChannel *source, + GIOCondition condition, + gpointer data) +{ + int res; + if ((res = nfct_catch(nfcth)) < 0) { + if (errno == ENOBUFS) { + log_status_message(3, "nfct_catch returned ENOBUFS: conntrack information may be incomplete"); + } else { + log_status_message(3, "error catching nfct: %s", strerror(errno)); + return FALSE; + } + } + return TRUE; +} + int main(int argc, char *argv[]) { @@ -923,13 +978,14 @@ main(int argc, char *argv[]) gboolean wrote_pidfile = FALSE; - openlog("pvepw-logger", LOG_CONS|LOG_PID, LOG_DAEMON); + openlog("pvefw-logger", LOG_CONS|LOG_PID, LOG_DAEMON); GOptionContext *context; GOptionEntry entries[] = { { "debug", 'd', 0, G_OPTION_ARG_NONE, &debug, "Turn on debug messages", NULL }, { "foreground", 'f', 0, G_OPTION_ARG_NONE, &foreground, "Do not daemonize server", NULL }, + { "conntrack", 0, 0, G_OPTION_ARG_NONE, &conntrack, "Add conntrack logging", NULL }, { NULL }, }; @@ -952,6 +1008,23 @@ main(int argc, char *argv[]) g_option_context_free(context); + if (!conntrack) { + int log_nf_conntrackfd = open(LOG_CONNTRACK_FILE, O_RDONLY); + if (log_nf_conntrackfd == -1) { + if (errno != ENOENT) { + fprintf(stderr, "error: failed to open "LOG_CONNTRACK_FILE": %s\n", strerror(errno)); + } + } else { + char c = '0'; + ssize_t bytes = read(log_nf_conntrackfd, &c, sizeof(c)); + if (bytes < 0) { + fprintf(stderr, "error: failed to read value in log_nf_conntrack: %s\n", strerror(errno)); + } else { + conntrack = (c == '1'); + } + } + } + if (debug) foreground = TRUE; if ((lockfd = open(LOCKFILE, O_RDWR|O_CREAT|O_APPEND, 0644)) == -1) { @@ -982,7 +1055,7 @@ main(int argc, char *argv[]) exit(-1); } - if (!nflog_bind_pf(logh, AF_INET) <= 0) { + if (nflog_bind_pf(logh, AF_INET) < 0) { fprintf(stderr, "nflog_bind_pf AF_INET failed\n"); exit(-1); } @@ -994,7 +1067,7 @@ main(int argc, char *argv[]) } #endif - if (!nflog_bind_pf(logh, AF_BRIDGE) <= 0) { + if (nflog_bind_pf(logh, AF_BRIDGE) < 0) { fprintf(stderr, "nflog_bind_pf AF_BRIDGE failed\n"); exit(-1); } @@ -1015,6 +1088,13 @@ main(int argc, char *argv[]) exit(-1); } + if (conntrack) { + if ((nfcth = nfct_open(CONNTRACK, NF_NETLINK_CONNTRACK_NEW|NF_NETLINK_CONNTRACK_DESTROY)) == NULL) { + fprintf(stderr, "unable to open netfilter conntrack\n"); + exit(-1); + } + } + sigset_t mask; sigemptyset(&mask); sigaddset(&mask, SIGINT); @@ -1074,6 +1154,13 @@ main(int argc, char *argv[]) g_io_add_watch(nflog_ch, G_IO_IN, nflog_read_cb, NULL); + if (conntrack) { + nfct_callback_register2(nfcth, NFCT_T_NEW|NFCT_T_DESTROY, &nfct_cb, NULL); + int nfctfd = nfct_fd(nfcth); + GIOChannel *nfct_ch = g_io_channel_unix_new(nfctfd); + g_io_add_watch(nfct_ch, G_IO_IN, nfct_read_cb, NULL); + } + GIOChannel *sig_ch = g_io_channel_unix_new(sigfd); if (!g_io_add_watch(sig_ch, G_IO_IN, signal_read_cb, NULL)) { exit(-1); @@ -1091,6 +1178,11 @@ main(int argc, char *argv[]) close(outfd); + if (conntrack) { + nfct_callback_unregister2(nfcth); + nfct_close(nfcth); + } + nflog_close(logh); if (wrote_pidfile)