Discussion:
[pve-devel] [PATCH v2 firewall 0/2] firewall conntrack logging
David Limbeck
2018-12-07 14:08:19 UTC
Permalink
Adds optional conntrack logging. pvefw-logger is restarted whenever the
config changes.

To enable conntrack logging set 'log_nf_conntrack: 1' in
/etc/pve/nodes/{node}/host.fw
To enable timestamps (start and end time in [DESTROY] messages) set
/proc/sys/net/netfilter/nf_conntrack_timestamp to 1


David Limbeck (2):
add conntrack logging via libnetfilter_conntrack
add log_nf_conntrack host firewall option

debian/control | 1 +
src/Makefile | 2 +-
src/PVE/Firewall.pm | 19 +++++++++++++-
src/pvefw-logger.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 95 insertions(+), 2 deletions(-)
--
2.11.0
David Limbeck
2018-12-07 14:08:21 UTC
Permalink
add log_nf_conntrack host firewall option to enable or disable logging
of connections. restarts pvefw-logger if the option changes in the
config. the pvefw-logger is always restarted in the beginning to make
sure the current config is applied.

Signed-off-by: David Limbeck <***@proxmox.com>
---
src/PVE/Firewall.pm | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/src/PVE/Firewall.pm b/src/PVE/Firewall.pm
index db1eae3..d9d8e26 100644
--- a/src/PVE/Firewall.pm
+++ b/src/PVE/Firewall.pm
@@ -2638,7 +2638,7 @@ sub parse_hostfw_option {

my $loglevels = "emerg|alert|crit|err|warning|notice|info|debug|nolog";

- if ($line =~ m/^(enable|nosmurfs|tcpflags|ndp):\s*(0|1)\s*$/i) {
+ if ($line =~ m/^(enable|nosmurfs|tcpflags|ndp|log_nf_conntrack):\s*(0|1)\s*$/i) {
$opt = lc($1);
$value = int($2);
} elsif ($line =~ m/^(log_level_in|log_level_out|tcp_flags_log_level|smurf_log_level):\s*(($loglevels)\s*)?$/i) {
@@ -4069,6 +4069,7 @@ sub apply_ruleset {

update_nf_conntrack_tcp_timeout_established($hostfw_conf);

+ update_nf_conntrack_logging($hostfw_conf);
}

sub update_nf_conntrack_max {
@@ -4105,6 +4106,22 @@ sub update_nf_conntrack_tcp_timeout_established {
PVE::ProcFSTools::write_proc_entry("/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established", $value);
}

+my $log_nf_conntrack_enabled = undef;
+sub update_nf_conntrack_logging {
+ my ($hostfw_conf) = @_;
+
+ my $options = $hostfw_conf->{options} || {};
+ my $value = $options->{log_nf_conntrack} || 0;
+ if (!defined($log_nf_conntrack_enabled)
+ || $value != $log_nf_conntrack_enabled) {
+ my $tmpfile = "$pve_fw_status_dir/log_nf_conntrack";
+ PVE::Tools::file_set_contents($tmpfile, $value);
+
+ PVE::Tools::run_command(['systemctl restart pvefw-logger.service']);
+ $log_nf_conntrack_enabled = $value;
+ }
+}
+
sub remove_pvefw_chains {

PVE::Firewall::remove_pvefw_chains_iptables("iptables");
--
2.11.0
David Limbeck
2018-12-07 14:08:20 UTC
Permalink
add conntrack logging to pvefw-logger including timestamps (requires
/proc/sys/net/netfilter/nf_conntrack_timestamp to be 1).
this allows the tracking of sessions (start, end timestamps with
nf_conntrack_timestamp on [DESTROY] messages). commit includes
Build-Depends inclusion of libnetfilter-conntrack-dev and
libnetfilter_conntrack library in the Makefile.
conntrack can also be enabled by passing --contrack on the command line.

Signed-off-by: David Limbeck <***@proxmox.com>
---
debian/control | 1 +
src/Makefile | 2 +-
src/pvefw-logger.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 77 insertions(+), 1 deletion(-)

diff --git a/debian/control b/debian/control
index a68a81c..2a92b16 100644
--- a/debian/control
+++ b/debian/control
@@ -5,6 +5,7 @@ Maintainer: Proxmox Support Team <***@proxmox.com>
Build-Depends: debhelper (>= 7.0.50~),
dh-systemd,
libglib2.0-dev,
+ libnetfilter-conntrack-dev,
libnetfilter-log-dev,
libpve-common-perl,
pve-cluster,
diff --git a/src/Makefile b/src/Makefile
index ed74393..a35e53d 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -25,7 +25,7 @@ LDFLAGS:=$(shell dpkg-buildflags --get LDFLAGS)
pvefw-logger: pvefw-logger.c
gcc -Wall -Werror pvefw-logger.c -o pvefw-logger -std=gnu99 \
$(CPPFLAGS) $(CFLAGS) $(LDFLAGS) \
- $(shell pkg-config libnetfilter_log glib-2.0 --libs --cflags)
+ $(shell pkg-config libnetfilter_log libnetfilter_conntrack glib-2.0 --libs --cflags)

.PHONY: install
install: pve-firewall pve-firewall.8 pve-firewall.bash-completion pvefw-logger
diff --git a/src/pvefw-logger.c b/src/pvefw-logger.c
index 2bd869c..bea7e5a 100644
--- a/src/pvefw-logger.c
+++ b/src/pvefw-logger.c
@@ -40,6 +40,7 @@
#include <linux/netlink.h>
#include <libnfnetlink/libnfnetlink.h>
#include <libnetfilter_log/libnetfilter_log.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/ip6.h>
@@ -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;

/*

@@ -917,6 +920,42 @@ 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) {
+ log_status_message(3, "error catching nfct");
+ return FALSE;
+ }
+ return TRUE;
+}
+
int
main(int argc, char *argv[])
{
@@ -932,6 +971,7 @@ main(int argc, char *argv[])
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 },
};

@@ -954,6 +994,22 @@ main(int argc, char *argv[])

g_option_context_free(context);

+ if (!conntrack) {
+ int log_nf_conntrackfd = open("/var/lib/pve-firewall/log_nf_conntrack", O_RDONLY);
+ if (log_nf_conntrackfd == -1) {
+ fprintf(stderr, "error: failed to open /var/lib/pve-firewall/log_nf_conntrack: %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 {
+ // should be either '0' or '1' so subtract '0' for either 0 or 1
+ conntrack = c-'0';
+ }
+ }
+ }
+
if (debug) foreground = TRUE;

if ((lockfd = open(LOCKFILE, O_RDWR|O_CREAT|O_APPEND, 0644)) == -1) {
@@ -1017,6 +1073,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);
@@ -1076,6 +1139,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);
@@ -1093,6 +1163,11 @@ main(int argc, char *argv[])

close(outfd);

+ if (conntrack) {
+ nfct_callback_unregister2(nfcth);
+ nfct_close(nfcth);
+ }
+
nflog_close(logh);

if (wrote_pidfile)
--
2.11.0
Loading...