* [PATCH lnf-ct 1/2] conntrack: add mark event filter
2015-03-12 22:18 [PATCH lnf-ct 0/2] add mark event filter Ken-ichirou MATSUZAWA
@ 2015-03-12 22:21 ` Ken-ichirou MATSUZAWA
2015-03-12 22:24 ` [PATCH lnf-ct 2/2] qa: add test for " Ken-ichirou MATSUZAWA
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Ken-ichirou MATSUZAWA @ 2015-03-12 22:21 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: Florian Westphal, The netfilter developer mailinglist
This patch adds mark filter for event listener, using same struct
nfct_filter_dump_mark at dump.
Signed-off-by: Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
---
include/internal/object.h | 7 +++
.../libnetfilter_conntrack.h | 1 +
src/conntrack/bsf.c | 73 ++++++++++++++++++++++
src/conntrack/filter.c | 13 ++++
4 files changed, 94 insertions(+)
diff --git a/include/internal/object.h b/include/internal/object.h
index 540ad0d..1259467 100644
--- a/include/internal/object.h
+++ b/include/internal/object.h
@@ -263,6 +263,13 @@ struct nfct_filter {
u_int32_t mask[4];
} l3proto_ipv6[2][__FILTER_IPV6_MAX];
+ u_int32_t mark_elems;
+ struct {
+#define __FILTER_MARK_MAX 127
+ u_int32_t val;
+ u_int32_t mask;
+ } mark[__FILTER_MARK_MAX];
+
u_int32_t set[1];
};
diff --git a/include/libnetfilter_conntrack/libnetfilter_conntrack.h b/include/libnetfilter_conntrack/libnetfilter_conntrack.h
index d04a0c6..cea9a78 100644
--- a/include/libnetfilter_conntrack/libnetfilter_conntrack.h
+++ b/include/libnetfilter_conntrack/libnetfilter_conntrack.h
@@ -499,6 +499,7 @@ enum nfct_filter_attr {
NFCT_FILTER_DST_IPV4, /* struct nfct_filter_ipv4 */
NFCT_FILTER_SRC_IPV6, /* struct nfct_filter_ipv6 */
NFCT_FILTER_DST_IPV6, /* struct nfct_filter_ipv6 */
+ NFCT_FILTER_MARK, /* struct nfct_filter_dump_mark */
NFCT_FILTER_MAX
};
diff --git a/src/conntrack/bsf.c b/src/conntrack/bsf.c
index 534202f..bc73369 100644
--- a/src/conntrack/bsf.c
+++ b/src/conntrack/bsf.c
@@ -55,6 +55,9 @@ static char *code2str(u_int16_t code)
case BPF_MISC|BPF_TAX:
return "BPF_MISC|BPF_TAX";
break;
+ case BPF_MISC|BPF_TXA:
+ return "BPF_MISC|BPF_TXA";
+ break;
case BPF_LD|BPF_B|BPF_IND:
return "BPF_LD|BPF_B|BPF_IND";
break;
@@ -228,6 +231,16 @@ nfct_bsf_x_equal_a(struct sock_filter *this, int pos)
}
static int
+nfct_bsf_a_equal_x(struct sock_filter *this, int pos)
+{
+ struct sock_filter __code = {
+ .code = BPF_MISC|BPF_TXA,
+ };
+ memcpy(&this[pos], &__code, sizeof(__code));
+ return NEW_POS(__code);
+}
+
+static int
nfct_bsf_load_attr(struct sock_filter *this, int word_size, int pos)
{
struct sock_filter __code = {
@@ -663,6 +676,63 @@ bsf_add_daddr_ipv6_filter(const struct nfct_filter *f, struct sock_filter *this)
return bsf_add_addr_ipv6_filter(f, this, CTA_IP_V6_DST);
}
+static int
+bsf_add_mark_filter(const struct nfct_filter *f, struct sock_filter *this)
+{
+ unsigned int i, j;
+ unsigned int jt;
+ struct stack *s;
+ struct jump jmp;
+ struct sock_filter __code = {
+ /* if (A == 0) skip next two */
+ .code = BPF_JMP|BPF_JEQ|BPF_K,
+ .k = 0,
+ .jt = 2,
+ .jf = 0,
+ };
+
+ /* nothing to filter, skip */
+ if (f->mark_elems == 0)
+ return 0;
+
+ /* XXX: see bsf_add_addr_ipv4_filter() */
+ s = stack_create(sizeof(struct jump), 3 + 127);
+ if (s == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ jt = 1;
+ j = 0;
+ j += nfct_bsf_load_payload_offset(this, j); /* A = nla header offset */
+ j += nfct_bsf_find_attr(this, CTA_MARK, j); /* A = CTA_MARK offset, started from A */
+ memcpy(&this[j], &__code, sizeof(__code)); /* if A == 0 skip next two op */
+ j += NEW_POS(__code);
+ j += nfct_bsf_x_equal_a(this, j); /* X = A <CTA_MARK offset> */
+ j += nfct_bsf_load_attr(this, BPF_W, j); /* A = skb->data[X:X + BPF_W] */
+ j += nfct_bsf_x_equal_a(this, j); /* X = A <CTA_MARK value> */
+
+ for (i = 0; i < f->mark_elems; i++) {
+ int mark = f->mark[i].val & f->mark[i].mask;
+
+ j += nfct_bsf_alu_and(this, f->mark[i].mask, j);
+ j += nfct_bsf_cmp_k_stack(this, mark, jt - j, j, s);
+ j += nfct_bsf_a_equal_x(this, j);
+ }
+
+ while (stack_pop(s, &jmp) != -1)
+ this[jmp.line].jt += jmp.jt + j;
+
+ if (f->logic[NFCT_FILTER_MARK] == NFCT_FILTER_LOGIC_NEGATIVE)
+ j += nfct_bsf_jump_to(this, 1, j);
+
+ j += nfct_bsf_ret_verdict(this, NFCT_FILTER_REJECT, j);
+
+ stack_destroy(s);
+
+ return j;
+}
+
/* this buffer must be big enough to store all the autogenerated lines */
#define BSF_BUFFER_SIZE 2048
@@ -696,6 +766,9 @@ int __setup_netlink_socket_filter(int fd, struct nfct_filter *f)
j += bsf_add_state_filter(f, &bsf[j]);
show_filter(bsf, from, j, "---- check state ----");
from = j;
+ j += bsf_add_mark_filter(f, &bsf[j]);
+ show_filter(bsf, from, j, "---- check mark ----");
+ from = j;
/* nothing to filter, skip */
if (j == 0)
diff --git a/src/conntrack/filter.c b/src/conntrack/filter.c
index 026545a..78fbbc5 100644
--- a/src/conntrack/filter.c
+++ b/src/conntrack/filter.c
@@ -79,6 +79,18 @@ static void filter_attr_dst_ipv6(struct nfct_filter *filter, const void *value)
filter->l3proto_elems_ipv6[1]++;
}
+static void filter_attr_mark(struct nfct_filter *filter, const void *value)
+{
+ const struct nfct_filter_dump_mark *this = value;
+
+ if (filter->mark_elems >= __FILTER_MARK_MAX)
+ return;
+
+ filter->mark[filter->mark_elems].val = this->val;
+ filter->mark[filter->mark_elems].mask = this->mask;
+ filter->mark_elems++;
+}
+
const filter_attr filter_attr_array[NFCT_FILTER_MAX] = {
[NFCT_FILTER_L4PROTO] = filter_attr_l4proto,
[NFCT_FILTER_L4PROTO_STATE] = filter_attr_l4proto_state,
@@ -86,4 +98,5 @@ const filter_attr filter_attr_array[NFCT_FILTER_MAX] = {
[NFCT_FILTER_DST_IPV4] = filter_attr_dst_ipv4,
[NFCT_FILTER_SRC_IPV6] = filter_attr_src_ipv6,
[NFCT_FILTER_DST_IPV6] = filter_attr_dst_ipv6,
+ [NFCT_FILTER_MARK] = filter_attr_mark,
};
--
2.1.4
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH lnf-ct 2/2] qa: add test for mark event filter
2015-03-12 22:18 [PATCH lnf-ct 0/2] add mark event filter Ken-ichirou MATSUZAWA
2015-03-12 22:21 ` [PATCH lnf-ct 1/2] conntrack: " Ken-ichirou MATSUZAWA
@ 2015-03-12 22:24 ` Ken-ichirou MATSUZAWA
2015-03-13 13:13 ` [PATCH lnf-ct 0/2] add " Pablo Neira Ayuso
2015-03-13 13:42 ` Florian Westphal
3 siblings, 0 replies; 5+ messages in thread
From: Ken-ichirou MATSUZAWA @ 2015-03-12 22:24 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: Florian Westphal, The netfilter developer mailinglist
testing mark filter in root by
# ./qa/ct_mark_filter.sh
Signed-off-by: Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
---
qa/Makefile.am | 6 ++-
qa/ct_mark_filter.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++
qa/ct_mark_filter.sh | 36 +++++++++++++
qa/nssocket_env.sh | 2 +-
4 files changed, 191 insertions(+), 2 deletions(-)
create mode 100644 qa/ct_mark_filter.c
create mode 100755 qa/ct_mark_filter.sh
diff --git a/qa/Makefile.am b/qa/Makefile.am
index b16ab01..3c8a1cb 100644
--- a/qa/Makefile.am
+++ b/qa/Makefile.am
@@ -1,7 +1,7 @@
include $(top_srcdir)/Make_global.am
check_PROGRAMS = test_api test_filter test_connlabel ct_stress \
- ct_events_reliable ct_echo_event
+ ct_events_reliable ct_echo_event ct_mark_filter
test_api_SOURCES = test_api.c
test_api_LDADD = ../src/libnetfilter_conntrack.la
@@ -22,3 +22,7 @@ AM_CFLAGS += -D_GNU_SOURCE
ct_echo_event_SOURCES = ct_echo_event.c nssocket.c
ct_echo_event_DEPENDENCIES = ct_echo_event.sh
ct_echo_event_LDADD = ../src/libnetfilter_conntrack.la -lmnl
+
+ct_mark_filter_SOURCES = ct_mark_filter.c nssocket.c
+ct_mark_filter_DEPENDENCIES = ct_mark_filter.sh
+ct_mark_filter_LDADD = ../src/libnetfilter_conntrack.la -lmnl
diff --git a/qa/ct_mark_filter.c b/qa/ct_mark_filter.c
new file mode 100644
index 0000000..276344a
--- /dev/null
+++ b/qa/ct_mark_filter.c
@@ -0,0 +1,149 @@
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <netinet/in.h>
+
+#include <libmnl/libmnl.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+
+#include "nssocket.h"
+
+static void tcp_echo_before_fin(const struct mnl_socket *nl,
+ const char *pre, const char *post)
+{
+ u_int8_t proto = IPPROTO_TCP;
+
+ sync_fifo(pre);
+ timeout.tv_sec = INIT_TIMEOUT;
+ handle_qacb(nl, true, cb_tcp_new, &proto);
+ handle_qacb(nl, true, cb_tcp_syn_recv, &proto);
+ handle_qacb(nl, true, cb_tcp_established, &proto);
+ handle_qacb(nl, false, NULL, NULL);
+ sync_fifo(post);
+}
+
+static void tcp_echo_after_fin(const struct mnl_socket *nl,
+ const char *pre, const char *post)
+{
+ u_int8_t proto = IPPROTO_TCP;
+
+ sync_fifo(pre);
+ timeout.tv_sec = INIT_TIMEOUT;
+ handle_qacb(nl, true, cb_tcp_fin_wait, &proto);
+ handle_qacb(nl, true, cb_tcp_close_wait, &proto);
+ handle_qacb(nl, true, cb_tcp_close, &proto);
+ handle_qacb(nl, true, cb_tcp_destroy, &proto);
+ handle_qacb(nl, false, NULL, NULL);
+ sync_fifo(post);
+}
+
+static void filter_mark_zero(const struct mnl_socket *nl,
+ const char *pre, const char *post)
+{
+ struct nfct_filter *filter = nfct_filter_create();
+ struct nfct_filter_dump_mark mark = {val: 0, mask: 0};
+
+ nfct_filter_add_attr(filter, NFCT_FILTER_MARK, &mark);
+ assert(nfct_filter_attach(mnl_socket_get_fd(nl), filter) != -1);
+ nfct_filter_destroy(filter);
+ tcp_echo(nl, pre, post);
+ assert(nfct_filter_detach(mnl_socket_get_fd(nl)) != -1);
+}
+
+static void filter_mark_1_1(const struct mnl_socket *nl,
+ const char *pre, const char *post)
+{
+ struct nfct_filter *filter = nfct_filter_create();
+ struct nfct_filter_dump_mark mark = {val: 1, mask: 1};
+
+ nfct_filter_add_attr(filter, NFCT_FILTER_MARK, &mark);
+ assert(nfct_filter_attach(mnl_socket_get_fd(nl), filter) != -1);
+ nfct_filter_destroy(filter);
+ tcp_echo_after_fin(nl, pre, post);
+ assert(nfct_filter_detach(mnl_socket_get_fd(nl)) != -1);
+}
+
+static void filter_mark_neg_1_1(const struct mnl_socket *nl,
+ const char *pre, const char *post)
+{
+ struct nfct_filter *filter = nfct_filter_create();
+ struct nfct_filter_dump_mark mark = {val: 1, mask: 1};
+
+ nfct_filter_add_attr(filter, NFCT_FILTER_MARK, &mark);
+ assert(nfct_filter_set_logic(filter, NFCT_FILTER_MARK,
+ NFCT_FILTER_LOGIC_NEGATIVE) != -1);
+ assert(nfct_filter_attach(mnl_socket_get_fd(nl), filter) != -1);
+ nfct_filter_destroy(filter);
+ tcp_echo_before_fin(nl, pre, post);
+ assert(nfct_filter_detach(mnl_socket_get_fd(nl)) != -1);
+}
+
+static void filter_mark_neg_0_fffffffd(const struct mnl_socket *nl,
+ const char *pre, const char *post)
+{
+ struct nfct_filter *filter = nfct_filter_create();
+ struct nfct_filter_dump_mark mark = {val: 0, mask: 0xfffffffd};
+
+ nfct_filter_add_attr(filter, NFCT_FILTER_MARK, &mark);
+ assert(nfct_filter_set_logic(filter, NFCT_FILTER_MARK,
+ NFCT_FILTER_LOGIC_NEGATIVE) != -1);
+ assert(nfct_filter_attach(mnl_socket_get_fd(nl), filter) != -1);
+ nfct_filter_destroy(filter);
+ tcp_echo_after_fin(nl, pre, post);
+ assert(nfct_filter_detach(mnl_socket_get_fd(nl)) != -1);
+}
+
+static void filter_mark_max(const struct mnl_socket *nl,
+ const char *pre, const char *post)
+{
+ struct nfct_filter *filter = nfct_filter_create();
+ struct nfct_filter_dump_mark mark;
+ int i;
+
+ for (i = 0; i < 126; i++) {
+ /* does not match to mark value 3 */
+ mark = (struct nfct_filter_dump_mark){val: 0, mask: 3};
+ nfct_filter_add_attr(filter, NFCT_FILTER_MARK, &mark);
+ }
+
+ /* __FILTER_MARK_MAX 127, should be added */
+ mark = (struct nfct_filter_dump_mark){val: 1, mask: 1};
+ nfct_filter_add_attr(filter, NFCT_FILTER_MARK, &mark);
+
+ /* over __FILTER_MARK_MAX, should be ignored */
+ mark = (struct nfct_filter_dump_mark){val: 0, mask: 0};
+ nfct_filter_add_attr(filter, NFCT_FILTER_MARK, &mark);
+
+ assert(nfct_filter_attach(mnl_socket_get_fd(nl), filter) != -1);
+ nfct_filter_destroy(filter);
+ tcp_echo_after_fin(nl, pre, post);
+ assert(nfct_filter_detach(mnl_socket_get_fd(nl)) != -1);
+}
+
+int main(int argc, char *argv[])
+{
+ struct mnl_socket *nl;
+ char *pre, *post;
+
+ if (argc != 4) {
+ fprintf(stderr, "usage: %s <netns> <pre_fifo> <post_fifo>\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ pre = argv[2];
+ post = argv[3];
+
+ nl = mnl_event_nssocket(argv[1]);
+ if (nl == NULL) {
+ perror("init_mnl_socket");
+ exit(EXIT_FAILURE);
+ }
+
+ filter_mark_zero(nl, pre, post);
+ filter_mark_1_1(nl, pre, post);
+ filter_mark_neg_1_1(nl, pre, post);
+ filter_mark_neg_0_fffffffd(nl, pre, post);
+ filter_mark_max(nl, pre, post);
+
+ return fini_nssocket();
+}
diff --git a/qa/ct_mark_filter.sh b/qa/ct_mark_filter.sh
new file mode 100755
index 0000000..a2c7fed
--- /dev/null
+++ b/qa/ct_mark_filter.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+. `dirname $0`/nssocket_env.sh
+
+echo "---- TCP echo with ctmark 0/0 [filter_mark_zero]"
+pre_sync
+echo | nc -q 0 $VETH_CHILD_ADDR $DSTPORT
+post_sync
+
+echo "---- iptables CONNMARK settings - ctmark tcp 2/2, tcp fin 1/1"
+ip netns exec $NETNS sh <<EOF
+ iptables -t mangle -I PREROUTING -p tcp -m tcp -j CONNMARK --set-mark 2/2
+ iptables -t mangle -I PREROUTING -p tcp -m tcp --tcp-flags FIN FIN -j CONNMARK --set-mark 1/1
+EOF
+
+echo "---- TCP echo with mark filter 1/1 [filter_mark_1_1]"
+pre_sync
+echo | nc -q 0 $VETH_CHILD_ADDR $DSTPORT
+post_sync
+
+echo "---- TCP echo with mark filter ! 1/1 [filter_mark_neg_1_1]"
+pre_sync
+echo | nc -q 0 $VETH_CHILD_ADDR $DSTPORT
+post_sync
+
+echo "---- TCP echo with mark filter !0/fffffffd [filter_mark_neg_0_fffffffd]"
+pre_sync
+echo | nc -q 0 $VETH_CHILD_ADDR $DSTPORT
+post_sync
+
+echo "---- max mark filter entry [filter_mark_max]"
+pre_sync
+echo | nc -q 0 $VETH_CHILD_ADDR $DSTPORT
+post_sync
+
+fin
diff --git a/qa/nssocket_env.sh b/qa/nssocket_env.sh
index 2bcd74d..1732eb1 100644
--- a/qa/nssocket_env.sh
+++ b/qa/nssocket_env.sh
@@ -11,7 +11,7 @@ DSTPORT="7"
ICMP_TYPE="8"
ICMP_CODE="0"
NF_TIMEOUT=2
-INIT_TIMEOUT=4
+INIT_TIMEOUT=8
dname=`dirname $0`
bname=`basename $0`
--
2.1.4
^ permalink raw reply related [flat|nested] 5+ messages in thread