0001
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
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
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
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
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
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");