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