diff options
author | Alexander Wirt <formorer@debian.org> | 2012-06-03 08:49:55 +0200 |
---|---|---|
committer | Alexander Wirt <formorer@debian.org> | 2012-06-03 08:49:55 +0200 |
commit | ea27bb406e3d8fe9466ba274af38e6f540ff5bfc (patch) | |
tree | 9f0c78416f8b617d6af715800ce22815645ee8ec /src/parse.c | |
parent | ed902b39d4f4aa2fc8130441d25b849a69b75c15 (diff) | |
download | conntrack-tools-ea27bb406e3d8fe9466ba274af38e6f540ff5bfc.tar.gz conntrack-tools-ea27bb406e3d8fe9466ba274af38e6f540ff5bfc.zip |
Imported Upstream version 1.2.1
Diffstat (limited to 'src/parse.c')
-rw-r--r-- | src/parse.c | 524 |
1 files changed, 524 insertions, 0 deletions
diff --git a/src/parse.c b/src/parse.c new file mode 100644 index 0000000..732bc44 --- /dev/null +++ b/src/parse.c @@ -0,0 +1,524 @@ +/* + * (C) 2006-2011 by Pablo Neira Ayuso <pablo@netfilter.org> + * (C) 2011 by Vyatta Inc. <http://www.vyatta.com> + * + * 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "network.h" + +#include <libnetfilter_conntrack/libnetfilter_conntrack.h> + +#ifndef ssizeof +#define ssizeof(x) (int)sizeof(x) +#endif + +static void ct_parse_u8(struct nf_conntrack *ct, int attr, void *data); +static void ct_parse_u16(struct nf_conntrack *ct, int attr, void *data); +static void ct_parse_u32(struct nf_conntrack *ct, int attr, void *data); +static void ct_parse_str(struct nf_conntrack *ct, int attr, void *data); +static void ct_parse_group(struct nf_conntrack *ct, int attr, void *data); +static void ct_parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data); + +struct ct_parser { + void (*parse)(struct nf_conntrack *ct, int attr, void *data); + int attr; + int size; + int max_size; +}; + +static struct ct_parser h[NTA_MAX] = { + [NTA_IPV4] = { + .parse = ct_parse_group, + .attr = ATTR_GRP_ORIG_IPV4, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv4)), + }, + [NTA_IPV6] = { + .parse = ct_parse_group, + .attr = ATTR_GRP_ORIG_IPV6, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv6)), + }, + [NTA_PORT] = { + .parse = ct_parse_group, + .attr = ATTR_GRP_ORIG_PORT, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_port)), + }, + [NTA_L4PROTO] = { + .parse = ct_parse_u8, + .attr = ATTR_L4PROTO, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_TCP_STATE] = { + .parse = ct_parse_u8, + .attr = ATTR_TCP_STATE, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_STATUS] = { + .parse = ct_parse_u32, + .attr = ATTR_STATUS, + .size = NTA_SIZE(sizeof(uint32_t)), + }, + [NTA_MARK] = { + .parse = ct_parse_u32, + .attr = ATTR_MARK, + .size = NTA_SIZE(sizeof(uint32_t)), + }, + [NTA_TIMEOUT] = { + .parse = ct_parse_u32, + .attr = ATTR_TIMEOUT, + .size = NTA_SIZE(sizeof(uint32_t)), + }, + [NTA_MASTER_IPV4] = { + .parse = ct_parse_group, + .attr = ATTR_GRP_MASTER_IPV4, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv4)), + }, + [NTA_MASTER_IPV6] = { + .parse = ct_parse_group, + .attr = ATTR_GRP_MASTER_IPV6, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv6)), + }, + [NTA_MASTER_L4PROTO] = { + .parse = ct_parse_u8, + .attr = ATTR_MASTER_L4PROTO, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_MASTER_PORT] = { + .parse = ct_parse_group, + .attr = ATTR_GRP_MASTER_PORT, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_port)), + }, + [NTA_SNAT_IPV4] = { + .parse = ct_parse_u32, + .attr = ATTR_SNAT_IPV4, + .size = NTA_SIZE(sizeof(uint32_t)), + }, + [NTA_DNAT_IPV4] = { + .parse = ct_parse_u32, + .attr = ATTR_DNAT_IPV4, + .size = NTA_SIZE(sizeof(uint32_t)), + }, + [NTA_SPAT_PORT] = { + .parse = ct_parse_u16, + .attr = ATTR_SNAT_PORT, + .size = NTA_SIZE(sizeof(uint16_t)), + }, + [NTA_DPAT_PORT] = { + .parse = ct_parse_u16, + .attr = ATTR_DNAT_PORT, + .size = NTA_SIZE(sizeof(uint16_t)), + }, + [NTA_NAT_SEQ_ADJ] = { + .parse = ct_parse_nat_seq_adj, + .size = NTA_SIZE(sizeof(struct nta_attr_natseqadj)), + }, + [NTA_SCTP_STATE] = { + .parse = ct_parse_u8, + .attr = ATTR_SCTP_STATE, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_SCTP_VTAG_ORIG] = { + .parse = ct_parse_u32, + .attr = ATTR_SCTP_VTAG_ORIG, + .size = NTA_SIZE(sizeof(uint32_t)), + }, + [NTA_SCTP_VTAG_REPL] = { + .parse = ct_parse_u32, + .attr = ATTR_SCTP_VTAG_REPL, + .size = NTA_SIZE(sizeof(uint32_t)), + }, + [NTA_DCCP_STATE] = { + .parse = ct_parse_u8, + .attr = ATTR_DCCP_STATE, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_DCCP_ROLE] = { + .parse = ct_parse_u8, + .attr = ATTR_DCCP_ROLE, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_ICMP_TYPE] = { + .parse = ct_parse_u8, + .attr = ATTR_ICMP_TYPE, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_ICMP_CODE] = { + .parse = ct_parse_u8, + .attr = ATTR_ICMP_CODE, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_ICMP_ID] = { + .parse = ct_parse_u16, + .attr = ATTR_ICMP_ID, + .size = NTA_SIZE(sizeof(uint16_t)), + }, + [NTA_TCP_WSCALE_ORIG] = { + .parse = ct_parse_u8, + .attr = ATTR_TCP_WSCALE_ORIG, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_TCP_WSCALE_REPL] = { + .parse = ct_parse_u8, + .attr = ATTR_TCP_WSCALE_REPL, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_HELPER_NAME] = { + .parse = ct_parse_str, + .attr = ATTR_HELPER_NAME, + .max_size = NFCT_HELPER_NAME_MAX, + }, +}; + +static void +ct_parse_u8(struct nf_conntrack *ct, int attr, void *data) +{ + uint8_t *value = (uint8_t *) data; + nfct_set_attr_u8(ct, h[attr].attr, *value); +} + +static void +ct_parse_u16(struct nf_conntrack *ct, int attr, void *data) +{ + uint16_t *value = (uint16_t *) data; + nfct_set_attr_u16(ct, h[attr].attr, ntohs(*value)); +} + +static void +ct_parse_u32(struct nf_conntrack *ct, int attr, void *data) +{ + uint32_t *value = (uint32_t *) data; + nfct_set_attr_u32(ct, h[attr].attr, ntohl(*value)); +} + +static void +ct_parse_str(struct nf_conntrack *ct, int attr, void *data) +{ + nfct_set_attr(ct, h[attr].attr, data); +} + +static void +ct_parse_group(struct nf_conntrack *ct, int attr, void *data) +{ + nfct_set_attr_grp(ct, h[attr].attr, data); +} + +static void +ct_parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data) +{ + struct nta_attr_natseqadj *this = data; + nfct_set_attr_u32(ct, ATTR_ORIG_NAT_SEQ_CORRECTION_POS, + ntohl(this->orig_seq_correction_pos)); + nfct_set_attr_u32(ct, ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE, + ntohl(this->orig_seq_offset_before)); + nfct_set_attr_u32(ct, ATTR_ORIG_NAT_SEQ_OFFSET_AFTER, + ntohl(this->orig_seq_offset_after)); + nfct_set_attr_u32(ct, ATTR_REPL_NAT_SEQ_CORRECTION_POS, + ntohl(this->repl_seq_correction_pos)); + nfct_set_attr_u32(ct, ATTR_REPL_NAT_SEQ_OFFSET_BEFORE, + ntohl(this->repl_seq_offset_before)); + nfct_set_attr_u32(ct, ATTR_REPL_NAT_SEQ_OFFSET_AFTER, + ntohl(this->repl_seq_offset_after)); +} + +int msg2ct(struct nf_conntrack *ct, struct nethdr *net, size_t remain) +{ + int len; + struct netattr *attr; + + if (remain < net->len) + return -1; + + len = net->len - NETHDR_SIZ; + attr = NETHDR_DATA(net); + + while (len > ssizeof(struct netattr)) { + ATTR_NETWORK2HOST(attr); + if (attr->nta_len > len) + return -1; + if (attr->nta_attr > NTA_MAX) + return -1; + if (h[attr->nta_attr].size && + attr->nta_len != h[attr->nta_attr].size) + return -1; + if (h[attr->nta_attr].max_size && + attr->nta_len > h[attr->nta_attr].max_size) + return -1; + if (h[attr->nta_attr].parse == NULL) { + attr = NTA_NEXT(attr, len); + continue; + } + h[attr->nta_attr].parse(ct, attr->nta_attr, NTA_DATA(attr)); + attr = NTA_NEXT(attr, len); + } + + return 0; +} + +static void exp_parse_ct_group(void *ct, int attr, void *data); +static void exp_parse_ct_u8(void *ct, int attr, void *data); +static void exp_parse_u32(void *exp, int attr, void *data); +static void exp_parse_str(void *exp, int attr, void *data); + +static struct exp_parser { + void (*parse)(void *obj, int attr, void *data); + int exp_attr; + int ct_attr; + int size; + int max_size; +} exp_h[NTA_EXP_MAX] = { + [NTA_EXP_MASTER_IPV4] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_MASTER, + .ct_attr = ATTR_GRP_ORIG_IPV4, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv4)), + }, + [NTA_EXP_MASTER_IPV6] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_MASTER, + .ct_attr = ATTR_GRP_ORIG_IPV6, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv6)), + }, + [NTA_EXP_MASTER_L4PROTO] = { + .parse = exp_parse_ct_u8, + .exp_attr = ATTR_EXP_MASTER, + .ct_attr = ATTR_L4PROTO, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_EXP_MASTER_PORT] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_MASTER, + .ct_attr = ATTR_GRP_ORIG_PORT, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_port)), + }, + [NTA_EXP_EXPECT_IPV4] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_EXPECTED, + .ct_attr = ATTR_GRP_ORIG_IPV4, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv4)), + }, + [NTA_EXP_EXPECT_IPV6] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_EXPECTED, + .ct_attr = ATTR_GRP_ORIG_IPV6, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv6)), + }, + [NTA_EXP_EXPECT_L4PROTO] = { + .parse = exp_parse_ct_u8, + .exp_attr = ATTR_EXP_EXPECTED, + .ct_attr = ATTR_L4PROTO, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_EXP_EXPECT_PORT] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_EXPECTED, + .ct_attr = ATTR_GRP_ORIG_PORT, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_port)), + }, + [NTA_EXP_MASK_IPV4] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_MASK, + .ct_attr = ATTR_GRP_ORIG_IPV4, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv4)), + }, + [NTA_EXP_MASK_IPV6] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_MASK, + .ct_attr = ATTR_GRP_ORIG_IPV6, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv6)), + }, + [NTA_EXP_MASK_L4PROTO] = { + .parse = exp_parse_ct_u8, + .exp_attr = ATTR_EXP_MASK, + .ct_attr = ATTR_L4PROTO, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_EXP_MASK_PORT] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_MASK, + .ct_attr = ATTR_GRP_ORIG_PORT, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_port)), + }, + [NTA_EXP_TIMEOUT] = { + .parse = exp_parse_u32, + .exp_attr = ATTR_EXP_TIMEOUT, + .size = NTA_SIZE(sizeof(uint32_t)), + }, + [NTA_EXP_FLAGS] = { + .parse = exp_parse_u32, + .exp_attr = ATTR_EXP_FLAGS, + .size = NTA_SIZE(sizeof(uint32_t)), + }, + [NTA_EXP_CLASS] = { + .parse = exp_parse_u32, + .exp_attr = ATTR_EXP_CLASS, + .size = NTA_SIZE(sizeof(uint32_t)), + }, + [NTA_EXP_NAT_IPV4] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_NAT_TUPLE, + .ct_attr = ATTR_GRP_ORIG_IPV4, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv4)), + }, + [NTA_EXP_NAT_L4PROTO] = { + .parse = exp_parse_ct_u8, + .exp_attr = ATTR_EXP_NAT_TUPLE, + .ct_attr = ATTR_L4PROTO, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_EXP_NAT_PORT] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_NAT_TUPLE, + .ct_attr = ATTR_GRP_ORIG_PORT, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_port)), + }, + [NTA_EXP_NAT_DIR] = { + .parse = exp_parse_u32, + .exp_attr = ATTR_EXP_NAT_DIR, + .size = NTA_SIZE(sizeof(uint32_t)), + }, + [NTA_EXP_HELPER_NAME] = { + .parse = exp_parse_str, + .exp_attr = ATTR_EXP_HELPER_NAME, + .max_size = NFCT_HELPER_NAME_MAX, + }, + [NTA_EXP_FN] = { + .parse = exp_parse_str, + .exp_attr = ATTR_EXP_FN, + .max_size = NFCT_HELPER_NAME_MAX, + }, +}; + +static void exp_parse_ct_group(void *ct, int attr, void *data) +{ + nfct_set_attr_grp(ct, exp_h[attr].ct_attr, data); +} + +static void exp_parse_ct_u8(void *ct, int attr, void *data) +{ + uint8_t *value = (uint8_t *) data; + nfct_set_attr_u8(ct, exp_h[attr].ct_attr, *value); +} + +static void exp_parse_u32(void *exp, int attr, void *data) +{ + uint32_t *value = (uint32_t *) data; + nfexp_set_attr_u32(exp, exp_h[attr].exp_attr, ntohl(*value)); +} + +static void exp_parse_str(void *exp, int attr, void *data) +{ + nfexp_set_attr(exp, exp_h[attr].exp_attr, data); +} + +int msg2exp(struct nf_expect *exp, struct nethdr *net, size_t remain) +{ + int len; + struct netattr *attr; + struct nf_conntrack *master, *expected, *mask, *nat; + + if (remain < net->len) + return -1; + + len = net->len - NETHDR_SIZ; + attr = NETHDR_DATA(net); + + master = nfct_new(); + if (master == NULL) + goto err_master; + + expected = nfct_new(); + if (expected == NULL) + goto err_expected; + + mask = nfct_new(); + if (mask == NULL) + goto err_mask; + + nat = nfct_new(); + if (nat == NULL) + goto err_nat; + + while (len > ssizeof(struct netattr)) { + ATTR_NETWORK2HOST(attr); + if (attr->nta_len > len) + goto err; + if (attr->nta_attr > NTA_MAX) + goto err; + if (exp_h[attr->nta_attr].size && + attr->nta_len != exp_h[attr->nta_attr].size) + goto err; + if (exp_h[attr->nta_attr].max_size && + attr->nta_len > exp_h[attr->nta_attr].max_size) + goto err; + if (exp_h[attr->nta_attr].parse == NULL) { + attr = NTA_NEXT(attr, len); + continue; + } + switch(exp_h[attr->nta_attr].exp_attr) { + case ATTR_EXP_MASTER: + exp_h[attr->nta_attr].parse(master, attr->nta_attr, + NTA_DATA(attr)); + case ATTR_EXP_EXPECTED: + exp_h[attr->nta_attr].parse(expected, attr->nta_attr, + NTA_DATA(attr)); + case ATTR_EXP_MASK: + exp_h[attr->nta_attr].parse(mask, attr->nta_attr, + NTA_DATA(attr)); + break; + case ATTR_EXP_NAT_TUPLE: + exp_h[attr->nta_attr].parse(nat, attr->nta_attr, + NTA_DATA(attr)); + nfexp_set_attr(exp, ATTR_EXP_NAT_TUPLE, nat); + break; + case ATTR_EXP_TIMEOUT: + case ATTR_EXP_FLAGS: + case ATTR_EXP_CLASS: + case ATTR_EXP_HELPER_NAME: + case ATTR_EXP_NAT_DIR: + case ATTR_EXP_FN: + exp_h[attr->nta_attr].parse(exp, attr->nta_attr, + NTA_DATA(attr)); + break; + } + attr = NTA_NEXT(attr, len); + } + + nfexp_set_attr(exp, ATTR_EXP_MASTER, master); + nfexp_set_attr(exp, ATTR_EXP_EXPECTED, expected); + nfexp_set_attr(exp, ATTR_EXP_MASK, mask); + + /* We can release the conntrack objects at this point because the + * setter makes a copy of them. This is not efficient, it would be + * better to save that extra copy but this is how the library works. + * I'm sorry, I cannot change it without breaking backward + * compatibility. Probably it is a good idea to think of adding new + * interfaces in the near future to get it better. */ + nfct_destroy(mask); + nfct_destroy(expected); + nfct_destroy(master); + nfct_destroy(nat); + + return 0; +err: + nfct_destroy(nat); +err_nat: + nfct_destroy(mask); +err_mask: + nfct_destroy(expected); +err_expected: + nfct_destroy(master); +err_master: + return -1; +} |