]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: introduce SYNPROXY matching
authorFernando Fernandez Mancera <ffmancera@riseup.net>
Sat, 22 Jun 2019 17:12:08 +0000 (19:12 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Wed, 17 Jul 2019 08:22:39 +0000 (10:22 +0200)
Add support for "synproxy" statement. For example (for TCP port 8888):

table ip x {
chain y {
type filter hook prerouting priority raw; policy accept;
tcp dport 8888 tcp flags syn notrack
}

chain z {
type filter hook input priority filter; policy accept;
tcp dport 8888 ct state invalid,untracked synproxy mss 1460 wscale 7 timestamp sack-perm
ct state invalid drop
}
}

Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
16 files changed:
doc/statements.txt
include/json.h
include/linux/netfilter/nf_synproxy.h [new file with mode: 0644]
include/linux/netfilter/nf_tables.h
include/statement.h
src/evaluate.c
src/json.c
src/netlink_delinearize.c
src/netlink_linearize.c
src/parser_bison.y
src/parser_json.c
src/scanner.l
src/statement.c
tests/py/inet/synproxy.t [new file with mode: 0644]
tests/py/inet/synproxy.t.json [new file with mode: 0644]
tests/py/inet/synproxy.t.payload [new file with mode: 0644]

index bc2f944960100dbf03a3fdc2f03443ef2ad4fc22..e17068a8a04be3ddfead38b5d9fc3a2c4452381e 100644 (file)
@@ -483,6 +483,93 @@ table inet x {
 }
 -------------------------------------
 
+SYNPROXY STATEMENT
+~~~~~~~~~~~~~~~~~~
+This statement will process TCP three-way-handshake parallel in netfilter
+context to protect either local or backend system. This statement requires
+connection tracking because sequence numbers need to be translated.
+
+[verse]
+*synproxy* [*mss* 'mss_value'] [*wscale* 'wscale_value'] ['SYNPROXY_FLAGS']
+
+.synproxy statement attributes
+[options="header"]
+|=================
+| Name | Description
+| mss | Maximum segment size announced to clients. This must match the backend.
+| wscale | Window scale announced to clients. This must match the backend.
+|=================
+
+.synproxy statement flags
+[options="header"]
+|=================
+| Flag | Description
+| sack-perm |
+Pass client selective acknowledgement option to backend (will be disabled if
+not present).
+| timestamp |
+Pass client timestamp option to backend (will be disabled if not present, also
+needed for selective acknowledgement and window scaling).
+|=================
+
+.Example ruleset for synproxy statement
+---------------------------------------
+Determine tcp options used by backend, from an external system
+
+              tcpdump -pni eth0 -c 1 'tcp[tcpflags] == (tcp-syn|tcp-ack)'
+                  port 80 &
+              telnet 192.0.2.42 80
+              18:57:24.693307 IP 192.0.2.42.80 > 192.0.2.43.48757:
+                  Flags [S.], seq 360414582, ack 788841994, win 14480,
+                  options [mss 1460,sackOK,
+                  TS val 1409056151 ecr 9690221,
+                  nop,wscale 9],
+                  length 0
+
+Switch tcp_loose mode off, so conntrack will mark out-of-flow packets as state INVALID.
+
+              echo 0 > /proc/sys/net/netfilter/nf_conntrack_tcp_loose
+
+Make SYN packets untracked.
+
+       table ip x {
+               chain y {
+                       type filter hook prerouting priority raw; policy accept;
+                       tcp flags syn notrack
+               }
+       }
+
+Catch UNTRACKED (SYN  packets) and INVALID (3WHS ACK packets) states and send
+them to SYNPROXY. This rule will respond to SYN packets with SYN+ACK
+syncookies, create ESTABLISHED for valid client response (3WHS ACK packets) and
+drop incorrect cookies. Flags combinations not expected during  3WHS will not
+match and continue (e.g. SYN+FIN, SYN+ACK). Finally, drop invalid packets, this
+will be out-of-flow packets that were not matched by SYNPROXY.
+
+    table ip foo {
+            chain z {
+                    type filter hook input priority filter; policy accept;
+                    ct state { invalid, untracked } synproxy mss 1460 wscale 9 timestamp sack-perm
+                    ct state invalid drop
+            }
+    }
+
+The outcome ruleset of the steps above should be similar to the one below.
+
+       table ip x {
+               chain y {
+                       type filter hook prerouting priority raw; policy accept;
+                       tcp flags syn notrack
+               }
+
+               chain z {
+                       type filter hook input priority filter; policy accept;
+                       ct state { invalid, untracked } synproxy mss 1460 wscale 9 timestamp sack-perm
+                       ct state invalid drop
+               }
+       }
+---------------------------------------
+
 FLOW STATEMENT
 ~~~~~~~~~~~~~~
 A flow statement allows us to select what flows you want to accelerate
index c724c299766be3455a72b060bbb98dbd95f7dc23..ce57c9f7f631f78f9b8b28f2f31e751e88910125 100644 (file)
@@ -83,6 +83,7 @@ json_t *queue_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
 json_t *verdict_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
 json_t *connlimit_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
 json_t *tproxy_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
+json_t *synproxy_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
 
 int do_command_list_json(struct netlink_ctx *ctx, struct cmd *cmd);
 
diff --git a/include/linux/netfilter/nf_synproxy.h b/include/linux/netfilter/nf_synproxy.h
new file mode 100644 (file)
index 0000000..0e7c391
--- /dev/null
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _NF_SYNPROXY_H
+#define _NF_SYNPROXY_H
+
+#include <linux/types.h>
+
+#define NF_SYNPROXY_OPT_MSS            0x01
+#define NF_SYNPROXY_OPT_WSCALE         0x02
+#define NF_SYNPROXY_OPT_SACK_PERM      0x04
+#define NF_SYNPROXY_OPT_TIMESTAMP      0x08
+#define NF_SYNPROXY_OPT_ECN            0x10
+#define NF_SYNPROXY_FLAGMASK           (NF_SYNPROXY_OPT_MSS | \
+                                        NF_SYNPROXY_OPT_WSCALE | \
+                                        NF_SYNPROXY_OPT_SACK_PERM | \
+                                        NF_SYNPROXY_OPT_TIMESTAMP)
+
+struct nf_synproxy_info {
+       __u8    options;
+       __u8    wscale;
+       __u16   mss;
+};
+
+#endif /* _NF_SYNPROXY_H */
index 709fbc8d70e10a7200ab0a9e3b670ddcf7b946c2..adc08935fb58d2240569808b55430c8afab598cc 100644 (file)
@@ -1543,6 +1543,23 @@ enum nft_osf_attributes {
 };
 #define NFTA_OSF_MAX (__NFTA_OSF_MAX - 1)
 
