]> git.ipfire.org Git - thirdparty/libnftnl.git/commitdiff
set: complete support
authorPablo Neira Ayuso <pablo@netfilter.org>
Sat, 2 Feb 2013 10:38:46 +0000 (11:38 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Sun, 3 Feb 2013 19:31:53 +0000 (20:31 +0100)
Including examples.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
examples/Makefile.am
examples/nft-set-add.c [new file with mode: 0644]
examples/nft-set-del.c [new file with mode: 0644]
examples/nft-set-get.c [new file with mode: 0644]
include/libnftables/set.h
src/set.c

index aee95df43bbe79a98c5a4a8ad15e6929c4ff63fe..d239196a0785219e155752e750f929fb2ddfd678 100644 (file)
@@ -11,6 +11,9 @@ check_PROGRAMS = nft-table-add                \
                 nft-rule-del           \
                 nft-rule-get           \
                 nft-events             \
+                nft-set-add            \
+                nft-set-get            \
+                nft-set-del            \
                 nft-compat-get
 
 nft_table_add_SOURCES = nft-table-add.c
@@ -46,5 +49,14 @@ nft_rule_get_LDADD = ../src/libnftables.la ${LIBMNL_LIBS}
 nft_events_SOURCES = nft-events.c
 nft_events_LDADD = ../src/libnftables.la ${LIBMNL_LIBS}
 
+nft_set_add_SOURCES = nft-set-add.c
+nft_set_add_LDADD = ../src/libnftables.la ${LIBMNL_LIBS}
+
+nft_set_del_SOURCES = nft-set-del.c
+nft_set_del_LDADD = ../src/libnftables.la ${LIBMNL_LIBS}
+
+nft_set_get_SOURCES = nft-set-get.c
+nft_set_get_LDADD = ../src/libnftables.la ${LIBMNL_LIBS}
+
 nft_compat_get_SOURCES = nft-compat-get.c
 nft_compat_get_LDADD = ../src/libnftables.la ${LIBMNL_LIBS}
diff --git a/examples/nft-set-add.c b/examples/nft-set-add.c
new file mode 100644 (file)
index 0000000..afc37c5
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * (C) 2013 by Pablo Neira Ayuso <pablo@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software has been sponsored by Sophos Astaro <http://www.sophos.com>
+ */
+
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#include <linux/netfilter/nf_tables.h>
+
+#include <libmnl/libmnl.h>
+#include <libnftables/table.h>
+#include <libnftables/set.h>
+
+int main(int argc, char *argv[])
+{
+       struct mnl_socket *nl;
+       char buf[MNL_SOCKET_BUFFER_SIZE];
+       struct nlmsghdr *nlh;
+       uint32_t portid, seq, family;
+       struct nft_set *t = NULL;
+       int ret;
+
+       if (argc != 4) {
+               fprintf(stderr, "%s <family> <table> <set>\n", argv[0]);
+               exit(EXIT_FAILURE);
+       }
+
+       t = nft_set_alloc();
+       if (t == NULL) {
+               perror("OOM");
+               exit(EXIT_FAILURE);
+       }
+
+       seq = time(NULL);
+       if (strcmp(argv[1], "ip") == 0)
+               family = AF_INET;
+       else if (strcmp(argv[1], "ip6") == 0)
+               family = AF_INET6;
+       else if (strcmp(argv[1], "bridge") == 0)
+               family = AF_BRIDGE;
+       else {
+               fprintf(stderr, "Unknown family: ip, ip6, bridge\n");
+               exit(EXIT_FAILURE);
+       }
+
+       nft_set_attr_set(t, NFT_SET_ATTR_TABLE, argv[2]);
+       nft_set_attr_set(t, NFT_SET_ATTR_NAME, argv[3]);
+       /* destroy set when the rule is destroyed, elements canno change */
+       nft_set_attr_set_u32(t, NFT_SET_ATTR_FLAGS, NFT_SET_ANONYMOUS |
+                                                   NFT_SET_CONSTANT);
+       /* This key is only used by user-space to interpret key type */
+       nft_set_attr_set_u32(t, NFT_SET_ATTR_KEY_TYPE, 0);
+       /* key is 4 bytes long */
+       nft_set_attr_set_u32(t, NFT_SET_ATTR_KEY_LEN, 4);
+       /*
+        * data type and data length only useful for mapping (1:1):
+        * matching -> action.
+        *
+        * This data is only used by user-space to interpret data type.
+        */
+       // nft_set_attr_set_u32(t, NFT_SET_ATTR_DATA_TYPE, NFT_DATA_VERDICT);
+       // nft_set_attr_set_u32(t, NFT_SET_ATTR_DATA_LEN, 4);
+
+       nlh = nft_set_nlmsg_build_hdr(buf, NFT_MSG_NEWSET, family,
+                                     NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK, seq);
+       nft_set_nlmsg_build_payload(nlh, t);
+       nft_set_free(t);
+
+       nl = mnl_socket_open(NETLINK_NETFILTER);
+       if (nl == NULL) {
+               perror("mnl_socket_open");
+               exit(EXIT_FAILURE);
+       }
+
+       if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
+               perror("mnl_socket_bind");
+               exit(EXIT_FAILURE);
+       }
+       portid = mnl_socket_get_portid(nl);
+
+       if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
+               perror("mnl_socket_send");
+               exit(EXIT_FAILURE);
+       }
+
+       ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+       while (ret > 0) {
+               ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL);
+               if (ret <= 0)
+                       break;
+               ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+       }
+       if (ret == -1) {
+               perror("error");
+               exit(EXIT_FAILURE);
+       }
+       mnl_socket_close(nl);
+
+       return EXIT_SUCCESS;
+}
diff --git a/examples/nft-set-del.c b/examples/nft-set-del.c
new file mode 100644 (file)
index 0000000..aebc018
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software has been sponsored by Sophos Astaro <http://www.sophos.com>
+ */
+
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#include <linux/netfilter/nf_tables.h>
+
+#include <libmnl/libmnl.h>
+#include <libnftables/set.h>
+
+int main(int argc, char *argv[])
+{
+       struct mnl_socket *nl;
+       char buf[MNL_SOCKET_BUFFER_SIZE];
+       struct nlmsghdr *nlh;
+       uint32_t portid, seq, family;
+       struct nft_set *t = NULL;
+       int ret;
+
+       if (argc != 4) {
+               fprintf(stderr, "%s <family> <table> <set>\n", argv[0]);
+               exit(EXIT_FAILURE);
+       }
+
+       t = nft_set_alloc();
+       if (t == NULL) {
+               perror("OOM");
+               exit(EXIT_FAILURE);
+       }
+
+       seq = time(NULL);
+       if (strcmp(argv[1], "ip") == 0)
+               family = AF_INET;
+       else if (strcmp(argv[1], "ip6") == 0)
+               family = AF_INET6;
+       else if (strcmp(argv[1], "bridge") == 0)
+               family = AF_BRIDGE;
+       else {
+               fprintf(stderr, "Unknown family: ip, ip6, bridge\n");
+               exit(EXIT_FAILURE);
+       }
+
+       nlh = nft_set_nlmsg_build_hdr(buf, NFT_MSG_DELSET, family,
+                                       NLM_F_ACK, seq);
+       nft_set_attr_set(t, NFT_SET_ATTR_TABLE, argv[2]);
+       nft_set_attr_set(t, NFT_SET_ATTR_NAME, argv[3]);
+
+       nft_set_nlmsg_build_payload(nlh, t);
+       nft_set_free(t);
+
+       nl = mnl_socket_open(NETLINK_NETFILTER);
+       if (nl == NULL) {
+               perror("mnl_socket_open");
+               exit(EXIT_FAILURE);
+       }
+
+       if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
+               perror("mnl_socket_bind");
+               exit(EXIT_FAILURE);
+       }
+       portid = mnl_socket_get_portid(nl);
+
+       if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
+               perror("mnl_socket_send");
+               exit(EXIT_FAILURE);
+       }
+
+       ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+       while (ret > 0) {
+               ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL);
+               if (ret <= 0)
+                       break;
+               ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+       }
+       if (ret == -1) {
+               perror("error");
+               exit(EXIT_FAILURE);
+       }
+       mnl_socket_close(nl);
+
+       return EXIT_SUCCESS;
+}
diff --git a/examples/nft-set-get.c b/examples/nft-set-get.c
new file mode 100644 (file)
index 0000000..a07a1d7
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software has been sponsored by Sophos Astaro <http://www.sophos.com>
+ */
+
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#include <linux/netfilter/nf_tables.h>
+
+#include <libmnl/libmnl.h>
+#include <libnftables/set.h>
+
+static int set_cb(const struct nlmsghdr *nlh, void *data)
+{
+       struct nft_set *t;
+       char buf[4096];
+
+       t = nft_set_alloc();
+       if (t == NULL) {
+               perror("OOM");
+               goto err;
+       }
+
+       if (nft_set_nlmsg_parse(nlh, t) < 0) {
+               perror("nft_set_nlmsg_parse");
+               goto err_free;
+       }
+
+       nft_set_snprintf(buf, sizeof(buf), t, 0, 0);
+       printf("%s", buf);
+
+err_free:
+       nft_set_free(t);
+err:
+       return MNL_CB_OK;
+}
+
+int main(int argc, char *argv[])
+{
+       struct mnl_socket *nl;
+       char buf[MNL_SOCKET_BUFFER_SIZE];
+       struct nlmsghdr *nlh;
+       uint32_t portid, seq, family;
+       struct nft_set *t = NULL;
+       int ret;
+
+       if (argc != 3) {
+               fprintf(stderr, "%s <family> <table>\n", argv[0]);
+               return EXIT_FAILURE;
+       }
+       t = nft_set_alloc();
+       if (t == NULL) {
+               perror("OOM");
+               exit(EXIT_FAILURE);
+       }
+       seq = time(NULL);
+       if (strcmp(argv[1], "ip") == 0)
+               family = AF_INET;
+       else if (strcmp(argv[1], "ip6") == 0)
+               family = AF_INET6;
+       else if (strcmp(argv[2], "bridge") == 0)
+               family = AF_BRIDGE;
+       else {
+               fprintf(stderr, "Unknown family: ip, ip6, bridge\n");
+               exit(EXIT_FAILURE);
+       }
+
+       nlh = nft_set_nlmsg_build_hdr(buf, NFT_MSG_GETSET, family,
+                                       NLM_F_DUMP|NLM_F_ACK, seq);
+       nft_set_attr_set(t, NFT_SET_ATTR_TABLE, argv[2]);
+       nft_set_nlmsg_build_payload(nlh, t);
+       nft_set_free(t);
+
+       nl = mnl_socket_open(NETLINK_NETFILTER);
+       if (nl == NULL) {
+               perror("mnl_socket_open");
+               exit(EXIT_FAILURE);
+       }
+
+       if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
+               perror("mnl_socket_bind");
+               exit(EXIT_FAILURE);
+       }
+       portid = mnl_socket_get_portid(nl);
+
+       if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
+               perror("mnl_socket_send");
+               exit(EXIT_FAILURE);
+       }
+
+       ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+       while (ret > 0) {
+               ret = mnl_cb_run(buf, ret, seq, portid, set_cb, NULL);
+               if (ret <= 0)
+                       break;
+               ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+       }
+       if (ret == -1) {
+               perror("error");
+               exit(EXIT_FAILURE);
+       }
+       mnl_socket_close(nl);
+
+       return EXIT_SUCCESS;
+}
index 00bf80620bcc649da48bf3f0610069e17d2590ed..e56fb500cc71c06c5982a75bbcbf59b3c6dc79cb 100644 (file)
@@ -7,8 +7,8 @@ enum {
        NFT_SET_ATTR_FLAGS,
        NFT_SET_ATTR_KEY_TYPE,
        NFT_SET_ATTR_KEY_LEN,
-       NFT_SET_ATTR_VERDICT,
-       NFT_SET_ATTR_CHAIN,
+       NFT_SET_ATTR_DATA_TYPE,
+       NFT_SET_ATTR_DATA_LEN,
 };
 
 struct nft_set;
