Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <linux/types.h>
0003 #include <net/ip.h>
0004 #include <net/tcp.h>
0005 #include <net/netlink.h>
0006 #include <net/netfilter/nf_tables.h>
0007 #include <net/netfilter/nf_conntrack.h>
0008 #include <net/netfilter/nf_conntrack_synproxy.h>
0009 #include <net/netfilter/nf_synproxy.h>
0010 #include <linux/netfilter/nf_tables.h>
0011 #include <linux/netfilter/nf_synproxy.h>
0012 
0013 struct nft_synproxy {
0014     struct nf_synproxy_info info;
0015 };
0016 
0017 static const struct nla_policy nft_synproxy_policy[NFTA_SYNPROXY_MAX + 1] = {
0018     [NFTA_SYNPROXY_MSS]     = { .type = NLA_U16 },
0019     [NFTA_SYNPROXY_WSCALE]      = { .type = NLA_U8 },
0020     [NFTA_SYNPROXY_FLAGS]       = { .type = NLA_U32 },
0021 };
0022 
0023 static void nft_synproxy_tcp_options(struct synproxy_options *opts,
0024                      const struct tcphdr *tcp,
0025                      struct synproxy_net *snet,
0026                      struct nf_synproxy_info *info,
0027                      const struct nft_synproxy *priv)
0028 {
0029     this_cpu_inc(snet->stats->syn_received);
0030     if (tcp->ece && tcp->cwr)
0031         opts->options |= NF_SYNPROXY_OPT_ECN;
0032 
0033     opts->options &= priv->info.options;
0034     opts->mss_encode = opts->mss_option;
0035     opts->mss_option = info->mss;
0036     if (opts->options & NF_SYNPROXY_OPT_TIMESTAMP)
0037         synproxy_init_timestamp_cookie(info, opts);
0038     else
0039         opts->options &= ~(NF_SYNPROXY_OPT_WSCALE |
0040                    NF_SYNPROXY_OPT_SACK_PERM |
0041                    NF_SYNPROXY_OPT_ECN);
0042 }
0043 
0044 static void nft_synproxy_eval_v4(const struct nft_synproxy *priv,
0045                  struct nft_regs *regs,
0046                  const struct nft_pktinfo *pkt,
0047                  const struct tcphdr *tcp,
0048                  struct tcphdr *_tcph,
0049                  struct synproxy_options *opts)
0050 {
0051     struct nf_synproxy_info info = priv->info;
0052     struct net *net = nft_net(pkt);
0053     struct synproxy_net *snet = synproxy_pernet(net);
0054     struct sk_buff *skb = pkt->skb;
0055 
0056     if (tcp->syn) {
0057         /* Initial SYN from client */
0058         nft_synproxy_tcp_options(opts, tcp, snet, &info, priv);
0059         synproxy_send_client_synack(net, skb, tcp, opts);
0060         consume_skb(skb);
0061         regs->verdict.code = NF_STOLEN;
0062     } else if (tcp->ack) {
0063         /* ACK from client */
0064         if (synproxy_recv_client_ack(net, skb, tcp, opts,
0065                          ntohl(tcp->seq))) {
0066             consume_skb(skb);
0067             regs->verdict.code = NF_STOLEN;
0068         } else {
0069             regs->verdict.code = NF_DROP;
0070         }
0071     }
0072 }
0073 
0074 #if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
0075 static void nft_synproxy_eval_v6(const struct nft_synproxy *priv,
0076                  struct nft_regs *regs,
0077                  const struct nft_pktinfo *pkt,
0078                  const struct tcphdr *tcp,
0079                  struct tcphdr *_tcph,
0080                  struct synproxy_options *opts)
0081 {
0082     struct nf_synproxy_info info = priv->info;
0083     struct net *net = nft_net(pkt);
0084     struct synproxy_net *snet = synproxy_pernet(net);
0085     struct sk_buff *skb = pkt->skb;
0086 
0087     if (tcp->syn) {
0088         /* Initial SYN from client */
0089         nft_synproxy_tcp_options(opts, tcp, snet, &info, priv);
0090         synproxy_send_client_synack_ipv6(net, skb, tcp, opts);
0091         consume_skb(skb);
0092         regs->verdict.code = NF_STOLEN;
0093     } else if (tcp->ack) {
0094         /* ACK from client */
0095         if (synproxy_recv_client_ack_ipv6(net, skb, tcp, opts,
0096                           ntohl(tcp->seq))) {
0097             consume_skb(skb);
0098             regs->verdict.code = NF_STOLEN;
0099         } else {
0100             regs->verdict.code = NF_DROP;
0101         }
0102     }
0103 }
0104 #endif /* CONFIG_NF_TABLES_IPV6*/
0105 
0106 static void nft_synproxy_do_eval(const struct nft_synproxy *priv,
0107                  struct nft_regs *regs,
0108                  const struct nft_pktinfo *pkt)
0109 {
0110     struct synproxy_options opts = {};
0111     struct sk_buff *skb = pkt->skb;
0112     int thoff = nft_thoff(pkt);
0113     const struct tcphdr *tcp;
0114     struct tcphdr _tcph;
0115 
0116     if (pkt->tprot != IPPROTO_TCP) {
0117         regs->verdict.code = NFT_BREAK;
0118         return;
0119     }
0120 
0121     if (nf_ip_checksum(skb, nft_hook(pkt), thoff, IPPROTO_TCP)) {
0122         regs->verdict.code = NF_DROP;
0123         return;
0124     }
0125 
0126     tcp = skb_header_pointer(skb, thoff,
0127                  sizeof(struct tcphdr),
0128                  &_tcph);
0129     if (!tcp) {
0130         regs->verdict.code = NF_DROP;
0131         return;
0132     }
0133 
0134     if (!synproxy_parse_options(skb, thoff, tcp, &opts)) {
0135         regs->verdict.code = NF_DROP;
0136         return;
0137     }
0138 
0139     switch (skb->protocol) {
0140     case htons(ETH_P_IP):
0141         nft_synproxy_eval_v4(priv, regs, pkt, tcp, &_tcph, &opts);
0142         return;
0143 #if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
0144     case htons(ETH_P_IPV6):
0145         nft_synproxy_eval_v6(priv, regs, pkt, tcp, &_tcph, &opts);
0146         return;
0147 #endif
0148     }
0149     regs->verdict.code = NFT_BREAK;
0150 }
0151 
0152 static int nft_synproxy_do_init(const struct nft_ctx *ctx,
0153                 const struct nlattr * const tb[],
0154                 struct nft_synproxy *priv)
0155 {
0156     struct synproxy_net *snet = synproxy_pernet(ctx->net);
0157     u32 flags;
0158     int err;
0159 
0160     if (tb[NFTA_SYNPROXY_MSS])
0161         priv->info.mss = ntohs(nla_get_be16(tb[NFTA_SYNPROXY_MSS]));
0162     if (tb[NFTA_SYNPROXY_WSCALE])
0163         priv->info.wscale = nla_get_u8(tb[NFTA_SYNPROXY_WSCALE]);
0164     if (tb[NFTA_SYNPROXY_FLAGS]) {
0165         flags = ntohl(nla_get_be32(tb[NFTA_SYNPROXY_FLAGS]));
0166         if (flags & ~NF_SYNPROXY_OPT_MASK)
0167             return -EOPNOTSUPP;
0168         priv->info.options = flags;
0169     }
0170 
0171     err = nf_ct_netns_get(ctx->net, ctx->family);
0172     if (err)
0173         return err;
0174 
0175     switch (ctx->family) {
0176     case NFPROTO_IPV4:
0177         err = nf_synproxy_ipv4_init(snet, ctx->net);
0178         if (err)
0179             goto nf_ct_failure;
0180         break;
0181 #if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
0182     case NFPROTO_IPV6:
0183         err = nf_synproxy_ipv6_init(snet, ctx->net);
0184         if (err)
0185             goto nf_ct_failure;
0186         break;
0187 #endif
0188     case NFPROTO_INET:
0189     case NFPROTO_BRIDGE:
0190         err = nf_synproxy_ipv4_init(snet, ctx->net);
0191         if (err)
0192             goto nf_ct_failure;
0193         err = nf_synproxy_ipv6_init(snet, ctx->net);
0194         if (err) {
0195             nf_synproxy_ipv4_fini(snet, ctx->net);
0196             goto nf_ct_failure;
0197         }
0198         break;
0199     }
0200 
0201     return 0;
0202 
0203 nf_ct_failure:
0204     nf_ct_netns_put(ctx->net, ctx->family);
0205     return err;
0206 }
0207 
0208 static void nft_synproxy_do_destroy(const struct nft_ctx *ctx)
0209 {
0210     struct synproxy_net *snet = synproxy_pernet(ctx->net);
0211 
0212     switch (ctx->family) {
0213     case NFPROTO_IPV4:
0214         nf_synproxy_ipv4_fini(snet, ctx->net);
0215         break;
0216 #if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
0217     case NFPROTO_IPV6:
0218         nf_synproxy_ipv6_fini(snet, ctx->net);
0219         break;
0220 #endif
0221     case NFPROTO_INET:
0222     case NFPROTO_BRIDGE:
0223         nf_synproxy_ipv4_fini(snet, ctx->net);
0224         nf_synproxy_ipv6_fini(snet, ctx->net);
0225         break;
0226     }
0227     nf_ct_netns_put(ctx->net, ctx->family);
0228 }
0229 
0230 static int nft_synproxy_do_dump(struct sk_buff *skb, struct nft_synproxy *priv)
0231 {
0232     if (nla_put_be16(skb, NFTA_SYNPROXY_MSS, htons(priv->info.mss)) ||
0233         nla_put_u8(skb, NFTA_SYNPROXY_WSCALE, priv->info.wscale) ||
0234         nla_put_be32(skb, NFTA_SYNPROXY_FLAGS, htonl(priv->info.options)))
0235         goto nla_put_failure;
0236 
0237     return 0;
0238 
0239 nla_put_failure:
0240     return -1;
0241 }
0242 
0243 static void nft_synproxy_eval(const struct nft_expr *expr,
0244                   struct nft_regs *regs,
0245                   const struct nft_pktinfo *pkt)
0246 {
0247     const struct nft_synproxy *priv = nft_expr_priv(expr);
0248 
0249     nft_synproxy_do_eval(priv, regs, pkt);
0250 }
0251 
0252 static int nft_synproxy_validate(const struct nft_ctx *ctx,
0253                  const struct nft_expr *expr,
0254                  const struct nft_data **data)
0255 {
0256     return nft_chain_validate_hooks(ctx->chain, (1 << NF_INET_LOCAL_IN) |
0257                             (1 << NF_INET_FORWARD));
0258 }
0259 
0260 static int nft_synproxy_init(const struct nft_ctx *ctx,
0261                  const struct nft_expr *expr,
0262                  const struct nlattr * const tb[])
0263 {
0264     struct nft_synproxy *priv = nft_expr_priv(expr);
0265 
0266     return nft_synproxy_do_init(ctx, tb, priv);
0267 }
0268 
0269 static void nft_synproxy_destroy(const struct nft_ctx *ctx,
0270                  const struct nft_expr *expr)
0271 {
0272     nft_synproxy_do_destroy(ctx);
0273 }
0274 
0275 static int nft_synproxy_dump(struct sk_buff *skb, const struct nft_expr *expr)
0276 {
0277     struct nft_synproxy *priv = nft_expr_priv(expr);
0278 
0279     return nft_synproxy_do_dump(skb, priv);
0280 }
0281 
0282 static struct nft_expr_type nft_synproxy_type;
0283 static const struct nft_expr_ops nft_synproxy_ops = {
0284     .eval       = nft_synproxy_eval,
0285     .size       = NFT_EXPR_SIZE(sizeof(struct nft_synproxy)),
0286     .init       = nft_synproxy_init,
0287     .destroy    = nft_synproxy_destroy,
0288     .dump       = nft_synproxy_dump,
0289     .type       = &nft_synproxy_type,
0290     .validate   = nft_synproxy_validate,
0291     .reduce     = NFT_REDUCE_READONLY,
0292 };
0293 
0294 static struct nft_expr_type nft_synproxy_type __read_mostly = {
0295     .ops        = &nft_synproxy_ops,
0296     .name       = "synproxy",
0297     .owner      = THIS_MODULE,
0298     .policy     = nft_synproxy_policy,
0299     .maxattr    = NFTA_SYNPROXY_MAX,
0300 };
0301 
0302 static int nft_synproxy_obj_init(const struct nft_ctx *ctx,
0303                  const struct nlattr * const tb[],
0304                  struct nft_object *obj)
0305 {
0306     struct nft_synproxy *priv = nft_obj_data(obj);
0307 
0308     return nft_synproxy_do_init(ctx, tb, priv);
0309 }
0310 
0311 static void nft_synproxy_obj_destroy(const struct nft_ctx *ctx,
0312                      struct nft_object *obj)
0313 {
0314     nft_synproxy_do_destroy(ctx);
0315 }
0316 
0317 static int nft_synproxy_obj_dump(struct sk_buff *skb,
0318                  struct nft_object *obj, bool reset)
0319 {
0320     struct nft_synproxy *priv = nft_obj_data(obj);
0321 
0322     return nft_synproxy_do_dump(skb, priv);
0323 }
0324 
0325 static void nft_synproxy_obj_eval(struct nft_object *obj,
0326                   struct nft_regs *regs,
0327                   const struct nft_pktinfo *pkt)
0328 {
0329     const struct nft_synproxy *priv = nft_obj_data(obj);
0330 
0331     nft_synproxy_do_eval(priv, regs, pkt);
0332 }
0333 
0334 static void nft_synproxy_obj_update(struct nft_object *obj,
0335                     struct nft_object *newobj)
0336 {
0337     struct nft_synproxy *newpriv = nft_obj_data(newobj);
0338     struct nft_synproxy *priv = nft_obj_data(obj);
0339 
0340     priv->info = newpriv->info;
0341 }
0342 
0343 static struct nft_object_type nft_synproxy_obj_type;
0344 static const struct nft_object_ops nft_synproxy_obj_ops = {
0345     .type       = &nft_synproxy_obj_type,
0346     .size       = sizeof(struct nft_synproxy),
0347     .init       = nft_synproxy_obj_init,
0348     .destroy    = nft_synproxy_obj_destroy,
0349     .dump       = nft_synproxy_obj_dump,
0350     .eval       = nft_synproxy_obj_eval,
0351     .update     = nft_synproxy_obj_update,
0352 };
0353 
0354 static struct nft_object_type nft_synproxy_obj_type __read_mostly = {
0355     .type       = NFT_OBJECT_SYNPROXY,
0356     .ops        = &nft_synproxy_obj_ops,
0357     .maxattr    = NFTA_SYNPROXY_MAX,
0358     .policy     = nft_synproxy_policy,
0359     .owner      = THIS_MODULE,
0360 };
0361 
0362 static int __init nft_synproxy_module_init(void)
0363 {
0364     int err;
0365 
0366     err = nft_register_obj(&nft_synproxy_obj_type);
0367     if (err < 0)
0368         return err;
0369 
0370     err = nft_register_expr(&nft_synproxy_type);
0371     if (err < 0)
0372         goto err;
0373 
0374     return 0;
0375 
0376 err:
0377     nft_unregister_obj(&nft_synproxy_obj_type);
0378     return err;
0379 }
0380 
0381 static void __exit nft_synproxy_module_exit(void)
0382 {
0383     nft_unregister_expr(&nft_synproxy_type);
0384     nft_unregister_obj(&nft_synproxy_obj_type);
0385 }
0386 
0387 module_init(nft_synproxy_module_init);
0388 module_exit(nft_synproxy_module_exit);
0389 
0390 MODULE_LICENSE("GPL");
0391 MODULE_AUTHOR("Fernando Fernandez <ffmancera@riseup.net>");
0392 MODULE_ALIAS_NFT_EXPR("synproxy");
0393 MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_SYNPROXY);
0394 MODULE_DESCRIPTION("nftables SYNPROXY expression support");