summaryrefslogtreecommitdiffstats
path: root/src/conntrack
diff options
context:
space:
mode:
Diffstat (limited to 'src/conntrack')
-rw-r--r--src/conntrack/Makefile.am3
-rw-r--r--src/conntrack/api.c6
-rw-r--r--src/conntrack/bsf.c495
-rw-r--r--src/conntrack/filter.c11
-rw-r--r--src/conntrack/stack.c67
5 files changed, 319 insertions, 263 deletions
diff --git a/src/conntrack/Makefile.am b/src/conntrack/Makefile.am
index 2d62177..d989d10 100644
--- a/src/conntrack/Makefile.am
+++ b/src/conntrack/Makefile.am
@@ -14,4 +14,5 @@ libnfconntrack_la_SOURCES = api.c callback.c \
compare.c \
copy.c \
filter.c bsf.c \
- grp.c grp_getter.c grp_setter.c
+ grp.c grp_getter.c grp_setter.c \
+ stack.c
diff --git a/src/conntrack/api.c b/src/conntrack/api.c
index 6dae83f..141aa9d 100644
--- a/src/conntrack/api.c
+++ b/src/conntrack/api.c
@@ -1009,8 +1009,8 @@ void nfct_filter_destroy(struct nfct_filter *filter)
* @type: filter attribute type
* @value: pointer to the value of the filter attribute
*
- * Limitations: You can add up to 256 IPv4 addresses and masks for
- * NFCT_FILTER_SRC_IPV4 and, similarly, 256 for NFCT_FILTER_DST_IPV4.
+ * Limitations: You can add up to 127 IPv4 addresses and masks for
+ * NFCT_FILTER_SRC_IPV4 and, similarly, 127 for NFCT_FILTER_DST_IPV4.
*/
void nfct_filter_add_attr(struct nfct_filter *filter,
const enum nfct_filter_attr type,
@@ -1033,6 +1033,8 @@ void nfct_filter_add_attr(struct nfct_filter *filter,
* @filter: filter object that we want to modify
* @type: filter attribute type
* @value: value of the filter attribute using unsigned int (32 bits).
+ *
+ * Limitations: You can add up to 255 protocols which is a reasonable limit.
*/
void nfct_filter_add_attr_u32(struct nfct_filter *filter,
const enum nfct_filter_attr type,
diff --git a/src/conntrack/bsf.c b/src/conntrack/bsf.c
index 0d20949..f2d14f8 100644
--- a/src/conntrack/bsf.c
+++ b/src/conntrack/bsf.c
@@ -6,6 +6,7 @@
*/
#include "internal/internal.h"
+#include "internal/stack.h"
#include <linux/filter.h>
#ifndef SKF_AD_NLATTR
@@ -32,175 +33,192 @@ static void show_filter(struct sock_filter *this, int size)
static inline void show_filter(struct sock_filter *this, int size) {}
#endif
-static void set_basic_filter(struct sock_filter *this,
- unsigned int first_type,
- unsigned int second_type,
- unsigned int third_type,
- unsigned int label,
- unsigned int word_size)
+#define NEW_POS(x) (sizeof(x)/sizeof(struct sock_filter))
+
+static inline int
+nfct_bsf_load_payload_offset(struct sock_filter *this, int pos)
{
- struct sock_filter filter[] = {
- [0] = {
- /* A = sizeof(struct nlmsghdr) + sizeof(struct nfgenmsg) */
- .code = BPF_LD|BPF_IMM,
- .k = sizeof(struct nlmsghdr) + sizeof(struct nfgenmsg),
- },
- [1] = {
- /* X = first_type */
- .code = BPF_LDX|BPF_IMM,
- .k = first_type,
- },
- [2] = {
- /* A = netlink attribute offset */
- .code = BPF_LD|BPF_B|BPF_ABS,
- .k = SKF_AD_OFF + SKF_AD_NLATTR,
- },
- [3] = {
- /* Reject if not found (A == 0) */
- .code = BPF_JMP|BPF_JEQ|BPF_K,
- .k = 0,
- .jt = label - 3 - 1,
- },
- [4] = {
- /* A += sizeof(struct nfattr) */
- .code = BPF_ALU|BPF_ADD|BPF_K,
- .k = sizeof(struct nfattr),
- },
- [5] = {
- /* X = second_type */
- .code = BPF_LDX|BPF_IMM,
- .k = second_type,
- },
- [6] = {
- /* A = netlink attribute offset */
- .code = BPF_LD|BPF_B|BPF_ABS,
- .k = SKF_AD_OFF + SKF_AD_NLATTR,
+ struct sock_filter __code = {
+ .code = BPF_LD|BPF_IMM,
+ .k = sizeof(struct nlmsghdr) + sizeof(struct nfgenmsg),
+ };
+ memcpy(&this[pos], &__code, sizeof(__code));
+ return NEW_POS(__code);
+}
+
+static inline int
+nfct_bsf_find_attr(struct sock_filter *this, int attr, int pos)
+{
+ struct sock_filter __code[] = {
+ [0] = {
+ /* X = attribute type */
+ .code = BPF_LDX|BPF_IMM,
+ .k = attr,
},
- [7] = {
- /* Reject if not found (A == 0) */
+ [1] = {
+ /* A = netlink attribute offset */
+ .code = BPF_LD|BPF_B|BPF_ABS,
+ .k = SKF_AD_OFF + SKF_AD_NLATTR,
+ }
+ };
+ memcpy(&this[pos], __code, sizeof(__code));
+ return NEW_POS(__code);
+}
+
+struct jump {
+ int line;
+ u_int8_t jt;
+ u_int8_t jf;
+};
+
+static inline int
+nfct_bsf_cmp_k_stack(struct sock_filter *this, int k,
+ int jump_true, int pos, struct stack *s)
+{
+ struct sock_filter __code = {
.code = BPF_JMP|BPF_JEQ|BPF_K,
- .k = 0,
- .jt = label - 7 - 1,
- },
- [8] = {
+ .k = k,
+ };
+ struct jump jmp = {
+ .line = pos,
+ .jt = jump_true - 1,
+ .jf = 0,
+ };
+ stack_push(s, &jmp);
+ memcpy(&this[pos], &__code, sizeof(__code));
+ return NEW_POS(__code);
+}
+
+static inline int
+nfct_bsf_alu_and(struct sock_filter *this, int k, int pos)
+{
+ struct sock_filter __code = {
+ .code = BPF_ALU|BPF_AND|BPF_K,
+ .k = k,
+ };
+ memcpy(&this[pos], &__code, sizeof(__code));
+ return NEW_POS(__code);
+}
+
+static inline int
+nfct_bsf_add_attr_data_offset(struct sock_filter *this, int pos)
+{
+ struct sock_filter __code = {
/* A += sizeof(struct nfattr) */
.code = BPF_ALU|BPF_ADD|BPF_K,
.k = sizeof(struct nfattr),
- },
- [9] = {
- /* X = third_type */
- .code = BPF_LDX|BPF_IMM,
- .k = third_type,
- },
- [10] = {
- /* A = netlink attribute offset */
- .code = BPF_LD|BPF_B|BPF_ABS,
- .k = SKF_AD_OFF + SKF_AD_NLATTR,
- },
- [11] = {
- /* Reject if not found (A == 0) */
- .code = BPF_JMP|BPF_JEQ|BPF_K,
- .k = 0,
- .jt = label - 11 - 1,
- },
- [12] = {
- /* X = A */
+ };
+ memcpy(&this[pos], &__code, sizeof(__code));
+ return NEW_POS(__code);
+}
+
+static inline int
+nfct_bsf_x_equal_a(struct sock_filter *this, int pos)
+{
+ struct sock_filter __code = {
.code = BPF_MISC|BPF_TAX,
- },
- [13] = {
+ };
+ memcpy(&this[pos], &__code, sizeof(__code));
+ return NEW_POS(__code);
+}
+
+static inline int
+nfct_bsf_load_attr(struct sock_filter *this, int word_size, int pos)
+{
+ struct sock_filter __code = {
/* A = skb->data[X + k:word_size] */
.code = BPF_LD|word_size|BPF_IND,
.k = sizeof(struct nfattr),
- },
+
};
+ memcpy(&this[pos], &__code, sizeof(__code));
+ return NEW_POS(__code);
+}
- memcpy(this, filter, sizeof(filter));
+static inline int
+nfct_bsf_ret_verdict(struct sock_filter *this, int verdict, int pos)
+{
+ struct sock_filter __code = {
+ .code = BPF_RET|BPF_K,
+ .k = verdict,
+ };
+ memcpy(&this[pos], &__code, sizeof(__code));
+ return NEW_POS(__code);
}
+static inline int
+nfct_bsf_jump_to(struct sock_filter *this, int line, int pos)
+{
+ struct sock_filter __code = {
+ .code = BPF_JMP|BPF_JA,
+ .k = line,
+ };
+ memcpy(&this[pos], &__code, sizeof(__code));
+ return NEW_POS(__code);
+};
+
static int
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)
+ unsigned int logic)
{
- struct sock_filter filter[14 + __FILTER_PROTO_MAX];
- struct sock_filter verdict = {
- /* Reject */
- .code = BPF_RET|BPF_K,
- .k = NFCT_FILTER_REJECT,
- };
unsigned int i, j;
unsigned int label_continue, jt;
+ struct stack *s;
+ struct jump jmp;
- /* calculate the number of filter lines */
- for (i = 0, j = 0; i < sizeof(state_flags) * 8; i++) {
- if (state_flags & (1 << i)) {
- j++;
- }
- }
-
- /* nothing to filter, skip */
- if (j == 0)
- return 0;
-
- if (j + 14 >= __FILTER_PROTO_MAX + 14 || j + 14 > remain) {
- errno = ENOSPC;
+ /* XXX: 32 maximum states + 3 jumps in the three-level iteration */
+ s = stack_create(sizeof(struct jump), 3 + 32);
+ if (s == NULL) {
+ errno = ENOMEM;
return -1;
}
- memset(filter, 0, sizeof(filter));
-
- jt = j + 1;
+ jt = 1;
if (logic == NFCT_FILTER_LOGIC_POSITIVE)
- label_continue = j + 1;
+ label_continue = 1;
else
- label_continue = j + 2;
-
- set_basic_filter(filter,
- CTA_PROTOINFO,
- cta_protoinfo_proto,
- cta_protoinfo_state,
- 14 + label_continue,
- BPF_B);
-
- for (i = 0, j = 0; i < sizeof(state_flags) * 8; i++) {
- struct sock_filter cmp = {
- .code = BPF_JMP|BPF_JEQ|BPF_K,
- .k = i,
- .jt = jt - j - 1,
- };
-
+ label_continue = 2;
+
+ j = 0;
+ j += nfct_bsf_load_payload_offset(this, j);
+ j += nfct_bsf_find_attr(this, CTA_PROTOINFO, j);
+ j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
+ j += nfct_bsf_add_attr_data_offset(this, j);
+ j += nfct_bsf_find_attr(this, cta_protoinfo_proto, j);
+ j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
+ j += nfct_bsf_add_attr_data_offset(this, j);
+ j += nfct_bsf_find_attr(this, cta_protoinfo_state, j);
+ j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
+ j += nfct_bsf_x_equal_a(this, j);
+ j += nfct_bsf_load_attr(this, BPF_B, j);
+
+ for (i = 0; i < sizeof(state_flags) * 8; i++) {
if (state_flags & (1 << i)) {
- memcpy(&filter[j + 14], &cmp, sizeof(cmp));
- j++;
+ j += nfct_bsf_cmp_k_stack(this, i, jt - j, j, s);
}
}
- memcpy(this, filter, sizeof(struct sock_filter) * (j + 14));
+ while (stack_pop(s, &jmp) != -1)
+ this[jmp.line].jt += jmp.jt + j;
- 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++;
- }
+ if (logic == NFCT_FILTER_LOGIC_NEGATIVE)
+ j += nfct_bsf_jump_to(this, 1, j);
- memcpy(&this[j + 14], &verdict, sizeof(verdict));
- j++;
+ j += nfct_bsf_ret_verdict(this, NFCT_FILTER_REJECT, j);
- return j + 14;
+ stack_destroy(s);
+
+ return j;
}
static int
add_state_filter(struct sock_filter *this,
int proto,
u_int16_t flags,
- unsigned int logic,
- size_t remain)
+ unsigned int logic)
{
struct {
unsigned int cta_protoinfo;
@@ -229,25 +247,22 @@ add_state_filter(struct sock_filter *this,
cta[proto].cta_protoinfo,
cta[proto].cta_state,
flags,
- logic,
- remain);
+ logic);
}
static int
-bsf_add_state_filter(const struct nfct_filter *filter,
- struct sock_filter *this,
- size_t remain)
+bsf_add_state_filter(const struct nfct_filter *filter, struct sock_filter *this)
{
unsigned int i, j;
for (i = 0, j = 0; i < IPPROTO_MAX; i++) {
- if (filter->l4proto_state[i].map) {
+ if (filter->l4proto_state[i].map &&
+ filter->l4proto_state[i].len > 0) {
j += add_state_filter(
this,
i,
filter->l4proto_state[i].map,
- filter->logic[NFCT_FILTER_L4PROTO_STATE],
- remain);
+ filter->logic[NFCT_FILTER_L4PROTO_STATE]);
}
}
@@ -255,93 +270,71 @@ bsf_add_state_filter(const struct nfct_filter *filter,
}
static int
-bsf_add_proto_filter(const struct nfct_filter *f,
- struct sock_filter *this,
- size_t remain)
+bsf_add_proto_filter(const struct nfct_filter *f, struct sock_filter *this)
{
- struct sock_filter filter[14 + IPPROTO_MAX];
- struct sock_filter verdict = {
- /* Reject */
- .code = BPF_RET|BPF_K,
- .k = NFCT_FILTER_REJECT,
- };
unsigned int i, j;
unsigned int label_continue, jt;
-
- for (i = 0, j = 0; i < IPPROTO_MAX; i++) {
- if (test_bit(i, f->l4proto_map)) {
- j++;
- }
- }
+ struct stack *s;
+ struct jump jmp;
/* nothing to filter, skip */
- if (j == 0)
+ if (f->l4proto_len == 0)
return 0;
- if (j + 14 >= IPPROTO_MAX + 14 || j + 14 > remain) {
- errno = ENOSPC;
+ /* XXX: 255 maximum proto + 3 jumps in the three-level iteration */
+ s = stack_create(sizeof(struct jump), 3 + 255);
+ if (s == NULL) {
+ errno = ENOMEM;
return -1;
}
- jt = j + 1;
+ jt = 1;
if (f->logic[NFCT_FILTER_L4PROTO] == NFCT_FILTER_LOGIC_POSITIVE)
- label_continue = j + 1;
+ label_continue = 1;
else
- label_continue = j + 2;
-
- memset(filter, 0, sizeof(filter));
-
- set_basic_filter(filter,
- CTA_TUPLE_ORIG,
- CTA_TUPLE_PROTO,
- CTA_PROTO_NUM,
- 14 + label_continue,
- BPF_B);
-
- for (i = 0, j = 0; i < IPPROTO_MAX; i++) {
- struct sock_filter cmp = {
- .code = BPF_JMP|BPF_JEQ|BPF_K,
- .k = i,
- .jt = jt - j - 1,
- };
-
+ label_continue = 2;
+
+ j = 0;
+ j += nfct_bsf_load_payload_offset(this, j);
+ j += nfct_bsf_find_attr(this, CTA_TUPLE_ORIG, j);
+ j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
+ j += nfct_bsf_add_attr_data_offset(this, j);
+ j += nfct_bsf_find_attr(this, CTA_TUPLE_PROTO, j);
+ j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
+ j += nfct_bsf_add_attr_data_offset(this, j);
+ j += nfct_bsf_find_attr(this, CTA_PROTO_NUM, j);
+ j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
+ j += nfct_bsf_x_equal_a(this, j);
+ j += nfct_bsf_load_attr(this, BPF_B, j);
+
+ for (i = 0; i < IPPROTO_MAX; i++) {
if (test_bit(i, f->l4proto_map)) {
- memcpy(&filter[j + 14], &cmp, sizeof(cmp));
- j++;
+ j += nfct_bsf_cmp_k_stack(this, i, jt - j, j, s);
}
}
- memcpy(this, filter, sizeof(struct sock_filter) * (j + 14));
+ while (stack_pop(s, &jmp) != -1)
+ this[jmp.line].jt += jmp.jt + j;
- 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++;
- }
+ if (f->logic[NFCT_FILTER_L4PROTO] == NFCT_FILTER_LOGIC_NEGATIVE)
+ j += nfct_bsf_jump_to(this, 1, j);
+
+ j += nfct_bsf_ret_verdict(this, NFCT_FILTER_REJECT, j);
- memcpy(&this[j + 14], &verdict, sizeof(verdict));
- j++;
+ stack_destroy(s);
- return j + 14;
+ return j;
}
static int
bsf_add_addr_ipv4_filter(const struct nfct_filter *f,
struct sock_filter *this,
- unsigned int type,
- size_t remain)
+ unsigned int type)
{
- struct sock_filter filter[14 + __FILTER_ADDR_MAX];
- struct sock_filter verdict = {
- /* Reject */
- .code = BPF_RET|BPF_K,
- .k = NFCT_FILTER_REJECT,
- };
unsigned int i, j, dir, attr;
unsigned int label_continue, jt;
+ struct stack *s;
+ struct jump jmp;
switch(type) {
case CTA_IP_V4_SRC:
@@ -360,107 +353,89 @@ bsf_add_addr_ipv4_filter(const struct nfct_filter *f,
if (f->l3proto_elems[dir] == 0)
return 0;
- if (f->l3proto_elems[dir] + 14 >= __FILTER_ADDR_MAX + 14 ||
- f->l3proto_elems[dir] + 14 > remain) {
- errno = ENOSPC;
+ /* XXX: 127 maximum IPs + 3 jumps in the three-level iteration */
+ s = stack_create(sizeof(struct jump), 3 + 127);
+ if (s == NULL) {
+ errno = ENOMEM;
return -1;
}
- jt = (f->l3proto_elems[dir] * 2) + 1;
+ jt = 1;
if (f->logic[attr] == NFCT_FILTER_LOGIC_POSITIVE)
- label_continue = (f->l3proto_elems[dir] * 2) + 1;
+ label_continue = 1;
else
- label_continue = (f->l3proto_elems[dir] * 2) + 2;
-
- memset(filter, 0, sizeof(filter));
-
- set_basic_filter(filter,
- CTA_TUPLE_ORIG,
- CTA_TUPLE_IP,
- type,
- 14 + label_continue,
- BPF_W);
-
- for (i = 0, j = 0; i < f->l3proto_elems[dir]; i++) {
- struct sock_filter cmp[] = {
- [0] = {
- .code = BPF_ALU|BPF_AND|BPF_K,
- .k = f->l3proto[dir][i].mask,
- },
- [1] = {
- .code = BPF_JMP|BPF_JEQ|BPF_K,
- .k = f->l3proto[dir][i].addr &
- f->l3proto[dir][i].mask,
- .jt = jt - j - 2,
- },
- };
- memcpy(&filter[j + 14], cmp, sizeof(cmp));
- j+=2;
+ label_continue = 2;
+
+ j = 0;
+ j += nfct_bsf_load_payload_offset(this, j);
+ j += nfct_bsf_find_attr(this, CTA_TUPLE_ORIG, j);
+ j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
+ j += nfct_bsf_add_attr_data_offset(this, j);
+ j += nfct_bsf_find_attr(this, CTA_TUPLE_IP, j);
+ j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
+ j += nfct_bsf_add_attr_data_offset(this, j);
+ j += nfct_bsf_find_attr(this, type, j);
+ j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
+ j += nfct_bsf_x_equal_a(this, j);
+ j += nfct_bsf_load_attr(this, BPF_W, j);
+
+ for (i = 0; i < f->l3proto_elems[dir]; i++) {
+ int ip = f->l3proto[dir][i].addr & f->l3proto[dir][i].mask;
+
+ j += nfct_bsf_alu_and(this, f->l3proto[dir][i].mask, j);
+ j += nfct_bsf_cmp_k_stack(this, ip, jt - j, j, s);
}
- memcpy(this, filter, sizeof(struct sock_filter) * (j + 14));
+ while (stack_pop(s, &jmp) != -1)
+ this[jmp.line].jt += jmp.jt + j;
- 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++;
- }
+ if (f->logic[attr] == NFCT_FILTER_LOGIC_NEGATIVE)
+ j += nfct_bsf_jump_to(this, 1, j);
+
+ j += nfct_bsf_ret_verdict(this, NFCT_FILTER_REJECT, j);
- memcpy(&this[j + 14], &verdict, sizeof(verdict));
- j++;
+ stack_destroy(s);
- return j + 14;
+ return j;
}
static int
-bsf_add_saddr_ipv4_filter(const struct nfct_filter *f,
- struct sock_filter *this,
- size_t remain)
+bsf_add_saddr_ipv4_filter(const struct nfct_filter *f, struct sock_filter *this)
{
- return bsf_add_addr_ipv4_filter(f, this, CTA_IP_V4_SRC, remain);
+ return bsf_add_addr_ipv4_filter(f, this, CTA_IP_V4_SRC);
}
static int
-bsf_add_daddr_ipv4_filter(const struct nfct_filter *f,
- struct sock_filter *this,
- size_t remain)
+bsf_add_daddr_ipv4_filter(const struct nfct_filter *f, struct sock_filter *this)
{
- return bsf_add_addr_ipv4_filter(f, this, CTA_IP_V4_DST, remain);
+ return bsf_add_addr_ipv4_filter(f, this, CTA_IP_V4_DST);
}
/* this buffer must be big enough to store all the autogenerated lines */
-#define BSF_BUFFER_SIZE 1024
+#define BSF_BUFFER_SIZE 2048
int __setup_netlink_socket_filter(int fd, struct nfct_filter *f)
{
struct sock_filter bsf[BSF_BUFFER_SIZE];
- struct sock_filter bsf_accept = {
- /* Accept */
- .code = BPF_RET|BPF_K,
- .k = NFCT_FILTER_ACCEPT,
- };
struct sock_fprog sf;
unsigned int j = 0;
memset(bsf, 0, sizeof(bsf));
- j += bsf_add_proto_filter(f, &bsf[j], BSF_BUFFER_SIZE-j);
- j += bsf_add_saddr_ipv4_filter(f, &bsf[j], BSF_BUFFER_SIZE-j);
- j += bsf_add_daddr_ipv4_filter(f, &bsf[j], BSF_BUFFER_SIZE-j);
- j += bsf_add_state_filter(f, &bsf[j], BSF_BUFFER_SIZE-j);
+ j += bsf_add_proto_filter(f, &bsf[j]);
+ j += bsf_add_saddr_ipv4_filter(f, &bsf[j]);
+ j += bsf_add_daddr_ipv4_filter(f, &bsf[j]);
+ j += bsf_add_state_filter(f, &bsf[j]);
/* nothing to filter, skip */
if (j == 0)
return 0;
- memcpy(&bsf[j], &bsf_accept, sizeof(struct sock_filter));
+ j += nfct_bsf_ret_verdict(bsf, NFCT_FILTER_ACCEPT, j);
- show_filter(bsf, j+1);
+ show_filter(bsf, j);
- sf.len = (sizeof(struct sock_filter) * (j + 1)) / sizeof(bsf[0]);
+ sf.len = (sizeof(struct sock_filter) * j) / sizeof(bsf[0]);
sf.filter = bsf;
return setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &sf, sizeof(sf));
diff --git a/src/conntrack/filter.c b/src/conntrack/filter.c
index 7966e54..7cee673 100644
--- a/src/conntrack/filter.c
+++ b/src/conntrack/filter.c
@@ -9,7 +9,11 @@
static void filter_attr_l4proto(struct nfct_filter *filter, const void *value)
{
+ if (filter->l4proto_len >= __FILTER_L4PROTO_MAX)
+ return;
+
set_bit(*((int *) value), filter->l4proto_map);
+ filter->l4proto_len++;
}
static void
@@ -18,12 +22,16 @@ filter_attr_l4proto_state(struct nfct_filter *filter, const void *value)
const struct nfct_filter_proto *this = value;
set_bit_u16(this->state, &filter->l4proto_state[this->proto].map);
+ filter->l4proto_state[this->proto].len++;
}
static void filter_attr_src_ipv4(struct nfct_filter *filter, const void *value)
{
const struct nfct_filter_ipv4 *this = value;
+ if (filter->l3proto_elems[0] >= __FILTER_ADDR_MAX)
+ return;
+
filter->l3proto[0][filter->l3proto_elems[0]].addr = this->addr;
filter->l3proto[0][filter->l3proto_elems[0]].mask = this->mask;
filter->l3proto_elems[0]++;
@@ -33,6 +41,9 @@ static void filter_attr_dst_ipv4(struct nfct_filter *filter, const void *value)
{
const struct nfct_filter_ipv4 *this = value;
+ if (filter->l3proto_elems[1] >= __FILTER_ADDR_MAX)
+ return;
+
filter->l3proto[1][filter->l3proto_elems[1]].addr = this->addr;
filter->l3proto[1][filter->l3proto_elems[1]].mask = this->mask;
filter->l3proto_elems[1]++;
diff --git a/src/conntrack/stack.c b/src/conntrack/stack.c
new file mode 100644
index 0000000..404e38b
--- /dev/null
+++ b/src/conntrack/stack.c
@@ -0,0 +1,67 @@
+/*
+ * (C) 2008 by Pablo Neira Ayuso <pablo@netfilter.org>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "internal/stack.h"
+
+struct stack {
+ int num_elems;
+ int max_elems;
+ size_t elem_size;
+ char *data;
+};
+
+struct stack *stack_create(size_t elem_size, int max_elems)
+{
+ struct stack *s;
+
+ s = calloc(sizeof(struct stack), 1);
+ if (s == NULL)
+ return NULL;
+
+ s->data = calloc(elem_size * max_elems, 1);
+ if (s->data == NULL) {
+ free(s);
+ return NULL;
+ }
+ s->elem_size = elem_size;
+ s->max_elems = max_elems;
+
+ return s;
+}
+
+void stack_destroy(struct stack *s)
+{
+ free(s->data);
+ free(s);
+}
+
+int stack_push(struct stack *s, void *data)
+{
+ if (s->num_elems >= s->max_elems) {
+ errno = ENOSPC;
+ return -1;
+ }
+ memcpy(s->data + (s->elem_size * s->num_elems), data, s->elem_size);
+ s->num_elems++;
+ return 0;
+}
+
+int stack_pop(struct stack *s, void *data)
+{
+ if (s->num_elems <= 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ s->num_elems--;
+ memcpy(data, s->data + (s->elem_size * s->num_elems), s->elem_size);
+ return 0;
+}