Root/
1 | /* SANE connection tracking helper |
2 | * (SANE = Scanner Access Now Easy) |
3 | * For documentation about the SANE network protocol see |
4 | * http://www.sane-project.org/html/doc015.html |
5 | */ |
6 | |
7 | /* Copyright (C) 2007 Red Hat, Inc. |
8 | * Author: Michal Schmidt <mschmidt@redhat.com> |
9 | * Based on the FTP conntrack helper (net/netfilter/nf_conntrack_ftp.c): |
10 | * (C) 1999-2001 Paul `Rusty' Russell |
11 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> |
12 | * (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org> |
13 | * (C) 2003 Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> |
14 | * |
15 | * This program is free software; you can redistribute it and/or modify |
16 | * it under the terms of the GNU General Public License version 2 as |
17 | * published by the Free Software Foundation. |
18 | */ |
19 | |
20 | #include <linux/module.h> |
21 | #include <linux/moduleparam.h> |
22 | #include <linux/netfilter.h> |
23 | #include <linux/slab.h> |
24 | #include <linux/in.h> |
25 | #include <linux/tcp.h> |
26 | #include <net/netfilter/nf_conntrack.h> |
27 | #include <net/netfilter/nf_conntrack_helper.h> |
28 | #include <net/netfilter/nf_conntrack_expect.h> |
29 | #include <linux/netfilter/nf_conntrack_sane.h> |
30 | |
31 | MODULE_LICENSE("GPL"); |
32 | MODULE_AUTHOR("Michal Schmidt <mschmidt@redhat.com>"); |
33 | MODULE_DESCRIPTION("SANE connection tracking helper"); |
34 | MODULE_ALIAS_NFCT_HELPER("sane"); |
35 | |
36 | static char *sane_buffer; |
37 | |
38 | static DEFINE_SPINLOCK(nf_sane_lock); |
39 | |
40 | #define MAX_PORTS 8 |
41 | static u_int16_t ports[MAX_PORTS]; |
42 | static unsigned int ports_c; |
43 | module_param_array(ports, ushort, &ports_c, 0400); |
44 | |
45 | struct sane_request { |
46 | __be32 RPC_code; |
47 | #define SANE_NET_START 7 /* RPC code */ |
48 | |
49 | __be32 handle; |
50 | }; |
51 | |
52 | struct sane_reply_net_start { |
53 | __be32 status; |
54 | #define SANE_STATUS_SUCCESS 0 |
55 | |
56 | __be16 zero; |
57 | __be16 port; |
58 | /* other fields aren't interesting for conntrack */ |
59 | }; |
60 | |
61 | static int help(struct sk_buff *skb, |
62 | unsigned int protoff, |
63 | struct nf_conn *ct, |
64 | enum ip_conntrack_info ctinfo) |
65 | { |
66 | unsigned int dataoff, datalen; |
67 | const struct tcphdr *th; |
68 | struct tcphdr _tcph; |
69 | void *sb_ptr; |
70 | int ret = NF_ACCEPT; |
71 | int dir = CTINFO2DIR(ctinfo); |
72 | struct nf_ct_sane_master *ct_sane_info; |
73 | struct nf_conntrack_expect *exp; |
74 | struct nf_conntrack_tuple *tuple; |
75 | struct sane_request *req; |
76 | struct sane_reply_net_start *reply; |
77 | |
78 | ct_sane_info = &nfct_help(ct)->help.ct_sane_info; |
79 | /* Until there's been traffic both ways, don't look in packets. */ |
80 | if (ctinfo != IP_CT_ESTABLISHED && |
81 | ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) |
82 | return NF_ACCEPT; |
83 | |
84 | /* Not a full tcp header? */ |
85 | th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph); |
86 | if (th == NULL) |
87 | return NF_ACCEPT; |
88 | |
89 | /* No data? */ |
90 | dataoff = protoff + th->doff * 4; |
91 | if (dataoff >= skb->len) |
92 | return NF_ACCEPT; |
93 | |
94 | datalen = skb->len - dataoff; |
95 | |
96 | spin_lock_bh(&nf_sane_lock); |
97 | sb_ptr = skb_header_pointer(skb, dataoff, datalen, sane_buffer); |
98 | BUG_ON(sb_ptr == NULL); |
99 | |
100 | if (dir == IP_CT_DIR_ORIGINAL) { |
101 | if (datalen != sizeof(struct sane_request)) |
102 | goto out; |
103 | |
104 | req = sb_ptr; |
105 | if (req->RPC_code != htonl(SANE_NET_START)) { |
106 | /* Not an interesting command */ |
107 | ct_sane_info->state = SANE_STATE_NORMAL; |
108 | goto out; |
109 | } |
110 | |
111 | /* We're interested in the next reply */ |
112 | ct_sane_info->state = SANE_STATE_START_REQUESTED; |
113 | goto out; |
114 | } |
115 | |
116 | /* Is it a reply to an uninteresting command? */ |
117 | if (ct_sane_info->state != SANE_STATE_START_REQUESTED) |
118 | goto out; |
119 | |
120 | /* It's a reply to SANE_NET_START. */ |
121 | ct_sane_info->state = SANE_STATE_NORMAL; |
122 | |
123 | if (datalen < sizeof(struct sane_reply_net_start)) { |
124 | pr_debug("nf_ct_sane: NET_START reply too short\n"); |
125 | goto out; |
126 | } |
127 | |
128 | reply = sb_ptr; |
129 | if (reply->status != htonl(SANE_STATUS_SUCCESS)) { |
130 | /* saned refused the command */ |
131 | pr_debug("nf_ct_sane: unsuccessful SANE_STATUS = %u\n", |
132 | ntohl(reply->status)); |
133 | goto out; |
134 | } |
135 | |
136 | /* Invalid saned reply? Ignore it. */ |
137 | if (reply->zero != 0) |
138 | goto out; |
139 | |
140 | exp = nf_ct_expect_alloc(ct); |
141 | if (exp == NULL) { |
142 | ret = NF_DROP; |
143 | goto out; |
144 | } |
145 | |
146 | tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; |
147 | nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct), |
148 | &tuple->src.u3, &tuple->dst.u3, |
149 | IPPROTO_TCP, NULL, &reply->port); |
150 | |
151 | pr_debug("nf_ct_sane: expect: "); |
152 | nf_ct_dump_tuple(&exp->tuple); |
153 | |
154 | /* Can't expect this? Best to drop packet now. */ |
155 | if (nf_ct_expect_related(exp) != 0) |
156 | ret = NF_DROP; |
157 | |
158 | nf_ct_expect_put(exp); |
159 | |
160 | out: |
161 | spin_unlock_bh(&nf_sane_lock); |
162 | return ret; |
163 | } |
164 | |
165 | static struct nf_conntrack_helper sane[MAX_PORTS][2] __read_mostly; |
166 | static char sane_names[MAX_PORTS][2][sizeof("sane-65535")] __read_mostly; |
167 | |
168 | static const struct nf_conntrack_expect_policy sane_exp_policy = { |
169 | .max_expected = 1, |
170 | .timeout = 5 * 60, |
171 | }; |
172 | |
173 | /* don't make this __exit, since it's called from __init ! */ |
174 | static void nf_conntrack_sane_fini(void) |
175 | { |
176 | int i, j; |
177 | |
178 | for (i = 0; i < ports_c; i++) { |
179 | for (j = 0; j < 2; j++) { |
180 | pr_debug("nf_ct_sane: unregistering helper for pf: %d " |
181 | "port: %d\n", |
182 | sane[i][j].tuple.src.l3num, ports[i]); |
183 | nf_conntrack_helper_unregister(&sane[i][j]); |
184 | } |
185 | } |
186 | |
187 | kfree(sane_buffer); |
188 | } |
189 | |
190 | static int __init nf_conntrack_sane_init(void) |
191 | { |
192 | int i, j = -1, ret = 0; |
193 | char *tmpname; |
194 | |
195 | sane_buffer = kmalloc(65536, GFP_KERNEL); |
196 | if (!sane_buffer) |
197 | return -ENOMEM; |
198 | |
199 | if (ports_c == 0) |
200 | ports[ports_c++] = SANE_PORT; |
201 | |
202 | /* FIXME should be configurable whether IPv4 and IPv6 connections |
203 | are tracked or not - YK */ |
204 | for (i = 0; i < ports_c; i++) { |
205 | sane[i][0].tuple.src.l3num = PF_INET; |
206 | sane[i][1].tuple.src.l3num = PF_INET6; |
207 | for (j = 0; j < 2; j++) { |
208 | sane[i][j].tuple.src.u.tcp.port = htons(ports[i]); |
209 | sane[i][j].tuple.dst.protonum = IPPROTO_TCP; |
210 | sane[i][j].expect_policy = &sane_exp_policy; |
211 | sane[i][j].me = THIS_MODULE; |
212 | sane[i][j].help = help; |
213 | tmpname = &sane_names[i][j][0]; |
214 | if (ports[i] == SANE_PORT) |
215 | sprintf(tmpname, "sane"); |
216 | else |
217 | sprintf(tmpname, "sane-%d", ports[i]); |
218 | sane[i][j].name = tmpname; |
219 | |
220 | pr_debug("nf_ct_sane: registering helper for pf: %d " |
221 | "port: %d\n", |
222 | sane[i][j].tuple.src.l3num, ports[i]); |
223 | ret = nf_conntrack_helper_register(&sane[i][j]); |
224 | if (ret) { |
225 | printk(KERN_ERR "nf_ct_sane: failed to " |
226 | "register helper for pf: %d port: %d\n", |
227 | sane[i][j].tuple.src.l3num, ports[i]); |
228 | nf_conntrack_sane_fini(); |
229 | return ret; |
230 | } |
231 | } |
232 | } |
233 | |
234 | return 0; |
235 | } |
236 | |
237 | module_init(nf_conntrack_sane_init); |
238 | module_exit(nf_conntrack_sane_fini); |
239 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9