+/**
+ * enum nft_synproxy_attributes - nftables synproxy expression
+ * netlink attributes
+ *
+ * @NFTA_SYNPROXY_MSS: mss value sent to the backend (NLA_U16)
+ * @NFTA_SYNPROXY_WSCALE: wscale value sent to the backend (NLA_U8)
+ * @NFTA_SYNPROXY_FLAGS: flags (NLA_U32)
+ */
+enum nft_synproxy_attributes {
+       NFTA_SYNPROXY_UNSPEC,
+       NFTA_SYNPROXY_MSS,
+       NFTA_SYNPROXY_WSCALE,
+       NFTA_SYNPROXY_FLAGS,
+       __NFTA_SYNPROXY_MAX,
+};
+#define NFTA_SYNPROXY_MAX (__NFTA_SYNPROXY_MAX - 1)
+
 /**
  * enum nft_device_attributes - nf_tables device netlink attributes
  *
index 6fb5cf15f8bdd8b625ca685f34af9160038f023f..585908de7da213e7c6b1d7c999fcbb3c45df75de 100644 (file)
@@ -204,6 +204,14 @@ struct map_stmt {
 
 extern struct stmt *map_stmt_alloc(const struct location *loc);
 
+struct synproxy_stmt {
+       uint16_t        mss;
+       uint8_t         wscale;
+       uint32_t        flags;
+};
+
+extern struct stmt *synproxy_stmt_alloc(const struct location *loc);
+
 struct meter_stmt {
        struct expr             *set;
        struct expr             *key;
@@ -271,6 +279,7 @@ extern struct stmt *xt_stmt_alloc(const struct location *loc);
  * @STMT_FLOW_OFFLOAD: flow offload statement
  * @STMT_CONNLIMIT:    connection limit statement
  * @STMT_MAP:          map statement
+ * @STMT_SYNPROXY:     synproxy statement
  */
 enum stmt_types {
        STMT_INVALID,
@@ -298,6 +307,7 @@ enum stmt_types {
        STMT_FLOW_OFFLOAD,
        STMT_CONNLIMIT,
        STMT_MAP,
+       STMT_SYNPROXY,
 };
 
 /**
@@ -362,6 +372,7 @@ struct stmt {
                struct objref_stmt      objref;
                struct flow_stmt        flow;
                struct map_stmt         map;
+               struct synproxy_stmt    synproxy;
        };
 };
 
index 864d3daf1a5fe524986f27a3e79483bbd795e2ff..55cd9d00d274c59f94bebc4af237da29f9db3407 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/netfilter.h>
 #include <linux/netfilter_arp.h>
 #include <linux/netfilter/nf_tables.h>
+#include <linux/netfilter/nf_synproxy.h>
 #include <linux/netfilter_ipv4.h>
 #include <netinet/ip_icmp.h>
 #include <netinet/icmp6.h>
@@ -2746,6 +2747,18 @@ static int stmt_evaluate_tproxy(struct eval_ctx *ctx, struct stmt *stmt)
        return 0;
 }
 
+static int stmt_evaluate_synproxy(struct eval_ctx *ctx, struct stmt *stmt)
+{
+       if (stmt->synproxy.flags != 0 &&
+           !(stmt->synproxy.flags & (NF_SYNPROXY_OPT_MSS |
+                                     NF_SYNPROXY_OPT_WSCALE |
+                                     NF_SYNPROXY_OPT_TIMESTAMP |
+                                     NF_SYNPROXY_OPT_SACK_PERM)))
+               return stmt_error(ctx, stmt, "This flags are not supported for SYNPROXY");
+
+       return 0;
+}
+
 static int stmt_evaluate_dup(struct eval_ctx *ctx, struct stmt *stmt)
 {
        int err;
@@ -3090,6 +3103,8 @@ int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
                return stmt_evaluate_objref(ctx, stmt);
        case STMT_MAP:
                return stmt_evaluate_map(ctx, stmt);
+       case STMT_SYNPROXY:
+               return stmt_evaluate_synproxy(ctx, stmt);
        default:
                BUG("unknown statement type %s\n", stmt->ops->name);
        }
index 47543768dfab9d03784ea681ddf0f06fef4dc747..96ba557a3478b272b4d9d74f98a07bfe4d031aa7 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/netfilter/nf_log.h>
 #include <linux/netfilter/nf_nat.h>
 #include <linux/netfilter/nf_tables.h>
+#include <linux/netfilter/nf_synproxy.h>
 #include <linux/xfrm.h>
 #include <pwd.h>
 #include <grp.h>
@@ -1466,6 +1467,34 @@ json_t *tproxy_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
        return json_pack("{s:o}", "tproxy", root);
 }
 
+json_t *synproxy_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
+{
+       json_t *root = json_object(), *flags = json_array();
+
+       if (stmt->synproxy.flags & NF_SYNPROXY_OPT_MSS)
+               json_object_set_new(root, "mss",
+                                   json_integer(stmt->synproxy.mss));
+       if (stmt->synproxy.flags & NF_SYNPROXY_OPT_WSCALE)
+               json_object_set_new(root, "wscale",
+                                   json_integer(stmt->synproxy.wscale));
+       if (stmt->synproxy.flags & NF_SYNPROXY_OPT_TIMESTAMP)
+               json_array_append_new(flags, json_string("timestamp"));
+       if (stmt->synproxy.flags & NF_SYNPROXY_OPT_SACK_PERM)
+               json_array_append_new(flags, json_string("sack-perm"));
+
+       if (json_array_size(flags) > 0)
+               json_object_set_new(root, "flags", flags);
+       else
+               json_decref(flags);
+
+       if (!json_object_size(root)) {
+               json_decref(root);
+               root = json_null();
+       }
+
+       return json_pack("{s:o}", "synproxy", root);
+}
+
 static json_t *table_print_json_full(struct netlink_ctx *ctx,
                                     struct table *table)
 {
index 1dd3ffd107b2b67d3f9d527bef2e8deda2f9f5d7..fc2574b1dea9692828c1b8c247d5fa26e6357a85 100644 (file)
@@ -1010,6 +1010,22 @@ out_err:
        xfree(stmt);
 }
 
+static void netlink_parse_synproxy(struct netlink_parse_ctx *ctx,
+                                  const struct location *loc,
+                                  const struct nftnl_expr *nle)
+{
+       struct stmt *stmt;
+
+       stmt = synproxy_stmt_alloc(loc);
+       stmt->synproxy.mss = nftnl_expr_get_u16(nle, NFTNL_EXPR_SYNPROXY_MSS);
+       stmt->synproxy.wscale = nftnl_expr_get_u8(nle,
+                                                 NFTNL_EXPR_SYNPROXY_WSCALE);
+       stmt->synproxy.flags = nftnl_expr_get_u32(nle,
+                                                 NFTNL_EXPR_SYNPROXY_FLAGS);
+
+       ctx->stmt = stmt;
+}
+
 static void netlink_parse_tproxy(struct netlink_parse_ctx *ctx,
                              const struct location *loc,
                              const struct nftnl_expr *nle)
@@ -1476,6 +1492,7 @@ static const struct {
        { .name = "tcpopt",     .parse = netlink_parse_exthdr },
        { .name = "flow_offload", .parse = netlink_parse_flow_offload },
        { .name = "xfrm",       .parse = netlink_parse_xfrm },
+       { .name = "synproxy",   .parse = netlink_parse_synproxy },
 };
 
 static int netlink_parse_expr(const struct nftnl_expr *nle,
index 2c6aa64d3ac1cb7403b77c576e38bb793900865b..498326d0087a13d8c270e1e5b6cf17c0fc962b55 100644 (file)
@@ -1141,6 +1141,21 @@ static void netlink_gen_tproxy_stmt(struct netlink_linearize_ctx *ctx,
        nftnl_rule_add_expr(ctx->nlr, nle);
 }
 
+static void netlink_gen_synproxy_stmt(struct netlink_linearize_ctx *ctx,
+                                     const struct stmt *stmt)
+{
+       struct nftnl_expr *nle;
+
+       nle = alloc_nft_expr("synproxy");
+       nftnl_expr_set_u16(nle, NFTNL_EXPR_SYNPROXY_MSS, stmt->synproxy.mss);
+       nftnl_expr_set_u8(nle, NFTNL_EXPR_SYNPROXY_WSCALE,
+                         stmt->synproxy.wscale);
+       nftnl_expr_set_u32(nle, NFTNL_EXPR_SYNPROXY_FLAGS,
+                          stmt->synproxy.flags);
+
+       nftnl_rule_add_expr(ctx->nlr, nle);
+}
+
 static void netlink_gen_dup_stmt(struct netlink_linearize_ctx *ctx,
                                 const struct stmt *stmt)
 {
@@ -1382,6 +1397,8 @@ static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
                return netlink_gen_nat_stmt(ctx, stmt);
        case STMT_TPROXY:
                return netlink_gen_tproxy_stmt(ctx, stmt);
+       case STMT_SYNPROXY:
+               return netlink_gen_synproxy_stmt(ctx, stmt);
        case STMT_DUP:
                return netlink_gen_dup_stmt(ctx, stmt);
        case STMT_QUEUE:
index c7591bc24dab2ae0b1c641df3abb122d9df68fa3..53e669521efa0d02323930a9703cf8dbc943cbc5 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/netfilter/nf_nat.h>
 #include <linux/netfilter/nf_log.h>
 #include <linux/netfilter/nfnetlink_osf.h>
+#include <linux/netfilter/nf_synproxy.h>
 #include <linux/xfrm.h>
 #include <netinet/ip_icmp.h>
 #include <netinet/icmp6.h>
@@ -200,6 +201,11 @@ int nft_lex(void *, void *, void *);
 
 %token OSF                     "osf"
 
+%token SYNPROXY                        "synproxy"
+%token MSS                     "mss"
+%token WSCALE                  "wscale"
+%token SACKPERM                        "sack-perm"
+
 %token HOOK                    "hook"
 %token DEVICE                  "device"
 %token DEVICES                 "devices"
@@ -611,6 +617,9 @@ int nft_lex(void *, void *, void *);
 %type <val>                    nf_nat_flags nf_nat_flag offset_opt
 %type <stmt>                   tproxy_stmt
 %destructor { stmt_free($$); } tproxy_stmt
+%type <stmt>                   synproxy_stmt synproxy_stmt_alloc
+%destructor { stmt_free($$); } synproxy_stmt synproxy_stmt_alloc
+
 
 %type <stmt>                   queue_stmt queue_stmt_alloc
 %destructor { stmt_free($$); } queue_stmt queue_stmt_alloc
@@ -2289,6 +2298,7 @@ stmt                      :       verdict_stmt
                        |       fwd_stmt
                        |       set_stmt
                        |       map_stmt
+                       |       synproxy_stmt
                        ;
 
 verdict_stmt           :       verdict_expr
@@ -2719,6 +2729,43 @@ tproxy_stmt              :       TPROXY TO stmt_expr
                        }
                        ;
 
+synproxy_stmt          :       synproxy_stmt_alloc
+                       |       synproxy_stmt_alloc     synproxy_args
+                       ;
+
+synproxy_stmt_alloc    :       SYNPROXY
+                       {
+                               $$ = synproxy_stmt_alloc(&@$);
+                       }
+                       ;
+
+synproxy_args          :       synproxy_arg
+                       {
+                               $<stmt>$        = $<stmt>0;
+                       }
+                       |       synproxy_args   synproxy_arg
+                       ;
+
+synproxy_arg           :       MSS     NUM
+                       {
+                               $<stmt>0->synproxy.mss = $2;
+                               $<stmt>0->synproxy.flags |= NF_SYNPROXY_OPT_MSS;
+                       }
+                       |       WSCALE  NUM
+                       {
+                               $<stmt>0->synproxy.wscale = $2;
+                               $<stmt>0->synproxy.flags |= NF_SYNPROXY_OPT_WSCALE;
+                       }
+                       |       TIMESTAMP
+                       {
+                               $<stmt>0->synproxy.flags |= NF_SYNPROXY_OPT_TIMESTAMP;
+                       }
+                       |       SACKPERM
+                       {
+                               $<stmt>0->synproxy.flags |= NF_SYNPROXY_OPT_SACK_PERM;
+                       }
+                       ;
+
 primary_stmt_expr      :       symbol_expr             { $$ = $1; }
                        |       integer_expr            { $$ = $1; }
                        |       boolean_expr            { $$ = $1; }
index 79f5865c77378c62382fe6c1f800fd351b2fba43..42893c2f4a96d64eaca41e29aa0693092975f755 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/netfilter/nf_conntrack_tuple_common.h>
 #include <linux/netfilter/nf_log.h>
 #include <linux/netfilter/nf_nat.h>
+#include <linux/netfilter/nf_synproxy.h>
 #include <linux/netfilter/nf_tables.h>
 #include <jansson.h>
 
@@ -2180,6 +2181,98 @@ static struct stmt *json_parse_log_stmt(struct json_ctx *ctx,
        return stmt;
 }
 
+static int json_parse_synproxy_flag(struct json_ctx *ctx,
+                                   json_t *root, int *flags)
+{
+       const struct {
+               const char *flag;
+               int val;
+       } flag_tbl[] = {
+               { "timestamp", NF_SYNPROXY_OPT_TIMESTAMP },
+               { "sack-perm", NF_SYNPROXY_OPT_SACK_PERM },
+       };
+       const char *flag;
+       unsigned int i;
+
+       assert(flags);
+
+       if (!json_is_string(root)) {
+               json_error(ctx, "Invalid log flag type %s, expected string.",
+                          json_typename(root));
+               return 1;
+       }
+       flag = json_string_value(root);
+       for (i = 0; i < array_size(flag_tbl); i++) {
+               if (!strcmp(flag, flag_tbl[i].flag)) {
+                       *flags |= flag_tbl[i].val;
+                       return 0;
+               }
+       }
+       json_error(ctx, "Unknown log flag '%s'.", flag);
+       return 1;
+}
+
+static int json_parse_synproxy_flags(struct json_ctx *ctx, json_t *root)
+{
+       int flags = 0;
+       json_t *value;
+       size_t index;
+
+       if (json_is_string(root)) {
+               json_parse_synproxy_flag(ctx, root, &flags);
+               return flags;
+       } else if (!json_is_array(root)) {
+               json_error(ctx, "Invalid log flags type %s.",
+                          json_typename(root));
+               return -1;
+       }
+       json_array_foreach(root, index, value) {
+               if (json_parse_synproxy_flag(ctx, value, &flags))
+                       json_error(ctx, "Parsing log flag at index %zu failed.",
+                                  index);
+       }
+       return flags;
+}
+
+static struct stmt *json_parse_synproxy_stmt(struct json_ctx *ctx,
+                                            const char *key, json_t *value)
+{
+       struct stmt *stmt;
+       json_t *jflags;
+       int tmp, flags;
+
+       stmt = synproxy_stmt_alloc(int_loc);
+
+       if (!json_unpack(value, "{s:i}", "mss", &tmp)) {
+               if (tmp < 0) {
+                       json_error(ctx, "Invalid synproxy mss value '%d'", tmp);
+                       stmt_free(stmt);
+                       return NULL;
+               }
+               stmt->synproxy.mss = tmp;
+               stmt->synproxy.flags |= NF_SYNPROXY_OPT_MSS;
+       }
+       if (!json_unpack(value, "{s:i}", "wscale", &tmp)) {
+               if (tmp < 0) {
+                       json_error(ctx, "Invalid synproxy wscale value '%d'", tmp);
+                       stmt_free(stmt);
+                       return NULL;
+               }
+               stmt->synproxy.wscale = tmp;
+               stmt->synproxy.flags |= NF_SYNPROXY_OPT_WSCALE;
+       }
+       if (!json_unpack(value, "{s:o}", "flags", &jflags)) {
+               flags = json_parse_synproxy_flags(ctx, jflags);
+
+               if (flags < 0) {
+                       stmt_free(stmt);
+                       return NULL;
+               }
+               stmt->synproxy.flags |= flags;
+       }
+       return stmt;
+}
+
 static struct stmt *json_parse_cthelper_stmt(struct json_ctx *ctx,
                                             const char *key, json_t *value)
 {
@@ -2375,6 +2468,7 @@ static struct stmt *json_parse_stmt(struct json_ctx *ctx, json_t *root)
                { "queue", json_parse_queue_stmt },
                { "ct count", json_parse_connlimit_stmt },
                { "tproxy", json_parse_tproxy_stmt },
+               { "synproxy", json_parse_synproxy_stmt },
        };
        const char *type;
        unsigned int i;
index 51bf64f464e5b7909e711982d27374c0d9ef1b69..4ed5f9241381234277295a5671d66c0895e75104 100644 (file)
@@ -553,6 +553,11 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
 
 "osf"                  { return OSF; }
 
+"synproxy"             { return SYNPROXY; }
+"mss"                  { return MSS; }
+"wscale"               { return WSCALE; }
+"sack-perm"            { return SACKPERM; }
+
 "notrack"              { return NOTRACK; }
 
 "options"              { return OPTIONS; }
index a82c1b39cd773a69e238b05897f132a37d931610..a9e72de3edfdcfa662468a55acd9748548d3a82a 100644 (file)
@@ -29,6 +29,7 @@
 #include <netinet/in.h>
 #include <linux/netfilter/nf_nat.h>
 #include <linux/netfilter/nf_log.h>
+#include <linux/netfilter/nf_synproxy.h>
 
 struct stmt *stmt_alloc(const struct location *loc,
                        const struct stmt_ops *ops)
@@ -883,3 +884,53 @@ struct stmt *xt_stmt_alloc(const struct location *loc)
 {
        return stmt_alloc(loc, &xt_stmt_ops);
 }
+
+static const char *synproxy_sack_to_str(const uint32_t flags)
+{
+       if (flags & NF_SYNPROXY_OPT_SACK_PERM)
+               return " sack-perm";
+
+       return "";
+}
+
+static const char *synproxy_timestamp_to_str(const uint32_t flags)
+{
+       if (flags & NF_SYNPROXY_OPT_TIMESTAMP)
+               return " timestamp";
+
+       return "";
+}
+
+static void synproxy_stmt_print(const struct stmt *stmt,
+                               struct output_ctx *octx)
+{
+       uint32_t flags = stmt->synproxy.flags;
+       const char *ts_str = synproxy_timestamp_to_str(flags);
+       const char *sack_str = synproxy_sack_to_str(flags);
+
+       if (flags & (NF_SYNPROXY_OPT_MSS | NF_SYNPROXY_OPT_WSCALE))
+               nft_print(octx, "synproxy mss %u wscale %u%s%s",
+                         stmt->synproxy.mss, stmt->synproxy.wscale,
+                         ts_str, sack_str);
+       else if (flags & NF_SYNPROXY_OPT_MSS)
+               nft_print(octx, "synproxy mss %u%s%s", stmt->synproxy.mss,
+                         ts_str, sack_str);
+       else if (flags & NF_SYNPROXY_OPT_WSCALE)
+               nft_print(octx, "synproxy wscale %u%s%s", stmt->synproxy.wscale,
+                         ts_str, sack_str);
+       else
+               nft_print(octx, "synproxy%s%s", ts_str, sack_str);
+
+}
+
+static const struct stmt_ops synproxy_stmt_ops = {
+       .type           = STMT_SYNPROXY,
+       .name           = "synproxy",
+       .print          = synproxy_stmt_print,
+       .json           = synproxy_stmt_json,
+};
+
+struct stmt *synproxy_stmt_alloc(const struct location *loc)
+{
+       return stmt_alloc(loc, &synproxy_stmt_ops);
+}
diff --git a/tests/py/inet/synproxy.t b/tests/py/inet/synproxy.t
new file mode 100644 (file)
index 0000000..55a05e1
--- /dev/null
@@ -0,0 +1,13 @@
+:synproxychain;type filter hook input priority 0
+
+*ip;synproxyip;synproxychain
+*ip6;synproxyip6;synproxychain
+*inet;synproxyinet;synproxychain
+
+synproxy;ok
+synproxy mss 1460 wscale 7;ok
+synproxy mss 1460 wscale 5 timestamp sack-perm;ok
+synproxy timestamp sack-perm;ok
+synproxy timestamp;ok
+synproxy sack-perm;ok
+
diff --git a/tests/py/inet/synproxy.t.json b/tests/py/inet/synproxy.t.json
new file mode 100644 (file)
index 0000000..313fa9f
--- /dev/null
@@ -0,0 +1,71 @@
+# synproxy
+[
+    {
+        "synproxy":null
+    }
+]
+
+# synproxy mss 1460
+[
+    {
+        "synproxy": {
+            "mss": 1460
+        }
+    }
+]
+
+# synproxy wscale 7
+[
+    {
+        "synproxy": {
+            "wscale": 7
+        }
+    }
+]
+
+# synproxy mss 1460 wscale 7
+[
+    {
+        "synproxy": {
+            "mss": 1460,
+            "wscale": 7
+        }
+    }
+]
+
+# synproxy timestamp
+[
+    {
+        "synproxy": {
+            "flags": [
+                "timestamp"
+            ]
+        }
+    }
+]
+
+# synproxy timestamp sack-perm
+[
+    {
+        "synproxy": {
+            "flags": [
+                "timestamp",
+                "sack-perm"
+            ]
+        }
+    }
+]
+
+# synproxy mss 1460 wscale 7 timestamp sack-perm
+[
+    {
+        "synproxy": {
+            "mss": 1460,
+            "wscale": 7,
+            "flags": [
+                "timestamp",
+                "sack-perm"
+            ]
+        }
+    }
+]
diff --git a/tests/py/inet/synproxy.t.payload b/tests/py/inet/synproxy.t.payload
new file mode 100644 (file)
index 0000000..2e6feaa
--- /dev/null
@@ -0,0 +1,72 @@
+# synproxy
+ip synproxyip synproxychain
+  [ synproxy mss 0 wscale 0 ]
+
+# synproxy
+ip6 synproxyip6 synproxychain
+  [ synproxy mss 0 wscale 0 ]
+
+# synproxy
+inet synproxyinet synproxychain
+  [ synproxy mss 0 wscale 0 ]
+
+# synproxy mss 1460 wscale 7
+ip synproxyip synproxychain
+  [ synproxy mss 1460 wscale 7 ]
+
+# synproxy mss 1460 wscale 7
+ip6 synproxyip6 synproxychain
+  [ synproxy mss 1460 wscale 7 ]
+
+# synproxy mss 1460 wscale 7
+inet synproxyinet synproxychain
+  [ synproxy mss 1460 wscale 7 ]
+
+# synproxy mss 1460 wscale 5 timestamp sack-perm
+ip synproxyip synproxychain
+  [ synproxy mss 1460 wscale 5 ]
+
+# synproxy mss 1460 wscale 5 timestamp sack-perm
+ip6 synproxyip6 synproxychain
+  [ synproxy mss 1460 wscale 5 ]
+
+# synproxy mss 1460 wscale 5 timestamp sack-perm
+inet synproxyinet synproxychain
+  [ synproxy mss 1460 wscale 5 ]
+
+# synproxy timestamp sack-perm
+ip synproxyip synproxychain
+  [ synproxy mss 0 wscale 0 ]
+
+# synproxy timestamp sack-perm
+ip6 synproxyip6 synproxychain
+  [ synproxy mss 0 wscale 0 ]
+
+# synproxy timestamp sack-perm
+inet synproxyinet synproxychain
+  [ synproxy mss 0 wscale 0 ]
+
+# synproxy timestamp
+ip synproxyip synproxychain
+  [ synproxy mss 0 wscale 0 ]
+
+# synproxy timestamp
+ip6 synproxyip6 synproxychain
+  [ synproxy mss 0 wscale 0 ]
+
+# synproxy timestamp
+inet synproxyinet synproxychain
+  [ synproxy mss 0 wscale 0 ]
+
+# synproxy sack-perm
+ip synproxyip synproxychain
+  [ synproxy mss 0 wscale 0 ]
+
+# synproxy sack-perm
+ip6 synproxyip6 synproxychain
+  [ synproxy mss 0 wscale 0 ]
+
+# synproxy sack-perm
+inet synproxyinet synproxychain
+  [ synproxy mss 0 wscale 0 ]
+