]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: add ct expectations support
authorStéphane Veyret <sveyret@gmail.com>
Tue, 9 Jul 2019 13:02:09 +0000 (15:02 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Tue, 16 Jul 2019 19:26:52 +0000 (21:26 +0200)
This modification allow to directly add/list/delete expectations.

Signed-off-by: Stéphane Veyret <sveyret@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
19 files changed:
doc/libnftables-json.adoc
doc/stateful-objects.txt
include/linux/netfilter/nf_tables.h
include/rule.h
src/evaluate.c
src/json.c
src/mnl.c
src/netlink.c
src/parser_bison.y
src/parser_json.c
src/rule.c
src/scanner.l
src/statement.c
tests/py/ip/objects.t
tests/py/ip/objects.t.json
tests/py/ip/objects.t.payload
tests/py/nft-test.py
tests/shell/testcases/listing/0013objects_0
tests/shell/testcases/nft-f/0018ct_expectation_obj_0 [new file with mode: 0755]

index 429f530db913c933112d40a4f4f62d6edbe3a493..6877f0549db1f3405bcf1ba93eb7207d4781d874 100644 (file)
@@ -23,7 +23,7 @@ libnftables-json - Supported JSON schema by libnftables
 
 'LIST_OBJECT' := 'TABLE' | 'CHAIN' | 'RULE' | 'SET' | 'MAP' | 'ELEMENT' |
                 'FLOWTABLE' | 'COUNTER' | 'QUOTA' | 'CT_HELPER' | 'LIMIT' |
-                'METAINFO_OBJECT' | 'CT_TIMEOUT'
+                'METAINFO_OBJECT' | 'CT_TIMEOUT' | 'CT_EXPECTATION'
 
 == DESCRIPTION
 libnftables supports JSON formatted input and output. This is implemented as an
@@ -118,7 +118,7 @@ ____
 
 'ADD_OBJECT' := 'TABLE' | 'CHAIN' | 'RULE' | 'SET' | 'MAP' | 'ELEMENT' |
                 'FLOWTABLE' | 'COUNTER | QUOTA' | 'CT_HELPER' | 'LIMIT' |
-               'CT_TIMEOUT'
+               'CT_TIMEOUT' | 'CT_EXPECTATION'
 ____
 
 Add a new ruleset element to the kernel.
@@ -162,7 +162,8 @@ ____
 'LIST_OBJECT' := 'TABLE' | 'TABLES' | 'CHAIN' | 'CHAINS' | 'SET' | 'SETS' |
                  'MAP' | 'MAPS | COUNTER' | 'COUNTERS' | 'QUOTA' | 'QUOTAS' |
                  'CT_HELPER' | 'CT_HELPERS' | 'LIMIT' | 'LIMITS | RULESET' |
-                 'METER' | 'METERS' | 'FLOWTABLES' | 'CT_TIMEOUT'
+                 'METER' | 'METERS' | 'FLOWTABLES' | 'CT_TIMEOUT' |
+                 'CT_EXPECTATION'
 ____
 
 List ruleset elements. The plural forms are used to list all objects of that
@@ -597,6 +598,45 @@ This object represents a named conntrack timeout policy.
 *l3proto*::
        The ct timeout object's layer 3 protocol, e.g. *"ip"* or *"ip6"*.
 
+=== CT EXPECTATION
+[verse]
+____
+*{ "ct expectation": {
+       "family":* 'STRING'*,
+       "table":* 'STRING'*,
+       "name":* 'STRING'*,
+       "handle":* 'NUMBER'*,
+       "l3proto":* 'STRING'
+       "protocol":* 'CTH_PROTO'*,
+       "dport":* 'NUMBER'*,
+       "timeout:* 'NUMBER'*,
+       "size:* 'NUMBER'*,
+*}}*
+
+'CTH_PROTO' := *"tcp"* | *"udp"* | *"dccp"* | *"sctp"* | *"gre"* | *"icmpv6"* | *"icmp"* | *"generic"*
+____
+
+This object represents a named conntrack expectation.
+
+*family*::
+       The table's family.
+*table*::
+       The table's name.
+*name*::
+       The ct expectation object's name.
+*handle*::
+       The ct expectation object's handle. In input, it is used by *delete* command only.
+*l3proto*::
+       The ct expectation object's layer 3 protocol, e.g. *"ip"* or *"ip6"*.
+*protocol*::
+       The ct expectation object's layer 4 protocol.
+*dport*::
+       The destination port of the expected connection.
+*timeout*::
+       The time in millisecond that this expectation will live.
+*size*::
+       The maximum count of expectations to be living in the same time.
+
 == STATEMENTS
 Statements are the building blocks for rules. Each rule consists of at least
 one.
@@ -1004,6 +1044,15 @@ Assign connection tracking timeout policy.
 *ct timeout*::
        CT timeout reference.
 
+=== CT EXPECTATION
+[verse]
+*{ "ct expectation":* 'EXPRESSION' *}*
+
+Assign connection tracking expectation.
+
+*ct expectation*::
+       CT expectation reference.
+
 === XT
 [verse]
 *{ "xt": null }*
index cc1b698d7831aca3dc187446594d7b5c6c2a9e22..32a3a5c816cf2023680767ecde8782f40db390e5 100644 (file)
@@ -95,6 +95,55 @@ sport=22 dport=41360 [UNREPLIED] src=172.16.19.1 dst=172.16.19.128
 sport=41360 dport=22
 ----------------------------------
 
+CT EXPECTATION
+~~~~~~~~~~~~~~
+[verse]
+*ct expectation* 'name' *{ protocol* 'protocol' *; dport* 'dport' *; timeout* 'timeout' *; size* 'size' *; [*l3proto* 'family' *;*] *}*
+
+Ct expectation is used to create connection expectations. Expectations are
+assigned with the *ct expectation set* statement. 'protocol', 'dport',
+'timeout' and 'size' are mandatory, l3proto is derived from the table family
+by default.
+
+.conntrack expectation specifications
+[options="header"]
+|=================
+|Keyword | Description | Type
+|protocol |
+layer 4 protocol of the expectation object |
+string (e.g. ip)
+|dport |
+destination port of expected connection |
+unsigned integer
+|timeout |
+timeout value for expectation |
+unsigned integer
+|size |
+size value for expectation |
+unsigned integer
+|l3proto |
+layer 3 protocol of the expectation object |
+address family (e.g. ip)
+|=================
+
+.defining and assigning ct expectation policy
+---------------------------------------------
+table ip filter {
+       ct expectation expect {
+               protocol udp
+               dport 9876
+               timeout 2m
+               size 8
+               l3proto ip
+       }
+
+       chain input {
+               type filter hook input priority filter; policy accept;
+               ct expectation set "expect"
+       }
+}
+----------------------------------
+
 COUNTER
 ~~~~~~~
 [verse]
index 393bcb5677a2b16328f5db0634e96daf65bbf493..709fbc8d70e10a7200ab0a9e3b670ddcf7b946c2 100644 (file)
@@ -1445,6 +1445,17 @@ enum nft_ct_timeout_timeout_attributes {
 };
 #define NFTA_CT_TIMEOUT_MAX    (__NFTA_CT_TIMEOUT_MAX - 1)
 
+enum nft_ct_expect_attributes {
+       NFTA_CT_EXPECT_UNSPEC,
+       NFTA_CT_EXPECT_L3PROTO,
+       NFTA_CT_EXPECT_L4PROTO,
+       NFTA_CT_EXPECT_DPORT,
+       NFTA_CT_EXPECT_TIMEOUT,
+       NFTA_CT_EXPECT_SIZE,
+       __NFTA_CT_EXPECT_MAX,
+};
+#define NFTA_CT_EXPECT_MAX     (__NFTA_CT_EXPECT_MAX - 1)
+
 #define NFT_OBJECT_UNSPEC      0
 #define NFT_OBJECT_COUNTER     1
 #define NFT_OBJECT_QUOTA       2
@@ -1454,7 +1465,8 @@ enum nft_ct_timeout_timeout_attributes {
 #define NFT_OBJECT_TUNNEL      6
 #define NFT_OBJECT_CT_TIMEOUT  7
 #define NFT_OBJECT_SECMARK     8
-#define __NFT_OBJECT_MAX       9
+#define NFT_OBJECT_CT_EXPECT   9
+#define __NFT_OBJECT_MAX       10
 #define NFT_OBJECT_MAX         (__NFT_OBJECT_MAX - 1)
 
 /**
index 42d29b7c910e659d608ca79c36b48750feb5f0f9..67c3d3314953136b2be9e9597d1af351f39a2b0f 100644 (file)
@@ -386,6 +386,14 @@ struct ct_timeout {
        struct list_head timeout_list;
 };
 
+struct ct_expect {
+       uint16_t l3proto;
+       uint8_t l4proto;
+       uint16_t dport;
+       uint32_t timeout;
+       uint8_t size;
+};
+
 struct limit {
        uint64_t        rate;
        uint64_t        unit;
@@ -420,6 +428,7 @@ struct obj {
                struct limit            limit;
                struct ct_timeout       ct_timeout;
                struct secmark          secmark;
+               struct ct_expect        ct_expect;
        };
 };
 
@@ -554,6 +563,7 @@ enum cmd_obj {
        CMD_OBJ_CT_TIMEOUT,
        CMD_OBJ_SECMARK,
        CMD_OBJ_SECMARKS,
+       CMD_OBJ_CT_EXPECT,
 };
 
 struct markup {
index f95f42e1067a728eb9767fb50f7996d78d1dea66..ff0271c757c280b35308db7e98c254216537c683 100644 (file)
@@ -3520,6 +3520,7 @@ static int cmd_evaluate_add(struct eval_ctx *ctx, struct cmd *cmd)
        case CMD_OBJ_LIMIT:
        case CMD_OBJ_CT_TIMEOUT:
        case CMD_OBJ_SECMARK:
+       case CMD_OBJ_CT_EXPECT:
                return obj_evaluate(ctx, cmd->object);
        default:
                BUG("invalid command object type %u\n", cmd->obj);
@@ -3542,6 +3543,7 @@ static int cmd_evaluate_delete(struct eval_ctx *ctx, struct cmd *cmd)
        case CMD_OBJ_CT_TIMEOUT:
        case CMD_OBJ_LIMIT:
        case CMD_OBJ_SECMARK:
+       case CMD_OBJ_CT_EXPECT:
                return 0;
        default:
                BUG("invalid command object type %u\n", cmd->obj);
@@ -3685,6 +3687,8 @@ static int cmd_evaluate_list(struct eval_ctx *ctx, struct cmd *cmd)
                return cmd_evaluate_list_obj(ctx, cmd, NFT_OBJECT_LIMIT);
        case CMD_OBJ_SECMARK:
                return cmd_evaluate_list_obj(ctx, cmd, NFT_OBJECT_SECMARK);
+       case CMD_OBJ_CT_EXPECT:
+               return cmd_evaluate_list_obj(ctx, cmd, NFT_OBJECT_CT_EXPECT);
        case CMD_OBJ_COUNTERS:
        case CMD_OBJ_QUOTAS:
        case CMD_OBJ_CT_HELPERS:
index 215de65a114a72094247b54d2083b684b4a3eb66..47543768dfab9d03784ea681ddf0f06fef4dc747 100644 (file)
@@ -325,6 +325,17 @@ static json_t *obj_print_json(const struct obj *obj)
                json_object_update(root, tmp);
                json_decref(tmp);
                break;
+       case NFT_OBJECT_CT_EXPECT:
+               tmp = json_pack("{s:o, s:I, s:I, s:s, s:I}",
+                               "protocol",
+                               proto_name_json(obj->ct_expect.l4proto),
+                               "dport", obj->ct_expect.dport,
+                               "timeout", obj->ct_expect.timeout,
+                               "size", obj->ct_expect.size,
+                               "l3proto", family2str(obj->ct_expect.l3proto));
+               json_object_update(root, tmp);
+               json_decref(tmp);
+               break;
        case NFT_OBJECT_LIMIT:
                rate = obj->limit.rate;
                burst = obj->limit.burst;
index a954e9d8f5cd38813268c6b5083405f5e8be36c4..eab8d5486437b6f520511caafd7480bd1a334c5b 100644 (file)
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -1003,6 +1003,19 @@ int mnl_nft_obj_add(struct netlink_ctx *ctx, const struct cmd *cmd,
                nftnl_obj_set(nlo, NFTNL_OBJ_CT_TIMEOUT_ARRAY,
                              obj->ct_timeout.timeout);
                break;
+       case NFT_OBJECT_CT_EXPECT:
+               if (obj->ct_expect.l3proto)
+                       nftnl_obj_set_u16(nlo, NFTNL_OBJ_CT_EXPECT_L3PROTO,
+                                         obj->ct_expect.l3proto);
+               nftnl_obj_set_u8(nlo, NFTNL_OBJ_CT_EXPECT_L4PROTO,
+                                obj->ct_expect.l4proto);
+               nftnl_obj_set_u16(nlo, NFTNL_OBJ_CT_EXPECT_DPORT,
+                                 obj->ct_expect.dport);
+               nftnl_obj_set_u32(nlo, NFTNL_OBJ_CT_EXPECT_TIMEOUT,
+                                 obj->ct_expect.timeout);
+               nftnl_obj_set_u8(nlo, NFTNL_OBJ_CT_EXPECT_SIZE,
+                                obj->ct_expect.size);
+               break;
        case NFT_OBJECT_SECMARK:
                nftnl_obj_set_str(nlo, NFTNL_OBJ_SECMARK_CTX,
                                  obj->secmark.ctx);
index 0374c39aca91d43d01b83a15897ff4dcaa2331cd..14b0df410726a856f3d62ebd6cdb799e90bd8931 100644 (file)
@@ -996,6 +996,18 @@ struct obj *netlink_delinearize_obj(struct netlink_ctx *ctx,
                obj->limit.flags =
                        nftnl_obj_get_u32(nlo, NFTNL_OBJ_LIMIT_FLAGS);
                break;
+       case NFT_OBJECT_CT_EXPECT:
+               obj->ct_expect.l3proto =
+                       nftnl_obj_get_u16(nlo, NFTNL_OBJ_CT_EXPECT_L3PROTO);
+               obj->ct_expect.l4proto =
+                       nftnl_obj_get_u8(nlo, NFTNL_OBJ_CT_EXPECT_L4PROTO);
+               obj->ct_expect.dport =
+                       nftnl_obj_get_u16(nlo, NFTNL_OBJ_CT_EXPECT_DPORT);
+               obj->ct_expect.timeout =
+                       nftnl_obj_get_u32(nlo, NFTNL_OBJ_CT_EXPECT_TIMEOUT);
+               obj->ct_expect.size =
+                       nftnl_obj_get_u8(nlo, NFTNL_OBJ_CT_EXPECT_SIZE);
+               break;
        }
        obj->type = type;
 
index 0a387f619998fb2e4dd5293c9bad911495261724..c7591bc24dab2ae0b1c641df3abb122d9df68fa3 100644 (file)
@@ -435,6 +435,7 @@ int nft_lex(void *, void *, void *);
 %token ZONE                    "zone"
 %token DIRECTION               "direction"
 %token EVENT                   "event"
+%token EXPECTATION             "expectation"
 %token EXPIRATION              "expiration"
 %token HELPER                  "helper"
 %token LABEL                   "label"
@@ -582,7 +583,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 ct_timeout_block limit_block secmark_block
+%type <obj>                    obj_block_alloc counter_block quota_block ct_helper_block ct_timeout_block ct_expect_block limit_block secmark_block
 %destructor { obj_free($$); }  obj_block_alloc
 
 %type <list>                   stmt_list
@@ -987,6 +988,10 @@ add_cmd                    :       TABLE           table_spec
                        {
                                $$ = cmd_alloc_obj_ct(CMD_ADD, NFT_OBJECT_CT_TIMEOUT, &$3, &@$, $4);
                        }
+                       |       CT      EXPECTATION     obj_spec        ct_obj_alloc    '{' ct_expect_block '}'
+                       {
+                               $$ = cmd_alloc_obj_ct(CMD_ADD, NFT_OBJECT_CT_EXPECT, &$3, &@$, $4);
+                       }
                        |       LIMIT           obj_spec        limit_obj
                        {
                                $$ = cmd_alloc(CMD_ADD, CMD_OBJ_LIMIT, &$2, &@$, $3);
@@ -1076,6 +1081,10 @@ create_cmd               :       TABLE           table_spec
                        {
                                $$ = cmd_alloc_obj_ct(CMD_CREATE, NFT_OBJECT_CT_TIMEOUT, &$3, &@$, $4);
                        }
+                       |       CT      EXPECTATION obj_spec    ct_obj_alloc    '{' ct_expect_block '}'
+                       {
+                               $$ = cmd_alloc_obj_ct(CMD_CREATE, NFT_OBJECT_CT_EXPECT, &$3, &@$, $4);
+                       }
                        |       LIMIT           obj_spec        limit_obj
                        {
                                $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_LIMIT, &$2, &@$, $3);
@@ -1296,6 +1305,10 @@ list_cmd         :       TABLE           table_spec
                        {
                                $$ = cmd_alloc(CMD_LIST, CMD_OBJ_CT_TIMEOUT, &$4, &@$, NULL);
                        }
+                       |       CT              EXPECTATION             TABLE           table_spec
+                       {
+                               $$ = cmd_alloc(CMD_LIST, CMD_OBJ_CT_EXPECT, &$4, &@$, NULL);
+                       }
                        ;
 
 reset_cmd              :       COUNTERS        ruleset_spec
@@ -1536,6 +1549,15 @@ table_block              :       /* empty */     { $$ = $<table>-1; }
                                list_add_tail(&$5->list, &$1->objs);
                                $$ = $1;
                        }
+                       |       table_block     CT      EXPECTATION obj_identifier obj_block_alloc '{'  ct_expect_block '}' stmt_separator
+                       {
+                               $5->location = @4;
+                               $5->type = NFT_OBJECT_CT_EXPECT;
+                               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
@@ -1860,6 +1882,15 @@ ct_timeout_block :       /*empty */      { $$ = $<obj>-1; }
                        }
                        ;
 
+ct_expect_block                :       /*empty */      { $$ = $<obj>-1; }
+                       |       ct_expect_block     common_block
+                       |       ct_expect_block     stmt_separator
+                       |       ct_expect_block     ct_expect_config
+                       {
+                               $$ = $1;
+                       }
+                       ;
+
 limit_block            :       /* empty */     { $$ = $<obj>-1; }
                        |       limit_block     common_block
                        |       limit_block     stmt_separator
@@ -3474,6 +3505,7 @@ secmark_obj               :       secmark_config
 
 ct_obj_type            :       HELPER          { $$ = NFT_OBJECT_CT_HELPER; }
                        |       TIMEOUT         { $$ = NFT_OBJECT_CT_TIMEOUT; }
+                       |       EXPECTATION     { $$ = NFT_OBJECT_CT_EXPECT; }
                        ;
 
 ct_l4protoname         :       TCP     { $$ = IPPROTO_TCP; }
@@ -3550,6 +3582,28 @@ ct_timeout_config        :       PROTOCOL        ct_l4protoname  stmt_separator
                        }
                        ;
 
