summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/internal.h5
-rw-r--r--include/libnetfilter_conntrack/libnetfilter_conntrack.h10
-rw-r--r--src/conntrack/api.c34
-rw-r--r--src/conntrack/bsf.c89
-rw-r--r--utils/conntrack_filter.c5
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
@@ -185,6 +185,11 @@ struct nfct_filter {
*/
/*
+ * filter logic: use positive or negative logic
+ */
+ enum nfct_filter_logic logic[NFCT_FILTER_MAX];
+
+ /*
* This the layer 4 protocol map for filtering.
*/
u_int32_t l4proto_map[IPPROTO_MAX/32];
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
@@ -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
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) {