ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / net / ipv4 / netfilter / ip_conntrack_proto_tcp.c
1 /* (C) 1999-2001 Paul `Rusty' Russell
2  * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
3  *
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.
7  */
8
9 #include <linux/types.h>
10 #include <linux/sched.h>
11 #include <linux/timer.h>
12 #include <linux/netfilter.h>
13 #include <linux/module.h>
14 #include <linux/in.h>
15 #include <linux/ip.h>
16 #include <linux/tcp.h>
17 #include <linux/string.h>
18
19 #include <net/tcp.h>
20
21 #include <linux/netfilter_ipv4/ip_conntrack.h>
22 #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
23 #include <linux/netfilter_ipv4/lockhelp.h>
24
25 #if 0
26 #define DEBUGP printk
27 #else
28 #define DEBUGP(format, args...)
29 #endif
30
31 /* Protects conntrack->proto.tcp */
32 static DECLARE_RWLOCK(tcp_lock);
33
34 /* FIXME: Examine ipfilter's timeouts and conntrack transitions more
35    closely.  They're more complex. --RR */
36
37 /* Actually, I believe that neither ipmasq (where this code is stolen
38    from) nor ipfilter do it exactly right.  A new conntrack machine taking
39    into account packet loss (which creates uncertainty as to exactly
40    the conntrack of the connection) is required.  RSN.  --RR */
41
42 static const char *tcp_conntrack_names[] = {
43         "NONE",
44         "ESTABLISHED",
45         "SYN_SENT",
46         "SYN_RECV",
47         "FIN_WAIT",
48         "TIME_WAIT",
49         "CLOSE",
50         "CLOSE_WAIT",
51         "LAST_ACK",
52         "LISTEN"
53 };
54
55 #define SECS *HZ
56 #define MINS * 60 SECS
57 #define HOURS * 60 MINS
58 #define DAYS * 24 HOURS
59
60 unsigned long ip_ct_tcp_timeout_syn_sent =      2 MINS;
61 unsigned long ip_ct_tcp_timeout_syn_recv =     60 SECS;
62 unsigned long ip_ct_tcp_timeout_established =   5 DAYS;
63 unsigned long ip_ct_tcp_timeout_fin_wait =      2 MINS;
64 unsigned long ip_ct_tcp_timeout_close_wait =   60 SECS;
65 unsigned long ip_ct_tcp_timeout_last_ack =     30 SECS;
66 unsigned long ip_ct_tcp_timeout_time_wait =     2 MINS;
67 unsigned long ip_ct_tcp_timeout_close =        10 SECS;
68
69 static unsigned long * tcp_timeouts[]
70 = { 0,                                 /*      TCP_CONNTRACK_NONE */
71     &ip_ct_tcp_timeout_established,    /*      TCP_CONNTRACK_ESTABLISHED,      */
72     &ip_ct_tcp_timeout_syn_sent,       /*      TCP_CONNTRACK_SYN_SENT, */
73     &ip_ct_tcp_timeout_syn_recv,       /*      TCP_CONNTRACK_SYN_RECV, */
74     &ip_ct_tcp_timeout_fin_wait,       /*      TCP_CONNTRACK_FIN_WAIT, */
75     &ip_ct_tcp_timeout_time_wait,      /*      TCP_CONNTRACK_TIME_WAIT,        */
76     &ip_ct_tcp_timeout_close,          /*      TCP_CONNTRACK_CLOSE,    */
77     &ip_ct_tcp_timeout_close_wait,     /*      TCP_CONNTRACK_CLOSE_WAIT,       */
78     &ip_ct_tcp_timeout_last_ack,       /*      TCP_CONNTRACK_LAST_ACK, */
79     0,                                 /*      TCP_CONNTRACK_LISTEN */
80  };
81  
82 #define sNO TCP_CONNTRACK_NONE
83 #define sES TCP_CONNTRACK_ESTABLISHED
84 #define sSS TCP_CONNTRACK_SYN_SENT
85 #define sSR TCP_CONNTRACK_SYN_RECV
86 #define sFW TCP_CONNTRACK_FIN_WAIT
87 #define sTW TCP_CONNTRACK_TIME_WAIT
88 #define sCL TCP_CONNTRACK_CLOSE
89 #define sCW TCP_CONNTRACK_CLOSE_WAIT
90 #define sLA TCP_CONNTRACK_LAST_ACK
91 #define sLI TCP_CONNTRACK_LISTEN
92 #define sIV TCP_CONNTRACK_MAX
93
94 static enum tcp_conntrack tcp_conntracks[2][5][TCP_CONNTRACK_MAX] = {
95         {
96 /*      ORIGINAL */
97 /*        sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI      */
98 /*syn*/ {sSS, sES, sSS, sSR, sSS, sSS, sSS, sSS, sSS, sLI },
99 /*fin*/ {sTW, sFW, sSS, sTW, sFW, sTW, sCL, sTW, sLA, sLI },
100 /*ack*/ {sES, sES, sSS, sES, sFW, sTW, sCL, sCW, sLA, sES },
101 /*rst*/ {sCL, sCL, sSS, sCL, sCL, sTW, sCL, sCL, sCL, sCL },
102 /*none*/{sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV }
103         },
104         {
105 /*      REPLY */
106 /*        sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI      */
107 /*syn*/ {sSR, sES, sSR, sSR, sSR, sSR, sSR, sSR, sSR, sSR },
108 /*fin*/ {sCL, sCW, sSS, sTW, sTW, sTW, sCL, sCW, sLA, sLI },
109 /*ack*/ {sCL, sES, sSS, sSR, sFW, sTW, sCL, sCW, sCL, sLI },
110 /*rst*/ {sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sLA, sLI },
111 /*none*/{sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV }
112         }
113 };
114
115 static int tcp_pkt_to_tuple(const struct sk_buff *skb,
116                              unsigned int dataoff,
117                              struct ip_conntrack_tuple *tuple)
118 {
119         struct tcphdr hdr;
120
121         /* Actually only need first 8 bytes. */
122         if (skb_copy_bits(skb, dataoff, &hdr, 8) != 0)
123                 return 0;
124
125         tuple->src.u.tcp.port = hdr.source;
126         tuple->dst.u.tcp.port = hdr.dest;
127
128         return 1;
129 }
130
131 static int tcp_invert_tuple(struct ip_conntrack_tuple *tuple,
132                             const struct ip_conntrack_tuple *orig)
133 {
134         tuple->src.u.tcp.port = orig->dst.u.tcp.port;
135         tuple->dst.u.tcp.port = orig->src.u.tcp.port;
136         return 1;
137 }
138
139 /* Print out the per-protocol part of the tuple. */
140 static unsigned int tcp_print_tuple(char *buffer,
141                                     const struct ip_conntrack_tuple *tuple)
142 {
143         return sprintf(buffer, "sport=%hu dport=%hu ",
144                        ntohs(tuple->src.u.tcp.port),
145                        ntohs(tuple->dst.u.tcp.port));
146 }
147
148 /* Print out the private part of the conntrack. */
149 static unsigned int tcp_print_conntrack(char *buffer,
150                                         const struct ip_conntrack *conntrack)
151 {
152         enum tcp_conntrack state;
153
154         READ_LOCK(&tcp_lock);
155         state = conntrack->proto.tcp.state;
156         READ_UNLOCK(&tcp_lock);
157
158         return sprintf(buffer, "%s ", tcp_conntrack_names[state]);
159 }
160
161 static unsigned int get_conntrack_index(const struct tcphdr *tcph)
162 {
163         if (tcph->rst) return 3;
164         else if (tcph->syn) return 0;
165         else if (tcph->fin) return 1;
166         else if (tcph->ack) return 2;
167         else return 4;
168 }
169
170 /* Returns verdict for packet, or -1 for invalid. */
171 static int tcp_packet(struct ip_conntrack *conntrack,
172                       const struct sk_buff *skb,
173                       enum ip_conntrack_info ctinfo)
174 {
175         enum tcp_conntrack newconntrack, oldtcpstate;
176         struct tcphdr tcph;
177
178         if (skb_copy_bits(skb, skb->nh.iph->ihl * 4, &tcph, sizeof(tcph)) != 0)
179                 return -1;
180
181         /* If only reply is a RST, we can consider ourselves not to
182            have an established connection: this is a fairly common
183            problem case, so we can delete the conntrack
184            immediately.  --RR */
185         if (!test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status) && tcph.rst) {
186                 if (del_timer(&conntrack->timeout))
187                         conntrack->timeout.function((unsigned long)conntrack);
188                 return NF_ACCEPT;
189         }
190
191         WRITE_LOCK(&tcp_lock);
192         oldtcpstate = conntrack->proto.tcp.state;
193         newconntrack
194                 = tcp_conntracks
195                 [CTINFO2DIR(ctinfo)]
196                 [get_conntrack_index(&tcph)][oldtcpstate];
197
198         /* Invalid */
199         if (newconntrack == TCP_CONNTRACK_MAX) {
200                 DEBUGP("ip_conntrack_tcp: Invalid dir=%i index=%u conntrack=%u\n",
201                        CTINFO2DIR(ctinfo), get_conntrack_index(&tcph),
202                        conntrack->proto.tcp.state);
203                 WRITE_UNLOCK(&tcp_lock);
204                 return -1;
205         }
206
207         conntrack->proto.tcp.state = newconntrack;
208
209         /* Poor man's window tracking: record SYN/ACK for handshake check */
210         if (oldtcpstate == TCP_CONNTRACK_SYN_SENT
211             && CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY
212             && tcph.syn && tcph.ack) {
213                 conntrack->proto.tcp.handshake_ack
214                         = htonl(ntohl(tcph.seq) + 1);
215                 goto out;
216         }
217
218         /* Set ASSURED if we see valid ack in ESTABLISHED after SYN_RECV */
219         if (oldtcpstate == TCP_CONNTRACK_SYN_RECV
220             && CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL
221             && tcph.ack && !tcph.syn
222             && tcph.ack_seq == conntrack->proto.tcp.handshake_ack)
223                 set_bit(IPS_ASSURED_BIT, &conntrack->status);
224
225 out:    WRITE_UNLOCK(&tcp_lock);
226         ip_ct_refresh(conntrack, *tcp_timeouts[newconntrack]);
227
228         return NF_ACCEPT;
229 }
230
231 /* Called when a new connection for this protocol found. */
232 static int tcp_new(struct ip_conntrack *conntrack, const struct sk_buff *skb)
233 {
234         enum tcp_conntrack newconntrack;
235         struct tcphdr tcph;
236
237         if (skb_copy_bits(skb, skb->nh.iph->ihl * 4, &tcph, sizeof(tcph)) != 0)
238                 return -1;
239
240         /* Don't need lock here: this conntrack not in circulation yet */
241         newconntrack
242                 = tcp_conntracks[0][get_conntrack_index(&tcph)]
243                 [TCP_CONNTRACK_NONE];
244
245         /* Invalid: delete conntrack */
246         if (newconntrack == TCP_CONNTRACK_MAX) {
247                 DEBUGP("ip_conntrack_tcp: invalid new deleting.\n");
248                 return 0;
249         }
250
251         conntrack->proto.tcp.state = newconntrack;
252         return 1;
253 }
254
255 static int tcp_exp_matches_pkt(struct ip_conntrack_expect *exp,
256                                const struct sk_buff *skb)
257 {
258         const struct iphdr *iph = skb->nh.iph;
259         struct tcphdr tcph;
260         unsigned int datalen;
261
262         if (skb_copy_bits(skb, skb->nh.iph->ihl * 4, &tcph, sizeof(tcph)) != 0)
263                 return 0;
264         datalen = skb->len - iph->ihl*4 - tcph.doff*4;
265
266         return between(exp->seq, ntohl(tcph.seq), ntohl(tcph.seq) + datalen);
267 }
268
269 struct ip_conntrack_protocol ip_conntrack_protocol_tcp
270 = { { NULL, NULL }, IPPROTO_TCP, "tcp",
271     tcp_pkt_to_tuple, tcp_invert_tuple, tcp_print_tuple, tcp_print_conntrack,
272     tcp_packet, tcp_new, NULL, tcp_exp_matches_pkt, NULL };