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