From d65c9ce404a5a3dc4de220189daaf610f4ec306e Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 18 Jul 2008 14:36:06 +0200 Subject: Extend high-level API for netlink BSF to add negative logic This patch introduces nfct_filter_set_logic() to set the filtering logic which results in a more flexible solution. Signed-off-by: Pablo Neira Ayuso --- include/internal.h | 5 ++ .../libnetfilter_conntrack.h | 10 +++ src/conntrack/api.c | 34 +++++++++ src/conntrack/bsf.c | 89 +++++++++++++++++----- utils/conntrack_filter.c | 5 ++ 5 files changed, 124 insertions(+), 19 deletions(-) diff --git a/include/internal.h b/include/internal.h index 33b0dcd..9dc33f2 100644 --- a/include/internal.h +++ b/include/internal.h @@ -184,6 +184,11 @@ struct nfct_filter { * once it is attached, you can release this object. */ + /* + * filter logic: use positive or negative logic + */ + enum nfct_filter_logic logic[NFCT_FILTER_MAX]; + /* * This the layer 4 protocol map for filtering. */ diff --git a/include/libnetfilter_conntrack/libnetfilter_conntrack.h b/include/libnetfilter_conntrack/libnetfilter_conntrack.h index 328cf8b..9840f90 100644 --- a/include/libnetfilter_conntrack/libnetfilter_conntrack.h +++ b/include/libnetfilter_conntrack/libnetfilter_conntrack.h @@ -356,6 +356,16 @@ extern void nfct_filter_add_attr_u32(struct nfct_filter *filter, const enum nfct_filter_attr attr, const u_int32_t value); +enum nfct_filter_logic { + NFCT_FILTER_LOGIC_POSITIVE, + NFCT_FILTER_LOGIC_NEGATIVE, + NFCT_FILTER_LOGIC_MAX +}; + +extern int nfct_filter_set_logic(struct nfct_filter *filter, + const enum nfct_filter_attr attr, + const enum nfct_filter_logic logic); + extern int nfct_filter_attach(int fd, struct nfct_filter *filter); extern int nfct_filter_detach(int fd); diff --git a/src/conntrack/api.c b/src/conntrack/api.c index 3bd96a8..fcd3fb4 100644 --- a/src/conntrack/api.c +++ b/src/conntrack/api.c @@ -907,6 +907,40 @@ void nfct_filter_add_attr_u32(struct nfct_filter *filter, nfct_filter_add_attr(filter, type, &value); } +/** + * nfct_filter_set_logic - set the filter logic for an attribute type + * @filter: filter object that we want to modify + * @type: filter attribute type + * @logic: filter logic that we want to use + * + * You can only use this function once to set the filtering logic for + * one attribute. You can define two logics: NFCT_FILTER_POSITIVE_LOGIC + * that accept events that match the filter, and NFCT_FILTER_NEGATIVE_LOGIC + * that rejects events that match the filter. Default filtering logic is + * NFCT_FILTER_POSITIVE_LOGIC. + * + * On error, it returns -1 and errno is appropriately set. On success, it + * returns 0. + */ +int nfct_filter_set_logic(struct nfct_filter *filter, + const enum nfct_filter_attr type, + const enum nfct_filter_logic logic) +{ + if (type >= NFCT_FILTER_MAX) { + errno = ENOTSUP; + return -1; + } + + if (filter->logic[type]) { + errno = EBUSY; + return -1; + } + + filter->logic[type] = logic; + + return 0; +} + /** * nfct_filter_attach - attach a filter to a socket descriptor * @fd: socket descriptor diff --git a/src/conntrack/bsf.c b/src/conntrack/bsf.c index 2ac5fe1..cd9e883 100644 --- a/src/conntrack/bsf.c +++ b/src/conntrack/bsf.c @@ -122,6 +122,7 @@ add_state_filter_cta(struct sock_filter *this, unsigned int cta_protoinfo_proto, unsigned int cta_protoinfo_state, u_int16_t state_flags, + unsigned int logic, size_t remain) { struct sock_filter filter[14 + __FILTER_PROTO_MAX]; @@ -131,7 +132,7 @@ add_state_filter_cta(struct sock_filter *this, .k = NFCT_FILTER_REJECT, }; unsigned int i, j; - unsigned int label_continue; + unsigned int label_continue, jt; /* calculate the number of filter lines */ for (i = 0, j = 0; i < sizeof(state_flags) * 8; i++) { @@ -151,7 +152,11 @@ add_state_filter_cta(struct sock_filter *this, memset(filter, 0, sizeof(filter)); - label_continue = j + 1; + jt = j + 1; + if (logic == NFCT_FILTER_LOGIC_POSITIVE) + label_continue = j + 1; + else + label_continue = j + 2; set_basic_filter(filter, CTA_PROTOINFO, @@ -164,7 +169,7 @@ add_state_filter_cta(struct sock_filter *this, struct sock_filter cmp = { .code = BPF_JMP|BPF_JEQ|BPF_K, .k = i, - .jt = label_continue - j - 1, + .jt = jt - j - 1, }; if (state_flags & (1 << i)) { @@ -174,15 +179,27 @@ add_state_filter_cta(struct sock_filter *this, } memcpy(this, filter, sizeof(struct sock_filter) * (j + 14)); + + if (logic == NFCT_FILTER_LOGIC_NEGATIVE) { + struct sock_filter jump = { + .code = BPF_JMP|BPF_JA, + .k = 1, + }; + memcpy(&this[j + 14], &jump, sizeof(jump)); + j++; + } + memcpy(&this[j + 14], &verdict, sizeof(verdict)); + j++; - return j + 14 + 1; + return j + 14; } static int add_state_filter(struct sock_filter *this, int proto, u_int16_t flags, + unsigned int logic, size_t remain) { struct { @@ -212,6 +229,7 @@ add_state_filter(struct sock_filter *this, cta[proto].cta_protoinfo, cta[proto].cta_state, flags, + logic, remain); } @@ -223,12 +241,13 @@ bsf_add_state_filter(const struct nfct_filter *filter, unsigned int i, j; for (i = 0, j = 0; i < IPPROTO_MAX; i++) { - if (test_bit(i, filter->l4proto_map) && - filter->l4proto_state[i].map) { - j += add_state_filter(this, - i, - filter->l4proto_state[i].map, - remain); + if (filter->l4proto_state[i].map) { + j += add_state_filter( + this, + i, + filter->l4proto_state[i].map, + filter->logic[NFCT_FILTER_L4PROTO_STATE], + remain); } } @@ -247,7 +266,7 @@ bsf_add_proto_filter(const struct nfct_filter *f, .k = NFCT_FILTER_REJECT, }; unsigned int i, j; - unsigned int label_continue; + unsigned int label_continue, jt; for (i = 0, j = 0; i < IPPROTO_MAX; i++) { if (test_bit(i, f->l4proto_map)) { @@ -264,7 +283,11 @@ bsf_add_proto_filter(const struct nfct_filter *f, return -1; } - label_continue = j + 1; + jt = j + 1; + if (f->logic[NFCT_FILTER_L4PROTO] == NFCT_FILTER_LOGIC_POSITIVE) + label_continue = j + 1; + else + label_continue = j + 2; memset(filter, 0, sizeof(filter)); @@ -279,7 +302,7 @@ bsf_add_proto_filter(const struct nfct_filter *f, struct sock_filter cmp = { .code = BPF_JMP|BPF_JEQ|BPF_K, .k = i, - .jt = label_continue - j - 1, + .jt = jt - j - 1, }; if (test_bit(i, f->l4proto_map)) { @@ -289,9 +312,20 @@ bsf_add_proto_filter(const struct nfct_filter *f, } memcpy(this, filter, sizeof(struct sock_filter) * (j + 14)); + + if (f->logic[NFCT_FILTER_L4PROTO] == NFCT_FILTER_LOGIC_NEGATIVE) { + struct sock_filter jump = { + .code = BPF_JMP|BPF_JA, + .k = 1, + }; + memcpy(&this[j + 14], &jump, sizeof(jump)); + j++; + } + memcpy(&this[j + 14], &verdict, sizeof(verdict)); + j++; - return j + 14 + 1; + return j + 14; } static int @@ -306,15 +340,17 @@ bsf_add_addr_ipv4_filter(const struct nfct_filter *f, .code = BPF_RET|BPF_K, .k = NFCT_FILTER_REJECT, }; - unsigned int i, j, dir; - unsigned int label_continue; + unsigned int i, j, dir, attr; + unsigned int label_continue, jt; switch(type) { case CTA_IP_V4_SRC: dir = __FILTER_ADDR_SRC; + attr = NFCT_FILTER_SRC_IPV4; break; case CTA_IP_V4_DST: dir = __FILTER_ADDR_DST; + attr = NFCT_FILTER_DST_IPV4; break; default: return 0; @@ -330,7 +366,11 @@ bsf_add_addr_ipv4_filter(const struct nfct_filter *f, return -1; } - label_continue = (f->l3proto_elems[dir] * 2) + 1; + jt = (f->l3proto_elems[dir] * 2) + 1; + if (f->logic[attr] == NFCT_FILTER_LOGIC_POSITIVE) + label_continue = (f->l3proto_elems[dir] * 2) + 1; + else + label_continue = (f->l3proto_elems[dir] * 2) + 2; memset(filter, 0, sizeof(filter)); @@ -351,7 +391,7 @@ bsf_add_addr_ipv4_filter(const struct nfct_filter *f, .code = BPF_JMP|BPF_JEQ|BPF_K, .k = f->l3proto[dir][i].addr & f->l3proto[dir][i].mask, - .jt = label_continue - j - 2, + .jt = jt - j - 2, }, }; memcpy(&filter[j + 14], cmp, sizeof(cmp)); @@ -359,9 +399,20 @@ bsf_add_addr_ipv4_filter(const struct nfct_filter *f, } memcpy(this, filter, sizeof(struct sock_filter) * (j + 14)); + + if (f->logic[attr] == NFCT_FILTER_LOGIC_NEGATIVE) { + struct sock_filter jump = { + .code = BPF_JMP|BPF_JA, + .k = 1, + }; + memcpy(&this[j + 14], &jump, sizeof(jump)); + j++; + } + memcpy(&this[j + 14], &verdict, sizeof(verdict)); + j++; - return j + 14 + 1; + return j + 14; } static int diff --git a/utils/conntrack_filter.c b/utils/conntrack_filter.c index 7d22950..eb26189 100644 --- a/utils/conntrack_filter.c +++ b/utils/conntrack_filter.c @@ -58,6 +58,11 @@ int main() .mask = 0xffffffff, }; + /* ignore whatever that comes from 127.0.0.1 */ + nfct_filter_set_logic(filter, + NFCT_FILTER_SRC_IPV4, + NFCT_FILTER_LOGIC_NEGATIVE); + nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV4, &filter_ipv4); if (nfct_filter_attach(nfct_fd(h), filter) == -1) { -- cgit v1.2.3