From 20cd0222c910e96c378e091e64b71d26e48916fe Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 26 Apr 2012 19:37:03 +0200 Subject: conntrack: add nfct_set_attr_l and ATTR_HELPER_INFO This adds the ATTR_HELPER_INFO that can be used to send binary data that will be attached to the conntrack. This is useful for the user-space connection tracking support. This patch also adds a new interface: nfct_set_attr_l(attr, type, value, length); that is used to set the variable length helper information. Signed-off-by: Pablo Neira Ayuso --- src/conntrack/api.c | 45 +++++++---- src/conntrack/build_mnl.c | 5 ++ src/conntrack/copy.c | 17 +++++ src/conntrack/getter.c | 6 ++ src/conntrack/parse_mnl.c | 12 +++ src/conntrack/setter.c | 191 ++++++++++++++++++++++++++++++++-------------- 6 files changed, 204 insertions(+), 72 deletions(-) (limited to 'src') diff --git a/src/conntrack/api.c b/src/conntrack/api.c index 202b85d..000571f 100644 --- a/src/conntrack/api.c +++ b/src/conntrack/api.c @@ -93,6 +93,8 @@ void nfct_destroy(struct nf_conntrack *ct) assert(ct != NULL); if (ct->secctx) free(ct->secctx); + if (ct->helper_info) + free(ct->helper_info); free(ct); ct = NULL; /* bugtrap */ } @@ -351,6 +353,29 @@ void nfct_callback_unregister2(struct nfct_handle *h) * @{ */ +/** + * nfct_set_attr_l - set the value of a certain conntrack attribute + * \param ct pointer to a valid conntrack + * \param type attribute type + * \param pointer to attribute value + * \param length of attribute value (in bytes) + */ +void +nfct_set_attr_l(struct nf_conntrack *ct, const enum nf_conntrack_attr type, + const void *value, size_t len) +{ + assert(ct != NULL); + assert(value != NULL); + + if (unlikely(type >= ATTR_MAX)) + return; + + if (set_attr_array[type]) { + set_attr_array[type](ct, value, len); + set_bit(type, ct->head.set); + } +} + /** * nfct_set_attr - set the value of a certain conntrack attribute * \param ct pointer to a valid conntrack @@ -369,16 +394,8 @@ void nfct_set_attr(struct nf_conntrack *ct, const enum nf_conntrack_attr type, const void *value) { - assert(ct != NULL); - assert(value != NULL); - - if (unlikely(type >= ATTR_MAX)) - return; - - if (set_attr_array[type]) { - set_attr_array[type](ct, value); - set_bit(type, ct->head.set); - } + /* We assume the setter knows the size of the passed pointer. */ + nfct_set_attr_l(ct, type, value, 0); } /** @@ -391,7 +408,7 @@ void nfct_set_attr_u8(struct nf_conntrack *ct, const enum nf_conntrack_attr type, u_int8_t value) { - nfct_set_attr(ct, type, &value); + nfct_set_attr_l(ct, type, &value, sizeof(u_int8_t)); } /** @@ -404,7 +421,7 @@ void nfct_set_attr_u16(struct nf_conntrack *ct, const enum nf_conntrack_attr type, u_int16_t value) { - nfct_set_attr(ct, type, &value); + nfct_set_attr_l(ct, type, &value, sizeof(u_int16_t)); } /** @@ -417,7 +434,7 @@ void nfct_set_attr_u32(struct nf_conntrack *ct, const enum nf_conntrack_attr type, u_int32_t value) { - nfct_set_attr(ct, type, &value); + nfct_set_attr_l(ct, type, &value, sizeof(u_int32_t)); } /** @@ -430,7 +447,7 @@ void nfct_set_attr_u64(struct nf_conntrack *ct, const enum nf_conntrack_attr type, u_int64_t value) { - nfct_set_attr(ct, type, &value); + nfct_set_attr_l(ct, type, &value, sizeof(u_int64_t)); } /** diff --git a/src/conntrack/build_mnl.c b/src/conntrack/build_mnl.c index 997c2c9..46aec8a 100644 --- a/src/conntrack/build_mnl.c +++ b/src/conntrack/build_mnl.c @@ -363,6 +363,11 @@ nfct_build_helper_name(struct nlmsghdr *nlh, const struct nf_conntrack *ct) nest = mnl_attr_nest_start(nlh, CTA_HELP); mnl_attr_put_strz(nlh, CTA_HELP_NAME, ct->helper_name); + + if (ct->helper_info != NULL) { + mnl_attr_put(nlh, CTA_HELP_INFO, ct->helper_info_len, + ct->helper_info); + } mnl_attr_nest_end(nlh, nest); return 0; } diff --git a/src/conntrack/copy.c b/src/conntrack/copy.c index 3c47b15..a6aa9f7 100644 --- a/src/conntrack/copy.c +++ b/src/conntrack/copy.c @@ -434,6 +434,22 @@ static void copy_attr_timestamp_stop(struct nf_conntrack *dest, dest->timestamp.stop = orig->timestamp.stop; } +static void copy_attr_help_info(struct nf_conntrack *dest, + const struct nf_conntrack *orig) +{ + if (orig->helper_info == NULL) + return; + + if (dest->helper_info != NULL) + free(dest->helper_info); + + dest->helper_info = calloc(1, orig->helper_info_len); + if (dest->helper_info == NULL) + return; + + memcpy(dest->helper_info, orig->helper_info, orig->helper_info_len); +} + const copy_attr copy_attr_array[ATTR_MAX] = { [ATTR_ORIG_IPV4_SRC] = copy_attr_orig_ipv4_src, [ATTR_ORIG_IPV4_DST] = copy_attr_orig_ipv4_dst, @@ -500,6 +516,7 @@ const copy_attr copy_attr_array[ATTR_MAX] = { [ATTR_SECCTX] = copy_attr_secctx, [ATTR_TIMESTAMP_START] = copy_attr_timestamp_start, [ATTR_TIMESTAMP_STOP] = copy_attr_timestamp_stop, + [ATTR_HELPER_INFO] = copy_attr_help_info, }; /* this is used by nfct_copy() with the NFCT_CP_OVERRIDE flag set. */ diff --git a/src/conntrack/getter.c b/src/conntrack/getter.c index 5e0a450..e7ab048 100644 --- a/src/conntrack/getter.c +++ b/src/conntrack/getter.c @@ -334,6 +334,11 @@ static const void *get_attr_timestamp_stop(const struct nf_conntrack *ct) return &ct->timestamp.stop; } +static const void *get_attr_helper_info(const struct nf_conntrack *ct) +{ + return ct->helper_info; +} + const get_attr get_attr_array[ATTR_MAX] = { [ATTR_ORIG_IPV4_SRC] = get_attr_orig_ipv4_src, [ATTR_ORIG_IPV4_DST] = get_attr_orig_ipv4_dst, @@ -400,4 +405,5 @@ const get_attr get_attr_array[ATTR_MAX] = { [ATTR_SECCTX] = get_attr_secctx, [ATTR_TIMESTAMP_START] = get_attr_timestamp_start, [ATTR_TIMESTAMP_STOP] = get_attr_timestamp_stop, + [ATTR_HELPER_INFO] = get_attr_helper_info, }; diff --git a/src/conntrack/parse_mnl.c b/src/conntrack/parse_mnl.c index 86d9c54..93f6681 100644 --- a/src/conntrack/parse_mnl.c +++ b/src/conntrack/parse_mnl.c @@ -678,6 +678,18 @@ nfct_parse_helper(const struct nlattr *attr, struct nf_conntrack *ct) ct->helper_name[NFCT_HELPER_NAME_MAX-1] = '\0'; set_bit(ATTR_HELPER_NAME, ct->head.set); + if (!tb[CTA_HELP_INFO]) + return 0; + + ct->helper_info_len = mnl_attr_get_payload_len(tb[CTA_HELP_INFO]); + ct->helper_info = calloc(1, ct->helper_info_len); + if (ct->helper_info == NULL) + return -1; + + memcpy(ct->helper_info, mnl_attr_get_payload(tb[CTA_HELP_INFO]), + ct->helper_info_len); + set_bit(ATTR_HELPER_INFO, ct->head.set); + return 0; } diff --git a/src/conntrack/setter.c b/src/conntrack/setter.c index afab94f..dbcd68e 100644 --- a/src/conntrack/setter.c +++ b/src/conntrack/setter.c @@ -37,67 +37,80 @@ static const u_int8_t invmap_icmpv6[] = { [ICMPV6_NI_REPLY - 128] = ICMPV6_NI_REPLY + 1 }; -static void set_attr_orig_ipv4_src(struct nf_conntrack *ct, const void *value) +static void +set_attr_orig_ipv4_src(struct nf_conntrack *ct, const void *value, size_t len) { ct->head.orig.src.v4 = *((u_int32_t *) value); } -static void set_attr_orig_ipv4_dst(struct nf_conntrack *ct, const void *value) +static void +set_attr_orig_ipv4_dst(struct nf_conntrack *ct, const void *value, size_t len) { ct->head.orig.dst.v4 = *((u_int32_t *) value); } -static void set_attr_repl_ipv4_src(struct nf_conntrack *ct, const void *value) +static void +set_attr_repl_ipv4_src(struct nf_conntrack *ct, const void *value, size_t len) { ct->repl.src.v4 = *((u_int32_t *) value); } -static void set_attr_repl_ipv4_dst(struct nf_conntrack *ct, const void *value) +static void +set_attr_repl_ipv4_dst(struct nf_conntrack *ct, const void *value, size_t len) { ct->repl.dst.v4 = *((u_int32_t *) value); } -static void set_attr_orig_ipv6_src(struct nf_conntrack *ct, const void *value) +static void +set_attr_orig_ipv6_src(struct nf_conntrack *ct, const void *value, size_t len) { memcpy(&ct->head.orig.src.v6, value, sizeof(u_int32_t)*4); } -static void set_attr_orig_ipv6_dst(struct nf_conntrack *ct, const void *value) +static void +set_attr_orig_ipv6_dst(struct nf_conntrack *ct, const void *value, size_t len) { memcpy(&ct->head.orig.dst.v6, value, sizeof(u_int32_t)*4); } -static void set_attr_repl_ipv6_src(struct nf_conntrack *ct, const void *value) +static void +set_attr_repl_ipv6_src(struct nf_conntrack *ct, const void *value, size_t len) { memcpy(&ct->repl.src.v6, value, sizeof(u_int32_t)*4); } -static void set_attr_repl_ipv6_dst(struct nf_conntrack *ct, const void *value) +static void +set_attr_repl_ipv6_dst(struct nf_conntrack *ct, const void *value, size_t len) { memcpy(&ct->repl.dst.v6, value, sizeof(u_int32_t)*4); } -static void set_attr_orig_port_src(struct nf_conntrack *ct, const void *value) +static void +set_attr_orig_port_src(struct nf_conntrack *ct, const void *value, size_t len) { ct->head.orig.l4src.all = *((u_int16_t *) value); } -static void set_attr_orig_port_dst(struct nf_conntrack *ct, const void *value) +static void +set_attr_orig_port_dst(struct nf_conntrack *ct, const void *value, size_t len) { ct->head.orig.l4dst.all = *((u_int16_t *) value); } -static void set_attr_repl_port_src(struct nf_conntrack *ct, const void *value) +static void +set_attr_repl_port_src(struct nf_conntrack *ct, const void *value, size_t len) { ct->repl.l4src.all = *((u_int16_t *) value); } -static void set_attr_repl_port_dst(struct nf_conntrack *ct, const void *value) +static void +set_attr_repl_port_dst(struct nf_conntrack *ct, const void *value, size_t len) { ct->repl.l4dst.all = *((u_int16_t *) value); } -static void set_attr_icmp_type(struct nf_conntrack *ct, const void *value) +static void +set_attr_icmp_type(struct nf_conntrack *ct, const void *value, size_t len) { u_int8_t rtype; @@ -123,231 +136,292 @@ static void set_attr_icmp_type(struct nf_conntrack *ct, const void *value) } -static void set_attr_icmp_code(struct nf_conntrack *ct, const void *value) +static void +set_attr_icmp_code(struct nf_conntrack *ct, const void *value, size_t len) { ct->head.orig.l4dst.icmp.code = *((u_int8_t *) value); ct->repl.l4dst.icmp.code = *((u_int8_t *) value); } -static void set_attr_icmp_id(struct nf_conntrack *ct, const void *value) +static void +set_attr_icmp_id(struct nf_conntrack *ct, const void *value, size_t len) { ct->head.orig.l4src.icmp.id = *((u_int16_t *) value); ct->repl.l4src.icmp.id = *((u_int16_t *) value); } -static void set_attr_orig_l3proto(struct nf_conntrack *ct, const void *value) +static void +set_attr_orig_l3proto(struct nf_conntrack *ct, const void *value, size_t len) { ct->head.orig.l3protonum = *((u_int8_t *) value); } -static void set_attr_repl_l3proto(struct nf_conntrack *ct, const void *value) +static void +set_attr_repl_l3proto(struct nf_conntrack *ct, const void *value, size_t len) { ct->repl.l3protonum = *((u_int8_t *) value); } -static void set_attr_orig_l4proto(struct nf_conntrack *ct, const void *value) +static void +set_attr_orig_l4proto(struct nf_conntrack *ct, const void *value, size_t len) { ct->head.orig.protonum = *((u_int8_t *) value); } -static void set_attr_repl_l4proto(struct nf_conntrack *ct, const void *value) +static void +set_attr_repl_l4proto(struct nf_conntrack *ct, const void *value, size_t len) { ct->repl.protonum = *((u_int8_t *) value); } -static void set_attr_tcp_state(struct nf_conntrack *ct, const void *value) +static void +set_attr_tcp_state(struct nf_conntrack *ct, const void *value, size_t len) { ct->protoinfo.tcp.state = *((u_int8_t *) value); } -static void set_attr_tcp_flags_orig(struct nf_conntrack *ct, const void *value) +static void +set_attr_tcp_flags_orig(struct nf_conntrack *ct, const void *value, size_t len) { ct->protoinfo.tcp.flags[__DIR_ORIG].value = *((u_int8_t *) value); } -static void set_attr_tcp_mask_orig(struct nf_conntrack *ct, const void *value) +static void +set_attr_tcp_mask_orig(struct nf_conntrack *ct, const void *value, size_t len) { ct->protoinfo.tcp.flags[__DIR_ORIG].mask = *((u_int8_t *) value); } -static void set_attr_tcp_flags_repl(struct nf_conntrack *ct, const void *value) +static void +set_attr_tcp_flags_repl(struct nf_conntrack *ct, const void *value, size_t len) { ct->protoinfo.tcp.flags[__DIR_REPL].value = *((u_int8_t *) value); } -static void set_attr_tcp_mask_repl(struct nf_conntrack *ct, const void *value) +static void +set_attr_tcp_mask_repl(struct nf_conntrack *ct, const void *value, size_t len) { ct->protoinfo.tcp.flags[__DIR_REPL].mask = *((u_int8_t *) value); } -static void set_attr_sctp_state(struct nf_conntrack *ct, const void *value) +static void +set_attr_sctp_state(struct nf_conntrack *ct, const void *value, size_t len) { ct->protoinfo.sctp.state = *((u_int8_t *) value); } -static void set_attr_sctp_vtag_orig(struct nf_conntrack *ct, const void *value) +static void +set_attr_sctp_vtag_orig(struct nf_conntrack *ct, const void *value, size_t len) { ct->protoinfo.sctp.vtag[__DIR_ORIG] = *((u_int32_t *) value); } -static void set_attr_sctp_vtag_repl(struct nf_conntrack *ct, const void *value) +static void +set_attr_sctp_vtag_repl(struct nf_conntrack *ct, const void *value, size_t len) { ct->protoinfo.sctp.vtag[__DIR_REPL] = *((u_int32_t *) value); } -static void set_attr_snat_ipv4(struct nf_conntrack *ct, const void *value) +static void +set_attr_snat_ipv4(struct nf_conntrack *ct, const void *value, size_t len) { ct->snat.min_ip = ct->snat.max_ip = *((u_int32_t *) value); } -static void set_attr_dnat_ipv4(struct nf_conntrack *ct, const void *value) +static void +set_attr_dnat_ipv4(struct nf_conntrack *ct, const void *value, size_t len) { ct->dnat.min_ip = ct->snat.max_ip = *((u_int32_t *) value); } -static void set_attr_snat_port(struct nf_conntrack *ct, const void *value) +static void +set_attr_snat_port(struct nf_conntrack *ct, const void *value, size_t len) { ct->snat.l4min.all = ct->snat.l4max.all = *((u_int16_t *) value); } -static void set_attr_dnat_port(struct nf_conntrack *ct, const void *value) +static void +set_attr_dnat_port(struct nf_conntrack *ct, const void *value, size_t len) { ct->dnat.l4min.all = ct->dnat.l4max.all = *((u_int16_t *) value); } -static void set_attr_timeout(struct nf_conntrack *ct, const void *value) +static void +set_attr_timeout(struct nf_conntrack *ct, const void *value, size_t len) { ct->timeout = *((u_int32_t *) value); } -static void set_attr_mark(struct nf_conntrack *ct, const void *value) +static void +set_attr_mark(struct nf_conntrack *ct, const void *value, size_t len) { ct->mark = *((u_int32_t *) value); } -static void set_attr_secmark(struct nf_conntrack *ct, const void *value) +static void +set_attr_secmark(struct nf_conntrack *ct, const void *value, size_t len) { ct->secmark = *((u_int32_t *) value); } -static void set_attr_status(struct nf_conntrack *ct, const void *value) +static void +set_attr_status(struct nf_conntrack *ct, const void *value, size_t len) { ct->status = *((u_int32_t *) value); } -static void set_attr_id(struct nf_conntrack *ct, const void *value) +static void +set_attr_id(struct nf_conntrack *ct, const void *value, size_t len) { ct->id = *((u_int32_t *) value); } -static void set_attr_master_ipv4_src(struct nf_conntrack *ct, const void *value) +static void +set_attr_master_ipv4_src(struct nf_conntrack *ct, const void *value, size_t len) { ct->master.src.v4 = *((u_int32_t *) value); } -static void set_attr_master_ipv4_dst(struct nf_conntrack *ct, const void *value) +static void +set_attr_master_ipv4_dst(struct nf_conntrack *ct, const void *value, size_t len) { ct->master.dst.v4 = *((u_int32_t *) value); } -static void set_attr_master_ipv6_src(struct nf_conntrack *ct, const void *value) +static void +set_attr_master_ipv6_src(struct nf_conntrack *ct, const void *value, size_t len) { memcpy(&ct->master.src.v6, value, sizeof(u_int32_t)*4); } -static void set_attr_master_ipv6_dst(struct nf_conntrack *ct, const void *value) +static void +set_attr_master_ipv6_dst(struct nf_conntrack *ct, const void *value, size_t len) { memcpy(&ct->master.dst.v6, value, sizeof(u_int32_t)*4); } -static void set_attr_master_port_src(struct nf_conntrack *ct, const void *value) +static void +set_attr_master_port_src(struct nf_conntrack *ct, const void *value, size_t len) { ct->master.l4src.all = *((u_int16_t *) value); } -static void set_attr_master_port_dst(struct nf_conntrack *ct, const void *value) +static void +set_attr_master_port_dst(struct nf_conntrack *ct, const void *value, size_t len) { ct->master.l4dst.all = *((u_int16_t *) value); } -static void set_attr_master_l3proto(struct nf_conntrack *ct, const void *value) +static void +set_attr_master_l3proto(struct nf_conntrack *ct, const void *value, size_t len) { ct->master.l3protonum = *((u_int8_t *) value); } -static void set_attr_master_l4proto(struct nf_conntrack *ct, const void *value) +static void +set_attr_master_l4proto(struct nf_conntrack *ct, const void *value, size_t len) { ct->master.protonum = *((u_int8_t *) value); } -static void set_attr_orig_cor_pos(struct nf_conntrack *ct, const void *value) +static void +set_attr_orig_cor_pos(struct nf_conntrack *ct, const void *value, size_t len) { ct->natseq[__DIR_ORIG].correction_pos = *((u_int32_t *) value); } -static void set_attr_orig_off_bfr(struct nf_conntrack *ct, const void *value) +static void +set_attr_orig_off_bfr(struct nf_conntrack *ct, const void *value, size_t len) { ct->natseq[__DIR_ORIG].offset_before = *((u_int32_t *) value); } -static void set_attr_orig_off_aft(struct nf_conntrack *ct, const void *value) +static void +set_attr_orig_off_aft(struct nf_conntrack *ct, const void *value, size_t len) { ct->natseq[__DIR_ORIG].offset_after = *((u_int32_t *) value); } -static void set_attr_repl_cor_pos(struct nf_conntrack *ct, const void *value) +static void +set_attr_repl_cor_pos(struct nf_conntrack *ct, const void *value, size_t len) { ct->natseq[__DIR_REPL].correction_pos = *((u_int32_t *) value); } -static void set_attr_repl_off_bfr(struct nf_conntrack *ct, const void *value) +static void +set_attr_repl_off_bfr(struct nf_conntrack *ct, const void *value, size_t len) { ct->natseq[__DIR_REPL].offset_before = *((u_int32_t *) value); } -static void set_attr_repl_off_aft(struct nf_conntrack *ct, const void *value) +static void +set_attr_repl_off_aft(struct nf_conntrack *ct, const void *value, size_t len) { ct->natseq[__DIR_REPL].offset_after = *((u_int32_t *) value); } -static void set_attr_helper_name(struct nf_conntrack *ct, const void *value) +static void +set_attr_helper_name(struct nf_conntrack *ct, const void *value, size_t len) { strncpy(ct->helper_name, value, NFCT_HELPER_NAME_MAX); ct->helper_name[NFCT_HELPER_NAME_MAX-1] = '\0'; } -static void set_attr_dccp_state(struct nf_conntrack *ct, const void *value) +static void +set_attr_dccp_state(struct nf_conntrack *ct, const void *value, size_t len) { ct->protoinfo.dccp.state = *((u_int8_t *) value); } -static void set_attr_dccp_role(struct nf_conntrack *ct, const void *value) +static void +set_attr_dccp_role(struct nf_conntrack *ct, const void *value, size_t len) { ct->protoinfo.dccp.role = *((u_int8_t *) value); } static void -set_attr_dccp_handshake_seq(struct nf_conntrack *ct, const void *value) +set_attr_dccp_handshake_seq(struct nf_conntrack *ct, const void *value, + size_t len) { ct->protoinfo.dccp.handshake_seq = *((u_int64_t *) value); } -static void set_attr_tcp_wscale_orig(struct nf_conntrack *ct, const void *value) +static void +set_attr_tcp_wscale_orig(struct nf_conntrack *ct, const void *value, size_t len) { ct->protoinfo.tcp.wscale[__DIR_ORIG] = *((u_int8_t *) value); } -static void set_attr_tcp_wscale_repl(struct nf_conntrack *ct, const void *value) +static void +set_attr_tcp_wscale_repl(struct nf_conntrack *ct, const void *value, size_t len) { ct->protoinfo.tcp.wscale[__DIR_REPL] = *((u_int8_t *) value); } -static void set_attr_zone(struct nf_conntrack *ct, const void *value) +static void +set_attr_zone(struct nf_conntrack *ct, const void *value, size_t len) { ct->zone = *((u_int16_t *) value); } -static void set_attr_do_nothing(struct nf_conntrack *ct, const void *value) {} +static void +set_attr_helper_info(struct nf_conntrack *ct, const void *value, size_t len) +{ + if (ct->helper_info == NULL) { +retry: + ct->helper_info = calloc(1, len); + if (ct->helper_info == NULL) + return; + + memcpy(ct->helper_info, value, len); + } else { + free(ct->helper_info); + goto retry; + } +} + +static void +set_attr_do_nothing(struct nf_conntrack *ct, const void *value, size_t len) {} const set_attr set_attr_array[ATTR_MAX] = { [ATTR_ORIG_IPV4_SRC] = set_attr_orig_ipv4_src, @@ -415,4 +489,5 @@ const set_attr set_attr_array[ATTR_MAX] = { [ATTR_SECCTX] = set_attr_do_nothing, [ATTR_TIMESTAMP_START] = set_attr_do_nothing, [ATTR_TIMESTAMP_STOP] = set_attr_do_nothing, + [ATTR_HELPER_INFO] = set_attr_helper_info, }; -- cgit v1.2.3