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
= nft_thoff(pkt
);
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
, 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
);
189 err
= nf_synproxy_ipv4_init(snet
, ctx
->net
);
192 err
= nf_synproxy_ipv6_init(snet
, ctx
->net
);
194 nf_synproxy_ipv4_fini(snet
, ctx
->net
);
203 nf_ct_netns_put(ctx
->net
, ctx
->family
);
207 static void nft_synproxy_do_destroy(const struct nft_ctx
*ctx
)
209 struct synproxy_net
*snet
= synproxy_pernet(ctx
->net
);
211 switch (ctx
->family
) {
213 nf_synproxy_ipv4_fini(snet
, ctx
->net
);
215 #if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
217 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
)
253 if (ctx
->family
!= NFPROTO_IPV4
&&
254 ctx
->family
!= NFPROTO_IPV6
&&
255 ctx
->family
!= NFPROTO_INET
)
258 return nft_chain_validate_hooks(ctx
->chain
, (1 << NF_INET_LOCAL_IN
) |
259 (1 << NF_INET_FORWARD
));
262 static int nft_synproxy_init(const struct nft_ctx
*ctx
,
263 const struct nft_expr
*expr
,
264 const struct nlattr
* const tb
[])
266 struct nft_synproxy
*priv
= nft_expr_priv(expr
);
268 return nft_synproxy_do_init(ctx
, tb
, priv
);
271 static void nft_synproxy_destroy(const struct nft_ctx
*ctx
,
272 const struct nft_expr
*expr
)
274 nft_synproxy_do_destroy(ctx
);
277 static int nft_synproxy_dump(struct sk_buff
*skb
,
278 const struct nft_expr
*expr
, bool reset
)
280 struct nft_synproxy
*priv
= nft_expr_priv(expr
);
282 return nft_synproxy_do_dump(skb
, priv
);
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
,
297 static struct nft_expr_type nft_synproxy_type __read_mostly
= {
298 .ops
= &nft_synproxy_ops
,
300 .owner
= THIS_MODULE
,
301 .policy
= nft_synproxy_policy
,
302 .maxattr
= NFTA_SYNPROXY_MAX
,
305 static int nft_synproxy_obj_init(const struct nft_ctx
*ctx
,
306 const struct nlattr
* const tb
[],
307 struct nft_object
*obj
)
309 struct nft_synproxy
*priv
= nft_obj_data(obj
);
311 return nft_synproxy_do_init(ctx
, tb
, priv
);
314 static void nft_synproxy_obj_destroy(const struct nft_ctx
*ctx
,
315 struct nft_object
*obj
)
317 nft_synproxy_do_destroy(ctx
);
320 static int nft_synproxy_obj_dump(struct sk_buff
*skb
,
321 struct nft_object
*obj
, bool reset
)
323 struct nft_synproxy
*priv
= nft_obj_data(obj
);
325 return nft_synproxy_do_dump(skb
, priv
);
328 static void nft_synproxy_obj_eval(struct nft_object
*obj
,
329 struct nft_regs
*regs
,
330 const struct nft_pktinfo
*pkt
)
332 const struct nft_synproxy
*priv
= nft_obj_data(obj
);
334 nft_synproxy_do_eval(priv
, regs
, pkt
);
337 static void nft_synproxy_obj_update(struct nft_object
*obj
,
338 struct nft_object
*newobj
)
340 struct nft_synproxy
*newpriv
= nft_obj_data(newobj
);
341 struct nft_synproxy
*priv
= nft_obj_data(obj
);
343 priv
->info
= newpriv
->info
;
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
,
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
,
365 static int __init
nft_synproxy_module_init(void)
369 err
= nft_register_obj(&nft_synproxy_obj_type
);
373 err
= nft_register_expr(&nft_synproxy_type
);
380 nft_unregister_obj(&nft_synproxy_obj_type
);
384 static void __exit
nft_synproxy_module_exit(void)
386 nft_unregister_expr(&nft_synproxy_type
);
387 nft_unregister_obj(&nft_synproxy_obj_type
);
390 module_init(nft_synproxy_module_init
);
391 module_exit(nft_synproxy_module_exit
);
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");