00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
#include <linux/tcp.h>
00018
#include <linux/slab.h>
00019
#include <linux/random.h>
00020
#include <net/tcp.h>
00021
00022
extern int sysctl_tcp_syncookies;
00023
00024
00025
00026
00027
00028
00029 static __u16
const msstab[] = {
00030 64 - 1,
00031 256 - 1,
00032 512 - 1,
00033 536 - 1,
00034 1024 - 1,
00035 1440 - 1,
00036 1460 - 1,
00037 4312 - 1,
00038 (__u16)-1
00039 };
00040
00041 #define NUM_MSS (sizeof(msstab)/sizeof(msstab[0]) - 1)
00042
00043
00044
00045
00046
00047 __u32
cookie_v4_init_sequence(
struct sock *sk,
struct sk_buff *skb, __u16 *mssp)
00048 {
00049
int mssind;
00050
const __u16 mss = *mssp;
00051
00052
00053 sk->
tp_pinfo.af_tcp.last_synq_overflow = jiffies;
00054
00055
00056
for (mssind = 0; mss >
msstab[mssind + 1]; mssind++)
00057 ;
00058 *mssp =
msstab[mssind] + 1;
00059
00060
NET_INC_STATS_BH(SyncookiesSent);
00061
00062
return secure_tcp_syn_cookie(skb->
nh.iph->saddr, skb->
nh.iph->daddr,
00063 skb->
h.th->source, skb->
h.th->dest,
00064 ntohl(skb->
h.th->seq),
00065 jiffies / (HZ * 60), mssind);
00066 }
00067
00068
00069
00070
00071
00072
00073
00074 #define COUNTER_TRIES 4
00075
00076
00077
00078
00079 static inline int cookie_check(
struct sk_buff *skb, __u32 cookie)
00080 {
00081 __u32 seq;
00082 __u32 mssind;
00083
00084 seq = ntohl(skb->
h.th->seq)-1;
00085 mssind = check_tcp_syn_cookie(cookie,
00086 skb->
nh.iph->saddr, skb->
nh.iph->daddr,
00087 skb->
h.th->source, skb->
h.th->dest,
00088 seq, jiffies / (HZ * 60),
COUNTER_TRIES);
00089
00090
return mssind <
NUM_MSS ?
msstab[mssind] + 1 : 0;
00091 }
00092
00093
extern struct or_calltable or_ipv4;
00094
00095 static inline struct sock *
get_cookie_sock(
struct sock *sk,
struct sk_buff *skb,
00096
struct open_request *req,
00097
struct dst_entry *dst)
00098 {
00099
struct tcp_opt *tp = &(sk->
tp_pinfo.af_tcp);
00100
struct sock *child;
00101
00102 child = tp->af_specific->syn_recv_sock(sk, skb, req, dst);
00103
if (child)
00104
tcp_acceptq_queue(sk, req, child);
00105
else
00106
tcp_openreq_free(req);
00107
00108
return child;
00109 }
00110
00111 struct sock *
cookie_v4_check(
struct sock *sk,
struct sk_buff *skb,
00112
struct ip_options *opt)
00113 {
00114 __u32 cookie = ntohl(skb->
h.th->ack_seq) - 1;
00115
struct sock *ret = sk;
00116
struct open_request *req;
00117
int mss;
00118
struct rtable *rt;
00119 __u8 rcv_wscale;
00120
00121
if (!
sysctl_tcp_syncookies || !skb->
h.th->ack)
00122
goto out;
00123
00124
if (time_after(jiffies, sk->tp_pinfo.af_tcp.last_synq_overflow +
TCP_TIMEOUT_INIT) ||
00125 (mss =
cookie_check(skb, cookie)) == 0) {
00126
NET_INC_STATS_BH(SyncookiesFailed);
00127
goto out;
00128 }
00129
00130
NET_INC_STATS_BH(SyncookiesRecv);
00131
00132 req =
tcp_openreq_alloc();
00133 ret = NULL;
00134
if (!req)
00135
goto out;
00136
00137 req->rcv_isn = htonl(skb->
h.th->seq) - 1;
00138 req->snt_isn = cookie;
00139 req->mss = mss;
00140 req->rmt_port = skb->
h.th->source;
00141 req->af.v4_req.loc_addr = skb->
nh.iph->daddr;
00142 req->af.v4_req.rmt_addr = skb->
nh.iph->saddr;
00143 req->class = &
or_ipv4;
00144 req->af.v4_req.opt = NULL;
00145
00146
00147
00148
00149
if (opt && opt->
optlen) {
00150
int opt_size =
sizeof(
struct ip_options) + opt->optlen;
00151
00152 req->af.v4_req.opt = kmalloc(opt_size, GFP_ATOMIC);
00153
if (req->af.v4_req.opt) {
00154
if (
ip_options_echo(req->af.v4_req.opt, skb)) {
00155 kfree(req->af.v4_req.opt);
00156 req->af.v4_req.opt = NULL;
00157 }
00158 }
00159 }
00160
00161 req->snd_wscale = req->rcv_wscale = req->tstamp_ok = 0;
00162 req->wscale_ok = req->sack_ok = 0;
00163 req->expires = 0UL;
00164 req->retrans = 0;
00165
00166
00167
00168
00169
00170
00171
00172
if (
ip_route_output(&rt,
00173 opt &&
00174 opt->
srr ? opt->
faddr : req->af.v4_req.rmt_addr,
00175 req->af.v4_req.loc_addr,
00176
RT_CONN_FLAGS(sk),
00177 0)) {
00178
tcp_openreq_free(req);
00179
goto out;
00180 }
00181
00182
00183 req->window_clamp = rt->u.dst.window;
00184
tcp_select_initial_window(
tcp_full_space(sk), req->mss,
00185 &req->rcv_wnd, &req->window_clamp,
00186 0, &rcv_wscale);
00187
00188 req->rcv_wscale = rcv_wscale;
00189
00190 ret =
get_cookie_sock(sk, skb, req, &rt->u.
dst);
00191 out:
return ret;
00192 }