diff -ruN patch-o-matic-ng-20040621/.config src/patch-o-matic-ng-20040621/.config --- patch-o-matic-ng-20040621/.config 1970-01-01 01:00:00.000000000 +0100 +++ src/patch-o-matic-ng-20040621/.config 2004-08-25 10:13:16.000000000 +0200 @@ -0,0 +1,4 @@ +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CLEARCASE=m diff -ruN patch-o-matic-ng-20040621/conntrack_clearcase/help src/patch-o-matic-ng-20040621/conntrack_clearcase/help --- patch-o-matic-ng-20040621/conntrack_clearcase/help 1970-01-01 01:00:00.000000000 +0100 +++ src/patch-o-matic-ng-20040621/conntrack_clearcase/help 2004-08-25 10:23:03.000000000 +0200 @@ -0,0 +1,6 @@ + This adds CONFIG_IP_NF_CLEARCASE, which is the CLEARCASE + connection tracker. + + This option supplies two connection tracking modules; + ip_conntrack_clearcase_udp and ip_conntrack_clearcasae_tcp, which track + clearcase requests using UDP and TCP respectively. diff -ruN patch-o-matic-ng-20040621/conntrack_clearcase/info src/patch-o-matic-ng-20040621/conntrack_clearcase/info --- patch-o-matic-ng-20040621/conntrack_clearcase/info 1970-01-01 01:00:00.000000000 +0100 +++ src/patch-o-matic-ng-20040621/conntrack_clearcase/info 2004-08-25 10:21:14.000000000 +0200 @@ -0,0 +1,4 @@ +Author: "Marcelo Barbosa Lima" +Status: request for permanent inclusion +Repository: extra +Requires: linux < 2.6.0 diff -ruN patch-o-matic-ng-20040621/conntrack_clearcase/linux/.config.ladd src/patch-o-matic-ng-20040621/conntrack_clearcase/linux/.config.ladd --- patch-o-matic-ng-20040621/conntrack_clearcase/linux/.config.ladd 1970-01-01 01:00:00.000000000 +0100 +++ src/patch-o-matic-ng-20040621/conntrack_clearcase/linux/.config.ladd 2004-08-25 10:41:59.000000000 +0200 @@ -0,0 +1,2 @@ +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_CLEARCASE=m diff -ruN patch-o-matic-ng-20040621/conntrack_clearcase/linux/Documentation/Configure.help.ladd src/patch-o-matic-ng-20040621/conntrack_clearcase/linux/Documentation/Configure.help.ladd --- patch-o-matic-ng-20040621/conntrack_clearcase/linux/Documentation/Configure.help.ladd 1970-01-01 01:00:00.000000000 +0100 +++ src/patch-o-matic-ng-20040621/conntrack_clearcase/linux/Documentation/Configure.help.ladd 2004-08-25 09:48:38.000000000 +0200 @@ -0,0 +1,12 @@ +CONFIG_IP_NF_CONNTRACK +CLEARCASE protocol support +CONFIG_IP_NF_CLEARCASE + This adds CONFIG_IP_NF_CLEARCASE, which is the CLEARCASE + connection tracker. + + This option supplies two connection tracking modules; + ip_conntrack_clearcase_udp and ip_conntrack_clearcasae_tcp, which track + clearcase requests using UDP and TCP respectively. + + If you want to compile it as a module, say M here and read + . If unsure, say `N'. diff -ruN patch-o-matic-ng-20040621/conntrack_clearcase/linux/include/linux/netfilter_ipv4/ip_conntrack_clearcase.h src/patch-o-matic-ng-20040621/conntrack_clearcase/linux/include/linux/netfilter_ipv4/ip_conntrack_clearcase.h --- patch-o-matic-ng-20040621/conntrack_clearcase/linux/include/linux/netfilter_ipv4/ip_conntrack_clearcase.h 1970-01-01 01:00:00.000000000 +0100 +++ src/patch-o-matic-ng-20040621/conntrack_clearcase/linux/include/linux/netfilter_ipv4/ip_conntrack_clearcase.h 2004-08-24 14:28:21.000000000 +0200 @@ -0,0 +1,68 @@ +/* CLEARCASE extension for IP connection tracking, Version 2.2 + * (C) 2000 by Marcelo Barbosa Lima + * - original CLEARCASE tracking module + * - "recent" connection handling for kernel 2.3+ netfilter + * + * (C) 2001 by Rusty Russell + * - upgraded conntrack modules to oldnat api - kernel 2.4.0+ + * + * (C) 2002 by Ian (Larry) Latter + * - upgraded conntrack modules to newnat api - kernel 2.4.20+ + * - extended matching to support filtering on procedures + * + * ip_conntrack_CLEARCASE.h,v 2.2 2003/01/12 18:30:00 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + ** + */ + +#include +#include +#include +#include +#include + +#include + +#ifndef _IP_CONNTRACK_CLEARCASE_H +#define _IP_CONNTRACK_CLEARCASE_H + +#define CLEARCASE_PORT 371 + + +/* Datum in CLEARCASE packets are encoded in XDR */ +#define IXDR_GET_INT32(buf) ((u_int32_t) ntohl((uint32_t)*buf)) + +/* Fast timeout, to deny DoS attacks */ +#define EXP (60 * HZ) + +/* Normal timeouts */ +#define EXPIRES (180 * HZ) + +/* For future conections CLEARCASE, using client's cache bindings + * I'll use ip_conntrack_lock to lock these lists */ + +/* This identifies each request and stores protocol */ +struct request_p { + struct list_head list; + + u_int32_t xid; + u_int32_t ip; + u_int16_t port; + + /* Protocol */ + u_int16_t proto; + + struct timer_list timeout; +}; + +static inline int request_p_cmp(const struct request_p *p, u_int32_t xid, + u_int32_t ip, u_int32_t port) { + return (p->xid == xid && p->ip == ip && p->port); + +} + +#endif /* _IP_CONNTRACK_CLEARCASE_H */ diff -ruN patch-o-matic-ng-20040621/conntrack_clearcase/linux/net/ipv4/netfilter/Config.in.ladd src/patch-o-matic-ng-20040621/conntrack_clearcase/linux/net/ipv4/netfilter/Config.in.ladd --- patch-o-matic-ng-20040621/conntrack_clearcase/linux/net/ipv4/netfilter/Config.in.ladd 1970-01-01 01:00:00.000000000 +0100 +++ src/patch-o-matic-ng-20040621/conntrack_clearcase/linux/net/ipv4/netfilter/Config.in.ladd 2004-08-25 10:30:59.000000000 +0200 @@ -0,0 +1,2 @@ +if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then + dep_tristate ' CLEARCASE protocol support' CONFIG_IP_NF_CLEARCASE $CONFIG_IP_NF_CONNTRACK diff -ruN patch-o-matic-ng-20040621/conntrack_clearcase/linux/net/ipv4/netfilter/Makefile.ladd src/patch-o-matic-ng-20040621/conntrack_clearcase/linux/net/ipv4/netfilter/Makefile.ladd --- patch-o-matic-ng-20040621/conntrack_clearcase/linux/net/ipv4/netfilter/Makefile.ladd 1970-01-01 01:00:00.000000000 +0100 +++ src/patch-o-matic-ng-20040621/conntrack_clearcase/linux/net/ipv4/netfilter/Makefile.ladd 2004-08-25 11:47:15.000000000 +0200 @@ -0,0 +1,6 @@ +# connection tracking helpers +obj-$(CONFIG_IP_NF_CLEARCASE) += ip_conntrack_clearcase_tcp.o ip_conntrack_clearcase_udp.o +ifdef CONFIG_IP_NF_CLEARCASE + export-objs += ip_conntrack_clearcase_tcp.o ip_conntrack_clearcase_udp.o +endif + diff -ruN patch-o-matic-ng-20040621/conntrack_clearcase/linux/net/ipv4/netfilter/ip_conntrack_clearcase_tcp.c src/patch-o-matic-ng-20040621/conntrack_clearcase/linux/net/ipv4/netfilter/ip_conntrack_clearcase_tcp.c --- patch-o-matic-ng-20040621/conntrack_clearcase/linux/net/ipv4/netfilter/ip_conntrack_clearcase_tcp.c 1970-01-01 01:00:00.000000000 +0100 +++ src/patch-o-matic-ng-20040621/conntrack_clearcase/linux/net/ipv4/netfilter/ip_conntrack_clearcase_tcp.c 2004-08-24 15:05:56.000000000 +0200 @@ -0,0 +1,513 @@ +/* clearcase extension for IP (TCP) connection tracking, Version 2.2 + * (C) 2000 by Marcelo Barbosa Lima + * - original clearcase tracking module + * - "recent" connection handling for kernel 2.3+ netfilter + * + * (C) 2001 by Rusty Russell + * - upgraded conntrack modules to oldnat api - kernel 2.4.0+ + * + * (C) 2002,2003 by Ian (Larry) Latter + * - upgraded conntrack modules to newnat api - kernel 2.4.20+ + * - extended matching to support filtering on procedures + * + * ip_conntrack_clearcase_tcp.c,v 2.2 2003/01/12 18:30:00 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + ** + * Module load syntax: + * insmod ip_conntrack_clearcase_tcp.o ports=port1,port2,...port + * + * Please give the ports of all clearcase servers you wish to connect to. + * If you don't specify ports, the default will be port 111. + ** + * Note to all: + * + * clearcases should not be exposed to the internet - ask the Pentagon; + * + * "The unidentified crackers pleaded guilty in July to charges + * of juvenile delinquency stemming from a string of Pentagon + * network intrusions in February. + * + * The youths, going by the names TooShort and Makaveli, used + * a common server security hole to break in, according to + * Dane Jasper, owner of the California Internet service + * provider, Sonic. They used the hole, known as the 'statd' + * exploit, to attempt more than 800 break-ins, Jasper said." + * + * From: Wired News; "Pentagon Kids Kicked Off Grid" - Nov 6, 1998 + * URL: http://www.wired.com/news/politics/0,1283,16098,00.html + ** + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define MAX_PORTS 8 +static int ports[MAX_PORTS]; +static int ports_n_c = 0; + +#ifdef MODULE_PARM +MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); +MODULE_PARM_DESC(ports, "port numbers (TCP/TCP) of clearcase portmapper servers"); +#endif + +MODULE_AUTHOR("Marcelo Barbosa Lima "); +MODULE_DESCRIPTION("clearcase TCP connection tracking module"); +MODULE_LICENSE("GPL"); + +#if 0 +#define DEBUGP(format, args...) printk(KERN_DEBUG "ip_conntrack_clearcase_tcp: " \ + format, ## args) +#else +#define DEBUGP(format, args...) +#endif + +DECLARE_RWLOCK(ipct_clearcase_tcp_lock); +#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ipct_clearcase_tcp_lock) +#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ipct_clearcase_tcp_lock) + +#include + +/* For future conections clearcase, using client's cache bindings + * I'll use ip_conntrack_lock to lock these lists */ + +LIST_HEAD(request_p_list_tcp); + + +static void delete_request_p(unsigned long request_p_ul) +{ + struct request_p *p = (void *)request_p_ul; + + WRITE_LOCK(&ipct_clearcase_tcp_lock); + LIST_DELETE(&request_p_list_tcp, p); + WRITE_UNLOCK(&ipct_clearcase_tcp_lock); + kfree(p); + return; +} + + +static void req_cl(struct request_p * r) +{ + WRITE_LOCK(&ipct_clearcase_tcp_lock); + del_timer(&r->timeout); + LIST_DELETE(&request_p_list_tcp, r); + WRITE_UNLOCK(&ipct_clearcase_tcp_lock); + kfree(r); + return; +} + + +static void clean_request(struct list_head *list) +{ + struct list_head *first = list->prev; + struct list_head *temp = list->next; + struct list_head *aux; + + if (list_empty(list)) + return; + + while (first != temp) { + aux = temp->next; + req_cl((struct request_p *)temp); + temp = aux; + } + req_cl((struct request_p *)temp); + return; +} + + +static void alloc_request_p(u_int32_t xid, u_int16_t proto, u_int32_t ip, + u_int16_t port) +{ + struct request_p *req_p; + + /* Verifies if entry already exists */ + WRITE_LOCK(&ipct_clearcase_tcp_lock); + req_p = LIST_FIND(&request_p_list_tcp, request_p_cmp, + struct request_p *, xid, ip, port); + + if (req_p) { + /* Refresh timeout */ + if (del_timer(&req_p->timeout)) { + req_p->timeout.expires = jiffies + EXP; + add_timer(&req_p->timeout); + } + WRITE_UNLOCK(&ipct_clearcase_tcp_lock); + return; + + } + WRITE_UNLOCK(&ipct_clearcase_tcp_lock); + + /* Allocate new request_p */ + req_p = (struct request_p *) kmalloc(sizeof(struct request_p), GFP_ATOMIC); + if (!req_p) { + DEBUGP("can't allocate request_p\n"); + return; + } + *req_p = ((struct request_p) {{ NULL, NULL }, xid, ip, port, proto, + { { NULL, NULL }, jiffies + EXP, (unsigned long)req_p, + NULL }}); + + /* Initialize timer */ + init_timer(&req_p->timeout); + req_p->timeout.function = delete_request_p; + add_timer(&req_p->timeout); + + /* Put in list */ + WRITE_LOCK(&ipct_clearcase_tcp_lock); + list_prepend(&request_p_list_tcp, req_p); + WRITE_UNLOCK(&ipct_clearcase_tcp_lock); + return; + +} + + +static int check_clearcase_packet(const u_int32_t *data, + int dir, struct ip_conntrack *ct, + struct list_head request_p_list) +{ + struct request_p *req_p; + u_int32_t xid; + u_int32_t mtype; + struct ip_conntrack_expect expect, *exp = &expect; + + /* Translstion's buffer for XDR */ + u_int32_t port_buf; + + /* Get XID and Message Type*/ + data--; + xid = ntohl(*data); + data++; + mtype = ntohl(*data); + data--; + + /* This does sanity checking on clearcase payloads, + * and permits only the clearcase "get port" (3) + * in authorised procedures in client + * communications with the portmapper. + */ + + /* perform direction dependant clearcase work */ + if (dir == IP_CT_DIR_ORIGINAL) { + + data += 5; + + /* Get clearcase requestor */ + if (IXDR_GET_INT32(data) != 3) { + DEBUGP("clearcase packet contains an invalid (non \"get\") requestor. [skip] \n"); + return NF_ACCEPT; + } + DEBUGP("clearcase packet contains a \"get\" requestor. [cont]\n"); + + data++; + + /* Jump Credentials and Verfifier */ + data = data + IXDR_GET_INT32(data) + 2; + data = data + IXDR_GET_INT32(data) + 2; + + /* Get clearcase procedure */ + DEBUGP("clearcase packet contains procedure request [%u]. [cont]\n", + (unsigned int)IXDR_GET_INT32(data)); + + /* Get clearcase protocol and store against client parameters */ + data = data + 2; + alloc_request_p(xid, IXDR_GET_INT32(data), ct->tuplehash[dir].tuple.src.ip, + ct->tuplehash[dir].tuple.src.u.all); + + DEBUGP("allocated clearcase req_p for xid=%u %u.%u.%u.%u:%u\n", + ntohl(xid), + NIPQUAD(ct->tuplehash[dir].tuple.src.ip), + ntohs(ct->tuplehash[dir].tuple.src.u.all)); + + } else { + + /* Check for returning packet's stored counterpart */ + req_p = LIST_FIND(&request_p_list_tcp, request_p_cmp, + struct request_p *, xid, + ct->tuplehash[!dir].tuple.src.ip, + ct->tuplehash[!dir].tuple.src.u.tcp.port); + + // Next Connection will be TCP + req_p->proto=6; + + /* Drop unexpected packets */ + if (!req_p) { + DEBUGP("packet is not expected. [skip]\n"); + return NF_ACCEPT; + } + + /* Verifies if packet is really an clearcase reply packet */ + data ++; + if (IXDR_GET_INT32(data) != 1) { + DEBUGP("packet is not a valid clearcase reply. [skip]\n"); + return NF_ACCEPT; + } + + /* Is status accept? */ + data++; + if (IXDR_GET_INT32(data)) { + DEBUGP("packet is not an clearcase accept. [skip]\n"); + return NF_ACCEPT; + } + + /* Get Verifier length. Jump verifier */ + data++; + data = data + IXDR_GET_INT32(data) + 2; + + /* Is accpet status "success"? */ + if (IXDR_GET_INT32(data)) { + DEBUGP("packet is not an clearcase accept status of success. [skip]\n"); + return NF_ACCEPT; + } + + /* Get server port number */ + //data++; + data += 10; + port_buf = (u_int16_t) IXDR_GET_INT32(data); + + /* If a packet has made it this far then it deserves an + * expectation ... if port == 0, then this service is + * not going to be registered. + */ + if (port_buf) { + DEBUGP("port found: %u\n", port_buf); + + memset(&expect, 0, sizeof(expect)); + + /* Watch out, Radioactive-Man! */ + exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; + exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; + exp->mask.src.ip = 0xffffffff; + exp->mask.dst.ip = 0xffffffff; + + switch (req_p->proto) { + case IPPROTO_UDP: + exp->tuple.src.u.udp.port = 0; + exp->tuple.dst.u.udp.port = htons(port_buf); + exp->tuple.dst.protonum = IPPROTO_UDP; + exp->mask.src.u.udp.port = 0; + exp->mask.dst.u.udp.port = htons(0xffff); + exp->mask.dst.protonum = 0xffff; + break; + + case IPPROTO_TCP: + exp->tuple.src.u.tcp.port = 0; + exp->tuple.dst.u.tcp.port = htons(port_buf); + exp->tuple.dst.protonum = IPPROTO_TCP; + exp->mask.src.u.tcp.port = 0; + exp->mask.dst.u.tcp.port = htons(0xffff); + exp->mask.dst.protonum = 0xffff; + break; + } + exp->expectfn = NULL; + + ip_conntrack_expect_related(ct, &expect); + + DEBUGP("expect related ip %u.%u.%u.%u:0-%u.%u.%u.%u:%u proto=%u\n", + NIPQUAD(exp->tuple.src.ip), + NIPQUAD(exp->tuple.dst.ip), + port_buf, req_p->proto); + + DEBUGP("expect related mask %u.%u.%u.%u:0-%u.%u.%u.%u:65535 proto=%u\n", + NIPQUAD(exp->mask.src.ip), + NIPQUAD(exp->mask.dst.ip), + exp->mask.dst.protonum); + + } + + req_cl(req_p); + + DEBUGP("packet evaluated. [expect]\n"); + return NF_ACCEPT; + } + + return NF_ACCEPT; + +} + + +/* CLEARCASE TCP helper */ +static int help(const struct iphdr *iph, size_t len, + struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) +{ + struct tcphdr *tcph = (void *) iph + iph->ihl * 4; + const u_int32_t *data = (const u_int32_t *)tcph + tcph->doff; + size_t tcplen = len - iph->ihl * 4; + + int dir = CTINFO2DIR(ctinfo); + int crp_ret; + + + DEBUGP("new packet to evaluate ..\n"); + + /* This works for packets like handshake packets, ignore */ + if (len == ((tcph->doff + iph->ihl) * 4)) { + DEBUGP("packet has no data (may still be handshaking). [skip]\n"); + return NF_ACCEPT; + } + + /* Until there's been traffic both ways, don't look in packets. */ + if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) + { + DEBUGP("connection tracking state is; ctinfo=%u ..\n", ctinfo); + DEBUGP("[note: failure to get past this error may indicate asymmetric routing]\n"); + DEBUGP("packet is not yet part of a two way stream. [skip]\n"); + return NF_ACCEPT; + } + + /* Not whole TCP header? */ + if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) { + DEBUGP("TCP header length is; tcplen=%u ..\n", (unsigned) tcplen); + DEBUGP("packet does not contain a complete TCP header. [skip]\n"); + return NF_ACCEPT; + } + + /* FIXME: Source route IP option packets --RR */ + if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, + csum_partial((char *) tcph, tcplen, 0))) { + DEBUGP("csum; %p %u %u.%u.%u.%u %u.%u.%u.%u\n", + tcph, tcplen, NIPQUAD(iph->saddr), + NIPQUAD(iph->daddr)); + DEBUGP("[note: failure to get past this error may indicate source routing]\n"); + DEBUGP("packet contains a bad checksum. [skip]\n"); + return NF_ACCEPT; + } + + /* perform direction dependant protocol work */ + if (dir == IP_CT_DIR_ORIGINAL) { + + DEBUGP("packet is from the initiator. [cont]\n"); + + /* Tests if packet len is ok */ + if ((tcplen - (tcph->doff * 4)) != 140) { + DEBUGP("packet length is not correct. [skip]\n"); + return NF_ACCEPT; + } + + } else { + + DEBUGP("packet is from the receiver. [cont]\n"); + + /* Tests if packet len is ok */ + if ((tcplen - (tcph->doff * 4)) != 64) { + DEBUGP("packet length is not correct. [skip]\n"); + return NF_ACCEPT; + } + } + + /* Get to the data */ + data++; + + /* Check the CLEARCASE data */ + crp_ret = check_clearcase_packet(data, dir, ct, request_p_list_tcp); + + return crp_ret; + +} + + +static struct ip_conntrack_helper clearcase_helpers[MAX_PORTS]; + +static void fini(void); + + +static int __init init(void) +{ + int port, ret; + static char name[10]; + + + /* If no port given, default to standard CLEARCASE port */ + if (ports[0] == 0) + ports[0] = CLEARCASE_PORT; + + for (port = 0; (port < MAX_PORTS) && ports[port]; port++) { + memset(&clearcase_helpers[port], 0, sizeof(struct ip_conntrack_helper)); + + if (ports[port] == CLEARCASE_PORT) + sprintf(name, "clearcase"); + else + sprintf(name, "clearcase-%d", port); + + clearcase_helpers[port].name = name; + clearcase_helpers[port].me = THIS_MODULE; + clearcase_helpers[port].max_expected = 1; + clearcase_helpers[port].flags = IP_CT_HELPER_F_REUSE_EXPECT; + clearcase_helpers[port].timeout = 0; + + clearcase_helpers[port].tuple.dst.protonum = IPPROTO_TCP; + clearcase_helpers[port].mask.dst.protonum = 0xffff; + + /* CLEARCASE can come from ports 0:65535 to ports[port] (111) */ + clearcase_helpers[port].tuple.src.u.tcp.port = htons(ports[port]); + clearcase_helpers[port].mask.src.u.tcp.port = htons(0xffff); + clearcase_helpers[port].mask.dst.u.tcp.port = htons(0x0); + + clearcase_helpers[port].help = help; + + DEBUGP("registering helper for port #%d: %d/TCP\n", port, ports[port]); + DEBUGP("helper match ip %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", + NIPQUAD(clearcase_helpers[port].tuple.dst.ip), + ntohs(clearcase_helpers[port].tuple.dst.u.tcp.port), + NIPQUAD(clearcase_helpers[port].tuple.src.ip), + ntohs(clearcase_helpers[port].tuple.src.u.tcp.port)); + DEBUGP("helper match mask %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", + NIPQUAD(clearcase_helpers[port].mask.dst.ip), + ntohs(clearcase_helpers[port].mask.dst.u.tcp.port), + NIPQUAD(clearcase_helpers[port].mask.src.ip), + ntohs(clearcase_helpers[port].mask.src.u.tcp.port)); + + ret = ip_conntrack_helper_register(&clearcase_helpers[port]); + + if (ret) { + printk("ERROR registering port %d\n", + ports[port]); + fini(); + return -EBUSY; + } + ports_n_c++; + } + return 0; +} + + +/* This function is intentionally _NOT_ defined as __exit, because + * it is needed by the init function */ +static void fini(void) +{ + int port; + + DEBUGP("cleaning request list\n"); + clean_request(&request_p_list_tcp); + + for (port = 0; (port < ports_n_c) && ports[port]; port++) { + DEBUGP("unregistering port %d\n", ports[port]); + ip_conntrack_helper_unregister(&clearcase_helpers[port]); + } +} + + +module_init(init); +module_exit(fini); + +struct module *ip_conntrack_clearcase_tcp = THIS_MODULE; +EXPORT_SYMBOL(request_p_list_tcp); +EXPORT_SYMBOL(ip_conntrack_clearcase_tcp); +EXPORT_SYMBOL(ipct_clearcase_tcp_lock); diff -ruN patch-o-matic-ng-20040621/conntrack_clearcase/linux/net/ipv4/netfilter/ip_conntrack_clearcase_udp.c src/patch-o-matic-ng-20040621/conntrack_clearcase/linux/net/ipv4/netfilter/ip_conntrack_clearcase_udp.c --- patch-o-matic-ng-20040621/conntrack_clearcase/linux/net/ipv4/netfilter/ip_conntrack_clearcase_udp.c 1970-01-01 01:00:00.000000000 +0100 +++ src/patch-o-matic-ng-20040621/conntrack_clearcase/linux/net/ipv4/netfilter/ip_conntrack_clearcase_udp.c 2004-08-24 15:07:55.000000000 +0200 @@ -0,0 +1,515 @@ +/* clearcase extension for IP (UDP) connection tracking, Version 2.2 + * (C) 2000 by Marcelo Barbosa Lima + * - original clearcase tracking module + * - "recent" connection handling for kernel 2.3+ netfilter + * + * (C) 2001 by Rusty Russell + * - upgraded conntrack modules to oldnat api - kernel 2.4.0+ + * + * (C) 2002,2003 by Ian (Larry) Latter + * - upgraded conntrack modules to newnat api - kernel 2.4.20+ + * - extended matching to support filtering on procedures + * + * ip_conntrack_clearcase_udp.c,v 2.2 2003/01/12 18:30:00 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + ** + * Module load syntax: + * insmod ip_conntrack_clearcase_udp.o ports=port1,port2,...port + * + * Please give the ports of all clearcase servers you wish to connect to. + * If you don't specify ports, the default will be port 111. + ** + * Note to all: + * + * clearcases should not be exposed to the internet - ask the Pentagon; + * + * "The unidentified crackers pleaded guilty in July to charges + * of juvenile delinquency stemming from a string of Pentagon + * network intrusions in February. + * + * The youths, going by the names TooShort and Makaveli, used + * a common server security hole to break in, according to + * Dane Jasper, owner of the California Internet service + * provider, Sonic. They used the hole, known as the 'statd' + * exploit, to attempt more than 800 break-ins, Jasper said." + * + * From: Wired News; "Pentagon Kids Kicked Off Grid" - Nov 6, 1998 + * URL: http://www.wired.com/news/politics/0,1283,16098,00.html + ** + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define MAX_PORTS 8 +static int ports[MAX_PORTS]; +static int ports_n_c = 0; + +#ifdef MODULE_PARM +MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); +MODULE_PARM_DESC(ports, "port numbers (TCP/UDP) of clearcase portmapper servers"); +#endif + +MODULE_AUTHOR("Marcelo Barbosa Lima "); +MODULE_DESCRIPTION("clearcase UDP connection tracking module"); +MODULE_LICENSE("GPL"); + +#if 0 +#define DEBUGP(format, args...) printk(KERN_DEBUG "ip_conntrack_clearcase_udp: " \ + format, ## args) +#else +#define DEBUGP(format, args...) +#endif + +DECLARE_RWLOCK(ipct_clearcase_udp_lock); +#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ipct_clearcase_udp_lock) +#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ipct_clearcase_udp_lock) + +#include + +/* For future conections clearcase, using client's cache bindings + * I'll use ip_conntrack_lock to lock these lists */ + +LIST_HEAD(request_p_list_udp); + + +static void delete_request_p(unsigned long request_p_ul) +{ + struct request_p *p = (void *)request_p_ul; + + WRITE_LOCK(&ipct_clearcase_udp_lock); + LIST_DELETE(&request_p_list_udp, p); + WRITE_UNLOCK(&ipct_clearcase_udp_lock); + kfree(p); + return; +} + + +static void req_cl(struct request_p * r) +{ + WRITE_LOCK(&ipct_clearcase_udp_lock); + del_timer(&r->timeout); + LIST_DELETE(&request_p_list_udp, r); + WRITE_UNLOCK(&ipct_clearcase_udp_lock); + kfree(r); + return; +} + + +static void clean_request(struct list_head *list) +{ + struct list_head *first = list->prev; + struct list_head *temp = list->next; + struct list_head *aux; + + if (list_empty(list)) + return; + + while (first != temp) { + aux = temp->next; + req_cl((struct request_p *)temp); + temp = aux; + } + req_cl((struct request_p *)temp); + return; +} + + +static void alloc_request_p(u_int32_t xid, u_int16_t proto, u_int32_t ip, + u_int16_t port) +{ + struct request_p *req_p; + + /* Verifies if entry already exists */ + WRITE_LOCK(&ipct_clearcase_udp_lock); + req_p = LIST_FIND(&request_p_list_udp, request_p_cmp, + struct request_p *, xid, ip, port); + + if (req_p) { + /* Refresh timeout */ + if (del_timer(&req_p->timeout)) { + req_p->timeout.expires = jiffies + EXP; + add_timer(&req_p->timeout); + } + WRITE_UNLOCK(&ipct_clearcase_udp_lock); + return; + + } + WRITE_UNLOCK(&ipct_clearcase_udp_lock); + + /* Allocate new request_p */ + req_p = (struct request_p *) kmalloc(sizeof(struct request_p), GFP_ATOMIC); + if (!req_p) { + DEBUGP("can't allocate request_p\n"); + return; + } + *req_p = ((struct request_p) {{ NULL, NULL }, xid, ip, port, proto, + { { NULL, NULL }, jiffies + EXP, (unsigned long)req_p, + NULL }}); + + /* Initialize timer */ + init_timer(&req_p->timeout); + req_p->timeout.function = delete_request_p; + add_timer(&req_p->timeout); + + /* Put in list */ + WRITE_LOCK(&ipct_clearcase_udp_lock); + list_prepend(&request_p_list_udp, req_p); + WRITE_UNLOCK(&ipct_clearcase_udp_lock); + return; + +} + + +static int check_clearcase_packet(const u_int32_t *data, + int dir, struct ip_conntrack *ct, + struct list_head request_p_list) +{ + struct request_p *req_p; + u_int32_t xid; + u_int32_t mtype; + struct ip_conntrack_expect expect, *exp = &expect; + + /* Translstion's buffer for XDR */ + u_int32_t port_buf; + + + /* Get XID and Message Type*/ + xid = *data; + data++; + mtype = ntohl(*data); + data--; + + /* This does sanity checking on clearcase payloads, + * and permits only the clearcase "get port" (3) + * in authorised procedures in client + * communications with the portmapper. + */ + + /* perform direction dependant clearcase work */ + if (dir == IP_CT_DIR_ORIGINAL) { + + data += 5; + + /* Get clearcase requestor */ + if (IXDR_GET_INT32(data) != 3) { + DEBUGP("clearcase packet contains an invalid (non \"get\") requestor. [skip] \n"); + return NF_ACCEPT; + } + DEBUGP("clearcase packet contains a \"get\" requestor. [cont]\n"); + + data++; + + /* Jump Credentials and Verfifier */ + data = data + IXDR_GET_INT32(data) + 2; + data = data + IXDR_GET_INT32(data) + 2; + + /* Get clearcase procedure */ + DEBUGP("clearcase packet contains procedure request [%u]. [cont]\n", + (unsigned int)IXDR_GET_INT32(data)); + + /* Get clearcase protocol and store against client parameters */ + data = data + 2; + alloc_request_p(xid, IXDR_GET_INT32(data), ct->tuplehash[dir].tuple.src.ip, + ct->tuplehash[dir].tuple.src.u.all); + + DEBUGP("allocated clearcase req_p for xid=%u %u.%u.%u.%u:%u\n", + ntohl(xid), + NIPQUAD(ct->tuplehash[dir].tuple.src.ip), + ntohs(ct->tuplehash[dir].tuple.src.u.all)); + + // DEBUGP("allocated clearcase request for protocol %u. [done]\n", + // (unsigned int)IXDR_GET_INT32(data)); + + } else { + + /* Check for returning packet's stored counterpart */ + req_p = LIST_FIND(&request_p_list_udp, request_p_cmp, + struct request_p *, xid, + ct->tuplehash[!dir].tuple.src.ip, + ct->tuplehash[!dir].tuple.src.u.tcp.port); + + // Next Connection will be TCP + req_p->proto=6; + + /* Drop unexpected packets */ + if (!req_p) { + DEBUGP("packet is not expected. [skip]\n"); + return NF_ACCEPT; + } + + /* Verifies if packet is really an clearcase reply packet */ + data++; + if (IXDR_GET_INT32(data) != 1) { + DEBUGP("packet is not a valid clearcase reply. [skip]\n"); + return NF_ACCEPT; + } + + /* Is status accept? */ + data++; + if (IXDR_GET_INT32(data)) { + DEBUGP("packet is not an clearcase accept. [skip]\n"); + return NF_ACCEPT; + } + + /* Get Verifier length. Jump verifier */ + data++; + data = data + IXDR_GET_INT32(data) + 2; + + /* Is accpet status "success"? */ + if (IXDR_GET_INT32(data)) { + DEBUGP("packet is not an clearcase accept status of success. [skip]\n"); + return NF_ACCEPT; + } + + /* Get server port number */ + //data++; + data += 10; + port_buf = (u_int16_t) IXDR_GET_INT32(data); + + /* If a packet has made it this far then it deserves an + * expectation ... if port == 0, then this service is + * not going to be registered. + */ + if (port_buf) { + DEBUGP("port found: %u\n", port_buf); + + memset(&expect, 0, sizeof(expect)); + + /* Watch out, Radioactive-Man! */ + exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; + exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; + exp->mask.src.ip = 0xffffffff; + exp->mask.dst.ip = 0xffffffff; + + DEBUGP("req_p->proto: %u\n",req_p->proto); + + switch (req_p->proto) { + case IPPROTO_UDP: + exp->tuple.src.u.udp.port = 0; + exp->tuple.dst.u.udp.port = htons(port_buf); + exp->tuple.dst.protonum = IPPROTO_UDP; + exp->mask.src.u.udp.port = 0; + exp->mask.dst.u.udp.port = htons(0xffff); + exp->mask.dst.protonum = 0xffff; + break; + + case IPPROTO_TCP: + exp->tuple.src.u.tcp.port = 0; + exp->tuple.dst.u.tcp.port = htons(port_buf); + exp->tuple.dst.protonum = IPPROTO_TCP; + exp->mask.src.u.tcp.port = 0; + exp->mask.dst.u.tcp.port = htons(0xffff); + exp->mask.dst.protonum = 0xffff; + break; + } + exp->expectfn = NULL; + + ip_conntrack_expect_related(ct, &expect); + + DEBUGP("expect related ip %u.%u.%u.%u:0-%u.%u.%u.%u:%u proto=%u\n", + NIPQUAD(exp->tuple.src.ip), + NIPQUAD(exp->tuple.dst.ip), + port_buf, req_p->proto); + + DEBUGP("expect related mask %u.%u.%u.%u:0-%u.%u.%u.%u:65535 proto=%u\n", + NIPQUAD(exp->mask.src.ip), + NIPQUAD(exp->mask.dst.ip), + exp->mask.dst.protonum); + + } + + req_cl(req_p); + + DEBUGP("packet evaluated. [expect]\n"); + return NF_ACCEPT; + } + + return NF_ACCEPT; + +} + + +/* clearcase UDP helper */ +static int help(const struct iphdr *iph, size_t len, + struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) +{ + struct udphdr *udph = (void *) iph + iph->ihl * 4; + const u_int32_t *data = (const u_int32_t *)udph + 2; + size_t udplen = len - iph->ihl * 4; + int dir = CTINFO2DIR(ctinfo); + int crp_ret; + + + /* Checksum */ + const u_int16_t *chsm = (const u_int16_t *)udph + 3; + + + DEBUGP("new packet to evaluate ..\n"); + + /* Not whole UDP header? */ + if (udplen < sizeof(struct udphdr)) { + DEBUGP("UDP header length is; udplen=%u ..\n", (unsigned) udplen); + DEBUGP("packet does not contain a complete UDP header. [skip]\n"); + return NF_ACCEPT; + } + + /* FIXME: Source route IP option packets --RR */ + if (*chsm) { + if (csum_tcpudp_magic(iph->saddr, iph->daddr, udplen, IPPROTO_UDP, + csum_partial((char *)udph, udplen, 0))) { + DEBUGP("[note: failure to get past this error may indicate source routing]\n"); + DEBUGP("packet contains a bad checksum. [skip]\n"); + return NF_ACCEPT; + } + } + + /* perform direction dependant protocol work */ + if (dir == IP_CT_DIR_ORIGINAL) { + + DEBUGP("packet is from the initiator. [cont]\n"); + + /* Tests if packet len is ok */ + if ((udplen - sizeof(struct udphdr)) != 140) { + DEBUGP("packet length is not correct. [skip]\n"); + return NF_ACCEPT; + } + + } else { + + DEBUGP("packet is from the receiver. [cont]\n"); + + /* Until there's been traffic both ways, don't look in packets. */ + if (ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { + DEBUGP("connection tracking state is; ctinfo=%u ..\n", ctinfo); + DEBUGP("[note: failure to get past this error may indicate asymmetric routing]\n"); + DEBUGP("packet is not yet part of a two way stream. [skip]\n"); + return NF_ACCEPT; + } + + /* Tests if packet len is ok */ + if ((udplen - sizeof(struct udphdr)) != 64) { + DEBUGP("packet length is not correct. [skip]\n"); + return NF_ACCEPT; + } + + } + + /* Get to the data */ + /* udp *data == *correct */ + + /* Check the clearcase data */ + crp_ret = check_clearcase_packet(data, dir, ct, request_p_list_udp); + + return crp_ret; + +} + + +static struct ip_conntrack_helper clearcase_helpers[MAX_PORTS]; + +static void fini(void); + + +static int __init init(void) +{ + int port, ret; + static char name[10]; + + + /* If no port given, default to standard clearcase port */ + if (ports[0] == 0) + ports[0] = CLEARCASE_PORT; + + for (port = 0; (port < MAX_PORTS) && ports[port]; port++) { + memset(&clearcase_helpers[port], 0, sizeof(struct ip_conntrack_helper)); + + if (ports[port] == CLEARCASE_PORT) + sprintf(name, "clearcase"); + else + sprintf(name, "clearcase-%d", port); + + clearcase_helpers[port].name = name; + clearcase_helpers[port].me = THIS_MODULE; + clearcase_helpers[port].max_expected = 1; + clearcase_helpers[port].flags = IP_CT_HELPER_F_REUSE_EXPECT; + clearcase_helpers[port].timeout = 0; + + clearcase_helpers[port].tuple.dst.protonum = IPPROTO_UDP; + clearcase_helpers[port].mask.dst.protonum = 0xffff; + + /* clearcase can come from ports 0:65535 to ports[port] (111) */ + clearcase_helpers[port].tuple.src.u.udp.port = htons(ports[port]); + clearcase_helpers[port].mask.src.u.udp.port = htons(0xffff); + clearcase_helpers[port].mask.dst.u.udp.port = htons(0x0); + + clearcase_helpers[port].help = help; + + DEBUGP("registering helper for port #%d: %d/UDP\n", port, ports[port]); + DEBUGP("helper match ip %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", + NIPQUAD(clearcase_helpers[port].tuple.dst.ip), + ntohs(clearcase_helpers[port].tuple.dst.u.udp.port), + NIPQUAD(clearcase_helpers[port].tuple.src.ip), + ntohs(clearcase_helpers[port].tuple.src.u.udp.port)); + DEBUGP("helper match mask %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", + NIPQUAD(clearcase_helpers[port].mask.dst.ip), + ntohs(clearcase_helpers[port].mask.dst.u.udp.port), + NIPQUAD(clearcase_helpers[port].mask.src.ip), + ntohs(clearcase_helpers[port].mask.src.u.udp.port)); + + ret = ip_conntrack_helper_register(&clearcase_helpers[port]); + + if (ret) { + printk("ERROR registering port %d\n", + ports[port]); + fini(); + return -EBUSY; + } + ports_n_c++; + } + return 0; +} + + +/* This function is intentionally _NOT_ defined as __exit, because + * it is needed by the init function */ +static void fini(void) +{ + int port; + + DEBUGP("cleaning request list\n"); + clean_request(&request_p_list_udp); + + for (port = 0; (port < ports_n_c) && ports[port]; port++) { + DEBUGP("unregistering port %d\n", ports[port]); + ip_conntrack_helper_unregister(&clearcase_helpers[port]); + } +} + + +module_init(init); +module_exit(fini); + +struct module *ip_conntrack_clearcase_udp = THIS_MODULE; +EXPORT_SYMBOL(request_p_list_udp); +EXPORT_SYMBOL(ip_conntrack_clearcase_udp); +EXPORT_SYMBOL(ipct_clearcase_udp_lock); +