1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/types.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>
14 struct nf_synproxy_info info
;
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
},
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
)
29 this_cpu_inc(snet
->stats
->syn_received
);
30 if (tcp
->ece
&& tcp
->cwr
)
31 opts
->options
|= NF_SYNPROXY_OPT_ECN
;
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
);
39 opts
->options
&= ~(NF_SYNPROXY_OPT_WSCALE
|
40 NF_SYNPROXY_OPT_SACK_PERM
|
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
,
49 struct synproxy_options
*opts
)
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
;
57 /* Initial SYN from client */
58 nft_synproxy_tcp_options(opts
, tcp
, snet
, &info
, priv
);
59 synproxy_send_client_synack(net
, skb
, tcp
, opts
);
61 regs
->verdict
.code
= NF_STOLEN
;
62 } else if (tcp
->ack
) {
64 if (synproxy_recv_client_ack(net
, skb
, tcp
, opts
,
67 regs
->verdict
.code
= NF_STOLEN
;
69 regs
->verdict
.code
= NF_DROP
;
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
,
80 struct synproxy_options
*opts
)
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
;
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
);
92 regs
->verdict
.code
= NF_STOLEN
;
93 } else if (tcp
->ack
) {
95 if (synproxy_recv_client_ack_ipv6(net
, skb
, tcp
, opts
,
98 regs
->verdict
.code
= NF_STOLEN
;
100 regs
->verdict
.code
= NF_DROP
;
104 #endif /* CONFIG_NF_TABLES_IPV6*/
106 static void nft_synproxy_do_eval(const struct nft_synproxy
*priv
,
107 struct nft_regs
*regs
,
108 const struct nft_pktinfo
*pkt
)
110 struct synproxy_options opts
= {};
111 struct sk_buff
*skb
= pkt
->skb
;
112 int thoff
= pkt
->xt
.thoff
;
113 const struct tcphdr
*tcp
;
116 if (pkt
->tprot
!= IPPROTO_TCP
) {
117 regs
->verdict
.code
= NFT_BREAK
;
121 if (nf_ip_checksum(skb
, nft_hook(pkt
), thoff
, IPPROTO_TCP
)) {
122 regs
->verdict
.code
= NF_DROP
;
126 tcp
= skb_header_pointer(skb
, pkt
->xt
.thoff
,
127 sizeof(struct tcphdr
),
130 regs
->verdict
.code
= NF_DROP
;
134 if (!synproxy_parse_options(skb
, thoff
, tcp
, &opts
)) {
135 regs
->verdict
.code
= NF_DROP
;
139 switch (skb
->protocol
) {
140 case htons(ETH_P_IP
):
141 nft_synproxy_eval_v4(priv
, regs
, pkt
, tcp
, &_tcph
, &opts
);
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
);
149 regs
->verdict
.code
= NFT_BREAK
;
152 static int nft_synproxy_do_init(const struct nft_ctx
*ctx
,
153 const struct nlattr
* const tb
[],
154 struct nft_synproxy
*priv
)
156 struct synproxy_net
*snet
= synproxy_pernet(ctx
->net
);
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
)
168 priv
->info
.options
= flags
;
171 err
= nf_ct_netns_get(ctx
->net
, ctx
->family
);
175 switch (ctx
->family
) {
177 err
= nf_synproxy_ipv4_init(snet
, ctx
->net
);
181 #if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
183 err
= nf_synproxy_ipv6_init(snet
, ctx
->net
);
190 err
= nf_synproxy_ipv4_init(snet
, ctx
->net
);
193 err
= nf_synproxy_ipv6_init(snet
, ctx
->net
);
202 nf_ct_netns_put(ctx
->net
, ctx
->family
);
206 static void nft_synproxy_do_destroy(const struct nft_ctx
*ctx
)
208 struct synproxy_net
*snet
= synproxy_pernet(ctx
->net
);
210 switch (ctx
->family
) {
212 nf_synproxy_ipv4_fini(snet
, ctx
->net
);
214 #if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
216 nf_synproxy_ipv6_fini(snet
, ctx
->net
);
221 nf_synproxy_ipv4_fini(snet
, ctx
->net
);
222 nf_synproxy_ipv6_fini(snet
, ctx
->net
);
225 nf_ct_netns_put(ctx
->net
, ctx
->family
);
228 static int nft_synproxy_do_dump(struct sk_buff
*skb
, struct nft_synproxy
*priv
)
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
;
241 static void nft_synproxy_eval(const struct nft_expr
*expr
,
242 struct nft_regs
*regs
,
243 const struct nft_pktinfo
*pkt
)
245 const struct nft_synproxy
*priv
= nft_expr_priv(expr
);
247 nft_synproxy_do_eval(priv
, regs
, pkt
);
250 static int nft_synproxy_validate(const struct nft_ctx
*ctx
,
251 const struct nft_expr
*expr
,
252 const struct nft_data
**data
)
254 return nft_chain_validate_hooks(ctx
->chain
, (1 << NF_INET_LOCAL_IN
) |
255 (1 << NF_INET_FORWARD
));
258 static int nft_synproxy_init(const struct nft_ctx
*ctx
,
259 const struct nft_expr
*expr
,
260 const struct nlattr
* const tb
[])
262 struct nft_synproxy
*priv
= nft_expr_priv(expr
);
264 return nft_synproxy_do_init(ctx
, tb
, priv
);
267 static void nft_synproxy_destroy(const struct nft_ctx
*ctx
,
268 const struct nft_expr
*expr
)
270 nft_synproxy_do_destroy(ctx
);
273 static int nft_synproxy_dump(struct sk_buff
*skb
, const struct nft_expr
*expr
)
275 struct nft_synproxy
*priv
= nft_expr_priv(expr
);
277 return nft_synproxy_do_dump(skb
, priv
);
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
,
291 static struct nft_expr_type nft_synproxy_type __read_mostly
= {
292 .ops
= &nft_synproxy_ops
,
294 .owner
= THIS_MODULE
,
295 .policy
= nft_synproxy_policy
,
296 .maxattr
= NFTA_SYNPROXY_MAX
,
299 static int nft_synproxy_obj_init(const struct nft_ctx
*ctx
,
300 const struct nlattr
* const tb
[],
301 struct nft_object
*obj
)
303 struct nft_synproxy
*priv
= nft_obj_data(obj
);
305 return nft_synproxy_do_init(ctx
, tb
, priv
);
308 static void nft_synproxy_obj_destroy(const struct nft_ctx
*ctx
,
309 struct nft_object
*obj
)
311 nft_synproxy_do_destroy(ctx
);
314 static int nft_synproxy_obj_dump(struct sk_buff
*skb
,
315 struct nft_object
*obj
, bool reset
)
317 struct nft_synproxy
*priv
= nft_obj_data(obj
);
319 return nft_synproxy_do_dump(skb
, priv
);
322 static void nft_synproxy_obj_eval(struct nft_object
*obj
,
323 struct nft_regs
*regs
,
324 const struct nft_pktinfo
*pkt
)
326 const struct nft_synproxy
*priv
= nft_obj_data(obj
);
328 nft_synproxy_do_eval(priv
, regs
, pkt
);
331 static void nft_synproxy_obj_update(struct nft_object
*obj
,
332 struct nft_object
*newobj
)
334 struct nft_synproxy
*newpriv
= nft_obj_data(newobj
);
335 struct nft_synproxy
*priv
= nft_obj_data(obj
);
337 priv
->info
= newpriv
->info
;
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
,
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
,
359 static int __init
nft_synproxy_module_init(void)
363 err
= nft_register_obj(&nft_synproxy_obj_type
);
367 err
= nft_register_expr(&nft_synproxy_type
);
374 nft_unregister_obj(&nft_synproxy_obj_type
);
378 static void __exit
nft_synproxy_module_exit(void)
380 nft_unregister_expr(&nft_synproxy_type
);
381 nft_unregister_obj(&nft_synproxy_obj_type
);
384 module_init(nft_synproxy_module_init
);
385 module_exit(nft_synproxy_module_exit
);
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
);
391 MODULE_DESCRIPTION("nftables SYNPROXY expression support");