]> git.ipfire.org Git - thirdparty/ulogd2.git/commitdiff
nfct: implement src and dst filter
authorEric Leblond <eric@regit.org>
Mon, 16 Jul 2012 21:03:39 +0000 (23:03 +0200)
committerEric Leblond <eric@regit.org>
Sat, 5 Jan 2013 09:55:08 +0000 (10:55 +0100)
This patch implements two filtering options in NFCT input plugin.
If 'accept_src_filter' is set to a network it will only catch the
event where the source is that specific network. 'accept_dst_filter'
does the same for the destination.

input/flow/ulogd_inpflow_NFCT.c
ulogd.conf.in

index 489c9e02b0a3553a468997d5e665a9b6de4ddd2a..b3e48d79a46eaa9b6acbb3e3a79aa783a0013998 100644 (file)
@@ -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);
index 6aff802ff9c74c11e4e64629137733deba18c5bd..fa1fbf2bf3f20a372e09cd06a624e83f1fe689fd 100644 (file)
@@ -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