aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/netfilter/ipt_SYNPROXY.c394
-rw-r--r--net/ipv6/netfilter/ip6t_SYNPROXY.c420
-rw-r--r--net/netfilter/nf_synproxy_core.c896
3 files changed, 874 insertions, 836 deletions
diff --git a/net/ipv4/netfilter/ipt_SYNPROXY.c b/net/ipv4/netfilter/ipt_SYNPROXY.c
index 690b17ef6a44..7f7979734fb4 100644
--- a/net/ipv4/netfilter/ipt_SYNPROXY.c
+++ b/net/ipv4/netfilter/ipt_SYNPROXY.c
@@ -6,258 +6,11 @@
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8 8
9#include <linux/module.h>
10#include <linux/skbuff.h>
11#include <net/tcp.h>
12
13#include <linux/netfilter_ipv4/ip_tables.h> 9#include <linux/netfilter_ipv4/ip_tables.h>
14#include <linux/netfilter/x_tables.h> 10#include <linux/netfilter/x_tables.h>
15#include <linux/netfilter/xt_SYNPROXY.h> 11#include <linux/netfilter/xt_SYNPROXY.h>
16#include <net/netfilter/nf_conntrack.h>
17#include <net/netfilter/nf_conntrack_seqadj.h>
18#include <net/netfilter/nf_conntrack_synproxy.h>
19#include <net/netfilter/nf_conntrack_ecache.h>
20
21static struct iphdr *
22synproxy_build_ip(struct net *net, struct sk_buff *skb, __be32 saddr,
23 __be32 daddr)
24{
25 struct iphdr *iph;
26
27 skb_reset_network_header(skb);
28 iph = skb_put(skb, sizeof(*iph));
29 iph->version = 4;
30 iph->ihl = sizeof(*iph) / 4;
31 iph->tos = 0;
32 iph->id = 0;
33 iph->frag_off = htons(IP_DF);
34 iph->ttl = net->ipv4.sysctl_ip_default_ttl;
35 iph->protocol = IPPROTO_TCP;
36 iph->check = 0;
37 iph->saddr = saddr;
38 iph->daddr = daddr;
39
40 return iph;
41}
42
43static void
44synproxy_send_tcp(struct net *net,
45 const struct sk_buff *skb, struct sk_buff *nskb,
46 struct nf_conntrack *nfct, enum ip_conntrack_info ctinfo,
47 struct iphdr *niph, struct tcphdr *nth,
48 unsigned int tcp_hdr_size)
49{
50 nth->check = ~tcp_v4_check(tcp_hdr_size, niph->saddr, niph->daddr, 0);
51 nskb->ip_summed = CHECKSUM_PARTIAL;
52 nskb->csum_start = (unsigned char *)nth - nskb->head;
53 nskb->csum_offset = offsetof(struct tcphdr, check);
54
55 skb_dst_set_noref(nskb, skb_dst(skb));
56 nskb->protocol = htons(ETH_P_IP);
57 if (ip_route_me_harder(net, nskb, RTN_UNSPEC))
58 goto free_nskb;
59
60 if (nfct) {
61 nf_ct_set(nskb, (struct nf_conn *)nfct, ctinfo);
62 nf_conntrack_get(nfct);
63 }
64
65 ip_local_out(net, nskb->sk, nskb);
66 return;
67
68free_nskb:
69 kfree_skb(nskb);
70}
71
72static void
73synproxy_send_client_synack(struct net *net,
74 const struct sk_buff *skb, const struct tcphdr *th,
75 const struct synproxy_options *opts)
76{
77 struct sk_buff *nskb;
78 struct iphdr *iph, *niph;
79 struct tcphdr *nth;
80 unsigned int tcp_hdr_size;
81 u16 mss = opts->mss;
82
83 iph = ip_hdr(skb);
84
85 tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
86 nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
87 GFP_ATOMIC);
88 if (nskb == NULL)
89 return;
90 skb_reserve(nskb, MAX_TCP_HEADER);
91
92 niph = synproxy_build_ip(net, nskb, iph->daddr, iph->saddr);
93
94 skb_reset_transport_header(nskb);
95 nth = skb_put(nskb, tcp_hdr_size);
96 nth->source = th->dest;
97 nth->dest = th->source;
98 nth->seq = htonl(__cookie_v4_init_sequence(iph, th, &mss));
99 nth->ack_seq = htonl(ntohl(th->seq) + 1);
100 tcp_flag_word(nth) = TCP_FLAG_SYN | TCP_FLAG_ACK;
101 if (opts->options & XT_SYNPROXY_OPT_ECN)
102 tcp_flag_word(nth) |= TCP_FLAG_ECE;
103 nth->doff = tcp_hdr_size / 4;
104 nth->window = 0;
105 nth->check = 0;
106 nth->urg_ptr = 0;
107
108 synproxy_build_options(nth, opts);
109
110 synproxy_send_tcp(net, skb, nskb, skb_nfct(skb),
111 IP_CT_ESTABLISHED_REPLY, niph, nth, tcp_hdr_size);
112}
113
114static void
115synproxy_send_server_syn(struct net *net,
116 const struct sk_buff *skb, const struct tcphdr *th,
117 const struct synproxy_options *opts, u32 recv_seq)
118{
119 struct synproxy_net *snet = synproxy_pernet(net);
120 struct sk_buff *nskb;
121 struct iphdr *iph, *niph;
122 struct tcphdr *nth;
123 unsigned int tcp_hdr_size;
124
125 iph = ip_hdr(skb);
126
127 tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
128 nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
129 GFP_ATOMIC);
130 if (nskb == NULL)
131 return;
132 skb_reserve(nskb, MAX_TCP_HEADER);
133
134 niph = synproxy_build_ip(net, nskb, iph->saddr, iph->daddr);
135
136 skb_reset_transport_header(nskb);
137 nth = skb_put(nskb, tcp_hdr_size);
138 nth->source = th->source;
139 nth->dest = th->dest;
140 nth->seq = htonl(recv_seq - 1);
141 /* ack_seq is used to relay our ISN to the synproxy hook to initialize
142 * sequence number translation once a connection tracking entry exists.
143 */
144 nth->ack_seq = htonl(ntohl(th->ack_seq) - 1);
145 tcp_flag_word(nth) = TCP_FLAG_SYN;
146 if (opts->options & XT_SYNPROXY_OPT_ECN)
147 tcp_flag_word(nth) |= TCP_FLAG_ECE | TCP_FLAG_CWR;
148 nth->doff = tcp_hdr_size / 4;
149 nth->window = th->window;
150 nth->check = 0;
151 nth->urg_ptr = 0;
152
153 synproxy_build_options(nth, opts);
154
155 synproxy_send_tcp(net, skb, nskb, &snet->tmpl->ct_general, IP_CT_NEW,
156 niph, nth, tcp_hdr_size);
157}
158
159static void
160synproxy_send_server_ack(struct net *net,
161 const struct ip_ct_tcp *state,
162 const struct sk_buff *skb, const struct tcphdr *th,
163 const struct synproxy_options *opts)
164{
165 struct sk_buff *nskb;
166 struct iphdr *iph, *niph;
167 struct tcphdr *nth;
168 unsigned int tcp_hdr_size;
169
170 iph = ip_hdr(skb);
171
172 tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
173 nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
174 GFP_ATOMIC);
175 if (nskb == NULL)
176 return;
177 skb_reserve(nskb, MAX_TCP_HEADER);
178
179 niph = synproxy_build_ip(net, nskb, iph->daddr, iph->saddr);
180 12
181 skb_reset_transport_header(nskb); 13#include <net/netfilter/nf_synproxy.h>
182 nth = skb_put(nskb, tcp_hdr_size);
183 nth->source = th->dest;
184 nth->dest = th->source;
185 nth->seq = htonl(ntohl(th->ack_seq));
186 nth->ack_seq = htonl(ntohl(th->seq) + 1);
187 tcp_flag_word(nth) = TCP_FLAG_ACK;
188 nth->doff = tcp_hdr_size / 4;
189 nth->window = htons(state->seen[IP_CT_DIR_ORIGINAL].td_maxwin);
190 nth->check = 0;
191 nth->urg_ptr = 0;
192
193 synproxy_build_options(nth, opts);
194
195 synproxy_send_tcp(net, skb, nskb, NULL, 0, niph, nth, tcp_hdr_size);
196}
197
198static void
199synproxy_send_client_ack(struct net *net,
200 const struct sk_buff *skb, const struct tcphdr *th,
201 const struct synproxy_options *opts)
202{
203 struct sk_buff *nskb;
204 struct iphdr *iph, *niph;
205 struct tcphdr *nth;
206 unsigned int tcp_hdr_size;
207
208 iph = ip_hdr(skb);
209
210 tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
211 nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
212 GFP_ATOMIC);
213 if (nskb == NULL)
214 return;
215 skb_reserve(nskb, MAX_TCP_HEADER);
216
217 niph = synproxy_build_ip(net, nskb, iph->saddr, iph->daddr);
218
219 skb_reset_transport_header(nskb);
220 nth = skb_put(nskb, tcp_hdr_size);
221 nth->source = th->source;
222 nth->dest = th->dest;
223 nth->seq = htonl(ntohl(th->seq) + 1);
224 nth->ack_seq = th->ack_seq;
225 tcp_flag_word(nth) = TCP_FLAG_ACK;
226 nth->doff = tcp_hdr_size / 4;
227 nth->window = htons(ntohs(th->window) >> opts->wscale);
228 nth->check = 0;
229 nth->urg_ptr = 0;
230
231 synproxy_build_options(nth, opts);
232
233 synproxy_send_tcp(net, skb, nskb, skb_nfct(skb),
234 IP_CT_ESTABLISHED_REPLY, niph, nth, tcp_hdr_size);
235}
236
237static bool
238synproxy_recv_client_ack(struct net *net,
239 const struct sk_buff *skb, const struct tcphdr *th,
240 struct synproxy_options *opts, u32 recv_seq)
241{
242 struct synproxy_net *snet = synproxy_pernet(net);
243 int mss;
244
245 mss = __cookie_v4_check(ip_hdr(skb), th, ntohl(th->ack_seq) - 1);
246 if (mss == 0) {
247 this_cpu_inc(snet->stats->cookie_invalid);
248 return false;
249 }
250
251 this_cpu_inc(snet->stats->cookie_valid);
252 opts->mss = mss;
253 opts->options |= XT_SYNPROXY_OPT_MSS;
254
255 if (opts->options & XT_SYNPROXY_OPT_TIMESTAMP)
256 synproxy_check_timestamp_cookie(opts);
257
258 synproxy_send_server_syn(net, skb, th, opts, recv_seq);
259 return true;
260}
261 14
262static unsigned int 15static unsigned int
263synproxy_tg4(struct sk_buff *skb, const struct xt_action_param *par) 16synproxy_tg4(struct sk_buff *skb, const struct xt_action_param *par)
@@ -309,135 +62,6 @@ synproxy_tg4(struct sk_buff *skb, const struct xt_action_param *par)
309 return XT_CONTINUE; 62 return XT_CONTINUE;
310} 63}
311 64
312static unsigned int ipv4_synproxy_hook(void *priv,
313 struct sk_buff *skb,
314 const struct nf_hook_state *nhs)
315{
316 struct net *net = nhs->net;
317 struct synproxy_net *snet = synproxy_pernet(net);
318 enum ip_conntrack_info ctinfo;
319 struct nf_conn *ct;
320 struct nf_conn_synproxy *synproxy;
321 struct synproxy_options opts = {};
322 const struct ip_ct_tcp *state;
323 struct tcphdr *th, _th;
324 unsigned int thoff;
325
326 ct = nf_ct_get(skb, &ctinfo);
327 if (ct == NULL)
328 return NF_ACCEPT;
329
330 synproxy = nfct_synproxy(ct);
331 if (synproxy == NULL)
332 return NF_ACCEPT;
333
334 if (nf_is_loopback_packet(skb) ||
335 ip_hdr(skb)->protocol != IPPROTO_TCP)
336 return NF_ACCEPT;
337
338 thoff = ip_hdrlen(skb);
339 th = skb_header_pointer(skb, thoff, sizeof(_th), &_th);
340 if (th == NULL)
341 return NF_DROP;
342
343 state = &ct->proto.tcp;
344 switch (state->state) {
345 case TCP_CONNTRACK_CLOSE:
346 if (th->rst && !test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
347 nf_ct_seqadj_init(ct, ctinfo, synproxy->isn -
348 ntohl(th->seq) + 1);
349 break;
350 }
351
352 if (!th->syn || th->ack ||
353 CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)
354 break;
355
356 /* Reopened connection - reset the sequence number and timestamp
357 * adjustments, they will get initialized once the connection is
358 * reestablished.
359 */
360 nf_ct_seqadj_init(ct, ctinfo, 0);
361 synproxy->tsoff = 0;
362 this_cpu_inc(snet->stats->conn_reopened);
363
364 /* fall through */
365 case TCP_CONNTRACK_SYN_SENT:
366 if (!synproxy_parse_options(skb, thoff, th, &opts))
367 return NF_DROP;
368
369 if (!th->syn && th->ack &&
370 CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) {
371 /* Keep-Alives are sent with SEG.SEQ = SND.NXT-1,
372 * therefore we need to add 1 to make the SYN sequence
373 * number match the one of first SYN.
374 */
375 if (synproxy_recv_client_ack(net, skb, th, &opts,
376 ntohl(th->seq) + 1)) {
377 this_cpu_inc(snet->stats->cookie_retrans);
378 consume_skb(skb);
379 return NF_STOLEN;
380 } else {
381 return NF_DROP;
382 }
383 }
384
385 synproxy->isn = ntohl(th->ack_seq);
386 if (opts.options & XT_SYNPROXY_OPT_TIMESTAMP)
387 synproxy->its = opts.tsecr;
388
389 nf_conntrack_event_cache(IPCT_SYNPROXY, ct);
390 break;
391 case TCP_CONNTRACK_SYN_RECV:
392 if (!th->syn || !th->ack)
393 break;
394
395 if (!synproxy_parse_options(skb, thoff, th, &opts))
396 return NF_DROP;
397
398 if (opts.options & XT_SYNPROXY_OPT_TIMESTAMP) {
399 synproxy->tsoff = opts.tsval - synproxy->its;
400 nf_conntrack_event_cache(IPCT_SYNPROXY, ct);
401 }
402
403 opts.options &= ~(XT_SYNPROXY_OPT_MSS |
404 XT_SYNPROXY_OPT_WSCALE |
405 XT_SYNPROXY_OPT_SACK_PERM);
406
407 swap(opts.tsval, opts.tsecr);
408 synproxy_send_server_ack(net, state, skb, th, &opts);
409
410 nf_ct_seqadj_init(ct, ctinfo, synproxy->isn - ntohl(th->seq));
411 nf_conntrack_event_cache(IPCT_SEQADJ, ct);
412
413 swap(opts.tsval, opts.tsecr);
414 synproxy_send_client_ack(net, skb, th, &opts);
415
416 consume_skb(skb);
417 return NF_STOLEN;
418 default:
419 break;
420 }
421
422 synproxy_tstamp_adjust(skb, thoff, th, ct, ctinfo, synproxy);
423 return NF_ACCEPT;
424}
425
426static const struct nf_hook_ops ipv4_synproxy_ops[] = {
427 {
428 .hook = ipv4_synproxy_hook,
429 .pf = NFPROTO_IPV4,
430 .hooknum = NF_INET_LOCAL_IN,
431 .priority = NF_IP_PRI_CONNTRACK_CONFIRM - 1,
432 },
433 {
434 .hook = ipv4_synproxy_hook,
435 .pf = NFPROTO_IPV4,
436 .hooknum = NF_INET_POST_ROUTING,
437 .priority = NF_IP_PRI_CONNTRACK_CONFIRM - 1,
438 },
439};
440
441static int synproxy_tg4_check(const struct xt_tgchk_param *par) 65static int synproxy_tg4_check(const struct xt_tgchk_param *par)
442{ 66{
443 struct synproxy_net *snet = synproxy_pernet(par->net); 67 struct synproxy_net *snet = synproxy_pernet(par->net);
@@ -452,13 +76,10 @@ static int synproxy_tg4_check(const struct xt_tgchk_param *par)
452 if (err) 76 if (err)
453 return err; 77 return err;
454 78
455 if (snet->hook_ref4 == 0) { 79 err = nf_synproxy_ipv4_init(snet, par->net);
456 err = nf_register_net_hooks(par->net, ipv4_synproxy_ops, 80 if (err) {
457 ARRAY_SIZE(ipv4_synproxy_ops)); 81 nf_ct_netns_put(par->net, par->family);
458 if (err) { 82 return err;
459 nf_ct_netns_put(par->net, par->family);
460 return err;
461 }
462 } 83 }
463 84
464 snet->hook_ref4++; 85 snet->hook_ref4++;
@@ -469,10 +90,7 @@ static void synproxy_tg4_destroy(const struct xt_tgdtor_param *par)
469{ 90{
470 struct synproxy_net *snet = synproxy_pernet(par->net); 91 struct synproxy_net *snet = synproxy_pernet(par->net);
471 92
472 snet->hook_ref4--; 93 nf_synproxy_ipv4_fini(snet, par->net);
473 if (snet->hook_ref4 == 0)
474 nf_unregister_net_hooks(par->net, ipv4_synproxy_ops,
475 ARRAY_SIZE(ipv4_synproxy_ops));
476 nf_ct_netns_put(par->net, par->family); 94 nf_ct_netns_put(par->net, par->family);
477} 95}
478 96
diff --git a/net/ipv6/netfilter/ip6t_SYNPROXY.c b/net/ipv6/netfilter/ip6t_SYNPROXY.c
index cb6d42b03cb5..55a9b92d0a1f 100644
--- a/net/ipv6/netfilter/ip6t_SYNPROXY.c
+++ b/net/ipv6/netfilter/ip6t_SYNPROXY.c
@@ -6,272 +6,11 @@
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8 8
9#include <linux/module.h>
10#include <linux/skbuff.h>
11#include <net/ip6_checksum.h>
12#include <net/ip6_route.h>
13#include <net/tcp.h>
14
15#include <linux/netfilter_ipv6/ip6_tables.h> 9#include <linux/netfilter_ipv6/ip6_tables.h>
16#include <linux/netfilter/x_tables.h> 10#include <linux/netfilter/x_tables.h>
17#include <linux/netfilter/xt_SYNPROXY.h> 11#include <linux/netfilter/xt_SYNPROXY.h>
18#include <net/netfilter/nf_conntrack.h>
19#include <net/netfilter/nf_conntrack_seqadj.h>
20#include <net/netfilter/nf_conntrack_synproxy.h>
21#include <net/netfilter/nf_conntrack_ecache.h>
22
23static struct ipv6hdr *
24synproxy_build_ip(struct net *net, struct sk_buff *skb,
25 const struct in6_addr *saddr,
26 const struct in6_addr *daddr)
27{
28 struct ipv6hdr *iph;
29
30 skb_reset_network_header(skb);
31 iph = skb_put(skb, sizeof(*iph));
32 ip6_flow_hdr(iph, 0, 0);
33 iph->hop_limit = net->ipv6.devconf_all->hop_limit;
34 iph->nexthdr = IPPROTO_TCP;
35 iph->saddr = *saddr;
36 iph->daddr = *daddr;
37
38 return iph;
39}
40
41static void
42synproxy_send_tcp(struct net *net,
43 const struct sk_buff *skb, struct sk_buff *nskb,
44 struct nf_conntrack *nfct, enum ip_conntrack_info ctinfo,
45 struct ipv6hdr *niph, struct tcphdr *nth,
46 unsigned int tcp_hdr_size)
47{
48 struct dst_entry *dst;
49 struct flowi6 fl6;
50
51 nth->check = ~tcp_v6_check(tcp_hdr_size, &niph->saddr, &niph->daddr, 0);
52 nskb->ip_summed = CHECKSUM_PARTIAL;
53 nskb->csum_start = (unsigned char *)nth - nskb->head;
54 nskb->csum_offset = offsetof(struct tcphdr, check);
55
56 memset(&fl6, 0, sizeof(fl6));
57 fl6.flowi6_proto = IPPROTO_TCP;
58 fl6.saddr = niph->saddr;
59 fl6.daddr = niph->daddr;
60 fl6.fl6_sport = nth->source;
61 fl6.fl6_dport = nth->dest;
62 security_skb_classify_flow((struct sk_buff *)skb, flowi6_to_flowi(&fl6));
63 dst = ip6_route_output(net, NULL, &fl6);
64 if (dst->error) {
65 dst_release(dst);
66 goto free_nskb;
67 }
68 dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
69 if (IS_ERR(dst))
70 goto free_nskb;
71
72 skb_dst_set(nskb, dst);
73
74 if (nfct) {
75 nf_ct_set(nskb, (struct nf_conn *)nfct, ctinfo);
76 nf_conntrack_get(nfct);
77 }
78
79 ip6_local_out(net, nskb->sk, nskb);
80 return;
81
82free_nskb:
83 kfree_skb(nskb);
84}
85
86static void
87synproxy_send_client_synack(struct net *net,
88 const struct sk_buff *skb, const struct tcphdr *th,
89 const struct synproxy_options *opts)
90{
91 struct sk_buff *nskb;
92 struct ipv6hdr *iph, *niph;
93 struct tcphdr *nth;
94 unsigned int tcp_hdr_size;
95 u16 mss = opts->mss;
96
97 iph = ipv6_hdr(skb);
98
99 tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
100 nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
101 GFP_ATOMIC);
102 if (nskb == NULL)
103 return;
104 skb_reserve(nskb, MAX_TCP_HEADER);
105
106 niph = synproxy_build_ip(net, nskb, &iph->daddr, &iph->saddr);
107
108 skb_reset_transport_header(nskb);
109 nth = skb_put(nskb, tcp_hdr_size);
110 nth->source = th->dest;
111 nth->dest = th->source;
112 nth->seq = htonl(__cookie_v6_init_sequence(iph, th, &mss));
113 nth->ack_seq = htonl(ntohl(th->seq) + 1);
114 tcp_flag_word(nth) = TCP_FLAG_SYN | TCP_FLAG_ACK;
115 if (opts->options & XT_SYNPROXY_OPT_ECN)
116 tcp_flag_word(nth) |= TCP_FLAG_ECE;
117 nth->doff = tcp_hdr_size / 4;
118 nth->window = 0;
119 nth->check = 0;
120 nth->urg_ptr = 0;
121
122 synproxy_build_options(nth, opts);
123
124 synproxy_send_tcp(net, skb, nskb, skb_nfct(skb),
125 IP_CT_ESTABLISHED_REPLY, niph, nth, tcp_hdr_size);
126}
127 12
128static void 13#include <net/netfilter/nf_synproxy.h>
129synproxy_send_server_syn(struct net *net,
130 const struct sk_buff *skb, const struct tcphdr *th,
131 const struct synproxy_options *opts, u32 recv_seq)
132{
133 struct synproxy_net *snet = synproxy_pernet(net);
134 struct sk_buff *nskb;
135 struct ipv6hdr *iph, *niph;
136 struct tcphdr *nth;
137 unsigned int tcp_hdr_size;
138
139 iph = ipv6_hdr(skb);
140
141 tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
142 nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
143 GFP_ATOMIC);
144 if (nskb == NULL)
145 return;
146 skb_reserve(nskb, MAX_TCP_HEADER);
147
148 niph = synproxy_build_ip(net, nskb, &iph->saddr, &iph->daddr);
149
150 skb_reset_transport_header(nskb);
151 nth = skb_put(nskb, tcp_hdr_size);
152 nth->source = th->source;
153 nth->dest = th->dest;
154 nth->seq = htonl(recv_seq - 1);
155 /* ack_seq is used to relay our ISN to the synproxy hook to initialize
156 * sequence number translation once a connection tracking entry exists.
157 */
158 nth->ack_seq = htonl(ntohl(th->ack_seq) - 1);
159 tcp_flag_word(nth) = TCP_FLAG_SYN;
160 if (opts->options & XT_SYNPROXY_OPT_ECN)
161 tcp_flag_word(nth) |= TCP_FLAG_ECE | TCP_FLAG_CWR;
162 nth->doff = tcp_hdr_size / 4;
163 nth->window = th->window;
164 nth->check = 0;
165 nth->urg_ptr = 0;
166
167 synproxy_build_options(nth, opts);
168
169 synproxy_send_tcp(net, skb, nskb, &snet->tmpl->ct_general, IP_CT_NEW,
170 niph, nth, tcp_hdr_size);
171}
172
173static void
174synproxy_send_server_ack(struct net *net,
175 const struct ip_ct_tcp *state,
176 const struct sk_buff *skb, const struct tcphdr *th,
177 const struct synproxy_options *opts)
178{
179 struct sk_buff *nskb;
180 struct ipv6hdr *iph, *niph;
181 struct tcphdr *nth;
182 unsigned int tcp_hdr_size;
183
184 iph = ipv6_hdr(skb);
185
186 tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
187 nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
188 GFP_ATOMIC);
189 if (nskb == NULL)
190 return;
191 skb_reserve(nskb, MAX_TCP_HEADER);
192
193 niph = synproxy_build_ip(net, nskb, &iph->daddr, &iph->saddr);
194
195 skb_reset_transport_header(nskb);
196 nth = skb_put(nskb, tcp_hdr_size);
197 nth->source = th->dest;
198 nth->dest = th->source;
199 nth->seq = htonl(ntohl(th->ack_seq));
200 nth->ack_seq = htonl(ntohl(th->seq) + 1);
201 tcp_flag_word(nth) = TCP_FLAG_ACK;
202 nth->doff = tcp_hdr_size / 4;
203 nth->window = htons(state->seen[IP_CT_DIR_ORIGINAL].td_maxwin);
204 nth->check = 0;
205 nth->urg_ptr = 0;
206
207 synproxy_build_options(nth, opts);
208
209 synproxy_send_tcp(net, skb, nskb, NULL, 0, niph, nth, tcp_hdr_size);
210}
211
212static void
213synproxy_send_client_ack(struct net *net,
214 const struct sk_buff *skb, const struct tcphdr *th,
215 const struct synproxy_options *opts)
216{
217 struct sk_buff *nskb;
218 struct ipv6hdr *iph, *niph;
219 struct tcphdr *nth;
220 unsigned int tcp_hdr_size;
221
222 iph = ipv6_hdr(skb);
223
224 tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
225 nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
226 GFP_ATOMIC);
227 if (nskb == NULL)
228 return;
229 skb_reserve(nskb, MAX_TCP_HEADER);
230
231 niph = synproxy_build_ip(net, nskb, &iph->saddr, &iph->daddr);
232
233 skb_reset_transport_header(nskb);
234 nth = skb_put(nskb, tcp_hdr_size);
235 nth->source = th->source;
236 nth->dest = th->dest;
237 nth->seq = htonl(ntohl(th->seq) + 1);
238 nth->ack_seq = th->ack_seq;
239 tcp_flag_word(nth) = TCP_FLAG_ACK;
240 nth->doff = tcp_hdr_size / 4;
241 nth->window = htons(ntohs(th->window) >> opts->wscale);
242 nth->check = 0;
243 nth->urg_ptr = 0;
244
245 synproxy_build_options(nth, opts);
246
247 synproxy_send_tcp(net, skb, nskb, skb_nfct(skb),
248 IP_CT_ESTABLISHED_REPLY, niph, nth, tcp_hdr_size);
249}
250
251static bool
252synproxy_recv_client_ack(struct net *net,
253 const struct sk_buff *skb, const struct tcphdr *th,
254 struct synproxy_options *opts, u32 recv_seq)
255{
256 struct synproxy_net *snet = synproxy_pernet(net);
257 int mss;
258
259 mss = __cookie_v6_check(ipv6_hdr(skb), th, ntohl(th->ack_seq) - 1);
260 if (mss == 0) {
261 this_cpu_inc(snet->stats->cookie_invalid);
262 return false;
263 }
264
265 this_cpu_inc(snet->stats->cookie_valid);
266 opts->mss = mss;
267 opts->options |= XT_SYNPROXY_OPT_MSS;
268
269 if (opts->options & XT_SYNPROXY_OPT_TIMESTAMP)
270 synproxy_check_timestamp_cookie(opts);
271
272 synproxy_send_server_syn(net, skb, th, opts, recv_seq);
273 return true;
274}
275 14
276static unsigned int 15static unsigned int
277synproxy_tg6(struct sk_buff *skb, const struct xt_action_param *par) 16synproxy_tg6(struct sk_buff *skb, const struct xt_action_param *par)
@@ -307,13 +46,14 @@ synproxy_tg6(struct sk_buff *skb, const struct xt_action_param *par)
307 XT_SYNPROXY_OPT_SACK_PERM | 46 XT_SYNPROXY_OPT_SACK_PERM |
308 XT_SYNPROXY_OPT_ECN); 47 XT_SYNPROXY_OPT_ECN);
309 48
310 synproxy_send_client_synack(net, skb, th, &opts); 49 synproxy_send_client_synack_ipv6(net, skb, th, &opts);
311 consume_skb(skb); 50 consume_skb(skb);
312 return NF_STOLEN; 51 return NF_STOLEN;
313 52
314 } else if (th->ack && !(th->fin || th->rst || th->syn)) { 53 } else if (th->ack && !(th->fin || th->rst || th->syn)) {
315 /* ACK from client */ 54 /* ACK from client */
316 if (synproxy_recv_client_ack(net, skb, th, &opts, ntohl(th->seq))) { 55 if (synproxy_recv_client_ack_ipv6(net, skb, th, &opts,
56 ntohl(th->seq))) {
317 consume_skb(skb); 57 consume_skb(skb);
318 return NF_STOLEN; 58 return NF_STOLEN;
319 } else { 59 } else {
@@ -324,141 +64,6 @@ synproxy_tg6(struct sk_buff *skb, const struct xt_action_param *par)
324 return XT_CONTINUE; 64 return XT_CONTINUE;
325} 65}
326 66
327static unsigned int ipv6_synproxy_hook(void *priv,
328 struct sk_buff *skb,
329 const struct nf_hook_state *nhs)
330{
331 struct net *net = nhs->net;
332 struct synproxy_net *snet = synproxy_pernet(net);
333 enum ip_conntrack_info ctinfo;
334 struct nf_conn *ct;
335 struct nf_conn_synproxy *synproxy;
336 struct synproxy_options opts = {};
337 const struct ip_ct_tcp *state;
338 struct tcphdr *th, _th;
339 __be16 frag_off;
340 u8 nexthdr;
341 int thoff;
342
343 ct = nf_ct_get(skb, &ctinfo);
344 if (ct == NULL)
345 return NF_ACCEPT;
346
347 synproxy = nfct_synproxy(ct);
348 if (synproxy == NULL)
349 return NF_ACCEPT;
350
351 if (nf_is_loopback_packet(skb))
352 return NF_ACCEPT;
353
354 nexthdr = ipv6_hdr(skb)->nexthdr;
355 thoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr,
356 &frag_off);
357 if (thoff < 0 || nexthdr != IPPROTO_TCP)
358 return NF_ACCEPT;
359
360 th = skb_header_pointer(skb, thoff, sizeof(_th), &_th);
361 if (th == NULL)
362 return NF_DROP;
363
364 state = &ct->proto.tcp;
365 switch (state->state) {
366 case TCP_CONNTRACK_CLOSE:
367 if (th->rst && !test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
368 nf_ct_seqadj_init(ct, ctinfo, synproxy->isn -
369 ntohl(th->seq) + 1);
370 break;
371 }
372
373 if (!th->syn || th->ack ||
374 CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)
375 break;
376
377 /* Reopened connection - reset the sequence number and timestamp
378 * adjustments, they will get initialized once the connection is
379 * reestablished.
380 */
381 nf_ct_seqadj_init(ct, ctinfo, 0);
382 synproxy->tsoff = 0;
383 this_cpu_inc(snet->stats->conn_reopened);
384
385 /* fall through */
386 case TCP_CONNTRACK_SYN_SENT:
387 if (!synproxy_parse_options(skb, thoff, th, &opts))
388 return NF_DROP;
389
390 if (!th->syn && th->ack &&
391 CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) {
392 /* Keep-Alives are sent with SEG.SEQ = SND.NXT-1,
393 * therefore we need to add 1 to make the SYN sequence
394 * number match the one of first SYN.
395 */
396 if (synproxy_recv_client_ack(net, skb, th, &opts,
397 ntohl(th->seq) + 1)) {
398 this_cpu_inc(snet->stats->cookie_retrans);
399 consume_skb(skb);
400 return NF_STOLEN;
401 } else {
402 return NF_DROP;
403 }
404 }
405
406 synproxy->isn = ntohl(th->ack_seq);
407 if (opts.options & XT_SYNPROXY_OPT_TIMESTAMP)
408 synproxy->its = opts.tsecr;
409
410 nf_conntrack_event_cache(IPCT_SYNPROXY, ct);
411 break;
412 case TCP_CONNTRACK_SYN_RECV:
413 if (!th->syn || !th->ack)
414 break;
415
416 if (!synproxy_parse_options(skb, thoff, th, &opts))
417 return NF_DROP;
418
419 if (opts.options & XT_SYNPROXY_OPT_TIMESTAMP) {
420 synproxy->tsoff = opts.tsval - synproxy->its;
421 nf_conntrack_event_cache(IPCT_SYNPROXY, ct);
422 }
423
424 opts.options &= ~(XT_SYNPROXY_OPT_MSS |
425 XT_SYNPROXY_OPT_WSCALE |
426 XT_SYNPROXY_OPT_SACK_PERM);
427
428 swap(opts.tsval, opts.tsecr);
429 synproxy_send_server_ack(net, state, skb, th, &opts);
430
431 nf_ct_seqadj_init(ct, ctinfo, synproxy->isn - ntohl(th->seq));
432 nf_conntrack_event_cache(IPCT_SEQADJ, ct);
433
434 swap(opts.tsval, opts.tsecr);
435 synproxy_send_client_ack(net, skb, th, &opts);
436
437 consume_skb(skb);
438 return NF_STOLEN;
439 default:
440 break;
441 }
442
443 synproxy_tstamp_adjust(skb, thoff, th, ct, ctinfo, synproxy);
444 return NF_ACCEPT;
445}
446
447static const struct nf_hook_ops ipv6_synproxy_ops[] = {
448 {
449 .hook = ipv6_synproxy_hook,
450 .pf = NFPROTO_IPV6,
451 .hooknum = NF_INET_LOCAL_IN,
452 .priority = NF_IP_PRI_CONNTRACK_CONFIRM - 1,
453 },
454 {
455 .hook = ipv6_synproxy_hook,
456 .pf = NFPROTO_IPV6,
457 .hooknum = NF_INET_POST_ROUTING,
458 .priority = NF_IP_PRI_CONNTRACK_CONFIRM - 1,
459 },
460};
461
462static int synproxy_tg6_check(const struct xt_tgchk_param *par) 67static int synproxy_tg6_check(const struct xt_tgchk_param *par)
463{ 68{
464 struct synproxy_net *snet = synproxy_pernet(par->net); 69 struct synproxy_net *snet = synproxy_pernet(par->net);
@@ -474,16 +79,12 @@ static int synproxy_tg6_check(const struct xt_tgchk_param *par)
474 if (err) 79 if (err)
475 return err; 80 return err;
476 81
477 if (snet->hook_ref6 == 0) { 82 err = nf_synproxy_ipv6_init(snet, par->net);
478 err = nf_register_net_hooks(par->net, ipv6_synproxy_ops, 83 if (err) {
479 ARRAY_SIZE(ipv6_synproxy_ops)); 84 nf_ct_netns_put(par->net, par->family);
480 if (err) { 85 return err;
481 nf_ct_netns_put(par->net, par->family);
482 return err;
483 }
484 } 86 }
485 87
486 snet->hook_ref6++;
487 return err; 88 return err;
488} 89}
489 90
@@ -491,10 +92,7 @@ static void synproxy_tg6_destroy(const struct xt_tgdtor_param *par)
491{ 92{
492 struct synproxy_net *snet = synproxy_pernet(par->net); 93 struct synproxy_net *snet = synproxy_pernet(par->net);
493 94
494 snet->hook_ref6--; 95 nf_synproxy_ipv6_fini(snet, par->net);
495 if (snet->hook_ref6 == 0)
496 nf_unregister_net_hooks(par->net, ipv6_synproxy_ops,
497 ARRAY_SIZE(ipv6_synproxy_ops));
498 nf_ct_netns_put(par->net, par->family); 96 nf_ct_netns_put(par->net, par->family);
499} 97}
500 98
diff --git a/net/netfilter/nf_synproxy_core.c b/net/netfilter/nf_synproxy_core.c
index 3d58a9e93e5a..50677285f82e 100644
--- a/net/netfilter/nf_synproxy_core.c
+++ b/net/netfilter/nf_synproxy_core.c
@@ -13,16 +13,16 @@
13#include <net/netns/generic.h> 13#include <net/netns/generic.h>
14#include <linux/proc_fs.h> 14#include <linux/proc_fs.h>
15 15
16#include <linux/netfilter_ipv4/ip_tables.h> 16#include <linux/netfilter_ipv6.h>
17#include <linux/netfilter/x_tables.h> 17#include <linux/netfilter/nf_SYNPROXY.h>
18#include <linux/netfilter/xt_tcpudp.h>
19#include <linux/netfilter/xt_SYNPROXY.h>
20 18
21#include <net/netfilter/nf_conntrack.h> 19#include <net/netfilter/nf_conntrack.h>
20#include <net/netfilter/nf_conntrack_ecache.h>
22#include <net/netfilter/nf_conntrack_extend.h> 21#include <net/netfilter/nf_conntrack_extend.h>
23#include <net/netfilter/nf_conntrack_seqadj.h> 22#include <net/netfilter/nf_conntrack_seqadj.h>
24#include <net/netfilter/nf_conntrack_synproxy.h> 23#include <net/netfilter/nf_conntrack_synproxy.h>
25#include <net/netfilter/nf_conntrack_zones.h> 24#include <net/netfilter/nf_conntrack_zones.h>
25#include <net/netfilter/nf_synproxy.h>
26 26
27unsigned int synproxy_net_id; 27unsigned int synproxy_net_id;
28EXPORT_SYMBOL_GPL(synproxy_net_id); 28EXPORT_SYMBOL_GPL(synproxy_net_id);
@@ -60,7 +60,7 @@ synproxy_parse_options(const struct sk_buff *skb, unsigned int doff,
60 case TCPOPT_MSS: 60 case TCPOPT_MSS:
61 if (opsize == TCPOLEN_MSS) { 61 if (opsize == TCPOLEN_MSS) {
62 opts->mss = get_unaligned_be16(ptr); 62 opts->mss = get_unaligned_be16(ptr);
63 opts->options |= XT_SYNPROXY_OPT_MSS; 63 opts->options |= NF_SYNPROXY_OPT_MSS;
64 } 64 }
65 break; 65 break;
66 case TCPOPT_WINDOW: 66 case TCPOPT_WINDOW:
@@ -68,19 +68,19 @@ synproxy_parse_options(const struct sk_buff *skb, unsigned int doff,
68 opts->wscale = *ptr; 68 opts->wscale = *ptr;
69 if (opts->wscale > TCP_MAX_WSCALE) 69 if (opts->wscale > TCP_MAX_WSCALE)
70 opts->wscale = TCP_MAX_WSCALE; 70 opts->wscale = TCP_MAX_WSCALE;
71 opts->options |= XT_SYNPROXY_OPT_WSCALE; 71 opts->options |= NF_SYNPROXY_OPT_WSCALE;
72 } 72 }
73 break; 73 break;
74 case TCPOPT_TIMESTAMP: 74 case TCPOPT_TIMESTAMP:
75 if (opsize == TCPOLEN_TIMESTAMP) { 75 if (opsize == TCPOLEN_TIMESTAMP) {
76 opts->tsval = get_unaligned_be32(ptr); 76 opts->tsval = get_unaligned_be32(ptr);
77 opts->tsecr = get_unaligned_be32(ptr + 4); 77 opts->tsecr = get_unaligned_be32(ptr + 4);
78 opts->options |= XT_SYNPROXY_OPT_TIMESTAMP; 78 opts->options |= NF_SYNPROXY_OPT_TIMESTAMP;
79 } 79 }
80 break; 80 break;
81 case TCPOPT_SACK_PERM: 81 case TCPOPT_SACK_PERM:
82 if (opsize == TCPOLEN_SACK_PERM) 82 if (opsize == TCPOLEN_SACK_PERM)
83 opts->options |= XT_SYNPROXY_OPT_SACK_PERM; 83 opts->options |= NF_SYNPROXY_OPT_SACK_PERM;
84 break; 84 break;
85 } 85 }
86 86
@@ -92,36 +92,36 @@ synproxy_parse_options(const struct sk_buff *skb, unsigned int doff,
92} 92}
93EXPORT_SYMBOL_GPL(synproxy_parse_options); 93EXPORT_SYMBOL_GPL(synproxy_parse_options);
94 94
95unsigned int synproxy_options_size(const struct synproxy_options *opts) 95static unsigned int
96synproxy_options_size(const struct synproxy_options *opts)
96{ 97{
97 unsigned int size = 0; 98 unsigned int size = 0;
98 99
99 if (opts->options & XT_SYNPROXY_OPT_MSS) 100 if (opts->options & NF_SYNPROXY_OPT_MSS)
100 size += TCPOLEN_MSS_ALIGNED; 101 size += TCPOLEN_MSS_ALIGNED;
101 if (opts->options & XT_SYNPROXY_OPT_TIMESTAMP) 102 if (opts->options & NF_SYNPROXY_OPT_TIMESTAMP)
102 size += TCPOLEN_TSTAMP_ALIGNED; 103 size += TCPOLEN_TSTAMP_ALIGNED;
103 else if (opts->options & XT_SYNPROXY_OPT_SACK_PERM) 104 else if (opts->options & NF_SYNPROXY_OPT_SACK_PERM)
104 size += TCPOLEN_SACKPERM_ALIGNED; 105 size += TCPOLEN_SACKPERM_ALIGNED;
105 if (opts->options & XT_SYNPROXY_OPT_WSCALE) 106 if (opts->options & NF_SYNPROXY_OPT_WSCALE)
106 size += TCPOLEN_WSCALE_ALIGNED; 107 size += TCPOLEN_WSCALE_ALIGNED;
107 108
108 return size; 109 return size;
109} 110}
110EXPORT_SYMBOL_GPL(synproxy_options_size);
111 111
112void 112static void
113synproxy_build_options(struct tcphdr *th, const struct synproxy_options *opts) 113synproxy_build_options(struct tcphdr *th, const struct synproxy_options *opts)
114{ 114{
115 __be32 *ptr = (__be32 *)(th + 1); 115 __be32 *ptr = (__be32 *)(th + 1);
116 u8 options = opts->options; 116 u8 options = opts->options;
117 117
118 if (options & XT_SYNPROXY_OPT_MSS) 118 if (options & NF_SYNPROXY_OPT_MSS)
119 *ptr++ = htonl((TCPOPT_MSS << 24) | 119 *ptr++ = htonl((TCPOPT_MSS << 24) |
120 (TCPOLEN_MSS << 16) | 120 (TCPOLEN_MSS << 16) |
121 opts->mss); 121 opts->mss);
122 122
123 if (options & XT_SYNPROXY_OPT_TIMESTAMP) { 123 if (options & NF_SYNPROXY_OPT_TIMESTAMP) {
124 if (options & XT_SYNPROXY_OPT_SACK_PERM) 124 if (options & NF_SYNPROXY_OPT_SACK_PERM)
125 *ptr++ = htonl((TCPOPT_SACK_PERM << 24) | 125 *ptr++ = htonl((TCPOPT_SACK_PERM << 24) |
126 (TCPOLEN_SACK_PERM << 16) | 126 (TCPOLEN_SACK_PERM << 16) |
127 (TCPOPT_TIMESTAMP << 8) | 127 (TCPOPT_TIMESTAMP << 8) |
@@ -134,58 +134,56 @@ synproxy_build_options(struct tcphdr *th, const struct synproxy_options *opts)
134 134
135 *ptr++ = htonl(opts->tsval); 135 *ptr++ = htonl(opts->tsval);
136 *ptr++ = htonl(opts->tsecr); 136 *ptr++ = htonl(opts->tsecr);
137 } else if (options & XT_SYNPROXY_OPT_SACK_PERM) 137 } else if (options & NF_SYNPROXY_OPT_SACK_PERM)
138 *ptr++ = htonl((TCPOPT_NOP << 24) | 138 *ptr++ = htonl((TCPOPT_NOP << 24) |
139 (TCPOPT_NOP << 16) | 139 (TCPOPT_NOP << 16) |
140 (TCPOPT_SACK_PERM << 8) | 140 (TCPOPT_SACK_PERM << 8) |
141 TCPOLEN_SACK_PERM); 141 TCPOLEN_SACK_PERM);
142 142
143 if (options & XT_SYNPROXY_OPT_WSCALE) 143 if (options & NF_SYNPROXY_OPT_WSCALE)
144 *ptr++ = htonl((TCPOPT_NOP << 24) | 144 *ptr++ = htonl((TCPOPT_NOP << 24) |
145 (TCPOPT_WINDOW << 16) | 145 (TCPOPT_WINDOW << 16) |
146 (TCPOLEN_WINDOW << 8) | 146 (TCPOLEN_WINDOW << 8) |
147 opts->wscale); 147 opts->wscale);
148} 148}
149EXPORT_SYMBOL_GPL(synproxy_build_options);
150 149
151void synproxy_init_timestamp_cookie(const struct xt_synproxy_info *info, 150void synproxy_init_timestamp_cookie(const struct nf_synproxy_info *info,
152 struct synproxy_options *opts) 151 struct synproxy_options *opts)
153{ 152{
154 opts->tsecr = opts->tsval; 153 opts->tsecr = opts->tsval;
155 opts->tsval = tcp_time_stamp_raw() & ~0x3f; 154 opts->tsval = tcp_time_stamp_raw() & ~0x3f;
156 155
157 if (opts->options & XT_SYNPROXY_OPT_WSCALE) { 156 if (opts->options & NF_SYNPROXY_OPT_WSCALE) {
158 opts->tsval |= opts->wscale; 157 opts->tsval |= opts->wscale;
159 opts->wscale = info->wscale; 158 opts->wscale = info->wscale;
160 } else 159 } else
161 opts->tsval |= 0xf; 160 opts->tsval |= 0xf;
162 161
163 if (opts->options & XT_SYNPROXY_OPT_SACK_PERM) 162 if (opts->options & NF_SYNPROXY_OPT_SACK_PERM)
164 opts->tsval |= 1 << 4; 163 opts->tsval |= 1 << 4;
165 164
166 if (opts->options & XT_SYNPROXY_OPT_ECN) 165 if (opts->options & NF_SYNPROXY_OPT_ECN)
167 opts->tsval |= 1 << 5; 166 opts->tsval |= 1 << 5;
168} 167}
169EXPORT_SYMBOL_GPL(synproxy_init_timestamp_cookie); 168EXPORT_SYMBOL_GPL(synproxy_init_timestamp_cookie);
170 169
171void synproxy_check_timestamp_cookie(struct synproxy_options *opts) 170static void
171synproxy_check_timestamp_cookie(struct synproxy_options *opts)
172{ 172{
173 opts->wscale = opts->tsecr & 0xf; 173 opts->wscale = opts->tsecr & 0xf;
174 if (opts->wscale != 0xf) 174 if (opts->wscale != 0xf)
175 opts->options |= XT_SYNPROXY_OPT_WSCALE; 175 opts->options |= NF_SYNPROXY_OPT_WSCALE;
176 176
177 opts->options |= opts->tsecr & (1 << 4) ? XT_SYNPROXY_OPT_SACK_PERM : 0; 177 opts->options |= opts->tsecr & (1 << 4) ? NF_SYNPROXY_OPT_SACK_PERM : 0;
178 178
179 opts->options |= opts->tsecr & (1 << 5) ? XT_SYNPROXY_OPT_ECN : 0; 179 opts->options |= opts->tsecr & (1 << 5) ? NF_SYNPROXY_OPT_ECN : 0;
180} 180}
181EXPORT_SYMBOL_GPL(synproxy_check_timestamp_cookie);
182 181
183unsigned int synproxy_tstamp_adjust(struct sk_buff *skb, 182static unsigned int
184 unsigned int protoff, 183synproxy_tstamp_adjust(struct sk_buff *skb, unsigned int protoff,
185 struct tcphdr *th, 184 struct tcphdr *th, struct nf_conn *ct,
186 struct nf_conn *ct, 185 enum ip_conntrack_info ctinfo,
187 enum ip_conntrack_info ctinfo, 186 const struct nf_conn_synproxy *synproxy)
188 const struct nf_conn_synproxy *synproxy)
189{ 187{
190 unsigned int optoff, optend; 188 unsigned int optoff, optend;
191 __be32 *ptr, old; 189 __be32 *ptr, old;
@@ -235,7 +233,6 @@ unsigned int synproxy_tstamp_adjust(struct sk_buff *skb,
235 } 233 }
236 return 1; 234 return 1;
237} 235}
238EXPORT_SYMBOL_GPL(synproxy_tstamp_adjust);
239 236
240static struct nf_ct_ext_type nf_ct_synproxy_extend __read_mostly = { 237static struct nf_ct_ext_type nf_ct_synproxy_extend __read_mostly = {
241 .len = sizeof(struct nf_conn_synproxy), 238 .len = sizeof(struct nf_conn_synproxy),
@@ -416,5 +413,830 @@ static void __exit synproxy_core_exit(void)
416module_init(synproxy_core_init); 413module_init(synproxy_core_init);
417module_exit(synproxy_core_exit); 414module_exit(synproxy_core_exit);
418 415
416static struct iphdr *
417synproxy_build_ip(struct net *net, struct sk_buff *skb, __be32 saddr,
418 __be32 daddr)
419{
420 struct iphdr *iph;
421
422 skb_reset_network_header(skb);
423 iph = skb_put(skb, sizeof(*iph));
424 iph->version = 4;
425 iph->ihl = sizeof(*iph) / 4;
426 iph->tos = 0;
427 iph->id = 0;
428 iph->frag_off = htons(IP_DF);
429 iph->ttl = net->ipv4.sysctl_ip_default_ttl;
430 iph->protocol = IPPROTO_TCP;
431 iph->check = 0;
432 iph->saddr = saddr;
433 iph->daddr = daddr;
434
435 return iph;
436}
437
438static void
439synproxy_send_tcp(struct net *net,
440 const struct sk_buff *skb, struct sk_buff *nskb,
441 struct nf_conntrack *nfct, enum ip_conntrack_info ctinfo,
442 struct iphdr *niph, struct tcphdr *nth,
443 unsigned int tcp_hdr_size)
444{
445 nth->check = ~tcp_v4_check(tcp_hdr_size, niph->saddr, niph->daddr, 0);
446 nskb->ip_summed = CHECKSUM_PARTIAL;
447 nskb->csum_start = (unsigned char *)nth - nskb->head;
448 nskb->csum_offset = offsetof(struct tcphdr, check);
449
450 skb_dst_set_noref(nskb, skb_dst(skb));
451 nskb->protocol = htons(ETH_P_IP);
452 if (ip_route_me_harder(net, nskb, RTN_UNSPEC))
453 goto free_nskb;
454
455 if (nfct) {
456 nf_ct_set(nskb, (struct nf_conn *)nfct, ctinfo);
457 nf_conntrack_get(nfct);
458 }
459
460 ip_local_out(net, nskb->sk, nskb);
461 return;
462
463free_nskb:
464 kfree_skb(nskb);
465}
466
467void
468synproxy_send_client_synack(struct net *net,
469 const struct sk_buff *skb, const struct tcphdr *th,
470 const struct synproxy_options *opts)
471{
472 struct sk_buff *nskb;
473 struct iphdr *iph, *niph;
474 struct tcphdr *nth;
475 unsigned int tcp_hdr_size;
476 u16 mss = opts->mss;
477
478 iph = ip_hdr(skb);
479
480 tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
481 nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
482 GFP_ATOMIC);
483 if (!nskb)
484 return;
485 skb_reserve(nskb, MAX_TCP_HEADER);
486
487 niph = synproxy_build_ip(net, nskb, iph->daddr, iph->saddr);
488
489 skb_reset_transport_header(nskb);
490 nth = skb_put(nskb, tcp_hdr_size);
491 nth->source = th->dest;
492 nth->dest = th->source;
493 nth->seq = htonl(__cookie_v4_init_sequence(iph, th, &mss));
494 nth->ack_seq = htonl(ntohl(th->seq) + 1);
495 tcp_flag_word(nth) = TCP_FLAG_SYN | TCP_FLAG_ACK;
496 if (opts->options & NF_SYNPROXY_OPT_ECN)
497 tcp_flag_word(nth) |= TCP_FLAG_ECE;
498 nth->doff = tcp_hdr_size / 4;
499 nth->window = 0;
500 nth->check = 0;
501 nth->urg_ptr = 0;
502
503 synproxy_build_options(nth, opts);
504
505 synproxy_send_tcp(net, skb, nskb, skb_nfct(skb),
506 IP_CT_ESTABLISHED_REPLY, niph, nth, tcp_hdr_size);
507}
508EXPORT_SYMBOL_GPL(synproxy_send_client_synack);
509
510static void
511synproxy_send_server_syn(struct net *net,
512 const struct sk_buff *skb, const struct tcphdr *th,
513 const struct synproxy_options *opts, u32 recv_seq)
514{
515 struct synproxy_net *snet = synproxy_pernet(net);
516 struct sk_buff *nskb;
517 struct iphdr *iph, *niph;
518 struct tcphdr *nth;
519 unsigned int tcp_hdr_size;
520
521 iph = ip_hdr(skb);
522
523 tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
524 nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
525 GFP_ATOMIC);
526 if (!nskb)
527 return;
528 skb_reserve(nskb, MAX_TCP_HEADER);
529
530 niph = synproxy_build_ip(net, nskb, iph->saddr, iph->daddr);
531
532 skb_reset_transport_header(nskb);
533 nth = skb_put(nskb, tcp_hdr_size);
534 nth->source = th->source;
535 nth->dest = th->dest;
536 nth->seq = htonl(recv_seq - 1);
537 /* ack_seq is used to relay our ISN to the synproxy hook to initialize
538 * sequence number translation once a connection tracking entry exists.
539 */
540 nth->ack_seq = htonl(ntohl(th->ack_seq) - 1);
541 tcp_flag_word(nth) = TCP_FLAG_SYN;
542 if (opts->options & NF_SYNPROXY_OPT_ECN)
543 tcp_flag_word(nth) |= TCP_FLAG_ECE | TCP_FLAG_CWR;
544 nth->doff = tcp_hdr_size / 4;
545 nth->window = th->window;
546 nth->check = 0;
547 nth->urg_ptr = 0;
548
549 synproxy_build_options(nth, opts);
550
551 synproxy_send_tcp(net, skb, nskb, &snet->tmpl->ct_general, IP_CT_NEW,
552 niph, nth, tcp_hdr_size);
553}
554
555static void
556synproxy_send_server_ack(struct net *net,
557 const struct ip_ct_tcp *state,
558 const struct sk_buff *skb, const struct tcphdr *th,
559 const struct synproxy_options *opts)
560{
561 struct sk_buff *nskb;
562 struct iphdr *iph, *niph;
563 struct tcphdr *nth;
564 unsigned int tcp_hdr_size;
565
566 iph = ip_hdr(skb);
567
568 tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
569 nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
570 GFP_ATOMIC);
571 if (!nskb)
572 return;
573 skb_reserve(nskb, MAX_TCP_HEADER);
574
575 niph = synproxy_build_ip(net, nskb, iph->daddr, iph->saddr);
576
577 skb_reset_transport_header(nskb);
578 nth = skb_put(nskb, tcp_hdr_size);
579 nth->source = th->dest;
580 nth->dest = th->source;
581 nth->seq = htonl(ntohl(th->ack_seq));
582 nth->ack_seq = htonl(ntohl(th->seq) + 1);
583 tcp_flag_word(nth) = TCP_FLAG_ACK;
584 nth->doff = tcp_hdr_size / 4;
585 nth->window = htons(state->seen[IP_CT_DIR_ORIGINAL].td_maxwin);
586 nth->check = 0;
587 nth->urg_ptr = 0;
588
589 synproxy_build_options(nth, opts);
590
591 synproxy_send_tcp(net, skb, nskb, NULL, 0, niph, nth, tcp_hdr_size);
592}
593
594static void
595synproxy_send_client_ack(struct net *net,
596 const struct sk_buff *skb, const struct tcphdr *th,
597 const struct synproxy_options *opts)
598{
599 struct sk_buff *nskb;
600 struct iphdr *iph, *niph;
601 struct tcphdr *nth;
602 unsigned int tcp_hdr_size;
603
604 iph = ip_hdr(skb);
605
606 tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
607 nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
608 GFP_ATOMIC);
609 if (!nskb)
610 return;
611 skb_reserve(nskb, MAX_TCP_HEADER);
612
613 niph = synproxy_build_ip(net, nskb, iph->saddr, iph->daddr);
614
615 skb_reset_transport_header(nskb);
616 nth = skb_put(nskb, tcp_hdr_size);
617 nth->source = th->source;
618 nth->dest = th->dest;
619 nth->seq = htonl(ntohl(th->seq) + 1);
620 nth->ack_seq = th->ack_seq;
621 tcp_flag_word(nth) = TCP_FLAG_ACK;
622 nth->doff = tcp_hdr_size / 4;
623 nth->window = htons(ntohs(th->window) >> opts->wscale);
624 nth->check = 0;
625 nth->urg_ptr = 0;
626
627 synproxy_build_options(nth, opts);
628
629 synproxy_send_tcp(net, skb, nskb, skb_nfct(skb),
630 IP_CT_ESTABLISHED_REPLY, niph, nth, tcp_hdr_size);
631}
632
633bool
634synproxy_recv_client_ack(struct net *net,
635 const struct sk_buff *skb, const struct tcphdr *th,
636 struct synproxy_options *opts, u32 recv_seq)
637{
638 struct synproxy_net *snet = synproxy_pernet(net);
639 int mss;
640
641 mss = __cookie_v4_check(ip_hdr(skb), th, ntohl(th->ack_seq) - 1);
642 if (mss == 0) {
643 this_cpu_inc(snet->stats->cookie_invalid);
644 return false;
645 }
646
647 this_cpu_inc(snet->stats->cookie_valid);
648 opts->mss = mss;
649 opts->options |= NF_SYNPROXY_OPT_MSS;
650
651 if (opts->options & NF_SYNPROXY_OPT_TIMESTAMP)
652 synproxy_check_timestamp_cookie(opts);
653
654 synproxy_send_server_syn(net, skb, th, opts, recv_seq);
655 return true;
656}
657EXPORT_SYMBOL_GPL(synproxy_recv_client_ack);
658
659unsigned int
660ipv4_synproxy_hook(void *priv, struct sk_buff *skb,
661 const struct nf_hook_state *nhs)
662{
663 struct net *net = nhs->net;
664 struct synproxy_net *snet = synproxy_pernet(net);
665 enum ip_conntrack_info ctinfo;
666 struct nf_conn *ct;
667 struct nf_conn_synproxy *synproxy;
668 struct synproxy_options opts = {};
669 const struct ip_ct_tcp *state;
670 struct tcphdr *th, _th;
671 unsigned int thoff;
672
673 ct = nf_ct_get(skb, &ctinfo);
674 if (!ct)
675 return NF_ACCEPT;
676
677 synproxy = nfct_synproxy(ct);
678 if (!synproxy)
679 return NF_ACCEPT;
680
681 if (nf_is_loopback_packet(skb) ||
682 ip_hdr(skb)->protocol != IPPROTO_TCP)
683 return NF_ACCEPT;
684
685 thoff = ip_hdrlen(skb);
686 th = skb_header_pointer(skb, thoff, sizeof(_th), &_th);
687 if (!th)
688 return NF_DROP;
689
690 state = &ct->proto.tcp;
691 switch (state->state) {
692 case TCP_CONNTRACK_CLOSE:
693 if (th->rst && !test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
694 nf_ct_seqadj_init(ct, ctinfo, synproxy->isn -
695 ntohl(th->seq) + 1);
696 break;
697 }
698
699 if (!th->syn || th->ack ||
700 CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)
701 break;
702
703 /* Reopened connection - reset the sequence number and timestamp
704 * adjustments, they will get initialized once the connection is
705 * reestablished.
706 */
707 nf_ct_seqadj_init(ct, ctinfo, 0);
708 synproxy->tsoff = 0;
709 this_cpu_inc(snet->stats->conn_reopened);
710
711 /* fall through */
712 case TCP_CONNTRACK_SYN_SENT:
713 if (!synproxy_parse_options(skb, thoff, th, &opts))
714 return NF_DROP;
715
716 if (!th->syn && th->ack &&
717 CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) {
718 /* Keep-Alives are sent with SEG.SEQ = SND.NXT-1,
719 * therefore we need to add 1 to make the SYN sequence
720 * number match the one of first SYN.
721 */
722 if (synproxy_recv_client_ack(net, skb, th, &opts,
723 ntohl(th->seq) + 1)) {
724 this_cpu_inc(snet->stats->cookie_retrans);
725 consume_skb(skb);
726 return NF_STOLEN;
727 } else {
728 return NF_DROP;
729 }
730 }
731
732 synproxy->isn = ntohl(th->ack_seq);
733 if (opts.options & NF_SYNPROXY_OPT_TIMESTAMP)
734 synproxy->its = opts.tsecr;
735
736 nf_conntrack_event_cache(IPCT_SYNPROXY, ct);
737 break;
738 case TCP_CONNTRACK_SYN_RECV:
739 if (!th->syn || !th->ack)
740 break;
741
742 if (!synproxy_parse_options(skb, thoff, th, &opts))
743 return NF_DROP;
744
745 if (opts.options & NF_SYNPROXY_OPT_TIMESTAMP) {
746 synproxy->tsoff = opts.tsval - synproxy->its;
747 nf_conntrack_event_cache(IPCT_SYNPROXY, ct);
748 }
749
750 opts.options &= ~(NF_SYNPROXY_OPT_MSS |
751 NF_SYNPROXY_OPT_WSCALE |
752 NF_SYNPROXY_OPT_SACK_PERM);
753
754 swap(opts.tsval, opts.tsecr);
755 synproxy_send_server_ack(net, state, skb, th, &opts);
756
757 nf_ct_seqadj_init(ct, ctinfo, synproxy->isn - ntohl(th->seq));
758 nf_conntrack_event_cache(IPCT_SEQADJ, ct);
759
760 swap(opts.tsval, opts.tsecr);
761 synproxy_send_client_ack(net, skb, th, &opts);
762
763 consume_skb(skb);
764 return NF_STOLEN;
765 default:
766 break;
767 }
768
769 synproxy_tstamp_adjust(skb, thoff, th, ct, ctinfo, synproxy);
770 return NF_ACCEPT;
771}
772EXPORT_SYMBOL_GPL(ipv4_synproxy_hook);
773
774static const struct nf_hook_ops ipv4_synproxy_ops[] = {
775 {
776 .hook = ipv4_synproxy_hook,
777 .pf = NFPROTO_IPV4,
778 .hooknum = NF_INET_LOCAL_IN,
779 .priority = NF_IP_PRI_CONNTRACK_CONFIRM - 1,
780 },
781 {
782 .hook = ipv4_synproxy_hook,
783 .pf = NFPROTO_IPV4,
784 .hooknum = NF_INET_POST_ROUTING,
785 .priority = NF_IP_PRI_CONNTRACK_CONFIRM - 1,
786 },
787};
788
789int nf_synproxy_ipv4_init(struct synproxy_net *snet, struct net *net)
790{
791 int err;
792
793 if (snet->hook_ref4 == 0) {
794 err = nf_register_net_hooks(net, ipv4_synproxy_ops,
795 ARRAY_SIZE(ipv4_synproxy_ops));
796 if (err)
797 return err;
798 }
799
800 snet->hook_ref4++;
801 return err;
802}
803EXPORT_SYMBOL_GPL(nf_synproxy_ipv4_init);
804
805void nf_synproxy_ipv4_fini(struct synproxy_net *snet, struct net *net)
806{
807 snet->hook_ref4--;
808 if (snet->hook_ref4 == 0)
809 nf_unregister_net_hooks(net, ipv4_synproxy_ops,
810 ARRAY_SIZE(ipv4_synproxy_ops));
811}
812EXPORT_SYMBOL_GPL(nf_synproxy_ipv4_fini);
813
814#if IS_ENABLED(CONFIG_IPV6)
815static struct ipv6hdr *
816synproxy_build_ip_ipv6(struct net *net, struct sk_buff *skb,
817 const struct in6_addr *saddr,
818 const struct in6_addr *daddr)
819{
820 struct ipv6hdr *iph;
821
822 skb_reset_network_header(skb);
823 iph = skb_put(skb, sizeof(*iph));
824 ip6_flow_hdr(iph, 0, 0);
825 iph->hop_limit = net->ipv6.devconf_all->hop_limit;
826 iph->nexthdr = IPPROTO_TCP;
827 iph->saddr = *saddr;
828 iph->daddr = *daddr;
829
830 return iph;
831}
832
833static void
834synproxy_send_tcp_ipv6(struct net *net,
835 const struct sk_buff *skb, struct sk_buff *nskb,
836 struct nf_conntrack *nfct, enum ip_conntrack_info ctinfo,
837 struct ipv6hdr *niph, struct tcphdr *nth,
838 unsigned int tcp_hdr_size)
839{
840 struct dst_entry *dst;
841 struct flowi6 fl6;
842 int err;
843
844 nth->check = ~tcp_v6_check(tcp_hdr_size, &niph->saddr, &niph->daddr, 0);
845 nskb->ip_summed = CHECKSUM_PARTIAL;
846 nskb->csum_start = (unsigned char *)nth - nskb->head;
847 nskb->csum_offset = offsetof(struct tcphdr, check);
848
849 memset(&fl6, 0, sizeof(fl6));
850 fl6.flowi6_proto = IPPROTO_TCP;
851 fl6.saddr = niph->saddr;
852 fl6.daddr = niph->daddr;
853 fl6.fl6_sport = nth->source;
854 fl6.fl6_dport = nth->dest;
855 security_skb_classify_flow((struct sk_buff *)skb,
856 flowi6_to_flowi(&fl6));
857 err = nf_ip6_route(net, &dst, flowi6_to_flowi(&fl6), false);
858 if (err) {
859 goto free_nskb;
860 }
861
862 dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
863 if (IS_ERR(dst))
864 goto free_nskb;
865
866 skb_dst_set(nskb, dst);
867
868 if (nfct) {
869 nf_ct_set(nskb, (struct nf_conn *)nfct, ctinfo);
870 nf_conntrack_get(nfct);
871 }
872
873 ip6_local_out(net, nskb->sk, nskb);
874 return;
875
876free_nskb:
877 kfree_skb(nskb);
878}
879
880void
881synproxy_send_client_synack_ipv6(struct net *net,
882 const struct sk_buff *skb,
883 const struct tcphdr *th,
884 const struct synproxy_options *opts)
885{
886 struct sk_buff *nskb;
887 struct ipv6hdr *iph, *niph;
888 struct tcphdr *nth;
889 unsigned int tcp_hdr_size;
890 u16 mss = opts->mss;
891
892 iph = ipv6_hdr(skb);
893
894 tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
895 nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
896 GFP_ATOMIC);
897 if (!nskb)
898 return;
899 skb_reserve(nskb, MAX_TCP_HEADER);
900
901 niph = synproxy_build_ip_ipv6(net, nskb, &iph->daddr, &iph->saddr);
902
903 skb_reset_transport_header(nskb);
904 nth = skb_put(nskb, tcp_hdr_size);
905 nth->source = th->dest;
906 nth->dest = th->source;
907 nth->seq = htonl(nf_ipv6_cookie_init_sequence(iph, th, &mss));
908 nth->ack_seq = htonl(ntohl(th->seq) + 1);
909 tcp_flag_word(nth) = TCP_FLAG_SYN | TCP_FLAG_ACK;
910 if (opts->options & NF_SYNPROXY_OPT_ECN)
911 tcp_flag_word(nth) |= TCP_FLAG_ECE;
912 nth->doff = tcp_hdr_size / 4;
913 nth->window = 0;
914 nth->check = 0;
915 nth->urg_ptr = 0;
916
917 synproxy_build_options(nth, opts);
918
919 synproxy_send_tcp_ipv6(net, skb, nskb, skb_nfct(skb),
920 IP_CT_ESTABLISHED_REPLY, niph, nth,
921 tcp_hdr_size);
922}
923EXPORT_SYMBOL_GPL(synproxy_send_client_synack_ipv6);
924
925static void
926synproxy_send_server_syn_ipv6(struct net *net, const struct sk_buff *skb,
927 const struct tcphdr *th,
928 const struct synproxy_options *opts, u32 recv_seq)
929{
930 struct synproxy_net *snet = synproxy_pernet(net);
931 struct sk_buff *nskb;
932 struct ipv6hdr *iph, *niph;
933 struct tcphdr *nth;
934 unsigned int tcp_hdr_size;
935
936 iph = ipv6_hdr(skb);
937
938 tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
939 nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
940 GFP_ATOMIC);
941 if (!nskb)
942 return;
943 skb_reserve(nskb, MAX_TCP_HEADER);
944
945 niph = synproxy_build_ip_ipv6(net, nskb, &iph->saddr, &iph->daddr);
946
947 skb_reset_transport_header(nskb);
948 nth = skb_put(nskb, tcp_hdr_size);
949 nth->source = th->source;
950 nth->dest = th->dest;
951 nth->seq = htonl(recv_seq - 1);
952 /* ack_seq is used to relay our ISN to the synproxy hook to initialize
953 * sequence number translation once a connection tracking entry exists.
954 */
955 nth->ack_seq = htonl(ntohl(th->ack_seq) - 1);
956 tcp_flag_word(nth) = TCP_FLAG_SYN;
957 if (opts->options & NF_SYNPROXY_OPT_ECN)
958 tcp_flag_word(nth) |= TCP_FLAG_ECE | TCP_FLAG_CWR;
959 nth->doff = tcp_hdr_size / 4;
960 nth->window = th->window;
961 nth->check = 0;
962 nth->urg_ptr = 0;
963
964 synproxy_build_options(nth, opts);
965
966 synproxy_send_tcp_ipv6(net, skb, nskb, &snet->tmpl->ct_general,
967 IP_CT_NEW, niph, nth, tcp_hdr_size);
968}
969
970static void
971synproxy_send_server_ack_ipv6(struct net *net, const struct ip_ct_tcp *state,
972 const struct sk_buff *skb,
973 const struct tcphdr *th,
974 const struct synproxy_options *opts)
975{
976 struct sk_buff *nskb;
977 struct ipv6hdr *iph, *niph;
978 struct tcphdr *nth;
979 unsigned int tcp_hdr_size;
980
981 iph = ipv6_hdr(skb);
982
983 tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
984 nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
985 GFP_ATOMIC);
986 if (!nskb)
987 return;
988 skb_reserve(nskb, MAX_TCP_HEADER);
989
990 niph = synproxy_build_ip_ipv6(net, nskb, &iph->daddr, &iph->saddr);
991
992 skb_reset_transport_header(nskb);
993 nth = skb_put(nskb, tcp_hdr_size);
994 nth->source = th->dest;
995 nth->dest = th->source;
996 nth->seq = htonl(ntohl(th->ack_seq));
997 nth->ack_seq = htonl(ntohl(th->seq) + 1);
998 tcp_flag_word(nth) = TCP_FLAG_ACK;
999 nth->doff = tcp_hdr_size / 4;
1000 nth->window = htons(state->seen[IP_CT_DIR_ORIGINAL].td_maxwin);
1001 nth->check = 0;
1002 nth->urg_ptr = 0;
1003
1004 synproxy_build_options(nth, opts);
1005
1006 synproxy_send_tcp_ipv6(net, skb, nskb, NULL, 0, niph, nth,
1007 tcp_hdr_size);
1008}
1009
1010static void
1011synproxy_send_client_ack_ipv6(struct net *net, const struct sk_buff *skb,
1012 const struct tcphdr *th,
1013 const struct synproxy_options *opts)
1014{
1015 struct sk_buff *nskb;
1016 struct ipv6hdr *iph, *niph;
1017 struct tcphdr *nth;
1018 unsigned int tcp_hdr_size;
1019
1020 iph = ipv6_hdr(skb);
1021
1022 tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
1023 nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
1024 GFP_ATOMIC);
1025 if (!nskb)
1026 return;
1027 skb_reserve(nskb, MAX_TCP_HEADER);
1028
1029 niph = synproxy_build_ip_ipv6(net, nskb, &iph->saddr, &iph->daddr);
1030
1031 skb_reset_transport_header(nskb);
1032 nth = skb_put(nskb, tcp_hdr_size);
1033 nth->source = th->source;
1034 nth->dest = th->dest;
1035 nth->seq = htonl(ntohl(th->seq) + 1);
1036 nth->ack_seq = th->ack_seq;
1037 tcp_flag_word(nth) = TCP_FLAG_ACK;
1038 nth->doff = tcp_hdr_size / 4;
1039 nth->window = htons(ntohs(th->window) >> opts->wscale);
1040 nth->check = 0;
1041 nth->urg_ptr = 0;
1042
1043 synproxy_build_options(nth, opts);
1044
1045 synproxy_send_tcp_ipv6(net, skb, nskb, skb_nfct(skb),
1046 IP_CT_ESTABLISHED_REPLY, niph, nth,
1047 tcp_hdr_size);
1048}
1049
1050bool
1051synproxy_recv_client_ack_ipv6(struct net *net,
1052 const struct sk_buff *skb,
1053 const struct tcphdr *th,
1054 struct synproxy_options *opts, u32 recv_seq)
1055{
1056 struct synproxy_net *snet = synproxy_pernet(net);
1057 int mss;
1058
1059 mss = __cookie_v6_check(ipv6_hdr(skb), th, ntohl(th->ack_seq) - 1);
1060 if (mss == 0) {
1061 this_cpu_inc(snet->stats->cookie_invalid);
1062 return false;
1063 }
1064
1065 this_cpu_inc(snet->stats->cookie_valid);
1066 opts->mss = mss;
1067 opts->options |= NF_SYNPROXY_OPT_MSS;
1068
1069 if (opts->options & NF_SYNPROXY_OPT_TIMESTAMP)
1070 synproxy_check_timestamp_cookie(opts);
1071
1072 synproxy_send_server_syn_ipv6(net, skb, th, opts, recv_seq);
1073 return true;
1074}
1075EXPORT_SYMBOL_GPL(synproxy_recv_client_ack_ipv6);
1076
1077unsigned int
1078ipv6_synproxy_hook(void *priv, struct sk_buff *skb,
1079 const struct nf_hook_state *nhs)
1080{
1081 struct net *net = nhs->net;
1082 struct synproxy_net *snet = synproxy_pernet(net);
1083 enum ip_conntrack_info ctinfo;
1084 struct nf_conn *ct;
1085 struct nf_conn_synproxy *synproxy;
1086 struct synproxy_options opts = {};
1087 const struct ip_ct_tcp *state;
1088 struct tcphdr *th, _th;
1089 __be16 frag_off;
1090 u8 nexthdr;
1091 int thoff;
1092
1093 ct = nf_ct_get(skb, &ctinfo);
1094 if (!ct)
1095 return NF_ACCEPT;
1096
1097 synproxy = nfct_synproxy(ct);
1098 if (!synproxy)
1099 return NF_ACCEPT;
1100
1101 if (nf_is_loopback_packet(skb))
1102 return NF_ACCEPT;
1103
1104 nexthdr = ipv6_hdr(skb)->nexthdr;
1105 thoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr,
1106 &frag_off);
1107 if (thoff < 0 || nexthdr != IPPROTO_TCP)
1108 return NF_ACCEPT;
1109
1110 th = skb_header_pointer(skb, thoff, sizeof(_th), &_th);
1111 if (!th)
1112 return NF_DROP;
1113
1114 state = &ct->proto.tcp;
1115 switch (state->state) {
1116 case TCP_CONNTRACK_CLOSE:
1117 if (th->rst && !test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
1118 nf_ct_seqadj_init(ct, ctinfo, synproxy->isn -
1119 ntohl(th->seq) + 1);
1120 break;
1121 }
1122
1123 if (!th->syn || th->ack ||
1124 CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)
1125 break;
1126
1127 /* Reopened connection - reset the sequence number and timestamp
1128 * adjustments, they will get initialized once the connection is
1129 * reestablished.
1130 */
1131 nf_ct_seqadj_init(ct, ctinfo, 0);
1132 synproxy->tsoff = 0;
1133 this_cpu_inc(snet->stats->conn_reopened);
1134
1135 /* fall through */
1136 case TCP_CONNTRACK_SYN_SENT:
1137 if (!synproxy_parse_options(skb, thoff, th, &opts))
1138 return NF_DROP;
1139
1140 if (!th->syn && th->ack &&
1141 CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) {
1142 /* Keep-Alives are sent with SEG.SEQ = SND.NXT-1,
1143 * therefore we need to add 1 to make the SYN sequence
1144 * number match the one of first SYN.
1145 */
1146 if (synproxy_recv_client_ack_ipv6(net, skb, th, &opts,
1147 ntohl(th->seq) + 1)) {
1148 this_cpu_inc(snet->stats->cookie_retrans);
1149 consume_skb(skb);
1150 return NF_STOLEN;
1151 } else {
1152 return NF_DROP;
1153 }
1154 }
1155
1156 synproxy->isn = ntohl(th->ack_seq);
1157 if (opts.options & NF_SYNPROXY_OPT_TIMESTAMP)
1158 synproxy->its = opts.tsecr;
1159
1160 nf_conntrack_event_cache(IPCT_SYNPROXY, ct);
1161 break;
1162 case TCP_CONNTRACK_SYN_RECV:
1163 if (!th->syn || !th->ack)
1164 break;
1165
1166 if (!synproxy_parse_options(skb, thoff, th, &opts))
1167 return NF_DROP;
1168
1169 if (opts.options & NF_SYNPROXY_OPT_TIMESTAMP) {
1170 synproxy->tsoff = opts.tsval - synproxy->its;
1171 nf_conntrack_event_cache(IPCT_SYNPROXY, ct);
1172 }
1173
1174 opts.options &= ~(NF_SYNPROXY_OPT_MSS |
1175 NF_SYNPROXY_OPT_WSCALE |
1176 NF_SYNPROXY_OPT_SACK_PERM);
1177
1178 swap(opts.tsval, opts.tsecr);
1179 synproxy_send_server_ack_ipv6(net, state, skb, th, &opts);
1180
1181 nf_ct_seqadj_init(ct, ctinfo, synproxy->isn - ntohl(th->seq));
1182 nf_conntrack_event_cache(IPCT_SEQADJ, ct);
1183
1184 swap(opts.tsval, opts.tsecr);
1185 synproxy_send_client_ack_ipv6(net, skb, th, &opts);
1186
1187 consume_skb(skb);
1188 return NF_STOLEN;
1189 default:
1190 break;
1191 }
1192
1193 synproxy_tstamp_adjust(skb, thoff, th, ct, ctinfo, synproxy);
1194 return NF_ACCEPT;
1195}
1196EXPORT_SYMBOL_GPL(ipv6_synproxy_hook);
1197
1198static const struct nf_hook_ops ipv6_synproxy_ops[] = {
1199 {
1200 .hook = ipv6_synproxy_hook,
1201 .pf = NFPROTO_IPV6,
1202 .hooknum = NF_INET_LOCAL_IN,
1203 .priority = NF_IP_PRI_CONNTRACK_CONFIRM - 1,
1204 },
1205 {
1206 .hook = ipv6_synproxy_hook,
1207 .pf = NFPROTO_IPV6,
1208 .hooknum = NF_INET_POST_ROUTING,
1209 .priority = NF_IP_PRI_CONNTRACK_CONFIRM - 1,
1210 },
1211};
1212
1213int
1214nf_synproxy_ipv6_init(struct synproxy_net *snet, struct net *net)
1215{
1216 int err;
1217
1218 if (snet->hook_ref6 == 0) {
1219 err = nf_register_net_hooks(net, ipv6_synproxy_ops,
1220 ARRAY_SIZE(ipv6_synproxy_ops));
1221 if (err)
1222 return err;
1223 }
1224
1225 snet->hook_ref6++;
1226 return err;
1227}
1228EXPORT_SYMBOL_GPL(nf_synproxy_ipv6_init);
1229
1230void
1231nf_synproxy_ipv6_fini(struct synproxy_net *snet, struct net *net)
1232{
1233 snet->hook_ref6--;
1234 if (snet->hook_ref6 == 0)
1235 nf_unregister_net_hooks(net, ipv6_synproxy_ops,
1236 ARRAY_SIZE(ipv6_synproxy_ops));
1237}
1238EXPORT_SYMBOL_GPL(nf_synproxy_ipv6_fini);
1239#endif /* CONFIG_IPV6 */
1240
419MODULE_LICENSE("GPL"); 1241MODULE_LICENSE("GPL");
420MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); 1242MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");