1 include/linux/netfilter_ipv4/ip_conntrack_rpc.h | 71 +++
2 include/linux/netfilter_ipv4/ipt_rpc.h | 35 +
3 net/ipv4/netfilter/Kconfig | 32 +
4 net/ipv4/netfilter/Makefile | 1
5 net/ipv4/netfilter/ip_conntrack_rpc_tcp.c | 554 ++++++++++++++++++++++++
6 net/ipv4/netfilter/ip_conntrack_rpc_udp.c | 527 ++++++++++++++++++++++
7 net/ipv4/netfilter/ipt_rpc.c | 443 +++++++++++++++++++
8 7 files changed, 1663 insertions(+)
10 diff -Nur --exclude '*.orig' linux.org/include/linux/netfilter_ipv4/ip_conntrack_rpc.h linux/include/linux/netfilter_ipv4/ip_conntrack_rpc.h
11 --- linux.org/include/linux/netfilter_ipv4/ip_conntrack_rpc.h 1970-01-01 01:00:00.000000000 +0100
12 +++ linux/include/linux/netfilter_ipv4/ip_conntrack_rpc.h 2006-05-04 11:26:08.000000000 +0200
14 +/* RPC extension for IP connection tracking, Version 2.2
15 + * (C) 2000 by Marcelo Barbosa Lima <marcelo.lima@dcc.unicamp.br>
16 + * - original rpc tracking module
17 + * - "recent" connection handling for kernel 2.3+ netfilter
19 + * (C) 2001 by Rusty Russell <rusty@rustcorp.com.au>
20 + * - upgraded conntrack modules to oldnat api - kernel 2.4.0+
22 + * (C) 2002 by Ian (Larry) Latter <Ian.Latter@mq.edu.au>
23 + * - upgraded conntrack modules to newnat api - kernel 2.4.20+
24 + * - extended matching to support filtering on procedures
26 + * (C) 2005 by David Stes <stes@pandora.be>
27 + * - upgraded to 2.6.13 API
29 + * ip_conntrack_rpc.h,v 2.2 2003/01/12 18:30:00
31 + * This program is free software; you can redistribute it and/or
32 + * modify it under the terms of the GNU General Public License
33 + * as published by the Free Software Foundation; either version
34 + * 2 of the License, or (at your option) any later version.
38 +#include <asm/param.h>
39 +#include <linux/sched.h>
40 +#include <linux/timer.h>
41 +#include <linux/stddef.h>
42 +#include <linux/list.h>
44 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
46 +#ifndef _IP_CONNTRACK_RPC_H
47 +#define _IP_CONNTRACK_RPC_H
52 +/* Datum in RPC packets are encoded in XDR */
53 +#define IXDR_GET_INT32(buf) ((u_int32_t) ntohl((uint32_t)*buf))
55 +/* Fast timeout, to deny DoS atacks */
56 +#define EXP (60 * HZ)
58 +/* Normal timeouts */
59 +#define EXPIRES (180 * HZ)
61 +/* For future conections RPC, using client's cache bindings
62 + * I'll use ip_conntrack_lock to lock these lists */
64 +/* This identifies each request and stores protocol */
66 + struct list_head list;
75 + struct timer_list timeout;
78 +static inline int request_p_cmp(const struct request_p *p, u_int32_t xid,
79 + u_int32_t ip, u_int32_t port) {
80 + return (p->xid == xid && p->ip == ip && p->port);
84 +#endif /* _IP_CONNTRACK_RPC_H */
85 diff -Nur --exclude '*.orig' linux.org/include/linux/netfilter_ipv4/ipt_rpc.h linux/include/linux/netfilter_ipv4/ipt_rpc.h
86 --- linux.org/include/linux/netfilter_ipv4/ipt_rpc.h 1970-01-01 01:00:00.000000000 +0100
87 +++ linux/include/linux/netfilter_ipv4/ipt_rpc.h 2006-05-04 11:26:08.000000000 +0200
89 +/* RPC extension for IP netfilter matching, Version 2.2
90 + * (C) 2000 by Marcelo Barbosa Lima <marcelo.lima@dcc.unicamp.br>
91 + * - original rpc tracking module
92 + * - "recent" connection handling for kernel 2.3+ netfilter
94 + * (C) 2001 by Rusty Russell <rusty@rustcorp.com.au>
95 + * - upgraded conntrack modules to oldnat api - kernel 2.4.0+
97 + * (C) 2002 by Ian (Larry) Latter <Ian.Latter@mq.edu.au>
98 + * - upgraded conntrack modules to newnat api - kernel 2.4.20+
99 + * - extended matching to support filtering on procedures
101 + * ipt_rpc.h.c,v 2.2 2003/01/12 18:30:00
103 + * This program is free software; you can redistribute it and/or
104 + * modify it under the terms of the GNU General Public License
105 + * as published by the Free Software Foundation; either version
106 + * 2 of the License, or (at your option) any later version.
113 +struct ipt_rpc_data;
115 +struct ipt_rpc_info {
118 + const char c_procs[1408];
120 + struct ipt_rpc_data *data;
123 +#endif /* _IPT_RPC_H */
124 diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/Kconfig linux/net/ipv4/netfilter/Kconfig
125 --- linux.org/net/ipv4/netfilter/Kconfig 2006-05-02 23:38:44.000000000 +0200
126 +++ linux/net/ipv4/netfilter/Kconfig 2006-05-04 11:26:08.000000000 +0200
128 Allows altering the ARP packet payload: source and destination
129 hardware and network addresses.
131 +config IP_NF_MATCH_RPC
132 + tristate 'RPC match support'
133 + depends on IP_NF_CONNTRACK && IP_NF_IPTABLES
135 + This adds CONFIG_IP_NF_MATCH_RPC, which is the RPC connection
136 + matcher and tracker.
138 + This option supplies two connection tracking modules;
139 + ip_conntrack_rpc_udp and ip_conntrack_rpc_tcp, which track
140 + portmapper requests using UDP and TCP respectively.
142 + This option also adds an RPC match module for iptables, which
143 + matches both via the old "record match" method and a new
144 + "procedure match" method. The older method matches all RPC
145 + procedure packets that relate to previously recorded packets
146 + seen querying a portmapper. The newer method matches only
147 + those RPC procedure packets explicitly specified by the user,
148 + and that can then be related to previously recorded packets
149 + seen querying a portmapper.
151 + These three modules are required if RPCs are to be filtered
152 + accurately; as RPCs are allocated pseudo-randomly to UDP and
153 + TCP ports as they register with the portmapper.
155 + Up to 8 portmapper ports per module, and up to 128 RPC
156 + procedures per iptables rule, may be specified by the user,
157 + to enable effective RPC management.
160 + If you want to compile it as a module, say M here and read
161 + <file:Documentation/modules.txt>. If unsure, say `N'.
165 diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/Makefile linux/net/ipv4/netfilter/Makefile
166 --- linux.org/net/ipv4/netfilter/Makefile 2006-05-02 23:38:44.000000000 +0200
167 +++ linux/net/ipv4/netfilter/Makefile 2006-05-04 11:26:08.000000000 +0200
169 +obj-$(CONFIG_IP_NF_MATCH_RPC) += ip_conntrack_rpc_tcp.o ip_conntrack_rpc_udp.o ipt_rpc.o
170 diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/ip_conntrack_rpc_tcp.c linux/net/ipv4/netfilter/ip_conntrack_rpc_tcp.c
171 --- linux.org/net/ipv4/netfilter/ip_conntrack_rpc_tcp.c 1970-01-01 01:00:00.000000000 +0100
172 +++ linux/net/ipv4/netfilter/ip_conntrack_rpc_tcp.c 2006-05-04 11:26:08.000000000 +0200
174 +/* RPC extension for IP (TCP) connection tracking, Version 2.2
175 + * (C) 2000 by Marcelo Barbosa Lima <marcelo.lima@dcc.unicamp.br>
176 + * - original rpc tracking module
177 + * - "recent" connection handling for kernel 2.3+ netfilter
179 + * (C) 2001 by Rusty Russell <rusty@rustcorp.com.au>
180 + * - upgraded conntrack modules to oldnat api - kernel 2.4.0+
182 + * (C) 2002,2003 by Ian (Larry) Latter <Ian.Latter@mq.edu.au>
183 + * - upgraded conntrack modules to newnat api - kernel 2.4.20+
184 + * - extended matching to support filtering on procedures
186 + * (c) 2004,2005 by David Stes <stes@pandora.be>
187 + * - add nsrexec option for Legato NetWorker
188 + * - upgraded to 2.6.12+ conntrack module api
190 + * (c) 2005 by David Stes <stes@pandora.be>
191 + * - upgraded to 2.6.13 conntrack module api
193 + * ip_conntrack_rpc_tpc.c,v 2.2 2003/01/12 18:30:00
195 + * This program is free software; you can redistribute it and/or
196 + * modify it under the terms of the GNU General Public License
197 + * as published by the Free Software Foundation; either version
198 + * 2 of the License, or (at your option) any later version.
200 + * Module load syntax:
201 + * insmod ip_conntrack_rpc_tcp.o nsrexec=<n> ports=port1,...port<MAX_PORTS>
203 + * Please give the ports of all RPC servers you wish to connect to.
204 + * For example, ports=111,7938 for Legato NetWorker's portmapper on 7938.
205 + * If you don't specify ports, the default will be port 111 (SUN portmap).
207 + * Please specify nsrexec, the TCP port of the rexec() service of
208 + * Legato NetWorker. For example, nsrexec=7937
213 + * RPCs should not be exposed to the internet - ask the Pentagon;
215 + * "The unidentified crackers pleaded guilty in July to charges
216 + * of juvenile delinquency stemming from a string of Pentagon
217 + * network intrusions in February.
219 + * The youths, going by the names TooShort and Makaveli, used
220 + * a common server security hole to break in, according to
221 + * Dane Jasper, owner of the California Internet service
222 + * provider, Sonic. They used the hole, known as the 'statd'
223 + * exploit, to attempt more than 800 break-ins, Jasper said."
225 + * From: Wired News; "Pentagon Kids Kicked Off Grid" - Nov 6, 1998
226 + * URL: http://www.wired.com/news/politics/0,1283,16098,00.html
230 +#include <linux/module.h>
231 +#include <linux/netfilter.h>
232 +#include <linux/ip.h>
233 +#include <net/checksum.h>
234 +#include <net/tcp.h>
236 +#include <asm/param.h>
237 +#include <linux/sched.h>
238 +#include <linux/timer.h>
239 +#include <linux/stddef.h>
240 +#include <linux/list.h>
242 +#include <linux/netfilter_ipv4/ip_tables.h>
243 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
244 +#include <linux/netfilter_ipv4/ip_conntrack_rpc.h>
247 +static int ports[MAX_PORTS];
248 +static int ports_n_c = 0;
249 +static int nsrexec = 0;
252 +module_param(nsrexec,int, 0400);
253 +MODULE_PARM_DESC(nsrexec, "TCP port of Legato NetWorker's rexec service");
254 +module_param_array(ports, int, &ports_n_c, 0400);
255 +MODULE_PARM_DESC(ports, "port numbers (TCP/UDP) of RPC portmapper servers");
258 +MODULE_AUTHOR("Marcelo Barbosa Lima <marcelo.lima@dcc.unicamp.br>");
259 +MODULE_DESCRIPTION("RPC TCP connection tracking module");
260 +MODULE_LICENSE("GPL");
262 +#define PRINTK(format, args...) printk(KERN_DEBUG "ip_conntrack_rpc_tcp: " \
266 +#define DEBUGP(format, args...) printk(KERN_DEBUG "ip_conntrack_rpc_tcp: " \
269 +#define DEBUGP(format, args...)
272 +DEFINE_RWLOCK(ipct_rpc_tcp_lock);
274 +#define ASSERT_READ_LOCK(x)
275 +#define ASSERT_WRITE_LOCK(x)
277 +#include <linux/netfilter_ipv4/listhelp.h>
279 +/* For future conections RPC, using client's cache bindings
280 + * I'll use ip_conntrack_lock to lock these lists */
282 +LIST_HEAD(request_p_list_tcp);
285 +static void delete_request_p(unsigned long request_p_ul)
287 + struct request_p *p = (void *)request_p_ul;
289 + write_lock_bh(&ipct_rpc_tcp_lock);
290 + LIST_DELETE(&request_p_list_tcp, p);
291 + write_unlock_bh(&ipct_rpc_tcp_lock);
297 +static void req_cl(struct request_p * r)
299 + write_lock_bh(&ipct_rpc_tcp_lock);
300 + del_timer(&r->timeout);
301 + LIST_DELETE(&request_p_list_tcp, r);
302 + write_unlock_bh(&ipct_rpc_tcp_lock);
308 +static void clean_request(struct list_head *list)
310 + struct list_head *first = list->prev;
311 + struct list_head *temp = list->next;
312 + struct list_head *aux;
314 + if (list_empty(list))
317 + while (first != temp) {
319 + req_cl((struct request_p *)temp);
322 + req_cl((struct request_p *)temp);
327 +static void alloc_request_p(u_int32_t xid, u_int16_t proto, u_int32_t ip,
330 + struct request_p *req_p;
332 + /* Verifies if entry already exists */
333 + write_lock_bh(&ipct_rpc_tcp_lock);
334 + req_p = LIST_FIND(&request_p_list_tcp, request_p_cmp,
335 + struct request_p *, xid, ip, port);
338 + /* Refresh timeout */
339 + if (del_timer(&req_p->timeout)) {
340 + req_p->timeout.expires = jiffies + EXP;
341 + add_timer(&req_p->timeout);
343 + write_unlock_bh(&ipct_rpc_tcp_lock);
347 + write_unlock_bh(&ipct_rpc_tcp_lock);
349 + /* Allocate new request_p */
350 + req_p = (struct request_p *) kmalloc(sizeof(struct request_p), GFP_ATOMIC);
352 + DEBUGP("can't allocate request_p\n");
356 + req_p->list.next = NULL;
357 + req_p->list.prev = NULL;
360 + req_p->port = port;
361 + req_p->proto = proto;
363 + /* Initialize timer */
364 + init_timer(&req_p->timeout);
365 + req_p->timeout.expires = jiffies + EXP;
366 + req_p->timeout.data = (unsigned long)req_p;
367 + req_p->timeout.function = delete_request_p;
368 + add_timer(&req_p->timeout);
371 + write_lock_bh(&ipct_rpc_tcp_lock);
372 + list_prepend(&request_p_list_tcp, req_p);
373 + write_unlock_bh(&ipct_rpc_tcp_lock);
378 +static int check_rpc_packet(const u_int32_t *data,
379 + int dir, struct ip_conntrack *ct,
380 + struct list_head request_p_list)
383 + int ret = NF_ACCEPT;
384 + struct request_p *req_p;
385 + struct ip_conntrack_expect *exp;
389 + DEBUGP("ct is NULL");
393 + /* Translstion's buffer for XDR */
394 + u_int16_t port_buf;
399 + /* This does sanity checking on RPC payloads,
400 + * and permits only the RPC "get port" (3)
401 + * in authorised procedures in client
402 + * communications with the portmapper.
405 + /* perform direction dependant RPC work */
406 + if (dir == IP_CT_DIR_ORIGINAL) {
410 + /* Get RPC requestor */
411 + if (IXDR_GET_INT32(data) != 3) {
412 + DEBUGP("RPC packet contains an invalid (non \"get\") requestor. [skip]\n");
415 + DEBUGP("RPC packet contains a \"get\" requestor. [cont]\n");
419 + /* Jump Credentials and Verfifier */
420 + data += IXDR_GET_INT32(data) + 2;
421 + data += IXDR_GET_INT32(data) + 2;
423 + /* Get RPC procedure */
424 + DEBUGP("RPC packet contains procedure request [%u]. [cont]\n",
425 + (unsigned int)IXDR_GET_INT32(data));
427 + /* Get RPC protocol and store against client parameters */
429 + alloc_request_p(xid, IXDR_GET_INT32(data), ct->tuplehash[dir].tuple.src.ip,
430 + ct->tuplehash[dir].tuple.src.u.all);
432 + DEBUGP("allocated RPC req_p for xid=%u proto=%u %u.%u.%u.%u:%u\n",
433 + xid, IXDR_GET_INT32(data),
434 + NIPQUAD(ct->tuplehash[dir].tuple.src.ip),
435 + ntohs(ct->tuplehash[dir].tuple.src.u.all));
437 + DEBUGP("allocated RPC request for protocol %u. [done]\n",
438 + (unsigned int)IXDR_GET_INT32(data));
442 + /* Check for returning packet's stored counterpart */
443 + req_p = LIST_FIND(&request_p_list_tcp, request_p_cmp,
444 + struct request_p *, xid,
445 + ct->tuplehash[!dir].tuple.src.ip,
446 + ct->tuplehash[!dir].tuple.src.u.all);
448 + /* Drop unexpected packets */
450 + DEBUGP("packet is not expected. [skip]\n");
454 + /* Verifies if packet is really an RPC reply packet */
456 + if (IXDR_GET_INT32(data) != 1) {
457 + DEBUGP("packet is not a valid RPC reply. [skip]\n");
461 + /* Is status accept? */
463 + if (IXDR_GET_INT32(data)) {
464 + DEBUGP("packet is not an RPC accept. [skip]\n");
468 + /* Get Verifier length. Jump verifier */
470 + data = data + IXDR_GET_INT32(data) + 2;
472 + /* Is accpet status "success"? */
473 + if (IXDR_GET_INT32(data)) {
474 + DEBUGP("packet is not an RPC accept status of success. [skip]\n");
478 + /* Get server port number */
480 + port_buf = (u_int16_t) IXDR_GET_INT32(data);
482 + /* If a packet has made it this far then it deserves an
483 + * expectation ... if port == 0, then this service is
484 + * not going to be registered.
486 + if (port_buf && port_buf != nsrexec) {
487 + DEBUGP("port found: %u\n", port_buf);
489 + exp = ip_conntrack_expect_alloc(ct);
495 + /* Watch out, Radioactive-Man! */
496 + exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
497 + exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
498 + exp->mask.src.ip = 0xffffffff;
499 + exp->mask.dst.ip = 0xffffffff;
501 + switch (req_p->proto) {
503 + exp->tuple.src.u.udp.port = 0;
504 + exp->tuple.dst.u.udp.port = htons(port_buf);
505 + exp->tuple.dst.protonum = IPPROTO_UDP;
506 + exp->mask.src.u.udp.port = 0;
507 + exp->mask.dst.u.udp.port = htons(0xffff);
508 + exp->mask.dst.protonum = 0xff;
512 + exp->tuple.src.u.tcp.port = 0;
513 + exp->tuple.dst.u.tcp.port = htons(port_buf);
514 + exp->tuple.dst.protonum = IPPROTO_TCP;
515 + exp->mask.src.u.tcp.port = 0;
516 + exp->mask.dst.u.tcp.port = htons(0xffff);
517 + exp->mask.dst.protonum = 0xff;
520 + exp->expectfn = NULL;
523 + if (exp->master->helper == NULL) {
524 + DEBUGP("master helper NULL");
528 + DEBUGP("expect related ip %u.%u.%u.%u:0-%u.%u.%u.%u:%u proto=%u\n",
529 + NIPQUAD(exp->tuple.src.ip),
530 + NIPQUAD(exp->tuple.dst.ip),
531 + port_buf, req_p->proto);
533 + DEBUGP("expect related mask %u.%u.%u.%u:0-%u.%u.%u.%u:65535 proto=%u\n",
534 + NIPQUAD(exp->mask.src.ip),
535 + NIPQUAD(exp->mask.dst.ip),
536 + exp->mask.dst.protonum);
538 + if (ip_conntrack_expect_related(exp) != 0) {
547 + DEBUGP("packet evaluated. [expect]\n");
555 +/* RPC TCP helper */
556 +/* static int help(const struct iphdr *iph, size_t len,
557 + struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) */
558 +static int help(struct sk_buff **pskb,
559 + struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
563 + struct tcphdr _tcph, *tcph;
564 + const u_int32_t *data;
569 + /* Not whole TCP header? */
570 + iph=(*pskb)->nh.iph;
571 + tcph = skb_header_pointer(*pskb,iph->ihl*4,sizeof(_tcph),&_tcph);
575 + len = (*pskb)->len; /* stes */
576 + data = (const u_int32_t *)tcph + tcph->doff;
577 + tcplen = len - iph->ihl * 4;
578 + dir = CTINFO2DIR(ctinfo);
580 + DEBUGP("new packet to evaluate ..\n");
582 + /* This works for packets like handshake packets, ignore */
583 + if (len == ((tcph->doff + iph->ihl) * 4)) {
584 + DEBUGP("packet has no data (may still be handshaking). [skip]\n");
588 + /* Until there's been traffic both ways, don't look in packets. */
589 + if (ctinfo != IP_CT_ESTABLISHED
590 + && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
591 + DEBUGP("connection tracking state is; ctinfo=%u ..\n", ctinfo);
592 + DEBUGP("[note: failure to get past this error may indicate asymmetric routing]\n");
593 + DEBUGP("packet is not yet part of a two way stream. [skip]\n");
597 + /* Not whole TCP header? */
598 + if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) {
599 + DEBUGP("TCP header length is; tcplen=%u ..\n", (unsigned) tcplen);
600 + DEBUGP("packet does not contain a complete TCP header. [skip]\n");
604 + /* perform direction dependant protocol work */
605 + if (dir == IP_CT_DIR_ORIGINAL) {
607 + DEBUGP("packet is from the initiator. [cont]\n");
609 + /* Tests if packet len is ok */
610 + if ((tcplen - (tcph->doff * 4)) != 60) {
611 + DEBUGP("packet length is not correct. [skip]\n");
617 + DEBUGP("packet is from the receiver. [cont]\n");
619 + /* Tests if packet len is ok */
620 + if ((tcplen - (tcph->doff * 4)) != 32) {
621 + DEBUGP("packet length is not correct. [skip]\n");
626 + /* Get to the data */
629 + /* Check the RPC data */
630 + crp_ret = check_rpc_packet(data, dir, ct, request_p_list_tcp);
637 +static struct ip_conntrack_helper rpc_helpers[MAX_PORTS];
638 +static char rpc_names[MAX_PORTS][10];
640 +static void fini(void);
642 +static int __init init(void)
647 + /* If no port given, default to standard RPC port */
649 + ports[0] = RPC_PORT;
651 + for (port = 0; (port < MAX_PORTS) && ports[port]; port++) {
652 + memset(&rpc_helpers[port], 0, sizeof(struct ip_conntrack_helper));
654 + tmpname = &rpc_names[port][0];
655 + if (ports[port] == RPC_PORT)
656 + sprintf(tmpname, "rpc");
658 + sprintf(tmpname, "rpc-%d", ports[port]);
659 + rpc_helpers[port].name = tmpname;
661 + rpc_helpers[port].me = THIS_MODULE;
662 + rpc_helpers[port].max_expected = 1;
663 + rpc_helpers[port].timeout = 5 * 60; /* stes */
665 + rpc_helpers[port].tuple.dst.protonum = IPPROTO_TCP;
666 + rpc_helpers[port].mask.dst.protonum = 0xff;
668 + /* RPC can come from ports 0:65535 to ports[port] (111) */
669 + rpc_helpers[port].tuple.src.u.tcp.port = htons(ports[port]);
670 + rpc_helpers[port].mask.src.u.tcp.port = htons(0xffff);
671 + rpc_helpers[port].mask.dst.u.tcp.port = htons(0x0);
673 + rpc_helpers[port].help = help;
675 + PRINTK("registering helper for port #%d: %d/TCP\n", port, ports[port]);
676 + PRINTK("helper match ip %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
677 + NIPQUAD(rpc_helpers[port].tuple.dst.ip),
678 + ntohs(rpc_helpers[port].tuple.dst.u.tcp.port),
679 + NIPQUAD(rpc_helpers[port].tuple.src.ip),
680 + ntohs(rpc_helpers[port].tuple.src.u.tcp.port));
681 + PRINTK("helper match mask %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
682 + NIPQUAD(rpc_helpers[port].mask.dst.ip),
683 + ntohs(rpc_helpers[port].mask.dst.u.tcp.port),
684 + NIPQUAD(rpc_helpers[port].mask.src.ip),
685 + ntohs(rpc_helpers[port].mask.src.u.tcp.port));
687 + ret = ip_conntrack_helper_register(&rpc_helpers[port]);
690 + printk("ERROR registering port %d\n",
698 + PRINTK("%s Legato NetWorker support for port %d/TCP\n", (nsrexec)?"enabling":"disabling", nsrexec);
704 +/* This function is intentionally _NOT_ defined as __exit, because
705 + * it is needed by the init function */
706 +static void fini(void)
710 + DEBUGP("cleaning request list\n");
711 + clean_request(&request_p_list_tcp);
713 + for (port = 0; (port < ports_n_c) && ports[port]; port++) {
714 + DEBUGP("unregistering port %d\n", ports[port]);
715 + ip_conntrack_helper_unregister(&rpc_helpers[port]);
723 +struct module *ip_conntrack_rpc_tcp = THIS_MODULE;
724 +EXPORT_SYMBOL(request_p_list_tcp);
725 +EXPORT_SYMBOL(ip_conntrack_rpc_tcp);
726 +EXPORT_SYMBOL(ipct_rpc_tcp_lock);
728 diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/ip_conntrack_rpc_udp.c linux/net/ipv4/netfilter/ip_conntrack_rpc_udp.c
729 --- linux.org/net/ipv4/netfilter/ip_conntrack_rpc_udp.c 1970-01-01 01:00:00.000000000 +0100
730 +++ linux/net/ipv4/netfilter/ip_conntrack_rpc_udp.c 2006-05-04 11:26:08.000000000 +0200
732 +/* RPC extension for IP (UDP) connection tracking, Version 2.2
733 + * (C) 2000 by Marcelo Barbosa Lima <marcelo.lima@dcc.unicamp.br>
734 + * - original rpc tracking module
735 + * - "recent" connection handling for kernel 2.3+ netfilter
737 + * (C) 2001 by Rusty Russell <rusty@rustcorp.com.au>
738 + * - upgraded conntrack modules to oldnat api - kernel 2.4.0+
740 + * (C) 2002,2003 by Ian (Larry) Latter <Ian.Latter@mq.edu.au>
741 + * - upgraded conntrack modules to newnat api - kernel 2.4.20+
742 + * - extended matching to support filtering on procedures
744 + * (c) 2004,2005 by David Stes <stes@pandora.be>
745 + * - upgraded to 2.6.12+ conntrack module api
747 + * (c) 2005 by David Stes <stes@pandora.be>
748 + * - upgraded to 2.6.13 api
750 + * ip_conntrack_rpc_udp.c,v 2.2 2003/01/12 18:30:00
752 + * This program is free software; you can redistribute it and/or
753 + * modify it under the terms of the GNU General Public License
754 + * as published by the Free Software Foundation; either version
755 + * 2 of the License, or (at your option) any later version.
757 + * Module load syntax:
758 + * insmod ip_conntrack_rpc_udp.o ports=port1,port2,...port<MAX_PORTS>
760 + * Please give the ports of all RPC servers you wish to connect to.
761 + * If you don't specify ports, the default will be port 111.
765 + * RPCs should not be exposed to the internet - ask the Pentagon;
767 + * "The unidentified crackers pleaded guilty in July to charges
768 + * of juvenile delinquency stemming from a string of Pentagon
769 + * network intrusions in February.
771 + * The youths, going by the names TooShort and Makaveli, used
772 + * a common server security hole to break in, according to
773 + * Dane Jasper, owner of the California Internet service
774 + * provider, Sonic. They used the hole, known as the 'statd'
775 + * exploit, to attempt more than 800 break-ins, Jasper said."
777 + * From: Wired News; "Pentagon Kids Kicked Off Grid" - Nov 6, 1998
778 + * URL: http://www.wired.com/news/politics/0,1283,16098,00.html
782 +#include <linux/module.h>
783 +#include <linux/netfilter.h>
784 +#include <linux/ip.h>
785 +#include <net/checksum.h>
786 +#include <net/udp.h>
788 +#include <asm/param.h>
789 +#include <linux/sched.h>
790 +#include <linux/timer.h>
791 +#include <linux/stddef.h>
792 +#include <linux/list.h>
793 +#include <linux/udp.h>
795 +#include <linux/netfilter_ipv4/ip_tables.h>
796 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
797 +#include <linux/netfilter_ipv4/ip_conntrack_rpc.h>
800 +static int ports[MAX_PORTS];
801 +static int ports_n_c = 0;
804 +module_param_array(ports, int, &ports_n_c, 0400);
805 +MODULE_PARM_DESC(ports, "port numbers (TCP/UDP) of RPC portmapper servers");
808 +MODULE_AUTHOR("Marcelo Barbosa Lima <marcelo.lima@dcc.unicamp.br>");
809 +MODULE_DESCRIPTION("RPC UDP connection tracking module");
810 +MODULE_LICENSE("GPL");
812 +#define PRINTK(format, args...) printk(KERN_DEBUG "ip_conntrack_rpc_udp: " \
816 +#define DEBUGP(format, args...) printk(KERN_DEBUG "ip_conntrack_rpc_udp: " \
819 +#define DEBUGP(format, args...)
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>
827 +/* For future conections RPC, using client's cache bindings
828 + * I'll use ip_conntrack_lock to lock these lists */
830 +LIST_HEAD(request_p_list_udp);
833 +static void delete_request_p(unsigned long request_p_ul)
835 + struct request_p *p = (void *)request_p_ul;
837 + write_lock_bh(&ipct_rpc_udp_lock);
838 + LIST_DELETE(&request_p_list_udp, p);
839 + write_unlock_bh(&ipct_rpc_udp_lock);
845 +static void req_cl(struct request_p * r)
847 + write_lock_bh(&ipct_rpc_udp_lock);
848 + del_timer(&r->timeout);
849 + LIST_DELETE(&request_p_list_udp, r);
850 + write_unlock_bh(&ipct_rpc_udp_lock);
856 +static void clean_request(struct list_head *list)
858 + struct list_head *first = list->prev;
859 + struct list_head *temp = list->next;
860 + struct list_head *aux;
862 + if (list_empty(list))
865 + while (first != temp) {
867 + req_cl((struct request_p *)temp);
870 + req_cl((struct request_p *)temp);
875 +static void alloc_request_p(u_int32_t xid, u_int16_t proto, u_int32_t ip,
878 + struct request_p *req_p;
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);
886 + /* Refresh timeout */
887 + if (del_timer(&req_p->timeout)) {
888 + req_p->timeout.expires = jiffies + EXP;
889 + add_timer(&req_p->timeout);
891 + write_unlock_bh(&ipct_rpc_udp_lock);
895 + write_unlock_bh(&ipct_rpc_udp_lock);
897 + /* Allocate new request_p */
898 + req_p = (struct request_p *) kmalloc(sizeof(struct request_p), GFP_ATOMIC);
900 + DEBUGP("can't allocate request_p\n");
904 + req_p->list.next = NULL;
905 + req_p->list.prev = NULL;
908 + req_p->port = port;
909 + req_p->proto = proto;
911 + /* Initialize timer */
912 + init_timer(&req_p->timeout);
913 + req_p->timeout.expires = jiffies + EXP;
914 + req_p->timeout.data = (unsigned long)req_p;
915 + req_p->timeout.function = delete_request_p;
916 + add_timer(&req_p->timeout);
919 + write_lock_bh(&ipct_rpc_udp_lock);
920 + list_prepend(&request_p_list_udp, req_p);
921 + write_unlock_bh(&ipct_rpc_udp_lock);
927 +static int check_rpc_packet(const u_int32_t *data,
928 + int dir, struct ip_conntrack *ct,
929 + struct list_head request_p_list)
931 + int ret = NF_ACCEPT;
933 + struct request_p *req_p;
934 + struct ip_conntrack_expect *exp;
936 + /* Translstion's buffer for XDR */
937 + u_int16_t port_buf;
943 + /* This does sanity checking on RPC payloads,
944 + * and permits only the RPC "get port" (3)
945 + * in authorised procedures in client
946 + * communications with the portmapper.
949 + /* perform direction dependant RPC work */
950 + if (dir == IP_CT_DIR_ORIGINAL) {
954 + /* Get RPC requestor */
955 + if (IXDR_GET_INT32(data) != 3) {
956 + DEBUGP("RPC packet contains an invalid (non \"get\") requestor. [skip]\n");
959 + DEBUGP("RPC packet contains a \"get\" requestor. [cont]\n");
963 + /* Jump Credentials and Verfifier */
964 + data = data + IXDR_GET_INT32(data) + 2;
965 + data = data + IXDR_GET_INT32(data) + 2;
967 + /* Get RPC procedure */
968 + DEBUGP("RPC packet contains procedure request [%u]. [cont]\n",
969 + (unsigned int)IXDR_GET_INT32(data));
971 + /* Get RPC protocol and store against client parameters */
973 + alloc_request_p(xid, IXDR_GET_INT32(data), ct->tuplehash[dir].tuple.src.ip,
974 + ct->tuplehash[dir].tuple.src.u.all);
976 + DEBUGP("allocated RPC req_p for xid=%u proto=%u %u.%u.%u.%u:%u\n",
977 + xid, IXDR_GET_INT32(data),
978 + NIPQUAD(ct->tuplehash[dir].tuple.src.ip),
979 + ntohs(ct->tuplehash[dir].tuple.src.u.all));
981 + DEBUGP("allocated RPC request for protocol %u. [done]\n",
982 + (unsigned int)IXDR_GET_INT32(data));
986 + /* Check for returning packet's stored counterpart */
987 + req_p = LIST_FIND(&request_p_list_udp, request_p_cmp,
988 + struct request_p *, xid,
989 + ct->tuplehash[!dir].tuple.src.ip,
990 + ct->tuplehash[!dir].tuple.src.u.all);
992 + /* Drop unexpected packets */
994 + DEBUGP("packet is not expected. [skip]\n");
998 + /* Verifies if packet is really an RPC reply packet */
1000 + if (IXDR_GET_INT32(data) != 1) {
1001 + DEBUGP("packet is not a valid RPC reply. [skip]\n");
1005 + /* Is status accept? */
1007 + if (IXDR_GET_INT32(data)) {
1008 + DEBUGP("packet is not an RPC accept. [skip]\n");
1012 + /* Get Verifier length. Jump verifier */
1014 + data = data + IXDR_GET_INT32(data) + 2;
1016 + /* Is accpet status "success"? */
1017 + if (IXDR_GET_INT32(data)) {
1018 + DEBUGP("packet is not an RPC accept status of success. [skip]\n");
1022 + /* Get server port number */
1024 + port_buf = (u_int16_t) IXDR_GET_INT32(data);
1026 + /* If a packet has made it this far then it deserves an
1027 + * expectation ... if port == 0, then this service is
1028 + * not going to be registered.
1031 + DEBUGP("port found: %u\n", port_buf);
1033 + exp = ip_conntrack_expect_alloc(ct);
1039 + /* Watch out, Radioactive-Man! */
1040 + exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
1041 + exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
1042 + exp->mask.src.ip = 0xffffffff;
1043 + exp->mask.dst.ip = 0xffffffff;
1045 + switch (req_p->proto) {
1047 + exp->tuple.src.u.udp.port = 0;
1048 + exp->tuple.dst.u.udp.port = htons(port_buf);
1049 + exp->tuple.dst.protonum = IPPROTO_UDP;
1050 + exp->mask.src.u.udp.port = 0;
1051 + exp->mask.dst.u.udp.port = htons(0xffff);
1052 + exp->mask.dst.protonum = 0xff;
1056 + exp->tuple.src.u.tcp.port = 0;
1057 + exp->tuple.dst.u.tcp.port = htons(port_buf);
1058 + exp->tuple.dst.protonum = IPPROTO_TCP;
1059 + exp->mask.src.u.tcp.port = 0;
1060 + exp->mask.dst.u.tcp.port = htons(0xffff);
1061 + exp->mask.dst.protonum = 0xff;
1064 + exp->expectfn = NULL;
1067 + DEBUGP("expect related ip %u.%u.%u.%u:0-%u.%u.%u.%u:%u proto=%u\n",
1068 + NIPQUAD(exp->tuple.src.ip),
1069 + NIPQUAD(exp->tuple.dst.ip),
1070 + port_buf, req_p->proto);
1072 + DEBUGP("expect related mask %u.%u.%u.%u:0-%u.%u.%u.%u:65535 proto=%u\n",
1073 + NIPQUAD(exp->mask.src.ip),
1074 + NIPQUAD(exp->mask.dst.ip),
1075 + exp->mask.dst.protonum);
1077 + if (ip_conntrack_expect_related(exp) != 0) {
1085 + DEBUGP("packet evaluated. [expect]\n");
1092 +/* RPC UDP helper */
1093 +/* static int help(const struct iphdr *iph, size_t len,
1094 + struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) */
1095 +static int help(struct sk_buff **pskb,
1096 + struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
1100 + struct udphdr _udph, *udph;
1101 + const u_int32_t *data;
1103 + struct iphdr *iph;
1105 + const u_int16_t *chsm;
1107 + /* Not whole UDP header? */
1108 + iph=(*pskb)->nh.iph;
1109 + udph = skb_header_pointer(*pskb,iph->ihl*4,sizeof(_udph),&_udph);
1113 + len = (*pskb)->len; /* stes */
1114 + data = (const u_int32_t *)udph + 2;
1115 + udplen = len - iph->ihl * 4;
1116 + dir = CTINFO2DIR(ctinfo);
1119 + chsm = (const u_int16_t *)udph + 3;
1121 + DEBUGP("new packet to evaluate ..\n");
1123 + /* Not whole UDP header? */
1124 + if (udplen < sizeof(struct udphdr)) {
1125 + DEBUGP("UDP header length is; udplen=%u ..\n", (unsigned) udplen);
1126 + DEBUGP("packet does not contain a complete UDP header. [skip]\n");
1130 + /* perform direction dependant protocol work */
1131 + if (dir == IP_CT_DIR_ORIGINAL) {
1133 + DEBUGP("packet is from the initiator. [cont]\n");
1135 + /* Tests if packet len is ok */
1136 + if ((udplen - sizeof(struct udphdr)) != 56) {
1137 + DEBUGP("packet length is not correct. [skip]\n");
1143 + DEBUGP("packet is from the receiver. [cont]\n");
1145 + /* Until there's been traffic both ways, don't look in packets. */
1146 + if (ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
1147 + DEBUGP("connection tracking state is; ctinfo=%u ..\n", ctinfo);
1148 + DEBUGP("[note: failure to get past this error may indicate asymmetric routing]\n");
1149 + DEBUGP("packet is not yet part of a two way stream. [skip]\n");
1153 + /* Tests if packet len is ok */
1154 + if ((udplen - sizeof(struct udphdr)) != 28) {
1155 + DEBUGP("packet length is not correct. [skip]\n");
1161 + /* Get to the data */
1162 + /* udp *data == *correct */
1164 + /* Check the RPC data */
1165 + crp_ret = check_rpc_packet(data, dir, ct, request_p_list_udp);
1172 +static struct ip_conntrack_helper rpc_helpers[MAX_PORTS];
1173 +static char rpc_names[MAX_PORTS][10];
1175 +static void fini(void);
1177 +static int __init init(void)
1182 + /* If no port given, default to standard RPC port */
1183 + if (ports[0] == 0)
1184 + ports[0] = RPC_PORT;
1186 + for (port = 0; (port < MAX_PORTS) && ports[port]; port++) {
1187 + memset(&rpc_helpers[port], 0, sizeof(struct ip_conntrack_helper));
1189 + tmpname = &rpc_names[port][0];
1190 + if (ports[port] == RPC_PORT)
1191 + sprintf(tmpname, "rpc");
1193 + sprintf(tmpname, "rpc-%d", ports[port]);
1194 + rpc_helpers[port].name = tmpname;
1196 + rpc_helpers[port].me = THIS_MODULE;
1197 + rpc_helpers[port].max_expected = 1;
1198 + rpc_helpers[port].timeout = 5 * 60; /* stes */
1200 + rpc_helpers[port].tuple.dst.protonum = IPPROTO_UDP;
1201 + rpc_helpers[port].mask.dst.protonum = 0xff;
1203 + /* RPC can come from ports 0:65535 to ports[port] (111) */
1204 + rpc_helpers[port].tuple.src.u.udp.port = htons(ports[port]);
1205 + rpc_helpers[port].mask.src.u.udp.port = htons(0xffff);
1206 + rpc_helpers[port].mask.dst.u.udp.port = htons(0x0);
1208 + rpc_helpers[port].help = help;
1210 + PRINTK("registering helper for port #%d: %d/UDP\n", port, ports[port]);
1211 + PRINTK("helper match ip %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
1212 + NIPQUAD(rpc_helpers[port].tuple.dst.ip),
1213 + ntohs(rpc_helpers[port].tuple.dst.u.udp.port),
1214 + NIPQUAD(rpc_helpers[port].tuple.src.ip),
1215 + ntohs(rpc_helpers[port].tuple.src.u.udp.port));
1216 + PRINTK("helper match mask %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
1217 + NIPQUAD(rpc_helpers[port].mask.dst.ip),
1218 + ntohs(rpc_helpers[port].mask.dst.u.udp.port),
1219 + NIPQUAD(rpc_helpers[port].mask.src.ip),
1220 + ntohs(rpc_helpers[port].mask.src.u.udp.port));
1222 + ret = ip_conntrack_helper_register(&rpc_helpers[port]);
1225 + printk("ERROR registering port %d\n",
1236 +/* This function is intentionally _NOT_ defined as __exit, because
1237 + * it is needed by the init function */
1238 +static void fini(void)
1242 + DEBUGP("cleaning request list\n");
1243 + clean_request(&request_p_list_udp);
1245 + for (port = 0; (port < ports_n_c) && ports[port]; port++) {
1246 + DEBUGP("unregistering port %d\n", ports[port]);
1247 + ip_conntrack_helper_unregister(&rpc_helpers[port]);
1255 +struct module *ip_conntrack_rpc_udp = THIS_MODULE;
1256 +EXPORT_SYMBOL(request_p_list_udp);
1257 +EXPORT_SYMBOL(ip_conntrack_rpc_udp);
1258 +EXPORT_SYMBOL(ipct_rpc_udp_lock);
1260 diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/ipt_rpc.c linux/net/ipv4/netfilter/ipt_rpc.c
1261 --- linux.org/net/ipv4/netfilter/ipt_rpc.c 1970-01-01 01:00:00.000000000 +0100
1262 +++ linux/net/ipv4/netfilter/ipt_rpc.c 2006-05-04 11:26:08.000000000 +0200
1264 +/* RPC extension for IP connection matching, Version 2.2
1265 + * (C) 2000 by Marcelo Barbosa Lima <marcelo.lima@dcc.unicamp.br>
1266 + * - original rpc tracking module
1267 + * - "recent" connection handling for kernel 2.3+ netfilter
1269 + * (C) 2001 by Rusty Russell <rusty@rustcorp.com.au>
1270 + * - upgraded conntrack modules to oldnat api - kernel 2.4.0+
1272 + * (C) 2002,2003 by Ian (Larry) Latter <Ian.Latter@mq.edu.au>
1273 + * - upgraded conntrack modules to newnat api - kernel 2.4.20+
1274 + * - extended matching to support filtering on procedures
1276 + * (c) 2004,2005 by David Stes <stes@pandora.be>
1277 + * - upgraded to 2.6.12+ conntrack module api
1278 + * - upgraded to 2.6.13 api
1280 + * ipt_rpc.c,v 2.2 2003/01/12 18:30:00
1282 + * This program is free software; you can redistribute it and/or
1283 + * modify it under the terms of the GNU General Public License
1284 + * as published by the Free Software Foundation; either version
1285 + * 2 of the License, or (at your option) any later version.
1287 + * Module load syntax:
1288 + * insmod ipt_rpc.o ports=port1,port2,...port<MAX_PORTS>
1290 + * Please give the ports of all RPC servers you wish to connect to.
1291 + * If you don't specify ports, the default will be port 111.
1295 + * RPCs should not be exposed to the internet - ask the Pentagon;
1297 + * "The unidentified crackers pleaded guilty in July to charges
1298 + * of juvenile delinquency stemming from a string of Pentagon
1299 + * network intrusions in February.
1301 + * The youths, going by the names TooShort and Makaveli, used
1302 + * a common server security hole to break in, according to
1303 + * Dane Jasper, owner of the California Internet service
1304 + * provider, Sonic. They used the hole, known as the 'statd'
1305 + * exploit, to attempt more than 800 break-ins, Jasper said."
1307 + * From: Wired News; "Pentagon Kids Kicked Off Grid" - Nov 6, 1998
1308 + * URL: http://www.wired.com/news/politics/0,1283,16098,00.html
1312 +#include <linux/module.h>
1313 +#include <linux/skbuff.h>
1314 +#include <linux/list.h>
1315 +#include <linux/udp.h>
1316 +#include <linux/tcp.h>
1317 +#include <linux/netfilter_ipv4/ip_conntrack.h>
1318 +#include <linux/netfilter_ipv4/ip_tables.h>
1319 +#include <linux/netfilter_ipv4/ip_conntrack_rpc.h>
1320 +#include <linux/netfilter_ipv4/ipt_rpc.h>
1322 +#define MAX_PORTS 8
1323 +static int ports[MAX_PORTS];
1324 +static int ports_n_c = 0;
1327 +module_param_array(ports, int, &ports_n_c, 0400);
1328 +MODULE_PARM_DESC(ports, "port numbers (TCP/UDP) of RPC portmapper servers");
1331 +MODULE_AUTHOR("Marcelo Barbosa Lima <marcelo.lima@dcc.unicamp.br>");
1332 +MODULE_DESCRIPTION("RPC connection matching module");
1333 +MODULE_LICENSE("GPL");
1335 +#define PRINTK(format, args...) printk(KERN_DEBUG "ipt_rpc: " \
1339 +#define DEBUGP(format, args...) printk(KERN_DEBUG "ipt_rpc: " \
1342 +#define DEBUGP(format, args...)
1345 +/* EXPORT_NO_SYMBOLS; */
1347 +/* vars from ip_conntrack_rpc_tcp */
1348 +extern struct list_head request_p_list_tcp;
1349 +extern struct module *ip_conntrack_rpc_tcp;
1351 +/* vars from ip_conntrack_rpc_udp */
1352 +extern struct list_head request_p_list_udp;
1353 +extern struct module *ip_conntrack_rpc_udp;
1355 +extern rwlock_t ipct_rpc_tcp_lock;
1356 +extern rwlock_t ipct_rpc_udp_lock;
1358 +#define ASSERT_READ_LOCK(x)
1359 +#define ASSERT_WRITE_LOCK(x)
1362 +#define ASSERT_READ_LOCK(x) \
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); \
1370 +#define ASSERT_WRITE_LOCK(x) \
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); \
1379 +#include <linux/netfilter_ipv4/listhelp.h>
1381 +const int IPT_RPC_CHAR_LEN = 11;
1383 +static int k_atoi(char *string)
1385 + unsigned int result = 0;
1386 + int maxoctet = IPT_RPC_CHAR_LEN;
1388 + for ( ; *string != 0 && maxoctet != 0; maxoctet--, string++) {
1393 + if (*string < 48 || *string > 57) {
1396 + result = result * 10 + ( *string - 48 );
1402 +static int match_rpcs(char *c_procs, int i_procs, int proc)
1406 + unsigned int proc_num;
1408 + DEBUGP("entered match_rpcs [%i] [%i] ..\n", i_procs, proc);
1410 + if (i_procs == -1)
1413 + for (proc_ctr=0; proc_ctr <= i_procs; proc_ctr++) {
1415 + proc_ptr = c_procs;
1416 + proc_ptr += proc_ctr * IPT_RPC_CHAR_LEN;
1417 + proc_num = k_atoi(proc_ptr);
1419 + if (proc_num == proc)
1427 +static int check_rpc_packet(const u_int32_t *data, const void *matchinfo,
1428 + int *hotdrop, int dir, struct ip_conntrack *ct,
1429 + int offset, struct list_head request_p_list)
1431 + const struct ipt_rpc_info *rpcinfo = matchinfo;
1432 + struct request_p *req_p;
1439 + /* This does sanity checking on RPC payloads,
1440 + * and permits only the RPC "get port" (3)
1441 + * in authorised procedures in client
1442 + * communications with the portmapper.
1447 + /* Get RPC requestor */
1448 + if (IXDR_GET_INT32(data) != 3) {
1449 + DEBUGP("RPC packet contains an invalid (non \"get\") requestor. [skip]\n");
1450 + if(rpcinfo->strict == 1)
1454 + DEBUGP("RPC packet contains a \"get\" requestor. [cont]\n");
1458 + /* Jump Credentials and Verfifier */
1459 + data = data + IXDR_GET_INT32(data) + 2;
1460 + data = data + IXDR_GET_INT32(data) + 2;
1462 + /* Get RPC procedure */
1463 + if (match_rpcs((char *)&rpcinfo->c_procs,
1464 + rpcinfo->i_procs, IXDR_GET_INT32(data)) == 0) {
1465 + DEBUGP("RPC packet contains illegal procedure request [%u]. [drop]\n",
1466 + (unsigned int)IXDR_GET_INT32(data));
1468 + /* If the RPC conntrack half entry already exists .. */
1470 + switch (ct->tuplehash[0].tuple.dst.protonum) {
1472 + write_lock_bh(&ipct_rpc_udp_lock);
1474 + write_lock_bh(&ipct_rpc_tcp_lock);
1476 + req_p = LIST_FIND(&request_p_list, request_p_cmp,
1477 + struct request_p *, xid,
1478 + ct->tuplehash[dir].tuple.src.ip,
1479 + ct->tuplehash[dir].tuple.src.u.all);
1482 + DEBUGP("found req_p for xid=%u proto=%u %u.%u.%u.%u:%u\n",
1483 + xid, ct->tuplehash[dir].tuple.dst.protonum,
1484 + NIPQUAD(ct->tuplehash[dir].tuple.src.ip),
1485 + ntohs(ct->tuplehash[dir].tuple.src.u.all));
1487 + /* .. remove it */
1488 + if (del_timer(&req_p->timeout))
1489 + req_p->timeout.expires = 0;
1491 + LIST_DELETE(&request_p_list, req_p);
1492 + DEBUGP("RPC req_p removed. [done]\n");
1495 + DEBUGP("no req_p found for xid=%u proto=%u %u.%u.%u.%u:%u\n",
1496 + xid, ct->tuplehash[dir].tuple.dst.protonum,
1497 + NIPQUAD(ct->tuplehash[dir].tuple.src.ip),
1498 + ntohs(ct->tuplehash[dir].tuple.src.u.all));
1501 + switch (ct->tuplehash[0].tuple.dst.protonum) {
1503 + write_unlock_bh(&ipct_rpc_udp_lock);
1505 + write_unlock_bh(&ipct_rpc_tcp_lock);
1508 + if(rpcinfo->strict == 1)
1513 + DEBUGP("RPC packet contains authorised procedure request [%u]. [match]\n",
1514 + (unsigned int)IXDR_GET_INT32(data));
1515 + return (1 && (!offset));
1520 +/* static int match(const struct sk_buff *skb, const struct net_device *in,
1521 + const struct net_device *out, const void *matchinfo,
1522 + int offset, const void *hdr, u_int16_t datalen, int *hotdrop)
1524 +static int match(const struct sk_buff *skb, const struct net_device *in,
1525 + const struct net_device *out, const void *matchinfo,
1526 + int offset, unsigned int protoff, int *hotdrop)
1528 + struct ip_conntrack *ct;
1529 + enum ip_conntrack_info ctinfo;
1530 + const u_int32_t *data;
1531 + enum ip_conntrack_dir dir;
1532 + const struct tcphdr *tcp;
1533 + const struct ipt_rpc_info *rpcinfo = matchinfo;
1534 + int port, portsok;
1536 + struct iphdr *ip; /* stes */
1537 + void *hdr; /* stes */
1538 + u_int16_t datalen; /* stes */
1540 + /* Initialization stes - see 2.4 ip_tables.c ipt_do_table() */
1542 + hdr = (u_int32_t *)ip + ip->ihl;
1543 + datalen = skb->len - ip->ihl * 4;
1545 + DEBUGP("new packet to evaluate ..\n");
1547 + ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
1549 + DEBUGP("no ct available [skip]\n");
1553 + DEBUGP("ct detected. [cont]\n");
1554 + dir = CTINFO2DIR(ctinfo);
1556 + /* we only want the client to server packets for matching */
1557 + if (dir != IP_CT_DIR_ORIGINAL)
1560 + /* This does sanity checking on UDP or TCP packets,
1561 + * like their respective modules.
1564 + switch (ct->tuplehash[0].tuple.dst.protonum) {
1567 + DEBUGP("PROTO_UDP [cont]\n");
1568 + if (offset == 0 && datalen < sizeof(struct udphdr)) {
1569 + DEBUGP("packet does not contain a complete header. [drop]\n");
1573 + for (port=0,portsok=0; port <= ports_n_c; port++) {
1574 + if (ntohs(ct->tuplehash[dir].tuple.dst.u.all) == ports[port]) {
1579 + if (portsok == 0) {
1580 + DEBUGP("packet is not destined for a portmapper [%u]. [skip]\n",
1581 + ntohs(ct->tuplehash[dir].tuple.dst.u.all));
1585 + if ((datalen - sizeof(struct udphdr)) != 56) {
1586 + DEBUGP("packet length is not correct for RPC content. [skip]\n");
1587 + if (rpcinfo->strict == 1)
1591 + DEBUGP("packet length is correct. [cont]\n");
1593 + /* Get to the data */
1594 + data = (const u_int32_t *)hdr + 2;
1596 + /* Check the RPC data */
1597 + tval = check_rpc_packet(data, matchinfo, hotdrop,
1599 + request_p_list_udp);
1605 + DEBUGP("PROTO_TCP [cont]\n");
1606 + if (offset == 0 && datalen < sizeof(struct tcphdr)) {
1607 + DEBUGP("packet does not contain a complete header. [drop]\n");
1611 + for (port=0,portsok=0; port <= ports_n_c; port++) {
1612 + if (ntohs(ct->tuplehash[dir].tuple.dst.u.all) == ports[port]) {
1617 + if (portsok == 0) {
1618 + DEBUGP("packet is not destined for a portmapper [%u]. [skip]\n",
1619 + ntohs(ct->tuplehash[dir].tuple.dst.u.all));
1624 + if (datalen == (tcp->doff * 4)) {
1625 + DEBUGP("packet does not contain any data. [match]\n");
1626 + return (1 && (!offset));
1629 + /* Tests if packet len is ok */
1630 + if ((datalen - (tcp->doff * 4)) != 60) {
1631 + DEBUGP("packet length is not correct for RPC content. [skip]\n");
1632 + if(rpcinfo->strict == 1)
1636 + DEBUGP("packet length is correct. [cont]\n");
1638 + /* Get to the data */
1639 + data = (const u_int32_t *)tcp + tcp->doff + 1;
1641 + /* Check the RPC data */
1642 + tval = check_rpc_packet(data, matchinfo, hotdrop,
1644 + request_p_list_tcp);
1650 + DEBUGP("transport protocol=%u, is not supported [skip]\n",
1651 + ct->tuplehash[0].tuple.dst.protonum);
1656 +static int checkentry(const char *tablename, const struct ipt_ip *ip, void *matchinfo,
1657 + unsigned int matchsize, unsigned int hook_mask)
1660 + & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_FORWARD) | (1 << NF_IP_POST_ROUTING)
1661 + | (1 << NF_IP_LOCAL_IN) | (1 << NF_IP_LOCAL_OUT))) {
1662 + printk("ipt_rpc: only valid for PRE_ROUTING, FORWARD, POST_ROUTING, LOCAL_IN and/or LOCAL_OUT targets.\n");
1666 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_rpc_info)))
1672 +static struct ipt_match rpc_match = {
1675 + .checkentry = &checkentry,
1676 + .me = THIS_MODULE,
1679 +static int __init init(void)
1683 + /* If no port given, default to standard RPC port */
1684 + if (ports[0] == 0)
1685 + ports[0] = RPC_PORT;
1687 + PRINTK("registering match [%s] for;\n", rpc_match.name);
1688 + for (port = 0; (port < MAX_PORTS) && ports[port]; port++) {
1689 + PRINTK(" port %i (UDP|TCP);\n", ports[port]);
1693 + return ipt_register_match(&rpc_match);
1697 +static void fini(void)
1699 + DEBUGP("unregistering match\n");
1700 + ipt_unregister_match(&rpc_match);