1 /*
2  * Copyright (c) 2013 Patrick McHardy <kaber@trash.net>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  */
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>
16 #include <linux/netfilter/x_tables.h>
17 #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 
22 static struct ipv6hdr *
23 synproxy_build_ip(struct net *net, struct sk_buff *skb,
24 		  const struct in6_addr *saddr,
25 		  const struct in6_addr *daddr)
26 {
27 	struct ipv6hdr *iph;
28 
29 	skb_reset_network_header(skb);
30 	iph = skb_put(skb, sizeof(*iph));
31 	ip6_flow_hdr(iph, 0, 0);
32 	iph->hop_limit	= net->ipv6.devconf_all->hop_limit;
33 	iph->nexthdr	= IPPROTO_TCP;
34 	iph->saddr	= *saddr;
35 	iph->daddr	= *daddr;
36 
37 	return iph;
38 }
39 
40 static void
41 synproxy_send_tcp(struct net *net,
42 		  const struct sk_buff *skb, struct sk_buff *nskb,
43 		  struct nf_conntrack *nfct, enum ip_conntrack_info ctinfo,
44 		  struct ipv6hdr *niph, struct tcphdr *nth,
45 		  unsigned int tcp_hdr_size)
46 {
47 	struct dst_entry *dst;
48 	struct flowi6 fl6;
49 
50 	nth->check = ~tcp_v6_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 	memset(&fl6, 0, sizeof(fl6));
56 	fl6.flowi6_proto = IPPROTO_TCP;
57 	fl6.saddr = niph->saddr;
58 	fl6.daddr = niph->daddr;
59 	fl6.fl6_sport = nth->source;
60 	fl6.fl6_dport = nth->dest;
61 	security_skb_classify_flow((struct sk_buff *)skb, flowi6_to_flowi(&fl6));
62 	dst = ip6_route_output(net, NULL, &fl6);
63 	if (dst->error) {
64 		dst_release(dst);
65 		goto free_nskb;
66 	}
67 	dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
68 	if (IS_ERR(dst))
69 		goto free_nskb;
70 
71 	skb_dst_set(nskb, dst);
72 
73 	if (nfct) {
74 		nf_ct_set(nskb, (struct nf_conn *)nfct, ctinfo);
75 		nf_conntrack_get(nfct);
76 	}
77 
78 	ip6_local_out(net, nskb->sk, nskb);
79 	return;
80 
81 free_nskb:
82 	kfree_skb(nskb);
83 }
84 
85 static void
86 synproxy_send_client_synack(struct net *net,
87 			    const struct sk_buff *skb, const struct tcphdr *th,
88 			    const struct synproxy_options *opts)
89 {
90 	struct sk_buff *nskb;
91 	struct ipv6hdr *iph, *niph;
92 	struct tcphdr *nth;
93 	unsigned int tcp_hdr_size;
94 	u16 mss = opts->mss;
95 
96 	iph = ipv6_hdr(skb);
97 
98 	tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
99 	nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
100 			 GFP_ATOMIC);
101 	if (nskb == NULL)
102 		return;
103 	skb_reserve(nskb, MAX_TCP_HEADER);
104 
105 	niph = synproxy_build_ip(net, nskb, &iph->daddr, &iph->saddr);
106 
107 	skb_reset_transport_header(nskb);
108 	nth = skb_put(nskb, tcp_hdr_size);
109 	nth->source	= th->dest;
110 	nth->dest	= th->source;
111 	nth->seq	= htonl(__cookie_v6_init_sequence(iph, th, &mss));
112 	nth->ack_seq	= htonl(ntohl(th->seq) + 1);
113 	tcp_flag_word(nth) = TCP_FLAG_SYN | TCP_FLAG_ACK;
114 	if (opts->options & XT_SYNPROXY_OPT_ECN)
115 		tcp_flag_word(nth) |= TCP_FLAG_ECE;
116 	nth->doff	= tcp_hdr_size / 4;
117 	nth->window	= 0;
118 	nth->check	= 0;
119 	nth->urg_ptr	= 0;
120 
121 	synproxy_build_options(nth, opts);
122 
123 	synproxy_send_tcp(net, skb, nskb, skb_nfct(skb),
124 			  IP_CT_ESTABLISHED_REPLY, niph, nth, tcp_hdr_size);
125 }
126 
127 static void
128 synproxy_send_server_syn(struct net *net,
129 			 const struct sk_buff *skb, const struct tcphdr *th,
130 			 const struct synproxy_options *opts, u32 recv_seq)
131 {
132 	struct synproxy_net *snet = synproxy_pernet(net);
133 	struct sk_buff *nskb;
134 	struct ipv6hdr *iph, *niph;
135 	struct tcphdr *nth;
136 	unsigned int tcp_hdr_size;
137 
138 	iph = ipv6_hdr(skb);
139 
140 	tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
141 	nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
142 			 GFP_ATOMIC);
143 	if (nskb == NULL)
144 		return;
145 	skb_reserve(nskb, MAX_TCP_HEADER);
146 
147 	niph = synproxy_build_ip(net, nskb, &iph->saddr, &iph->daddr);
148 
149 	skb_reset_transport_header(nskb);
150 	nth = skb_put(nskb, tcp_hdr_size);
151 	nth->source	= th->source;
152 	nth->dest	= th->dest;
153 	nth->seq	= htonl(recv_seq - 1);
154 	/* ack_seq is used to relay our ISN to the synproxy hook to initialize
155 	 * sequence number translation once a connection tracking entry exists.
156 	 */
157 	nth->ack_seq	= htonl(ntohl(th->ack_seq) - 1);
158 	tcp_flag_word(nth) = TCP_FLAG_SYN;
159 	if (opts->options & XT_SYNPROXY_OPT_ECN)
160 		tcp_flag_word(nth) |= TCP_FLAG_ECE | TCP_FLAG_CWR;
161 	nth->doff	= tcp_hdr_size / 4;
162 	nth->window	= th->window;
163 	nth->check	= 0;
164 	nth->urg_ptr	= 0;
165 
166 	synproxy_build_options(nth, opts);
167 
168 	synproxy_send_tcp(net, skb, nskb, &snet->tmpl->ct_general, IP_CT_NEW,
169 			  niph, nth, tcp_hdr_size);
170 }
171 
172 static void
173 synproxy_send_server_ack(struct net *net,
174 			 const struct ip_ct_tcp *state,
175 			 const struct sk_buff *skb, const struct tcphdr *th,
176 			 const struct synproxy_options *opts)
177 {
178 	struct sk_buff *nskb;
179 	struct ipv6hdr *iph, *niph;
180 	struct tcphdr *nth;
181 	unsigned int tcp_hdr_size;
182 
183 	iph = ipv6_hdr(skb);
184 
185 	tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
186 	nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
187 			 GFP_ATOMIC);
188 	if (nskb == NULL)
189 		return;
190 	skb_reserve(nskb, MAX_TCP_HEADER);
191 
192 	niph = synproxy_build_ip(net, nskb, &iph->daddr, &iph->saddr);
193 
194 	skb_reset_transport_header(nskb);
195 	nth = skb_put(nskb, tcp_hdr_size);
196 	nth->source	= th->dest;
197 	nth->dest	= th->source;
198 	nth->seq	= htonl(ntohl(th->ack_seq));
199 	nth->ack_seq	= htonl(ntohl(th->seq) + 1);
200 	tcp_flag_word(nth) = TCP_FLAG_ACK;
201 	nth->doff	= tcp_hdr_size / 4;
202 	nth->window	= htons(state->seen[IP_CT_DIR_ORIGINAL].td_maxwin);
203 	nth->check	= 0;
204 	nth->urg_ptr	= 0;
205 
206 	synproxy_build_options(nth, opts);
207 
208 	synproxy_send_tcp(net, skb, nskb, NULL, 0, niph, nth, tcp_hdr_size);
209 }
210 
211 static void
212 synproxy_send_client_ack(struct net *net,
213 			 const struct sk_buff *skb, const struct tcphdr *th,
214 			 const struct synproxy_options *opts)
215 {
216 	struct sk_buff *nskb;
217 	struct ipv6hdr *iph, *niph;
218 	struct tcphdr *nth;
219 	unsigned int tcp_hdr_size;
220 
221 	iph = ipv6_hdr(skb);
222 
223 	tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
224 	nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
225 			 GFP_ATOMIC);
226 	if (nskb == NULL)
227 		return;
228 	skb_reserve(nskb, MAX_TCP_HEADER);
229 
230 	niph = synproxy_build_ip(net, nskb, &iph->saddr, &iph->daddr);
231 
232 	skb_reset_transport_header(nskb);
233 	nth = skb_put(nskb, tcp_hdr_size);
234 	nth->source	= th->source;
235 	nth->dest	= th->dest;
236 	nth->seq	= htonl(ntohl(th->seq) + 1);
237 	nth->ack_seq	= th->ack_seq;
238 	tcp_flag_word(nth) = TCP_FLAG_ACK;
239 	nth->doff	= tcp_hdr_size / 4;
240 	nth->window	= htons(ntohs(th->window) >> opts->wscale);
241 	nth->check	= 0;
242 	nth->urg_ptr	= 0;
243 
244 	synproxy_build_options(nth, opts);
245 
246 	synproxy_send_tcp(net, skb, nskb, skb_nfct(skb),
247 			  IP_CT_ESTABLISHED_REPLY, niph, nth, tcp_hdr_size);
248 }
249 
250 static bool
251 synproxy_recv_client_ack(struct net *net,
252 			 const struct sk_buff *skb, const struct tcphdr *th,
253 			 struct synproxy_options *opts, u32 recv_seq)
254 {
255 	struct synproxy_net *snet = synproxy_pernet(net);
256 	int mss;
257 
258 	mss = __cookie_v6_check(ipv6_hdr(skb), th, ntohl(th->ack_seq) - 1);
259 	if (mss == 0) {
260 		this_cpu_inc(snet->stats->cookie_invalid);
261 		return false;
262 	}
263 
264 	this_cpu_inc(snet->stats->cookie_valid);
265 	opts->mss = mss;
266 	opts->options |= XT_SYNPROXY_OPT_MSS;
267 
268 	if (opts->options & XT_SYNPROXY_OPT_TIMESTAMP)
269 		synproxy_check_timestamp_cookie(opts);
270 
271 	synproxy_send_server_syn(net, skb, th, opts, recv_seq);
272 	return true;
273 }
274 
275 static unsigned int
276 synproxy_tg6(struct sk_buff *skb, const struct xt_action_param *par)
277 {
278 	const struct xt_synproxy_info *info = par->targinfo;
279 	struct net *net = xt_net(par);
280 	struct synproxy_net *snet = synproxy_pernet(net);
281 	struct synproxy_options opts = {};
282 	struct tcphdr *th, _th;
283 
284 	if (nf_ip6_checksum(skb, xt_hooknum(par), par->thoff, IPPROTO_TCP))
285 		return NF_DROP;
286 
287 	th = skb_header_pointer(skb, par->thoff, sizeof(_th), &_th);
288 	if (th == NULL)
289 		return NF_DROP;
290 
291 	if (!synproxy_parse_options(skb, par->thoff, th, &opts))
292 		return NF_DROP;
293 
294 	if (th->syn && !(th->ack || th->fin || th->rst)) {
295 		/* Initial SYN from client */
296 		this_cpu_inc(snet->stats->syn_received);
297 
298 		if (th->ece && th->cwr)
299 			opts.options |= XT_SYNPROXY_OPT_ECN;
300 
301 		opts.options &= info->options;
302 		if (opts.options & XT_SYNPROXY_OPT_TIMESTAMP)
303 			synproxy_init_timestamp_cookie(info, &opts);
304 		else
305 			opts.options &= ~(XT_SYNPROXY_OPT_WSCALE |
306 					  XT_SYNPROXY_OPT_SACK_PERM |
307 					  XT_SYNPROXY_OPT_ECN);
308 
309 		synproxy_send_client_synack(net, skb, th, &opts);
310 		consume_skb(skb);
311 		return NF_STOLEN;
312 
313 	} else if (th->ack && !(th->fin || th->rst || th->syn)) {
314 		/* ACK from client */
315 		if (synproxy_recv_client_ack(net, skb, th, &opts, ntohl(th->seq))) {
316 			consume_skb(skb);
317 			return NF_STOLEN;
318 		} else {
319 			return NF_DROP;
320 		}
321 	}
322 
323 	return XT_CONTINUE;
324 }
325 
326 static unsigned int ipv6_synproxy_hook(void *priv,
327 				       struct sk_buff *skb,
328 				       const struct nf_hook_state *nhs)
329 {
330 	struct net *net = nhs->net;
331 	struct synproxy_net *snet = synproxy_pernet(net);
332 	enum ip_conntrack_info ctinfo;
333 	struct nf_conn *ct;
334 	struct nf_conn_synproxy *synproxy;
335 	struct synproxy_options opts = {};
336 	const struct ip_ct_tcp *state;
337 	struct tcphdr *th, _th;
338 	__be16 frag_off;
339 	u8 nexthdr;
340 	int thoff;
341 
342 	ct = nf_ct_get(skb, &ctinfo);
343 	if (ct == NULL)
344 		return NF_ACCEPT;
345 
346 	synproxy = nfct_synproxy(ct);
347 	if (synproxy == NULL)
348 		return NF_ACCEPT;
349 
350 	if (nf_is_loopback_packet(skb))
351 		return NF_ACCEPT;
352 
353 	nexthdr = ipv6_hdr(skb)->nexthdr;
354 	thoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr,
355 				 &frag_off);
356 	if (thoff < 0)
357 		return NF_ACCEPT;
358 
359 	th = skb_header_pointer(skb, thoff, sizeof(_th), &_th);
360 	if (th == NULL)
361 		return NF_DROP;
362 
363 	state = &ct->proto.tcp;
364 	switch (state->state) {
365 	case TCP_CONNTRACK_CLOSE:
366 		if (th->rst && !test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
367 			nf_ct_seqadj_init(ct, ctinfo, synproxy->isn -
368 						      ntohl(th->seq) + 1);
369 			break;
370 		}
371 
372 		if (!th->syn || th->ack ||
373 		    CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)
374 			break;
375 
376 		/* Reopened connection - reset the sequence number and timestamp
377 		 * adjustments, they will get initialized once the connection is
378 		 * reestablished.
379 		 */
380 		nf_ct_seqadj_init(ct, ctinfo, 0);
381 		synproxy->tsoff = 0;
382 		this_cpu_inc(snet->stats->conn_reopened);
383 
384 		/* fall through */
385 	case TCP_CONNTRACK_SYN_SENT:
386 		if (!synproxy_parse_options(skb, thoff, th, &opts))
387 			return NF_DROP;
388 
389 		if (!th->syn && th->ack &&
390 		    CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) {
391 			/* Keep-Alives are sent with SEG.SEQ = SND.NXT-1,
392 			 * therefore we need to add 1 to make the SYN sequence
393 			 * number match the one of first SYN.
394 			 */
395 			if (synproxy_recv_client_ack(net, skb, th, &opts,
396 						     ntohl(th->seq) + 1)) {
397 				this_cpu_inc(snet->stats->cookie_retrans);
398 				consume_skb(skb);
399 				return NF_STOLEN;
400 			} else {
401 				return NF_DROP;
402 			}
403 		}
404 
405 		synproxy->isn = ntohl(th->ack_seq);
406 		if (opts.options & XT_SYNPROXY_OPT_TIMESTAMP)
407 			synproxy->its = opts.tsecr;
408 		break;
409 	case TCP_CONNTRACK_SYN_RECV:
410 		if (!th->syn || !th->ack)
411 			break;
412 
413 		if (!synproxy_parse_options(skb, thoff, th, &opts))
414 			return NF_DROP;
415 
416 		if (opts.options & XT_SYNPROXY_OPT_TIMESTAMP)
417 			synproxy->tsoff = opts.tsval - synproxy->its;
418 
419 		opts.options &= ~(XT_SYNPROXY_OPT_MSS |
420 				  XT_SYNPROXY_OPT_WSCALE |
421 				  XT_SYNPROXY_OPT_SACK_PERM);
422 
423 		swap(opts.tsval, opts.tsecr);
424 		synproxy_send_server_ack(net, state, skb, th, &opts);
425 
426 		nf_ct_seqadj_init(ct, ctinfo, synproxy->isn - ntohl(th->seq));
427 
428 		swap(opts.tsval, opts.tsecr);
429 		synproxy_send_client_ack(net, skb, th, &opts);
430 
431 		consume_skb(skb);
432 		return NF_STOLEN;
433 	default:
434 		break;
435 	}
436 
437 	synproxy_tstamp_adjust(skb, thoff, th, ct, ctinfo, synproxy);
438 	return NF_ACCEPT;
439 }
440 
441 static struct nf_hook_ops ipv6_synproxy_ops[] __read_mostly = {
442 	{
443 		.hook		= ipv6_synproxy_hook,
444 		.pf		= NFPROTO_IPV6,
445 		.hooknum	= NF_INET_LOCAL_IN,
446 		.priority	= NF_IP_PRI_CONNTRACK_CONFIRM - 1,
447 	},
448 	{
449 		.hook		= ipv6_synproxy_hook,
450 		.pf		= NFPROTO_IPV6,
451 		.hooknum	= NF_INET_POST_ROUTING,
452 		.priority	= NF_IP_PRI_CONNTRACK_CONFIRM - 1,
453 	},
454 };
455 
456 static int synproxy_tg6_check(const struct xt_tgchk_param *par)
457 {
458 	struct synproxy_net *snet = synproxy_pernet(par->net);
459 	const struct ip6t_entry *e = par->entryinfo;
460 	int err;
461 
462 	if (!(e->ipv6.flags & IP6T_F_PROTO) ||
463 	    e->ipv6.proto != IPPROTO_TCP ||
464 	    e->ipv6.invflags & XT_INV_PROTO)
465 		return -EINVAL;
466 
467 	err = nf_ct_netns_get(par->net, par->family);
468 	if (err)
469 		return err;
470 
471 	if (snet->hook_ref6 == 0) {
472 		err = nf_register_net_hooks(par->net, ipv6_synproxy_ops,
473 					    ARRAY_SIZE(ipv6_synproxy_ops));
474 		if (err) {
475 			nf_ct_netns_put(par->net, par->family);
476 			return err;
477 		}
478 	}
479 
480 	snet->hook_ref6++;
481 	return err;
482 }
483 
484 static void synproxy_tg6_destroy(const struct xt_tgdtor_param *par)
485 {
486 	struct synproxy_net *snet = synproxy_pernet(par->net);
487 
488 	snet->hook_ref6--;
489 	if (snet->hook_ref6 == 0)
490 		nf_unregister_net_hooks(par->net, ipv6_synproxy_ops,
491 					ARRAY_SIZE(ipv6_synproxy_ops));
492 	nf_ct_netns_put(par->net, par->family);
493 }
494 
495 static struct xt_target synproxy_tg6_reg __read_mostly = {
496 	.name		= "SYNPROXY",
497 	.family		= NFPROTO_IPV6,
498 	.hooks		= (1 << NF_INET_LOCAL_IN) | (1 << NF_INET_FORWARD),
499 	.target		= synproxy_tg6,
500 	.targetsize	= sizeof(struct xt_synproxy_info),
501 	.checkentry	= synproxy_tg6_check,
502 	.destroy	= synproxy_tg6_destroy,
503 	.me		= THIS_MODULE,
504 };
505 
506 static int __init synproxy_tg6_init(void)
507 {
508 	return xt_register_target(&synproxy_tg6_reg);
509 }
510 
511 static void __exit synproxy_tg6_exit(void)
512 {
513 	xt_unregister_target(&synproxy_tg6_reg);
514 }
515 
516 module_init(synproxy_tg6_init);
517 module_exit(synproxy_tg6_exit);
518 
519 MODULE_LICENSE("GPL");
520 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
521