From b1c5141ca0ea40f0321cc8fad0bb6ef657547c2e Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 28 Oct 2012 18:07:14 +0100 Subject: expr: add bitwise Signed-off-by: Pablo Neira Ayuso --- include/libnftables/expr.h | 8 ++ src/Makefile.am | 1 + src/expr/bitwise.c | 235 +++++++++++++++++++++++++++++++++++++++++++++ src/expr_ops.c | 2 + 4 files changed, 246 insertions(+) create mode 100644 src/expr/bitwise.c diff --git a/include/libnftables/expr.h b/include/libnftables/expr.h index 09cd2e0..cddfbcf 100644 --- a/include/libnftables/expr.h +++ b/include/libnftables/expr.h @@ -61,6 +61,14 @@ enum { NFT_EXPR_CTR_BYTES, }; +enum { + NFT_EXPR_BITWISE_SREG = NFT_RULE_EXPR_ATTR_BASE, + NFT_EXPR_BITWISE_DREG, + NFT_EXPR_BITWISE_LEN, + NFT_EXPR_BITWISE_MASK, + NFT_EXPR_BITWISE_XOR, +}; + enum { NFT_EXPR_TG_NAME = NFT_RULE_EXPR_ATTR_BASE, NFT_EXPR_TG_REV, diff --git a/src/Makefile.am b/src/Makefile.am index b1c1044..4cca790 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,6 +9,7 @@ libnftables_la_SOURCES = table.c \ rule.c \ expr.c \ expr_ops.c \ + expr/bitwise.c \ expr/cmp.c \ expr/counter.c \ expr/data_reg.c \ diff --git a/src/expr/bitwise.c b/src/expr/bitwise.c new file mode 100644 index 0000000..8275758 --- /dev/null +++ b/src/expr/bitwise.c @@ -0,0 +1,235 @@ +/* + * (C) 2012 by Pablo Neira Ayuso + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This code has been sponsored by Sophos Astaro + */ + +#include "internal.h" + +#include +#include +#include /* for memcpy */ +#include +#include +#include +#include +#include "data_reg.h" +#include "expr_ops.h" + +struct nft_expr_bitwise { + enum nft_registers sreg; + enum nft_registers dreg; + unsigned int len; + union nft_data_reg mask; + union nft_data_reg xor; +}; + +static int +nft_rule_expr_bitwise_set(struct nft_rule_expr *e, uint16_t type, + const void *data, size_t data_len) +{ + struct nft_expr_bitwise *bitwise = (struct nft_expr_bitwise *)e->data; + + switch(type) { + case NFT_EXPR_BITWISE_SREG: + bitwise->sreg = *((uint32_t *)data); + break; + case NFT_EXPR_BITWISE_DREG: + bitwise->dreg = *((uint32_t *)data); + break; + case NFT_EXPR_BITWISE_LEN: + bitwise->len = *((unsigned int *)data); + break; + case NFT_EXPR_BITWISE_MASK: + memcpy(&bitwise->mask.val, data, data_len); + bitwise->mask.len = data_len; + break; + case NFT_EXPR_BITWISE_XOR: + memcpy(&bitwise->xor.val, data, data_len); + bitwise->xor.len = data_len; + break; + default: + return -1; + } + return 0; +} + +static const void * +nft_rule_expr_bitwise_get(struct nft_rule_expr *e, uint16_t type, size_t *data_len) +{ + struct nft_expr_bitwise *bitwise = (struct nft_expr_bitwise *)e->data; + + switch(type) { + case NFT_EXPR_BITWISE_SREG: + if (e->flags & (1 << NFT_EXPR_BITWISE_SREG)) { + *data_len = sizeof(bitwise->sreg); + return &bitwise->sreg; + } + break; + case NFT_EXPR_BITWISE_DREG: + if (e->flags & (1 << NFT_EXPR_BITWISE_DREG)) { + *data_len = sizeof(bitwise->dreg); + return &bitwise->dreg; + } + break; + case NFT_EXPR_BITWISE_LEN: + if (e->flags & (1 << NFT_EXPR_BITWISE_LEN)) { + *data_len = sizeof(bitwise->len); + return &bitwise->len; + } + break; + case NFT_EXPR_BITWISE_MASK: + if (e->flags & (1 << NFT_EXPR_BITWISE_MASK)) { + *data_len = bitwise->mask.len; + return &bitwise->mask.val; + } + break; + case NFT_EXPR_BITWISE_XOR: + if (e->flags & (1 << NFT_EXPR_BITWISE_XOR)) { + *data_len = bitwise->xor.len; + return &bitwise->xor.val; + } + break; + default: + break; + } + return NULL; +} + +static int nft_rule_expr_bitwise_cb(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = data; + int type = mnl_attr_get_type(attr); + + if (mnl_attr_type_valid(attr, NFTA_BITWISE_MAX) < 0) + return MNL_CB_OK; + + switch(type) { + case NFTA_BITWISE_SREG: + case NFTA_BITWISE_DREG: + case NFTA_BITWISE_LEN: + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + case NFTA_BITWISE_MASK: + case NFTA_BITWISE_XOR: + if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + } + + tb[type] = attr; + return MNL_CB_OK; +} + +static void +nft_rule_expr_bitwise_build(struct nlmsghdr *nlh, struct nft_rule_expr *e) +{ + struct nft_expr_bitwise *bitwise = (struct nft_expr_bitwise *)e->data; + + if (e->flags & (1 << NFT_EXPR_BITWISE_SREG)) + mnl_attr_put_u32(nlh, NFTA_BITWISE_SREG, htonl(bitwise->sreg)); + if (e->flags & (1 << NFT_EXPR_BITWISE_DREG)) + mnl_attr_put_u32(nlh, NFTA_BITWISE_DREG, htonl(bitwise->dreg)); + if (e->flags & (1 << NFT_EXPR_BITWISE_LEN)) + mnl_attr_put_u32(nlh, NFTA_BITWISE_LEN, htonl(bitwise->len)); + if (e->flags & (1 << NFT_EXPR_BITWISE_MASK)) { + struct nlattr *nest; + + nest = mnl_attr_nest_start(nlh, NFTA_BITWISE_MASK); + mnl_attr_put(nlh, NFTA_DATA_VALUE, bitwise->mask.len, + bitwise->mask.val); + mnl_attr_nest_end(nlh, nest); + } + if (e->flags & (1 << NFT_EXPR_BITWISE_XOR)) { + struct nlattr *nest; + + nest = mnl_attr_nest_start(nlh, NFTA_BITWISE_XOR); + mnl_attr_put(nlh, NFTA_DATA_VALUE, bitwise->xor.len, + bitwise->xor.val); + mnl_attr_nest_end(nlh, nest); + } +} + +static int +nft_rule_expr_bitwise_parse(struct nft_rule_expr *e, struct nlattr *attr) +{ + struct nft_expr_bitwise *bitwise = (struct nft_expr_bitwise *)e->data; + struct nlattr *tb[NFTA_BITWISE_MAX+1] = {}; + int ret = 0; + + if (mnl_attr_parse_nested(attr, nft_rule_expr_bitwise_cb, tb) < 0) + return -1; + + if (tb[NFTA_BITWISE_SREG]) { + bitwise->sreg = ntohl(mnl_attr_get_u32(tb[NFTA_BITWISE_SREG])); + e->flags |= (1 << NFT_EXPR_BITWISE_SREG); + } + if (tb[NFTA_BITWISE_DREG]) { + bitwise->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_BITWISE_DREG])); + e->flags |= (1 << NFT_EXPR_BITWISE_DREG); + } + if (tb[NFTA_BITWISE_LEN]) { + bitwise->len = ntohl(mnl_attr_get_u32(tb[NFTA_BITWISE_LEN])); + e->flags |= (1 << NFT_EXPR_BITWISE_LEN); + } + if (tb[NFTA_BITWISE_MASK]) { + ret = nft_parse_data(&bitwise->mask, tb[NFTA_BITWISE_MASK], NULL); + e->flags |= (1 << NFTA_BITWISE_MASK); + } + if (tb[NFTA_BITWISE_XOR]) { + ret = nft_parse_data(&bitwise->xor, tb[NFTA_BITWISE_XOR], NULL); + e->flags |= (1 << NFTA_BITWISE_XOR); + } + + return ret; +} + +static int +nft_rule_expr_bitwise_snprintf(char *buf, size_t size, struct nft_rule_expr *e) +{ + struct nft_expr_bitwise *bitwise = (struct nft_expr_bitwise *)e->data; + int len = size, offset = 0, ret, i; + + ret = snprintf(buf, len, "sreg=%u dreg=%u ", + bitwise->sreg, bitwise->dreg); + SNPRINTF_BUFFER_SIZE(ret, size, len, offset); + + ret = snprintf(buf+offset, len, " mask="); + SNPRINTF_BUFFER_SIZE(ret, size, len, offset); + + for (i=0; imask.len/sizeof(uint32_t); i++) { + ret = snprintf(buf+offset, len, "%.8x ", bitwise->mask.val[i]); + SNPRINTF_BUFFER_SIZE(ret, size, len, offset); + } + + ret = snprintf(buf+offset, len, " xor="); + SNPRINTF_BUFFER_SIZE(ret, size, len, offset); + + for (i=0; ixor.len/sizeof(uint32_t); i++) { + ret = snprintf(buf+offset, len, "%.8x ", bitwise->xor.val[i]); + SNPRINTF_BUFFER_SIZE(ret, size, len, offset); + } + + return offset; +} + +struct expr_ops expr_ops_bitwise = { + .name = "bitwise", + .alloc_len = sizeof(struct nft_expr_bitwise), + .max_attr = NFTA_BITWISE_MAX, + .set = nft_rule_expr_bitwise_set, + .get = nft_rule_expr_bitwise_get, + .parse = nft_rule_expr_bitwise_parse, + .build = nft_rule_expr_bitwise_build, + .snprintf = nft_rule_expr_bitwise_snprintf, +}; diff --git a/src/expr_ops.c b/src/expr_ops.c index 2b21d96..9d121a0 100644 --- a/src/expr_ops.c +++ b/src/expr_ops.c @@ -2,6 +2,7 @@ #include "expr_ops.h" +extern struct expr_ops expr_ops_bitwise; extern struct expr_ops expr_ops_cmp; extern struct expr_ops expr_ops_counter; extern struct expr_ops expr_ops_immediate; @@ -11,6 +12,7 @@ extern struct expr_ops expr_ops_payload; extern struct expr_ops expr_ops_target; struct expr_ops *expr_ops[] = { + &expr_ops_bitwise, &expr_ops_cmp, &expr_ops_counter, &expr_ops_immediate, -- cgit v1.2.3