2 * Syncookies implementation for the Linux kernel
4 * Copyright (C) 1997 Andi Kleen
5 * Based on ideas by D.J.Bernstein and Eric Schenk.
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
12 * $Id: syncookies.c,v 1.9 1999/08/23 06:30:34 davem Exp $
14 * Missing: IPv6 support.
17 #include <linux/config.h>
18 #if defined(CONFIG_SYN_COOKIES)
19 #include <linux/tcp.h>
20 #include <linux/malloc.h>
21 #include <linux/random.h>
24 extern int sysctl_tcp_syncookies
;
26 static unsigned long tcp_lastsynq_overflow
;
29 * This table has to be sorted and terminated with (__u16)-1.
30 * XXX generate a better table.
31 * Unresolved Issues: HIPPI with a 64k MSS is not well supported.
33 static __u16
const msstab
[] = {
44 /* The number doesn't include the -1 terminator */
45 #define NUM_MSS (sizeof(msstab)/sizeof(msstab[0]) - 1)
48 * Generate a syncookie. mssp points to the mss, which is returned
49 * rounded down to the value encoded in the cookie.
51 __u32
cookie_v4_init_sequence(struct sock
*sk
, struct sk_buff
*skb
,
55 const __u16 mss
= *mssp
;
57 tcp_lastsynq_overflow
= jiffies
;
58 /* XXX sort msstab[] by probability? Binary search? */
59 for (mssind
= 0; mss
> msstab
[mssind
+1]; mssind
++)
61 *mssp
= msstab
[mssind
]+1;
63 net_statistics
.SyncookiesSent
++;
65 return secure_tcp_syn_cookie(skb
->nh
.iph
->saddr
, skb
->nh
.iph
->daddr
,
66 skb
->h
.th
->source
, skb
->h
.th
->dest
,
67 ntohl(skb
->h
.th
->seq
),
68 jiffies
/ (HZ
*60), mssind
);
72 * This (misnamed) value is the age of syncookie which is permitted.
73 * Its ideal value should be dependent on TCP_TIMEOUT_INIT and
74 * sysctl_tcp_retries1. It's a rather complicated formula (exponential
75 * backoff) to compute at runtime so it's currently hardcoded here.
77 #define COUNTER_TRIES 4
79 * Check if a ack sequence number is a valid syncookie.
80 * Return the decoded mss if it is, or 0 if not.
82 static inline int cookie_check(struct sk_buff
*skb
, __u32 cookie
)
87 if ((jiffies
- tcp_lastsynq_overflow
) > TCP_TIMEOUT_INIT
)
90 seq
= ntohl(skb
->h
.th
->seq
)-1;
91 mssind
= check_tcp_syn_cookie(cookie
,
92 skb
->nh
.iph
->saddr
, skb
->nh
.iph
->daddr
,
93 skb
->h
.th
->source
, skb
->h
.th
->dest
,
94 seq
, jiffies
/(HZ
*60), COUNTER_TRIES
);
96 return mssind
< NUM_MSS
? msstab
[mssind
]+1 : 0;
99 extern struct or_calltable or_ipv4
;
101 static inline struct sock
*
102 get_cookie_sock(struct sock
*sk
, struct sk_buff
*skb
, struct open_request
*req
,
103 struct dst_entry
*dst
)
105 struct tcp_opt
*tp
= &sk
->tp_pinfo
.af_tcp
;
107 /* Oops! It was missing, syn_recv_sock decreases it. */
110 sk
= tp
->af_specific
->syn_recv_sock(sk
, skb
, req
, dst
);
114 /* Queue up for accept() */
115 tcp_synq_queue(tp
, req
);
118 req
->class->destructor(req
);
119 tcp_openreq_free(req
);
125 cookie_v4_check(struct sock
*sk
, struct sk_buff
*skb
, struct ip_options
*opt
)
127 __u32 cookie
= ntohl(skb
->h
.th
->ack_seq
)-1;
128 struct open_request
*req
;
133 if (!sysctl_tcp_syncookies
)
138 mss
= cookie_check(skb
, cookie
);
140 net_statistics
.SyncookiesFailed
++;
144 net_statistics
.SyncookiesRecv
++;
146 req
= tcp_openreq_alloc();
150 req
->rcv_isn
= htonl(skb
->h
.th
->seq
)-1;
151 req
->snt_isn
= cookie
;
153 req
->rmt_port
= skb
->h
.th
->source
;
154 req
->af
.v4_req
.loc_addr
= skb
->nh
.iph
->daddr
;
155 req
->af
.v4_req
.rmt_addr
= skb
->nh
.iph
->saddr
;
156 req
->class = &or_ipv4
; /* for savety */
158 req
->af
.v4_req
.opt
= NULL
;
160 /* We throwed the options of the initial SYN away, so we hope
161 * the ACK carries the same options again (see RFC1122 4.2.3.8)
163 if (opt
&& opt
->optlen
) {
164 int opt_size
= sizeof(struct ip_options
) + opt
->optlen
;
166 req
->af
.v4_req
.opt
= kmalloc(opt_size
, GFP_ATOMIC
);
167 if (req
->af
.v4_req
.opt
) {
168 if (ip_options_echo(req
->af
.v4_req
.opt
, skb
)) {
169 kfree_s(req
->af
.v4_req
.opt
, opt_size
);
170 req
->af
.v4_req
.opt
= NULL
;
175 req
->snd_wscale
= req
->rcv_wscale
= req
->tstamp_ok
= 0;
181 * We need to lookup the route here to get at the correct
182 * window size. We should better make sure that the window size
183 * hasn't changed since we received the original syn, but I see
184 * no easy way to do this.
186 if (ip_route_output(&rt
,
188 opt
->srr
? opt
->faddr
: req
->af
.v4_req
.rmt_addr
,
189 req
->af
.v4_req
.loc_addr
,
190 sk
->protinfo
.af_inet
.tos
| RTO_CONN
,
192 tcp_openreq_free(req
);
196 /* Try to redo what tcp_v4_send_synack did. */
197 req
->window_clamp
= rt
->u
.dst
.window
;
198 tcp_select_initial_window(tcp_full_space(sk
),req
->mss
,
199 &req
->rcv_wnd
, &req
->window_clamp
,
201 req
->rcv_wscale
= rcv_wscale
;
203 return get_cookie_sock(sk
, skb
, req
, &rt
->u
.dst
);