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