summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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));