]>
Commit | Line | Data |
---|---|---|
2380c486 JR |
1 | diff -NurpP --minimal linux/include/net/netfilter/nf_conntrack.h linux/include/net/netfilter/nf_conntrack.h |
2 | --- linux/include/net/netfilter/nf_conntrack.h 2007-05-30 11:57:00.000000000 +0200 | |
3 | +++ linux/include/net/netfilter/nf_conntrack.h 2007-05-30 11:58:41.000000000 +0200 | |
4 | @@ -29,6 +29,7 @@ union nf_conntrack_expect_proto { | |
5 | }; | |
6 | ||
7 | /* Add protocol helper include file here */ | |
8 | +#include <linux/netfilter/nf_conntrack_rsh.h> | |
9 | #include <linux/netfilter/nf_conntrack_ftp.h> | |
10 | #include <linux/netfilter/nf_conntrack_pptp.h> | |
11 | #include <linux/netfilter/nf_conntrack_h323.h> | |
12 | @@ -39,6 +40,7 @@ union nf_conntrack_expect_proto { | |
13 | /* per conntrack: application helper private data */ | |
14 | union nf_conntrack_help { | |
15 | /* insert conntrack helper private data (master) here */ | |
16 | + struct nf_ct_rsh_master ct_rsh_info; | |
17 | struct nf_ct_ftp_master ct_ftp_info; | |
18 | struct nf_ct_pptp_master ct_pptp_info; | |
19 | struct nf_ct_h323_master ct_h323_info; | |
20 | diff -NurpP --minimal linux/include/linux/netfilter/nf_conntrack_rsh.h linux/include/linux/netfilter/nf_conntrack_rsh.h | |
21 | --- linux/include/linux/netfilter/nf_conntrack_rsh.h 1970-01-01 01:00:00.000000000 +0100 | |
22 | +++ linux/include/linux/netfilter/nf_conntrack_rsh.h 2007-05-30 11:58:41.000000000 +0200 | |
23 | @@ -0,0 +1,28 @@ | |
24 | +/* RSH extension for IP connection tracking, Version 1.0 | |
25 | + * (C) 2002 by Ian (Larry) Latter <Ian.Latter@mq.edu.au> | |
26 | + * based on HW's ip_conntrack_irc.c | |
27 | + * | |
28 | + * nf_conntrack_rsh.c,v 1.0 2002/07/17 14:49:26 | |
29 | + * | |
30 | + * This program is free software; you can redistribute it and/or | |
31 | + * modify it under the terms of the GNU General Public License | |
32 | + * as published by the Free Software Foundation; either version | |
33 | + * 2 of the License, or (at your option) any later version. | |
34 | + */ | |
35 | +#ifndef _IP_CONNTRACK_RSH_H | |
36 | +#define _IP_CONNTRACK_RSH_H | |
37 | + | |
38 | +#define RSH_PORT 514 | |
39 | + | |
40 | +/* This structure is per expected connection */ | |
41 | +struct nf_ct_rsh_expect | |
42 | +{ | |
43 | + u_int16_t port; | |
44 | +}; | |
45 | + | |
46 | +/* This structure exists only once per master */ | |
47 | +struct nf_ct_rsh_master { | |
48 | +}; | |
49 | + | |
50 | +#endif /* _IP_CONNTRACK_RSH_H */ | |
51 | + | |
52 | diff -NurpP --minimal linux/net/ipv4/netfilter/Kconfig linux/net/ipv4/netfilter/Kconfig | |
53 | --- linux/net/ipv4/netfilter/Kconfig 2007-05-30 11:57:07.000000000 +0200 | |
54 | +++ linux/net/ipv4/netfilter/Kconfig 2007-05-30 11:58:41.000000000 +0200 | |
55 | @@ -870,5 +870,28 @@ config IP_NF_MMS | |
56 | If you want to compile it as a module, say M here and read | |
57 | <file:Documentation/modules.txt>. If unsure, say `Y'. | |
58 | ||
59 | +config NF_CONNTRACK_RSH | |
60 | + tristate 'RSH protocol support' | |
61 | + depends on NF_CONNTRACK | |
62 | + help | |
63 | + The RSH connection tracker is required if the dynamic | |
64 | + stderr "Server to Client" connection is to occur during a | |
65 | + normal RSH session. This typically operates as follows; | |
66 | + | |
67 | + Client 0:1023 --> Server 514 (stream 1 - stdin/stdout) | |
68 | + Client 0:1023 <-- Server 0:1023 (stream 2 - stderr) | |
69 | + | |
70 | + This connection tracker will identify new RSH sessions, | |
71 | + extract the outbound session details, and notify netfilter | |
72 | + of pending "related" sessions. | |
73 | + | |
74 | + Warning: This module could be dangerous. It is not "best | |
75 | + practice" to use RSH, use SSH in all instances. | |
76 | + (see rfc1244, rfc1948, rfc2179, etc ad-nauseum) | |
77 | + | |
78 | + | |
79 | + If you want to compile it as a module, say M here and read | |
80 | + <file:Documentation/modules.txt>. If unsure, say `N'. | |
81 | + | |
82 | endmenu | |
83 | ||
84 | diff -NurpP --minimal linux/net/netfilter/Makefile linux/net/netfilter/Makefile | |
85 | --- linux/net/netfilter/Makefile 2007-05-30 11:57:07.000000000 +0200 | |
86 | +++ linux/net/netfilter/Makefile 2007-05-30 11:58:41.000000000 +0200 | |
87 | @@ -0,0 +0,1 @@ | |
88 | +obj-$(CONFIG_NF_CONNTRACK_RSH) += nf_conntrack_rsh.o | |
89 | diff -NurpP --minimal linux/net/netfilter/nf_conntrack_rsh.c linux/net/netfilter/nf_conntrack_rsh.c | |
90 | --- linux/net/netfilter/nf_conntrack_rsh.c 1970-01-01 01:00:00.000000000 +0100 | |
91 | +++ linux/net/netfilter/nf_conntrack_rsh.c 2007-05-30 11:58:41.000000000 +0200 | |
92 | @@ -0,0 +1,353 @@ | |
93 | +/* RSH extension for IP connection tracking, Version 1.0 | |
94 | + * (C) 2002 by Ian (Larry) Latter <Ian.Latter@mq.edu.au> | |
95 | + * based on HW's ip_conntrack_irc.c | |
96 | + * | |
97 | + * (C) 2004,2005 by David Stes <stes@pandora.be> | |
98 | + * Modification for Legato NetWorker range [7937-9936] instead of [0:1023] | |
99 | + * | |
100 | + * (C) 2005 by David Stes <stes@pandora.be> | |
101 | + * Upgrade to 2.6.13 API | |
102 | + * | |
103 | + * ip_conntrack_rsh.c,v 1.0 2002/07/17 14:49:26 | |
104 | + * | |
105 | + * This program is free software; you can redistribute it and/or | |
106 | + * modify it under the terms of the GNU General Public License | |
107 | + * as published by the Free Software Foundation; either version | |
108 | + * 2 of the License, or (at your option) any later version. | |
109 | + ** | |
110 | + * Module load syntax: | |
111 | + * insmod ip_conntrack_rsh.o range=1023,ports=port1,port2,...port<MAX_PORTS> | |
112 | + * | |
113 | + * please give the ports of all RSH servers You wish to connect to. | |
114 | + * If You don't specify ports, the default will be port 514 | |
115 | + ** | |
116 | + * Note to all: | |
117 | + * RSH blows ... you should use SSH (openssh.org) to replace it, | |
118 | + * unfortunately I babysit some sysadmins that won't migrate | |
119 | + * their legacy crap, in our second tier. | |
120 | + */ | |
121 | + | |
122 | + | |
123 | +/* | |
124 | + * Some docco ripped from the net to teach me all there is to know about | |
125 | + * RSH, in 16.5 seconds (ie, all of the non-netfilter docco used to write | |
126 | + * this module). | |
127 | + * | |
128 | + * I have no idea what "unix rshd man pages" these guys have .. but that | |
129 | + * is some pretty detailed docco! | |
130 | + ** | |
131 | + * | |
132 | + * 4. Of the rsh protocol. | |
133 | + * ----------------------- | |
134 | + * | |
135 | + * The rshd listens on TCP port #514. The following info is from the unix | |
136 | + * rshd man pages : | |
137 | + * | |
138 | + * "Service Request Protocol | |
139 | + * | |
140 | + * When the rshd daemon receives a service request, it initiates the | |
141 | + * following protocol: | |
142 | + * | |
143 | + * 1. The rshd daemon checks the source port number for the request. | |
144 | + * If the port number is not in the range 0 through 1023, the rshd daemon | |
145 | + * terminates the connection. | |
146 | + * | |
147 | + * 2. The rshd daemon reads characters from the socket up to a null byte. | |
148 | + * The string read is interpreted as an ASCII number (base 10). If this | |
149 | + * number is nonzero, the rshd daemon interprets it as the port number | |
150 | + * of a secondary stream to be used as standard error. A second connection | |
151 | + * is created to the specified port on the client host. The source port | |
152 | + * on the local host is in the range 0 through 1023. | |
153 | + * | |
154 | + * 3. The rshd daemon uses the source address of the initial connection | |
155 | + * request to determine the name of the client host. If the name cannot | |
156 | + * be determined, the rshd daemon uses the dotted decimal representation | |
157 | + * of the client host's address. | |
158 | + * | |
159 | + * 4. The rshd daemon retrieves the following information from the initial | |
160 | + * socket: | |
161 | + * | |
162 | + * * A null-terminated string of at most 16 bytes interpreted as | |
163 | + * the user name of the user on the client host. | |
164 | + * | |
165 | + * * A null-terminated string of at most 16 bytes interpreted as | |
166 | + * the user name to be used on the local server host. | |
167 | + * | |
168 | + * * Another null-terminated string interpreted as a command line | |
169 | + * to be passed to a shell on the local server host. | |
170 | + * | |
171 | + * 5. The rshd daemon attempts to validate the user using the following steps: | |
172 | + * | |
173 | + * a. The rshd daemon looks up the local user name in the /etc/passwd | |
174 | + * file and tries to switch to the home directory (using the chdir | |
175 | + * subroutine). If either the lookup or the directory change fails, | |
176 | + * the rshd daemon terminates the connection. | |
177 | + * | |
178 | + * b. If the local user ID is a nonzero value, the rshd daemon searches | |
179 | + * the /etc/hosts.equiv file to see if the name of the client | |
180 | + * workstation is listed. If the client workstation is listed as an | |
181 | + * equivalent host, the rshd daemon validates the user. | |
182 | + * | |
183 | + * c. If the $HOME/.rhosts file exists, the rshd daemon tries to | |
184 | + * authenticate the user by checking the .rhosts file. | |
185 | + * | |
186 | + * d. If either the $HOME/.rhosts authentication fails or the | |
187 | + * client host is not an equivalent host, the rshd daemon | |
188 | + * terminates the connection. | |
189 | + * | |
190 | + * 6. Once rshd validates the user, the rshd daemon returns a null byte | |
191 | + * on the initial connection and passes the command line to the user's | |
192 | + * local login shell. The shell then inherits the network connections | |
193 | + * established by the rshd daemon." | |
194 | + * | |
195 | + */ | |
196 | + | |
197 | + | |
198 | +#include <linux/module.h> | |
199 | +#include <linux/netfilter.h> | |
200 | +#include <linux/ip.h> | |
201 | +#include <net/checksum.h> | |
202 | +#include <net/tcp.h> | |
203 | + | |
204 | +#include <linux/netfilter_ipv4/ip_tables.h> | |
205 | +#include <net/netfilter/nf_conntrack_expect.h> | |
206 | +#include <net/netfilter/nf_conntrack_helper.h> | |
207 | +#include <linux/netfilter/nf_conntrack_rsh.h> | |
208 | + | |
209 | +#define MAX_PORTS 8 | |
210 | +static int range; /* defaults to = 1023 */ | |
211 | +static unsigned short rangemask; /* defaults to = 0xfc00 */ | |
212 | +static int ports[MAX_PORTS]; | |
213 | +static int ports_n_c = 0; | |
214 | + | |
215 | +MODULE_AUTHOR("Ian (Larry) Latter <Ian.Latter@mq.edu.au>"); | |
216 | +MODULE_DESCRIPTION("RSH connection tracking module"); | |
217 | +MODULE_LICENSE("GPL"); | |
218 | +#ifdef MODULE_PARM | |
219 | +module_param(range, int, 0400); | |
220 | +MODULE_PARM_DESC(range, "max port of reserved range (default is 1023)"); | |
221 | +module_param_array(ports, int, &ports_n_c, 0400); | |
222 | +MODULE_PARM_DESC(ports, "port numbers of RSH servers"); | |
223 | +#endif | |
224 | + | |
225 | +static DEFINE_SPINLOCK(rsh_buffer_lock); | |
226 | +static char rsh_buffer[65535]; | |
227 | + | |
228 | +unsigned int (*ip_nat_rsh_hook)(struct sk_buff **pskb, | |
229 | + enum ip_conntrack_info ctinfo, | |
230 | + unsigned int matchoff, | |
231 | + struct nf_conntrack_expect *exp); | |
232 | + | |
233 | +#define PRINTK(format, args...) printk(KERN_DEBUG "ip_conntrack_rsh: " \ | |
234 | + format, ## args) | |
235 | + | |
236 | +#if 0 | |
237 | +#define DEBUGP(format, args...) printk(KERN_DEBUG "ip_conntrack_rsh: " \ | |
238 | + format, ## args) | |
239 | +#else | |
240 | +#define DEBUGP(format, args...) | |
241 | +#endif | |
242 | + | |
243 | + | |
244 | +/* FIXME: This should be in userspace. Later. */ | |
245 | +static int help(struct sk_buff **pskb, | |
246 | + struct nf_conn *ct, enum ip_conntrack_info ctinfo) | |
247 | +{ | |
248 | + struct tcphdr _tcph, *th; | |
249 | + char *data, *rb_ptr; | |
250 | + int ret = NF_ACCEPT; | |
251 | + int dir = CTINFO2DIR(ctinfo); | |
252 | + struct nf_conntrack_expect *exp; | |
253 | + unsigned int dataoff, datalen; | |
254 | + u_int16_t port; | |
255 | + int maxoctet = 4; | |
256 | + | |
257 | + /* note that "maxoctet" is used to maintain sanity (8 was the | |
258 | + * original array size used in rshd/glibc) -- is there a | |
259 | + * vulnerability in rshd.c in the looped port *= 10? | |
260 | + */ | |
261 | + | |
262 | + DEBUGP("entered\n"); | |
263 | + | |
264 | + /* bail if packet is not from RSH client */ | |
265 | + if (dir == IP_CT_DIR_REPLY) { | |
266 | + return NF_ACCEPT; | |
267 | + } | |
268 | + | |
269 | + /* Until there's been traffic both ways, don't look in packets. */ | |
270 | + if (ctinfo != IP_CT_ESTABLISHED | |
271 | + && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { | |
272 | + DEBUGP("Conntrackinfo = %u\n", ctinfo); | |
273 | + return NF_ACCEPT; | |
274 | + } | |
275 | + | |
276 | + /* Not a full tcp header? */ | |
277 | + th = skb_header_pointer(*pskb, ip_hdr(*pskb)->ihl*4, | |
278 | + sizeof(_tcph), &_tcph); | |
279 | + if (!th) { | |
280 | + DEBUGP("rsh: skb_header_pointer null\n"); | |
281 | + return NF_ACCEPT; | |
282 | + } | |
283 | + | |
284 | + /* No data? */ | |
285 | + dataoff = ip_hdr(*pskb)->ihl*4 + th->doff*4; | |
286 | + if (dataoff >= (*pskb)->len) { | |
287 | + return NF_ACCEPT; | |
288 | + } | |
289 | + datalen = (*pskb)->len - dataoff; | |
290 | + spin_lock_bh(&rsh_buffer_lock); | |
291 | + rb_ptr = skb_header_pointer(*pskb, dataoff, datalen, rsh_buffer); | |
292 | + BUG_ON(rb_ptr == NULL); | |
293 | + data = rb_ptr; | |
294 | + | |
295 | + DEBUGP("rsh: find rsh stderr port datalen %u\n",datalen); | |
296 | + | |
297 | + maxoctet = 5; | |
298 | + port = 0; | |
299 | + for ( ; *data != 0 && maxoctet != 0; data++, maxoctet--) { | |
300 | + if (*data < 0) { | |
301 | + ret = 1; goto out; | |
302 | + } | |
303 | + if (*data == 0) { | |
304 | + break; | |
305 | + } | |
306 | + if (*data < 48 || *data > 57) { | |
307 | + DEBUGP("these aren't the packets you're looking for ..\n"); | |
308 | + ret = NF_ACCEPT; goto out; | |
309 | + } | |
310 | + port = port * 10 + ( *data - 48 ); | |
311 | + } | |
312 | + | |
313 | + /* dont relate sessions that try to expose the client */ | |
314 | + if (port == 0) { | |
315 | + DEBUGP("skipping, port is 0!\n"); | |
316 | + ret = NF_ACCEPT;goto out; | |
317 | + } | |
318 | + | |
319 | + DEBUGP("found port %u\n", port); | |
320 | + if (port > range) { | |
321 | + DEBUGP("skipping, expected port size is greater than range!\n"); | |
322 | + return NF_ACCEPT; | |
323 | + } | |
324 | + | |
325 | + exp = nf_ct_expect_alloc(ct); | |
326 | + if (!exp) { | |
327 | + ret = NF_DROP; | |
328 | + goto out; | |
329 | + } | |
330 | + | |
331 | + /* new(,related) connection is; | |
332 | + * reply + dst (uint)port + src port (0:1023) | |
333 | + */ | |
334 | + | |
335 | + /* Watch out, Radioactive-Man! */ | |
336 | + exp->tuple.src.u3.ip = ct->tuplehash[!dir].tuple.src.u3.ip; | |
337 | + exp->tuple.dst.u3.ip = ct->tuplehash[!dir].tuple.dst.u3.ip; | |
338 | + exp->tuple.src.u.tcp.port = 0; | |
339 | + exp->tuple.dst.u.tcp.port = htons(port); | |
340 | + exp->tuple.dst.protonum = IPPROTO_TCP; | |
341 | + | |
342 | + exp->mask.src.u3.ip = 0xffffffff; | |
343 | + | |
344 | + exp->mask.src.u.tcp.port = htons(rangemask); | |
345 | + | |
346 | + exp->expectfn = NULL; | |
347 | + exp->master = ct; | |
348 | + | |
349 | + DEBUGP("expect related ip %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n", | |
350 | + NIPQUAD(exp->tuple.src.ip), | |
351 | + ntohs(exp->tuple.src.u.tcp.port), | |
352 | + NIPQUAD(exp->tuple.dst.ip), | |
353 | + ntohs(exp->tuple.dst.u.tcp.port)); | |
354 | + | |
355 | + if (ip_nat_rsh_hook) | |
356 | + ret = ip_nat_rsh_hook(pskb, ctinfo, rb_ptr - data, exp); | |
357 | + else if (nf_ct_expect_related(exp) != 0) { | |
358 | + ret = NF_DROP; | |
359 | + } | |
360 | + | |
361 | + nf_ct_expect_put(exp); | |
362 | + | |
363 | +out: | |
364 | + spin_unlock_bh(&rsh_buffer_lock); | |
365 | + return ret; | |
366 | +} | |
367 | + | |
368 | +static struct nf_conntrack_helper rsh_helpers[MAX_PORTS]; | |
369 | +static char rsh_names[MAX_PORTS][10]; | |
370 | +static const struct nf_conntrack_expect_policy rsh_exp_policy = { | |
371 | + .max_expected = 1, | |
372 | + .timeout = 5, /* stes bug timeout=0 */ | |
373 | +}; | |
374 | + | |
375 | +static void fini(void); | |
376 | + | |
377 | +static int __init init(void) | |
378 | +{ | |
379 | + int port, ret; | |
380 | + char *tmpname; | |
381 | + | |
382 | + /* If no port given, default to standard RSH port */ | |
383 | + if (ports[0] == 0) | |
384 | + ports[0] = RSH_PORT; | |
385 | + | |
386 | + /* the check on reserved port <1023 doesn't work with Legato */ | |
387 | + /* for Legato NetWorker, the check should be that port <= 9936 */ | |
388 | + | |
389 | + if (range == 0) | |
390 | + range = 1023; | |
391 | + | |
392 | + /* Legato uses range [ 7937 : 9936 ] -> 7937 by default */ | |
393 | + | |
394 | + rangemask = 0xffff ^ range; /* defaults to = 0xfc00 */ | |
395 | + | |
396 | + for (port = 0; (port < MAX_PORTS) && ports[port]; port++) { | |
397 | + memset(&rsh_helpers[port], 0, sizeof(struct nf_conntrack_helper)); | |
398 | + | |
399 | + tmpname = &rsh_names[port][0]; | |
400 | + if (ports[port] == RSH_PORT) | |
401 | + sprintf(tmpname, "rsh"); | |
402 | + else | |
403 | + sprintf(tmpname, "rsh-%d", ports[port]); | |
404 | + rsh_helpers[port].name = tmpname; | |
405 | + | |
406 | + rsh_helpers[port].me = THIS_MODULE; | |
407 | + rsh_helpers[port].expect_policy = &rsh_exp_policy; | |
408 | + | |
409 | + rsh_helpers[port].tuple.dst.protonum = IPPROTO_TCP; | |
410 | + | |
411 | + /* RSH must come from ports 0:1023 to ports[port] (514) */ | |
412 | + rsh_helpers[port].tuple.src.u.tcp.port = htons(ports[port]); | |
413 | + | |
414 | + rsh_helpers[port].help = help; | |
415 | + | |
416 | + PRINTK("registering helper for port #%d: %d/TCP\n", port, ports[port]); | |
417 | + PRINTK("helper match ip %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n", | |
418 | + NIPQUAD(rsh_helpers[port].tuple.src.u3.ip), | |
419 | + ntohs(rsh_helpers[port].tuple.src.u.tcp.port), | |
420 | + NIPQUAD(rsh_helpers[port].tuple.dst.u3.ip), | |
421 | + ntohs(rsh_helpers[port].tuple.dst.u.tcp.port)); | |
422 | + | |
423 | + ret = nf_conntrack_helper_register(&rsh_helpers[port]); | |
424 | + | |
425 | + if (ret) { | |
426 | + printk("ERROR registering port %d\n", | |
427 | + ports[port]); | |
428 | + fini(); | |
429 | + return -EBUSY; | |
430 | + } | |
431 | + ports_n_c++; | |
432 | + } | |
433 | + return 0; | |
434 | +} | |
435 | + | |
436 | +/* This function is intentionally _NOT_ defined as __exit, because | |
437 | + * it is needed by the init function */ | |
438 | +static void fini(void) | |
439 | +{ | |
440 | + int port; | |
441 | + for (port = 0; (port < MAX_PORTS) && ports[port]; port++) { | |
442 | + DEBUGP("unregistering port %d\n", ports[port]); | |
443 | + nf_conntrack_helper_unregister(&rsh_helpers[port]); | |
444 | + } | |
445 | +} | |
446 | + | |
447 | +module_init(init); | |
448 | +module_exit(fini); |