summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--input/flow/ulogd_inpflow_NFCT.c216
-rw-r--r--ulogd.conf.in4
2 files changed, 218 insertions, 2 deletions
diff --git a/input/flow/ulogd_inpflow_NFCT.c b/input/flow/ulogd_inpflow_NFCT.c
index 489c9e0..b3e48d7 100644
--- a/input/flow/ulogd_inpflow_NFCT.c
+++ b/input/flow/ulogd_inpflow_NFCT.c
@@ -43,6 +43,7 @@
#include <ulogd/ulogd.h>
#include <ulogd/timer.h>
#include <ulogd/ipfix_protocol.h>
+#include <ulogd/addr.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
@@ -72,7 +73,7 @@ struct nfct_pluginstance {
#define EVENT_MASK NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY
static struct config_keyset nfct_kset = {
- .num_ces = 9,
+ .num_ces = 11,
.ces = {
{
.key = "pollinterval",
@@ -128,6 +129,16 @@ static struct config_keyset nfct_kset = {
.options = CONFIG_OPT_NONE,
.u.value = 0,
},
+ {
+ .key = "accept_src_filter",
+ .type = CONFIG_TYPE_STRING,
+ .options = CONFIG_OPT_NONE,
+ },
+ {
+ .key = "accept_dst_filter",
+ .type = CONFIG_TYPE_STRING,
+ .options = CONFIG_OPT_NONE,
+ },
},
};
#define pollint_ce(x) (x->ces[0])
@@ -139,6 +150,8 @@ static struct config_keyset nfct_kset = {
#define nlsockbufmaxsize_ce(x) (x->ces[6])
#define nlresynctimeout_ce(x) (x->ces[7])
#define reliable_ce(x) (x->ces[8])
+#define src_filter_ce(x) ((x)->ces[9])
+#define dst_filter_ce(x) ((x)->ces[10])
enum nfct_keys {
NFCT_ORIG_IP_SADDR = 0,
@@ -993,11 +1006,200 @@ static void overrun_timeout(struct ulogd_timer *a, void *data)
nfct_send(cpi->ovh, NFCT_Q_DUMP, &family);
}
+
+#define NFCT_SRC_DIR 1
+#define NFCT_DST_DIR 2
+
+static inline int nfct_set_dir(int dir, int *filter_dir_ipv4, int *filter_dir_ipv6)
+{
+ switch (dir) {
+ case NFCT_DST_DIR:
+ *filter_dir_ipv4 = NFCT_FILTER_DST_IPV4;
+ *filter_dir_ipv6 = NFCT_FILTER_DST_IPV6;
+ break;
+ case NFCT_SRC_DIR:
+ *filter_dir_ipv4 = NFCT_FILTER_SRC_IPV4;
+ *filter_dir_ipv6 = NFCT_FILTER_SRC_IPV6;
+ break;
+ default:
+ ulogd_log(ULOGD_FATAL,
+ "Invalid direction %d\n",
+ dir);
+ return -1;
+ }
+ return 0;
+}
+
+static int nfct_add_to_filter(struct nfct_filter *filter,
+ struct ulogd_addr *addr,
+ int l3, int dir)
+{
+ int filter_dir_ipv4;
+ int filter_dir_ipv6;
+
+ if (nfct_set_dir(dir, &filter_dir_ipv4, &filter_dir_ipv6) == -1)
+ return -1;
+
+ switch (l3) {
+ case AF_INET6:
+ {
+ struct nfct_filter_ipv6 filter_ipv6;
+ /* BSF always wants data in host-byte order */
+ ulogd_ipv6_addr2addr_host(addr->in.ipv6, filter_ipv6.addr);
+ ulogd_ipv6_cidr2mask_host(addr->netmask, filter_ipv6.mask);
+
+ nfct_filter_set_logic(filter,
+ filter_dir_ipv6,
+ NFCT_FILTER_LOGIC_POSITIVE);
+ nfct_filter_add_attr(filter,
+ filter_dir_ipv6,
+ &filter_ipv6);
+ }
+ break;
+ case AF_INET:
+ {
+ /* BSF always wants data in host-byte order */
+ struct nfct_filter_ipv4 filter_ipv4 = {
+ .addr = ntohl(addr->in.ipv4),
+ .mask = ulogd_bits2netmask(addr->netmask),
+ };
+
+ nfct_filter_set_logic(filter,
+ filter_dir_ipv4,
+ NFCT_FILTER_LOGIC_POSITIVE);
+ nfct_filter_add_attr(filter, filter_dir_ipv4,
+ &filter_ipv4);
+ }
+ break;
+ default:
+ ulogd_log(ULOGD_FATAL, "Invalid protocol %d\n", l3);
+ return -1;
+ }
+ return 0;
+}
+
+static int build_nfct_filter_dir(struct nfct_filter *filter, char* filter_string, int dir)
+{
+ char *from = filter_string;
+ char *comma;
+ struct ulogd_addr addr;
+ int has_ipv4 = 0;
+ int has_ipv6 = 0;
+
+ while ((comma = strchr(from, ',')) != NULL) {
+ size_t len = comma - from;
+ switch(ulogd_parse_addr(from, len, &addr)) {
+ case AF_INET:
+ nfct_add_to_filter(filter, &addr, AF_INET, dir);
+ has_ipv4 = 1;
+ break;
+ case AF_INET6:
+ nfct_add_to_filter(filter, &addr, AF_INET6, dir);
+ has_ipv6 = 1;
+ break;
+ default:
+ return -1;
+ }
+ from += len + 1;
+ }
+ switch(ulogd_parse_addr(from, strlen(from), &addr)) {
+ case AF_INET:
+ nfct_add_to_filter(filter, &addr, AF_INET, dir);
+ has_ipv4 = 1;
+ break;
+ case AF_INET6:
+ nfct_add_to_filter(filter, &addr, AF_INET6, dir);
+ has_ipv6 = 1;
+ break;
+ default:
+ return -1;
+ }
+
+ if (!has_ipv6) {
+ struct nfct_filter_ipv6 filter_ipv6;
+ int filter_dir_ipv4;
+ int filter_dir_ipv6;
+ if (nfct_set_dir(dir, &filter_dir_ipv4, &filter_dir_ipv6) == -1)
+ return -1;
+ nfct_filter_set_logic(filter,
+ filter_dir_ipv6,
+ NFCT_FILTER_LOGIC_NEGATIVE);
+ nfct_filter_add_attr(filter, filter_dir_ipv6,
+ &filter_ipv6);
+ }
+ if (!has_ipv4) {
+ struct nfct_filter_ipv4 filter_ipv4;
+ int filter_dir_ipv4;
+ int filter_dir_ipv6;
+ if (nfct_set_dir(dir, &filter_dir_ipv4, &filter_dir_ipv6) == -1)
+ return -1;
+ nfct_filter_set_logic(filter,
+ filter_dir_ipv4,
+ NFCT_FILTER_LOGIC_NEGATIVE);
+ nfct_filter_add_attr(filter, filter_dir_ipv4,
+ &filter_ipv4);
+ }
+
+ return 0;
+}
+
+static int build_nfct_filter(struct ulogd_pluginstance *upi)
+{
+ struct nfct_pluginstance *cpi =
+ (struct nfct_pluginstance *)upi->private;
+ struct nfct_filter *filter = NULL;
+
+ if (!cpi->cth) {
+ ulogd_log(ULOGD_FATAL, "Refusing to attach NFCT filter to NULL handler\n");
+ goto err_init;
+ }
+
+ filter = nfct_filter_create();
+ if (!filter) {
+ ulogd_log(ULOGD_FATAL, "error creating NFCT filter\n");
+ goto err_init;
+ }
+
+ if (strlen(src_filter_ce(upi->config_kset).u.string) != 0) {
+ char *filter_string = src_filter_ce(upi->config_kset).u.string;
+ if (build_nfct_filter_dir(filter, filter_string, NFCT_SRC_DIR) != 0) {
+ ulogd_log(ULOGD_FATAL,
+ "Unable to create src filter\n");
+ goto err_filter;
+ }
+ }
+ if (strlen(dst_filter_ce(upi->config_kset).u.string) != 0) {
+ char *filter_string = dst_filter_ce(upi->config_kset).u.string;
+ if (build_nfct_filter_dir(filter, filter_string, NFCT_DST_DIR) != 0) {
+ ulogd_log(ULOGD_FATAL,
+ "Unable to create dst filter\n");
+ goto err_filter;
+ }
+ }
+
+ if (filter) {
+ if (nfct_filter_attach(nfct_fd(cpi->cth), filter) == -1) {
+ ulogd_log(ULOGD_FATAL, "nfct_filter_attach");
+ }
+
+ /* release the filter object, this does not detach the filter */
+ nfct_filter_destroy(filter);
+ }
+
+ return 0;
+
+err_filter:
+ nfct_filter_destroy(filter);
+err_init:
+ return -1;
+}
+
static int constructor_nfct_events(struct ulogd_pluginstance *upi)
{
struct nfct_pluginstance *cpi =
(struct nfct_pluginstance *)upi->private;
+
cpi->cth = nfct_open(NFNL_SUBSYS_CTNETLINK,
eventmask_ce(upi->config_kset).u.value);
if (!cpi->cth) {
@@ -1005,9 +1207,19 @@ static int constructor_nfct_events(struct ulogd_pluginstance *upi)
goto err_cth;
}
+ if ((strlen(src_filter_ce(upi->config_kset).u.string) != 0) ||
+ (strlen(dst_filter_ce(upi->config_kset).u.string) != 0)
+ ) {
+ if (build_nfct_filter(upi) != 0) {
+ ulogd_log(ULOGD_FATAL, "error creating NFCT filter\n");
+ goto err_cth;
+ }
+ }
+
+
if (usehash_ce(upi->config_kset).u.value != 0) {
nfct_callback_register(cpi->cth, NFCT_T_ALL,
- &event_handler_hashtable, upi);
+ &event_handler_hashtable, upi);
} else {
nfct_callback_register(cpi->cth, NFCT_T_ALL,
&event_handler_no_hashtable, upi);
diff --git a/ulogd.conf.in b/ulogd.conf.in
index 6aff802..fa1fbf2 100644
--- a/ulogd.conf.in
+++ b/ulogd.conf.in
@@ -125,6 +125,10 @@ plugin="@pkglibdir@/ulogd_output_GRAPHITE.so"
#netlink_socket_buffer_maxsize=1085440
#netlink_resync_timeout=60 # seconds to wait to perform resynchronization
#pollinterval=10 # use poll-based logging instead of event-driven
+# If pollinterval is not set, NFCT plugin will work in event mode
+# In this case, you can use the following filters on events:
+#accept_src_filter=192.168.1.0/24,1:2::/64 # source ip of connection must belong to these networks
+#accept_dst_filter=192.168.1.0/24 # destination ip of connection must belong to these networks
[ct2]
#netlink_socket_buffer_size=217088