]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
exthdr: add boolean DCCP option matching
authorJeremy Sowden <jeremy@azazel.net>
Tue, 11 Apr 2023 20:45:34 +0000 (21:45 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Thu, 1 Jun 2023 19:43:16 +0000 (21:43 +0200)
Iptables supports the matching of DCCP packets based on the presence
or absence of DCCP options.  Extend exthdr expressions to add this
functionality to nftables.

Link: https://bugzilla.netfilter.org/show_bug.cgi?id=930
Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
16 files changed:
doc/libnftables-json.adoc
doc/payload-expression.txt
include/dccpopt.h [new file with mode: 0644]
include/exthdr.h
include/linux/netfilter/nf_tables.h
src/Makefile.am
src/dccpopt.c [new file with mode: 0644]
src/evaluate.c
src/exthdr.c
src/json.c
src/parser_bison.y
src/parser_json.c
src/scanner.l
tests/py/inet/dccp.t
tests/py/inet/dccp.t.json
tests/py/inet/dccp.t.payload

index f4aea36eb57113f17519961aeb2ae2f72e778412..f9288487e4b25ee3c1b9ab54394678af37de0788 100644 (file)
@@ -1226,6 +1226,17 @@ If the *field* property is not given, the expression is to be used as an SCTP
 chunk existence check in a *match* statement with a boolean on the right hand
 side.
 
+=== DCCP OPTION
+[verse]
+*{ "dccp option": {
+       "type":* 'NUMBER'*
+*}}*
+
+Create a reference to a DCCP option (*type*).
+
+The expression is to be used as a DCCP option existence check in a *match*
+statement with a boolean on the right hand side.
+
 === META
 [verse]
 ____
index f1de34476145942ecb59e97b55818d9c7522d073..06538832ec526b38f768cc7dc41018f749a73219 100644 (file)
@@ -753,6 +753,7 @@ The following syntaxes are valid only in a relational expression with boolean ty
 *exthdr* {*hbh* | *frag* | *rt* | *dst* | *mh*}
 *tcp option* {*eol* | *nop* | *maxseg* | *window* | *sack-perm* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*}
 *ip option* { lsrr | ra | rr | ssrr }
+*dccp option* 'dccp_option_type'
 
 .IPv6 extension headers
 [options="header"]
@@ -855,6 +856,11 @@ ip6 filter input frag more-fragments 1 counter
 filter input ip option lsrr exists counter
 ---------------------------------------
 
+.finding DCCP option
+------------------
+filter input dccp option 40 exists counter
+---------------------------------------
+
 CONNTRACK EXPRESSIONS
 ~~~~~~~~~~~~~~~~~~~~~
 Conntrack expressions refer to meta data of the connection tracking entry associated with a packet. +
diff --git a/include/dccpopt.h b/include/dccpopt.h
new file mode 100644 (file)
index 0000000..9686932
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef NFTABLES_DCCPOPT_H
+#define NFTABLES_DCCPOPT_H
+
+#include <nftables.h>
+#include <stdint.h>
+
+#define DCCPOPT_TYPE_MIN 0
+#define DCCPOPT_TYPE_MAX UINT8_MAX
+
+enum dccpopt_fields {
+       DCCPOPT_FIELD_INVALID,
+       DCCPOPT_FIELD_TYPE,
+};
+
+enum dccpopt_types {
+       DCCPOPT_PADDING                 =   0,
+       DCCPOPT_MANDATORY               =   1,
+       DCCPOPT_SLOW_RECEIVER           =   2,
+       DCCPOPT_RESERVED_SHORT          =   3,
+       DCCPOPT_CHANGE_L                =  32,
+       DCCPOPT_CONFIRM_L               =  33,
+       DCCPOPT_CHANGE_R                =  34,
+       DCCPOPT_CONFIRM_R               =  35,
+       DCCPOPT_INIT_COOKIE             =  36,
+       DCCPOPT_NDP_COUNT               =  37,
+       DCCPOPT_ACK_VECTOR_NONCE_0      =  38,
+       DCCPOPT_ACK_VECTOR_NONCE_1      =  39,
+       DCCPOPT_DATA_DROPPED            =  40,
+       DCCPOPT_TIMESTAMP               =  41,
+       DCCPOPT_TIMESTAMP_ECHO          =  42,
+       DCCPOPT_ELAPSED_TIME            =  43,
+       DCCPOPT_DATA_CHECKSUM           =  44,
+       DCCPOPT_RESERVED_LONG           =  45,
+       DCCPOPT_CCID_SPECIFIC           = 128,
+};
+
+const struct exthdr_desc *dccpopt_find_desc(uint8_t type);
+struct expr *dccpopt_expr_alloc(const struct location *loc, uint8_t type);
+void dccpopt_init_raw(struct expr *expr, uint8_t type, unsigned int offset,
+                     unsigned int len);
+
+#endif /* NFTABLES_DCCPOPT_H */
index 1bc756f936491bedad3b0ca9f249cca3c6363b62..084daba5358f7416790fd17589f7fe2c96deaef6 100644 (file)
@@ -4,6 +4,7 @@
 #include <proto.h>
 #include <tcpopt.h>
 #include <ipopt.h>
+#include <dccpopt.h>
 
 enum exthdr_desc_id {
        EXTHDR_DESC_UNKNOWN     = 0,
index 9c6f02c26054ade2efd43a67f1b10b4b6a276f5b..673e05073de8252e3aa4a7172c3e434d9aaf1801 100644 (file)
@@ -859,12 +859,14 @@ enum nft_exthdr_flags {
  * @NFT_EXTHDR_OP_TCP: match against tcp options
  * @NFT_EXTHDR_OP_IPV4: match against ipv4 options
  * @NFT_EXTHDR_OP_SCTP: match against sctp chunks
+ * @NFT_EXTHDR_OP_DCCP: match against dccp options
  */
 enum nft_exthdr_op {
        NFT_EXTHDR_OP_IPV6,
        NFT_EXTHDR_OP_TCPOPT,
        NFT_EXTHDR_OP_IPV4,
        NFT_EXTHDR_OP_SCTP,
+       NFT_EXTHDR_OP_DCCP,
        __NFT_EXTHDR_OP_MAX
 };
 #define NFT_EXTHDR_OP_MAX      (__NFT_EXTHDR_OP_MAX - 1)
index 264d981e20c7f7fbcdd6d06d021c0151b1e00f58..ace38bd75a97ec89c7cc2a7afd036d90ea13e9fd 100644 (file)
@@ -75,6 +75,7 @@ libnftables_la_SOURCES =                      \
                socket.c                        \
                print.c                         \
                sctp_chunk.c                    \
+               dccpopt.c                       \
                libnftables.c                   \
                libnftables.map
 
diff --git a/src/dccpopt.c b/src/dccpopt.c
new file mode 100644 (file)
index 0000000..3a2eb95
--- /dev/null
@@ -0,0 +1,276 @@
+#include <stddef.h>
+#include <stdint.h>
+
+#include <datatype.h>
+#include <dccpopt.h>
+#include <expression.h>
+#include <nftables.h>
+#include <utils.h>
+
+#define PHT(__token, __offset, __len)                                   \
+       PROTO_HDR_TEMPLATE(__token, &integer_type, BYTEORDER_BIG_ENDIAN, \
+                          __offset, __len)
+
+static const struct proto_hdr_template dccpopt_unknown_template =
+       PROTO_HDR_TEMPLATE("unknown", &invalid_type, BYTEORDER_INVALID, 0, 0);
+
+/*
+ *             Option                           DCCP-  Section
+ *     Type    Length     Meaning               Data?  Reference
+ *     ----    ------     -------               -----  ---------
+ *       0        1       Padding                 Y      5.8.1
+ *       1        1       Mandatory               N      5.8.2
+ *       2        1       Slow Receiver           Y      11.6
+ *     3-31       1       Reserved
+ *      32     variable   Change L                N      6.1
+ *      33     variable   Confirm L               N      6.2
+ *      34     variable   Change R                N      6.1
+ *      35     variable   Confirm R               N      6.2
+ *      36     variable   Init Cookie             N      8.1.4
+ *      37       3-8      NDP Count               Y      7.7
+ *      38     variable   Ack Vector [Nonce 0]    N      11.4
+ *      39     variable   Ack Vector [Nonce 1]    N      11.4
+ *      40     variable   Data Dropped            N      11.7
+ *      41        6       Timestamp               Y      13.1
+ *      42      6/8/10    Timestamp Echo          Y      13.3
+ *      43       4/6      Elapsed Time            N      13.2
+ *      44        6       Data Checksum           Y      9.3
+ *     45-127  variable   Reserved
+ *    128-255  variable   CCID-specific options   -      10.3
+ */
+
+static const struct exthdr_desc dccpopt_padding = {
+       .name           = "padding",
+       .type           = DCCPOPT_PADDING,
+       .templates      = {
+               [DCCPOPT_FIELD_TYPE]    = PHT("type",   0,      8),
+       },
+};
+
+static const struct exthdr_desc dccpopt_mandatory = {
+       .name           = "mandatory",
+       .type           = DCCPOPT_MANDATORY,
+       .templates      = {
+               [DCCPOPT_FIELD_TYPE]    = PHT("type",   0,      8),
+       },
+};
+
+static const struct exthdr_desc dccpopt_slow_receiver = {
+       .name           = "slow_receiver",
+       .type           = DCCPOPT_SLOW_RECEIVER,
+       .templates      = {
+               [DCCPOPT_FIELD_TYPE]    = PHT("type",   0,      8),
+       },
+};
+
+static const struct exthdr_desc dccpopt_reserved_short = {
+       .name           = "reserved_short",
+       .type           = DCCPOPT_RESERVED_SHORT,
+       .templates      = {
+               [DCCPOPT_FIELD_TYPE]    = PHT("type",   0,      8),
+       },
+};
+
+static const struct exthdr_desc dccpopt_change_l = {
+       .name           = "change_l",
+       .type           = DCCPOPT_CHANGE_L,
+       .templates      = {
+               [DCCPOPT_FIELD_TYPE]    = PHT("type",    0,    8)
+       },
+};
+
+static const struct exthdr_desc dccpopt_confirm_l = {
+       .name           = "confirm_l",
+       .type           = DCCPOPT_CONFIRM_L,
+       .templates      = {
+               [DCCPOPT_FIELD_TYPE]    = PHT("type",    0,    8),
+       },
+};
+
+static const struct exthdr_desc dccpopt_change_r = {
+       .name           = "change_r",
+       .type           = DCCPOPT_CHANGE_R,
+       .templates      = {
+               [DCCPOPT_FIELD_TYPE]    = PHT("type",    0,    8),
+       },
+};
+
+static const struct exthdr_desc dccpopt_confirm_r = {
+       .name           = "confirm_r",
+       .type           = DCCPOPT_CONFIRM_R,
+       .templates      = {
+               [DCCPOPT_FIELD_TYPE]    = PHT("type",    0,    8),
+       },
+};
+
+static const struct exthdr_desc dccpopt_init_cookie = {
+       .name           = "init_cookie",
+       .type           = DCCPOPT_INIT_COOKIE,
+       .templates      = {
+               [DCCPOPT_FIELD_TYPE]    = PHT("type",    0,    8),
+       },
+};
+
+static const struct exthdr_desc dccpopt_ndp_count = {
+       .name           = "ndp_count",
+       .type           = DCCPOPT_NDP_COUNT,
+       .templates      = {
+               [DCCPOPT_FIELD_TYPE]    = PHT("type",    0,    8),
+       },
+};
+
+static const struct exthdr_desc dccpopt_ack_vector_nonce_0 = {
+       .name           = "ack_vector_nonce_0",
+       .type           = DCCPOPT_ACK_VECTOR_NONCE_0,
+       .templates      = {
+               [DCCPOPT_FIELD_TYPE]    = PHT("type",    0,    8),
+       },
+};
+
+static const struct exthdr_desc dccpopt_ack_vector_nonce_1 = {
+       .name           = "ack_vector_nonce_1",
+       .type           = DCCPOPT_ACK_VECTOR_NONCE_1,
+       .templates      = {
+               [DCCPOPT_FIELD_TYPE]    = PHT("type",    0,    8),
+       },
+};
+
+static const struct exthdr_desc dccpopt_data_dropped = {
+       .name           = "data_dropped",
+       .type           = DCCPOPT_DATA_DROPPED,
+       .templates      = {
+               [DCCPOPT_FIELD_TYPE]    = PHT("type",    0,    8),
+       },
+};
+
+static const struct exthdr_desc dccpopt_timestamp = {
+       .name           = "timestamp",
+       .type           = DCCPOPT_TIMESTAMP,
+       .templates      = {
+               [DCCPOPT_FIELD_TYPE]    = PHT("type",    0,    8),
+       },
+};
+
+static const struct exthdr_desc dccpopt_timestamp_echo = {
+       .name           = "timestamp_echo",
+       .type           = DCCPOPT_TIMESTAMP_ECHO,
+       .templates      = {
+               [DCCPOPT_FIELD_TYPE]    = PHT("type",    0,    8),
+       },
+};
+
+static const struct exthdr_desc dccpopt_elapsed_time = {
+       .name           = "elapsed_time",
+       .type           = DCCPOPT_ELAPSED_TIME,
+       .templates      = {
+               [DCCPOPT_FIELD_TYPE]    = PHT("type",    0,    8),
+       },
+};
+
+static const struct exthdr_desc dccpopt_data_checksum = {
+       .name           = "data_checksum",
+       .type           = DCCPOPT_DATA_CHECKSUM,
+       .templates      = {
+               [DCCPOPT_FIELD_TYPE]    = PHT("type",    0,    8),
+       },
+};
+
+static const struct exthdr_desc dccpopt_reserved_long = {
+       .name           = "reserved_long",
+       .type           = DCCPOPT_RESERVED_LONG,
+       .templates      = {
+               [DCCPOPT_FIELD_TYPE]    = PHT("type",    0,    8),
+       },
+};
+
+static const struct exthdr_desc dccpopt_ccid_specific = {
+       .name           = "ccid_specific",
+       .type           = DCCPOPT_CCID_SPECIFIC,
+       .templates      = {
+               [DCCPOPT_FIELD_TYPE]    = PHT("type",    0,    8),
+       },
+};
+
+const struct exthdr_desc *dccpopt_protocols[1 + UINT8_MAX] = {
+       [DCCPOPT_PADDING]               = &dccpopt_padding,
+       [DCCPOPT_MANDATORY]             = &dccpopt_mandatory,
+       [DCCPOPT_SLOW_RECEIVER]         = &dccpopt_slow_receiver,
+       [DCCPOPT_RESERVED_SHORT]        = &dccpopt_reserved_short,
+       [DCCPOPT_CHANGE_L]              = &dccpopt_change_l,
+       [DCCPOPT_CONFIRM_L]             = &dccpopt_confirm_l,
+       [DCCPOPT_CHANGE_R]              = &dccpopt_change_r,
+       [DCCPOPT_CONFIRM_R]             = &dccpopt_confirm_r,
+       [DCCPOPT_INIT_COOKIE]           = &dccpopt_init_cookie,
+       [DCCPOPT_NDP_COUNT]             = &dccpopt_ndp_count,
+       [DCCPOPT_ACK_VECTOR_NONCE_0]    = &dccpopt_ack_vector_nonce_0,
+       [DCCPOPT_ACK_VECTOR_NONCE_1]    = &dccpopt_ack_vector_nonce_1,
+       [DCCPOPT_DATA_DROPPED]          = &dccpopt_data_dropped,
+       [DCCPOPT_TIMESTAMP]             = &dccpopt_timestamp,
+       [DCCPOPT_TIMESTAMP_ECHO]        = &dccpopt_timestamp_echo,
+       [DCCPOPT_ELAPSED_TIME]          = &dccpopt_elapsed_time,
+       [DCCPOPT_DATA_CHECKSUM]         = &dccpopt_data_checksum,
+       [DCCPOPT_RESERVED_LONG]         = &dccpopt_reserved_long,
+       [DCCPOPT_CCID_SPECIFIC]         = &dccpopt_ccid_specific,
+};
+
+const struct exthdr_desc *
+dccpopt_find_desc(uint8_t type)
+{
+       enum dccpopt_types proto_idx =
+                 3 <= type && type <=  31 ? DCCPOPT_RESERVED_SHORT :
+                45 <= type && type <= 127 ? DCCPOPT_RESERVED_LONG  :
+               128 <= type                ? DCCPOPT_CCID_SPECIFIC  : type;
+
+       return dccpopt_protocols[proto_idx];
+}
+
+struct expr *
+dccpopt_expr_alloc(const struct location *loc, uint8_t type)
+{
+       const struct proto_hdr_template *tmpl;
+       const struct exthdr_desc *desc;
+       struct expr *expr;
+
+       desc = dccpopt_find_desc(type);
+       tmpl = &desc->templates[DCCPOPT_FIELD_TYPE];
+
+       expr = expr_alloc(loc, EXPR_EXTHDR, tmpl->dtype,
+                         BYTEORDER_BIG_ENDIAN, BITS_PER_BYTE);
+       expr->exthdr.desc     = desc;
+       expr->exthdr.tmpl     = tmpl;
+       expr->exthdr.offset   = tmpl->offset;
+       expr->exthdr.raw_type = type;
+       expr->exthdr.flags    = NFT_EXTHDR_F_PRESENT;
+       expr->exthdr.op       = NFT_EXTHDR_OP_DCCP;
+
+       return expr;
+}
+
+void
+dccpopt_init_raw(struct expr *expr, uint8_t type, unsigned int offset,
+                unsigned int len)
+{
+       const struct proto_hdr_template *tmpl;
+       const struct exthdr_desc *desc;
+
+       assert(expr->etype == EXPR_EXTHDR);
+
+       desc = dccpopt_find_desc(type);
+       tmpl = &desc->templates[DCCPOPT_FIELD_TYPE];
+
+       expr->len = len;
+       datatype_set(expr, &boolean_type);
+
+       expr->exthdr.offset = offset;
+       expr->exthdr.desc   = desc;
+       expr->exthdr.flags  = NFT_EXTHDR_F_PRESENT;
+       expr->exthdr.op     = NFT_EXTHDR_OP_DCCP;
+
+       /* Make sure that it's the right template based on offset and
+        * len
+        */
+       if (tmpl->offset != offset || tmpl->len != len)
+               expr->exthdr.tmpl = &dccpopt_unknown_template;
+       else
+               expr->exthdr.tmpl = tmpl;
+}
index 50f1496c782164147076ff2ab493d0a766e7ad98..00bb8988bd4c92cb57e2ea44666ac5886c1cbd4f 100644 (file)
@@ -622,6 +622,7 @@ static int expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp)
        switch (expr->exthdr.op) {
        case NFT_EXTHDR_OP_TCPOPT:
        case NFT_EXTHDR_OP_SCTP:
+       case NFT_EXTHDR_OP_DCCP:
                return __expr_evaluate_exthdr(ctx, exprp);
        case NFT_EXTHDR_OP_IPV4:
                dependency = &proto_ip;
index 3e5f5cd8b73e13af3a8586b4c2e4148e22b324be..d0274bea6ca075e983e7d8fa076958c1a3b05613 100644 (file)
@@ -84,6 +84,9 @@ static void exthdr_expr_print(const struct expr *expr, struct output_ctx *octx)
                if (expr->exthdr.flags & NFT_EXTHDR_F_PRESENT)
                        return;
                nft_print(octx, " %s", expr->exthdr.tmpl->token);
+       } else if (expr->exthdr.op == NFT_EXTHDR_OP_DCCP) {
+               nft_print(octx, "dccp option %d", expr->exthdr.raw_type);
+               return;
        } else {
                if (expr->exthdr.flags & NFT_EXTHDR_F_PRESENT)
                        nft_print(octx, "exthdr %s", name);
@@ -177,6 +180,8 @@ static struct expr *exthdr_expr_parse_udata(const struct nftnl_udata *attr)
        case NFT_EXTHDR_OP_SCTP:
                return sctp_chunk_expr_alloc(&internal_location,
                                             desc_id, type);
+       case NFT_EXTHDR_OP_DCCP:
+               return dccpopt_expr_alloc(&internal_location, type);
        case __NFT_EXTHDR_OP_MAX:
                return NULL;
        }
@@ -206,6 +211,7 @@ static int exthdr_expr_build_udata(struct nftnl_udata_buf *udbuf,
        case NFT_EXTHDR_OP_TCPOPT:
        case NFT_EXTHDR_OP_IPV4:
        case NFT_EXTHDR_OP_SCTP:
+       case NFT_EXTHDR_OP_DCCP:
                nftnl_udata_put_u32(udbuf, NFTNL_UDATA_EXTHDR_OP, op);
                nftnl_udata_put_u32(udbuf, NFTNL_UDATA_EXTHDR_DESC, expr->exthdr.raw_type);
                break;
@@ -332,6 +338,8 @@ void exthdr_init_raw(struct expr *expr, uint8_t type,
                return ipopt_init_raw(expr, type, offset, len, flags, true);
        if (op == NFT_EXTHDR_OP_SCTP)
                return sctp_chunk_init_raw(expr, type, offset, len, flags);
+       if (op == NFT_EXTHDR_OP_DCCP)
+               return dccpopt_init_raw(expr, type, offset, len);
 
        expr->len = len;
        expr->exthdr.flags = flags;
index 1b42ebc06dd3698ee98aae4359359dbad27811b6..981d177b75d4f0a92b1cb42a14dfee9d71ad1b86 100644 (file)
@@ -751,6 +751,11 @@ json_t *exthdr_expr_json(const struct expr *expr, struct output_ctx *octx)
                return json_pack("{s:o}", "tcp option", root);
        }
 
+       if (expr->exthdr.op == NFT_EXTHDR_OP_DCCP) {
+               root = json_pack("{s:i}", "type", expr->exthdr.raw_type);
+               return json_pack("{s:o}", "dccp option", root);
+       }
+
        root = json_pack("{s:s}", "name", desc);
        if (!is_exists)
                json_object_set_new(root, "field", json_string(field));
index 90a2b9c3d681c1fb3bc205af910f63d4c62aa971..763c1b2dcd6121063aaed1b3830ff1f56682481b 100644 (file)
@@ -5968,6 +5968,15 @@ dccp_hdr_expr            :       DCCP    dccp_hdr_field  close_scope_dccp
                        {
                                $$ = payload_expr_alloc(&@$, &proto_dccp, $2);
                        }
+                       |       DCCP    OPTION          NUM     close_scope_dccp
+                       {
+                               if ($3 > DCCPOPT_TYPE_MAX) {
+                                       erec_queue(error(&@1, "value too large"),
+                                                  state->msgs);
+                                       YYERROR;
+                               }
+                               $$ = dccpopt_expr_alloc(&@$, $3);
+                       }
                        ;
 
 dccp_hdr_field         :       SPORT           { $$ = DCCPHDR_SPORT; }
index ad31b4e0365fc39eac1994455f2112670f79bc2f..f1cc39505382cbd2d5c4ec96c106d27f377c10b8 100644 (file)
@@ -756,6 +756,22 @@ static struct expr *json_parse_sctp_chunk_expr(struct json_ctx *ctx,
        return sctp_chunk_expr_alloc(int_loc, desc->type, fieldval);
 }
 
+static struct expr *json_parse_dccp_option_expr(struct json_ctx *ctx,
+                                               const char *type, json_t *root)
+{
+       const int opt_type;
+
+       if (json_unpack_err(ctx, root, "{s:i}", "type", &opt_type))
+               return NULL;
+
+       if (opt_type < DCCPOPT_TYPE_MIN || opt_type > DCCPOPT_TYPE_MAX) {
+               json_error(ctx, "Unknown dccp option type '%d'.", opt_type);
+               return NULL;
+       }
+
+       return dccpopt_expr_alloc(int_loc, opt_type);
+}
+
 static const struct exthdr_desc *exthdr_lookup_byname(const char *name)
 {
        const struct exthdr_desc *exthdr_tbl[] = {
@@ -1462,6 +1478,7 @@ static struct expr *json_parse_expr(struct json_ctx *ctx, json_t *root)
                { "tcp option", json_parse_tcp_option_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_CONCAT },
                { "ip option", json_parse_ip_option_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_CONCAT },
                { "sctp chunk", json_parse_sctp_chunk_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_CONCAT },
+               { "dccp option", json_parse_dccp_option_expr, CTX_F_PRIMARY },
                { "meta", json_parse_meta_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
                { "osf", json_parse_osf_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_MAP | CTX_F_CONCAT },
                { "ipsec", json_parse_xfrm_expr, CTX_F_PRIMARY | CTX_F_MAP | CTX_F_CONCAT },
index 15ca3d461d700dec60732ca0fd9393b238650aa4..c903b8c3e02d9b190eebc503cef302049d4f09e0 100644 (file)
@@ -632,6 +632,9 @@ addrstring  ({macaddr}|{ip4addr}|{ip6addr})
 <SCANSTATE_CT,SCANSTATE_EXPR_DCCP,SCANSTATE_SCTP,SCANSTATE_TCP,SCANSTATE_EXPR_TH,SCANSTATE_EXPR_UDP,SCANSTATE_EXPR_UDPLITE>{
        "dport"                 { return DPORT; }
 }
+<SCANSTATE_EXPR_DCCP>{
+       "option"                { return OPTION; }
+}
 
 "vxlan"                        { return VXLAN; }
 "vni"                  { return VNI; }
index 90142f53254ef49ab1b784864d7b87319791239b..99cddbe77c5b54fc9afa0ccf8e921d464849c221 100644 (file)
@@ -23,3 +23,8 @@ dccp type {request, response, data, ack, dataack, closereq, close, reset, sync,
 dccp type != {request, response, data, ack, dataack, closereq, close, reset, sync, syncack};ok
 dccp type request;ok
 dccp type != request;ok
+
+dccp option 0 exists;ok
+dccp option 43 missing;ok
+dccp option 255 exists;ok
+dccp option 256 exists;fail
index 806ef5eefca39bb8910228c4287fb72b41d378ba..9f47e97b8711e0a229dd2c5e5ee0c410a818d214 100644 (file)
     }
 ]
 
+# dccp option 0 exists
+[
+    {
+        "match": {
+            "left": {
+                "dccp option": {
+                    "type": 0
+                }
+            },
+            "op": "==",
+            "right": true
+        }
+    }
+]
+
+# dccp option 43 missing
+[
+    {
+        "match": {
+            "left": {
+                "dccp option": {
+                    "type": 43
+                }
+            },
+            "op": "==",
+            "right": false
+        }
+    }
+]
+
+# dccp option 255 exists
+[
+    {
+        "match": {
+            "left": {
+                "dccp option": {
+                    "type": 255
+                }
+            },
+            "op": "==",
+            "right": true
+        }
+    }
+]
index fbe9dc5b0016eb4466d0c4aa7a99fda28e877ae5..c0b87be18da7b9c48516b97c654d8791a01c67f2 100644 (file)
@@ -99,3 +99,17 @@ inet test-inet input
   [ bitwise reg 1 = ( reg 1 & 0x0000001e ) ^ 0x00000000 ]
   [ cmp neq reg 1 0x00000000 ]
 
+# dccp option 0 exists
+ip test-inet input
+  [ exthdr load 1b @ 0 + 0 present => reg 1 ]
+  [ cmp eq reg 1 0x00000001 ]
+
+# dccp option 43 missing
+ip test-inet input
+  [ exthdr load 1b @ 43 + 0 present => reg 1 ]
+  [ cmp eq reg 1 0x00000000 ]
+
+# dccp option 255 exists
+ip test-inet input
+  [ exthdr load 1b @ 255 + 0 present => reg 1 ]
+  [ cmp eq reg 1 0x00000001 ]