diff -Nru --exclude *.rej 2.4.4-pre6-dropped/include/linux/netfilter_ipv4/ip_conntrack.h 2.4.4-pre6-irc/include/linux/netfilter_ipv4/ip_conntrack.h
--- 2.4.4-pre6-dropped/include/linux/netfilter_ipv4/ip_conntrack.h	Fri Apr 27 01:50:12 2001
+++ 2.4.4-pre6-irc/include/linux/netfilter_ipv4/ip_conntrack.h	Fri Apr 27 02:00:05 2001
@@ -86,6 +86,10 @@
 
 #include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
 
+#if defined(CONFIG_IP_NF_IRC) || defined(CONFIG_IP_NF_IRC_MODULE)
+#include <linux/netfilter_ipv4/ip_conntrack_irc.h>
+#endif
+
 struct ip_conntrack
 {
 	/* Usage count in here is 1 for destruct timer, 1 per skb,
@@ -123,6 +127,7 @@
 
 	union {
 		struct ip_ct_ftp ct_ftp_info;
+		struct ip_ct_irc ct_irc_info;
 	} help;
 
 #ifdef CONFIG_IP_NF_NAT_NEEDED
diff -Nru --exclude *.rej 2.4.4-pre6-dropped/include/linux/netfilter_ipv4/ip_conntrack_irc.h 2.4.4-pre6-irc/include/linux/netfilter_ipv4/ip_conntrack_irc.h
--- 2.4.4-pre6-dropped/include/linux/netfilter_ipv4/ip_conntrack_irc.h	Wed Dec 31 21:00:00 1969
+++ 2.4.4-pre6-irc/include/linux/netfilter_ipv4/ip_conntrack_irc.h	Fri Apr 27 01:59:35 2001
@@ -0,0 +1,47 @@
+/* IRC extension for IP connection tracking.
+ * (C) 2000 by Harald Welte <laforge@gnumonks.org>
+ * based on RR's ip_conntrack_ftp.h
+ *
+ * ip_conntrack_irc.h,v 1.6 2000/11/07 18:26:42 laforge Exp
+ *
+ *      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.
+ *
+ *
+ */
+#ifndef _IP_CONNTRACK_IRC_H
+#define _IP_CONNTRACK_IRC_H
+
+#ifndef __KERNEL__
+#error Only in kernel.
+#endif
+
+#include <linux/netfilter_ipv4/lockhelp.h>
+
+#define IP_CONNTR_IRC	2
+
+struct dccproto {
+	char* match;
+	int matchlen;
+};
+
+/* Protects irc part of conntracks */
+DECLARE_LOCK_EXTERN(ip_irc_lock);
+
+/* We record seq number and length of irc ip/port text here: all in
+   host order. */
+struct ip_ct_irc
+{
+	/* This tells NAT that this is an IRC connection */
+	int is_irc;
+	/* sequence number where address part of DCC command begins */
+	u_int32_t seq;
+	/* 0 means not found yet */
+	u_int32_t len;
+	/* Port that was to be used */
+	u_int16_t port;
+};
+
+#endif /* _IP_CONNTRACK_IRC_H */
diff -Nru --exclude *.rej 2.4.4-pre6-dropped/net/ipv4/netfilter/ip_conntrack_irc.c 2.4.4-pre6-irc/net/ipv4/netfilter/ip_conntrack_irc.c
--- 2.4.4-pre6-dropped/net/ipv4/netfilter/ip_conntrack_irc.c	Wed Dec 31 21:00:00 1969
+++ 2.4.4-pre6-irc/net/ipv4/netfilter/ip_conntrack_irc.c	Fri Apr 27 01:59:35 2001
@@ -0,0 +1,276 @@
+/* IRC extension for IP connection tracking, Version 1.17
+ * (C) 2000 by Harald Welte <laforge@gnumonks.org>
+ * based on RR's ip_conntrack_ftp.c	
+ *
+ * ip_conntrack_irc.c,v 1.17 2001/04/23 05:21:22 laforge Exp
+ *
+ *      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_nat_irc.o ports=port1,port2,...port<MAX_PORTS>
+ *	
+ * 	please give the ports of all IRC servers You wish to connect to.
+ *	If You don't specify ports, the default will be port 6667
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/netfilter.h>
+#include <linux/ip.h>
+#include <net/checksum.h>
+#include <net/tcp.h>
+
+#include <linux/netfilter_ipv4/lockhelp.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+#include <linux/netfilter_ipv4/ip_conntrack_irc.h>
+
+#define MAX_PORTS 8
+static int ports[MAX_PORTS];
+static int ports_n_c = 0;
+
+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
+MODULE_DESCRIPTION("IRC (DCC) connection tracking module");
+#ifdef MODULE_PARM
+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
+MODULE_PARM_DESC(ports, "port numbers of IRC servers");
+#endif
+
+#define NUM_DCCPROTO 	5
+struct dccproto dccprotos[NUM_DCCPROTO] = {
+	{"SEND ", 5},
+	{"CHAT ", 5},
+	{"MOVE ", 5},
+	{"TSEND ", 6},
+	{"SCHAT ", 6}
+};
+#define MAXMATCHLEN	6
+
+DECLARE_LOCK(ip_irc_lock);
+struct module *ip_conntrack_irc = THIS_MODULE;
+
+#if 0
+#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
+					":" format, ## args)
+#else
+#define DEBUGP(format, args...)
+#endif
+
+int parse_dcc(char *data, char *data_end, u_int32_t * ip, u_int16_t * port,
+	      char **ad_beg_p, char **ad_end_p)
+/* tries to get the ip_addr and port out of a dcc command
+   return value: -1 on failure, 0 on success 
+	data		pointer to first byte of DCC command data
+	data_end	pointer to last byte of dcc command data
+	ip		returns parsed ip of dcc command
+	port		returns parsed port of dcc command
+	ad_beg_p	returns pointer to first byte of addr data
+	ad_end_p	returns pointer to last byte of addr data */
+{
+
+	/* at least 12: "AAAAAAAA P\1\n" */
+	while (*data++ != ' ')
+		if (data > data_end - 12)
+			return -1;
+
+	*ad_beg_p = data;
+	*ip = simple_strtoul(data, &data, 10);
+
+	/* skip blanks between ip and port */
+	while (*data == ' ')
+		data++;
+
+
+	*port = simple_strtoul(data, &data, 10);
+	*ad_end_p = data;
+
+	return 0;
+}
+
+
+/* FIXME: This should be in userspace.  Later. */
+static int help(const struct iphdr *iph, size_t len,
+		struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
+{
+	/* tcplen not negative guarenteed by ip_conntrack_tcp.c */
+	struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
+	const char *data = (const char *) tcph + tcph->doff * 4;
+	const char *_data = data;
+	char *data_limit;
+	u_int32_t tcplen = len - iph->ihl * 4;
+	u_int32_t datalen = tcplen - tcph->doff * 4;
+	int dir = CTINFO2DIR(ctinfo);
+	struct ip_conntrack_tuple t, mask;
+
+	u_int32_t dcc_ip;
+	u_int16_t dcc_port;
+	int i;
+	char *addr_beg_p, *addr_end_p;
+
+	struct ip_ct_irc *info = &ct->help.ct_irc_info;
+
+	memset(&mask, 0, sizeof(struct ip_conntrack_tuple));
+	mask.dst.u.tcp.port = 0xFFFF;
+	mask.dst.protonum = 0xFFFF;
+
+	DEBUGP("entered\n");
+	/* Can't track connections formed before we registered */
+	if (!info)
+		return NF_ACCEPT;
+
+	/* If packet is coming from IRC server */
+	if (dir == IP_CT_DIR_REPLY)
+		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("Conntrackinfo = %u\n", ctinfo);
+		return NF_ACCEPT;
+	}
+
+	/* Not whole TCP header? */
+	if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) {
+		DEBUGP("tcplen = %u\n", (unsigned) tcplen);
+		return NF_ACCEPT;
+	}
+
+	/* Checksum invalid?  Ignore. */
+	/* FIXME: Source route IP option packets --RR */
+	if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
+			 csum_partial((char *) tcph, tcplen, 0))) {
+		DEBUGP("bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
+		     tcph, tcplen, NIPQUAD(iph->saddr),
+		     NIPQUAD(iph->daddr));
+		return NF_ACCEPT;
+	}
+
+	data_limit = (char *) data + datalen;
+	while (data < (data_limit - (22 + MAXMATCHLEN))) {
+		if (memcmp(data, "\1DCC ", 5)) {
+			data++;
+			continue;
+		}
+
+		data += 5;
+
+		DEBUGP("DCC found in master %u.%u.%u.%u:%u %u.%u.%u.%u:%u...\n",
+			NIPQUAD(iph->saddr), ntohs(tcph->source),
+			NIPQUAD(iph->daddr), ntohs(tcph->dest));
+
+		for (i = 0; i < NUM_DCCPROTO; i++) {
+			if (memcmp(data, dccprotos[i].match,
+				   dccprotos[i].matchlen)) {
+				/* no match */
+				continue;
+			}
+
+			DEBUGP("DCC %s detected\n", dccprotos[i].match);
+			data += dccprotos[i].matchlen;
+			if (parse_dcc((char *) data, data_limit, &dcc_ip,
+				       &dcc_port, &addr_beg_p, &addr_end_p)) {
+				/* unable to parse */
+				DEBUGP("unable to parse dcc command\n");
+				continue;
+			}
+			DEBUGP("DCC bound ip/port: %u.%u.%u.%u:%u\n",
+				HIPQUAD(dcc_ip), dcc_port);
+
+			if (ct->tuplehash[dir].tuple.src.ip != htonl(dcc_ip)) {
+				if (net_ratelimit())
+					printk(KERN_WARNING
+						"Forged DCC command from "
+						"%u.%u.%u.%u: %u.%u.%u.%u:%u\n",
+				NIPQUAD(ct->tuplehash[dir].tuple.src.ip),
+						HIPQUAD(dcc_ip), dcc_port);
+
+				continue;
+			}
+
+			LOCK_BH(&ip_irc_lock);
+
+			/* save position of address in dcc string,
+			 * neccessary for NAT */
+			info->is_irc = IP_CONNTR_IRC;
+			DEBUGP("tcph->seq = %u\n", tcph->seq);
+			info->seq = ntohl(tcph->seq) + (addr_beg_p - _data);
+			info->len = (addr_end_p - addr_beg_p);
+			info->port = dcc_port;
+			DEBUGP("wrote info seq=%u (ofs=%u), len=%d\n",
+				info->seq, (addr_end_p - _data), info->len);
+
+			memset(&t, 0, sizeof(t));
+			t.src.ip = 0;
+			t.src.u.tcp.port = 0;
+			t.dst.ip = htonl(dcc_ip);
+			t.dst.u.tcp.port = htons(info->port);
+			t.dst.protonum = IPPROTO_TCP;
+
+			DEBUGP("expect_related %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n",
+				NIPQUAD(t.src.ip),
+				ntohs(t.src.u.tcp.port),
+				NIPQUAD(t.dst.ip),
+				ntohs(t.dst.u.tcp.port));
+
+			ip_conntrack_expect_related(ct, &t, &mask, NULL);
+			UNLOCK_BH(&ip_irc_lock);
+
+			return NF_ACCEPT;
+		} /* for .. NUM_DCCPROTO */
+	} /* while data < ... */
+
+	return NF_ACCEPT;
+}
+
+static struct ip_conntrack_helper irc_helpers[MAX_PORTS];
+
+static void fini(void);
+
+static int __init init(void)
+{
+	int i, ret;
+
+	/* If no port given, default to standard irc port */
+	if (ports[0] == 0)
+		ports[0] = 6667;
+
+	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
+		memset(&irc_helpers[i], 0,
+		       sizeof(struct ip_conntrack_helper));
+		irc_helpers[i].tuple.src.u.tcp.port = htons(ports[i]);
+		irc_helpers[i].tuple.dst.protonum = IPPROTO_TCP;
+		irc_helpers[i].mask.src.u.tcp.port = 0xFFFF;
+		irc_helpers[i].mask.dst.protonum = 0xFFFF;
+		irc_helpers[i].help = help;
+
+		DEBUGP("port #%d: %d\n", i, ports[i]);
+
+		ret = ip_conntrack_helper_register(&irc_helpers[i]);
+
+		if (ret) {
+			printk("ip_conntrack_irc: ERROR registering port %d\n",
+				ports[i]);
+			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 i;
+	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
+		DEBUGP("unregistering port %d\n",
+		       ports[i]);
+		ip_conntrack_helper_unregister(&irc_helpers[i]);
+	}
+}
+
+module_init(init);
+module_exit(fini);
diff -Nru --exclude *.rej 2.4.4-pre6-dropped/net/ipv4/netfilter/ip_nat_irc.c 2.4.4-pre6-irc/net/ipv4/netfilter/ip_nat_irc.c
--- 2.4.4-pre6-dropped/net/ipv4/netfilter/ip_nat_irc.c	Wed Dec 31 21:00:00 1969
+++ 2.4.4-pre6-irc/net/ipv4/netfilter/ip_nat_irc.c	Fri Apr 27 01:59:35 2001
@@ -0,0 +1,361 @@
+/* IRC extension for TCP NAT alteration.
+ * (C) 2000 by Harald Welte <laforge@gnumonks.org>
+ * based on a copy of RR's ip_nat_ftp.c
+ *
+ * ip_nat_irc.c,v 1.14 2001/04/23 05:21:22 laforge Exp
+ *
+ *      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_nat_irc.o ports=port1,port2,...port<MAX_PORTS>
+ *	
+ * 	please give the ports of all IRC servers You wish to connect to.
+ *	If You don't specify ports, the default will be port 6667
+ */
+
+#include <linux/module.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/kernel.h>
+#include <net/tcp.h>
+#include <linux/netfilter_ipv4/ip_nat.h>
+#include <linux/netfilter_ipv4/ip_nat_helper.h>
+#include <linux/netfilter_ipv4/ip_nat_rule.h>
+#include <linux/netfilter_ipv4/ip_conntrack_irc.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+#define MAX_PORTS 8
+static int ports[MAX_PORTS];
+static int ports_c = 0;
+
+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
+MODULE_DESCRIPTION("IRC (DCC) network address translation module");
+#ifdef MODULE_PARM
+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
+MODULE_PARM_DESC(ports, "port numbers of IRC servers");
+#endif
+
+/* protects irc part of conntracks */
+DECLARE_LOCK_EXTERN(ip_irc_lock);
+
+/* FIXME: Time out? --RR */
+
+static int
+irc_nat_expected(struct sk_buff **pskb,
+		 unsigned int hooknum,
+		 struct ip_conntrack *ct,
+		 struct ip_nat_info *info,
+		 struct ip_conntrack *master,
+		 struct ip_nat_info *masterinfo, unsigned int *verdict)
+{
+	struct ip_nat_multi_range mr;
+	u_int32_t newdstip, newsrcip, newip;
+	struct ip_ct_irc *ircinfo;
+
+	IP_NF_ASSERT(info);
+	IP_NF_ASSERT(master);
+	IP_NF_ASSERT(masterinfo);
+
+	IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
+
+	DEBUGP("nat_expected: We have a connection!\n");
+
+	/* Master must be an irc connection */
+	ircinfo = &master->help.ct_irc_info;
+	LOCK_BH(&ip_irc_lock);
+	if (ircinfo->is_irc != IP_CONNTR_IRC) {
+		UNLOCK_BH(&ip_irc_lock);
+		DEBUGP("nat_expected: master not irc\n");
+		return 0;
+	}
+
+	newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
+	newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
+	DEBUGP("nat_expected: DCC cmd. %u.%u.%u.%u->%u.%u.%u.%u\n",
+	       NIPQUAD(newsrcip), NIPQUAD(newdstip));
+
+	UNLOCK_BH(&ip_irc_lock);
+
+	if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
+		newip = newsrcip;
+	else
+		newip = newdstip;
+
+	DEBUGP("nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip));
+
+	mr.rangesize = 1;
+	/* We don't want to manip the per-protocol, just the IPs. */
+	mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
+	mr.range[0].min_ip = mr.range[0].max_ip = newip;
+
+	*verdict = ip_nat_setup_info(ct, &mr, hooknum);
+
+
+	return 1;
+}
+
+/* Grrr... SACK.  Fuck me even harder.  Don't want to fix it on the
+   fly, so blow it away. */
+static void delete_sack(struct sk_buff *skb, struct tcphdr *tcph)
+{
+	unsigned int i;
+	u_int8_t *opt = (u_int8_t *) tcph;
+
+	DEBUGP("Seeking SACKPERM in SYN packet (doff = %u).\n",
+	       tcph->doff * 4);
+	for (i = sizeof(struct tcphdr); i < tcph->doff * 4;) {
+		DEBUGP("%u ", opt[i]);
+		switch (opt[i]) {
+		case TCPOPT_NOP:
+		case TCPOPT_EOL:
+			i++;
+			break;
+
+		case TCPOPT_SACK_PERM:
+			goto found_opt;
+
+		default:
+			/* Worst that can happen: it will take us over. */
+			i += opt[i + 1] ? : 1;
+		}
+	}
+	DEBUGP("\n");
+	return;
+
+      found_opt:
+	DEBUGP("\n");
+	DEBUGP("Found SACKPERM at offset %u.\n", i);
+
+	/* Must be within TCP header, and valid SACK perm. */
+	if (i + opt[i + 1] <= tcph->doff * 4 && opt[i + 1] == 2) {
+		/* Replace with NOPs. */
+		tcph->check
+		    =
+		    ip_nat_cheat_check(*((u_int16_t *) (opt + i)) ^ 0xFFFF,
+				       0, tcph->check);
+		opt[i] = opt[i + 1] = 0;
+	} else
+		DEBUGP("Something wrong with SACK_PERM.\n");
+}
+
+static int irc_data_fixup(const struct ip_ct_irc *ct_irc_info,
+			  struct ip_conntrack *ct,
+			  unsigned int datalen,
+			  struct sk_buff **pskb,
+			  enum ip_conntrack_info ctinfo)
+{
+	u_int32_t newip;
+	struct ip_conntrack_tuple t;
+	struct iphdr *iph = (*pskb)->nh.iph;
+	struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
+	int port;
+
+	/* "4294967296 65635 " */
+	char buffer[18];
+
+	MUST_BE_LOCKED(&ip_irc_lock);
+
+	DEBUGP("IRC_NAT: info (seq %u + %u) packet(seq %u + %u)\n",
+	       ct_irc_info->seq, ct_irc_info->len,
+	       ntohl(tcph->seq), datalen);
+
+	newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
+
+	/* Alter conntrack's expectations. */
+
+	/* We can read expect here without conntrack lock, since it's
+	   only set in ip_conntrack_irc, with ip_irc_lock held
+	   writable */
+
+	t = ct->expected.tuple;
+	t.dst.ip = newip;
+	for (port = ct_irc_info->port; port != 0; port++) {
+		t.dst.u.tcp.port = htons(port);
+		if (ip_conntrack_expect_related(ct, &t,
+						&ct->expected.mask,
+						NULL) == 0) {
+			DEBUGP("using port %d", port);
+			break;
+		}
+
+	}
+	if (port == 0)
+		return 0;
+
+	/*      strlen("\1DCC CHAT chat AAAAAAAA P\1\n")=27
+	 *      strlen("\1DCC SCHAT chat AAAAAAAA P\1\n")=28
+	 *      strlen("\1DCC SEND F AAAAAAAA P S\1\n")=26
+	 *      strlen("\1DCC MOVE F AAAAAAAA P S\1\n")=26
+	 *      strlen("\1DCC TSEND F AAAAAAAA P S\1\n")=27
+	 *              AAAAAAAAA: bound addr (1.0.0.0==16777216, min 8 digits,
+	 *                      255.255.255.255==4294967296, 10 digits)
+	 *              P:         bound port (min 1 d, max 5d (65635))
+	 *              F:         filename   (min 1 d )
+	 *              S:         size       (min 1 d )
+	 *              0x01, \n:  terminators
+	 */
+
+	sprintf(buffer, "%u %u", ntohl(newip), port);
+	DEBUGP("ip_nat_irc: Inserting '%s' == %u.%u.%u.%u, port %u\n",
+	       buffer, NIPQUAD(newip), port);
+
+	return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, 
+					ct_irc_info->seq - ntohl(tcph->seq),
+					ct_irc_info->len, buffer, 
+					strlen(buffer));
+}
+
+static unsigned int help(struct ip_conntrack *ct,
+			 struct ip_nat_info *info,
+			 enum ip_conntrack_info ctinfo,
+			 unsigned int hooknum, struct sk_buff **pskb)
+{
+	struct iphdr *iph = (*pskb)->nh.iph;
+	struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
+	unsigned int datalen;
+	int dir;
+	int score;
+	struct ip_ct_irc *ct_irc_info = &ct->help.ct_irc_info;
+
+	/* Delete SACK_OK on initial TCP SYNs. */
+	if (tcph->syn && !tcph->ack)
+		delete_sack(*pskb, tcph);
+
+	/* Only mangle things once: original direction in POST_ROUTING
+	   and reply direction on PRE_ROUTING. */
+	dir = CTINFO2DIR(ctinfo);
+	if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
+	      || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) {
+		DEBUGP("nat_irc: Not touching dir %s at hook %s\n",
+		       dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
+		       hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
+		       : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
+		       : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
+		return NF_ACCEPT;
+	}
+	DEBUGP("got beyond not touching\n");
+
+	datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4;
+	score = 0;
+	LOCK_BH(&ip_irc_lock);
+	if (ct_irc_info->len) {
+		DEBUGP("got beyond ct_irc_info->len\n");
+
+		/* If it's in the right range... */
+		score += between(ct_irc_info->seq, ntohl(tcph->seq),
+				 ntohl(tcph->seq) + datalen);
+		score += between(ct_irc_info->seq + ct_irc_info->len,
+				 ntohl(tcph->seq),
+				 ntohl(tcph->seq) + datalen);
+		if (score == 1) {
+			/* Half a match?  This means a partial retransmisison.
+			   It's a cracker being funky. */
+			if (net_ratelimit()) {
+				printk
+				    ("IRC_NAT: partial packet %u/%u in %u/%u\n",
+				     ct_irc_info->seq, ct_irc_info->len,
+				     ntohl(tcph->seq),
+				     ntohl(tcph->seq) + datalen);
+			}
+			UNLOCK_BH(&ip_irc_lock);
+			return NF_DROP;
+		} else if (score == 2) {
+			DEBUGP("IRC_NAT: score=2, calling fixup\n");
+			if (!irc_data_fixup(ct_irc_info, ct, datalen,
+					    pskb, ctinfo)) {
+				UNLOCK_BH(&ip_irc_lock);
+				return NF_DROP;
+			}
+			/* skb may have been reallocated */
+			iph = (*pskb)->nh.iph;
+			tcph = (void *) iph + iph->ihl * 4;
+		}
+	}
+
+	UNLOCK_BH(&ip_irc_lock);
+
+	ip_nat_seq_adjust(*pskb, ct, ctinfo);
+
+	return NF_ACCEPT;
+}
+
+static struct ip_nat_helper ip_nat_irc_helpers[MAX_PORTS];
+static char ip_nih_names[MAX_PORTS][6];
+
+static struct ip_nat_expect irc_expect
+    = { {NULL, NULL}, irc_nat_expected };
+
+
+/* This function is intentionally _NOT_ defined as  __exit, because
+ * it is needed by init() */
+static void fini(void)
+{
+	int i;
+
+	for (i = 0; i < ports_c; i++) {
+		DEBUGP("ip_nat_irc: unregistering helper for port %d\n",
+		       ports[i]);
+		ip_nat_helper_unregister(&ip_nat_irc_helpers[i]);
+	}
+	ip_nat_expect_unregister(&irc_expect);
+}
+static int __init init(void)
+{
+	int ret;
+	int i;
+	struct ip_nat_helper *hlpr;
+	char *tmpname;
+
+	ret = ip_nat_expect_register(&irc_expect);
+	if (ret == 0) {
+
+		if (ports[0] == 0) {
+			ports[0] = 6667;
+		}
+
+		for (i = 0; (i < MAX_PORTS) && ports[i] != 0; i++) {
+			hlpr = &ip_nat_irc_helpers[i];
+			memset(hlpr, 0,
+			       sizeof(struct ip_nat_helper));
+
+			hlpr->tuple.dst.protonum = IPPROTO_TCP;
+			hlpr->tuple.src.u.tcp.port = htons(ports[i]);
+			hlpr->mask.src.u.tcp.port = 0xFFFF;
+			hlpr->mask.dst.protonum = 0xFFFF;
+			hlpr->help = help;
+
+			tmpname = &ip_nih_names[i][0];
+			sprintf(tmpname, "irc%2.2d", i);
+
+			hlpr->name = tmpname;
+			DEBUGP
+			    ("ip_nat_irc: Trying to register helper for port %d: name %s\n",
+			     ports[i], hlpr->name);
+			ret = ip_nat_helper_register(hlpr);
+
+			if (ret) {
+				printk
+				    ("ip_nat_irc: error registering helper for port %d\n",
+				     ports[i]);
+				fini();
+				return -EBUSY;
+			}
+			ports_c++;
+		}
+	}
+	return ret;
+}
+
+
+module_init(init);
+module_exit(fini);
diff -Nru linux-2.4.4-irctest/net/ipv4/netfilter/ip_conntrack_ftp.c linux-2.4.4-irc+ftp/net/ipv4/netfilter/ip_conntrack_ftp.c
--- linux-2.4.4-irctest/net/ipv4/netfilter/ip_conntrack_ftp.c	Sun Apr 29 03:29:36 2001
+++ linux-2.4.4-irc+ftp/net/ipv4/netfilter/ip_conntrack_ftp.c	Wed May  2 20:10:51 2001
@@ -335,7 +335,7 @@
 	LOCK_BH(&ip_ftp_lock);
 	if (htonl((array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3])
 	    == ct->tuplehash[dir].tuple.src.ip) {
-		info->is_ftp = 1;
+		info->is_ftp = 21;
 		info->seq = ntohl(tcph->seq) + matchoff;
 		info->len = matchlen;
 		info->ftptype = search[i].ftptype;
diff -Nru linux-2.4.4-irctest/net/ipv4/netfilter/ip_nat_ftp.c linux-2.4.4-irc+ftp/net/ipv4/netfilter/ip_nat_ftp.c
--- linux-2.4.4-irctest/net/ipv4/netfilter/ip_nat_ftp.c	Wed May  2 20:00:50 2001
+++ linux-2.4.4-irc+ftp/net/ipv4/netfilter/ip_nat_ftp.c	Wed May  2 20:11:24 2001
@@ -52,7 +52,7 @@
 	ftpinfo = &master->help.ct_ftp_info;
 
 	LOCK_BH(&ip_ftp_lock);
-	if (!ftpinfo->is_ftp) {
+	if (ftpinfo->is_ftp != 21) {
 		UNLOCK_BH(&ip_ftp_lock);
 		DEBUGP("nat_expected: master not ftp\n");
 		return 0;
