2 * Copyright (c) 2013 Patrick McHardy <kaber@trash.net>
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.
9 #include <linux/module.h>
10 #include <linux/skbuff.h>
13 #include <linux/netfilter_ipv4/ip_tables.h>
14 #include <linux/netfilter/x_tables.h>
15 #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>
21 synproxy_build_ip(struct net
*net
, struct sk_buff
*skb
, __be32 saddr
,
26 skb_reset_network_header(skb
);
27 iph
= (struct iphdr
*)skb_put(skb
, sizeof(*iph
));
29 iph
->ihl
= sizeof(*iph
) / 4;
32 iph
->frag_off
= htons(IP_DF
);
33 iph
->ttl
= net
->ipv4
.sysctl_ip_default_ttl
;
34 iph
->protocol
= IPPROTO_TCP
;
43 synproxy_send_tcp(struct net
*net
,
44 const struct sk_buff
*skb
, struct sk_buff
*nskb
,
45 struct nf_conntrack
*nfct
, enum ip_conntrack_info ctinfo
,
46 struct iphdr
*niph
, struct tcphdr
*nth
,
47 unsigned int tcp_hdr_size
)
49 nth
->check
= ~tcp_v4_check(tcp_hdr_size
, niph
->saddr
, niph
->daddr
, 0);
50 nskb
->ip_summed
= CHECKSUM_PARTIAL
;
51 nskb
->csum_start
= (unsigned char *)nth
- nskb
->head
;
52 nskb
->csum_offset
= offsetof(struct tcphdr
, check
);
54 skb_dst_set_noref(nskb
, skb_dst(skb
));
55 nskb
->protocol
= htons(ETH_P_IP
);
56 if (ip_route_me_harder(net
, nskb
, RTN_UNSPEC
))
61 nskb
->nfctinfo
= ctinfo
;
62 nf_conntrack_get(nfct
);
65 ip_local_out(net
, nskb
->sk
, nskb
);
73 synproxy_send_client_synack(struct net
*net
,
74 const struct sk_buff
*skb
, const struct tcphdr
*th
,
75 const struct synproxy_options
*opts
)
78 struct iphdr
*iph
, *niph
;
80 unsigned int tcp_hdr_size
;
85 tcp_hdr_size
= sizeof(*nth
) + synproxy_options_size(opts
);
86 nskb
= alloc_skb(sizeof(*niph
) + tcp_hdr_size
+ MAX_TCP_HEADER
,
90 skb_reserve(nskb
, MAX_TCP_HEADER
);
92 niph
= synproxy_build_ip(net
, nskb
, iph
->daddr
, iph
->saddr
);
94 skb_reset_transport_header(nskb
);
95 nth
= (struct tcphdr
*)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;
108 synproxy_build_options(nth
, opts
);
110 synproxy_send_tcp(net
, skb
, nskb
, skb
->nfct
, IP_CT_ESTABLISHED_REPLY
,
111 niph
, nth
, tcp_hdr_size
);
115 synproxy_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
)
119 struct synproxy_net
*snet
= synproxy_pernet(net
);
120 struct sk_buff
*nskb
;
121 struct iphdr
*iph
, *niph
;
123 unsigned int tcp_hdr_size
;
127 tcp_hdr_size
= sizeof(*nth
) + synproxy_options_size(opts
);
128 nskb
= alloc_skb(sizeof(*niph
) + tcp_hdr_size
+ MAX_TCP_HEADER
,
132 skb_reserve(nskb
, MAX_TCP_HEADER
);
134 niph
= synproxy_build_ip(net
, nskb
, iph
->saddr
, iph
->daddr
);
136 skb_reset_transport_header(nskb
);
137 nth
= (struct tcphdr
*)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.
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
;
153 synproxy_build_options(nth
, opts
);
155 synproxy_send_tcp(net
, skb
, nskb
, &snet
->tmpl
->ct_general
, IP_CT_NEW
,
156 niph
, nth
, tcp_hdr_size
);
160 synproxy_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
)
165 struct sk_buff
*nskb
;
166 struct iphdr
*iph
, *niph
;
168 unsigned int tcp_hdr_size
;
172 tcp_hdr_size
= sizeof(*nth
) + synproxy_options_size(opts
);
173 nskb
= alloc_skb(sizeof(*niph
) + tcp_hdr_size
+ MAX_TCP_HEADER
,
177 skb_reserve(nskb
, MAX_TCP_HEADER
);
179 niph
= synproxy_build_ip(net
, nskb
, iph
->daddr
, iph
->saddr
);
181 skb_reset_transport_header(nskb
);
182 nth
= (struct tcphdr
*)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
);
193 synproxy_build_options(nth
, opts
);
195 synproxy_send_tcp(net
, skb
, nskb
, NULL
, 0, niph
, nth
, tcp_hdr_size
);
199 synproxy_send_client_ack(struct net
*net
,
200 const struct sk_buff
*skb
, const struct tcphdr
*th
,
201 const struct synproxy_options
*opts
)
203 struct sk_buff
*nskb
;
204 struct iphdr
*iph
, *niph
;
206 unsigned int tcp_hdr_size
;
210 tcp_hdr_size
= sizeof(*nth
) + synproxy_options_size(opts
);
211 nskb
= alloc_skb(sizeof(*niph
) + tcp_hdr_size
+ MAX_TCP_HEADER
,
215 skb_reserve(nskb
, MAX_TCP_HEADER
);
217 niph
= synproxy_build_ip(net
, nskb
, iph
->saddr
, iph
->daddr
);
219 skb_reset_transport_header(nskb
);
220 nth
= (struct tcphdr
*)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
);
231 synproxy_build_options(nth
, opts
);
233 synproxy_send_tcp(net
, skb
, nskb
, skb
->nfct
, IP_CT_ESTABLISHED_REPLY
,
234 niph
, nth
, tcp_hdr_size
);
238 synproxy_recv_client_ack(struct net
*net
,
239 const struct sk_buff
*skb
, const struct tcphdr
*th
,
240 struct synproxy_options
*opts
, u32 recv_seq
)
242 struct synproxy_net
*snet
= synproxy_pernet(net
);
245 mss
= __cookie_v4_check(ip_hdr(skb
), th
, ntohl(th
->ack_seq
) - 1);
247 this_cpu_inc(snet
->stats
->cookie_invalid
);
251 this_cpu_inc(snet
->stats
->cookie_valid
);
253 opts
->options
|= XT_SYNPROXY_OPT_MSS
;
255 if (opts
->options
& XT_SYNPROXY_OPT_TIMESTAMP
)
256 synproxy_check_timestamp_cookie(opts
);
258 synproxy_send_server_syn(net
, skb
, th
, opts
, recv_seq
);
263 synproxy_tg4(struct sk_buff
*skb
, const struct xt_action_param
*par
)
265 const struct xt_synproxy_info
*info
= par
->targinfo
;
266 struct net
*net
= xt_net(par
);
267 struct synproxy_net
*snet
= synproxy_pernet(net
);
268 struct synproxy_options opts
= {};
269 struct tcphdr
*th
, _th
;
271 if (nf_ip_checksum(skb
, xt_hooknum(par
), par
->thoff
, IPPROTO_TCP
))
274 th
= skb_header_pointer(skb
, par
->thoff
, sizeof(_th
), &_th
);
278 if (!synproxy_parse_options(skb
, par
->thoff
, th
, &opts
))
281 if (th
->syn
&& !(th
->ack
|| th
->fin
|| th
->rst
)) {
282 /* Initial SYN from client */
283 this_cpu_inc(snet
->stats
->syn_received
);
285 if (th
->ece
&& th
->cwr
)
286 opts
.options
|= XT_SYNPROXY_OPT_ECN
;
288 opts
.options
&= info
->options
;
289 if (opts
.options
& XT_SYNPROXY_OPT_TIMESTAMP
)
290 synproxy_init_timestamp_cookie(info
, &opts
);
292 opts
.options
&= ~(XT_SYNPROXY_OPT_WSCALE
|
293 XT_SYNPROXY_OPT_SACK_PERM
|
294 XT_SYNPROXY_OPT_ECN
);
296 synproxy_send_client_synack(net
, skb
, th
, &opts
);
299 } else if (th
->ack
&& !(th
->fin
|| th
->rst
|| th
->syn
)) {
300 /* ACK from client */
301 synproxy_recv_client_ack(net
, skb
, th
, &opts
, ntohl(th
->seq
));
308 static unsigned int ipv4_synproxy_hook(void *priv
,
310 const struct nf_hook_state
*nhs
)
312 struct net
*net
= nhs
->net
;
313 struct synproxy_net
*snet
= synproxy_pernet(net
);
314 enum ip_conntrack_info ctinfo
;
316 struct nf_conn_synproxy
*synproxy
;
317 struct synproxy_options opts
= {};
318 const struct ip_ct_tcp
*state
;
319 struct tcphdr
*th
, _th
;
322 ct
= nf_ct_get(skb
, &ctinfo
);
326 synproxy
= nfct_synproxy(ct
);
327 if (synproxy
== NULL
)
330 if (nf_is_loopback_packet(skb
))
333 thoff
= ip_hdrlen(skb
);
334 th
= skb_header_pointer(skb
, thoff
, sizeof(_th
), &_th
);
338 state
= &ct
->proto
.tcp
;
339 switch (state
->state
) {
340 case TCP_CONNTRACK_CLOSE
:
341 if (th
->rst
&& !test_bit(IPS_SEEN_REPLY_BIT
, &ct
->status
)) {
342 nf_ct_seqadj_init(ct
, ctinfo
, synproxy
->isn
-
347 if (!th
->syn
|| th
->ack
||
348 CTINFO2DIR(ctinfo
) != IP_CT_DIR_ORIGINAL
)
351 /* Reopened connection - reset the sequence number and timestamp
352 * adjustments, they will get initialized once the connection is
355 nf_ct_seqadj_init(ct
, ctinfo
, 0);
357 this_cpu_inc(snet
->stats
->conn_reopened
);
360 case TCP_CONNTRACK_SYN_SENT
:
361 if (!synproxy_parse_options(skb
, thoff
, th
, &opts
))
364 if (!th
->syn
&& th
->ack
&&
365 CTINFO2DIR(ctinfo
) == IP_CT_DIR_ORIGINAL
) {
366 /* Keep-Alives are sent with SEG.SEQ = SND.NXT-1,
367 * therefore we need to add 1 to make the SYN sequence
368 * number match the one of first SYN.
370 if (synproxy_recv_client_ack(net
, skb
, th
, &opts
,
372 this_cpu_inc(snet
->stats
->cookie_retrans
);
377 synproxy
->isn
= ntohl(th
->ack_seq
);
378 if (opts
.options
& XT_SYNPROXY_OPT_TIMESTAMP
)
379 synproxy
->its
= opts
.tsecr
;
381 case TCP_CONNTRACK_SYN_RECV
:
382 if (!th
->syn
|| !th
->ack
)
385 if (!synproxy_parse_options(skb
, thoff
, th
, &opts
))
388 if (opts
.options
& XT_SYNPROXY_OPT_TIMESTAMP
)
389 synproxy
->tsoff
= opts
.tsval
- synproxy
->its
;
391 opts
.options
&= ~(XT_SYNPROXY_OPT_MSS
|
392 XT_SYNPROXY_OPT_WSCALE
|
393 XT_SYNPROXY_OPT_SACK_PERM
);
395 swap(opts
.tsval
, opts
.tsecr
);
396 synproxy_send_server_ack(net
, state
, skb
, th
, &opts
);
398 nf_ct_seqadj_init(ct
, ctinfo
, synproxy
->isn
- ntohl(th
->seq
));
400 swap(opts
.tsval
, opts
.tsecr
);
401 synproxy_send_client_ack(net
, skb
, th
, &opts
);
409 synproxy_tstamp_adjust(skb
, thoff
, th
, ct
, ctinfo
, synproxy
);
413 static int synproxy_tg4_check(const struct xt_tgchk_param
*par
)
415 const struct ipt_entry
*e
= par
->entryinfo
;
417 if (e
->ip
.proto
!= IPPROTO_TCP
||
418 e
->ip
.invflags
& XT_INV_PROTO
)
421 return nf_ct_netns_get(par
->net
, par
->family
);
424 static void synproxy_tg4_destroy(const struct xt_tgdtor_param
*par
)
426 nf_ct_netns_put(par
->net
, par
->family
);
429 static struct xt_target synproxy_tg4_reg __read_mostly
= {
431 .family
= NFPROTO_IPV4
,
432 .hooks
= (1 << NF_INET_LOCAL_IN
) | (1 << NF_INET_FORWARD
),
433 .target
= synproxy_tg4
,
434 .targetsize
= sizeof(struct xt_synproxy_info
),
435 .checkentry
= synproxy_tg4_check
,
436 .destroy
= synproxy_tg4_destroy
,
440 static struct nf_hook_ops ipv4_synproxy_ops
[] __read_mostly
= {
442 .hook
= ipv4_synproxy_hook
,
444 .hooknum
= NF_INET_LOCAL_IN
,
445 .priority
= NF_IP_PRI_CONNTRACK_CONFIRM
- 1,
448 .hook
= ipv4_synproxy_hook
,
450 .hooknum
= NF_INET_POST_ROUTING
,
451 .priority
= NF_IP_PRI_CONNTRACK_CONFIRM
- 1,
455 static int __init
synproxy_tg4_init(void)
459 err
= nf_register_hooks(ipv4_synproxy_ops
,
460 ARRAY_SIZE(ipv4_synproxy_ops
));
464 err
= xt_register_target(&synproxy_tg4_reg
);
471 nf_unregister_hooks(ipv4_synproxy_ops
, ARRAY_SIZE(ipv4_synproxy_ops
));
476 static void __exit
synproxy_tg4_exit(void)
478 xt_unregister_target(&synproxy_tg4_reg
);
479 nf_unregister_hooks(ipv4_synproxy_ops
, ARRAY_SIZE(ipv4_synproxy_ops
));
482 module_init(synproxy_tg4_init
);
483 module_exit(synproxy_tg4_exit
);
485 MODULE_LICENSE("GPL");
486 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");