summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2013-02-02 11:38:46 +0100
committerPablo Neira Ayuso <pablo@netfilter.org>2013-02-03 20:31:53 +0100
commitd07d9c1911739037be2db1d54a59aadf5c2d4adc (patch)
tree2db0c8dd1ec24c7f2efdd6e73f20a72e6381e042
parent3ed3c75a9a7a25ba9e8773e8830ab5b3914ef51b (diff)
set: complete support
Including examples. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r--examples/Makefile.am12
-rw-r--r--examples/nft-set-add.c109
-rw-r--r--examples/nft-set-del.c93
-rw-r--r--examples/nft-set-get.c114
-rw-r--r--include/libnftables/set.h4
-rw-r--r--src/set.c82
6 files changed, 369 insertions, 45 deletions
diff --git a/examples/Makefile.am b/examples/Makefile.am
index aee95df..d239196 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -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
index 0000000..afc37c5
--- /dev/null
+++ b/examples/nft-set-add.c
@@ -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
index 0000000..aebc018
--- /dev/null
+++ b/examples/nft-set-del.c
@@ -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
index 0000000..a07a1d7
--- /dev/null
+++ b/examples/nft-set-get.c
@@ -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;
+}
diff --git a/include/libnftables/set.h b/include/libnftables/set.h
index 00bf806..e56fb50 100644
--- a/include/libnftables/set.h
+++ b/include/libnftables/set.h
@@ -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;
diff --git a/src/set.c b/src/set.c
index 29d359e..54cc55d 100644
--- 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
@@ -29,13 +29,15 @@
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");