]> git.pld-linux.org Git - packages/kernel.git/blame - pom-ng-rpc-20060504.patch
- sip conntrack
[packages/kernel.git] / pom-ng-rpc-20060504.patch
CommitLineData
c6410bf7 1 include/linux/netfilter_ipv4/ip_conntrack_rpc.h | 71 +++
2 include/linux/netfilter_ipv4/ipt_rpc.h | 35 +
3 net/ipv4/netfilter/Kconfig | 32 +
4 net/ipv4/netfilter/Makefile | 1
5 net/ipv4/netfilter/ip_conntrack_rpc_tcp.c | 554 ++++++++++++++++++++++++
6 net/ipv4/netfilter/ip_conntrack_rpc_udp.c | 527 ++++++++++++++++++++++
7 net/ipv4/netfilter/ipt_rpc.c | 443 +++++++++++++++++++
8 7 files changed, 1663 insertions(+)
9
10diff -Nur --exclude '*.orig' linux.org/include/linux/netfilter_ipv4/ip_conntrack_rpc.h linux/include/linux/netfilter_ipv4/ip_conntrack_rpc.h
11--- linux.org/include/linux/netfilter_ipv4/ip_conntrack_rpc.h 1970-01-01 01:00:00.000000000 +0100
12+++ linux/include/linux/netfilter_ipv4/ip_conntrack_rpc.h 2006-05-04 11:26:08.000000000 +0200
13@@ -0,0 +1,71 @@
14+/* RPC extension for IP connection tracking, Version 2.2
15+ * (C) 2000 by Marcelo Barbosa Lima <marcelo.lima@dcc.unicamp.br>
16+ * - original rpc tracking module
17+ * - "recent" connection handling for kernel 2.3+ netfilter
18+ *
19+ * (C) 2001 by Rusty Russell <rusty@rustcorp.com.au>
20+ * - upgraded conntrack modules to oldnat api - kernel 2.4.0+
21+ *
22+ * (C) 2002 by Ian (Larry) Latter <Ian.Latter@mq.edu.au>
23+ * - upgraded conntrack modules to newnat api - kernel 2.4.20+
24+ * - extended matching to support filtering on procedures
25+ *
26+ * (C) 2005 by David Stes <stes@pandora.be>
27+ * - upgraded to 2.6.13 API
28+ *
29+ * ip_conntrack_rpc.h,v 2.2 2003/01/12 18:30:00
30+ *
31+ * This program is free software; you can redistribute it and/or
32+ * modify it under the terms of the GNU General Public License
33+ * as published by the Free Software Foundation; either version
34+ * 2 of the License, or (at your option) any later version.
35+ **
36+ */
37+
38+#include <asm/param.h>
39+#include <linux/sched.h>
40+#include <linux/timer.h>
41+#include <linux/stddef.h>
42+#include <linux/list.h>
43+
44+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
45+
46+#ifndef _IP_CONNTRACK_RPC_H
47+#define _IP_CONNTRACK_RPC_H
48+
49+#define RPC_PORT 111
50+
51+
52+/* Datum in RPC packets are encoded in XDR */
53+#define IXDR_GET_INT32(buf) ((u_int32_t) ntohl((uint32_t)*buf))
54+
55+/* Fast timeout, to deny DoS atacks */
56+#define EXP (60 * HZ)
57+
58+/* Normal timeouts */
59+#define EXPIRES (180 * HZ)
60+
61+/* For future conections RPC, using client's cache bindings
62+ * I'll use ip_conntrack_lock to lock these lists */
63+
64+/* This identifies each request and stores protocol */
65+struct request_p {
66+ struct list_head list;
67+
68+ u_int32_t xid;
69+ u_int32_t ip;
70+ u_int16_t port;
71+
72+ /* Protocol */
73+ u_int16_t proto;
74+
75+ struct timer_list timeout;
76+};
77+
78+static inline int request_p_cmp(const struct request_p *p, u_int32_t xid,
79+ u_int32_t ip, u_int32_t port) {
80+ return (p->xid == xid && p->ip == ip && p->port);
81+
82+}
83+
84+#endif /* _IP_CONNTRACK_RPC_H */
85diff -Nur --exclude '*.orig' linux.org/include/linux/netfilter_ipv4/ipt_rpc.h linux/include/linux/netfilter_ipv4/ipt_rpc.h
86--- linux.org/include/linux/netfilter_ipv4/ipt_rpc.h 1970-01-01 01:00:00.000000000 +0100
87+++ linux/include/linux/netfilter_ipv4/ipt_rpc.h 2006-05-04 11:26:08.000000000 +0200
88@@ -0,0 +1,35 @@
89+/* RPC extension for IP netfilter matching, Version 2.2
90+ * (C) 2000 by Marcelo Barbosa Lima <marcelo.lima@dcc.unicamp.br>
91+ * - original rpc tracking module
92+ * - "recent" connection handling for kernel 2.3+ netfilter
93+ *
94+ * (C) 2001 by Rusty Russell <rusty@rustcorp.com.au>
95+ * - upgraded conntrack modules to oldnat api - kernel 2.4.0+
96+ *
97+ * (C) 2002 by Ian (Larry) Latter <Ian.Latter@mq.edu.au>
98+ * - upgraded conntrack modules to newnat api - kernel 2.4.20+
99+ * - extended matching to support filtering on procedures
100+ *
101+ * ipt_rpc.h.c,v 2.2 2003/01/12 18:30:00
102+ *
103+ * This program is free software; you can redistribute it and/or
104+ * modify it under the terms of the GNU General Public License
105+ * as published by the Free Software Foundation; either version
106+ * 2 of the License, or (at your option) any later version.
107+ **
108+ */
109+
110+#ifndef _IPT_RPC_H
111+#define _IPT_RPC_H
112+
113+struct ipt_rpc_data;
114+
115+struct ipt_rpc_info {
116+ int inverse;
117+ int strict;
118+ const char c_procs[1408];
119+ int i_procs;
120+ struct ipt_rpc_data *data;
121+};
122+
123+#endif /* _IPT_RPC_H */
124diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/Kconfig linux/net/ipv4/netfilter/Kconfig
125--- linux.org/net/ipv4/netfilter/Kconfig 2006-05-02 23:38:44.000000000 +0200
126+++ linux/net/ipv4/netfilter/Kconfig 2006-05-04 11:26:08.000000000 +0200
127@@ -606,5 +606,37 @@
128 Allows altering the ARP packet payload: source and destination
129 hardware and network addresses.
130
131+config IP_NF_MATCH_RPC
132+ tristate 'RPC match support'
133+ depends on IP_NF_CONNTRACK && IP_NF_IPTABLES
134+ help
135+ This adds CONFIG_IP_NF_MATCH_RPC, which is the RPC connection
136+ matcher and tracker.
137+
138+ This option supplies two connection tracking modules;
139+ ip_conntrack_rpc_udp and ip_conntrack_rpc_tcp, which track
140+ portmapper requests using UDP and TCP respectively.
141+
142+ This option also adds an RPC match module for iptables, which
143+ matches both via the old "record match" method and a new
144+ "procedure match" method. The older method matches all RPC
145+ procedure packets that relate to previously recorded packets
146+ seen querying a portmapper. The newer method matches only
147+ those RPC procedure packets explicitly specified by the user,
148+ and that can then be related to previously recorded packets
149+ seen querying a portmapper.
150+
151+ These three modules are required if RPCs are to be filtered
152+ accurately; as RPCs are allocated pseudo-randomly to UDP and
153+ TCP ports as they register with the portmapper.
154+
155+ Up to 8 portmapper ports per module, and up to 128 RPC
156+ procedures per iptables rule, may be specified by the user,
157+ to enable effective RPC management.
158+
159+
160+ If you want to compile it as a module, say M here and read
161+ <file:Documentation/modules.txt>. If unsure, say `N'.
162+
163 endmenu
164
165diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/Makefile linux/net/ipv4/netfilter/Makefile
166--- linux.org/net/ipv4/netfilter/Makefile 2006-05-02 23:38:44.000000000 +0200
167+++ linux/net/ipv4/netfilter/Makefile 2006-05-04 11:26:08.000000000 +0200
168@@ -0,0 +0,1 @@
169+obj-$(CONFIG_IP_NF_MATCH_RPC) += ip_conntrack_rpc_tcp.o ip_conntrack_rpc_udp.o ipt_rpc.o
170diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/ip_conntrack_rpc_tcp.c linux/net/ipv4/netfilter/ip_conntrack_rpc_tcp.c
171--- linux.org/net/ipv4/netfilter/ip_conntrack_rpc_tcp.c 1970-01-01 01:00:00.000000000 +0100
172+++ linux/net/ipv4/netfilter/ip_conntrack_rpc_tcp.c 2006-05-04 11:26:08.000000000 +0200
173@@ -0,0 +1,554 @@
174+/* RPC extension for IP (TCP) connection tracking, Version 2.2
175+ * (C) 2000 by Marcelo Barbosa Lima <marcelo.lima@dcc.unicamp.br>
176+ * - original rpc tracking module
177+ * - "recent" connection handling for kernel 2.3+ netfilter
178+ *
179+ * (C) 2001 by Rusty Russell <rusty@rustcorp.com.au>
180+ * - upgraded conntrack modules to oldnat api - kernel 2.4.0+
181+ *
182+ * (C) 2002,2003 by Ian (Larry) Latter <Ian.Latter@mq.edu.au>
183+ * - upgraded conntrack modules to newnat api - kernel 2.4.20+
184+ * - extended matching to support filtering on procedures
185+ *
186+ * (c) 2004,2005 by David Stes <stes@pandora.be>
187+ * - add nsrexec option for Legato NetWorker
188+ * - upgraded to 2.6.12+ conntrack module api
189+ *
190+ * (c) 2005 by David Stes <stes@pandora.be>
191+ * - upgraded to 2.6.13 conntrack module api
192+ *
193+ * ip_conntrack_rpc_tpc.c,v 2.2 2003/01/12 18:30:00
194+ *
195+ * This program is free software; you can redistribute it and/or
196+ * modify it under the terms of the GNU General Public License
197+ * as published by the Free Software Foundation; either version
198+ * 2 of the License, or (at your option) any later version.
199+ **
200+ * Module load syntax:
201+ * insmod ip_conntrack_rpc_tcp.o nsrexec=<n> ports=port1,...port<MAX_PORTS>
202+ *
203+ * Please give the ports of all RPC servers you wish to connect to.
204+ * For example, ports=111,7938 for Legato NetWorker's portmapper on 7938.
205+ * If you don't specify ports, the default will be port 111 (SUN portmap).
206+ *
207+ * Please specify nsrexec, the TCP port of the rexec() service of
208+ * Legato NetWorker. For example, nsrexec=7937
209+ *
210+ **
211+ * Note to all:
212+ *
213+ * RPCs should not be exposed to the internet - ask the Pentagon;
214+ *
215+ * "The unidentified crackers pleaded guilty in July to charges
216+ * of juvenile delinquency stemming from a string of Pentagon
217+ * network intrusions in February.
218+ *
219+ * The youths, going by the names TooShort and Makaveli, used
220+ * a common server security hole to break in, according to
221+ * Dane Jasper, owner of the California Internet service
222+ * provider, Sonic. They used the hole, known as the 'statd'
223+ * exploit, to attempt more than 800 break-ins, Jasper said."
224+ *
225+ * From: Wired News; "Pentagon Kids Kicked Off Grid" - Nov 6, 1998
226+ * URL: http://www.wired.com/news/politics/0,1283,16098,00.html
227+ **
228+ */
229+
230+#include <linux/module.h>
231+#include <linux/netfilter.h>
232+#include <linux/ip.h>
233+#include <net/checksum.h>
234+#include <net/tcp.h>
235+
236+#include <asm/param.h>
237+#include <linux/sched.h>
238+#include <linux/timer.h>
239+#include <linux/stddef.h>
240+#include <linux/list.h>
241+
242+#include <linux/netfilter_ipv4/ip_tables.h>
243+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
244+#include <linux/netfilter_ipv4/ip_conntrack_rpc.h>
245+
246+#define MAX_PORTS 8
247+static int ports[MAX_PORTS];
248+static int ports_n_c = 0;
249+static int nsrexec = 0;
250+
251+#ifdef MODULE_PARM
252+module_param(nsrexec,int, 0400);
253+MODULE_PARM_DESC(nsrexec, "TCP port of Legato NetWorker's rexec service");
254+module_param_array(ports, int, &ports_n_c, 0400);
255+MODULE_PARM_DESC(ports, "port numbers (TCP/UDP) of RPC portmapper servers");
256+#endif
257+
258+MODULE_AUTHOR("Marcelo Barbosa Lima <marcelo.lima@dcc.unicamp.br>");
259+MODULE_DESCRIPTION("RPC TCP connection tracking module");
260+MODULE_LICENSE("GPL");
261+
262+#define PRINTK(format, args...) printk(KERN_DEBUG "ip_conntrack_rpc_tcp: " \
263+ format, ## args)
264+
265+#if 0
266+#define DEBUGP(format, args...) printk(KERN_DEBUG "ip_conntrack_rpc_tcp: " \
267+ format, ## args)
268+#else
269+#define DEBUGP(format, args...)
270+#endif
271+
272+DEFINE_RWLOCK(ipct_rpc_tcp_lock);
273+
274+#define ASSERT_READ_LOCK(x)
275+#define ASSERT_WRITE_LOCK(x)
276+
277+#include <linux/netfilter_ipv4/listhelp.h>
278+
279+/* For future conections RPC, using client's cache bindings
280+ * I'll use ip_conntrack_lock to lock these lists */
281+
282+LIST_HEAD(request_p_list_tcp);
283+
284+
285+static void delete_request_p(unsigned long request_p_ul)
286+{
287+ struct request_p *p = (void *)request_p_ul;
288+
289+ write_lock_bh(&ipct_rpc_tcp_lock);
290+ LIST_DELETE(&request_p_list_tcp, p);
291+ write_unlock_bh(&ipct_rpc_tcp_lock);
292+ kfree(p);
293+ return;
294+}
295+
296+
297+static void req_cl(struct request_p * r)
298+{
299+ write_lock_bh(&ipct_rpc_tcp_lock);
300+ del_timer(&r->timeout);
301+ LIST_DELETE(&request_p_list_tcp, r);
302+ write_unlock_bh(&ipct_rpc_tcp_lock);
303+ kfree(r);
304+ return;
305+}
306+
307+
308+static void clean_request(struct list_head *list)
309+{
310+ struct list_head *first = list->prev;
311+ struct list_head *temp = list->next;
312+ struct list_head *aux;
313+
314+ if (list_empty(list))
315+ return;
316+
317+ while (first != temp) {
318+ aux = temp->next;
319+ req_cl((struct request_p *)temp);
320+ temp = aux;
321+ }
322+ req_cl((struct request_p *)temp);
323+ return;
324+}
325+
326+
327+static void alloc_request_p(u_int32_t xid, u_int16_t proto, u_int32_t ip,
328+ u_int16_t port)
329+{
330+ struct request_p *req_p;
331+
332+ /* Verifies if entry already exists */
333+ write_lock_bh(&ipct_rpc_tcp_lock);
334+ req_p = LIST_FIND(&request_p_list_tcp, request_p_cmp,
335+ struct request_p *, xid, ip, port);
336+
337+ if (req_p) {
338+ /* Refresh timeout */
339+ if (del_timer(&req_p->timeout)) {
340+ req_p->timeout.expires = jiffies + EXP;
341+ add_timer(&req_p->timeout);
342+ }
343+ write_unlock_bh(&ipct_rpc_tcp_lock);
344+ return;
345+
346+ }
347+ write_unlock_bh(&ipct_rpc_tcp_lock);
348+
349+ /* Allocate new request_p */
350+ req_p = (struct request_p *) kmalloc(sizeof(struct request_p), GFP_ATOMIC);
351+ if (!req_p) {
352+ DEBUGP("can't allocate request_p\n");
353+ return;
354+ }
355+
356+ req_p->list.next = NULL;
357+ req_p->list.prev = NULL;
358+ req_p->xid = xid;
359+ req_p->ip = ip;
360+ req_p->port = port;
361+ req_p->proto = proto;
362+
363+ /* Initialize timer */
364+ init_timer(&req_p->timeout);
365+ req_p->timeout.expires = jiffies + EXP;
366+ req_p->timeout.data = (unsigned long)req_p;
367+ req_p->timeout.function = delete_request_p;
368+ add_timer(&req_p->timeout);
369+
370+ /* Put in list */
371+ write_lock_bh(&ipct_rpc_tcp_lock);
372+ list_prepend(&request_p_list_tcp, req_p);
373+ write_unlock_bh(&ipct_rpc_tcp_lock);
374+ return;
375+}
376+
377+
378+static int check_rpc_packet(const u_int32_t *data,
379+ int dir, struct ip_conntrack *ct,
380+ struct list_head request_p_list)
381+{
382+ u_int32_t xid;
383+ int ret = NF_ACCEPT;
384+ struct request_p *req_p;
385+ struct ip_conntrack_expect *exp;
386+
387+
388+ if (ct == NULL) {
389+ DEBUGP("ct is NULL");
390+ return ret;
391+ }
392+
393+ /* Translstion's buffer for XDR */
394+ u_int16_t port_buf;
395+
396+ /* Get XID */
397+ xid = *data;
398+
399+ /* This does sanity checking on RPC payloads,
400+ * and permits only the RPC "get port" (3)
401+ * in authorised procedures in client
402+ * communications with the portmapper.
403+ */
404+
405+ /* perform direction dependant RPC work */
406+ if (dir == IP_CT_DIR_ORIGINAL) {
407+
408+ data += 5;
409+
410+ /* Get RPC requestor */
411+ if (IXDR_GET_INT32(data) != 3) {
412+ DEBUGP("RPC packet contains an invalid (non \"get\") requestor. [skip]\n");
413+ return NF_ACCEPT;
414+ }
415+ DEBUGP("RPC packet contains a \"get\" requestor. [cont]\n");
416+
417+ data++;
418+
419+ /* Jump Credentials and Verfifier */
420+ data += IXDR_GET_INT32(data) + 2;
421+ data += IXDR_GET_INT32(data) + 2;
422+
423+ /* Get RPC procedure */
424+ DEBUGP("RPC packet contains procedure request [%u]. [cont]\n",
425+ (unsigned int)IXDR_GET_INT32(data));
426+
427+ /* Get RPC protocol and store against client parameters */
428+ data = data + 2;
429+ alloc_request_p(xid, IXDR_GET_INT32(data), ct->tuplehash[dir].tuple.src.ip,
430+ ct->tuplehash[dir].tuple.src.u.all);
431+
432+ DEBUGP("allocated RPC req_p for xid=%u proto=%u %u.%u.%u.%u:%u\n",
433+ xid, IXDR_GET_INT32(data),
434+ NIPQUAD(ct->tuplehash[dir].tuple.src.ip),
435+ ntohs(ct->tuplehash[dir].tuple.src.u.all));
436+
437+ DEBUGP("allocated RPC request for protocol %u. [done]\n",
438+ (unsigned int)IXDR_GET_INT32(data));
439+
440+ } else {
441+
442+ /* Check for returning packet's stored counterpart */
443+ req_p = LIST_FIND(&request_p_list_tcp, request_p_cmp,
444+ struct request_p *, xid,
445+ ct->tuplehash[!dir].tuple.src.ip,
446+ ct->tuplehash[!dir].tuple.src.u.all);
447+
448+ /* Drop unexpected packets */
449+ if (!req_p) {
450+ DEBUGP("packet is not expected. [skip]\n");
451+ return NF_ACCEPT;
452+ }
453+
454+ /* Verifies if packet is really an RPC reply packet */
455+ data++;
456+ if (IXDR_GET_INT32(data) != 1) {
457+ DEBUGP("packet is not a valid RPC reply. [skip]\n");
458+ return NF_ACCEPT;
459+ }
460+
461+ /* Is status accept? */
462+ data++;
463+ if (IXDR_GET_INT32(data)) {
464+ DEBUGP("packet is not an RPC accept. [skip]\n");
465+ return NF_ACCEPT;
466+ }
467+
468+ /* Get Verifier length. Jump verifier */
469+ data++;
470+ data = data + IXDR_GET_INT32(data) + 2;
471+
472+ /* Is accpet status "success"? */
473+ if (IXDR_GET_INT32(data)) {
474+ DEBUGP("packet is not an RPC accept status of success. [skip]\n");
475+ return NF_ACCEPT;
476+ }
477+
478+ /* Get server port number */
479+ data++;
480+ port_buf = (u_int16_t) IXDR_GET_INT32(data);
481+
482+ /* If a packet has made it this far then it deserves an
483+ * expectation ... if port == 0, then this service is
484+ * not going to be registered.
485+ */
486+ if (port_buf && port_buf != nsrexec) {
487+ DEBUGP("port found: %u\n", port_buf);
488+
489+ exp = ip_conntrack_expect_alloc(ct);
490+ if (!exp) {
491+ ret = NF_DROP;
492+ goto out;
493+ }
494+
495+ /* Watch out, Radioactive-Man! */
496+ exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
497+ exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
498+ exp->mask.src.ip = 0xffffffff;
499+ exp->mask.dst.ip = 0xffffffff;
500+
501+ switch (req_p->proto) {
502+ case IPPROTO_UDP:
503+ exp->tuple.src.u.udp.port = 0;
504+ exp->tuple.dst.u.udp.port = htons(port_buf);
505+ exp->tuple.dst.protonum = IPPROTO_UDP;
506+ exp->mask.src.u.udp.port = 0;
507+ exp->mask.dst.u.udp.port = htons(0xffff);
508+ exp->mask.dst.protonum = 0xff;
509+ break;
510+
511+ case IPPROTO_TCP:
512+ exp->tuple.src.u.tcp.port = 0;
513+ exp->tuple.dst.u.tcp.port = htons(port_buf);
514+ exp->tuple.dst.protonum = IPPROTO_TCP;
515+ exp->mask.src.u.tcp.port = 0;
516+ exp->mask.dst.u.tcp.port = htons(0xffff);
517+ exp->mask.dst.protonum = 0xff;
518+ break;
519+ }
520+ exp->expectfn = NULL;
521+ exp->master = ct;
522+
523+ if (exp->master->helper == NULL) {
524+ DEBUGP("master helper NULL");
525+ ret = NF_ACCEPT;
526+ }
527+
528+ DEBUGP("expect related ip %u.%u.%u.%u:0-%u.%u.%u.%u:%u proto=%u\n",
529+ NIPQUAD(exp->tuple.src.ip),
530+ NIPQUAD(exp->tuple.dst.ip),
531+ port_buf, req_p->proto);
532+
533+ DEBUGP("expect related mask %u.%u.%u.%u:0-%u.%u.%u.%u:65535 proto=%u\n",
534+ NIPQUAD(exp->mask.src.ip),
535+ NIPQUAD(exp->mask.dst.ip),
536+ exp->mask.dst.protonum);
537+
538+ if (ip_conntrack_expect_related(exp) != 0) {
539+ ret = NF_DROP;
540+ }
541+
542+ }
543+
544+out:
545+ req_cl(req_p);
546+
547+ DEBUGP("packet evaluated. [expect]\n");
548+ }
549+
550+ return ret;
551+
552+}
553+
554+
555+/* RPC TCP helper */
556+/* static int help(const struct iphdr *iph, size_t len,
557+ struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) */
558+static int help(struct sk_buff **pskb,
559+ struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
560+{
561+ int dir;
562+ int crp_ret;
563+ struct tcphdr _tcph, *tcph;
564+ const u_int32_t *data;
565+ size_t tcplen;
566+ struct iphdr *iph;
567+ size_t len;
568+
569+ /* Not whole TCP header? */
570+ iph=(*pskb)->nh.iph;
571+ tcph = skb_header_pointer(*pskb,iph->ihl*4,sizeof(_tcph),&_tcph);
572+ if (!tcph)
573+ return NF_ACCEPT;
574+
575+ len = (*pskb)->len; /* stes */
576+ data = (const u_int32_t *)tcph + tcph->doff;
577+ tcplen = len - iph->ihl * 4;
578+ dir = CTINFO2DIR(ctinfo);
579+
580+ DEBUGP("new packet to evaluate ..\n");
581+
582+ /* This works for packets like handshake packets, ignore */
583+ if (len == ((tcph->doff + iph->ihl) * 4)) {
584+ DEBUGP("packet has no data (may still be handshaking). [skip]\n");
585+ return NF_ACCEPT;
586+ }
587+
588+ /* Until there's been traffic both ways, don't look in packets. */
589+ if (ctinfo != IP_CT_ESTABLISHED
590+ && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
591+ DEBUGP("connection tracking state is; ctinfo=%u ..\n", ctinfo);
592+ DEBUGP("[note: failure to get past this error may indicate asymmetric routing]\n");
593+ DEBUGP("packet is not yet part of a two way stream. [skip]\n");
594+ return NF_ACCEPT;
595+ }
596+
597+ /* Not whole TCP header? */
598+ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) {
599+ DEBUGP("TCP header length is; tcplen=%u ..\n", (unsigned) tcplen);
600+ DEBUGP("packet does not contain a complete TCP header. [skip]\n");
601+ return NF_ACCEPT;
602+ }
603+
604+ /* perform direction dependant protocol work */
605+ if (dir == IP_CT_DIR_ORIGINAL) {
606+
607+ DEBUGP("packet is from the initiator. [cont]\n");
608+
609+ /* Tests if packet len is ok */
610+ if ((tcplen - (tcph->doff * 4)) != 60) {
611+ DEBUGP("packet length is not correct. [skip]\n");
612+ return NF_ACCEPT;
613+ }
614+
615+ } else {
616+
617+ DEBUGP("packet is from the receiver. [cont]\n");
618+
619+ /* Tests if packet len is ok */
620+ if ((tcplen - (tcph->doff * 4)) != 32) {
621+ DEBUGP("packet length is not correct. [skip]\n");
622+ return NF_ACCEPT;
623+ }
624+ }
625+
626+ /* Get to the data */
627+ data++;
628+
629+ /* Check the RPC data */
630+ crp_ret = check_rpc_packet(data, dir, ct, request_p_list_tcp);
631+
632+ return crp_ret;
633+
634+}
635+
636+
637+static struct ip_conntrack_helper rpc_helpers[MAX_PORTS];
638+static char rpc_names[MAX_PORTS][10];
639+
640+static void fini(void);
641+
642+static int __init init(void)
643+{
644+ int port, ret;
645+ char *tmpname;
646+
647+ /* If no port given, default to standard RPC port */
648+ if (ports[0] == 0)
649+ ports[0] = RPC_PORT;
650+
651+ for (port = 0; (port < MAX_PORTS) && ports[port]; port++) {
652+ memset(&rpc_helpers[port], 0, sizeof(struct ip_conntrack_helper));
653+
654+ tmpname = &rpc_names[port][0];
655+ if (ports[port] == RPC_PORT)
656+ sprintf(tmpname, "rpc");
657+ else
658+ sprintf(tmpname, "rpc-%d", ports[port]);
659+ rpc_helpers[port].name = tmpname;
660+
661+ rpc_helpers[port].me = THIS_MODULE;
662+ rpc_helpers[port].max_expected = 1;
663+ rpc_helpers[port].timeout = 5 * 60; /* stes */
664+
665+ rpc_helpers[port].tuple.dst.protonum = IPPROTO_TCP;
666+ rpc_helpers[port].mask.dst.protonum = 0xff;
667+
668+ /* RPC can come from ports 0:65535 to ports[port] (111) */
669+ rpc_helpers[port].tuple.src.u.tcp.port = htons(ports[port]);
670+ rpc_helpers[port].mask.src.u.tcp.port = htons(0xffff);
671+ rpc_helpers[port].mask.dst.u.tcp.port = htons(0x0);
672+
673+ rpc_helpers[port].help = help;
674+
675+ PRINTK("registering helper for port #%d: %d/TCP\n", port, ports[port]);
676+ PRINTK("helper match ip %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
677+ NIPQUAD(rpc_helpers[port].tuple.dst.ip),
678+ ntohs(rpc_helpers[port].tuple.dst.u.tcp.port),
679+ NIPQUAD(rpc_helpers[port].tuple.src.ip),
680+ ntohs(rpc_helpers[port].tuple.src.u.tcp.port));
681+ PRINTK("helper match mask %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
682+ NIPQUAD(rpc_helpers[port].mask.dst.ip),
683+ ntohs(rpc_helpers[port].mask.dst.u.tcp.port),
684+ NIPQUAD(rpc_helpers[port].mask.src.ip),
685+ ntohs(rpc_helpers[port].mask.src.u.tcp.port));
686+
687+ ret = ip_conntrack_helper_register(&rpc_helpers[port]);
688+
689+ if (ret) {
690+ printk("ERROR registering port %d\n",
691+ ports[port]);
692+ fini();
693+ return -EBUSY;
694+ }
695+ ports_n_c++;
696+ }
697+
698+ PRINTK("%s Legato NetWorker support for port %d/TCP\n", (nsrexec)?"enabling":"disabling", nsrexec);
699+
700+ return 0;
701+}
702+
703+
704+/* This function is intentionally _NOT_ defined as __exit, because
705+ * it is needed by the init function */
706+static void fini(void)
707+{
708+ int port;
709+
710+ DEBUGP("cleaning request list\n");
711+ clean_request(&request_p_list_tcp);
712+
713+ for (port = 0; (port < ports_n_c) && ports[port]; port++) {
714+ DEBUGP("unregistering port %d\n", ports[port]);
715+ ip_conntrack_helper_unregister(&rpc_helpers[port]);
716+ }
717+}
718+
719+
720+module_init(init);
721+module_exit(fini);
722+
723+struct module *ip_conntrack_rpc_tcp = THIS_MODULE;
724+EXPORT_SYMBOL(request_p_list_tcp);
725+EXPORT_SYMBOL(ip_conntrack_rpc_tcp);
726+EXPORT_SYMBOL(ipct_rpc_tcp_lock);
727+
728diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/ip_conntrack_rpc_udp.c linux/net/ipv4/netfilter/ip_conntrack_rpc_udp.c
729--- linux.org/net/ipv4/netfilter/ip_conntrack_rpc_udp.c 1970-01-01 01:00:00.000000000 +0100
730+++ linux/net/ipv4/netfilter/ip_conntrack_rpc_udp.c 2006-05-04 11:26:08.000000000 +0200
731@@ -0,0 +1,528 @@
732+/* RPC extension for IP (UDP) connection tracking, Version 2.2
733+ * (C) 2000 by Marcelo Barbosa Lima <marcelo.lima@dcc.unicamp.br>
734+ * - original rpc tracking module
735+ * - "recent" connection handling for kernel 2.3+ netfilter
736+ *
737+ * (C) 2001 by Rusty Russell <rusty@rustcorp.com.au>
738+ * - upgraded conntrack modules to oldnat api - kernel 2.4.0+
739+ *
740+ * (C) 2002,2003 by Ian (Larry) Latter <Ian.Latter@mq.edu.au>
741+ * - upgraded conntrack modules to newnat api - kernel 2.4.20+
742+ * - extended matching to support filtering on procedures
743+ *
744+ * (c) 2004,2005 by David Stes <stes@pandora.be>
745+ * - upgraded to 2.6.12+ conntrack module api
746+ *
747+ * (c) 2005 by David Stes <stes@pandora.be>
748+ * - upgraded to 2.6.13 api
749+ *
750+ * ip_conntrack_rpc_udp.c,v 2.2 2003/01/12 18:30:00
751+ *
752+ * This program is free software; you can redistribute it and/or
753+ * modify it under the terms of the GNU General Public License
754+ * as published by the Free Software Foundation; either version
755+ * 2 of the License, or (at your option) any later version.
756+ **
757+ * Module load syntax:
758+ * insmod ip_conntrack_rpc_udp.o ports=port1,port2,...port<MAX_PORTS>
759+ *
760+ * Please give the ports of all RPC servers you wish to connect to.
761+ * If you don't specify ports, the default will be port 111.
762+ **
763+ * Note to all:
764+ *
765+ * RPCs should not be exposed to the internet - ask the Pentagon;
766+ *
767+ * "The unidentified crackers pleaded guilty in July to charges
768+ * of juvenile delinquency stemming from a string of Pentagon
769+ * network intrusions in February.
770+ *
771+ * The youths, going by the names TooShort and Makaveli, used
772+ * a common server security hole to break in, according to
773+ * Dane Jasper, owner of the California Internet service
774+ * provider, Sonic. They used the hole, known as the 'statd'
775+ * exploit, to attempt more than 800 break-ins, Jasper said."
776+ *
777+ * From: Wired News; "Pentagon Kids Kicked Off Grid" - Nov 6, 1998
778+ * URL: http://www.wired.com/news/politics/0,1283,16098,00.html
779+ **
780+ */
781+
782+#include <linux/module.h>
783+#include <linux/netfilter.h>
784+#include <linux/ip.h>
785+#include <net/checksum.h>
786+#include <net/udp.h>
787+
788+#include <asm/param.h>
789+#include <linux/sched.h>
790+#include <linux/timer.h>
791+#include <linux/stddef.h>
792+#include <linux/list.h>
793+#include <linux/udp.h>
794+
795+#include <linux/netfilter_ipv4/ip_tables.h>
796+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
797+#include <linux/netfilter_ipv4/ip_conntrack_rpc.h>
798+
799+#define MAX_PORTS 8
800+static int ports[MAX_PORTS];
801+static int ports_n_c = 0;
802+
803+#ifdef MODULE_PARM
804+module_param_array(ports, int, &ports_n_c, 0400);
805+MODULE_PARM_DESC(ports, "port numbers (TCP/UDP) of RPC portmapper servers");
806+#endif
807+
808+MODULE_AUTHOR("Marcelo Barbosa Lima <marcelo.lima@dcc.unicamp.br>");
809+MODULE_DESCRIPTION("RPC UDP connection tracking module");
810+MODULE_LICENSE("GPL");
811+
812+#define PRINTK(format, args...) printk(KERN_DEBUG "ip_conntrack_rpc_udp: " \
813+ format, ## args)
814+
815+#if 0
816+#define DEBUGP(format, args...) printk(KERN_DEBUG "ip_conntrack_rpc_udp: " \
817+ format, ## args)
818+#else
819+#define DEBUGP(format, args...)
820+#endif
821+
822+DEFINE_RWLOCK(ipct_rpc_udp_lock);
823+#define ASSERT_READ_LOCK(x)
824+#define ASSERT_WRITE_LOCK(x)
825+#include <linux/netfilter_ipv4/listhelp.h>
826+
827+/* For future conections RPC, using client's cache bindings
828+ * I'll use ip_conntrack_lock to lock these lists */
829+
830+LIST_HEAD(request_p_list_udp);
831+
832+
833+static void delete_request_p(unsigned long request_p_ul)
834+{
835+ struct request_p *p = (void *)request_p_ul;
836+
837+ write_lock_bh(&ipct_rpc_udp_lock);
838+ LIST_DELETE(&request_p_list_udp, p);
839+ write_unlock_bh(&ipct_rpc_udp_lock);
840+ kfree(p);
841+ return;
842+}
843+
844+
845+static void req_cl(struct request_p * r)
846+{
847+ write_lock_bh(&ipct_rpc_udp_lock);
848+ del_timer(&r->timeout);
849+ LIST_DELETE(&request_p_list_udp, r);
850+ write_unlock_bh(&ipct_rpc_udp_lock);
851+ kfree(r);
852+ return;
853+}
854+
855+
856+static void clean_request(struct list_head *list)
857+{
858+ struct list_head *first = list->prev;
859+ struct list_head *temp = list->next;
860+ struct list_head *aux;
861+
862+ if (list_empty(list))
863+ return;
864+
865+ while (first != temp) {
866+ aux = temp->next;
867+ req_cl((struct request_p *)temp);
868+ temp = aux;
869+ }
870+ req_cl((struct request_p *)temp);
871+ return;
872+}
873+
874+
875+static void alloc_request_p(u_int32_t xid, u_int16_t proto, u_int32_t ip,
876+ u_int16_t port)
877+{
878+ struct request_p *req_p;
879+
880+ /* Verifies if entry already exists */
881+ write_lock_bh(&ipct_rpc_udp_lock);
882+ req_p = LIST_FIND(&request_p_list_udp, request_p_cmp,
883+ struct request_p *, xid, ip, port);
884+
885+ if (req_p) {
886+ /* Refresh timeout */
887+ if (del_timer(&req_p->timeout)) {
888+ req_p->timeout.expires = jiffies + EXP;
889+ add_timer(&req_p->timeout);
890+ }
891+ write_unlock_bh(&ipct_rpc_udp_lock);
892+ return;
893+
894+ }
895+ write_unlock_bh(&ipct_rpc_udp_lock);
896+
897+ /* Allocate new request_p */
898+ req_p = (struct request_p *) kmalloc(sizeof(struct request_p), GFP_ATOMIC);
899+ if (!req_p) {
900+ DEBUGP("can't allocate request_p\n");
901+ return;
902+ }
903+
904+ req_p->list.next = NULL;
905+ req_p->list.prev = NULL;
906+ req_p->xid = xid;
907+ req_p->ip = ip;
908+ req_p->port = port;
909+ req_p->proto = proto;
910+
911+ /* Initialize timer */
912+ init_timer(&req_p->timeout);
913+ req_p->timeout.expires = jiffies + EXP;
914+ req_p->timeout.data = (unsigned long)req_p;
915+ req_p->timeout.function = delete_request_p;
916+ add_timer(&req_p->timeout);
917+
918+ /* Put in list */
919+ write_lock_bh(&ipct_rpc_udp_lock);
920+ list_prepend(&request_p_list_udp, req_p);
921+ write_unlock_bh(&ipct_rpc_udp_lock);
922+ return;
923+
924+}
925+
926+
927+static int check_rpc_packet(const u_int32_t *data,
928+ int dir, struct ip_conntrack *ct,
929+ struct list_head request_p_list)
930+{
931+ int ret = NF_ACCEPT;
932+ u_int32_t xid;
933+ struct request_p *req_p;
934+ struct ip_conntrack_expect *exp;
935+
936+ /* Translstion's buffer for XDR */
937+ u_int16_t port_buf;
938+
939+
940+ /* Get XID */
941+ xid = *data;
942+
943+ /* This does sanity checking on RPC payloads,
944+ * and permits only the RPC "get port" (3)
945+ * in authorised procedures in client
946+ * communications with the portmapper.
947+ */
948+
949+ /* perform direction dependant RPC work */
950+ if (dir == IP_CT_DIR_ORIGINAL) {
951+
952+ data += 5;
953+
954+ /* Get RPC requestor */
955+ if (IXDR_GET_INT32(data) != 3) {
956+ DEBUGP("RPC packet contains an invalid (non \"get\") requestor. [skip]\n");
957+ return NF_ACCEPT;
958+ }
959+ DEBUGP("RPC packet contains a \"get\" requestor. [cont]\n");
960+
961+ data++;
962+
963+ /* Jump Credentials and Verfifier */
964+ data = data + IXDR_GET_INT32(data) + 2;
965+ data = data + IXDR_GET_INT32(data) + 2;
966+
967+ /* Get RPC procedure */
968+ DEBUGP("RPC packet contains procedure request [%u]. [cont]\n",
969+ (unsigned int)IXDR_GET_INT32(data));
970+
971+ /* Get RPC protocol and store against client parameters */
972+ data = data + 2;
973+ alloc_request_p(xid, IXDR_GET_INT32(data), ct->tuplehash[dir].tuple.src.ip,
974+ ct->tuplehash[dir].tuple.src.u.all);
975+
976+ DEBUGP("allocated RPC req_p for xid=%u proto=%u %u.%u.%u.%u:%u\n",
977+ xid, IXDR_GET_INT32(data),
978+ NIPQUAD(ct->tuplehash[dir].tuple.src.ip),
979+ ntohs(ct->tuplehash[dir].tuple.src.u.all));
980+
981+ DEBUGP("allocated RPC request for protocol %u. [done]\n",
982+ (unsigned int)IXDR_GET_INT32(data));
983+
984+ } else {
985+
986+ /* Check for returning packet's stored counterpart */
987+ req_p = LIST_FIND(&request_p_list_udp, request_p_cmp,
988+ struct request_p *, xid,
989+ ct->tuplehash[!dir].tuple.src.ip,
990+ ct->tuplehash[!dir].tuple.src.u.all);
991+
992+ /* Drop unexpected packets */
993+ if (!req_p) {
994+ DEBUGP("packet is not expected. [skip]\n");
995+ return NF_ACCEPT;
996+ }
997+
998+ /* Verifies if packet is really an RPC reply packet */
999+ data++;
1000+ if (IXDR_GET_INT32(data) != 1) {
1001+ DEBUGP("packet is not a valid RPC reply. [skip]\n");
1002+ return NF_ACCEPT;
1003+ }
1004+
1005+ /* Is status accept? */
1006+ data++;
1007+ if (IXDR_GET_INT32(data)) {
1008+ DEBUGP("packet is not an RPC accept. [skip]\n");
1009+ return NF_ACCEPT;
1010+ }
1011+
1012+ /* Get Verifier length. Jump verifier */
1013+ data++;
1014+ data = data + IXDR_GET_INT32(data) + 2;
1015+
1016+ /* Is accpet status "success"? */
1017+ if (IXDR_GET_INT32(data)) {
1018+ DEBUGP("packet is not an RPC accept status of success. [skip]\n");
1019+ return NF_ACCEPT;
1020+ }
1021+
1022+ /* Get server port number */
1023+ data++;
1024+ port_buf = (u_int16_t) IXDR_GET_INT32(data);
1025+
1026+ /* If a packet has made it this far then it deserves an
1027+ * expectation ... if port == 0, then this service is
1028+ * not going to be registered.
1029+ */
1030+ if (port_buf) {
1031+ DEBUGP("port found: %u\n", port_buf);
1032+
1033+ exp = ip_conntrack_expect_alloc(ct);
1034+ if (!exp) {
1035+ ret = NF_DROP;
1036+ goto out;
1037+ }
1038+
1039+ /* Watch out, Radioactive-Man! */
1040+ exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
1041+ exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
1042+ exp->mask.src.ip = 0xffffffff;
1043+ exp->mask.dst.ip = 0xffffffff;
1044+
1045+ switch (req_p->proto) {
1046+ case IPPROTO_UDP:
1047+ exp->tuple.src.u.udp.port = 0;
1048+ exp->tuple.dst.u.udp.port = htons(port_buf);
1049+ exp->tuple.dst.protonum = IPPROTO_UDP;
1050+ exp->mask.src.u.udp.port = 0;
1051+ exp->mask.dst.u.udp.port = htons(0xffff);
1052+ exp->mask.dst.protonum = 0xff;
1053+ break;
1054+
1055+ case IPPROTO_TCP:
1056+ exp->tuple.src.u.tcp.port = 0;
1057+ exp->tuple.dst.u.tcp.port = htons(port_buf);
1058+ exp->tuple.dst.protonum = IPPROTO_TCP;
1059+ exp->mask.src.u.tcp.port = 0;
1060+ exp->mask.dst.u.tcp.port = htons(0xffff);
1061+ exp->mask.dst.protonum = 0xff;
1062+ break;
1063+ }
1064+ exp->expectfn = NULL;
1065+ exp->master = ct;
1066+
1067+ DEBUGP("expect related ip %u.%u.%u.%u:0-%u.%u.%u.%u:%u proto=%u\n",
1068+ NIPQUAD(exp->tuple.src.ip),
1069+ NIPQUAD(exp->tuple.dst.ip),
1070+ port_buf, req_p->proto);
1071+
1072+ DEBUGP("expect related mask %u.%u.%u.%u:0-%u.%u.%u.%u:65535 proto=%u\n",
1073+ NIPQUAD(exp->mask.src.ip),
1074+ NIPQUAD(exp->mask.dst.ip),
1075+ exp->mask.dst.protonum);
1076+
1077+ if (ip_conntrack_expect_related(exp) != 0) {
1078+ ret = NF_DROP;
1079+ }
1080+ }
1081+
1082+out:
1083+ req_cl(req_p);
1084+
1085+ DEBUGP("packet evaluated. [expect]\n");
1086+ }
1087+
1088+ return ret;
1089+}
1090+
1091+
1092+/* RPC UDP helper */
1093+/* static int help(const struct iphdr *iph, size_t len,
1094+ struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) */
1095+static int help(struct sk_buff **pskb,
1096+ struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
1097+{
1098+ int dir;
1099+ int crp_ret;
1100+ struct udphdr _udph, *udph;
1101+ const u_int32_t *data;
1102+ size_t udplen;
1103+ struct iphdr *iph;
1104+ size_t len;
1105+ const u_int16_t *chsm;
1106+
1107+ /* Not whole UDP header? */
1108+ iph=(*pskb)->nh.iph;
1109+ udph = skb_header_pointer(*pskb,iph->ihl*4,sizeof(_udph),&_udph);
1110+ if (!udph)
1111+ return NF_ACCEPT;
1112+
1113+ len = (*pskb)->len; /* stes */
1114+ data = (const u_int32_t *)udph + 2;
1115+ udplen = len - iph->ihl * 4;
1116+ dir = CTINFO2DIR(ctinfo);
1117+
1118+ /* Checksum */
1119+ chsm = (const u_int16_t *)udph + 3;
1120+
1121+ DEBUGP("new packet to evaluate ..\n");
1122+
1123+ /* Not whole UDP header? */
1124+ if (udplen < sizeof(struct udphdr)) {
1125+ DEBUGP("UDP header length is; udplen=%u ..\n", (unsigned) udplen);
1126+ DEBUGP("packet does not contain a complete UDP header. [skip]\n");
1127+ return NF_ACCEPT;
1128+ }
1129+
1130+ /* perform direction dependant protocol work */
1131+ if (dir == IP_CT_DIR_ORIGINAL) {
1132+
1133+ DEBUGP("packet is from the initiator. [cont]\n");
1134+
1135+ /* Tests if packet len is ok */
1136+ if ((udplen - sizeof(struct udphdr)) != 56) {
1137+ DEBUGP("packet length is not correct. [skip]\n");
1138+ return NF_ACCEPT;
1139+ }
1140+
1141+ } else {
1142+
1143+ DEBUGP("packet is from the receiver. [cont]\n");
1144+
1145+ /* Until there's been traffic both ways, don't look in packets. */
1146+ if (ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
1147+ DEBUGP("connection tracking state is; ctinfo=%u ..\n", ctinfo);
1148+ DEBUGP("[note: failure to get past this error may indicate asymmetric routing]\n");
1149+ DEBUGP("packet is not yet part of a two way stream. [skip]\n");
1150+ return NF_ACCEPT;
1151+ }
1152+
1153+ /* Tests if packet len is ok */
1154+ if ((udplen - sizeof(struct udphdr)) != 28) {
1155+ DEBUGP("packet length is not correct. [skip]\n");
1156+ return NF_ACCEPT;
1157+ }
1158+
1159+ }
1160+
1161+ /* Get to the data */
1162+ /* udp *data == *correct */
1163+
1164+ /* Check the RPC data */
1165+ crp_ret = check_rpc_packet(data, dir, ct, request_p_list_udp);
1166+
1167+ return crp_ret;
1168+
1169+}
1170+
1171+
1172+static struct ip_conntrack_helper rpc_helpers[MAX_PORTS];
1173+static char rpc_names[MAX_PORTS][10];
1174+
1175+static void fini(void);
1176+
1177+static int __init init(void)
1178+{
1179+ int port, ret;
1180+ char *tmpname;
1181+
1182+ /* If no port given, default to standard RPC port */
1183+ if (ports[0] == 0)
1184+ ports[0] = RPC_PORT;
1185+
1186+ for (port = 0; (port < MAX_PORTS) && ports[port]; port++) {
1187+ memset(&rpc_helpers[port], 0, sizeof(struct ip_conntrack_helper));
1188+
1189+ tmpname = &rpc_names[port][0];
1190+ if (ports[port] == RPC_PORT)
1191+ sprintf(tmpname, "rpc");
1192+ else
1193+ sprintf(tmpname, "rpc-%d", ports[port]);
1194+ rpc_helpers[port].name = tmpname;
1195+
1196+ rpc_helpers[port].me = THIS_MODULE;
1197+ rpc_helpers[port].max_expected = 1;
1198+ rpc_helpers[port].timeout = 5 * 60; /* stes */
1199+
1200+ rpc_helpers[port].tuple.dst.protonum = IPPROTO_UDP;
1201+ rpc_helpers[port].mask.dst.protonum = 0xff;
1202+
1203+ /* RPC can come from ports 0:65535 to ports[port] (111) */
1204+ rpc_helpers[port].tuple.src.u.udp.port = htons(ports[port]);
1205+ rpc_helpers[port].mask.src.u.udp.port = htons(0xffff);
1206+ rpc_helpers[port].mask.dst.u.udp.port = htons(0x0);
1207+
1208+ rpc_helpers[port].help = help;
1209+
1210+ PRINTK("registering helper for port #%d: %d/UDP\n", port, ports[port]);
1211+ PRINTK("helper match ip %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
1212+ NIPQUAD(rpc_helpers[port].tuple.dst.ip),
1213+ ntohs(rpc_helpers[port].tuple.dst.u.udp.port),
1214+ NIPQUAD(rpc_helpers[port].tuple.src.ip),
1215+ ntohs(rpc_helpers[port].tuple.src.u.udp.port));
1216+ PRINTK("helper match mask %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
1217+ NIPQUAD(rpc_helpers[port].mask.dst.ip),
1218+ ntohs(rpc_helpers[port].mask.dst.u.udp.port),
1219+ NIPQUAD(rpc_helpers[port].mask.src.ip),
1220+ ntohs(rpc_helpers[port].mask.src.u.udp.port));
1221+
1222+ ret = ip_conntrack_helper_register(&rpc_helpers[port]);
1223+
1224+ if (ret) {
1225+ printk("ERROR registering port %d\n",
1226+ ports[port]);
1227+ fini();
1228+ return -EBUSY;
1229+ }
1230+ ports_n_c++;
1231+ }
1232+ return 0;
1233+}
1234+
1235+
1236+/* This function is intentionally _NOT_ defined as __exit, because
1237+ * it is needed by the init function */
1238+static void fini(void)
1239+{
1240+ int port;
1241+
1242+ DEBUGP("cleaning request list\n");
1243+ clean_request(&request_p_list_udp);
1244+
1245+ for (port = 0; (port < ports_n_c) && ports[port]; port++) {
1246+ DEBUGP("unregistering port %d\n", ports[port]);
1247+ ip_conntrack_helper_unregister(&rpc_helpers[port]);
1248+ }
1249+}
1250+
1251+
1252+module_init(init);
1253+module_exit(fini);
1254+
1255+struct module *ip_conntrack_rpc_udp = THIS_MODULE;
1256+EXPORT_SYMBOL(request_p_list_udp);
1257+EXPORT_SYMBOL(ip_conntrack_rpc_udp);
1258+EXPORT_SYMBOL(ipct_rpc_udp_lock);
1259+
1260diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/ipt_rpc.c linux/net/ipv4/netfilter/ipt_rpc.c
1261--- linux.org/net/ipv4/netfilter/ipt_rpc.c 1970-01-01 01:00:00.000000000 +0100
1262+++ linux/net/ipv4/netfilter/ipt_rpc.c 2006-05-04 11:26:08.000000000 +0200
1263@@ -0,0 +1,443 @@
1264+/* RPC extension for IP connection matching, Version 2.2
1265+ * (C) 2000 by Marcelo Barbosa Lima <marcelo.lima@dcc.unicamp.br>
1266+ * - original rpc tracking module
1267+ * - "recent" connection handling for kernel 2.3+ netfilter
1268+ *
1269+ * (C) 2001 by Rusty Russell <rusty@rustcorp.com.au>
1270+ * - upgraded conntrack modules to oldnat api - kernel 2.4.0+
1271+ *
1272+ * (C) 2002,2003 by Ian (Larry) Latter <Ian.Latter@mq.edu.au>
1273+ * - upgraded conntrack modules to newnat api - kernel 2.4.20+
1274+ * - extended matching to support filtering on procedures
1275+ *
1276+ * (c) 2004,2005 by David Stes <stes@pandora.be>
1277+ * - upgraded to 2.6.12+ conntrack module api
1278+ * - upgraded to 2.6.13 api
1279+ *
1280+ * ipt_rpc.c,v 2.2 2003/01/12 18:30:00
1281+ *
1282+ * This program is free software; you can redistribute it and/or
1283+ * modify it under the terms of the GNU General Public License
1284+ * as published by the Free Software Foundation; either version
1285+ * 2 of the License, or (at your option) any later version.
1286+ **
1287+ * Module load syntax:
1288+ * insmod ipt_rpc.o ports=port1,port2,...port<MAX_PORTS>
1289+ *
1290+ * Please give the ports of all RPC servers you wish to connect to.
1291+ * If you don't specify ports, the default will be port 111.
1292+ **
1293+ * Note to all:
1294+ *
1295+ * RPCs should not be exposed to the internet - ask the Pentagon;
1296+ *
1297+ * "The unidentified crackers pleaded guilty in July to charges
1298+ * of juvenile delinquency stemming from a string of Pentagon
1299+ * network intrusions in February.
1300+ *
1301+ * The youths, going by the names TooShort and Makaveli, used
1302+ * a common server security hole to break in, according to
1303+ * Dane Jasper, owner of the California Internet service
1304+ * provider, Sonic. They used the hole, known as the 'statd'
1305+ * exploit, to attempt more than 800 break-ins, Jasper said."
1306+ *
1307+ * From: Wired News; "Pentagon Kids Kicked Off Grid" - Nov 6, 1998
1308+ * URL: http://www.wired.com/news/politics/0,1283,16098,00.html
1309+ **
1310+ */
1311+
1312+#include <linux/module.h>
1313+#include <linux/skbuff.h>
1314+#include <linux/list.h>
1315+#include <linux/udp.h>
1316+#include <linux/tcp.h>
1317+#include <linux/netfilter_ipv4/ip_conntrack.h>
1318+#include <linux/netfilter_ipv4/ip_tables.h>
1319+#include <linux/netfilter_ipv4/ip_conntrack_rpc.h>
1320+#include <linux/netfilter_ipv4/ipt_rpc.h>
1321+
1322+#define MAX_PORTS 8
1323+static int ports[MAX_PORTS];
1324+static int ports_n_c = 0;
1325+
1326+#ifdef MODULE_PARM
1327+module_param_array(ports, int, &ports_n_c, 0400);
1328+MODULE_PARM_DESC(ports, "port numbers (TCP/UDP) of RPC portmapper servers");
1329+#endif
1330+
1331+MODULE_AUTHOR("Marcelo Barbosa Lima <marcelo.lima@dcc.unicamp.br>");
1332+MODULE_DESCRIPTION("RPC connection matching module");
1333+MODULE_LICENSE("GPL");
1334+
1335+#define PRINTK(format, args...) printk(KERN_DEBUG "ipt_rpc: " \
1336+ format, ## args)
1337+
1338+#if 0
1339+#define DEBUGP(format, args...) printk(KERN_DEBUG "ipt_rpc: " \
1340+ format, ## args)
1341+#else
1342+#define DEBUGP(format, args...)
1343+#endif
1344+
1345+/* EXPORT_NO_SYMBOLS; */
1346+
1347+/* vars from ip_conntrack_rpc_tcp */
1348+extern struct list_head request_p_list_tcp;
1349+extern struct module *ip_conntrack_rpc_tcp;
1350+
1351+/* vars from ip_conntrack_rpc_udp */
1352+extern struct list_head request_p_list_udp;
1353+extern struct module *ip_conntrack_rpc_udp;
1354+
1355+extern rwlock_t ipct_rpc_tcp_lock;
1356+extern rwlock_t ipct_rpc_udp_lock;
1357+
1358+#define ASSERT_READ_LOCK(x)
1359+#define ASSERT_WRITE_LOCK(x)
1360+
1361+#if 0
1362+#define ASSERT_READ_LOCK(x) \
1363+do { \
1364+ if (x == &request_p_list_udp) \
1365+ MUST_BE_READ_LOCKED(&ipct_rpc_udp_lock); \
1366+ else if (x == &request_p_list_tcp) \
1367+ MUST_BE_READ_LOCKED(&ipct_rpc_tcp_lock); \
1368+} while (0)
1369+
1370+#define ASSERT_WRITE_LOCK(x) \
1371+do { \
1372+ if (x == &request_p_list_udp) \
1373+ MUST_BE_WRITE_LOCKED(&ipct_rpc_udp_lock); \
1374+ else if (x == &request_p_list_tcp) \
1375+ MUST_BE_WRITE_LOCKED(&ipct_rpc_tcp_lock); \
1376+} while (0)
1377+#endif
1378+
1379+#include <linux/netfilter_ipv4/listhelp.h>
1380+
1381+const int IPT_RPC_CHAR_LEN = 11;
1382+
1383+static int k_atoi(char *string)
1384+{
1385+ unsigned int result = 0;
1386+ int maxoctet = IPT_RPC_CHAR_LEN;
1387+
1388+ for ( ; *string != 0 && maxoctet != 0; maxoctet--, string++) {
1389+ if (*string < 0)
1390+ return(0);
1391+ if (*string == 0)
1392+ break;
1393+ if (*string < 48 || *string > 57) {
1394+ return(0);
1395+ }
1396+ result = result * 10 + ( *string - 48 );
1397+ }
1398+ return(result);
1399+}
1400+
1401+
1402+static int match_rpcs(char *c_procs, int i_procs, int proc)
1403+{
1404+ int proc_ctr;
1405+ char *proc_ptr;
1406+ unsigned int proc_num;
1407+
1408+ DEBUGP("entered match_rpcs [%i] [%i] ..\n", i_procs, proc);
1409+
1410+ if (i_procs == -1)
1411+ return 1;
1412+
1413+ for (proc_ctr=0; proc_ctr <= i_procs; proc_ctr++) {
1414+
1415+ proc_ptr = c_procs;
1416+ proc_ptr += proc_ctr * IPT_RPC_CHAR_LEN;
1417+ proc_num = k_atoi(proc_ptr);
1418+
1419+ if (proc_num == proc)
1420+ return 1;
1421+ }
1422+
1423+ return 0;
1424+}
1425+
1426+
1427+static int check_rpc_packet(const u_int32_t *data, const void *matchinfo,
1428+ int *hotdrop, int dir, struct ip_conntrack *ct,
1429+ int offset, struct list_head request_p_list)
1430+{
1431+ const struct ipt_rpc_info *rpcinfo = matchinfo;
1432+ struct request_p *req_p;
1433+ u_int32_t xid;
1434+
1435+
1436+ /* Get XID */
1437+ xid = *data;
1438+
1439+ /* This does sanity checking on RPC payloads,
1440+ * and permits only the RPC "get port" (3)
1441+ * in authorised procedures in client
1442+ * communications with the portmapper.
1443+ */
1444+
1445+ data += 5;
1446+
1447+ /* Get RPC requestor */
1448+ if (IXDR_GET_INT32(data) != 3) {
1449+ DEBUGP("RPC packet contains an invalid (non \"get\") requestor. [skip]\n");
1450+ if(rpcinfo->strict == 1)
1451+ *hotdrop = 1;
1452+ return 0;
1453+ }
1454+ DEBUGP("RPC packet contains a \"get\" requestor. [cont]\n");
1455+
1456+ data++;
1457+
1458+ /* Jump Credentials and Verfifier */
1459+ data = data + IXDR_GET_INT32(data) + 2;
1460+ data = data + IXDR_GET_INT32(data) + 2;
1461+
1462+ /* Get RPC procedure */
1463+ if (match_rpcs((char *)&rpcinfo->c_procs,
1464+ rpcinfo->i_procs, IXDR_GET_INT32(data)) == 0) {
1465+ DEBUGP("RPC packet contains illegal procedure request [%u]. [drop]\n",
1466+ (unsigned int)IXDR_GET_INT32(data));
1467+
1468+ /* If the RPC conntrack half entry already exists .. */
1469+
1470+ switch (ct->tuplehash[0].tuple.dst.protonum) {
1471+ case IPPROTO_UDP:
1472+ write_lock_bh(&ipct_rpc_udp_lock);
1473+ case IPPROTO_TCP:
1474+ write_lock_bh(&ipct_rpc_tcp_lock);
1475+ }
1476+ req_p = LIST_FIND(&request_p_list, request_p_cmp,
1477+ struct request_p *, xid,
1478+ ct->tuplehash[dir].tuple.src.ip,
1479+ ct->tuplehash[dir].tuple.src.u.all);
1480+
1481+ if (req_p) {
1482+ DEBUGP("found req_p for xid=%u proto=%u %u.%u.%u.%u:%u\n",
1483+ xid, ct->tuplehash[dir].tuple.dst.protonum,
1484+ NIPQUAD(ct->tuplehash[dir].tuple.src.ip),
1485+ ntohs(ct->tuplehash[dir].tuple.src.u.all));
1486+
1487+ /* .. remove it */
1488+ if (del_timer(&req_p->timeout))
1489+ req_p->timeout.expires = 0;
1490+
1491+ LIST_DELETE(&request_p_list, req_p);
1492+ DEBUGP("RPC req_p removed. [done]\n");
1493+
1494+ } else {
1495+ DEBUGP("no req_p found for xid=%u proto=%u %u.%u.%u.%u:%u\n",
1496+ xid, ct->tuplehash[dir].tuple.dst.protonum,
1497+ NIPQUAD(ct->tuplehash[dir].tuple.src.ip),
1498+ ntohs(ct->tuplehash[dir].tuple.src.u.all));
1499+
1500+ }
1501+ switch (ct->tuplehash[0].tuple.dst.protonum) {
1502+ case IPPROTO_UDP:
1503+ write_unlock_bh(&ipct_rpc_udp_lock);
1504+ case IPPROTO_TCP:
1505+ write_unlock_bh(&ipct_rpc_tcp_lock);
1506+ }
1507+
1508+ if(rpcinfo->strict == 1)
1509+ *hotdrop = 1;
1510+ return 0;
1511+ }
1512+
1513+ DEBUGP("RPC packet contains authorised procedure request [%u]. [match]\n",
1514+ (unsigned int)IXDR_GET_INT32(data));
1515+ return (1 && (!offset));
1516+}
1517+
1518+
1519+
1520+/* static int match(const struct sk_buff *skb, const struct net_device *in,
1521+ const struct net_device *out, const void *matchinfo,
1522+ int offset, const void *hdr, u_int16_t datalen, int *hotdrop)
1523+*/
1524+static int match(const struct sk_buff *skb, const struct net_device *in,
1525+ const struct net_device *out, const void *matchinfo,
1526+ int offset, unsigned int protoff, int *hotdrop)
1527+{
1528+ struct ip_conntrack *ct;
1529+ enum ip_conntrack_info ctinfo;
1530+ const u_int32_t *data;
1531+ enum ip_conntrack_dir dir;
1532+ const struct tcphdr *tcp;
1533+ const struct ipt_rpc_info *rpcinfo = matchinfo;
1534+ int port, portsok;
1535+ int tval;
1536+ struct iphdr *ip; /* stes */
1537+ void *hdr; /* stes */
1538+ u_int16_t datalen; /* stes */
1539+
1540+ /* Initialization stes - see 2.4 ip_tables.c ipt_do_table() */
1541+ ip = skb->nh.iph;
1542+ hdr = (u_int32_t *)ip + ip->ihl;
1543+ datalen = skb->len - ip->ihl * 4;
1544+
1545+ DEBUGP("new packet to evaluate ..\n");
1546+
1547+ ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
1548+ if (!ct) {
1549+ DEBUGP("no ct available [skip]\n");
1550+ return 0;
1551+ }
1552+
1553+ DEBUGP("ct detected. [cont]\n");
1554+ dir = CTINFO2DIR(ctinfo);
1555+
1556+ /* we only want the client to server packets for matching */
1557+ if (dir != IP_CT_DIR_ORIGINAL)
1558+ return 0;
1559+
1560+ /* This does sanity checking on UDP or TCP packets,
1561+ * like their respective modules.
1562+ */
1563+
1564+ switch (ct->tuplehash[0].tuple.dst.protonum) {
1565+
1566+ case IPPROTO_UDP:
1567+ DEBUGP("PROTO_UDP [cont]\n");
1568+ if (offset == 0 && datalen < sizeof(struct udphdr)) {
1569+ DEBUGP("packet does not contain a complete header. [drop]\n");
1570+ return 0;
1571+ }
1572+
1573+ for (port=0,portsok=0; port <= ports_n_c; port++) {
1574+ if (ntohs(ct->tuplehash[dir].tuple.dst.u.all) == ports[port]) {
1575+ portsok++;
1576+ break;
1577+ }
1578+ }
1579+ if (portsok == 0) {
1580+ DEBUGP("packet is not destined for a portmapper [%u]. [skip]\n",
1581+ ntohs(ct->tuplehash[dir].tuple.dst.u.all));
1582+ return 0;
1583+ }
1584+
1585+ if ((datalen - sizeof(struct udphdr)) != 56) {
1586+ DEBUGP("packet length is not correct for RPC content. [skip]\n");
1587+ if (rpcinfo->strict == 1)
1588+ *hotdrop = 1;
1589+ return 0;
1590+ }
1591+ DEBUGP("packet length is correct. [cont]\n");
1592+
1593+ /* Get to the data */
1594+ data = (const u_int32_t *)hdr + 2;
1595+
1596+ /* Check the RPC data */
1597+ tval = check_rpc_packet(data, matchinfo, hotdrop,
1598+ dir, ct, offset,
1599+ request_p_list_udp);
1600+
1601+ return tval;
1602+
1603+
1604+ case IPPROTO_TCP:
1605+ DEBUGP("PROTO_TCP [cont]\n");
1606+ if (offset == 0 && datalen < sizeof(struct tcphdr)) {
1607+ DEBUGP("packet does not contain a complete header. [drop]\n");
1608+ return 0;
1609+ }
1610+
1611+ for (port=0,portsok=0; port <= ports_n_c; port++) {
1612+ if (ntohs(ct->tuplehash[dir].tuple.dst.u.all) == ports[port]) {
1613+ portsok++;
1614+ break;
1615+ }
1616+ }
1617+ if (portsok == 0) {
1618+ DEBUGP("packet is not destined for a portmapper [%u]. [skip]\n",
1619+ ntohs(ct->tuplehash[dir].tuple.dst.u.all));
1620+ return 0;
1621+ }
1622+
1623+ tcp = hdr;
1624+ if (datalen == (tcp->doff * 4)) {
1625+ DEBUGP("packet does not contain any data. [match]\n");
1626+ return (1 && (!offset));
1627+ }
1628+
1629+ /* Tests if packet len is ok */
1630+ if ((datalen - (tcp->doff * 4)) != 60) {
1631+ DEBUGP("packet length is not correct for RPC content. [skip]\n");
1632+ if(rpcinfo->strict == 1)
1633+ *hotdrop = 1;
1634+ return 0;
1635+ }
1636+ DEBUGP("packet length is correct. [cont]\n");
1637+
1638+ /* Get to the data */
1639+ data = (const u_int32_t *)tcp + tcp->doff + 1;
1640+
1641+ /* Check the RPC data */
1642+ tval = check_rpc_packet(data, matchinfo, hotdrop,
1643+ dir, ct, offset,
1644+ request_p_list_tcp);
1645+
1646+ return tval;
1647+
1648+ }
1649+
1650+ DEBUGP("transport protocol=%u, is not supported [skip]\n",
1651+ ct->tuplehash[0].tuple.dst.protonum);
1652+ return 0;
1653+}
1654+
1655+
1656+static int checkentry(const char *tablename, const struct ipt_ip *ip, void *matchinfo,
1657+ unsigned int matchsize, unsigned int hook_mask)
1658+{
1659+ if (hook_mask
1660+ & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_FORWARD) | (1 << NF_IP_POST_ROUTING)
1661+ | (1 << NF_IP_LOCAL_IN) | (1 << NF_IP_LOCAL_OUT))) {
1662+ printk("ipt_rpc: only valid for PRE_ROUTING, FORWARD, POST_ROUTING, LOCAL_IN and/or LOCAL_OUT targets.\n");
1663+ return 0;
1664+ }
1665+
1666+ if (matchsize != IPT_ALIGN(sizeof(struct ipt_rpc_info)))
1667+ return 0;
1668+
1669+ return 1;
1670+}
1671+
1672+static struct ipt_match rpc_match = {
1673+ .name = "rpc",
1674+ .match = &match,
1675+ .checkentry = &checkentry,
1676+ .me = THIS_MODULE,
1677+};
1678+
1679+static int __init init(void)
1680+{
1681+ int port;
1682+
1683+ /* If no port given, default to standard RPC port */
1684+ if (ports[0] == 0)
1685+ ports[0] = RPC_PORT;
1686+
1687+ PRINTK("registering match [%s] for;\n", rpc_match.name);
1688+ for (port = 0; (port < MAX_PORTS) && ports[port]; port++) {
1689+ PRINTK(" port %i (UDP|TCP);\n", ports[port]);
1690+ ports_n_c++;
1691+ }
1692+
1693+ return ipt_register_match(&rpc_match);
1694+}
1695+
1696+
1697+static void fini(void)
1698+{
1699+ DEBUGP("unregistering match\n");
1700+ ipt_unregister_match(&rpc_match);
1701+}
1702+
1703+
1704+module_init(init);
1705+module_exit(fini);
1706+
This page took 0.379351 seconds and 4 git commands to generate.