index 29d359ec9be123877e409237c3727844d36b13eb..54cc55d7ea9dd7c28072c8c29a5be3a23b2f0ee2 100644 (file)
--- a/src/set.c
+++ b/src/set.c
@@ -1,5 +1,5 @@
 /*
- * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
+ * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published
 struct nft_set {
        struct list_head        head;
 
-       uint32_t                flags;
+       uint32_t                set_flags;
        char                    *table;
        char                    *name;
        uint32_t                key_type;
        size_t                  key_len;
-       union nft_data_reg      data;
-       uint32_t                attr_flags;
+       uint32_t                data_type;
+       size_t                  data_len;
+
+       uint32_t                flags;
 };
 
 struct nft_set *nft_set_alloc(void)
@@ -77,7 +79,7 @@ void nft_set_attr_set(struct nft_set *s, uint16_t attr, void *data)
                s->name = strdup(data);
                break;
        case NFT_SET_ATTR_FLAGS:
-               s->flags = *((uint32_t *)data);
+               s->set_flags = *((uint32_t *)data);
                break;
        case NFT_SET_ATTR_KEY_TYPE:
                s->key_type = *((uint32_t *)data);
@@ -85,15 +87,6 @@ void nft_set_attr_set(struct nft_set *s, uint16_t attr, void *data)
        case NFT_SET_ATTR_KEY_LEN:
                s->key_len = *((uint32_t *)data);
                break;
-       case NFT_SET_ATTR_VERDICT:
-               s->data.verdict = *((uint32_t *)data);
-               break;
-       case NFT_SET_ATTR_CHAIN:
-               if (s->data.chain)
-                       free(s->data.chain);
-
-               s->data.chain = strdup(data);
-               break;
        default:
                return;
        }
@@ -136,13 +129,13 @@ void *nft_set_attr_get(struct nft_set *s, uint16_t attr)
                if (s->flags & (1 << NFT_SET_ATTR_KEY_LEN))
                        return &s->key_len;
                break;
-       case NFT_SET_ATTR_VERDICT:
-               if (s->flags & (1 << NFT_SET_ATTR_VERDICT))
-                       return &s->data.verdict;
+       case NFT_SET_ATTR_DATA_TYPE:
+               if (s->flags & (1 << NFT_SET_ATTR_DATA_TYPE))
+                       return &s->data_type;
                break;
-       case NFT_SET_ATTR_CHAIN:
-               if (s->flags & (1 << NFT_SET_ATTR_CHAIN))
-                       return &s->data.chain;
+       case NFT_SET_ATTR_DATA_LEN:
+               if (s->flags & (1 << NFT_SET_ATTR_DATA_LEN))
+                       return &s->data_len;
                break;
        default:
                break;
@@ -191,22 +184,17 @@ void nft_set_nlmsg_build_payload(struct nlmsghdr *nlh, struct nft_set *s)
                mnl_attr_put_strz(nlh, NFTA_SET_TABLE, s->table);
        if (s->flags & (1 << NFT_SET_ATTR_NAME))
                mnl_attr_put_strz(nlh, NFTA_SET_NAME, s->name);
+       if (s->flags & (1 << NFT_SET_ATTR_FLAGS))
+               mnl_attr_put_u32(nlh, NFTA_SET_FLAGS, htonl(s->set_flags));
        if (s->flags & (1 << NFT_SET_ATTR_KEY_TYPE))
                mnl_attr_put_u32(nlh, NFTA_SET_KEY_TYPE, htonl(s->key_type));
        if (s->flags & (1 << NFT_SET_ATTR_KEY_LEN))
                mnl_attr_put_u32(nlh, NFTA_SET_KEY_LEN, htonl(s->key_len));
-       if (s->flags & (1 << NFT_SET_ATTR_VERDICT)) {
-               struct nlattr *nest1, *nest2;
-
-               nest1 = mnl_attr_nest_start(nlh, NFTA_SET_DATA_TYPE);
-               nest2 = mnl_attr_nest_start(nlh, NFTA_DATA_VERDICT);
-               mnl_attr_put_u32(nlh, NFTA_VERDICT_CODE, htonl(s->data.verdict));
-               if (s->flags & (1 << NFT_SET_ATTR_CHAIN))
-                       mnl_attr_put_strz(nlh, NFTA_VERDICT_CHAIN, s->data.chain);
-
-               mnl_attr_nest_end(nlh, nest1);
-               mnl_attr_nest_end(nlh, nest2);
-       }
+       /* These are only used to map matching -> action (1:1) */
+       if (s->flags & (1 << NFT_SET_ATTR_DATA_TYPE))
+               mnl_attr_put_u32(nlh, NFTA_SET_DATA_TYPE, htonl(s->data_type));
+       if (s->flags & (1 << NFT_SET_ATTR_DATA_LEN))
+               mnl_attr_put_u32(nlh, NFTA_SET_DATA_LEN, htonl(s->data_len));
 }
 EXPORT_SYMBOL(nft_set_nlmsg_build_payload);
 
