diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2012-08-03 17:31:48 +0200 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2012-10-11 15:15:02 +0200 |
commit | 00c179b4c9f9f9394cc6f79e5f2a68410631fd72 (patch) | |
tree | 00057636d125f3c89e2b9485c67c4283a98d91b2 /src/expr/data_reg.c |
initial version of libnftables
It adds support for table, chain and rule handling.
This also includes expression handling for each rule.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src/expr/data_reg.c')
-rw-r--r-- | src/expr/data_reg.c | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/src/expr/data_reg.c b/src/expr/data_reg.c new file mode 100644 index 0000000..5b14695 --- /dev/null +++ b/src/expr/data_reg.c @@ -0,0 +1,158 @@ +/* + * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org> + * + * 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 <http://www.sophos.com> + */ + +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <arpa/inet.h> + +#include <libmnl/libmnl.h> +#include <linux/netfilter.h> +#include <linux/netfilter/nf_tables.h> +#include <libnftables/expr.h> +#include "expr_ops.h" +#include "data_reg.h" +#include "internal.h" + +static int nft_data_parse_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_DATA_MAX) < 0) + return MNL_CB_OK; + + switch(type) { + case NFTA_DATA_VALUE: + if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + case NFTA_DATA_VERDICT: + if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + } + tb[type] = attr; + return MNL_CB_OK; +} + +static int nft_verdict_parse_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_VERDICT_MAX) < 0) + return MNL_CB_OK; + + switch(type) { + case NFTA_VERDICT_CODE: + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + case NFTA_VERDICT_CHAIN: + if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + } + tb[type] = attr; + return MNL_CB_OK; +} + +static int +nft_parse_verdict(union nft_data_reg *data, const struct nlattr *attr, int *type) +{ + struct nlattr *tb[NFTA_VERDICT_MAX+1]; + + if (mnl_attr_parse_nested(attr, nft_verdict_parse_cb, tb) < 0) { + perror("mnl_attr_parse_nested"); + return -1; + } + + if (!tb[NFTA_VERDICT_CODE]) + return -1; + + data->verdict = ntohl(mnl_attr_get_u32(tb[NFTA_VERDICT_CODE])); + + switch(data->verdict) { + case NF_ACCEPT: + case NF_DROP: + case NF_QUEUE: + case NFT_CONTINUE: + case NFT_BREAK: + case NFT_RETURN: + if (type) + *type = DATA_VERDICT; + data->len = sizeof(data->verdict); + break; + case NFT_JUMP: + case NFT_GOTO: + if (!tb[NFTA_VERDICT_CHAIN]) + return -1; + + data->chain = strdup(mnl_attr_get_str(tb[NFTA_VERDICT_CHAIN])); + if (type) + *type = DATA_CHAIN; + break; + default: + return -1; + } + + return 0; +} + +static int +__nft_parse_data(union nft_data_reg *data, const struct nlattr *attr) +{ + void *orig = mnl_attr_get_payload(attr); + size_t data_len = mnl_attr_get_payload_len(attr); + + if (data_len == 0) + return -1; + + if (data_len > sizeof(uint32_t) * 4) + return -1; + + memcpy(data->val, orig, data_len); + data->len = data_len; + + return 0; +} + +int nft_parse_data(union nft_data_reg *data, struct nlattr *attr, int *type) +{ + struct nlattr *tb[NFTA_DATA_MAX+1] = {}; + int ret = 0; + + if (mnl_attr_parse_nested(attr, nft_data_parse_cb, tb) < 0) { + perror("mnl_attr_parse_nested"); + return -1; + } + if (tb[NFTA_DATA_VALUE]) { + if (type) + *type = DATA_VALUE; + + ret = __nft_parse_data(data, tb[NFTA_DATA_VALUE]); + if (ret < 0) + return ret; + } + if (tb[NFTA_DATA_VERDICT]) + ret = nft_parse_verdict(data, tb[NFTA_DATA_VERDICT], type); + + return ret; +} |