Add support for ct timeout objects, used to assign connection tracking timeout policies. Signed-off-by: Harsha Sharma <harshasharmaiitr@xxxxxxxxx> --- include/libnftnl/Makefile.am | 3 +- include/libnftnl/cttimeout.h | 88 +++++++ include/libnftnl/object.h | 8 + include/linux/netfilter/nf_tables.h | 108 ++++++++- include/obj.h | 8 + src/Makefile.am | 1 + src/libnftnl.map | 1 + src/obj/ct_timeout.c | 443 ++++++++++++++++++++++++++++++++++++ src/object.c | 4 +- 9 files changed, 660 insertions(+), 4 deletions(-) create mode 100644 include/libnftnl/cttimeout.h create mode 100644 src/obj/ct_timeout.c diff --git a/include/libnftnl/Makefile.am b/include/libnftnl/Makefile.am index d846a57..a94f414 100644 --- a/include/libnftnl/Makefile.am +++ b/include/libnftnl/Makefile.am @@ -10,4 +10,5 @@ pkginclude_HEADERS = batch.h \ ruleset.h \ common.h \ udata.h \ - gen.h + gen.h \ + cttimeout.h diff --git a/include/libnftnl/cttimeout.h b/include/libnftnl/cttimeout.h new file mode 100644 index 0000000..785e2bd --- /dev/null +++ b/include/libnftnl/cttimeout.h @@ -0,0 +1,88 @@ +#ifndef _LIBNETFILTER_CTTIMEOUT_H_ +#define _LIBNETFILTER_CTTIMEOUT_H_ + +#include <stdint.h> +#include <sys/types.h> +#include <linux/netfilter/nfnetlink_conntrack.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct nftnl_obj_ct_timeout; + +enum nftnl_obj_ct_timeout_tcp_attr { + NFTA_CT_TIMEOUT_ATTR_TCP_SYN_SENT = 0, + NFTA_CT_TIMEOUT_ATTR_TCP_SYN_RECV, + NFTA_CT_TIMEOUT_ATTR_TCP_ESTABLISHED, + NFTA_CT_TIMEOUT_ATTR_TCP_FIN_WAIT, + NFTA_CT_TIMEOUT_ATTR_TCP_CLOSE_WAIT, + NFTA_CT_TIMEOUT_ATTR_TCP_LAST_ACK, + NFTA_CT_TIMEOUT_ATTR_TCP_TIME_WAIT, + NFTA_CT_TIMEOUT_ATTR_TCP_CLOSE, + NFTA_CT_TIMEOUT_ATTR_TCP_SYN_SENT2, + NFTA_CT_TIMEOUT_ATTR_TCP_RETRANS, + NFTA_CT_TIMEOUT_ATTR_TCP_UNACK, + NFTA_CT_TIMEOUT_ATTR_TCP_MAX +}; + +enum nftnl_obj_ct_timeout_udp_attr { + NFTA_CT_TIMEOUT_ATTR_UDP_UNREPLIED = 0, + NFTA_CT_TIMEOUT_ATTR_UDP_REPLIED, + NFTA_CT_TIMEOUT_ATTR_UDP_MAX +}; + +enum nftnl_obj_timeout_udplite_attr { + NFTA_CT_TIMEOUT_ATTR_UDPLITE_UNREPLIED = 0, + NFTA_CT_TIMEOUT_ATTR_UDPLITE_REPLIED, + NFTA_CT_TIMEOUT_ATTR_UDPLITE_MAX +}; + +enum nftnl_obj_timeout_dccp_attr { + NFTA_CT_TIMEOUT_ATTR_DCCP_REQUEST, + NFTA_CT_TIMEOUT_ATTR_DCCP_RESPOND, + NFTA_CT_TIMEOUT_ATTR_DCCP_PARTOPEN, + NFTA_CT_TIMEOUT_ATTR_DCCP_OPEN, + NFTA_CT_TIMEOUT_ATTR_DCCP_CLOSEREQ, + NFTA_CT_TIMEOUT_ATTR_DCCP_CLOSING, + NFTA_CT_TIMEOUT_ATTR_DCCP_TIMEWAIT, + NFTA_CT_TIMEOUT_ATTR_DCCP_MAX +}; + +enum nftnl_obj_timeout_sctp_attr { + NFTA_CT_TIMEOUT_ATTR_SCTP_CLOSED = 0, + NFTA_CT_TIMEOUT_ATTR_SCTP_COOKIE_WAIT, + NFTA_CT_TIMEOUT_ATTR_SCTP_COOKIE_ECHOED, + NFTA_CT_TIMEOUT_ATTR_SCTP_ESTABLISHED, + NFTA_CT_TIMEOUT_ATTR_SCTP_SHUTDOWN_SENT, + NFTA_CT_TIMEOUT_ATTR_SCTP_SHUTDOWN_RECD, + NFTA_CT_TIMEOUT_ATTR_SCTP_SHUTDOWN_ACK_SENT, + NFTA_CT_TIMEOUT_ATTR_SCTP_MAX +}; + +enum nftnl_obj_timeout_icmp_attr { + NFTA_CT_TIMEOUT_ATTR_ICMP = 0, + NFTA_CT_TIMEOUT_ATTR_ICMP_MAX +}; + +enum nftnl_obj_timeout_icmpv6_attr { + NFTA_CT_TIMEOUT_ATTR_ICMPV6 = 0, + NFTA_CT_TIMEOUT_ATTR_ICMPV6_MAX +}; + +enum nftnl_obj_timeout_gre_attr { + NFTA_CT_TIMEOUT_ATTR_GRE_UNREPLIED = 0, + NFTA_CT_TIMEOUT_ATTR_GRE_REPLIED, + NFTA_CT_TIMEOUT_ATTR_GRE_MAX +}; + +enum nftnl_obj_timeout_generic_attr { + NFTA_CT_TIMEOUT_ATTR_GENERIC = 0, + NFTA_CT_TIMEOUT_ATTR_GENERIC_MAX +}; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/include/libnftnl/object.h b/include/libnftnl/object.h index 93a40d0..ecf9f6c 100644 --- a/include/libnftnl/object.h +++ b/include/libnftnl/object.h @@ -41,6 +41,13 @@ enum { NFTNL_OBJ_CT_HELPER_L4PROTO, }; +enum { + NFTNL_OBJ_CT_TIMEOUT_L3PROTO = NFTNL_OBJ_BASE, + NFTNL_OBJ_CT_TIMEOUT_L4PROTO, + NFTNL_OBJ_CT_TIMEOUT_DATA, + NFTNL_OBJ_CT_TIMEOUT_POLICY, +}; + enum { NFTNL_OBJ_LIMIT_RATE = NFTNL_OBJ_BASE, NFTNL_OBJ_LIMIT_UNIT, @@ -64,6 +71,7 @@ void nftnl_obj_set_u16(struct nftnl_obj *ne, uint16_t attr, uint16_t val); void nftnl_obj_set_u32(struct nftnl_obj *ne, uint16_t attr, uint32_t val); void nftnl_obj_set_u64(struct nftnl_obj *obj, uint16_t attr, uint64_t val); void nftnl_obj_set_str(struct nftnl_obj *ne, uint16_t attr, const char *str); +int nftnl_timeout_policy_attr_set_u32(struct nftnl_obj *ne, uint32_t type, uint32_t data); const void *nftnl_obj_get_data(struct nftnl_obj *ne, uint16_t attr, uint32_t *data_len); const void *nftnl_obj_get(struct nftnl_obj *ne, uint16_t attr); diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h index b904e33..6f93ee3 100644 --- a/include/linux/netfilter/nf_tables.h +++ b/include/linux/netfilter/nf_tables.h @@ -490,7 +490,7 @@ enum nft_immediate_attributes { * * which allow to express all bitwise operations: * - * mask xor + * mask xor * NOT: 1 1 * OR: 0 x * XOR: 1 x @@ -921,6 +921,7 @@ enum nft_rt_attributes { * @NFT_CT_DST_IP: conntrack layer 3 protocol destination (IPv4 address) * @NFT_CT_SRC_IP6: conntrack layer 3 protocol source (IPv6 address) * @NFT_CT_DST_IP6: conntrack layer 3 protocol destination (IPv6 address) + * @NFT_CT_TIMEOUT: connection tracking timeout policy assigned to conntrack */ enum nft_ct_keys { NFT_CT_STATE, @@ -946,6 +947,7 @@ enum nft_ct_keys { NFT_CT_DST_IP, NFT_CT_SRC_IP6, NFT_CT_DST_IP6, + NFT_CT_TIMEOUT, }; /** @@ -1305,12 +1307,114 @@ enum nft_ct_helper_attributes { }; #define NFTA_CT_HELPER_MAX (__NFTA_CT_HELPER_MAX - 1) +enum nft_ct_timeout_timeout_attributes { + NFTA_CT_TIMEOUT_UNSPEC, + NFTA_CT_TIMEOUT_L3PROTO, + NFTA_CT_TIMEOUT_L4PROTO, + NFTA_CT_TIMEOUT_DATA, + NFTA_CT_TIMEOUT_USE, + __NFTA_CT_TIMEOUT_MAX, +}; +#define NFTA_CT_TIMEOUT_MAX (__NFTA_CT_TIMEOUT_MAX - 1) + + +enum ctattr_timeout_tcp { + CTA_TIMEOUT_TCP_UNSPEC, + CTA_TIMEOUT_TCP_SYN_SENT, + CTA_TIMEOUT_TCP_SYN_RECV, + CTA_TIMEOUT_TCP_ESTABLISHED, + CTA_TIMEOUT_TCP_FIN_WAIT, + CTA_TIMEOUT_TCP_CLOSE_WAIT, + CTA_TIMEOUT_TCP_LAST_ACK, + CTA_TIMEOUT_TCP_TIME_WAIT, + CTA_TIMEOUT_TCP_CLOSE, + CTA_TIMEOUT_TCP_SYN_SENT2, + CTA_TIMEOUT_TCP_RETRANS, + CTA_TIMEOUT_TCP_UNACK, + __CTA_TIMEOUT_TCP_MAX +}; +#define CTA_TIMEOUT_TCP_MAX (__CTA_TIMEOUT_TCP_MAX - 1) + +enum ctattr_timeout_udp { + CTA_TIMEOUT_UDP_UNSPEC, + CTA_TIMEOUT_UDP_UNREPLIED, + CTA_TIMEOUT_UDP_REPLIED, + __CTA_TIMEOUT_UDP_MAX +}; +#define CTA_TIMEOUT_UDP_MAX (__CTA_TIMEOUT_UDP_MAX - 1) + +enum ctattr_timeout_udplite { + CTA_TIMEOUT_UDPLITE_UNSPEC, + CTA_TIMEOUT_UDPLITE_UNREPLIED, + CTA_TIMEOUT_UDPLITE_REPLIED, + __CTA_TIMEOUT_UDPLITE_MAX +}; +#define CTA_TIMEOUT_UDPLITE_MAX (__CTA_TIMEOUT_UDPLITE_MAX - 1) + +enum ctattr_timeout_icmp { + CTA_TIMEOUT_ICMP_UNSPEC, + CTA_TIMEOUT_ICMP_TIMEOUT, + __CTA_TIMEOUT_ICMP_MAX +}; +#define CTA_TIMEOUT_ICMP_MAX (__CTA_TIMEOUT_ICMP_MAX - 1) + +enum ctattr_timeout_dccp { + CTA_TIMEOUT_DCCP_UNSPEC, + CTA_TIMEOUT_DCCP_REQUEST, + CTA_TIMEOUT_DCCP_RESPOND, + CTA_TIMEOUT_DCCP_PARTOPEN, + CTA_TIMEOUT_DCCP_OPEN, + CTA_TIMEOUT_DCCP_CLOSEREQ, + CTA_TIMEOUT_DCCP_CLOSING, + CTA_TIMEOUT_DCCP_TIMEWAIT, + __CTA_TIMEOUT_DCCP_MAX +}; +#define CTA_TIMEOUT_DCCP_MAX (__CTA_TIMEOUT_DCCP_MAX - 1) + +enum ctattr_timeout_sctp { + CTA_TIMEOUT_SCTP_UNSPEC, + CTA_TIMEOUT_SCTP_CLOSED, + CTA_TIMEOUT_SCTP_COOKIE_WAIT, + CTA_TIMEOUT_SCTP_COOKIE_ECHOED, + CTA_TIMEOUT_SCTP_ESTABLISHED, + CTA_TIMEOUT_SCTP_SHUTDOWN_SENT, + CTA_TIMEOUT_SCTP_SHUTDOWN_RECD, + CTA_TIMEOUT_SCTP_SHUTDOWN_ACK_SENT, + __CTA_TIMEOUT_SCTP_MAX +}; +#define CTA_TIMEOUT_SCTP_MAX (__CTA_TIMEOUT_SCTP_MAX - 1) + +enum ctattr_timeout_icmpv6 { + CTA_TIMEOUT_ICMPV6_UNSPEC, + CTA_TIMEOUT_ICMPV6_TIMEOUT, + __CTA_TIMEOUT_ICMPV6_MAX +}; +#define CTA_TIMEOUT_ICMPV6_MAX (__CTA_TIMEOUT_ICMPV6_MAX - 1) + +enum ctattr_timeout_generic { + CTA_TIMEOUT_GENERIC_UNSPEC, + CTA_TIMEOUT_GENERIC_TIMEOUT, + __CTA_TIMEOUT_GENERIC_MAX +}; +#define CTA_TIMEOUT_GENERIC_MAX (__CTA_TIMEOUT_GENERIC_MAX - 1) + +enum ctattr_timeout_gre { + CTA_TIMEOUT_GRE_UNSPEC, + CTA_TIMEOUT_GRE_UNREPLIED, + CTA_TIMEOUT_GRE_REPLIED, + __CTA_TIMEOUT_GRE_MAX +}; +#define CTA_TIMEOUT_GRE_MAX (__CTA_TIMEOUT_GRE_MAX - 1) + +#define CTNL_TIMEOUT_NAME_MAX 32 + #define NFT_OBJECT_UNSPEC 0 #define NFT_OBJECT_COUNTER 1 #define NFT_OBJECT_QUOTA 2 #define NFT_OBJECT_CT_HELPER 3 #define NFT_OBJECT_LIMIT 4 -#define __NFT_OBJECT_MAX 5 +#define NFT_OBJECT_CT_TIMEOUT 5 +#define __NFT_OBJECT_MAX 6 #define NFT_OBJECT_MAX (__NFT_OBJECT_MAX - 1) /** diff --git a/include/obj.h b/include/obj.h index 4a728c8..49a1d92 100644 --- a/include/obj.h +++ b/include/obj.h @@ -36,6 +36,13 @@ struct nftnl_obj { uint8_t l4proto; char name[16]; } ct_helper; + struct nftnl_obj_ct_timeout { + uint16_t l3proto; + uint8_t l4proto; + char name[16]; + uint16_t polset; + uint32_t *timeout; + } ct_timeout; struct nftnl_obj_limit { uint64_t rate; uint64_t unit; @@ -63,6 +70,7 @@ struct obj_ops { extern struct obj_ops obj_ops_counter; extern struct obj_ops obj_ops_quota; extern struct obj_ops obj_ops_ct_helper; +extern struct obj_ops obj_ops_ct_timeout; extern struct obj_ops obj_ops_limit; #define nftnl_obj_data(obj) (void *)&obj->data diff --git a/src/Makefile.am b/src/Makefile.am index 578b7d3..77eb06d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -58,4 +58,5 @@ libnftnl_la_SOURCES = utils.c \ obj/ct_helper.c \ obj/quota.c \ obj/limit.c \ + obj/ct_timeout.c \ libnftnl.map diff --git a/src/libnftnl.map b/src/libnftnl.map index a24fe9b..9c5a7b0 100644 --- a/src/libnftnl.map +++ b/src/libnftnl.map @@ -340,5 +340,6 @@ LIBNFTNL_7 { nftnl_flowtable_list_add_tail; nftnl_flowtable_list_del; nftnl_flowtable_list_foreach; + nftnl_timeout_policy_attr_set_u32; } LIBNFTNL_6; diff --git a/src/obj/ct_timeout.c b/src/obj/ct_timeout.c new file mode 100644 index 0000000..5075fef --- /dev/null +++ b/src/obj/ct_timeout.c @@ -0,0 +1,443 @@ +/* + * (C) 2017 Red Hat GmbH + * Author: Florian Westphal <fw@xxxxxxxxx> + * + * 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. + */ + +#include <stdio.h> +#include <stdint.h> +#include <arpa/inet.h> +#include <errno.h> +#include <inttypes.h> + +#include <linux/netfilter/nf_tables.h> + +#include "internal.h" +#include <libmnl/libmnl.h> +#include <libnftnl/object.h> +#include <libnftnl/cttimeout.h> + +#include "obj.h" + +static const char *const tcp_state_to_name[] = { + [NFTA_CT_TIMEOUT_ATTR_TCP_SYN_SENT] = "SYN_SENT", + [NFTA_CT_TIMEOUT_ATTR_TCP_SYN_RECV] = "SYN_RECV", + [NFTA_CT_TIMEOUT_ATTR_TCP_ESTABLISHED] = "ESTABLISHED", + [NFTA_CT_TIMEOUT_ATTR_TCP_FIN_WAIT] = "FIN_WAIT", + [NFTA_CT_TIMEOUT_ATTR_TCP_CLOSE_WAIT] = "CLOSE_WAIT", + [NFTA_CT_TIMEOUT_ATTR_TCP_LAST_ACK] = "LAST_ACK", + [NFTA_CT_TIMEOUT_ATTR_TCP_TIME_WAIT] = "TIME_WAIT", + [NFTA_CT_TIMEOUT_ATTR_TCP_CLOSE] = "CLOSE", + [NFTA_CT_TIMEOUT_ATTR_TCP_SYN_SENT2] = "SYN_SENT2", + [NFTA_CT_TIMEOUT_ATTR_TCP_RETRANS] = "RETRANS", + [NFTA_CT_TIMEOUT_ATTR_TCP_UNACK] = "UNACKNOWLEDGED", +}; + +static const char *const generic_state_to_name[] = { + [NFTA_CT_TIMEOUT_ATTR_GENERIC] = "TIMEOUT", +}; + +static const char *const udp_state_to_name[] = { + [NFTA_CT_TIMEOUT_ATTR_UDP_UNREPLIED] = "UNREPLIED", + [NFTA_CT_TIMEOUT_ATTR_UDP_REPLIED] = "REPLIED", +}; + +static const char *const sctp_state_to_name[] = { + [NFTA_CT_TIMEOUT_ATTR_SCTP_CLOSED] = "CLOSED", + [NFTA_CT_TIMEOUT_ATTR_SCTP_COOKIE_WAIT] = "COOKIE_WAIT", + [NFTA_CT_TIMEOUT_ATTR_SCTP_COOKIE_ECHOED] = "COOKIE_ECHOED", + [NFTA_CT_TIMEOUT_ATTR_SCTP_ESTABLISHED] = "ESTABLISHED", + [NFTA_CT_TIMEOUT_ATTR_SCTP_SHUTDOWN_SENT] = "SHUTDOWN_SENT", + [NFTA_CT_TIMEOUT_ATTR_SCTP_SHUTDOWN_RECD] = "SHUTDOWN_RECD", + [NFTA_CT_TIMEOUT_ATTR_SCTP_SHUTDOWN_ACK_SENT] = "SHUTDOWN_ACK_SENT", +}; + +static const char *const dccp_state_to_name[] = { + [NFTA_CT_TIMEOUT_ATTR_DCCP_REQUEST] = "REQUEST", + [NFTA_CT_TIMEOUT_ATTR_DCCP_RESPOND] = "RESPOND", + [NFTA_CT_TIMEOUT_ATTR_DCCP_PARTOPEN] = "PARTOPEN", + [NFTA_CT_TIMEOUT_ATTR_DCCP_OPEN] = "OPEN", + [NFTA_CT_TIMEOUT_ATTR_DCCP_CLOSEREQ] = "CLOSEREQ", + [NFTA_CT_TIMEOUT_ATTR_DCCP_CLOSING] = "CLOSING", + [NFTA_CT_TIMEOUT_ATTR_DCCP_TIMEWAIT] = "TIMEWAIT", +}; + +static const char *const icmp_state_to_name[] = { + [NFTA_CT_TIMEOUT_ATTR_ICMP] = "TIMEOUT", +}; + +static const char *const icmpv6_state_to_name[] = { + [NFTA_CT_TIMEOUT_ATTR_ICMPV6] = "TIMEOUT", +}; + + +static struct { + int32_t nlattr_max; + uint32_t attr_max; + const char *const *state_to_name; +} timeout_protocol[IPPROTO_MAX] = { + [IPPROTO_ICMP] = { + .nlattr_max = __CTA_TIMEOUT_ICMP_MAX, + .attr_max = NFTA_CT_TIMEOUT_ATTR_ICMP_MAX, + .state_to_name = icmp_state_to_name, + }, + [IPPROTO_TCP] = { + .nlattr_max = __CTA_TIMEOUT_TCP_MAX, + .attr_max = NFTA_CT_TIMEOUT_ATTR_TCP_MAX, + .state_to_name = tcp_state_to_name, + }, + [IPPROTO_UDP] = { + .nlattr_max = __CTA_TIMEOUT_UDP_MAX, + .attr_max = NFTA_CT_TIMEOUT_ATTR_UDP_MAX, + .state_to_name = udp_state_to_name, + }, + [IPPROTO_GRE] = { + .nlattr_max = __CTA_TIMEOUT_GRE_MAX, + .attr_max = NFTA_CT_TIMEOUT_ATTR_GRE_MAX, + .state_to_name = udp_state_to_name, + }, + [IPPROTO_SCTP] = { + .nlattr_max = __CTA_TIMEOUT_SCTP_MAX, + .attr_max = NFTA_CT_TIMEOUT_ATTR_SCTP_MAX, + .state_to_name = sctp_state_to_name, + }, + [IPPROTO_DCCP] = { + .nlattr_max = __CTA_TIMEOUT_DCCP_MAX, + .attr_max = NFTA_CT_TIMEOUT_ATTR_DCCP_MAX, + .state_to_name = dccp_state_to_name, + }, + [IPPROTO_UDPLITE] = { + .nlattr_max = __CTA_TIMEOUT_UDPLITE_MAX, + .attr_max = NFTA_CT_TIMEOUT_ATTR_UDPLITE_MAX, + .state_to_name = udp_state_to_name, + }, + [IPPROTO_ICMPV6] = { + .nlattr_max = __CTA_TIMEOUT_ICMPV6_MAX, + .attr_max = NFTA_CT_TIMEOUT_ATTR_ICMPV6_MAX, + .state_to_name = icmpv6_state_to_name, + }, + /* add your new supported protocol tracker here. */ + [IPPROTO_RAW] = { + .nlattr_max = __CTA_TIMEOUT_GENERIC_MAX, + .attr_max = NFTA_CT_TIMEOUT_ATTR_GENERIC_MAX, + .state_to_name = generic_state_to_name, + }, +}; + + +struct _container_policy_cb { + unsigned int nlattr_max; + void *tb; +}; + +int +nftnl_timeout_policy_attr_set_u32(struct nftnl_obj *e, + uint32_t type, uint32_t data) +{ + struct nftnl_obj_ct_timeout *t = nftnl_obj_data(e); + size_t timeout_array_size; + /* Layer 4 protocol needs to be already set. */ + if (!(e->flags & (1 << NFTNL_OBJ_CT_TIMEOUT_L4PROTO))) + return -1; + if (t->timeout == NULL) { + /* if not supported, default to generic protocol tracker. */ + if (timeout_protocol[t->l4proto].attr_max != 0) { + timeout_array_size = sizeof(uint32_t) * + timeout_protocol[t->l4proto].attr_max; + } else { + timeout_array_size = sizeof(uint32_t) * + timeout_protocol[IPPROTO_RAW].attr_max; + } + t->timeout = calloc(1, timeout_array_size); + if (t->timeout == NULL) + return -1; + } + + /* this state does not exists in this protocol tracker.*/ + if (type > timeout_protocol[t->l4proto].attr_max) + return -1; + + t->timeout[type] = data; + t->polset |= (1 << type); + + if (!(e->flags & (1 << NFTNL_OBJ_CT_TIMEOUT_POLICY))) + e->flags |= (1 << NFTNL_OBJ_CT_TIMEOUT_POLICY); + if (!(e->flags & (1 << NFTNL_OBJ_CT_TIMEOUT_DATA))) + e->flags |= (1 << NFTNL_OBJ_CT_TIMEOUT_DATA); + + return 0; +} +EXPORT_SYMBOL(nftnl_timeout_policy_attr_set_u32); + +static int +parse_timeout_attr_policy_cb(const struct nlattr *attr, void *data) +{ + struct _container_policy_cb *data_cb = data; + const struct nlattr **tb = data_cb->tb; + uint16_t type = mnl_attr_get_type(attr); + + if (mnl_attr_type_valid(attr, data_cb->nlattr_max) < 0) + return MNL_CB_OK; + + if (type <= data_cb->nlattr_max) { + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) + abi_breakage(); + tb[type] = attr; + } + return MNL_CB_OK; +} + +static void +timeout_parse_attr_data(struct nftnl_obj *e, + const struct nlattr *nest) +{ + struct nftnl_obj_ct_timeout *t = nftnl_obj_data(e); + unsigned int nlattr_max = timeout_protocol[t->l4proto].nlattr_max; + struct nlattr *tb[nlattr_max]; + struct _container_policy_cb cnt = { + .nlattr_max = nlattr_max, + .tb = tb, + }; + unsigned int i; + + memset(tb, 0, sizeof(struct nlattr *) * nlattr_max); + + mnl_attr_parse_nested(nest, parse_timeout_attr_policy_cb, &cnt); + + for (i = 1; i < nlattr_max; i++) { + if (tb[i]) { + nftnl_timeout_policy_attr_set_u32(e, i-1, + ntohl(mnl_attr_get_u32(tb[i]))); + } + } +} + + +static int nftnl_obj_ct_timeout_set(struct nftnl_obj *e, uint16_t type, + const void *data, uint32_t data_len) +{ + struct nftnl_obj_ct_timeout *timeout = nftnl_obj_data(e); + + switch (type) { + case NFTNL_OBJ_CT_TIMEOUT_L3PROTO: + timeout->l3proto = *((uint16_t *)data); + break; + case NFTNL_OBJ_CT_TIMEOUT_L4PROTO: + timeout->l4proto = *((uint8_t *)data); + break; + default: + return -1; + } + return 0; +} + +static const void *nftnl_obj_ct_timeout_get(const struct nftnl_obj *e, + uint16_t type, uint32_t *data_len) +{ + struct nftnl_obj_ct_timeout *timeout = nftnl_obj_data(e); + + switch (type) { + case NFTNL_OBJ_CT_TIMEOUT_L3PROTO: + *data_len = sizeof(timeout->l3proto); + return &timeout->l3proto; + case NFTNL_OBJ_CT_TIMEOUT_L4PROTO: + *data_len = sizeof(timeout->l4proto); + return &timeout->l4proto; + } + return NULL; +} + +static int nftnl_obj_ct_timeout_cb(const struct nlattr *attr, void *data) +{ + int type = mnl_attr_get_type(attr); + const struct nlattr **tb = data; + + if (mnl_attr_type_valid(attr, NFTA_CT_TIMEOUT_MAX) < 0) + return MNL_CB_OK; + + switch (type) { + case NFTA_CT_TIMEOUT_L3PROTO: + if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0) + abi_breakage(); + break; + case NFTA_CT_TIMEOUT_L4PROTO: + if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0) + abi_breakage(); + break; + case NFTA_CT_TIMEOUT_DATA: + if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) + abi_breakage(); + break; + } + + tb[type] = attr; + return MNL_CB_OK; +} + +static void +nftnl_obj_ct_timeout_build(struct nlmsghdr *nlh, const struct nftnl_obj *e) +{ + struct nftnl_obj_ct_timeout *timeout = nftnl_obj_data(e); + struct nlattr *nest; + + if (e->flags & (1 << NFTNL_OBJ_CT_TIMEOUT_L3PROTO)) + mnl_attr_put_u16(nlh, NFTA_CT_TIMEOUT_L3PROTO, htons(timeout->l3proto)); + if (e->flags & (1 << NFTNL_OBJ_CT_TIMEOUT_L4PROTO)) + mnl_attr_put_u8(nlh, NFTA_CT_TIMEOUT_L4PROTO, timeout->l4proto); + if (e->flags & (1 << NFTNL_OBJ_CT_TIMEOUT_DATA) && timeout->polset) { + nest = mnl_attr_nest_start(nlh, NFTA_CT_TIMEOUT_DATA); + for (int i = 0; i < timeout_protocol[timeout->l4proto].attr_max; i++) { + if (timeout->polset & (1 << i)) + mnl_attr_put_u32(nlh, i+1, htonl(timeout->timeout[i])); + } + mnl_attr_nest_end(nlh, nest); + } +} + +static int +nftnl_obj_ct_timeout_parse(struct nftnl_obj *e, struct nlattr *attr) +{ + struct nftnl_obj_ct_timeout *timeout = nftnl_obj_data(e); + struct nlattr *tb[NFTA_CT_TIMEOUT_MAX + 1] = {}; + + if (mnl_attr_parse_nested(attr, nftnl_obj_ct_timeout_cb, tb) < 0) + return -1; + + if (tb[NFTA_CT_TIMEOUT_L3PROTO]) { + timeout->l3proto = ntohs(mnl_attr_get_u16(tb[NFTA_CT_TIMEOUT_L3PROTO])); + e->flags |= (1 << NFTNL_OBJ_CT_TIMEOUT_L3PROTO); + } + if (tb[NFTA_CT_TIMEOUT_L4PROTO]) { + timeout->l4proto = mnl_attr_get_u8(tb[NFTA_CT_TIMEOUT_L4PROTO]); + e->flags |= (1 << NFTNL_OBJ_CT_TIMEOUT_L4PROTO); + } + if (tb[NFTA_CT_TIMEOUT_DATA]) { + timeout_parse_attr_data(e, tb[NFTA_CT_TIMEOUT_DATA]); + e->flags |= (1 << NFTNL_OBJ_CT_TIMEOUT_DATA); + } + return 0; +} + +/*static int +nftnl_obj_quota_json_parse(struct nftnl_obj *e, json_t *root, + struct nftnl_parse_err *err) +{ +#ifdef JSON_PARSING + uint64_t bytes; + uint32_t flags; + + if (nftnl_jansson_parse_val(root, "bytes", NFTNL_TYPE_U64, &bytes, + err) == 0) + nftnl_obj_set_u64(e, NFTNL_OBJ_QUOTA_BYTES, bytes); + if (nftnl_jansson_parse_val(root, "consumed", NFTNL_TYPE_U64, &bytes, + err) == 0) + nftnl_obj_set_u64(e, NFTNL_OBJ_QUOTA_CONSUMED, bytes); + if (nftnl_jansson_parse_val(root, "flags", NFTNL_TYPE_U32, &flags, + err) == 0) + nftnl_obj_set_u32(e, NFTNL_OBJ_QUOTA_FLAGS, flags); + + return 0; +#else + errno = EOPNOTSUPP; + return -1; +#endif +}*/ + +static int nftnl_obj_ct_timeout_export(char *buf, size_t size, + const struct nftnl_obj *e, int type) +{ + struct nftnl_obj_ct_timeout *timeout = nftnl_obj_data(e); + + NFTNL_BUF_INIT(b, buf, size); + + if (e->flags & (1 << NFTNL_OBJ_CT_TIMEOUT_L3PROTO)) + nftnl_buf_u32(&b, type, timeout->l3proto, FAMILY); + if (e->flags & (1 << NFTNL_OBJ_CT_TIMEOUT_L4PROTO)) + nftnl_buf_u32(&b, type, timeout->l4proto, "service"); + + return nftnl_buf_done(&b); +} + +static int nftnl_obj_ct_timeout_snprintf_default(char *buf, size_t len, + const struct nftnl_obj *e) +{ + int ret = 0; + int offset = 0, remain = len; + + struct nftnl_obj_ct_timeout *timeout = nftnl_obj_data(e); + + if (e->flags & (1 << NFTNL_OBJ_CT_TIMEOUT_L3PROTO)) { + ret = snprintf(buf+offset, len, "family %d ", + timeout->l3proto); + SNPRINTF_BUFFER_SIZE(ret, remain, offset); + } + if (e->flags & (1 << NFTNL_OBJ_CT_TIMEOUT_L4PROTO)) { + ret = snprintf(buf+offset, len, "protocol %d ", + timeout->l4proto); + SNPRINTF_BUFFER_SIZE(ret, remain, offset); + } + if (e->flags & (1 << NFTNL_OBJ_CT_TIMEOUT_POLICY)) { + uint8_t l4num = timeout->l4proto; + int i; + + /* default to generic protocol tracker. */ + if (timeout_protocol[timeout->l4proto].attr_max == 0) + l4num = IPPROTO_RAW; + + ret = snprintf(buf+offset, len, "policy = {"); + SNPRINTF_BUFFER_SIZE(ret, remain, offset); + + for (i = 0; i < timeout_protocol[l4num].attr_max; i++) { + const char *state_name = + timeout_protocol[l4num].state_to_name[i][0] ? + timeout_protocol[l4num].state_to_name[i] : + "UNKNOWN"; + + ret = snprintf(buf+offset, len, + "%s = %u,", state_name, timeout->timeout[i]); + SNPRINTF_BUFFER_SIZE(ret, remain, offset); + } + + ret = snprintf(buf+offset, len, "}"); + SNPRINTF_BUFFER_SIZE(ret, remain, offset); + } + buf[offset] = '\0'; + + return ret; + +} + +static int nftnl_obj_ct_timeout_snprintf(char *buf, size_t len, uint32_t type, + uint32_t flags, + const struct nftnl_obj *e) +{ + if (len) + buf[0] = '\0'; + + switch (type) { + case NFTNL_OUTPUT_DEFAULT: + return nftnl_obj_ct_timeout_snprintf_default(buf, len, e); + case NFTNL_OUTPUT_JSON: + return nftnl_obj_ct_timeout_export(buf, len, e, type); + default: + break; + } + return -1; +} + +struct obj_ops obj_ops_ct_timeout = { + .name = "ct_timeout", + .type = NFT_OBJECT_CT_TIMEOUT, + .alloc_len = sizeof(struct nftnl_obj_ct_timeout), + .max_attr = NFTA_CT_TIMEOUT_MAX, + .set = nftnl_obj_ct_timeout_set, + .get = nftnl_obj_ct_timeout_get, + .parse = nftnl_obj_ct_timeout_parse, + .build = nftnl_obj_ct_timeout_build, + .snprintf = nftnl_obj_ct_timeout_snprintf, +// .json_parse = nftnl_obj_quota_json_parse, +}; diff --git a/src/object.c b/src/object.c index d8278f3..180afd1 100644 --- a/src/object.c +++ b/src/object.c @@ -30,6 +30,7 @@ static struct obj_ops *obj_ops[] = { [NFT_OBJECT_QUOTA] = &obj_ops_quota, [NFT_OBJECT_CT_HELPER] = &obj_ops_ct_helper, [NFT_OBJECT_LIMIT] = &obj_ops_limit, + [NFT_OBJECT_CT_TIMEOUT] = &obj_ops_ct_timeout, }; static struct obj_ops *nftnl_obj_ops_lookup(uint32_t type) @@ -454,7 +455,8 @@ static int nftnl_obj_snprintf_dflt(char *buf, size_t size, obj); SNPRINTF_BUFFER_SIZE(ret, remain, offset); } - ret = snprintf(buf + offset, offset, "]"); + + ret = snprintf(buf + strlen(buf), offset, "]"); SNPRINTF_BUFFER_SIZE(ret, remain, offset); return offset; -- 2.14.1 -- To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html