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