Blame view

net/netfilter/nf_conntrack_sane.c 6.1 KB
6fecd1985   Michal Schmidt   [NETFILTER]: Add ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  /* SANE connection tracking helper
   * (SANE = Scanner Access Now Easy)
   * For documentation about the SANE network protocol see
   * http://www.sane-project.org/html/doc015.html
   */
  
  /* Copyright (C) 2007 Red Hat, Inc.
   * Author: Michal Schmidt <mschmidt@redhat.com>
   * Based on the FTP conntrack helper (net/netfilter/nf_conntrack_ftp.c):
   *  (C) 1999-2001 Paul `Rusty' Russell
   *  (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
   *  (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org>
   *  (C) 2003 Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   */
  
  #include <linux/module.h>
  #include <linux/moduleparam.h>
  #include <linux/netfilter.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
23
  #include <linux/slab.h>
6fecd1985   Michal Schmidt   [NETFILTER]: Add ...
24
25
26
27
28
29
30
31
32
33
  #include <linux/in.h>
  #include <linux/tcp.h>
  #include <net/netfilter/nf_conntrack.h>
  #include <net/netfilter/nf_conntrack_helper.h>
  #include <net/netfilter/nf_conntrack_expect.h>
  #include <linux/netfilter/nf_conntrack_sane.h>
  
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Michal Schmidt <mschmidt@redhat.com>");
  MODULE_DESCRIPTION("SANE connection tracking helper");
4dc06f963   Pablo Neira Ayuso   netfilter: nf_con...
34
  MODULE_ALIAS_NFCT_HELPER("sane");
6fecd1985   Michal Schmidt   [NETFILTER]: Add ...
35
36
37
38
39
40
41
42
43
  
  static char *sane_buffer;
  
  static DEFINE_SPINLOCK(nf_sane_lock);
  
  #define MAX_PORTS 8
  static u_int16_t ports[MAX_PORTS];
  static unsigned int ports_c;
  module_param_array(ports, ushort, &ports_c, 0400);
6fecd1985   Michal Schmidt   [NETFILTER]: Add ...
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
  struct sane_request {
  	__be32 RPC_code;
  #define SANE_NET_START      7   /* RPC code */
  
  	__be32 handle;
  };
  
  struct sane_reply_net_start {
  	__be32 status;
  #define SANE_STATUS_SUCCESS 0
  
  	__be16 zero;
  	__be16 port;
  	/* other fields aren't interesting for conntrack */
  };
