aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/Kconfig13
-rw-r--r--net/netfilter/Makefile1
-rw-r--r--net/netfilter/nf_conntrack_sane.c242
3 files changed, 256 insertions, 0 deletions
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 80107d4909c5..614c92c17835 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -235,6 +235,19 @@ config NF_CONNTRACK_PPTP
235 235
236 To compile it as a module, choose M here. If unsure, say N. 236 To compile it as a module, choose M here. If unsure, say N.
237 237
238config NF_CONNTRACK_SANE
239 tristate "SANE protocol support (EXPERIMENTAL)"
240 depends on EXPERIMENTAL && NF_CONNTRACK
241 help
242 SANE is a protocol for remote access to scanners as implemented
243 by the 'saned' daemon. Like FTP, it uses separate control and
244 data connections.
245
246 With this module you can support SANE on a connection tracking
247 firewall.
248
249 To compile it as a module, choose M here. If unsure, say N.
250
238config NF_CONNTRACK_SIP 251config NF_CONNTRACK_SIP
239 tristate "SIP protocol support (EXPERIMENTAL)" 252 tristate "SIP protocol support (EXPERIMENTAL)"
240 depends on EXPERIMENTAL && NF_CONNTRACK 253 depends on EXPERIMENTAL && NF_CONNTRACK
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 5dc5574f7e99..5054b0ff8096 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_NF_CONNTRACK_H323) += nf_conntrack_h323.o
29obj-$(CONFIG_NF_CONNTRACK_IRC) += nf_conntrack_irc.o 29obj-$(CONFIG_NF_CONNTRACK_IRC) += nf_conntrack_irc.o
30obj-$(CONFIG_NF_CONNTRACK_NETBIOS_NS) += nf_conntrack_netbios_ns.o 30obj-$(CONFIG_NF_CONNTRACK_NETBIOS_NS) += nf_conntrack_netbios_ns.o
31obj-$(CONFIG_NF_CONNTRACK_PPTP) += nf_conntrack_pptp.o 31obj-$(CONFIG_NF_CONNTRACK_PPTP) += nf_conntrack_pptp.o
32obj-$(CONFIG_NF_CONNTRACK_SANE) += nf_conntrack_sane.o
32obj-$(CONFIG_NF_CONNTRACK_SIP) += nf_conntrack_sip.o 33obj-$(CONFIG_NF_CONNTRACK_SIP) += nf_conntrack_sip.o
33obj-$(CONFIG_NF_CONNTRACK_TFTP) += nf_conntrack_tftp.o 34obj-$(CONFIG_NF_CONNTRACK_TFTP) += nf_conntrack_tftp.o
34 35
diff --git a/net/netfilter/nf_conntrack_sane.c b/net/netfilter/nf_conntrack_sane.c
new file mode 100644
index 000000000000..eb2d1dc46d45
--- /dev/null
+++ b/net/netfilter/nf_conntrack_sane.c
@@ -0,0 +1,242 @@
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/in.h>
24#include <linux/tcp.h>
25#include <net/netfilter/nf_conntrack.h>
26#include <net/netfilter/nf_conntrack_helper.h>
27#include <net/netfilter/nf_conntrack_expect.h>
28#include <linux/netfilter/nf_conntrack_sane.h>
29
30MODULE_LICENSE("GPL");
31MODULE_AUTHOR("Michal Schmidt <mschmidt@redhat.com>");
32MODULE_DESCRIPTION("SANE connection tracking helper");
33
34static char *sane_buffer;
35
36static DEFINE_SPINLOCK(nf_sane_lock);
37
38#define MAX_PORTS 8
39static u_int16_t ports[MAX_PORTS];
40static unsigned int ports_c;
41module_param_array(ports, ushort, &ports_c, 0400);
42
43#if 0
44#define DEBUGP printk
45#else
46#define DEBUGP(format, args...)
47#endif
48
49struct sane_request {
50 __be32 RPC_code;
51#define SANE_NET_START 7 /* RPC code */
52
53 __be32 handle;
54};
55
56struct sane_reply_net_start {
57 __be32 status;
58#define SANE_STATUS_SUCCESS 0
59
60 __be16 zero;
61 __be16 port;
62 /* other fields aren't interesting for conntrack */
63};
64
65static int help(struct sk_buff **pskb,
66 unsigned int protoff,
67 struct nf_conn *ct,
68 enum ip_conntrack_info ctinfo)
69{
70 unsigned int dataoff, datalen;
71 struct tcphdr _tcph, *th;
72 char *sb_ptr;
73 int ret = NF_ACCEPT;
74 int dir = CTINFO2DIR(ctinfo);
75 struct nf_ct_sane_master *ct_sane_info;
76 struct nf_conntrack_expect *exp;
77 struct nf_conntrack_tuple *tuple;
78 struct sane_request *req;
79 struct sane_reply_net_start *reply;
80 int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
81
82 ct_sane_info = &nfct_help(ct)->help.ct_sane_info;
83 /* Until there's been traffic both ways, don't look in packets. */
84 if (ctinfo != IP_CT_ESTABLISHED &&
85 ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY)
86 return NF_ACCEPT;
87
88 /* Not a full tcp header? */
89 th = skb_header_pointer(*pskb, protoff, sizeof(_tcph), &_tcph);
90 if (th == NULL)
91 return NF_ACCEPT;
92
93 /* No data? */
94 dataoff = protoff + th->doff * 4;
95 if (dataoff >= (*pskb)->len)
96 return NF_ACCEPT;
97
98 datalen = (*pskb)->len - dataoff;
99
100 spin_lock_bh(&nf_sane_lock);
101 sb_ptr = skb_header_pointer(*pskb, dataoff, datalen, sane_buffer);
102 BUG_ON(sb_ptr == NULL);
103
104 if (dir == IP_CT_DIR_ORIGINAL) {
105 if (datalen != sizeof(struct sane_request))
106 goto out;
107
108 req = (struct sane_request *)sb_ptr;
109 if (req->RPC_code != htonl(SANE_NET_START)) {
110 /* Not an interesting command */
111 ct_sane_info->state = SANE_STATE_NORMAL;
112 goto out;
113 }
114
115 /* We're interested in the next reply */
116 ct_sane_info->state = SANE_STATE_START_REQUESTED;
117 goto out;
118 }
119
120 /* Is it a reply to an uninteresting command? */
121 if (ct_sane_info->state != SANE_STATE_START_REQUESTED)
122 goto out;
123
124 /* It's a reply to SANE_NET_START. */
125 ct_sane_info->state = SANE_STATE_NORMAL;
126
127 if (datalen < sizeof(struct sane_reply_net_start)) {
128 DEBUGP("nf_ct_sane: NET_START reply too short\n");
129 goto out;
130 }
131
132 reply = (struct sane_reply_net_start *)sb_ptr;
133 if (reply->status != htonl(SANE_STATUS_SUCCESS)) {
134 /* saned refused the command */
135 DEBUGP("nf_ct_sane: unsuccessful SANE_STATUS = %u\n",
136 ntohl(reply->status));
137 goto out;
138 }
139
140 /* Invalid saned reply? Ignore it. */
141 if (reply->zero != 0)
142 goto out;
143
144 exp = nf_conntrack_expect_alloc(ct);
145 if (exp == NULL) {
146 ret = NF_DROP;
147 goto out;
148 }
149
150 tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
151 nf_conntrack_expect_init(exp, family,
152 &tuple->src.u3, &tuple->dst.u3,
153 IPPROTO_TCP,
154 NULL, &reply->port);
155
156 DEBUGP("nf_ct_sane: expect: ");
157 NF_CT_DUMP_TUPLE(&exp->tuple);
158 NF_CT_DUMP_TUPLE(&exp->mask);
159
160 /* Can't expect this? Best to drop packet now. */
161 if (nf_conntrack_expect_related(exp) != 0)
162 ret = NF_DROP;
163
164 nf_conntrack_expect_put(exp);
165
166out:
167 spin_unlock_bh(&nf_sane_lock);
168 return ret;
169}
170
171static struct nf_conntrack_helper sane[MAX_PORTS][2];
172static char sane_names[MAX_PORTS][2][sizeof("sane-65535")];
173
174/* don't make this __exit, since it's called from __init ! */
175static void nf_conntrack_sane_fini(void)
176{
177 int i, j;
178
179 for (i = 0; i < ports_c; i++) {
180 for (j = 0; j < 2; j++) {
181 DEBUGP("nf_ct_sane: unregistering helper for pf: %d "
182 "port: %d\n",
183 sane[i][j].tuple.src.l3num, ports[i]);
184 nf_conntrack_helper_unregister(&sane[i][j]);
185 }
186 }
187
188 kfree(sane_buffer);
189}
190
191static int __init nf_conntrack_sane_init(void)
192{
193 int i, j = -1, ret = 0;
194 char *tmpname;
195
196 sane_buffer = kmalloc(65536, GFP_KERNEL);
197 if (!sane_buffer)
198 return -ENOMEM;
199
200 if (ports_c == 0)
201 ports[ports_c++] = SANE_PORT;
202
203 /* FIXME should be configurable whether IPv4 and IPv6 connections
204 are tracked or not - YK */
205 for (i = 0; i < ports_c; i++) {
206 sane[i][0].tuple.src.l3num = PF_INET;
207 sane[i][1].tuple.src.l3num = PF_INET6;
208 for (j = 0; j < 2; j++) {
209 sane[i][j].tuple.src.u.tcp.port = htons(ports[i]);
210 sane[i][j].tuple.dst.protonum = IPPROTO_TCP;
211 sane[i][j].mask.src.u.tcp.port = 0xFFFF;
212 sane[i][j].mask.dst.protonum = 0xFF;
213 sane[i][j].max_expected = 1;
214 sane[i][j].timeout = 5 * 60; /* 5 Minutes */
215 sane[i][j].me = THIS_MODULE;
216 sane[i][j].help = help;
217 tmpname = &sane_names[i][j][0];
218 if (ports[i] == SANE_PORT)
219 sprintf(tmpname, "sane");
220 else
221 sprintf(tmpname, "sane-%d", ports[i]);
222 sane[i][j].name = tmpname;
223
224 DEBUGP("nf_ct_sane: registering helper for pf: %d "
225 "port: %d\n",
226 sane[i][j].tuple.src.l3num, ports[i]);
227 ret = nf_conntrack_helper_register(&sane[i][j]);
228 if (ret) {
229 printk(KERN_ERR "nf_ct_sane: failed to "
230 "register helper for pf: %d port: %d\n",
231 sane[i][j].tuple.src.l3num, ports[i]);
232 nf_conntrack_sane_fini();
233 return ret;
234 }
235 }
236 }
237
238 return 0;
239}
240
241module_init(nf_conntrack_sane_init);
242module_exit(nf_conntrack_sane_fini);