1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2013 Patrick McHardy <kaber@trash.net>
6 #include <linux/module.h>
7 #include <linux/skbuff.h>
8 #include <asm/unaligned.h>
10 #include <net/netns/generic.h>
11 #include <linux/proc_fs.h>
13 #include <linux/netfilter_ipv6.h>
14 #include <linux/netfilter/nf_synproxy.h>
16 #include <net/netfilter/nf_conntrack.h>
17 #include <net/netfilter/nf_conntrack_ecache.h>
18 #include <net/netfilter/nf_conntrack_extend.h>
19 #include <net/netfilter/nf_conntrack_seqadj.h>
20 #include <net/netfilter/nf_conntrack_synproxy.h>
21 #include <net/netfilter/nf_conntrack_zones.h>
22 #include <net/netfilter/nf_synproxy.h>
24 unsigned int synproxy_net_id
;
25 EXPORT_SYMBOL_GPL(synproxy_net_id
);
28 synproxy_parse_options(const struct sk_buff
*skb
, unsigned int doff
,
29 const struct tcphdr
*th
, struct synproxy_options
*opts
)
31 int length
= (th
->doff
* 4) - sizeof(*th
);
34 ptr
= skb_header_pointer(skb
, doff
+ sizeof(*th
), length
, buf
);
58 if (opsize
== TCPOLEN_MSS
) {
59 opts
->mss_option
= get_unaligned_be16(ptr
);
60 opts
->options
|= NF_SYNPROXY_OPT_MSS
;
64 if (opsize
== TCPOLEN_WINDOW
) {
66 if (opts
->wscale
> TCP_MAX_WSCALE
)
67 opts
->wscale
= TCP_MAX_WSCALE
;
68 opts
->options
|= NF_SYNPROXY_OPT_WSCALE
;
71 case TCPOPT_TIMESTAMP
:
72 if (opsize
== TCPOLEN_TIMESTAMP
) {
73 opts
->tsval
= get_unaligned_be32(ptr
);
74 opts
->tsecr
= get_unaligned_be32(ptr
+ 4);
75 opts
->options
|= NF_SYNPROXY_OPT_TIMESTAMP
;
78 case TCPOPT_SACK_PERM
:
79 if (opsize
== TCPOLEN_SACK_PERM
)
80 opts
->options
|= NF_SYNPROXY_OPT_SACK_PERM
;
90 EXPORT_SYMBOL_GPL(synproxy_parse_options
);
93 synproxy_options_size(const struct synproxy_options
*opts
)
95 unsigned int size
= 0;
97 if (opts
->options
& NF_SYNPROXY_OPT_MSS
)
98 size
+= TCPOLEN_MSS_ALIGNED
;
99 if (opts
->options
& NF_SYNPROXY_OPT_TIMESTAMP
)
100 size
+= TCPOLEN_TSTAMP_ALIGNED
;
101 else if (opts
->options
& NF_SYNPROXY_OPT_SACK_PERM
)
102 size
+= TCPOLEN_SACKPERM_ALIGNED
;
103 if (opts
->options
& NF_SYNPROXY_OPT_WSCALE
)
104 size
+= TCPOLEN_WSCALE_ALIGNED
;
110 synproxy_build_options(struct tcphdr
*th
, const struct synproxy_options
*opts
)
112 __be32
*ptr
= (__be32
*)(th
+ 1);
113 u8 options
= opts
->options
;
115 if (options
& NF_SYNPROXY_OPT_MSS
)
116 *ptr
++ = htonl((TCPOPT_MSS
<< 24) |
117 (TCPOLEN_MSS
<< 16) |
120 if (options
& NF_SYNPROXY_OPT_TIMESTAMP
) {
121 if (options
& NF_SYNPROXY_OPT_SACK_PERM
)
122 *ptr
++ = htonl((TCPOPT_SACK_PERM
<< 24) |
123 (TCPOLEN_SACK_PERM
<< 16) |
124 (TCPOPT_TIMESTAMP
<< 8) |
127 *ptr
++ = htonl((TCPOPT_NOP
<< 24) |
129 (TCPOPT_TIMESTAMP
<< 8) |
132 *ptr
++ = htonl(opts
->tsval
);
133 *ptr
++ = htonl(opts
->tsecr
);
134 } else if (options
& NF_SYNPROXY_OPT_SACK_PERM
)
135 *ptr
++ = htonl((TCPOPT_NOP
<< 24) |
137 (TCPOPT_SACK_PERM
<< 8) |
140 if (options
& NF_SYNPROXY_OPT_WSCALE
)
141 *ptr
++ = htonl((TCPOPT_NOP
<< 24) |
142 (TCPOPT_WINDOW
<< 16) |
143 (TCPOLEN_WINDOW
<< 8) |
147 void synproxy_init_timestamp_cookie(const struct nf_synproxy_info
*info
,
148 struct synproxy_options
*opts
)
150 opts
->tsecr
= opts
->tsval
;
151 opts
->tsval
= tcp_time_stamp_raw() & ~0x3f;
153 if (opts
->options
& NF_SYNPROXY_OPT_WSCALE
) {
154 opts
->tsval
|= opts
->wscale
;
155 opts
->wscale
= info
->wscale
;
159 if (opts
->options
& NF_SYNPROXY_OPT_SACK_PERM
)
160 opts
->tsval
|= 1 << 4;
162 if (opts
->options
& NF_SYNPROXY_OPT_ECN
)
163 opts
->tsval
|= 1 << 5;
165 EXPORT_SYMBOL_GPL(synproxy_init_timestamp_cookie
);
168 synproxy_check_timestamp_cookie(struct synproxy_options
*opts
)
170 opts
->wscale
= opts
->tsecr
& 0xf;
171 if (opts
->wscale
!= 0xf)
172 opts
->options
|= NF_SYNPROXY_OPT_WSCALE
;
174 opts
->options
|= opts
->tsecr
& (1 << 4) ? NF_SYNPROXY_OPT_SACK_PERM
: 0;
176 opts
->options
|= opts
->tsecr
& (1 << 5) ? NF_SYNPROXY_OPT_ECN
: 0;
180 synproxy_tstamp_adjust(struct sk_buff
*skb
, unsigned int protoff
,
181 struct tcphdr
*th
, struct nf_conn
*ct
,
182 enum ip_conntrack_info ctinfo
,
183 const struct nf_conn_synproxy
*synproxy
)
185 unsigned int optoff
, optend
;
188 if (synproxy
->tsoff
== 0)
191 optoff
= protoff
+ sizeof(struct tcphdr
);
192 optend
= protoff
+ th
->doff
* 4;
194 if (skb_ensure_writable(skb
, optend
))
197 while (optoff
< optend
) {
198 unsigned char *op
= skb
->data
+ optoff
;
207 if (optoff
+ 1 == optend
||
208 optoff
+ op
[1] > optend
||
211 if (op
[0] == TCPOPT_TIMESTAMP
&&
212 op
[1] == TCPOLEN_TIMESTAMP
) {
213 if (CTINFO2DIR(ctinfo
) == IP_CT_DIR_REPLY
) {
214 ptr
= (__be32
*)&op
[2];
216 *ptr
= htonl(ntohl(*ptr
) -
219 ptr
= (__be32
*)&op
[6];
221 *ptr
= htonl(ntohl(*ptr
) +
224 inet_proto_csum_replace4(&th
->check
, skb
,
234 static struct nf_ct_ext_type nf_ct_synproxy_extend __read_mostly
= {
235 .len
= sizeof(struct nf_conn_synproxy
),
236 .align
= __alignof__(struct nf_conn_synproxy
),
237 .id
= NF_CT_EXT_SYNPROXY
,
240 #ifdef CONFIG_PROC_FS
241 static void *synproxy_cpu_seq_start(struct seq_file
*seq
, loff_t
*pos
)
243 struct synproxy_net
*snet
= synproxy_pernet(seq_file_net(seq
));
247 return SEQ_START_TOKEN
;
249 for (cpu
= *pos
- 1; cpu
< nr_cpu_ids
; cpu
++) {
250 if (!cpu_possible(cpu
))
253 return per_cpu_ptr(snet
->stats
, cpu
);
259 static void *synproxy_cpu_seq_next(struct seq_file
*seq
, void *v
, loff_t
*pos
)
261 struct synproxy_net
*snet
= synproxy_pernet(seq_file_net(seq
));
264 for (cpu
= *pos
; cpu
< nr_cpu_ids
; cpu
++) {
265 if (!cpu_possible(cpu
))
268 return per_cpu_ptr(snet
->stats
, cpu
);
274 static void synproxy_cpu_seq_stop(struct seq_file
*seq
, void *v
)
279 static int synproxy_cpu_seq_show(struct seq_file
*seq
, void *v
)
281 struct synproxy_stats
*stats
= v
;
283 if (v
== SEQ_START_TOKEN
) {
284 seq_puts(seq
, "entries\t\tsyn_received\t"
285 "cookie_invalid\tcookie_valid\t"
286 "cookie_retrans\tconn_reopened\n");
290 seq_printf(seq
, "%08x\t%08x\t%08x\t%08x\t%08x\t%08x\n", 0,
292 stats
->cookie_invalid
,
294 stats
->cookie_retrans
,
295 stats
->conn_reopened
);
300 static const struct seq_operations synproxy_cpu_seq_ops
= {
301 .start
= synproxy_cpu_seq_start
,
302 .next
= synproxy_cpu_seq_next
,
303 .stop
= synproxy_cpu_seq_stop
,
304 .show
= synproxy_cpu_seq_show
,
307 static int __net_init
synproxy_proc_init(struct net
*net
)
309 if (!proc_create_net("synproxy", 0444, net
->proc_net_stat
,
310 &synproxy_cpu_seq_ops
, sizeof(struct seq_net_private
)))
315 static void __net_exit
synproxy_proc_exit(struct net
*net
)
317 remove_proc_entry("synproxy", net
->proc_net_stat
);
320 static int __net_init
synproxy_proc_init(struct net
*net
)
325 static void __net_exit
synproxy_proc_exit(struct net
*net
)
329 #endif /* CONFIG_PROC_FS */
331 static int __net_init
synproxy_net_init(struct net
*net
)
333 struct synproxy_net
*snet
= synproxy_pernet(net
);
337 ct
= nf_ct_tmpl_alloc(net
, &nf_ct_zone_dflt
, GFP_KERNEL
);
341 if (!nfct_seqadj_ext_add(ct
))
343 if (!nfct_synproxy_ext_add(ct
))
346 __set_bit(IPS_CONFIRMED_BIT
, &ct
->status
);
347 nf_conntrack_get(&ct
->ct_general
);
350 snet
->stats
= alloc_percpu(struct synproxy_stats
);
351 if (snet
->stats
== NULL
)
354 err
= synproxy_proc_init(net
);
361 free_percpu(snet
->stats
);
368 static void __net_exit
synproxy_net_exit(struct net
*net
)
370 struct synproxy_net
*snet
= synproxy_pernet(net
);
372 nf_ct_put(snet
->tmpl
);
373 synproxy_proc_exit(net
);
374 free_percpu(snet
->stats
);
377 static struct pernet_operations synproxy_net_ops
= {
378 .init
= synproxy_net_init
,
379 .exit
= synproxy_net_exit
,
380 .id
= &synproxy_net_id
,
381 .size
= sizeof(struct synproxy_net
),
384 static int __init
synproxy_core_init(void)
388 err
= nf_ct_extend_register(&nf_ct_synproxy_extend
);
392 err
= register_pernet_subsys(&synproxy_net_ops
);
399 nf_ct_extend_unregister(&nf_ct_synproxy_extend
);
404 static void __exit
synproxy_core_exit(void)
406 unregister_pernet_subsys(&synproxy_net_ops
);
407 nf_ct_extend_unregister(&nf_ct_synproxy_extend
);
410 module_init(synproxy_core_init
);
411 module_exit(synproxy_core_exit
);
413 static struct iphdr
*
414 synproxy_build_ip(struct net
*net
, struct sk_buff
*skb
, __be32 saddr
,
419 skb_reset_network_header(skb
);
420 iph
= skb_put(skb
, sizeof(*iph
));
422 iph
->ihl
= sizeof(*iph
) / 4;
425 iph
->frag_off
= htons(IP_DF
);
426 iph
->ttl
= net
->ipv4
.sysctl_ip_default_ttl
;
427 iph
->protocol
= IPPROTO_TCP
;
436 synproxy_send_tcp(struct net
*net
,
437 const struct sk_buff
*skb
, struct sk_buff
*nskb
,
438 struct nf_conntrack
*nfct
, enum ip_conntrack_info ctinfo
,
439 struct iphdr
*niph
, struct tcphdr
*nth
,
440 unsigned int tcp_hdr_size
)
442 nth
->check
= ~tcp_v4_check(tcp_hdr_size
, niph
->saddr
, niph
->daddr
, 0);
443 nskb
->ip_summed
= CHECKSUM_PARTIAL
;
444 nskb
->csum_start
= (unsigned char *)nth
- nskb
->head
;
445 nskb
->csum_offset
= offsetof(struct tcphdr
, check
);
447 skb_dst_set_noref(nskb
, skb_dst(skb
));
448 nskb
->protocol
= htons(ETH_P_IP
);
449 if (ip_route_me_harder(net
, nskb
->sk
, nskb
, RTN_UNSPEC
))
453 nf_ct_set(nskb
, (struct nf_conn
*)nfct
, ctinfo
);
454 nf_conntrack_get(nfct
);
457 ip_local_out(net
, nskb
->sk
, nskb
);
465 synproxy_send_client_synack(struct net
*net
,
466 const struct sk_buff
*skb
, const struct tcphdr
*th
,
467 const struct synproxy_options
*opts
)
469 struct sk_buff
*nskb
;
470 struct iphdr
*iph
, *niph
;
472 unsigned int tcp_hdr_size
;
473 u16 mss
= opts
->mss_encode
;
477 tcp_hdr_size
= sizeof(*nth
) + synproxy_options_size(opts
);
478 nskb
= alloc_skb(sizeof(*niph
) + tcp_hdr_size
+ MAX_TCP_HEADER
,
482 skb_reserve(nskb
, MAX_TCP_HEADER
);
484 niph
= synproxy_build_ip(net
, nskb
, iph
->daddr
, iph
->saddr
);
486 skb_reset_transport_header(nskb
);
487 nth
= skb_put(nskb
, tcp_hdr_size
);
488 nth
->source
= th
->dest
;
489 nth
->dest
= th
->source
;
490 nth
->seq
= htonl(__cookie_v4_init_sequence(iph
, th
, &mss
));
491 nth
->ack_seq
= htonl(ntohl(th
->seq
) + 1);
492 tcp_flag_word(nth
) = TCP_FLAG_SYN
| TCP_FLAG_ACK
;
493 if (opts
->options
& NF_SYNPROXY_OPT_ECN
)
494 tcp_flag_word(nth
) |= TCP_FLAG_ECE
;
495 nth
->doff
= tcp_hdr_size
/ 4;
500 synproxy_build_options(nth
, opts
);
502 synproxy_send_tcp(net
, skb
, nskb
, skb_nfct(skb
),
503 IP_CT_ESTABLISHED_REPLY
, niph
, nth
, tcp_hdr_size
);
505 EXPORT_SYMBOL_GPL(synproxy_send_client_synack
);
508 synproxy_send_server_syn(struct net
*net
,
509 const struct sk_buff
*skb
, const struct tcphdr
*th
,
510 const struct synproxy_options
*opts
, u32 recv_seq
)
512 struct synproxy_net
*snet
= synproxy_pernet(net
);
513 struct sk_buff
*nskb
;
514 struct iphdr
*iph
, *niph
;
516 unsigned int tcp_hdr_size
;
520 tcp_hdr_size
= sizeof(*nth
) + synproxy_options_size(opts
);
521 nskb
= alloc_skb(sizeof(*niph
) + tcp_hdr_size
+ MAX_TCP_HEADER
,
525 skb_reserve(nskb
, MAX_TCP_HEADER
);
527 niph
= synproxy_build_ip(net
, nskb
, iph
->saddr
, iph
->daddr
);
529 skb_reset_transport_header(nskb
);
530 nth
= skb_put(nskb
, tcp_hdr_size
);
531 nth
->source
= th
->source
;
532 nth
->dest
= th
->dest
;
533 nth
->seq
= htonl(recv_seq
- 1);
534 /* ack_seq is used to relay our ISN to the synproxy hook to initialize
535 * sequence number translation once a connection tracking entry exists.
537 nth
->ack_seq
= htonl(ntohl(th
->ack_seq
) - 1);
538 tcp_flag_word(nth
) = TCP_FLAG_SYN
;
539 if (opts
->options
& NF_SYNPROXY_OPT_ECN
)
540 tcp_flag_word(nth
) |= TCP_FLAG_ECE
| TCP_FLAG_CWR
;
541 nth
->doff
= tcp_hdr_size
/ 4;
542 nth
->window
= th
->window
;
546 synproxy_build_options(nth
, opts
);
548 synproxy_send_tcp(net
, skb
, nskb
, &snet
->tmpl
->ct_general
, IP_CT_NEW
,
549 niph
, nth
, tcp_hdr_size
);
553 synproxy_send_server_ack(struct net
*net
,
554 const struct ip_ct_tcp
*state
,
555 const struct sk_buff
*skb
, const struct tcphdr
*th
,
556 const struct synproxy_options
*opts
)
558 struct sk_buff
*nskb
;
559 struct iphdr
*iph
, *niph
;
561 unsigned int tcp_hdr_size
;
565 tcp_hdr_size
= sizeof(*nth
) + synproxy_options_size(opts
);
566 nskb
= alloc_skb(sizeof(*niph
) + tcp_hdr_size
+ MAX_TCP_HEADER
,
570 skb_reserve(nskb
, MAX_TCP_HEADER
);
572 niph
= synproxy_build_ip(net
, nskb
, iph
->daddr
, iph
->saddr
);
574 skb_reset_transport_header(nskb
);
575 nth
= skb_put(nskb
, tcp_hdr_size
);
576 nth
->source
= th
->dest
;
577 nth
->dest
= th
->source
;
578 nth
->seq
= htonl(ntohl(th
->ack_seq
));
579 nth
->ack_seq
= htonl(ntohl(th
->seq
) + 1);
580 tcp_flag_word(nth
) = TCP_FLAG_ACK
;
581 nth
->doff
= tcp_hdr_size
/ 4;
582 nth
->window
= htons(state
->seen
[IP_CT_DIR_ORIGINAL
].td_maxwin
);
586 synproxy_build_options(nth
, opts
);
588 synproxy_send_tcp(net
, skb
, nskb
, NULL
, 0, niph
, nth
, tcp_hdr_size
);
592 synproxy_send_client_ack(struct net
*net
,
593 const struct sk_buff
*skb
, const struct tcphdr
*th
,
594 const struct synproxy_options
*opts
)
596 struct sk_buff
*nskb
;
597 struct iphdr
*iph
, *niph
;
599 unsigned int tcp_hdr_size
;
603 tcp_hdr_size
= sizeof(*nth
) + synproxy_options_size(opts
);
604 nskb
= alloc_skb(sizeof(*niph
) + tcp_hdr_size
+ MAX_TCP_HEADER
,
608 skb_reserve(nskb
, MAX_TCP_HEADER
);
610 niph
= synproxy_build_ip(net
, nskb
, iph
->saddr
, iph
->daddr
);
612 skb_reset_transport_header(nskb
);
613 nth
= skb_put(nskb
, tcp_hdr_size
);
614 nth
->source
= th
->source
;
615 nth
->dest
= th
->dest
;
616 nth
->seq
= htonl(ntohl(th
->seq
) + 1);
617 nth
->ack_seq
= th
->ack_seq
;
618 tcp_flag_word(nth
) = TCP_FLAG_ACK
;
619 nth
->doff
= tcp_hdr_size
/ 4;
620 nth
->window
= htons(ntohs(th
->window
) >> opts
->wscale
);
624 synproxy_build_options(nth
, opts
);
626 synproxy_send_tcp(net
, skb
, nskb
, skb_nfct(skb
),
627 IP_CT_ESTABLISHED_REPLY
, niph
, nth
, tcp_hdr_size
);
631 synproxy_recv_client_ack(struct net
*net
,
632 const struct sk_buff
*skb
, const struct tcphdr
*th
,
633 struct synproxy_options
*opts
, u32 recv_seq
)
635 struct synproxy_net
*snet
= synproxy_pernet(net
);
638 mss
= __cookie_v4_check(ip_hdr(skb
), th
, ntohl(th
->ack_seq
) - 1);
640 this_cpu_inc(snet
->stats
->cookie_invalid
);
644 this_cpu_inc(snet
->stats
->cookie_valid
);
645 opts
->mss_option
= mss
;
646 opts
->options
|= NF_SYNPROXY_OPT_MSS
;
648 if (opts
->options
& NF_SYNPROXY_OPT_TIMESTAMP
)
649 synproxy_check_timestamp_cookie(opts
);
651 synproxy_send_server_syn(net
, skb
, th
, opts
, recv_seq
);
654 EXPORT_SYMBOL_GPL(synproxy_recv_client_ack
);
657 ipv4_synproxy_hook(void *priv
, struct sk_buff
*skb
,
658 const struct nf_hook_state
*nhs
)
660 struct net
*net
= nhs
->net
;
661 struct synproxy_net
*snet
= synproxy_pernet(net
);
662 enum ip_conntrack_info ctinfo
;
664 struct nf_conn_synproxy
*synproxy
;
665 struct synproxy_options opts
= {};
666 const struct ip_ct_tcp
*state
;
667 struct tcphdr
*th
, _th
;
670 ct
= nf_ct_get(skb
, &ctinfo
);
674 synproxy
= nfct_synproxy(ct
);
678 if (nf_is_loopback_packet(skb
) ||
679 ip_hdr(skb
)->protocol
!= IPPROTO_TCP
)
682 thoff
= ip_hdrlen(skb
);
683 th
= skb_header_pointer(skb
, thoff
, sizeof(_th
), &_th
);
687 state
= &ct
->proto
.tcp
;
688 switch (state
->state
) {
689 case TCP_CONNTRACK_CLOSE
:
690 if (th
->rst
&& CTINFO2DIR(ctinfo
) != IP_CT_DIR_ORIGINAL
) {
691 nf_ct_seqadj_init(ct
, ctinfo
, synproxy
->isn
-
696 if (!th
->syn
|| th
->ack
||
697 CTINFO2DIR(ctinfo
) != IP_CT_DIR_ORIGINAL
)
700 /* Reopened connection - reset the sequence number and timestamp
701 * adjustments, they will get initialized once the connection is
704 nf_ct_seqadj_init(ct
, ctinfo
, 0);
706 this_cpu_inc(snet
->stats
->conn_reopened
);
708 case TCP_CONNTRACK_SYN_SENT
:
709 if (!synproxy_parse_options(skb
, thoff
, th
, &opts
))
712 if (!th
->syn
&& th
->ack
&&
713 CTINFO2DIR(ctinfo
) == IP_CT_DIR_ORIGINAL
) {
714 /* Keep-Alives are sent with SEG.SEQ = SND.NXT-1,
715 * therefore we need to add 1 to make the SYN sequence
716 * number match the one of first SYN.
718 if (synproxy_recv_client_ack(net
, skb
, th
, &opts
,
719 ntohl(th
->seq
) + 1)) {
720 this_cpu_inc(snet
->stats
->cookie_retrans
);
728 synproxy
->isn
= ntohl(th
->ack_seq
);
729 if (opts
.options
& NF_SYNPROXY_OPT_TIMESTAMP
)
730 synproxy
->its
= opts
.tsecr
;
732 nf_conntrack_event_cache(IPCT_SYNPROXY
, ct
);
734 case TCP_CONNTRACK_SYN_RECV
:
735 if (!th
->syn
|| !th
->ack
)
738 if (!synproxy_parse_options(skb
, thoff
, th
, &opts
))
741 if (opts
.options
& NF_SYNPROXY_OPT_TIMESTAMP
) {
742 synproxy
->tsoff
= opts
.tsval
- synproxy
->its
;
743 nf_conntrack_event_cache(IPCT_SYNPROXY
, ct
);
746 opts
.options
&= ~(NF_SYNPROXY_OPT_MSS
|
747 NF_SYNPROXY_OPT_WSCALE
|
748 NF_SYNPROXY_OPT_SACK_PERM
);
750 swap(opts
.tsval
, opts
.tsecr
);
751 synproxy_send_server_ack(net
, state
, skb
, th
, &opts
);
753 nf_ct_seqadj_init(ct
, ctinfo
, synproxy
->isn
- ntohl(th
->seq
));
754 nf_conntrack_event_cache(IPCT_SEQADJ
, ct
);
756 swap(opts
.tsval
, opts
.tsecr
);
757 synproxy_send_client_ack(net
, skb
, th
, &opts
);
765 synproxy_tstamp_adjust(skb
, thoff
, th
, ct
, ctinfo
, synproxy
);
768 EXPORT_SYMBOL_GPL(ipv4_synproxy_hook
);
770 static const struct nf_hook_ops ipv4_synproxy_ops
[] = {
772 .hook
= ipv4_synproxy_hook
,
774 .hooknum
= NF_INET_LOCAL_IN
,
775 .priority
= NF_IP_PRI_CONNTRACK_CONFIRM
- 1,
778 .hook
= ipv4_synproxy_hook
,
780 .hooknum
= NF_INET_POST_ROUTING
,
781 .priority
= NF_IP_PRI_CONNTRACK_CONFIRM
- 1,
785 int nf_synproxy_ipv4_init(struct synproxy_net
*snet
, struct net
*net
)
789 if (snet
->hook_ref4
== 0) {
790 err
= nf_register_net_hooks(net
, ipv4_synproxy_ops
,
791 ARRAY_SIZE(ipv4_synproxy_ops
));
799 EXPORT_SYMBOL_GPL(nf_synproxy_ipv4_init
);
801 void nf_synproxy_ipv4_fini(struct synproxy_net
*snet
, struct net
*net
)
804 if (snet
->hook_ref4
== 0)
805 nf_unregister_net_hooks(net
, ipv4_synproxy_ops
,
806 ARRAY_SIZE(ipv4_synproxy_ops
));
808 EXPORT_SYMBOL_GPL(nf_synproxy_ipv4_fini
);
810 #if IS_ENABLED(CONFIG_IPV6)
811 static struct ipv6hdr
*
812 synproxy_build_ip_ipv6(struct net
*net
, struct sk_buff
*skb
,
813 const struct in6_addr
*saddr
,
814 const struct in6_addr
*daddr
)
818 skb_reset_network_header(skb
);
819 iph
= skb_put(skb
, sizeof(*iph
));
820 ip6_flow_hdr(iph
, 0, 0);
821 iph
->hop_limit
= net
->ipv6
.devconf_all
->hop_limit
;
822 iph
->nexthdr
= IPPROTO_TCP
;
830 synproxy_send_tcp_ipv6(struct net
*net
,
831 const struct sk_buff
*skb
, struct sk_buff
*nskb
,
832 struct nf_conntrack
*nfct
, enum ip_conntrack_info ctinfo
,
833 struct ipv6hdr
*niph
, struct tcphdr
*nth
,
834 unsigned int tcp_hdr_size
)
836 struct dst_entry
*dst
;
840 nth
->check
= ~tcp_v6_check(tcp_hdr_size
, &niph
->saddr
, &niph
->daddr
, 0);
841 nskb
->ip_summed
= CHECKSUM_PARTIAL
;
842 nskb
->csum_start
= (unsigned char *)nth
- nskb
->head
;
843 nskb
->csum_offset
= offsetof(struct tcphdr
, check
);
845 memset(&fl6
, 0, sizeof(fl6
));
846 fl6
.flowi6_proto
= IPPROTO_TCP
;
847 fl6
.saddr
= niph
->saddr
;
848 fl6
.daddr
= niph
->daddr
;
849 fl6
.fl6_sport
= nth
->source
;
850 fl6
.fl6_dport
= nth
->dest
;
851 security_skb_classify_flow((struct sk_buff
*)skb
,
852 flowi6_to_flowi_common(&fl6
));
853 err
= nf_ip6_route(net
, &dst
, flowi6_to_flowi(&fl6
), false);
858 dst
= xfrm_lookup(net
, dst
, flowi6_to_flowi(&fl6
), NULL
, 0);
862 skb_dst_set(nskb
, dst
);
865 nf_ct_set(nskb
, (struct nf_conn
*)nfct
, ctinfo
);
866 nf_conntrack_get(nfct
);
869 ip6_local_out(net
, nskb
->sk
, nskb
);
877 synproxy_send_client_synack_ipv6(struct net
*net
,
878 const struct sk_buff
*skb
,
879 const struct tcphdr
*th
,
880 const struct synproxy_options
*opts
)
882 struct sk_buff
*nskb
;
883 struct ipv6hdr
*iph
, *niph
;
885 unsigned int tcp_hdr_size
;
886 u16 mss
= opts
->mss_encode
;
890 tcp_hdr_size
= sizeof(*nth
) + synproxy_options_size(opts
);
891 nskb
= alloc_skb(sizeof(*niph
) + tcp_hdr_size
+ MAX_TCP_HEADER
,
895 skb_reserve(nskb
, MAX_TCP_HEADER
);
897 niph
= synproxy_build_ip_ipv6(net
, nskb
, &iph
->daddr
, &iph
->saddr
);
899 skb_reset_transport_header(nskb
);
900 nth
= skb_put(nskb
, tcp_hdr_size
);
901 nth
->source
= th
->dest
;
902 nth
->dest
= th
->source
;
903 nth
->seq
= htonl(nf_ipv6_cookie_init_sequence(iph
, th
, &mss
));
904 nth
->ack_seq
= htonl(ntohl(th
->seq
) + 1);
905 tcp_flag_word(nth
) = TCP_FLAG_SYN
| TCP_FLAG_ACK
;
906 if (opts
->options
& NF_SYNPROXY_OPT_ECN
)
907 tcp_flag_word(nth
) |= TCP_FLAG_ECE
;
908 nth
->doff
= tcp_hdr_size
/ 4;
913 synproxy_build_options(nth
, opts
);
915 synproxy_send_tcp_ipv6(net
, skb
, nskb
, skb_nfct(skb
),
916 IP_CT_ESTABLISHED_REPLY
, niph
, nth
,
919 EXPORT_SYMBOL_GPL(synproxy_send_client_synack_ipv6
);
922 synproxy_send_server_syn_ipv6(struct net
*net
, const struct sk_buff
*skb
,
923 const struct tcphdr
*th
,
924 const struct synproxy_options
*opts
, u32 recv_seq
)
926 struct synproxy_net
*snet
= synproxy_pernet(net
);
927 struct sk_buff
*nskb
;
928 struct ipv6hdr
*iph
, *niph
;
930 unsigned int tcp_hdr_size
;
934 tcp_hdr_size
= sizeof(*nth
) + synproxy_options_size(opts
);
935 nskb
= alloc_skb(sizeof(*niph
) + tcp_hdr_size
+ MAX_TCP_HEADER
,
939 skb_reserve(nskb
, MAX_TCP_HEADER
);
941 niph
= synproxy_build_ip_ipv6(net
, nskb
, &iph
->saddr
, &iph
->daddr
);
943 skb_reset_transport_header(nskb
);
944 nth
= skb_put(nskb
, tcp_hdr_size
);
945 nth
->source
= th
->source
;
946 nth
->dest
= th
->dest
;
947 nth
->seq
= htonl(recv_seq
- 1);
948 /* ack_seq is used to relay our ISN to the synproxy hook to initialize
949 * sequence number translation once a connection tracking entry exists.
951 nth
->ack_seq
= htonl(ntohl(th
->ack_seq
) - 1);
952 tcp_flag_word(nth
) = TCP_FLAG_SYN
;
953 if (opts
->options
& NF_SYNPROXY_OPT_ECN
)
954 tcp_flag_word(nth
) |= TCP_FLAG_ECE
| TCP_FLAG_CWR
;
955 nth
->doff
= tcp_hdr_size
/ 4;
956 nth
->window
= th
->window
;
960 synproxy_build_options(nth
, opts
);
962 synproxy_send_tcp_ipv6(net
, skb
, nskb
, &snet
->tmpl
->ct_general
,
963 IP_CT_NEW
, niph
, nth
, tcp_hdr_size
);
967 synproxy_send_server_ack_ipv6(struct net
*net
, const struct ip_ct_tcp
*state
,
968 const struct sk_buff
*skb
,
969 const struct tcphdr
*th
,
970 const struct synproxy_options
*opts
)
972 struct sk_buff
*nskb
;
973 struct ipv6hdr
*iph
, *niph
;
975 unsigned int tcp_hdr_size
;
979 tcp_hdr_size
= sizeof(*nth
) + synproxy_options_size(opts
);
980 nskb
= alloc_skb(sizeof(*niph
) + tcp_hdr_size
+ MAX_TCP_HEADER
,
984 skb_reserve(nskb
, MAX_TCP_HEADER
);
986 niph
= synproxy_build_ip_ipv6(net
, nskb
, &iph
->daddr
, &iph
->saddr
);
988 skb_reset_transport_header(nskb
);
989 nth
= skb_put(nskb
, tcp_hdr_size
);
990 nth
->source
= th
->dest
;
991 nth
->dest
= th
->source
;
992 nth
->seq
= htonl(ntohl(th
->ack_seq
));
993 nth
->ack_seq
= htonl(ntohl(th
->seq
) + 1);
994 tcp_flag_word(nth
) = TCP_FLAG_ACK
;
995 nth
->doff
= tcp_hdr_size
/ 4;
996 nth
->window
= htons(state
->seen
[IP_CT_DIR_ORIGINAL
].td_maxwin
);
1000 synproxy_build_options(nth
, opts
);
1002 synproxy_send_tcp_ipv6(net
, skb
, nskb
, NULL
, 0, niph
, nth
,
1007 synproxy_send_client_ack_ipv6(struct net
*net
, const struct sk_buff
*skb
,
1008 const struct tcphdr
*th
,
1009 const struct synproxy_options
*opts
)
1011 struct sk_buff
*nskb
;
1012 struct ipv6hdr
*iph
, *niph
;
1014 unsigned int tcp_hdr_size
;
1016 iph
= ipv6_hdr(skb
);
1018 tcp_hdr_size
= sizeof(*nth
) + synproxy_options_size(opts
);
1019 nskb
= alloc_skb(sizeof(*niph
) + tcp_hdr_size
+ MAX_TCP_HEADER
,
1023 skb_reserve(nskb
, MAX_TCP_HEADER
);
1025 niph
= synproxy_build_ip_ipv6(net
, nskb
, &iph
->saddr
, &iph
->daddr
);
1027 skb_reset_transport_header(nskb
);
1028 nth
= skb_put(nskb
, tcp_hdr_size
);
1029 nth
->source
= th
->source
;
1030 nth
->dest
= th
->dest
;
1031 nth
->seq
= htonl(ntohl(th
->seq
) + 1);
1032 nth
->ack_seq
= th
->ack_seq
;
1033 tcp_flag_word(nth
) = TCP_FLAG_ACK
;
1034 nth
->doff
= tcp_hdr_size
/ 4;
1035 nth
->window
= htons(ntohs(th
->window
) >> opts
->wscale
);
1039 synproxy_build_options(nth
, opts
);
1041 synproxy_send_tcp_ipv6(net
, skb
, nskb
, skb_nfct(skb
),
1042 IP_CT_ESTABLISHED_REPLY
, niph
, nth
,
1047 synproxy_recv_client_ack_ipv6(struct net
*net
,
1048 const struct sk_buff
*skb
,
1049 const struct tcphdr
*th
,
1050 struct synproxy_options
*opts
, u32 recv_seq
)
1052 struct synproxy_net
*snet
= synproxy_pernet(net
);
1055 mss
= nf_cookie_v6_check(ipv6_hdr(skb
), th
, ntohl(th
->ack_seq
) - 1);
1057 this_cpu_inc(snet
->stats
->cookie_invalid
);
1061 this_cpu_inc(snet
->stats
->cookie_valid
);
1062 opts
->mss_option
= mss
;
1063 opts
->options
|= NF_SYNPROXY_OPT_MSS
;
1065 if (opts
->options
& NF_SYNPROXY_OPT_TIMESTAMP
)
1066 synproxy_check_timestamp_cookie(opts
);
1068 synproxy_send_server_syn_ipv6(net
, skb
, th
, opts
, recv_seq
);
1071 EXPORT_SYMBOL_GPL(synproxy_recv_client_ack_ipv6
);
1074 ipv6_synproxy_hook(void *priv
, struct sk_buff
*skb
,
1075 const struct nf_hook_state
*nhs
)
1077 struct net
*net
= nhs
->net
;
1078 struct synproxy_net
*snet
= synproxy_pernet(net
);
1079 enum ip_conntrack_info ctinfo
;
1081 struct nf_conn_synproxy
*synproxy
;
1082 struct synproxy_options opts
= {};
1083 const struct ip_ct_tcp
*state
;
1084 struct tcphdr
*th
, _th
;
1089 ct
= nf_ct_get(skb
, &ctinfo
);
1093 synproxy
= nfct_synproxy(ct
);
1097 if (nf_is_loopback_packet(skb
))
1100 nexthdr
= ipv6_hdr(skb
)->nexthdr
;
1101 thoff
= ipv6_skip_exthdr(skb
, sizeof(struct ipv6hdr
), &nexthdr
,
1103 if (thoff
< 0 || nexthdr
!= IPPROTO_TCP
)
1106 th
= skb_header_pointer(skb
, thoff
, sizeof(_th
), &_th
);
1110 state
= &ct
->proto
.tcp
;
1111 switch (state
->state
) {
1112 case TCP_CONNTRACK_CLOSE
:
1113 if (th
->rst
&& CTINFO2DIR(ctinfo
) != IP_CT_DIR_ORIGINAL
) {
1114 nf_ct_seqadj_init(ct
, ctinfo
, synproxy
->isn
-
1115 ntohl(th
->seq
) + 1);
1119 if (!th
->syn
|| th
->ack
||
1120 CTINFO2DIR(ctinfo
) != IP_CT_DIR_ORIGINAL
)
1123 /* Reopened connection - reset the sequence number and timestamp
1124 * adjustments, they will get initialized once the connection is
1127 nf_ct_seqadj_init(ct
, ctinfo
, 0);
1128 synproxy
->tsoff
= 0;
1129 this_cpu_inc(snet
->stats
->conn_reopened
);
1131 case TCP_CONNTRACK_SYN_SENT
:
1132 if (!synproxy_parse_options(skb
, thoff
, th
, &opts
))
1135 if (!th
->syn
&& th
->ack
&&
1136 CTINFO2DIR(ctinfo
) == IP_CT_DIR_ORIGINAL
) {
1137 /* Keep-Alives are sent with SEG.SEQ = SND.NXT-1,
1138 * therefore we need to add 1 to make the SYN sequence
1139 * number match the one of first SYN.
1141 if (synproxy_recv_client_ack_ipv6(net
, skb
, th
, &opts
,
1142 ntohl(th
->seq
) + 1)) {
1143 this_cpu_inc(snet
->stats
->cookie_retrans
);
1151 synproxy
->isn
= ntohl(th
->ack_seq
);
1152 if (opts
.options
& NF_SYNPROXY_OPT_TIMESTAMP
)
1153 synproxy
->its
= opts
.tsecr
;
1155 nf_conntrack_event_cache(IPCT_SYNPROXY
, ct
);
1157 case TCP_CONNTRACK_SYN_RECV
:
1158 if (!th
->syn
|| !th
->ack
)
1161 if (!synproxy_parse_options(skb
, thoff
, th
, &opts
))
1164 if (opts
.options
& NF_SYNPROXY_OPT_TIMESTAMP
) {
1165 synproxy
->tsoff
= opts
.tsval
- synproxy
->its
;
1166 nf_conntrack_event_cache(IPCT_SYNPROXY
, ct
);
1169 opts
.options
&= ~(NF_SYNPROXY_OPT_MSS
|
1170 NF_SYNPROXY_OPT_WSCALE
|
1171 NF_SYNPROXY_OPT_SACK_PERM
);
1173 swap(opts
.tsval
, opts
.tsecr
);
1174 synproxy_send_server_ack_ipv6(net
, state
, skb
, th
, &opts
);
1176 nf_ct_seqadj_init(ct
, ctinfo
, synproxy
->isn
- ntohl(th
->seq
));
1177 nf_conntrack_event_cache(IPCT_SEQADJ
, ct
);
1179 swap(opts
.tsval
, opts
.tsecr
);
1180 synproxy_send_client_ack_ipv6(net
, skb
, th
, &opts
);
1188 synproxy_tstamp_adjust(skb
, thoff
, th
, ct
, ctinfo
, synproxy
);
1191 EXPORT_SYMBOL_GPL(ipv6_synproxy_hook
);
1193 static const struct nf_hook_ops ipv6_synproxy_ops
[] = {
1195 .hook
= ipv6_synproxy_hook
,
1197 .hooknum
= NF_INET_LOCAL_IN
,
1198 .priority
= NF_IP_PRI_CONNTRACK_CONFIRM
- 1,
1201 .hook
= ipv6_synproxy_hook
,
1203 .hooknum
= NF_INET_POST_ROUTING
,
1204 .priority
= NF_IP_PRI_CONNTRACK_CONFIRM
- 1,
1209 nf_synproxy_ipv6_init(struct synproxy_net
*snet
, struct net
*net
)
1213 if (snet
->hook_ref6
== 0) {
1214 err
= nf_register_net_hooks(net
, ipv6_synproxy_ops
,
1215 ARRAY_SIZE(ipv6_synproxy_ops
));
1223 EXPORT_SYMBOL_GPL(nf_synproxy_ipv6_init
);
1226 nf_synproxy_ipv6_fini(struct synproxy_net
*snet
, struct net
*net
)
1229 if (snet
->hook_ref6
== 0)
1230 nf_unregister_net_hooks(net
, ipv6_synproxy_ops
,
1231 ARRAY_SIZE(ipv6_synproxy_ops
));
1233 EXPORT_SYMBOL_GPL(nf_synproxy_ipv6_fini
);
1234 #endif /* CONFIG_IPV6 */
1236 MODULE_LICENSE("GPL");
1237 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
1238 MODULE_DESCRIPTION("nftables SYNPROXY expression support");