3db05fea5   Herbert Xu   [NETFILTER]: Repl...
59
  static int help(struct sk_buff *skb,
6fecd1985   Michal Schmidt   [NETFILTER]: Add ...
60
61
62
63
64
  		unsigned int protoff,
  		struct nf_conn *ct,
  		enum ip_conntrack_info ctinfo)
  {
  	unsigned int dataoff, datalen;
02e23f405   Jan Engelhardt   [NETFILTER]: nf_c...
65
66
67
  	const struct tcphdr *th;
  	struct tcphdr _tcph;
  	void *sb_ptr;
6fecd1985   Michal Schmidt   [NETFILTER]: Add ...
68
69
70
71
72
73
74
  	int ret = NF_ACCEPT;
  	int dir = CTINFO2DIR(ctinfo);
  	struct nf_ct_sane_master *ct_sane_info;
  	struct nf_conntrack_expect *exp;
  	struct nf_conntrack_tuple *tuple;
  	struct sane_request *req;
  	struct sane_reply_net_start *reply;
6fecd1985   Michal Schmidt   [NETFILTER]: Add ...
75
76
77
78
  
  	ct_sane_info = &nfct_help(ct)->help.ct_sane_info;
  	/* Until there's been traffic both ways, don't look in packets. */
  	if (ctinfo != IP_CT_ESTABLISHED &&
fb0488337   Eric Dumazet   netfilter: add mo...
79
  	    ctinfo != IP_CT_ESTABLISHED_REPLY)
6fecd1985   Michal Schmidt   [NETFILTER]: Add ...
80
81
82
  		return NF_ACCEPT;
  
  	/* Not a full tcp header? */
3db05fea5   Herbert Xu   [NETFILTER]: Repl...
83
  	th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
6fecd1985   Michal Schmidt   [NETFILTER]: Add ...
84
85
86
87
88
  	if (th == NULL)
  		return NF_ACCEPT;
  
  	/* No data? */
  	dataoff = protoff + th->doff * 4;
3db05fea5   Herbert Xu   [NETFILTER]: Repl...
89
  	if (dataoff >= skb->len)
6fecd1985   Michal Schmidt   [NETFILTER]: Add ...
90
  		return NF_ACCEPT;
3db05fea5   Herbert Xu   [NETFILTER]: Repl...
91
  	datalen = skb->len - dataoff;
6fecd1985   Michal Schmidt   [NETFILTER]: Add ...
92
93
  
  	spin_lock_bh(&nf_sane_lock);
3db05fea5   Herbert Xu   [NETFILTER]: Repl...
94
  	sb_ptr = skb_header_pointer(skb, dataoff, datalen, sane_buffer);
6fecd1985   Michal Schmidt   [NETFILTER]: Add ...
95
96
97
98
99
  	BUG_ON(sb_ptr == NULL);
  
  	if (dir == IP_CT_DIR_ORIGINAL) {
  		if (datalen != sizeof(struct sane_request))
  			goto out;
02e23f405   Jan Engelhardt   [NETFILTER]: nf_c...
100
  		req = sb_ptr;
6fecd1985   Michal Schmidt   [NETFILTER]: Add ...
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
  		if (req->RPC_code != htonl(SANE_NET_START)) {
  			/* Not an interesting command */
  			ct_sane_info->state = SANE_STATE_NORMAL;
  			goto out;
  		}
  
  		/* We're interested in the next reply */
  		ct_sane_info->state = SANE_STATE_START_REQUESTED;
  		goto out;
  	}
  
  	/* Is it a reply to an uninteresting command? */
  	if (ct_sane_info->state != SANE_STATE_START_REQUESTED)
  		goto out;
  
  	/* It's a reply to SANE_NET_START. */
  	ct_sane_info->state = SANE_STATE_NORMAL;
  
  	if (datalen < sizeof(struct sane_reply_net_start)) {
0d53778e8   Patrick McHardy   [NETFILTER]: Conv...
120
121
  		pr_debug("nf_ct_sane: NET_START reply too short
  ");
6fecd1985   Michal Schmidt   [NETFILTER]: Add ...
122
123
  		goto out;
  	}
02e23f405   Jan Engelhardt   [NETFILTER]: nf_c...
124
  	reply = sb_ptr;
6fecd1985   Michal Schmidt   [NETFILTER]: Add ...
125
126
  	if (reply->status != htonl(SANE_STATUS_SUCCESS)) {
  		/* saned refused the command */
0d53778e8   Patrick McHardy   [NETFILTER]: Conv...
127
128
129
  		pr_debug("nf_ct_sane: unsuccessful SANE_STATUS = %u
  ",
  			 ntohl(reply->status));
6fecd1985   Michal Schmidt   [NETFILTER]: Add ...
130
131
132
133
134
135
  		goto out;
  	}
  
  	/* Invalid saned reply? Ignore it. */
  	if (reply->zero != 0)
  		goto out;
6823645d6   Patrick McHardy   [NETFILTER]: nf_c...
136
  	exp = nf_ct_expect_alloc(ct);
6fecd1985   Michal Schmidt   [NETFILTER]: Add ...
137
138
139
140
141
142
  	if (exp == NULL) {
  		ret = NF_DROP;
  		goto out;
  	}
  
  	tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
5e8fbe2ac   Patrick McHardy   [NETFILTER]: nf_c...
143
  	nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct),
6002f266b   Patrick McHardy   [NETFILTER]: nf_c...
144
  			  &tuple->src.u3, &tuple->dst.u3,
6823645d6   Patrick McHardy   [NETFILTER]: nf_c...
145
  			  IPPROTO_TCP, NULL, &reply->port);
6fecd1985   Michal Schmidt   [NETFILTER]: Add ...
146

0d53778e8   Patrick McHardy   [NETFILTER]: Conv...
147
  	pr_debug("nf_ct_sane: expect: ");
3c9fba656   Jan Engelhardt   [NETFILTER]: nf_c...
148
  	nf_ct_dump_tuple(&exp->tuple);
6fecd1985   Michal Schmidt   [NETFILTER]: Add ...
149
150
  
  	/* Can't expect this?  Best to drop packet now. */
