root/net/netfilter/nft_synproxy.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nft_synproxy_tcp_options
  2. nft_synproxy_eval_v4
  3. nft_synproxy_eval_v6
  4. nft_synproxy_do_eval
  5. nft_synproxy_do_init
  6. nft_synproxy_do_destroy
  7. nft_synproxy_do_dump
  8. nft_synproxy_eval
  9. nft_synproxy_validate
  10. nft_synproxy_init
  11. nft_synproxy_destroy
  12. nft_synproxy_dump
  13. nft_synproxy_obj_init
  14. nft_synproxy_obj_destroy
  15. nft_synproxy_obj_dump
  16. nft_synproxy_obj_eval
  17. nft_synproxy_obj_update
  18. nft_synproxy_module_init
  19. nft_synproxy_module_exit

   1 // SPDX-License-Identifier: GPL-2.0
   2 #include <linux/types.h>
   3 #include <net/ip.h>
   4 #include <net/tcp.h>
   5 #include <net/netlink.h>
   6 #include <net/netfilter/nf_tables.h>
   7 #include <net/netfilter/nf_conntrack.h>
   8 #include <net/netfilter/nf_conntrack_synproxy.h>
   9 #include <net/netfilter/nf_synproxy.h>
  10 #include <linux/netfilter/nf_tables.h>
  11 #include <linux/netfilter/nf_synproxy.h>
  12 
  13 struct nft_synproxy {
  14         struct nf_synproxy_info info;
  15 };
  16 
  17 static const struct nla_policy nft_synproxy_policy[NFTA_SYNPROXY_MAX + 1] = {
  18         [NFTA_SYNPROXY_MSS]             = { .type = NLA_U16 },
  19         [NFTA_SYNPROXY_WSCALE]          = { .type = NLA_U8 },
  20         [NFTA_SYNPROXY_FLAGS]           = { .type = NLA_U32 },
  21 };
  22 
  23 static void nft_synproxy_tcp_options(struct synproxy_options *opts,
  24                                      const struct tcphdr *tcp,
  25                                      struct synproxy_net *snet,
  26                                      struct nf_synproxy_info *info,
  27                                      const struct nft_synproxy *priv)
  28 {
  29         this_cpu_inc(snet->stats->syn_received);
  30         if (tcp->ece && tcp->cwr)
  31                 opts->options |= NF_SYNPROXY_OPT_ECN;
  32 
  33         opts->options &= priv->info.options;
  34         opts->mss_encode = opts->mss_option;
  35         opts->mss_option = info->mss;
  36         if (opts->options & NF_SYNPROXY_OPT_TIMESTAMP)
  37                 synproxy_init_timestamp_cookie(info, opts);
  38         else
  39                 opts->options &= ~(NF_SYNPROXY_OPT_WSCALE |
  40                                    NF_SYNPROXY_OPT_SACK_PERM |
  41                                    NF_SYNPROXY_OPT_ECN);
  42 }
  43 
  44 static void nft_synproxy_eval_v4(const struct nft_synproxy *priv,
  45                                  struct nft_regs *regs,
  46                                  const struct nft_pktinfo *pkt,
  47                                  const struct tcphdr *tcp,
  48                                  struct tcphdr *_tcph,
  49                                  struct synproxy_options *opts)
  50 {
  51         struct nf_synproxy_info info = priv->info;
  52         struct net *net = nft_net(pkt);
  53         struct synproxy_net *snet = synproxy_pernet(net);
  54         struct sk_buff *skb = pkt->skb;
  55 
  56         if (tcp->syn) {
  57                 /* Initial SYN from client */
  58                 nft_synproxy_tcp_options(opts, tcp, snet, &info, priv);
  59                 synproxy_send_client_synack(net, skb, tcp, opts);
  60                 consume_skb(skb);
  61                 regs->verdict.code = NF_STOLEN;
  62         } else if (tcp->ack) {
  63                 /* ACK from client */
  64                 if (synproxy_recv_client_ack(net, skb, tcp, opts,
  65                                              ntohl(tcp->seq))) {
  66                         consume_skb(skb);
  67                         regs->verdict.code = NF_STOLEN;
  68                 } else {
  69                         regs->verdict.code = NF_DROP;
  70                 }
  71         }
  72 }
  73 
  74 #if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
  75 static void nft_synproxy_eval_v6(const struct nft_synproxy *priv,
  76                                  struct nft_regs *regs,
  77                                  const struct nft_pktinfo *pkt,
  78                                  const struct tcphdr *tcp,
  79                                  struct tcphdr *_tcph,
  80                                  struct synproxy_options *opts)
  81 {
  82         struct nf_synproxy_info info = priv->info;
  83         struct net *net = nft_net(pkt);
  84         struct synproxy_net *snet = synproxy_pernet(net);
  85         struct sk_buff *skb = pkt->skb;
  86 
  87         if (tcp->syn) {
  88                 /* Initial SYN from client */
  89                 nft_synproxy_tcp_options(opts, tcp, snet, &info, priv);
  90                 synproxy_send_client_synack_ipv6(net, skb, tcp, opts);
  91                 consume_skb(skb);
  92                 regs->verdict.code = NF_STOLEN;
  93         } else if (tcp->ack) {
  94                 /* ACK from client */
  95                 if (synproxy_recv_client_ack_ipv6(net, skb, tcp, opts,
  96                                                   ntohl(tcp->seq))) {
  97                         consume_skb(skb);
  98                         regs->verdict.code = NF_STOLEN;
  99                 } else {
 100                         regs->verdict.code = NF_DROP;
 101                 }
 102         }
 103 }
 104 #endif /* CONFIG_NF_TABLES_IPV6*/
 105 
 106 static void nft_synproxy_do_eval(const struct nft_synproxy *priv,
 107                                  struct nft_regs *regs,
 108                                  const struct nft_pktinfo *pkt)
 109 {
 110         struct synproxy_options opts = {};
 111         struct sk_buff *skb = pkt->skb;
 112         int thoff = pkt->xt.thoff;
 113         const struct tcphdr *tcp;
 114         struct tcphdr _tcph;
 115 
 116         if (pkt->tprot != IPPROTO_TCP) {
 117                 regs->verdict.code = NFT_BREAK;
 118                 return;
 119         }
 120 
 121         if (nf_ip_checksum(skb, nft_hook(pkt), thoff, IPPROTO_TCP)) {
 122                 regs->verdict.code = NF_DROP;
 123                 return;
 124         }
 125 
 126         tcp = skb_header_pointer(skb, pkt->xt.thoff,
 127                                  sizeof(struct tcphdr),
 128                                  &_tcph);
 129         if (!tcp) {
 130                 regs->verdict.code = NF_DROP;
 131                 return;
 132         }
 133 
 134         if (!synproxy_parse_options(skb, thoff, tcp, &opts)) {
 135                 regs->verdict.code = NF_DROP;
 136                 return;
 137         }
 138 
 139         switch (skb->protocol) {
 140         case htons(ETH_P_IP):
 141                 nft_synproxy_eval_v4(priv, regs, pkt, tcp, &_tcph, &opts);
 142                 return;
 143 #if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
 144         case htons(ETH_P_IPV6):
 145                 nft_synproxy_eval_v6(priv, regs, pkt, tcp, &_tcph, &opts);
 146                 return;
 147 #endif
 148         }
 149         regs->verdict.code = NFT_BREAK;
 150 }
 151 
 152 static int nft_synproxy_do_init(const struct nft_ctx *ctx,
 153                                 const struct nlattr * const tb[],
 154                                 struct nft_synproxy *priv)
 155 {
 156         struct synproxy_net *snet = synproxy_pernet(ctx->net);
 157         u32 flags;
 158         int err;
 159 
 160         if (tb[NFTA_SYNPROXY_MSS])
 161                 priv->info.mss = ntohs(nla_get_be16(tb[NFTA_SYNPROXY_MSS]));
 162         if (tb[NFTA_SYNPROXY_WSCALE])
 163                 priv->info.wscale = nla_get_u8(tb[NFTA_SYNPROXY_WSCALE]);
 164         if (tb[NFTA_SYNPROXY_FLAGS]) {
 165                 flags = ntohl(nla_get_be32(tb[NFTA_SYNPROXY_FLAGS]));
 166                 if (flags & ~NF_SYNPROXY_OPT_MASK)
 167                         return -EOPNOTSUPP;
 168                 priv->info.options = flags;
 169         }
 170 
 171         err = nf_ct_netns_get(ctx->net, ctx->family);
 172         if (err)
 173                 return err;
 174 
 175         switch (ctx->family) {
 176         case NFPROTO_IPV4:
 177                 err = nf_synproxy_ipv4_init(snet, ctx->net);
 178                 if (err)
 179                         goto nf_ct_failure;
 180                 break;
 181 #if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
 182         case NFPROTO_IPV6:
 183                 err = nf_synproxy_ipv6_init(snet, ctx->net);
 184                 if (err)
 185                         goto nf_ct_failure;
 186                 break;
 187 #endif
 188         case NFPROTO_INET:
 189         case NFPROTO_BRIDGE:
 190                 err = nf_synproxy_ipv4_init(snet, ctx->net);
 191                 if (err)
 192                         goto nf_ct_failure;
 193                 err = nf_synproxy_ipv6_init(snet, ctx->net);
 194                 if (err)
 195                         goto nf_ct_failure;
 196                 break;
 197         }
 198 
 199         return 0;
 200 
 201 nf_ct_failure:
 202         nf_ct_netns_put(ctx->net, ctx->family);
 203         return err;
 204 }
 205 
 206 static void nft_synproxy_do_destroy(const struct nft_ctx *ctx)
 207 {
 208         struct synproxy_net *snet = synproxy_pernet(ctx->net);
 209 
 210         switch (ctx->family) {
 211         case NFPROTO_IPV4:
 212                 nf_synproxy_ipv4_fini(snet, ctx->net);
 213                 break;
 214 #if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
 215         case NFPROTO_IPV6:
 216                 nf_synproxy_ipv6_fini(snet, ctx->net);
 217                 break;
 218 #endif
 219         case NFPROTO_INET:
 220         case NFPROTO_BRIDGE:
 221                 nf_synproxy_ipv4_fini(snet, ctx->net);
 222                 nf_synproxy_ipv6_fini(snet, ctx->net);
 223                 break;
 224         }
 225         nf_ct_netns_put(ctx->net, ctx->family);
 226 }
 227 
 228 static int nft_synproxy_do_dump(struct sk_buff *skb, struct nft_synproxy *priv)
 229 {
 230         if (nla_put_be16(skb, NFTA_SYNPROXY_MSS, htons(priv->info.mss)) ||
 231             nla_put_u8(skb, NFTA_SYNPROXY_WSCALE, priv->info.wscale) ||
 232             nla_put_be32(skb, NFTA_SYNPROXY_FLAGS, htonl(priv->info.options)))
 233                 goto nla_put_failure;
 234 
 235         return 0;
 236 
 237 nla_put_failure:
 238         return -1;
 239 }
 240 
 241 static void nft_synproxy_eval(const struct nft_expr *expr,
 242                               struct nft_regs *regs,
 243                               const struct nft_pktinfo *pkt)
 244 {
 245         const struct nft_synproxy *priv = nft_expr_priv(expr);
 246 
 247         nft_synproxy_do_eval(priv, regs, pkt);
 248 }
 249 
 250 static int nft_synproxy_validate(const struct nft_ctx *ctx,
 251                                  const struct nft_expr *expr,
 252                                  const struct nft_data **data)
 253 {
 254         return nft_chain_validate_hooks(ctx->chain, (1 << NF_INET_LOCAL_IN) |
 255                                                     (1 << NF_INET_FORWARD));
 256 }
 257 
 258 static int nft_synproxy_init(const struct nft_ctx *ctx,
 259                              const struct nft_expr *expr,
 260                              const struct nlattr * const tb[])
 261 {
 262         struct nft_synproxy *priv = nft_expr_priv(expr);
 263 
 264         return nft_synproxy_do_init(ctx, tb, priv);
 265 }
 266 
 267 static void nft_synproxy_destroy(const struct nft_ctx *ctx,
 268                                  const struct nft_expr *expr)
 269 {
 270         nft_synproxy_do_destroy(ctx);
 271 }
 272 
 273 static int nft_synproxy_dump(struct sk_buff *skb, const struct nft_expr *expr)
 274 {
 275         struct nft_synproxy *priv = nft_expr_priv(expr);
 276 
 277         return nft_synproxy_do_dump(skb, priv);
 278 }
 279 
 280 static struct nft_expr_type nft_synproxy_type;
 281 static const struct nft_expr_ops nft_synproxy_ops = {
 282         .eval           = nft_synproxy_eval,
 283         .size           = NFT_EXPR_SIZE(sizeof(struct nft_synproxy)),
 284         .init           = nft_synproxy_init,
 285         .destroy        = nft_synproxy_destroy,
 286         .dump           = nft_synproxy_dump,
 287         .type           = &nft_synproxy_type,
 288         .validate       = nft_synproxy_validate,
 289 };
 290 
 291 static struct nft_expr_type nft_synproxy_type __read_mostly = {
 292         .ops            = &nft_synproxy_ops,
 293         .name           = "synproxy",
 294         .owner          = THIS_MODULE,
 295         .policy         = nft_synproxy_policy,
 296         .maxattr        = NFTA_SYNPROXY_MAX,
 297 };
 298 
 299 static int nft_synproxy_obj_init(const struct nft_ctx *ctx,
 300                                  const struct nlattr * const tb[],
 301                                  struct nft_object *obj)
 302 {
 303         struct nft_synproxy *priv = nft_obj_data(obj);
 304 
 305         return nft_synproxy_do_init(ctx, tb, priv);
 306 }
 307 
 308 static void nft_synproxy_obj_destroy(const struct nft_ctx *ctx,
 309                                      struct nft_object *obj)
 310 {
 311         nft_synproxy_do_destroy(ctx);
 312 }
 313 
 314 static int nft_synproxy_obj_dump(struct sk_buff *skb,
 315                                  struct nft_object *obj, bool reset)
 316 {
 317         struct nft_synproxy *priv = nft_obj_data(obj);
 318 
 319         return nft_synproxy_do_dump(skb, priv);
 320 }
 321 
 322 static void nft_synproxy_obj_eval(struct nft_object *obj,
 323                                   struct nft_regs *regs,
 324                                   const struct nft_pktinfo *pkt)
 325 {
 326         const struct nft_synproxy *priv = nft_obj_data(obj);
 327 
 328         nft_synproxy_do_eval(priv, regs, pkt);
 329 }
 330 
 331 static void nft_synproxy_obj_update(struct nft_object *obj,
 332                                     struct nft_object *newobj)
 333 {
 334         struct nft_synproxy *newpriv = nft_obj_data(newobj);
 335         struct nft_synproxy *priv = nft_obj_data(obj);
 336 
 337         priv->info = newpriv->info;
 338 }
 339 
 340 static struct nft_object_type nft_synproxy_obj_type;
 341 static const struct nft_object_ops nft_synproxy_obj_ops = {
 342         .type           = &nft_synproxy_obj_type,
 343         .size           = sizeof(struct nft_synproxy),
 344         .init           = nft_synproxy_obj_init,
 345         .destroy        = nft_synproxy_obj_destroy,
 346         .dump           = nft_synproxy_obj_dump,
 347         .eval           = nft_synproxy_obj_eval,
 348         .update         = nft_synproxy_obj_update,
 349 };
 350 
 351 static struct nft_object_type nft_synproxy_obj_type __read_mostly = {
 352         .type           = NFT_OBJECT_SYNPROXY,
 353         .ops            = &nft_synproxy_obj_ops,
 354         .maxattr        = NFTA_SYNPROXY_MAX,
 355         .policy         = nft_synproxy_policy,
 356         .owner          = THIS_MODULE,
 357 };
 358 
 359 static int __init nft_synproxy_module_init(void)
 360 {
 361         int err;
 362 
 363         err = nft_register_obj(&nft_synproxy_obj_type);
 364         if (err < 0)
 365                 return err;
 366 
 367         err = nft_register_expr(&nft_synproxy_type);
 368         if (err < 0)
 369                 goto err;
 370 
 371         return 0;
 372 
 373 err:
 374         nft_unregister_obj(&nft_synproxy_obj_type);
 375         return err;
 376 }
 377 
 378 static void __exit nft_synproxy_module_exit(void)
 379 {
 380         nft_unregister_expr(&nft_synproxy_type);
 381         nft_unregister_obj(&nft_synproxy_obj_type);
 382 }
 383 
 384 module_init(nft_synproxy_module_init);
 385 module_exit(nft_synproxy_module_exit);
 386 
 387 MODULE_LICENSE("GPL");
 388 MODULE_AUTHOR("Fernando Fernandez <ffmancera@riseup.net>");
 389 MODULE_ALIAS_NFT_EXPR("synproxy");
 390 MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_SYNPROXY);

/* [<][>][^][v][top][bottom][index][help] */