ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / net / ipv4 / syncookies.c
1 /*
2  *  Syncookies implementation for the Linux kernel
3  *
4  *  Copyright (C) 1997 Andi Kleen
5  *  Based on ideas by D.J.Bernstein and Eric Schenk. 
6  *
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.
11  * 
12  *  $Id: syncookies.c,v 1.18 2002/02/01 22:01:04 davem Exp $
13  *
14  *  Missing: IPv6 support. 
15  */
16
17 #include <linux/tcp.h>
18 #include <linux/slab.h>
19 #include <linux/random.h>
20 #include <linux/kernel.h>
21 #include <net/tcp.h>
22
23 extern int sysctl_tcp_syncookies;
24
25 /* 
26  * This table has to be sorted and terminated with (__u16)-1.
27  * XXX generate a better table.
28  * Unresolved Issues: HIPPI with a 64k MSS is not well supported.
29  */
30 static __u16 const msstab[] = {
31         64 - 1,
32         256 - 1,        
33         512 - 1,
34         536 - 1,
35         1024 - 1,       
36         1440 - 1,
37         1460 - 1,
38         4312 - 1,
39         (__u16)-1
40 };
41 /* The number doesn't include the -1 terminator */
42 #define NUM_MSS (ARRAY_SIZE(msstab) - 1)
43
44 /*
45  * Generate a syncookie.  mssp points to the mss, which is returned
46  * rounded down to the value encoded in the cookie.
47  */
48 __u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp)
49 {
50         struct tcp_opt *tp = tcp_sk(sk);
51         int mssind;
52         const __u16 mss = *mssp;
53
54         
55         tp->last_synq_overflow = jiffies;
56
57         /* XXX sort msstab[] by probability?  Binary search? */
58         for (mssind = 0; mss > msstab[mssind + 1]; mssind++)
59                 ;
60         *mssp = msstab[mssind] + 1;
61
62         NET_INC_STATS_BH(SyncookiesSent);
63
64         return secure_tcp_syn_cookie(skb->nh.iph->saddr, skb->nh.iph->daddr,
65                                      skb->h.th->source, skb->h.th->dest,
66                                      ntohl(skb->h.th->seq),
67                                      jiffies / (HZ * 60), mssind);
68 }
69
70 /* 
71  * This (misnamed) value is the age of syncookie which is permitted.
72  * Its ideal value should be dependent on TCP_TIMEOUT_INIT and
73  * sysctl_tcp_retries1. It's a rather complicated formula (exponential
74  * backoff) to compute at runtime so it's currently hardcoded here.
75  */
76 #define COUNTER_TRIES 4
77 /*  
78  * Check if a ack sequence number is a valid syncookie. 
79  * Return the decoded mss if it is, or 0 if not.
80  */
81 static inline int cookie_check(struct sk_buff *skb, __u32 cookie)
82 {
83         __u32 seq; 
84         __u32 mssind;
85
86         seq = ntohl(skb->h.th->seq)-1; 
87         mssind = check_tcp_syn_cookie(cookie,
88                                       skb->nh.iph->saddr, skb->nh.iph->daddr,
89                                       skb->h.th->source, skb->h.th->dest,
90                                       seq, jiffies / (HZ * 60), COUNTER_TRIES);
91
92         return mssind < NUM_MSS ? msstab[mssind] + 1 : 0;
93 }
94
95 extern struct or_calltable or_ipv4;
96
97 static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb,
98                                            struct open_request *req,
99                                            struct dst_entry *dst)
100 {
101         struct tcp_opt *tp = tcp_sk(sk);
102         struct sock *child;
103
104         child = tp->af_specific->syn_recv_sock(sk, skb, req, dst);
105         if (child) {
106                 sk_set_owner(child, sk->sk_owner);
107                 tcp_acceptq_queue(sk, req, child);
108         } else
109                 tcp_openreq_free(req);
110
111         return child;
112 }
113
114 struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
115                              struct ip_options *opt)
116 {
117         struct tcp_opt *tp = tcp_sk(sk);
118         __u32 cookie = ntohl(skb->h.th->ack_seq) - 1; 
119         struct sock *ret = sk;
120         struct open_request *req; 
121         int mss; 
122         struct rtable *rt; 
123         __u8 rcv_wscale;
124
125         if (!sysctl_tcp_syncookies || !skb->h.th->ack)
126                 goto out;
127
128         if (time_after(jiffies, tp->last_synq_overflow + TCP_TIMEOUT_INIT) ||
129             (mss = cookie_check(skb, cookie)) == 0) {
130                 NET_INC_STATS_BH(SyncookiesFailed);
131                 goto out;
132         }
133
134         NET_INC_STATS_BH(SyncookiesRecv);
135
136         req = tcp_openreq_alloc();
137         ret = NULL;
138         if (!req)
139                 goto out;
140
141         req->rcv_isn            = htonl(skb->h.th->seq) - 1;
142         req->snt_isn            = cookie; 
143         req->mss                = mss;
144         req->rmt_port           = skb->h.th->source;
145         req->af.v4_req.loc_addr = skb->nh.iph->daddr;
146         req->af.v4_req.rmt_addr = skb->nh.iph->saddr;
147         req->class              = &or_ipv4; /* for savety */
148         req->af.v4_req.opt      = NULL;
149
150         /* We throwed the options of the initial SYN away, so we hope
151          * the ACK carries the same options again (see RFC1122 4.2.3.8)
152          */
153         if (opt && opt->optlen) {
154                 int opt_size = sizeof(struct ip_options) + opt->optlen;
155
156                 req->af.v4_req.opt = kmalloc(opt_size, GFP_ATOMIC);
157                 if (req->af.v4_req.opt) {
158                         if (ip_options_echo(req->af.v4_req.opt, skb)) {
159                                 kfree(req->af.v4_req.opt);
160                                 req->af.v4_req.opt = NULL;
161                         }
162                 }
163         }
164
165         req->snd_wscale = req->rcv_wscale = req->tstamp_ok = 0;
166         req->wscale_ok  = req->sack_ok = 0; 
167         req->expires    = 0UL; 
168         req->retrans    = 0; 
169         
170         /*
171          * We need to lookup the route here to get at the correct
172          * window size. We should better make sure that the window size
173          * hasn't changed since we received the original syn, but I see
174          * no easy way to do this. 
175          */
176         {
177                 struct flowi fl = { .nl_u = { .ip4_u =
178                                               { .daddr = ((opt && opt->srr) ?
179                                                           opt->faddr :
180                                                           req->af.v4_req.rmt_addr),
181                                                 .saddr = req->af.v4_req.loc_addr,
182                                                 .tos = RT_CONN_FLAGS(sk) } },
183                                     .proto = IPPROTO_TCP,
184                                     .uli_u = { .ports =
185                                                { .sport = skb->h.th->dest,
186                                                  .dport = skb->h.th->source } } };
187                 if (ip_route_output_key(&rt, &fl)) {
188                         tcp_openreq_free(req);
189                         goto out; 
190                 }
191         }
192
193         /* Try to redo what tcp_v4_send_synack did. */
194         req->window_clamp = dst_metric(&rt->u.dst, RTAX_WINDOW);
195         tcp_select_initial_window(tcp_full_space(sk), req->mss,
196                                   &req->rcv_wnd, &req->window_clamp, 
197                                   0, &rcv_wscale);
198         /* BTW win scale with syncookies is 0 by definition */
199         req->rcv_wscale   = rcv_wscale; 
200
201         ret = get_cookie_sock(sk, skb, req, &rt->u.dst);
202 out:    return ret;
203 }