6823645d6   Patrick McHardy   [NETFILTER]: nf_c...
151
  	if (nf_ct_expect_related(exp) != 0)
6fecd1985   Michal Schmidt   [NETFILTER]: Add ...
152
  		ret = NF_DROP;
6823645d6   Patrick McHardy   [NETFILTER]: nf_c...
153
  	nf_ct_expect_put(exp);
6fecd1985   Michal Schmidt   [NETFILTER]: Add ...
154
155
156
157
158
  
  out:
  	spin_unlock_bh(&nf_sane_lock);
  	return ret;
  }
ec59a1110   Patrick McHardy   [NETFILTER]: nf_c...
159
160
  static struct nf_conntrack_helper sane[MAX_PORTS][2] __read_mostly;
  static char sane_names[MAX_PORTS][2][sizeof("sane-65535")] __read_mostly;
6fecd1985   Michal Schmidt   [NETFILTER]: Add ...
161

6002f266b   Patrick McHardy   [NETFILTER]: nf_c...
162
163
164
165
  static const struct nf_conntrack_expect_policy sane_exp_policy = {
  	.max_expected	= 1,
  	.timeout	= 5 * 60,
  };
6fecd1985   Michal Schmidt   [NETFILTER]: Add ...
166
167
168
169
170
171
172
  /* don't make this __exit, since it's called from __init ! */
  static void nf_conntrack_sane_fini(void)
  {
  	int i, j;
  
  	for (i = 0; i < ports_c; i++) {
  		for (j = 0; j < 2; j++) {
0d53778e8   Patrick McHardy   [NETFILTER]: Conv...
173
174
175
176
  			pr_debug("nf_ct_sane: unregistering helper for pf: %d "
  				 "port: %d
  ",
  				 sane[i][j].tuple.src.l3num, ports[i]);
6fecd1985   Michal Schmidt   [NETFILTER]: Add ...
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
  			nf_conntrack_helper_unregister(&sane[i][j]);
  		}
  	}
  
  	kfree(sane_buffer);
  }
  
  static int __init nf_conntrack_sane_init(void)
  {
  	int i, j = -1, ret = 0;
  	char *tmpname;
  
  	sane_buffer = kmalloc(65536, GFP_KERNEL);
  	if (!sane_buffer)
  		return -ENOMEM;
  
  	if (ports_c == 0)
  		ports[ports_c++] = SANE_PORT;
  
  	/* FIXME should be configurable whether IPv4 and IPv6 connections
  		 are tracked or not - YK */
  	for (i = 0; i < ports_c; i++) {
  		sane[i][0].tuple.src.l3num = PF_INET;
  		sane[i][1].tuple.src.l3num = PF_INET6;
  		for (j = 0; j < 2; j++) {
  			sane[i][j].tuple.src.u.tcp.port = htons(ports[i]);
  			sane[i][j].tuple.dst.protonum = IPPROTO_TCP;
6002f266b   Patrick McHardy   [NETFILTER]: nf_c...
204
  			sane[i][j].expect_policy = &sane_exp_policy;
6fecd1985   Michal Schmidt   [NETFILTER]: Add ...
205
206
207
208
209
210
211
212
  			sane[i][j].me = THIS_MODULE;
  			sane[i][j].help = help;
  			tmpname = &sane_names[i][j][0];
  			if (ports[i] == SANE_PORT)
  				sprintf(tmpname, "sane");
  			else
  				sprintf(tmpname, "sane-%d", ports[i]);
  			sane[i][j].name = tmpname;
0d53778e8   Patrick McHardy   [NETFILTER]: Conv...
213
214
215
216
  			pr_debug("nf_ct_sane: registering helper for pf: %d "
  				 "port: %d
  ",
  				 sane[i][j].tuple.src.l3num, ports[i]);
6fecd1985   Michal Schmidt   [NETFILTER]: Add ...
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
  			ret = nf_conntrack_helper_register(&sane[i][j]);
  			if (ret) {
  				printk(KERN_ERR "nf_ct_sane: failed to "
  				       "register helper for pf: %d port: %d
  ",
  					sane[i][j].tuple.src.l3num, ports[i]);
  				nf_conntrack_sane_fini();
  				return ret;
  			}
  		}
  	}
  
  	return 0;
  }
  
  module_init(nf_conntrack_sane_init);
  module_exit(nf_conntrack_sane_fini);