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 = nft_thoff(pkt); 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, 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 err = nf_synproxy_ipv4_init(snet, ctx->net); 190 if (err) 191 goto nf_ct_failure; 192 err = nf_synproxy_ipv6_init(snet, ctx->net); 193 if (err) { 194 nf_synproxy_ipv4_fini(snet, ctx->net); 195 goto nf_ct_failure; 196 } 197 break; 198 } 199 200 return 0; 201 202 nf_ct_failure: 203 nf_ct_netns_put(ctx->net, ctx->family); 204 return err; 205 } 206 207 static void nft_synproxy_do_destroy(const struct nft_ctx *ctx) 208 { 209 struct synproxy_net *snet = synproxy_pernet(ctx->net); 210 211 switch (ctx->family) { 212 case NFPROTO_IPV4: 213 nf_synproxy_ipv4_fini(snet, ctx->net); 214 break; 215 #if IS_ENABLED(CONFIG_NF_TABLES_IPV6) 216 case NFPROTO_IPV6: 217 nf_synproxy_ipv6_fini(snet, ctx->net); 218 break; 219 #endif 220 case NFPROTO_INET: 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 { 253 if (ctx->family != NFPROTO_IPV4 && 254 ctx->family != NFPROTO_IPV6 && 255 ctx->family != NFPROTO_INET) 256 return -EOPNOTSUPP; 257 258 return nft_chain_validate_hooks(ctx->chain, (1 << NF_INET_LOCAL_IN) | 259 (1 << NF_INET_FORWARD)); 260 } 261 262 static int nft_synproxy_init(const struct nft_ctx *ctx, 263 const struct nft_expr *expr, 264 const struct nlattr * const tb[]) 265 { 266 struct nft_synproxy *priv = nft_expr_priv(expr); 267 268 return nft_synproxy_do_init(ctx, tb, priv); 269 } 270 271 static void nft_synproxy_destroy(const struct nft_ctx *ctx, 272 const struct nft_expr *expr) 273 { 274 nft_synproxy_do_destroy(ctx); 275 } 276 277 static int nft_synproxy_dump(struct sk_buff *skb, 278 const struct nft_expr *expr, bool reset) 279 { 280 struct nft_synproxy *priv = nft_expr_priv(expr); 281 282 return nft_synproxy_do_dump(skb, priv); 283 } 284 285 static struct nft_expr_type nft_synproxy_type; 286 static const struct nft_expr_ops nft_synproxy_ops = { 287 .eval = nft_synproxy_eval, 288 .size = NFT_EXPR_SIZE(sizeof(struct nft_synproxy)), 289 .init = nft_synproxy_init, 290 .destroy = nft_synproxy_destroy, 291 .dump = nft_synproxy_dump, 292 .type = &nft_synproxy_type, 293 .validate = nft_synproxy_validate, 294 .reduce = NFT_REDUCE_READONLY, 295 }; 296 297 static struct nft_expr_type nft_synproxy_type __read_mostly = { 298 .ops = &nft_synproxy_ops, 299 .name = "synproxy", 300 .owner = THIS_MODULE, 301 .policy = nft_synproxy_policy, 302 .maxattr = NFTA_SYNPROXY_MAX, 303 }; 304 305 static int nft_synproxy_obj_init(const struct nft_ctx *ctx, 306 const struct nlattr * const tb[], 307 struct nft_object *obj) 308 { 309 struct nft_synproxy *priv = nft_obj_data(obj); 310 311 return nft_synproxy_do_init(ctx, tb, priv); 312 } 313 314 static void nft_synproxy_obj_destroy(const struct nft_ctx *ctx, 315 struct nft_object *obj) 316 { 317 nft_synproxy_do_destroy(ctx); 318 } 319 320 static int nft_synproxy_obj_dump(struct sk_buff *skb, 321 struct nft_object *obj, bool reset) 322 { 323 struct nft_synproxy *priv = nft_obj_data(obj); 324 325 return nft_synproxy_do_dump(skb, priv); 326 } 327 328 static void nft_synproxy_obj_eval(struct nft_object *obj, 329 struct nft_regs *regs, 330 const struct nft_pktinfo *pkt) 331 { 332 const struct nft_synproxy *priv = nft_obj_data(obj); 333 334 nft_synproxy_do_eval(priv, regs, pkt); 335 } 336 337 static void nft_synproxy_obj_update(struct nft_object *obj, 338 struct nft_object *newobj) 339 { 340 struct nft_synproxy *newpriv = nft_obj_data(newobj); 341 struct nft_synproxy *priv = nft_obj_data(obj); 342 343 priv->info = newpriv->info; 344 } 345 346 static struct nft_object_type nft_synproxy_obj_type; 347 static const struct nft_object_ops nft_synproxy_obj_ops = { 348 .type = &nft_synproxy_obj_type, 349 .size = sizeof(struct nft_synproxy), 350 .init = nft_synproxy_obj_init, 351 .destroy = nft_synproxy_obj_destroy, 352 .dump = nft_synproxy_obj_dump, 353 .eval = nft_synproxy_obj_eval, 354 .update = nft_synproxy_obj_update, 355 }; 356 357 static struct nft_object_type nft_synproxy_obj_type __read_mostly = { 358 .type = NFT_OBJECT_SYNPROXY, 359 .ops = &nft_synproxy_obj_ops, 360 .maxattr = NFTA_SYNPROXY_MAX, 361 .policy = nft_synproxy_policy, 362 .owner = THIS_MODULE, 363 }; 364 365 static int __init nft_synproxy_module_init(void) 366 { 367 int err; 368 369 err = nft_register_obj(&nft_synproxy_obj_type); 370 if (err < 0) 371 return err; 372 373 err = nft_register_expr(&nft_synproxy_type); 374 if (err < 0) 375 goto err; 376 377 return 0; 378 379 err: 380 nft_unregister_obj(&nft_synproxy_obj_type); 381 return err; 382 } 383 384 static void __exit nft_synproxy_module_exit(void) 385 { 386 nft_unregister_expr(&nft_synproxy_type); 387 nft_unregister_obj(&nft_synproxy_obj_type); 388 } 389 390 module_init(nft_synproxy_module_init); 391 module_exit(nft_synproxy_module_exit); 392 393 MODULE_LICENSE("GPL"); 394 MODULE_AUTHOR("Fernando Fernandez <ffmancera@riseup.net>"); 395 MODULE_ALIAS_NFT_EXPR("synproxy"); 396 MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_SYNPROXY); 397 MODULE_DESCRIPTION("nftables SYNPROXY expression support"); 398