+ct_expect_config       :       PROTOCOL        ct_l4protoname  stmt_separator
+                       {
+                               $<obj>0->ct_expect.l4proto = $2;
+                       }
+                       |       DPORT   NUM     stmt_separator
+                       {
+                               $<obj>0->ct_expect.dport = $2;
+                       }
+                       |       TIMEOUT time_spec       stmt_separator
+                       {
+                               $<obj>0->ct_expect.timeout = $2;
+                       }
+                       |       SIZE    NUM     stmt_separator
+                       {
+                               $<obj>0->ct_expect.size = $2;
+                       }
+                       |       L3PROTOCOL      family_spec_explicit    stmt_separator
+                       {
+                               $<obj>0->ct_expect.l3proto = $2;
+                       }
+                       ;
+
 ct_obj_alloc           :
                        {
                                $$ = obj_alloc(&@$);
@@ -4169,6 +4223,12 @@ ct_stmt                  :       CT      ct_key          SET     stmt_expr
                                $$->objref.expr = $4;
 
                        }
+                       |       CT      EXPECTATION     SET     stmt_expr
+                       {
+                               $$ = objref_stmt_alloc(&@$);
+                               $$->objref.type = NFT_OBJECT_CT_EXPECT;
+                               $$->objref.expr = $4;
+                       }
                        |       CT      ct_dir  ct_key_dir_optional SET stmt_expr
                        {
                                $$ = ct_stmt_alloc(&@$, $3, $2, $5);
index 9add6f88d09ed2bc8c51135f1aba003e44c6c0cd..79f5865c77378c62382fe6c1f800fd351b2fba43 100644 (file)
@@ -2210,6 +2210,21 @@ static struct stmt *json_parse_cttimeout_stmt(struct json_ctx *ctx,
        return stmt;
 }
 
+static struct stmt *json_parse_ctexpect_stmt(struct json_ctx *ctx,
+                                            const char *key, json_t *value)
+{
+       struct stmt *stmt = objref_stmt_alloc(int_loc);
+
+       stmt->objref.type = NFT_OBJECT_CT_EXPECT;
+       stmt->objref.expr = json_parse_stmt_expr(ctx, value);
+       if (!stmt->objref.expr) {
+               json_error(ctx, "Invalid ct expectation reference.");
+               stmt_free(stmt);
+               return NULL;
+       }
+       return stmt;
+}
+
 static struct stmt *json_parse_meter_stmt(struct json_ctx *ctx,
                                          const char *key, json_t *value)
 {
@@ -2355,6 +2370,7 @@ static struct stmt *json_parse_stmt(struct json_ctx *ctx, json_t *root)
                { "log", json_parse_log_stmt },
                { "ct helper", json_parse_cthelper_stmt },
                { "ct timeout", json_parse_cttimeout_stmt },
+               { "ct expectation", json_parse_ctexpect_stmt },
                { "meter", json_parse_meter_stmt },
                { "queue", json_parse_queue_stmt },
                { "ct count", json_parse_connlimit_stmt },
@@ -3014,6 +3030,33 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx,
                        return NULL;
                }
                break;
+       case NFT_OBJECT_CT_EXPECT:
+               cmd_obj = CMD_OBJ_CT_EXPECT;
+               obj->type = NFT_OBJECT_CT_EXPECT;
+               if (!json_unpack(root, "{s:s}", "l3proto", &tmp) &&
+                   parse_family(tmp, &l3proto)) {
+                       json_error(ctx, "Invalid ct expectation l3proto '%s'.", tmp);
+                       obj_free(obj);
+                       return NULL;
+               }
+               obj->ct_expect.l3proto = l3proto;
+               if (!json_unpack(root, "{s:s}", "protocol", &tmp)) {
+                       if (!strcmp(tmp, "tcp")) {
+                               obj->ct_expect.l4proto = IPPROTO_TCP;
+                       } else if (!strcmp(tmp, "udp")) {
+                               obj->ct_expect.l4proto = IPPROTO_UDP;
+                       } else {
+                               json_error(ctx, "Invalid ct expectation protocol '%s'.", tmp);
+                               obj_free(obj);
+                               return NULL;
+                       }
+               }
+               if (!json_unpack(root, "{s:o}", "dport", &tmp))
+                       obj->ct_expect.dport = atoi(tmp);
+               json_unpack(root, "{s:I}", "timeout", &obj->ct_expect.timeout);
+               if (!json_unpack(root, "{s:o}", "size", &tmp))
+                       obj->ct_expect.size = atoi(tmp);
+               break;
        case CMD_OBJ_LIMIT:
                obj->type = NFT_OBJECT_LIMIT;
                if (json_unpack_err(ctx, root, "{s:I, s:s}",
@@ -3069,6 +3112,7 @@ static struct cmd *json_parse_cmd_add(struct json_ctx *ctx,
                { "quota", CMD_OBJ_QUOTA, json_parse_cmd_add_object },
                { "ct helper", NFT_OBJECT_CT_HELPER, json_parse_cmd_add_object },
                { "ct timeout", NFT_OBJECT_CT_TIMEOUT, json_parse_cmd_add_object },
+               { "ct expectation", NFT_OBJECT_CT_EXPECT, json_parse_cmd_add_object },
                { "limit", CMD_OBJ_LIMIT, json_parse_cmd_add_object },
                { "secmark", CMD_OBJ_SECMARK, json_parse_cmd_add_object }
        };
@@ -3234,6 +3278,7 @@ static struct cmd *json_parse_cmd_list(struct json_ctx *ctx,
                { "ct helper", NFT_OBJECT_CT_HELPER, json_parse_cmd_add_object },
                { "ct helpers", CMD_OBJ_CT_HELPERS, json_parse_cmd_list_multiple },
                { "ct timeout", NFT_OBJECT_CT_TIMEOUT, json_parse_cmd_add_object },
+               { "ct expectation", NFT_OBJECT_CT_EXPECT, json_parse_cmd_add_object },
                { "limit", CMD_OBJ_LIMIT, json_parse_cmd_add_object },
                { "limits", CMD_OBJ_LIMIT, json_parse_cmd_list_multiple },
                { "ruleset", CMD_OBJ_RULESET, json_parse_cmd_list_multiple },
index 4e07871a1f65e3d246ecf25680a8b4136206a631..b957b4571249e28bacf19d8eba94b7d1a093a899 100644 (file)
@@ -1442,6 +1442,7 @@ void cmd_free(struct cmd *cmd)
                case CMD_OBJ_QUOTA:
                case CMD_OBJ_CT_HELPER:
                case CMD_OBJ_CT_TIMEOUT:
+               case CMD_OBJ_CT_EXPECT:
                case CMD_OBJ_LIMIT:
                case CMD_OBJ_SECMARK:
                        obj_free(cmd->object);
@@ -1532,6 +1533,7 @@ static int do_command_add(struct netlink_ctx *ctx, struct cmd *cmd, bool excl)
        case CMD_OBJ_QUOTA:
        case CMD_OBJ_CT_HELPER:
        case CMD_OBJ_CT_TIMEOUT:
+       case CMD_OBJ_CT_EXPECT:
        case CMD_OBJ_LIMIT:
        case CMD_OBJ_SECMARK:
                return mnl_nft_obj_add(ctx, cmd, flags);
@@ -1613,6 +1615,8 @@ static int do_command_delete(struct netlink_ctx *ctx, struct cmd *cmd)
                return mnl_nft_obj_del(ctx, cmd, NFT_OBJECT_CT_HELPER);
        case CMD_OBJ_CT_TIMEOUT:
                return mnl_nft_obj_del(ctx, cmd, NFT_OBJECT_CT_TIMEOUT);
+       case CMD_OBJ_CT_EXPECT:
+               return mnl_nft_obj_del(ctx, cmd, NFT_OBJECT_CT_EXPECT);
        case CMD_OBJ_LIMIT:
                return mnl_nft_obj_del(ctx, cmd, NFT_OBJECT_LIMIT);
        case CMD_OBJ_SECMARK:
@@ -1841,6 +1845,30 @@ static void obj_print_data(const struct obj *obj,
                print_proto_timeout_policy(obj->ct_timeout.l4proto,
                                           obj->ct_timeout.timeout, opts, octx);
                break;
+       case NFT_OBJECT_CT_EXPECT:
+               nft_print(octx, " %s {", obj->handle.obj.name);
+               if (nft_output_handle(octx))
+                       nft_print(octx, " # handle %" PRIu64, obj->handle.handle.id);
+               nft_print(octx, "%s", opts->nl);
+               nft_print(octx, "%s%sprotocol ", opts->tab, opts->tab);
+               print_proto_name_proto(obj->ct_expect.l4proto, octx);
+               nft_print(octx, "%s", opts->stmt_separator);
+               nft_print(octx, "%s%sdport %d%s",
+                         opts->tab, opts->tab,
+                         obj->ct_expect.dport,
+                         opts->stmt_separator);
+               nft_print(octx, "%s%stimeout ", opts->tab, opts->tab);
+               time_print(obj->ct_expect.timeout, octx);
+               nft_print(octx, "%s", opts->stmt_separator);
+               nft_print(octx, "%s%ssize %d%s",
+                         opts->tab, opts->tab,
+                         obj->ct_expect.size,
+                         opts->stmt_separator);
+               nft_print(octx, "%s%sl3proto %s%s",
+                         opts->tab, opts->tab,
+                         family2str(obj->ct_expect.l3proto),
+                         opts->stmt_separator);
+               break;
        case NFT_OBJECT_LIMIT: {
                bool inv = obj->limit.flags & NFT_LIMIT_F_INV;
                const char *data_unit;
@@ -1890,6 +1918,7 @@ static const char * const obj_type_name_array[] = {
        [NFT_OBJECT_LIMIT]      = "limit",
        [NFT_OBJECT_CT_TIMEOUT] = "ct timeout",
        [NFT_OBJECT_SECMARK]    = "secmark",
+       [NFT_OBJECT_CT_EXPECT]  = "ct expectation",
 };
 
 const char *obj_type_name(enum stmt_types type)
@@ -1906,6 +1935,7 @@ static uint32_t obj_type_cmd_array[NFT_OBJECT_MAX + 1] = {
        [NFT_OBJECT_LIMIT]      = CMD_OBJ_LIMIT,
        [NFT_OBJECT_CT_TIMEOUT] = CMD_OBJ_CT_TIMEOUT,
        [NFT_OBJECT_SECMARK]    = CMD_OBJ_SECMARK,
+       [NFT_OBJECT_CT_EXPECT]  = CMD_OBJ_CT_EXPECT,
 };
 
 uint32_t obj_type_to_cmd(uint32_t type)
@@ -2264,6 +2294,8 @@ static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
                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_CT_EXPECT:
+               return do_list_obj(ctx, cmd, NFT_OBJECT_CT_EXPECT);
        case CMD_OBJ_LIMIT:
        case CMD_OBJ_LIMITS:
                return do_list_obj(ctx, cmd, NFT_OBJECT_LIMIT);
@@ -2455,6 +2487,9 @@ struct cmd *cmd_alloc_obj_ct(enum cmd_ops op, int type, const struct handle *h,
        case NFT_OBJECT_CT_TIMEOUT:
                cmd_obj = CMD_OBJ_CT_TIMEOUT;
                break;
+       case NFT_OBJECT_CT_EXPECT:
+               cmd_obj = CMD_OBJ_CT_EXPECT;
+               break;
        default:
                BUG("missing type mapping");
        }
index 7f6c04316f91461469f78a40b071e9027a90c1cf..51bf64f464e5b7909e711982d27374c0d9ef1b69 100644 (file)
@@ -529,6 +529,7 @@ addrstring  ({macaddr}|{ip4addr}|{ip6addr})
 "reply"                        { return REPLY; }
 "direction"            { return DIRECTION; }
 "event"                        { return EVENT; }
+"expectation"          { return EXPECTATION; }
 "expiration"           { return EXPIRATION; }
 "helper"               { return HELPER; }
 "helpers"              { return HELPERS; }
index c5594233a45f33cbf9d753e48b165733981d629f..a82c1b39cd773a69e238b05897f132a37d931610 100644 (file)
@@ -208,6 +208,7 @@ static const char *objref_type[NFT_OBJECT_MAX + 1] = {
        [NFT_OBJECT_LIMIT]      = "limit",
        [NFT_OBJECT_CT_TIMEOUT] = "ct timeout",
        [NFT_OBJECT_SECMARK]    = "secmark",
+       [NFT_OBJECT_CT_EXPECT]  = "ct expectation",
 };
 
 const char *objref_type_name(uint32_t type)
@@ -227,6 +228,9 @@ static void objref_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
        case NFT_OBJECT_CT_TIMEOUT:
                nft_print(octx, "ct timeout set ");
                break;
+       case NFT_OBJECT_CT_EXPECT:
+               nft_print(octx, "ct expectation set ");
+               break;
        default:
                nft_print(octx, "%s name ",
                          objref_type_name(stmt->objref.type));
index fc2ee26607925ae03f4592891a4c14839355b249..35d01101bd53bbfe08bebd333900965011d58dee 100644 (file)
@@ -41,3 +41,12 @@ limit name tcp dport map {443 : "lim1", 80 : "lim2", 22 : "lim1"};ok
 %cttime5 type ct timeout {protocol tcp; policy = { estalbished:100 } ;};fail
 
 ct timeout set "cttime1";ok
+
+# ct expectation
+%ctexpect1 type ct expectation { protocol tcp; dport 1234; timeout 2m; size 12; };ok
+%ctexpect2 type ct expectation { protocol udp; };fail
+%ctexpect3 type ct expectation { protocol tcp; dport 4321; };fail
+%ctexpect4 type ct expectation { protocol tcp; dport 4321; timeout 2m; };fail
+%ctexpect5 type ct expectation { protocol udp; dport 9876; timeout 2m; size 12; l3proto ip; };ok
+
+ct expectation set "ctexpect1";ok
index a98d73c5f3157d63a1960877178635acdfd3a7fb..596ad188b5f4a0e551ae648b1b20bd5b92403dd5 100644 (file)
     }
 ]
 
+# ct expectation set "ctexpect1"
+[
+    {
+        "ct expect": "ctexpect1"
+    }
+]
+
index 719b6c3781b52510a113b4f1c71dfaf5be3f0899..ef3e86aa8ba726d7a8983a3d7ac4f6c52c503252 100644 (file)
@@ -63,3 +63,7 @@ ip test-ip4 output
 # ct timeout set "cttime1"
 ip test-ip4 output
   [ objref type 7 name cttime1 ]
+
+# ct expectation set "ctexpect1"
+ip test-ip4 output
+  [ objref type 9 name ctexpect1 ]
index fcbd28ca8fb9f9b6abfa50438e67875b9a43d0d0..7f424cf1e92d0c8d6158f56272ca9da5ee0f9c4a 100755 (executable)
@@ -1123,6 +1123,10 @@ def obj_process(obj_line, filename, lineno):
        obj_type = "ct timeout"
        tokens[3] = ""
 
+    if obj_type == "ct" and tokens[3] == "expectation":
+       obj_type = "ct expectation"
+       tokens[3] = ""
+
     if len(tokens) > 3:
         obj_spcf = " ".join(tokens[3:])
 
index da782a68b8e46b3ce683a4e6a64eb5ec63db7d14..f6915796eacf2e8886291860501480d11badc3e1 100755 (executable)
@@ -18,6 +18,14 @@ EXPECTED="table ip test {
                policy = { unreplied : 15, replied : 12 }
        }
 
+       ct expectation ctexpect {
+               protocol tcp
+               dport 5432
+               timeout 1h
+               size 12
+               l3proto ip
+       }
+
        chain input {
        }
 }"
@@ -29,6 +37,7 @@ $NFT add chain test input
 $NFT add quota test https-quota 25 mbytes
 $NFT add ct helper test cthelp { type \"sip\" protocol tcp \; }
 $NFT add ct timeout test cttime { protocol udp \; policy = {replied : 12, unreplied : 15 } \; }
+$NFT add ct expectation test ctexpect { protocol tcp \; dport 5432 \; timeout 1h \; size 12 \; }
 $NFT add table test-ip
 
 GET="$($NFT list table test)"
@@ -37,4 +46,3 @@ if [ "$EXPECTED" != "$GET" ] ; then
        [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
        exit 1
 fi
-
diff --git a/tests/shell/testcases/nft-f/0018ct_expectation_obj_0 b/tests/shell/testcases/nft-f/0018ct_expectation_obj_0
new file mode 100755 (executable)
index 0000000..eb9df3c
--- /dev/null
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+EXPECTED='table ip filter {
+       ct expectation ctexpect{
+               protocol tcp
+               dport 9876
+               timeout 1m
+               size 12
+               l3proto ip
+       }
+
+       chain c {
+               ct expectation set "ctexpect"
+       }
+}'
+
+set -e
+$NFT -f - <<< $EXPECTED