summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/internal/object.h4
-rw-r--r--include/libnetfilter_conntrack/libnetfilter_conntrack.h1
-rw-r--r--src/conntrack/bsf.c55
-rw-r--r--src/conntrack/filter.c10
4 files changed, 70 insertions, 0 deletions
diff --git a/include/internal/object.h b/include/internal/object.h
index 8854ef2..658e4d2 100644
--- a/include/internal/object.h
+++ b/include/internal/object.h
@@ -280,6 +280,10 @@ struct nfct_filter {
uint32_t mask;
} mark[__FILTER_MARK_MAX];
+ uint32_t zone_elems;
+#define __FILTER_ZONE_MAX 127
+ uint16_t zone[__FILTER_ZONE_MAX];
+
uint32_t set[1];
};
diff --git a/include/libnetfilter_conntrack/libnetfilter_conntrack.h b/include/libnetfilter_conntrack/libnetfilter_conntrack.h
index 2e9458a..27d972d 100644
--- a/include/libnetfilter_conntrack/libnetfilter_conntrack.h
+++ b/include/libnetfilter_conntrack/libnetfilter_conntrack.h
@@ -510,6 +510,7 @@ enum nfct_filter_attr {
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_ZONE, /* uint16_t */
NFCT_FILTER_MAX
};
diff --git a/src/conntrack/bsf.c b/src/conntrack/bsf.c
index 1e78bad..da5919c 100644
--- a/src/conntrack/bsf.c
+++ b/src/conntrack/bsf.c
@@ -738,6 +738,58 @@ bsf_add_mark_filter(const struct nfct_filter *f, struct sock_filter *this)
return j;
}
+static int
+bsf_add_zone_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->zone_elems == 0)
+ return 0;
+
+ /* 127 max filterable zones. One JMP instruction per zone. */
+ s = stack_create(sizeof(struct jump), 127);
+ if (s == NULL) {
+ errno = ENOMEM;
+ return 0;
+ }
+
+ jt = 1;
+ j = 0;
+ j += nfct_bsf_load_payload_offset(this, j); /* A = nla header offset */
+ j += nfct_bsf_find_attr(this, CTA_ZONE, j); /* A = CTA_ZONE 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_ZONE offset> */
+ j += nfct_bsf_load_attr(this, BPF_H, j); /* A = skb->data[X:X + BPF_H] */
+
+ for (i = 0; i < f->zone_elems; i++) {
+ j += nfct_bsf_cmp_k_stack(this, f->zone[i], jt - j, j, s);
+ }
+
+ while (stack_pop(s, &jmp) != -1)
+ this[jmp.line].jt += jmp.jt + j;
+
+ if (f->logic[NFCT_FILTER_ZONE] == 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
@@ -774,6 +826,9 @@ int __setup_netlink_socket_filter(int fd, struct nfct_filter *f)
j += bsf_add_mark_filter(f, &bsf[j]);
show_filter(bsf, from, j, "---- check mark ----");
from = j;
+ j += bsf_add_zone_filter(f, &bsf[j]);
+ show_filter(bsf, from, j, "---- check zone ----");
+ from = j;
/* nothing to filter, skip */
if (j == 0)
diff --git a/src/conntrack/filter.c b/src/conntrack/filter.c
index 57b2294..9feff80 100644
--- a/src/conntrack/filter.c
+++ b/src/conntrack/filter.c
@@ -104,6 +104,15 @@ static void filter_attr_mark(struct nfct_filter *filter, const void *value)
filter->mark_elems++;
}
+static void filter_attr_zone(struct nfct_filter *filter, const void *value)
+{
+ if (filter->zone_elems >= __FILTER_ZONE_MAX)
+ return;
+
+ filter->zone[filter->zone_elems] = *(uint16_t *) value;
+ filter->zone_elems++;
+}
+
const filter_attr filter_attr_array[NFCT_FILTER_MAX] = {
[NFCT_FILTER_L4PROTO] = filter_attr_l4proto,
[NFCT_FILTER_L4PROTO_STATE] = filter_attr_l4proto_state,
@@ -112,4 +121,5 @@ const filter_attr filter_attr_array[NFCT_FILTER_MAX] = {
[NFCT_FILTER_SRC_IPV6] = filter_attr_src_ipv6,
[NFCT_FILTER_DST_IPV6] = filter_attr_dst_ipv6,
[NFCT_FILTER_MARK] = filter_attr_mark,
+ [NFCT_FILTER_ZONE] = filter_attr_zone,
};