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