diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2008-07-18 14:36:06 +0200 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2008-07-18 14:36:06 +0200 |
commit | d65c9ce404a5a3dc4de220189daaf610f4ec306e (patch) | |
tree | d86743cc793c33231b051dd1b97dfa8b77c92bbb /src | |
parent | 563114a47ae03c988ca0e66eddda33d485e35f6b (diff) |
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 <pablo@netfilter.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/conntrack/api.c | 34 | ||||
-rw-r--r-- | src/conntrack/bsf.c | 89 |
2 files changed, 104 insertions, 19 deletions
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 @@ -908,6 +908,40 @@ void nfct_filter_add_attr_u32(struct nfct_filter *filter, } /** + * 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 * @filter: filter that we want to attach to the socket 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 |