@@ -226,15 +214,12 @@ static int nft_set_parse_attr_cb(const struct nlattr *attr, void *data)
                        return MNL_CB_ERROR;
                }
                break;
+       case NFTA_SET_FLAGS:
        case NFTA_SET_KEY_TYPE:
        case NFTA_SET_KEY_LEN:
-               if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
-                       perror("mnl_attr_validate");
-                       return MNL_CB_ERROR;
-               }
-               break;
        case NFTA_SET_DATA_TYPE:
-               if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0) {
+       case NFTA_SET_DATA_LEN:
+               if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
                        perror("mnl_attr_validate");
                        return MNL_CB_ERROR;
                }
@@ -260,15 +245,26 @@ int nft_set_nlmsg_parse(const struct nlmsghdr *nlh, struct nft_set *s)
                s->name = strdup(mnl_attr_get_str(tb[NFTA_SET_NAME]));
                s->flags |= (1 << NFT_SET_ATTR_NAME);
        }
+       if (tb[NFTA_SET_FLAGS]) {
+               s->set_flags = ntohl(mnl_attr_get_u32(tb[NFTA_SET_FLAGS]));
+               s->flags |= (1 << NFT_SET_ATTR_FLAGS);
+       }
        if (tb[NFTA_SET_KEY_TYPE]) {
-               s->key_type = ntohl(mnl_attr_get_u32(tb[NFTA_SET_NAME]));
+               s->key_type = ntohl(mnl_attr_get_u32(tb[NFTA_SET_KEY_TYPE]));
                s->flags |= (1 << NFT_SET_ATTR_KEY_TYPE);
        }
        if (tb[NFTA_SET_KEY_LEN]) {
-               s->key_len = ntohl(mnl_attr_get_u32(tb[NFTA_SET_NAME]));
+               s->key_len = ntohl(mnl_attr_get_u32(tb[NFTA_SET_KEY_LEN]));
                s->flags |= (1 << NFT_SET_ATTR_KEY_LEN);
        }
-       /* XXX */
+       if (tb[NFTA_SET_DATA_TYPE]) {
+               s->data_type = ntohl(mnl_attr_get_u32(tb[NFTA_SET_DATA_TYPE]));
+               s->flags |= (1 << NFT_SET_ATTR_DATA_TYPE);
+       }
+       if (tb[NFTA_SET_DATA_LEN]) {
+               s->data_len = ntohl(mnl_attr_get_u32(tb[NFTA_SET_DATA_LEN]));
+               s->flags |= (1 << NFT_SET_ATTR_DATA_LEN);
+       }
 
        return ret;
 }
@@ -280,8 +276,8 @@ int nft_set_snprintf(char *buf, size_t size, struct nft_set *s,
        int ret;
        int len = size, offset = 0;
 
-       ret = snprintf(buf, size, "set=%s table=%s ",
-                       s->table, s->name);
+       ret = snprintf(buf, size, "set=%s table=%s flags=%x ",
+                       s->name, s->table, s->set_flags);
        SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
 
        ret = snprintf(buf+offset-1, len, "\n");