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 sk_buff
*skb
, u32 saddr
, u32 daddr
)
25 skb_reset_network_header(skb
);
26 iph
= (struct iphdr
*)skb_put(skb
, sizeof(*iph
));
28 iph
->ihl
= sizeof(*iph
) / 4;
31 iph
->frag_off
= htons(IP_DF
);
32 iph
->ttl
= sysctl_ip_default_ttl
;
33 iph
->protocol
= IPPROTO_TCP
;
42 synproxy_send_tcp(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
)
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
);
52 skb_dst_set_noref(nskb
, skb_dst(skb
));
53 nskb
->protocol
= htons(ETH_P_IP
);
54 if (ip_route_me_harder(nskb
, RTN_UNSPEC
))
59 nskb
->nfctinfo
= ctinfo
;
60 nf_conntrack_get(nfct
);
71 synproxy_send_client_synack(const struct sk_buff
*skb
, const struct tcphdr
*th
,
72 const struct synproxy_options
*opts
)
75 struct iphdr
*iph
, *niph
;
77 unsigned int tcp_hdr_size
;
82 tcp_hdr_size
= sizeof(*nth
) + synproxy_options_size(opts
);
83 nskb
= alloc_skb(sizeof(*niph
) + tcp_hdr_size
+ MAX_TCP_HEADER
,
87 skb_reserve(nskb
, MAX_TCP_HEADER
);
89 niph
= synproxy_build_ip(nskb
, iph
->daddr
, iph
->saddr
);
91 skb_reset_transport_header(nskb
);
92 nth
= (struct tcphdr
*)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;
105 synproxy_build_options(nth
, opts
);
107 synproxy_send_tcp(skb
, nskb
, skb
->nfct
, IP_CT_ESTABLISHED_REPLY
,
108 niph
, nth
, tcp_hdr_size
);
112 synproxy_send_server_syn(const struct synproxy_net
*snet
,
113 const struct sk_buff
*skb
, const struct tcphdr
*th
,
114 const struct synproxy_options
*opts
, u32 recv_seq
)
116 struct sk_buff
*nskb
;
117 struct iphdr
*iph
, *niph
;
119 unsigned int tcp_hdr_size
;
123 tcp_hdr_size
= sizeof(*nth
) + synproxy_options_size(opts
);
124 nskb
= alloc_skb(sizeof(*niph
) + tcp_hdr_size
+ MAX_TCP_HEADER
,
128 skb_reserve(nskb
, MAX_TCP_HEADER
);
130 niph
= synproxy_build_ip(nskb
, iph
->saddr
, iph
->daddr
);
132 skb_reset_transport_header(nskb
);
133 nth
= (struct tcphdr
*)skb_put(nskb
, tcp_hdr_size
);
134 nth
->source
= th
->source
;
135 nth
->dest
= th
->dest
;
136 nth
->seq
= htonl(recv_seq
- 1);
137 /* ack_seq is used to relay our ISN to the synproxy hook to initialize
138 * sequence number translation once a connection tracking entry exists.
140 nth
->ack_seq
= htonl(ntohl(th
->ack_seq
) - 1);
141 tcp_flag_word(nth
) = TCP_FLAG_SYN
;
142 if (opts
->options
& XT_SYNPROXY_OPT_ECN
)
143 tcp_flag_word(nth
) |= TCP_FLAG_ECE
| TCP_FLAG_CWR
;
144 nth
->doff
= tcp_hdr_size
/ 4;
145 nth
->window
= th
->window
;
149 synproxy_build_options(nth
, opts
);
151 synproxy_send_tcp(skb
, nskb
, &snet
->tmpl
->ct_general
, IP_CT_NEW
,
152 niph
, nth
, tcp_hdr_size
);
156 synproxy_send_server_ack(const struct synproxy_net
*snet
,
157 const struct ip_ct_tcp
*state
,
158 const struct sk_buff
*skb
, const struct tcphdr
*th
,
159 const struct synproxy_options
*opts
)
161 struct sk_buff
*nskb
;
162 struct iphdr
*iph
, *niph
;
164 unsigned int tcp_hdr_size
;
168 tcp_hdr_size
= sizeof(*nth
) + synproxy_options_size(opts
);
169 nskb
= alloc_skb(sizeof(*niph
) + tcp_hdr_size
+ MAX_TCP_HEADER
,
173 skb_reserve(nskb
, MAX_TCP_HEADER
);
175 niph
= synproxy_build_ip(nskb
, iph
->daddr
, iph
->saddr
);
177 skb_reset_transport_header(nskb
);
178 nth
= (struct tcphdr
*)skb_put(nskb
, tcp_hdr_size
);
179 nth
->source
= th
->dest
;
180 nth
->dest
= th
->source
;
181 nth
->seq
= htonl(ntohl(th
->ack_seq
));
182 nth
->ack_seq
= htonl(ntohl(th
->seq
) + 1);
183 tcp_flag_word(nth
) = TCP_FLAG_ACK
;
184 nth
->doff
= tcp_hdr_size
/ 4;
185 nth
->window
= htons(state
->seen
[IP_CT_DIR_ORIGINAL
].td_maxwin
);
189 synproxy_build_options(nth
, opts
);
191 synproxy_send_tcp(skb
, nskb
, NULL
, 0, niph
, nth
, tcp_hdr_size
);
195 synproxy_send_client_ack(const struct synproxy_net
*snet
,
196 const struct sk_buff
*skb
, const struct tcphdr
*th
,
197 const struct synproxy_options
*opts
)
199 struct sk_buff
*nskb
;
200 struct iphdr
*iph
, *niph
;
202 unsigned int tcp_hdr_size
;
206 tcp_hdr_size
= sizeof(*nth
) + synproxy_options_size(opts
);
207 nskb
= alloc_skb(sizeof(*niph
) + tcp_hdr_size
+ MAX_TCP_HEADER
,
211 skb_reserve(nskb
, MAX_TCP_HEADER
);
213 niph
= synproxy_build_ip(nskb
, iph
->saddr
, iph
->daddr
);
215 skb_reset_transport_header(nskb
);
216 nth
= (struct tcphdr
*)skb_put(nskb
, tcp_hdr_size
);
217 nth
->source
= th
->source
;
218 nth
->dest
= th
->dest
;
219 nth
->seq
= htonl(ntohl(th
->seq
) + 1);
220 nth
->ack_seq
= th
->ack_seq
;
221 tcp_flag_word(nth
) = TCP_FLAG_ACK
;
222 nth
->doff
= tcp_hdr_size
/ 4;
223 nth
->window
= ntohs(htons(th
->window
) >> opts
->wscale
);
227 synproxy_build_options(nth
, opts
);
229 synproxy_send_tcp(skb
, nskb
, NULL
, 0, niph
, nth
, tcp_hdr_size
);
233 synproxy_recv_client_ack(const struct synproxy_net
*snet
,
234 const struct sk_buff
*skb
, const struct tcphdr
*th
,
235 struct synproxy_options
*opts
, u32 recv_seq
)
239 mss
= __cookie_v4_check(ip_hdr(skb
), th
, ntohl(th
->ack_seq
) - 1);
241 this_cpu_inc(snet
->stats
->cookie_invalid
);
245 this_cpu_inc(snet
->stats
->cookie_valid
);
247 opts
->options
|= XT_SYNPROXY_OPT_MSS
;
249 if (opts
->options
& XT_SYNPROXY_OPT_TIMESTAMP
)
250 synproxy_check_timestamp_cookie(opts
);
252 synproxy_send_server_syn(snet
, skb
, th
, opts
, recv_seq
);
257 synproxy_tg4(struct sk_buff
*skb
, const struct xt_action_param
*par
)
259 const struct xt_synproxy_info
*info
= par
->targinfo
;
260 struct synproxy_net
*snet
= synproxy_pernet(dev_net(par
->in
));
261 struct synproxy_options opts
= {};
262 struct tcphdr
*th
, _th
;
264 if (nf_ip_checksum(skb
, par
->hooknum
, par
->thoff
, IPPROTO_TCP
))
267 th
= skb_header_pointer(skb
, par
->thoff
, sizeof(_th
), &_th
);
271 if (!synproxy_parse_options(skb
, par
->thoff
, th
, &opts
))
274 if (th
->syn
&& !(th
->ack
|| th
->fin
|| th
->rst
)) {
275 /* Initial SYN from client */
276 this_cpu_inc(snet
->stats
->syn_received
);
278 if (th
->ece
&& th
->cwr
)
279 opts
.options
|= XT_SYNPROXY_OPT_ECN
;
281 opts
.options
&= info
->options
;
282 if (opts
.options
& XT_SYNPROXY_OPT_TIMESTAMP
)
283 synproxy_init_timestamp_cookie(info
, &opts
);
285 opts
.options
&= ~(XT_SYNPROXY_OPT_WSCALE
|
286 XT_SYNPROXY_OPT_SACK_PERM
|
287 XT_SYNPROXY_OPT_ECN
);
289 synproxy_send_client_synack(skb
, th
, &opts
);
292 } else if (th
->ack
&& !(th
->fin
|| th
->rst
|| th
->syn
)) {
293 /* ACK from client */
294 synproxy_recv_client_ack(snet
, skb
, th
, &opts
, ntohl(th
->seq
));
301 static unsigned int ipv4_synproxy_hook(const struct nf_hook_ops
*ops
,
303 const struct net_device
*in
,
304 const struct net_device
*out
,
305 int (*okfn
)(struct sk_buff
*))
307 struct synproxy_net
*snet
= synproxy_pernet(dev_net(in
? : out
));
308 enum ip_conntrack_info ctinfo
;
310 struct nf_conn_synproxy
*synproxy
;
311 struct synproxy_options opts
= {};
312 const struct ip_ct_tcp
*state
;
313 struct tcphdr
*th
, _th
;
316 ct
= nf_ct_get(skb
, &ctinfo
);
320 synproxy
= nfct_synproxy(ct
);
321 if (synproxy
== NULL
)
324 if (nf_is_loopback_packet(skb
))
327 thoff
= ip_hdrlen(skb
);
328 th
= skb_header_pointer(skb
, thoff
, sizeof(_th
), &_th
);
332 state
= &ct
->proto
.tcp
;
333 switch (state
->state
) {
334 case TCP_CONNTRACK_CLOSE
:
335 if (th
->rst
&& !test_bit(IPS_SEEN_REPLY_BIT
, &ct
->status
)) {
336 nf_ct_seqadj_init(ct
, ctinfo
, synproxy
->isn
-
341 if (!th
->syn
|| th
->ack
||
342 CTINFO2DIR(ctinfo
) != IP_CT_DIR_ORIGINAL
)
345 /* Reopened connection - reset the sequence number and timestamp
346 * adjustments, they will get initialized once the connection is
349 nf_ct_seqadj_init(ct
, ctinfo
, 0);
351 this_cpu_inc(snet
->stats
->conn_reopened
);
354 case TCP_CONNTRACK_SYN_SENT
:
355 if (!synproxy_parse_options(skb
, thoff
, th
, &opts
))
358 if (!th
->syn
&& th
->ack
&&
359 CTINFO2DIR(ctinfo
) == IP_CT_DIR_ORIGINAL
) {
360 /* Keep-Alives are sent with SEG.SEQ = SND.NXT-1,
361 * therefore we need to add 1 to make the SYN sequence
362 * number match the one of first SYN.
364 if (synproxy_recv_client_ack(snet
, skb
, th
, &opts
,
366 this_cpu_inc(snet
->stats
->cookie_retrans
);
371 synproxy
->isn
= ntohl(th
->ack_seq
);
372 if (opts
.options
& XT_SYNPROXY_OPT_TIMESTAMP
)
373 synproxy
->its
= opts
.tsecr
;
375 case TCP_CONNTRACK_SYN_RECV
:
376 if (!th
->syn
|| !th
->ack
)
379 if (!synproxy_parse_options(skb
, thoff
, th
, &opts
))
382 if (opts
.options
& XT_SYNPROXY_OPT_TIMESTAMP
)
383 synproxy
->tsoff
= opts
.tsval
- synproxy
->its
;
385 opts
.options
&= ~(XT_SYNPROXY_OPT_MSS
|
386 XT_SYNPROXY_OPT_WSCALE
|
387 XT_SYNPROXY_OPT_SACK_PERM
);
389 swap(opts
.tsval
, opts
.tsecr
);
390 synproxy_send_server_ack(snet
, state
, skb
, th
, &opts
);
392 nf_ct_seqadj_init(ct
, ctinfo
, synproxy
->isn
- ntohl(th
->seq
));
394 swap(opts
.tsval
, opts
.tsecr
);
395 synproxy_send_client_ack(snet
, skb
, th
, &opts
);
403 synproxy_tstamp_adjust(skb
, thoff
, th
, ct
, ctinfo
, synproxy
);
407 static int synproxy_tg4_check(const struct xt_tgchk_param
*par
)
409 const struct ipt_entry
*e
= par
->entryinfo
;
411 if (e
->ip
.proto
!= IPPROTO_TCP
||
412 e
->ip
.invflags
& XT_INV_PROTO
)
415 return nf_ct_l3proto_try_module_get(par
->family
);
418 static void synproxy_tg4_destroy(const struct xt_tgdtor_param
*par
)
420 nf_ct_l3proto_module_put(par
->family
);
423 static struct xt_target synproxy_tg4_reg __read_mostly
= {
425 .family
= NFPROTO_IPV4
,
426 .target
= synproxy_tg4
,
427 .targetsize
= sizeof(struct xt_synproxy_info
),
428 .checkentry
= synproxy_tg4_check
,
429 .destroy
= synproxy_tg4_destroy
,
433 static struct nf_hook_ops ipv4_synproxy_ops
[] __read_mostly
= {
435 .hook
= ipv4_synproxy_hook
,
436 .owner
= THIS_MODULE
,
438 .hooknum
= NF_INET_LOCAL_IN
,
439 .priority
= NF_IP_PRI_CONNTRACK_CONFIRM
- 1,
442 .hook
= ipv4_synproxy_hook
,
443 .owner
= THIS_MODULE
,
445 .hooknum
= NF_INET_POST_ROUTING
,
446 .priority
= NF_IP_PRI_CONNTRACK_CONFIRM
- 1,
450 static int __init
synproxy_tg4_init(void)
454 err
= nf_register_hooks(ipv4_synproxy_ops
,
455 ARRAY_SIZE(ipv4_synproxy_ops
));
459 err
= xt_register_target(&synproxy_tg4_reg
);
466 nf_unregister_hooks(ipv4_synproxy_ops
, ARRAY_SIZE(ipv4_synproxy_ops
));
471 static void __exit
synproxy_tg4_exit(void)
473 xt_unregister_target(&synproxy_tg4_reg
);
474 nf_unregister_hooks(ipv4_synproxy_ops
, ARRAY_SIZE(ipv4_synproxy_ops
));
477 module_init(synproxy_tg4_init
);
478 module_exit(synproxy_tg4_exit
);
480 MODULE_LICENSE("GPL");
481 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");