summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarsha Sharma <harshasharmaiitr@gmail.com>2018-08-14 01:06:56 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2018-08-31 18:40:08 +0200
commitc7c94802679cd9ba09aa78f332f533ecae1b9e0c (patch)
treebe2c336e6ff9de9c1a5b4e21ceca6ab5daae4a69
parent2e62c72974dcb2d4c4db1445ae55310a4f84ec15 (diff)
src: add ct timeout support
This patch adds support for adding, listing and deleting ct timeout objects which can be assigned via rule to assign connection tracking timeout policies via objref infrastructure. % nft add table filter % nft add chain filter output % nft add ct timeout filter test-tcp { protocol tcp \; policy = { established: 132, close: 13, close_wait: 17 } \; } % nft add rule filter output ct timeout set test-tcp % nft list ruleset table ip filter { ct timeout test-tcp { protocol tcp; l3proto ip policy = {established: 132, close_wait: 17, close: 13} } chain output { ct timeout set "test-tcp" } } % nft delete rule filter output handle <handle> % nft delete ct timeout filter test-tcp Note: Original patch has been rework to use fixed size array for timeouts and to validate timeout policy from the evaluation phase, once we have access to the layer 4 protocol number. --pablo Signed-off-by: Harsha Sharma <harshasharmaiitr@gmail.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r--include/linux/netfilter/nf_tables.h14
-rw-r--r--include/rule.h28
-rw-r--r--src/evaluate.c36
-rw-r--r--src/netlink.c15
-rw-r--r--src/parser_bison.y91
-rw-r--r--src/rule.c115
-rw-r--r--src/statement.c4
7 files changed, 298 insertions, 5 deletions
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index fe656525..143ebe28 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -972,6 +972,7 @@ enum nft_osf_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,
@@ -997,6 +998,7 @@ enum nft_ct_keys {
NFT_CT_DST_IP,
NFT_CT_SRC_IP6,
NFT_CT_DST_IP6,
+ NFT_CT_TIMEOUT,
__NFT_CT_MAX
};
#define NFT_CT_MAX (__NFT_CT_MAX - 1)
@@ -1403,13 +1405,23 @@ enum nft_ct_helper_attributes {
};
#define NFTA_CT_HELPER_MAX (__NFTA_CT_HELPER_MAX - 1)
+enum nft_ct_timeout_attributes {
+ NFTA_CT_TIMEOUT_L3PROTO,
+ NFTA_CT_TIMEOUT_L4PROTO,
+ NFTA_CT_TIMEOUT_DATA,
+ __NFTA_CT_TIMEOUT_MAX,
+};
+#define NFTA_CT_TIMEOUT_MAX (__NFTA_CT_TIMEOUT_MAX - 1)
+
#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_CONNLIMIT 5
-#define __NFT_OBJECT_MAX 6
+#define NFT_OBJECT_TUNNEL 6
+#define NFT_OBJECT_CT_TIMEOUT 7
+#define __NFT_OBJECT_MAX 8
#define NFT_OBJECT_MAX (__NFT_OBJECT_MAX - 1)
/**
diff --git a/include/rule.h b/include/rule.h
index cfbbcf1f..88478aa6 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -4,6 +4,8 @@
#include <stdint.h>
#include <nftables.h>
#include <list.h>
+#include <netinet/in.h>
+#include <libnftnl/object.h> /* For NFTNL_CTTIMEOUT_ARRAY_MAX. */
/**
* struct handle_spec - handle ID
@@ -324,6 +326,21 @@ struct ct_helper {
uint8_t l4proto;
};
+struct timeout_state {
+ struct list_head head;
+ struct location location;
+ uint8_t timeout_index;
+ const char *timeout_str;
+ unsigned int timeout_value;
+};
+
+struct ct_timeout {
+ uint16_t l3proto;
+ uint8_t l4proto;
+ uint32_t timeout[NFTNL_CTTIMEOUT_ARRAY_MAX];
+ struct list_head timeout_list;
+};
+
struct limit {
uint64_t rate;
uint64_t unit;
@@ -352,6 +369,7 @@ struct obj {
struct quota quota;
struct ct_helper ct_helper;
struct limit limit;
+ struct ct_timeout ct_timeout;
};
};
@@ -478,6 +496,7 @@ enum cmd_obj {
CMD_OBJ_LIMITS,
CMD_OBJ_FLOWTABLE,
CMD_OBJ_FLOWTABLES,
+ CMD_OBJ_CT_TIMEOUT,
};
struct markup {
@@ -633,4 +652,13 @@ enum udata_set_elem_flags {
SET_ELEM_F_INTERVAL_OPEN = 0x1,
};
+struct timeout_protocol {
+ uint32_t array_size;
+ const char *const *state_to_name;
+ uint32_t *dflt_timeout;
+};
+
+extern struct timeout_protocol timeout_protocol[IPPROTO_MAX];
+extern int timeout_str2num(uint16_t l4proto, struct timeout_state *ts);
+
#endif /* NFTABLES_RULE_H */
diff --git a/src/evaluate.c b/src/evaluate.c
index a3a78744..9a7118ec 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -3196,11 +3196,36 @@ static int chain_evaluate(struct eval_ctx *ctx, struct chain *chain)
return 0;
}
+static int obj_evaluate(struct eval_ctx *ctx, struct obj *obj)
+{
+ struct ct_timeout *ct = &obj->ct_timeout;
+ struct timeout_state *ts, *next;
+ unsigned int i;
+
+ if (obj->type != NFT_OBJECT_CT_TIMEOUT)
+ return 0;
+
+ for (i = 0; i < timeout_protocol[ct->l4proto].array_size; i++)
+ ct->timeout[i] = timeout_protocol[ct->l4proto].dflt_timeout[i];
+
+ list_for_each_entry_safe(ts, next, &ct->timeout_list, head) {
+ if (timeout_str2num(ct->l4proto, ts) < 0)
+ return __stmt_binary_error(ctx, &ts->location, NULL,
+ "invalid state for this protocol");
+
+ ct->timeout[ts->timeout_index] = ts->timeout_value;
+ list_del(&ts->head);
+ xfree(ts);
+ }
+ return 0;
+}
+
static int table_evaluate(struct eval_ctx *ctx, struct table *table)
{
struct flowtable *ft;
struct chain *chain;
struct set *set;
+ struct obj *obj;
if (table_lookup(&ctx->cmd->handle, ctx->cache) == NULL) {
if (table == NULL) {
@@ -3232,6 +3257,11 @@ static int table_evaluate(struct eval_ctx *ctx, struct table *table)
if (flowtable_evaluate(ctx, ft) < 0)
return -1;
}
+ list_for_each_entry(obj, &table->objs, list) {
+ handle_merge(&obj->handle, &table->handle);
+ if (obj_evaluate(ctx, obj) < 0)
+ return -1;
+ }
ctx->table = NULL;
return 0;
@@ -3281,7 +3311,8 @@ static int cmd_evaluate_add(struct eval_ctx *ctx, struct cmd *cmd)
case CMD_OBJ_QUOTA:
case CMD_OBJ_CT_HELPER:
case CMD_OBJ_LIMIT:
- return 0;
+ case CMD_OBJ_CT_TIMEOUT:
+ return obj_evaluate(ctx, cmd->object);
default:
BUG("invalid command object type %u\n", cmd->obj);
}
@@ -3307,6 +3338,7 @@ static int cmd_evaluate_delete(struct eval_ctx *ctx, struct cmd *cmd)
case CMD_OBJ_COUNTER:
case CMD_OBJ_QUOTA:
case CMD_OBJ_CT_HELPER:
+ case CMD_OBJ_CT_TIMEOUT:
case CMD_OBJ_LIMIT:
return 0;
default:
@@ -3439,6 +3471,8 @@ static int cmd_evaluate_list(struct eval_ctx *ctx, struct cmd *cmd)
return cmd_evaluate_list_obj(ctx, cmd, NFT_OBJECT_COUNTER);
case CMD_OBJ_CT_HELPER:
return cmd_evaluate_list_obj(ctx, cmd, NFT_OBJECT_CT_HELPER);
+ case CMD_OBJ_CT_TIMEOUT:
+ return cmd_evaluate_list_obj(ctx, cmd, NFT_OBJECT_CT_TIMEOUT);
case CMD_OBJ_LIMIT:
return cmd_evaluate_list_obj(ctx, cmd, NFT_OBJECT_LIMIT);
case CMD_OBJ_COUNTERS:
diff --git a/src/netlink.c b/src/netlink.c
index bd472799..f795d984 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -334,6 +334,14 @@ alloc_nftnl_obj(const struct handle *h, struct obj *obj)
nftnl_obj_set_u16(nlo, NFTNL_OBJ_CT_HELPER_L3PROTO,
obj->ct_helper.l3proto);
break;
+ case NFT_OBJECT_CT_TIMEOUT:
+ nftnl_obj_set_u8(nlo, NFTNL_OBJ_CT_TIMEOUT_L4PROTO,
+ obj->ct_timeout.l4proto);
+ if (obj->ct_timeout.l3proto)
+ nftnl_obj_set_u16(nlo, NFTNL_OBJ_CT_TIMEOUT_L3PROTO,
+ obj->ct_timeout.l3proto);
+ nftnl_obj_set(nlo, NFTNL_OBJ_CT_TIMEOUT_ARRAY, obj->ct_timeout.timeout);
+ break;
case NFT_OBJECT_LIMIT:
nftnl_obj_set_u64(nlo, NFTNL_OBJ_LIMIT_RATE, obj->limit.rate);
nftnl_obj_set_u64(nlo, NFTNL_OBJ_LIMIT_UNIT, obj->limit.unit);
@@ -1437,6 +1445,13 @@ struct obj *netlink_delinearize_obj(struct netlink_ctx *ctx,
obj->ct_helper.l3proto = nftnl_obj_get_u16(nlo, NFTNL_OBJ_CT_HELPER_L3PROTO);
obj->ct_helper.l4proto = nftnl_obj_get_u8(nlo, NFTNL_OBJ_CT_HELPER_L4PROTO);
break;
+ case NFT_OBJECT_CT_TIMEOUT:
+ obj->ct_timeout.l3proto = nftnl_obj_get_u16(nlo, NFTNL_OBJ_CT_TIMEOUT_L3PROTO);
+ obj->ct_timeout.l4proto = nftnl_obj_get_u8(nlo, NFTNL_OBJ_CT_TIMEOUT_L4PROTO);
+ memcpy(obj->ct_timeout.timeout,
+ nftnl_obj_get(nlo, NFTNL_OBJ_CT_TIMEOUT_ARRAY),
+ NFTNL_CTTIMEOUT_ARRAY_MAX * sizeof(uint32_t));
+ break;
case NFT_OBJECT_LIMIT:
obj->limit.rate =
nftnl_obj_get_u64(nlo, NFTNL_OBJ_LIMIT_RATE);
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 86036124..85830d88 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -554,7 +554,7 @@ int nft_lex(void *, void *, void *);
%type <flowtable> flowtable_block_alloc flowtable_block
%destructor { flowtable_free($$); } flowtable_block_alloc
-%type <obj> obj_block_alloc counter_block quota_block ct_helper_block limit_block
+%type <obj> obj_block_alloc counter_block quota_block ct_helper_block ct_timeout_block limit_block
%destructor { obj_free($$); } obj_block_alloc
%type <list> stmt_list
@@ -755,6 +755,9 @@ int nft_lex(void *, void *, void *);
%type <val> ct_l4protoname ct_obj_type
+%type <list> timeout_states timeout_state
+%destructor { xfree($$); } timeout_states timeout_state
+
%%
input : /* empty */
@@ -962,6 +965,10 @@ add_cmd : TABLE table_spec
$$ = cmd_alloc_obj_ct(CMD_ADD, NFT_OBJECT_CT_HELPER, &$3, &@$, $4);
}
+ | CT TIMEOUT obj_spec ct_obj_alloc '{' ct_timeout_block '}' stmt_separator
+ {
+ $$ = cmd_alloc_obj_ct(CMD_ADD, NFT_OBJECT_CT_TIMEOUT, &$3, &@$, $4);
+ }
| LIMIT obj_spec limit_obj
{
$$ = cmd_alloc(CMD_ADD, CMD_OBJ_LIMIT, &$2, &@$, $3);
@@ -1043,6 +1050,10 @@ create_cmd : TABLE table_spec
{
$$ = cmd_alloc_obj_ct(CMD_CREATE, NFT_OBJECT_CT_HELPER, &$3, &@$, $4);
}
+ | CT TIMEOUT obj_spec ct_obj_alloc '{' ct_timeout_block '}' stmt_separator
+ {
+ $$ = cmd_alloc_obj_ct(CMD_CREATE, NFT_OBJECT_CT_TIMEOUT, &$3, &@$, $4);
+ }
| LIMIT obj_spec limit_obj
{
$$ = cmd_alloc(CMD_CREATE, CMD_OBJ_LIMIT, &$2, &@$, $3);
@@ -1235,6 +1246,10 @@ list_cmd : TABLE table_spec
{
$$ = cmd_alloc(CMD_LIST, CMD_OBJ_CT_HELPERS, &$4, &@$, NULL);
}
+ | CT TIMEOUT TABLE table_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_CT_TIMEOUT, &$4, &@$, NULL);
+ }
;
reset_cmd : COUNTERS ruleset_spec
@@ -1466,6 +1481,15 @@ table_block : /* empty */ { $$ = $<table>-1; }
list_add_tail(&$5->list, &$1->objs);
$$ = $1;
}
+ | table_block CT TIMEOUT obj_identifier obj_block_alloc '{' ct_timeout_block '}' stmt_separator
+ {
+ $5->location = @4;
+ $5->type = NFT_OBJECT_CT_TIMEOUT;
+ handle_merge(&$5->handle, &$4);
+ handle_free(&$4);
+ list_add_tail(&$5->list, &$1->objs);
+ $$ = $1;
+ }
| table_block LIMIT obj_identifier
obj_block_alloc '{' limit_block '}'
stmt_separator
@@ -1761,6 +1785,15 @@ ct_helper_block : /* empty */ { $$ = $<obj>-1; }
}
;
+ct_timeout_block : /*empty */ { $$ = $<obj>-1; }
+ | ct_timeout_block common_block
+ | ct_timeout_block stmt_separator
+ | ct_timeout_block ct_timeout_config
+ {
+ $$ = $1;
+ }
+ ;
+
limit_block : /* empty */ { $$ = $<obj>-1; }
| limit_block common_block
| limit_block stmt_separator
@@ -3279,6 +3312,7 @@ quota_obj : quota_config
;
ct_obj_type : HELPER { $$ = NFT_OBJECT_CT_HELPER; }
+ | TIMEOUT { $$ = NFT_OBJECT_CT_TIMEOUT; }
;
ct_l4protoname : TCP { $$ = IPPROTO_TCP; }
@@ -3306,6 +3340,55 @@ ct_helper_config : TYPE QUOTED_STRING PROTOCOL ct_l4protoname stmt_separator
}
;
+timeout_states : timeout_state
+ {
+ $$ = xmalloc(sizeof(*$$));
+ init_list_head($$);
+ list_add_tail($1, $$);
+ }
+ | timeout_states COMMA timeout_state
+ {
+ list_add_tail($3, $1);
+ $$ = $1;
+ }
+ ;
+
+timeout_state : STRING COLON NUM
+
+ {
+ struct timeout_state *ts;
+
+ ts = xzalloc(sizeof(*ts));
+ ts->timeout_str = $1;
+ ts->timeout_value = $3;
+ ts->location = @1;
+ init_list_head(&ts->head);
+ $$ = &ts->head;
+ }
+ ;
+
+ct_timeout_config : PROTOCOL ct_l4protoname SEMICOLON
+ {
+ struct ct_timeout *ct;
+ int l4proto = $2;
+
+ ct = &$<obj>0->ct_timeout;
+ ct->l4proto = l4proto;
+ }
+ | POLICY '=' '{' timeout_states '}' stmt_separator
+ {
+ struct ct_timeout *ct;
+
+ ct = &$<obj>0->ct_timeout;
+ init_list_head(&ct->timeout_list);
+ list_splice_tail($4, &ct->timeout_list);
+ }
+ | L3PROTOCOL family_spec_explicit stmt_separator
+ {
+ $<obj>0->ct_timeout.l3proto = $2;
+ }
+ ;
+
ct_obj_alloc :
{
$$ = obj_alloc(&@$);
@@ -3781,6 +3864,7 @@ ct_key : L3PROTOCOL { $$ = NFT_CT_L3PROTOCOL; }
| PROTO_DST { $$ = NFT_CT_PROTO_DST; }
| LABEL { $$ = NFT_CT_LABELS; }
| EVENT { $$ = NFT_CT_EVENTMASK; }
+ | TIMEOUT { $$ = NFT_CT_TIMEOUT; }
| ct_key_dir_optional
;
@@ -3829,6 +3913,11 @@ ct_stmt : CT ct_key SET stmt_expr
$$->objref.type = NFT_OBJECT_CT_HELPER;
$$->objref.expr = $4;
break;
+ case NFT_CT_TIMEOUT:
+ $$ = objref_stmt_alloc(&@$);
+ $$->objref.type = NFT_OBJECT_CT_TIMEOUT;
+ $$->objref.expr = $4;
+ break;
default:
$$ = ct_stmt_alloc(&@$, $2, -1, $4);
break;
diff --git a/src/rule.c b/src/rule.c
index 470b112e..68abdc34 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -32,6 +32,70 @@
#include <net/if.h>
#include <linux/netfilter_bridge.h>
+static const char *const tcp_state_to_name[] = {
+ [NFTNL_CTTIMEOUT_TCP_SYN_SENT] = "syn_sent",
+ [NFTNL_CTTIMEOUT_TCP_SYN_RECV] = "syn_recv",
+ [NFTNL_CTTIMEOUT_TCP_ESTABLISHED] = "established",
+ [NFTNL_CTTIMEOUT_TCP_FIN_WAIT] = "fin_wait",
+ [NFTNL_CTTIMEOUT_TCP_CLOSE_WAIT] = "close_wait",
+ [NFTNL_CTTIMEOUT_TCP_LAST_ACK] = "last_ack",
+ [NFTNL_CTTIMEOUT_TCP_TIME_WAIT] = "time_wait",
+ [NFTNL_CTTIMEOUT_TCP_CLOSE] = "close",
+ [NFTNL_CTTIMEOUT_TCP_SYN_SENT2] = "syn_sent2",
+ [NFTNL_CTTIMEOUT_TCP_RETRANS] = "retrans",
+ [NFTNL_CTTIMEOUT_TCP_UNACK] = "unack",
+};
+
+static const char *const udp_state_to_name[] = {
+ [NFTNL_CTTIMEOUT_UDP_UNREPLIED] = "unreplied",
+ [NFTNL_CTTIMEOUT_UDP_REPLIED] = "replied",
+};
+
+static uint32_t tcp_dflt_timeout[] = {
+ [NFTNL_CTTIMEOUT_TCP_SYN_SENT] = 120,
+ [NFTNL_CTTIMEOUT_TCP_SYN_RECV] = 60,
+ [NFTNL_CTTIMEOUT_TCP_ESTABLISHED] = 432000,
+ [NFTNL_CTTIMEOUT_TCP_FIN_WAIT] = 120,
+ [NFTNL_CTTIMEOUT_TCP_CLOSE_WAIT] = 60,
+ [NFTNL_CTTIMEOUT_TCP_LAST_ACK] = 30,
+ [NFTNL_CTTIMEOUT_TCP_TIME_WAIT] = 120,
+ [NFTNL_CTTIMEOUT_TCP_CLOSE] = 10,
+ [NFTNL_CTTIMEOUT_TCP_SYN_SENT2] = 120,
+ [NFTNL_CTTIMEOUT_TCP_RETRANS] = 300,
+ [NFTNL_CTTIMEOUT_TCP_UNACK] = 300,
+};
+
+static uint32_t udp_dflt_timeout[] = {
+ [NFTNL_CTTIMEOUT_UDP_UNREPLIED] = 30,
+ [NFTNL_CTTIMEOUT_UDP_REPLIED] = 180,
+};
+
+struct timeout_protocol timeout_protocol[IPPROTO_MAX] = {
+ [IPPROTO_TCP] = {
+ .array_size = NFTNL_CTTIMEOUT_TCP_MAX,
+ .state_to_name = tcp_state_to_name,
+ .dflt_timeout = tcp_dflt_timeout,
+ },
+ [IPPROTO_UDP] = {
+ .array_size = NFTNL_CTTIMEOUT_UDP_MAX,
+ .state_to_name = udp_state_to_name,
+ .dflt_timeout = udp_dflt_timeout,
+ },
+};
+
+int timeout_str2num(uint16_t l4proto, struct timeout_state *ts)
+{
+ unsigned int i;
+
+ for (i = 0; i < timeout_protocol[l4proto].array_size; i++) {
+ if (!strcmp(timeout_protocol[l4proto].state_to_name[i], ts->timeout_str)) {
+ ts->timeout_index = i;
+ return 0;
+ }
+ }
+ return -1;
+}
+
void handle_free(struct handle *h)
{
xfree(h->table.name);
@@ -1261,6 +1325,7 @@ void cmd_free(struct cmd *cmd)
case CMD_OBJ_COUNTER:
case CMD_OBJ_QUOTA:
case CMD_OBJ_CT_HELPER:
+ case CMD_OBJ_CT_TIMEOUT:
case CMD_OBJ_LIMIT:
obj_free(cmd->object);
break;
@@ -1359,6 +1424,7 @@ static int do_command_add(struct netlink_ctx *ctx, struct cmd *cmd, bool excl)
case CMD_OBJ_COUNTER:
case CMD_OBJ_QUOTA:
case CMD_OBJ_CT_HELPER:
+ case CMD_OBJ_CT_TIMEOUT:
case CMD_OBJ_LIMIT:
return netlink_add_obj(ctx, cmd, flags);
case CMD_OBJ_FLOWTABLE:
@@ -1444,6 +1510,9 @@ static int do_command_delete(struct netlink_ctx *ctx, struct cmd *cmd)
return netlink_delete_obj(ctx, cmd, NFT_OBJECT_QUOTA);
case CMD_OBJ_CT_HELPER:
return netlink_delete_obj(ctx, cmd, NFT_OBJECT_CT_HELPER);
+ case CMD_OBJ_CT_TIMEOUT:
+ return netlink_delete_obj(ctx, cmd,
+ NFT_OBJECT_CT_TIMEOUT);
case CMD_OBJ_LIMIT:
return netlink_delete_obj(ctx, cmd, NFT_OBJECT_LIMIT);
case CMD_OBJ_FLOWTABLE:
@@ -1589,9 +1658,29 @@ static void print_proto_name_proto(uint8_t l4, struct output_ctx *octx)
const struct protoent *p = getprotobynumber(l4);
if (p)
- nft_print(octx, "%s\n", p->p_name);
+ nft_print(octx, "%s", p->p_name);
else
- nft_print(octx, "%d\n", l4);
+ nft_print(octx, "%d", l4);
+}
+
+static void print_proto_timeout_policy(uint8_t l4, const uint32_t *timeout,
+ struct output_ctx *octx)
+{
+ bool comma = false;
+ unsigned int i;
+
+ nft_print(octx, "\t\tpolicy = {");
+ for (i = 0; i < timeout_protocol[l4].array_size; i++) {
+ if (timeout[i] != timeout_protocol[l4].dflt_timeout[i]) {
+ if (comma)
+ nft_print(octx, ", ");
+ nft_print(octx, "%s: %u",
+ timeout_protocol[l4].state_to_name[i],
+ timeout[i]);
+ comma = true;
+ }
+ }
+ nft_print(octx, "}");
}
static void obj_print_data(const struct obj *obj,
@@ -1638,9 +1727,24 @@ static void obj_print_data(const struct obj *obj,
nft_print(octx, "\t\ttype \"%s\" protocol ",
obj->ct_helper.name);
print_proto_name_proto(obj->ct_helper.l4proto, octx);
+ nft_print(octx, "\n");
nft_print(octx, "\t\tl3proto %s",
family2str(obj->ct_helper.l3proto));
break;
+ case NFT_OBJECT_CT_TIMEOUT:
+ nft_print(octx, "ct timeout %s {", obj->handle.obj.name);
+ if (octx->handle > 0)
+ nft_print(octx, " # handle %" PRIu64, obj->handle.handle.id);
+ nft_print(octx, "%s", opts->nl);
+ nft_print(octx, "\t\tprotocol ");
+ print_proto_name_proto(obj->ct_timeout.l4proto, octx);
+ nft_print(octx, ";%s", opts->nl);
+ nft_print(octx, "\t\tl3proto %s",
+ family2str(obj->ct_timeout.l3proto));
+ nft_print(octx, "%s", opts->nl);
+ print_proto_timeout_policy(obj->ct_timeout.l4proto,
+ obj->ct_timeout.timeout, octx);
+ break;
case NFT_OBJECT_LIMIT: {
bool inv = obj->limit.flags & NFT_LIMIT_F_INV;
const char *data_unit;
@@ -1687,6 +1791,7 @@ static const char * const obj_type_name_array[] = {
[NFT_OBJECT_QUOTA] = "quota",
[NFT_OBJECT_CT_HELPER] = "",
[NFT_OBJECT_LIMIT] = "limit",
+ [NFT_OBJECT_CT_TIMEOUT] = "",
};
const char *obj_type_name(enum stmt_types type)
@@ -1701,6 +1806,7 @@ static uint32_t obj_type_cmd_array[NFT_OBJECT_MAX + 1] = {
[NFT_OBJECT_QUOTA] = CMD_OBJ_QUOTA,
[NFT_OBJECT_CT_HELPER] = CMD_OBJ_CT_HELPER,
[NFT_OBJECT_LIMIT] = CMD_OBJ_LIMIT,
+ [NFT_OBJECT_CT_TIMEOUT] = CMD_OBJ_CT_TIMEOUT,
};
uint32_t obj_type_to_cmd(uint32_t type)
@@ -2054,6 +2160,8 @@ static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
case CMD_OBJ_CT_HELPER:
case CMD_OBJ_CT_HELPERS:
return do_list_obj(ctx, cmd, NFT_OBJECT_CT_HELPER);
+ case CMD_OBJ_CT_TIMEOUT:
+ return do_list_obj(ctx, cmd, NFT_OBJECT_CT_TIMEOUT);
case CMD_OBJ_LIMIT:
case CMD_OBJ_LIMITS:
return do_list_obj(ctx, cmd, NFT_OBJECT_LIMIT);
@@ -2271,6 +2379,9 @@ struct cmd *cmd_alloc_obj_ct(enum cmd_ops op, int type, const struct handle *h,
case NFT_OBJECT_CT_HELPER:
cmd_obj = CMD_OBJ_CT_HELPER;
break;
+ case NFT_OBJECT_CT_TIMEOUT:
+ cmd_obj = CMD_OBJ_CT_TIMEOUT;
+ break;
default:
BUG("missing type mapping");
}
diff --git a/src/statement.c b/src/statement.c
index 45d2067c..a02ebc84 100644
--- a/src/statement.c
+++ b/src/statement.c
@@ -203,6 +203,7 @@ static const char *objref_type[NFT_OBJECT_MAX + 1] = {
[NFT_OBJECT_QUOTA] = "quota",
[NFT_OBJECT_CT_HELPER] = "ct helper",
[NFT_OBJECT_LIMIT] = "limit",
+ [NFT_OBJECT_CT_TIMEOUT] = "ct timeout",
};
const char *objref_type_name(uint32_t type)
@@ -219,6 +220,9 @@ static void objref_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
case NFT_OBJECT_CT_HELPER:
nft_print(octx, "ct helper set ");
break;
+ case NFT_OBJECT_CT_TIMEOUT:
+ nft_print(octx, "ct timeout set ");
+ break;
default:
nft_print(octx, "%s name ",
objref_type_name(stmt->objref.type));