diff -urN -X /tmp/fileoREb5i --minimal linux-2.4.0-test8-1/include/linux/netfilter_ipv4/ip_pool.h tmp2/include/linux/netfilter_ipv4/ip_pool.h
--- linux-2.4.0-test8-1/include/linux/netfilter_ipv4/ip_pool.h	Thu Jan  1 10:00:00 1970
+++ tmp2/include/linux/netfilter_ipv4/ip_pool.h	Wed Aug 30 19:26:03 2000
@@ -0,0 +1,64 @@
+#ifndef _IP_POOL_H
+#define _IP_POOL_H
+
+/***************************************************************************/
+/*  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.					   */
+/*									   */
+/*  This program is distributed in the hope that it will be useful,	   */
+/*  but WITHOUT ANY WARRANTY; without even the implied warranty of	   */
+/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the	   */
+/*  GNU General Public License for more details.			   */
+/*									   */
+/*  You should have received a copy of the GNU General Public License	   */
+/*  along with this program; if not, write to the Free Software	       	   */
+/*  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/
+/***************************************************************************/
+
+/* A sockopt of such quality has hardly ever been seen before on the open
+ * market!  This little beauty, hardly ever used: above 64, so it's
+ * traditionally used for firewalling, not touched (even once!) by the
+ * 2.0, 2.2 and 2.4 kernels!
+ *
+ * Comes with its own certificate of authenticity, valid anywhere in the
+ * Free world!
+ *
+ * Rusty, 19.4.2000
+ */
+#define SO_IP_POOL 81
+
+typedef int ip_pool_t;			/* pool index */
+#define IP_POOL_NONE	((ip_pool_t)-1)
+
+struct ip_pool_request {
+	int op;
+	ip_pool_t index;
+	u_int32_t addr;
+	u_int32_t addr2;
+};
+
+/* NOTE: I deliberately break the first cut ippool utility. Nobody uses it. */
+
+#define IP_POOL_BAD001		0x00000010
+
+#define IP_POOL_FLUSH		0x00000011	/* req.index, no arguments */
+#define IP_POOL_INIT		0x00000012	/* from addr to addr2 incl. */
+#define IP_POOL_DESTROY		0x00000013	/* req.index, no arguments */
+#define IP_POOL_ADD_ADDR	0x00000014	/* add addr to pool */
+#define IP_POOL_DEL_ADDR	0x00000015	/* del addr from pool */
+#define IP_POOL_HIGH_NR		0x00000016	/* result in req.index */
+#define IP_POOL_LOOKUP		0x00000017	/* result in addr and addr2 */
+#define IP_POOL_USAGE		0x00000018	/* result in addr */
+#define IP_POOL_TEST_ADDR	0x00000019	/* result (0/1) returned */
+
+#ifdef __KERNEL__
+
+/* NOTE: ip_pool_match() and ip_pool_mod() expect ADDR to be host byte order */
+extern int ip_pool_match(ip_pool_t pool, u_int32_t addr);
+extern int ip_pool_mod(ip_pool_t pool, u_int32_t addr, int isdel);
+
+#endif
+
+#endif /*_IP_POOL_H*/
diff -urN -X /tmp/fileoREb5i --minimal linux-2.4.0-test8-1/include/linux/netfilter_ipv4/ipt_pool.h tmp2/include/linux/netfilter_ipv4/ipt_pool.h
--- linux-2.4.0-test8-1/include/linux/netfilter_ipv4/ipt_pool.h	Thu Jan  1 10:00:00 1970
+++ tmp2/include/linux/netfilter_ipv4/ipt_pool.h	Wed Aug 30 19:26:03 2000
@@ -0,0 +1,25 @@
+#ifndef _IPT_POOL_H
+#define _IPT_POOL_H
+
+#include <linux/netfilter_ipv4/ip_pool.h>
+
+#define IPT_POOL_INV_SRC	0x00000001
+#define IPT_POOL_INV_DST	0x00000002
+#define IPT_POOL_DEL_SRC	0x00000004
+#define IPT_POOL_DEL_DST	0x00000008
+#define IPT_POOL_INV_MOD_SRC	0x00000010
+#define IPT_POOL_INV_MOD_DST	0x00000020
+#define IPT_POOL_MOD_SRC_ACCEPT	0x00000040
+#define IPT_POOL_MOD_DST_ACCEPT	0x00000080
+#define IPT_POOL_MOD_SRC_DROP	0x00000100
+#define IPT_POOL_MOD_DST_DROP	0x00000200
+
+/* match info */
+struct ipt_pool_info
+{
+	ip_pool_t src;
+	ip_pool_t dst;
+	unsigned flags;
+};
+
+#endif /*_IPT_POOL_H*/
diff -urN -X /tmp/fileoREb5i --minimal linux-2.4.0-test8-1/net/ipv4/netfilter/ip_pool.c tmp2/net/ipv4/netfilter/ip_pool.c
--- linux-2.4.0-test8-1/net/ipv4/netfilter/ip_pool.c	Thu Jan  1 10:00:00 1970
+++ tmp2/net/ipv4/netfilter/ip_pool.c	Wed Aug 30 19:26:03 2000
@@ -0,0 +1,332 @@
+/* Kernel module for IP pool management */
+
+#include <linux/module.h>
+#include <linux/ip.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ip_pool.h>
+#include <linux/errno.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+
+#if 0
+#define DP printk
+#else
+#define DP(format, args...)
+#endif
+
+MODULE_LICENSE("GPL");
+
+#define NR_POOL 16
+static int nr_pool = NR_POOL;/* overwrite this when loading module */
+
+struct ip_pool {
+	u_int32_t first_ip;	/* host byte order, included in range */
+	u_int32_t last_ip;	/* host byte order, included in range */
+	void *members;		/* the bitmap proper */
+	int nr_use;		/* total nr. of tests through this */
+	int nr_match;		/* total nr. of matches through this */
+	rwlock_t lock;
+};
+
+static struct ip_pool *POOL;
+
+static inline struct ip_pool *lookup(ip_pool_t index)
+{
+	if (index < 0 || index >= nr_pool) {
+		DP("ip_pool:lookup: bad index %d\n", index);
+		return 0;
+	}
+	return POOL+index;
+}
+
+int ip_pool_match(ip_pool_t index, u_int32_t addr)
+{
+        struct ip_pool *pool = lookup(index);
+	int res = 0;
+
+	if (!pool || !pool->members)
+		return 0;
+	read_lock_bh(&pool->lock);
+	if (pool->members) {
+		if (addr >= pool->first_ip && addr <= pool->last_ip) {
+			addr -= pool->first_ip;
+			if (test_bit(addr, pool->members)) {
+				res = 1;
+#ifdef CONFIG_IP_POOL_STATISTICS
+				pool->nr_match++;
+#endif
+			}
+		}
+#ifdef CONFIG_IP_POOL_STATISTICS
+		pool->nr_use++;
+#endif
+	}
+	read_unlock_bh(&pool->lock);
+	return res;
+}
+
+static int pool_change(ip_pool_t index, u_int32_t addr, int isdel)
+{
+	struct ip_pool *pool;
+	int res = -1;
+
+	pool = lookup(index);
+	if (    !pool || !pool->members
+	     || addr < pool->first_ip || addr > pool->last_ip)
+		return -1;
+	read_lock_bh(&pool->lock);
+	if (pool->members && addr >= pool->first_ip && addr <= pool->last_ip) {
+		addr -= pool->first_ip;
+		res = isdel
+			? (0 != test_and_clear_bit(addr, pool->members))
+			: (0 != test_and_set_bit(addr, pool->members));
+	}
+	read_unlock_bh(&pool->lock);
+	return res;
+}
+
+int ip_pool_mod(ip_pool_t index, u_int32_t addr, int isdel)
+{
+	int res = pool_change(index,addr,isdel);
+
+	if (!isdel) res = !res;
+	return res;
+}
+
+static inline int bitmap_bytes(u_int32_t a, u_int32_t b)
+{
+	return 4*((((b-a+8)/8)+3)/4);
+}
+
+static inline int poolbytes(ip_pool_t index)
+{
+	struct ip_pool *pool = lookup(index);
+
+	return pool ? bitmap_bytes(pool->first_ip, pool->last_ip) : 0;
+}
+
+static int setpool(
+	struct sock *sk,
+	int optval,
+	void *user,
+	unsigned int len
+) {
+	struct ip_pool_request req;
+
+	DP("ip_pool:setpool: optval=%d, user=%p, len=%d\n", optval, user, len);
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+	if (optval != SO_IP_POOL)
+		return -EBADF;
+	if (len != sizeof(req))
+		return -EINVAL;
+	if (copy_from_user(&req, user, sizeof(req)) != 0)
+		return -EFAULT;
+	printk("obsolete op - upgrade your ippool(8) utility.\n");
+	return -EINVAL;
+}
+
+static int getpool(
+	struct sock *sk,
+	int optval,
+	void *user,
+	int *len
+) {
+	struct ip_pool_request req;
+	struct ip_pool *pool;
+	ip_pool_t i;
+	int newbytes;
+	void *newmembers;
+	int res;
+
+	DP("ip_pool:getpool: optval=%d, user=%p\n", optval, user);
+	if (!capable(CAP_NET_ADMIN))
+		return -EINVAL;
+	if (optval != SO_IP_POOL)
+		return -EINVAL;
+	if (*len != sizeof(req)) {
+		return -EFAULT;
+	}
+	if (copy_from_user(&req, user, sizeof(req)) != 0)
+		return -EFAULT;
+	DP("ip_pool:getpool op=%d, index=%d\n", req.op, req.index);
+	if (req.op < IP_POOL_BAD001) {
+		printk("obsolete op - upgrade your ippool(8) utility.\n");
+		return -EFAULT;
+	}
+	switch(req.op) {
+	case IP_POOL_HIGH_NR:
+		DP("ip_pool HIGH_NR\n");
+		req.index = IP_POOL_NONE;
+		for (i=0; i<nr_pool; i++)
+			if (POOL[i].members)
+				req.index = i;
+		return copy_to_user(user, &req, sizeof(req));
+	case IP_POOL_LOOKUP:
+		DP("ip_pool LOOKUP\n");
+		pool = lookup(req.index);
+		if (!pool)
+			return -EINVAL;
+		if (!pool->members)
+			return -EBADF;
+		req.addr = htonl(pool->first_ip);
+		req.addr2 = htonl(pool->last_ip);
+		return copy_to_user(user, &req, sizeof(req));
+	case IP_POOL_USAGE:
+		DP("ip_pool USE\n");
+		pool = lookup(req.index);
+		if (!pool)
+			return -EINVAL;
+		if (!pool->members)
+			return -EBADF;
+		req.addr = pool->nr_use;
+		req.addr2 = pool->nr_match;
+		return copy_to_user(user, &req, sizeof(req));
+	case IP_POOL_TEST_ADDR:
+		DP("ip_pool TEST 0x%08x\n", req.addr);
+		pool = lookup(req.index);
+		if (!pool)
+			return -EINVAL;
+		res = 0;
+		read_lock_bh(&pool->lock);
+		if (!pool->members) {
+			DP("ip_pool TEST_ADDR no members in pool\n");
+			res = -EBADF;
+			goto unlock_and_return_res;
+		}
+		req.addr = ntohl(req.addr);
+		if (req.addr < pool->first_ip) {
+			DP("ip_pool TEST_ADDR address < pool bounds\n");
+			res = -ERANGE;
+			goto unlock_and_return_res;
+		}
+		if (req.addr > pool->last_ip) {
+			DP("ip_pool TEST_ADDR address > pool bounds\n");
+			res = -ERANGE;
+			goto unlock_and_return_res;
+		}
+		req.addr = (0 != test_bit((req.addr - pool->first_ip),
+					pool->members));
+		read_unlock_bh(&pool->lock);
+		return copy_to_user(user, &req, sizeof(req));
+	case IP_POOL_FLUSH:
+		DP("ip_pool FLUSH not yet implemented.\n");
+		return -EBUSY;
+	case IP_POOL_DESTROY:
+		DP("ip_pool DESTROY not yet implemented.\n");
+		return -EBUSY;
+	case IP_POOL_INIT:
+		DP("ip_pool INIT 0x%08x-0x%08x\n", req.addr, req.addr2);
+		pool = lookup(req.index);
+		if (!pool)
+			return -EINVAL;
+		req.addr = ntohl(req.addr);
+		req.addr2 = ntohl(req.addr2);
+		if (req.addr > req.addr2) {
+			DP("ip_pool INIT bad ip range\n");
+			return -EINVAL;
+		}
+		newbytes = bitmap_bytes(req.addr, req.addr2);
+		newmembers = kmalloc(newbytes, GFP_KERNEL);
+		if (!newmembers) {
+			DP("ip_pool INIT out of mem for %d bytes\n", newbytes);
+			return -ENOMEM;
+		}
+		memset(newmembers, 0, newbytes);
+		write_lock_bh(&pool->lock);
+		if (pool->members) {
+			DP("ip_pool INIT pool %d exists\n", req.index);
+			kfree(newmembers);
+			res = -EBUSY;
+			goto unlock_and_return_res;
+		}
+		pool->first_ip = req.addr;
+		pool->last_ip = req.addr2;
+		pool->nr_use = 0;
+		pool->nr_match = 0;
+		pool->members = newmembers;
+		write_unlock_bh(&pool->lock);
+		return 0;
+	case IP_POOL_ADD_ADDR:
+		DP("ip_pool ADD_ADDR 0x%08x\n", req.addr);
+		req.addr = pool_change(req.index, ntohl(req.addr), 0);
+		return copy_to_user(user, &req, sizeof(req));
+	case IP_POOL_DEL_ADDR:
+		DP("ip_pool DEL_ADDR 0x%08x\n", req.addr);
+		req.addr = pool_change(req.index, ntohl(req.addr), 1);
+		return copy_to_user(user, &req, sizeof(req));
+	default:
+		DP("ip_pool:getpool bad op %d\n", req.op);
+		return -EINVAL;
+	}
+	return -EINVAL;
+
+unlock_and_return_res:
+	if (pool)
+		read_unlock_bh(&pool->lock);
+	return res;
+}
+
+static struct nf_sockopt_ops so_pool
+= { { NULL, NULL }, PF_INET,
+    SO_IP_POOL, SO_IP_POOL+1, &setpool,
+    SO_IP_POOL, SO_IP_POOL+1, &getpool,
+    0, NULL };
+
+MODULE_PARM(nr_pool, "i");
+
+static int __init init(void)
+{
+	ip_pool_t i;
+	int res;
+
+	if (nr_pool < 1) {
+		printk("ip_pool module init: bad nr_pool %d\n", nr_pool);
+		return -EINVAL;
+	}
+	POOL = kmalloc(nr_pool * sizeof(*POOL), GFP_KERNEL);
+	if (!POOL) {
+		printk("ip_pool module init: out of memory for nr_pool %d\n",
+			nr_pool);
+		return -ENOMEM;
+	}
+	for (i=0; i<nr_pool; i++) {
+		POOL[i].first_ip = 0;
+		POOL[i].last_ip = 0;
+		POOL[i].members = 0;
+		POOL[i].nr_use = 0;
+		POOL[i].nr_match = 0;
+		POOL[i].lock = RW_LOCK_UNLOCKED;
+	}
+	res = nf_register_sockopt(&so_pool);
+	DP("ip_pool:init %d pools, result %d\n", nr_pool, res);
+	if (res != 0) {
+		kfree(POOL);
+		POOL = 0;
+	}
+	return res;
+}
+
+static void __exit fini(void)
+{
+	ip_pool_t i;
+
+	DP("ip_pool:fini BYEBYE\n");
+	nf_unregister_sockopt(&so_pool);
+	for (i=0; i<nr_pool; i++) {
+		if (POOL[i].members) {
+			kfree(POOL[i].members);
+			POOL[i].members = 0;
+		}
+	}
+	kfree(POOL);
+	POOL = 0;
+	DP("ip_pool:fini these are the famous last words\n");
+	return;
+}
+
+module_init(init);
+module_exit(fini);
diff -urN -X /tmp/fileoREb5i --minimal linux-2.4.0-test8-1/net/ipv4/netfilter/ipt_pool.c tmp2/net/ipv4/netfilter/ipt_pool.c
--- linux-2.4.0-test8-1/net/ipv4/netfilter/ipt_pool.c	Thu Jan  1 10:00:00 1970
+++ tmp2/net/ipv4/netfilter/ipt_pool.c	Wed Aug 30 19:27:05 2000
@@ -0,0 +1,71 @@
+/* Kernel module to match an IP address pool. */
+
+#include <linux/module.h>
+#include <linux/ip.h>
+#include <linux/skbuff.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ip_pool.h>
+#include <linux/netfilter_ipv4/ipt_pool.h>
+
+static inline int match_pool(
+	ip_pool_t index,
+	__u32 addr,
+	int inv
+) {
+	if (ip_pool_match(index, ntohl(addr)))
+		inv = !inv;
+	return inv;
+}
+
+static int match(
+	const struct sk_buff *skb,
+	const struct net_device *in,
+	const struct net_device *out,
+	const void *matchinfo,
+	int offset,
+	const void *hdr,
+	u_int16_t datalen,
+	int *hotdrop
+) {
+	const struct ipt_pool_info *info = matchinfo;
+	const struct iphdr *iph = skb->nh.iph;
+
+	if (info->src != IP_POOL_NONE && !match_pool(info->src, iph->saddr,
+						info->flags&IPT_POOL_INV_SRC))
+		return 0;
+
+	if (info->dst != IP_POOL_NONE && !match_pool(info->dst, iph->daddr,
+						info->flags&IPT_POOL_INV_DST))
+		return 0;
+
+	return 1;
+}
+
+static int checkentry(
+	const char *tablename,
+	const struct ipt_ip *ip,
+	void *matchinfo,
+	unsigned int matchsize,
+	unsigned int hook_mask
+) {
+	if (matchsize != IPT_ALIGN(sizeof(struct ipt_pool_info)))
+		return 0;
+	return 1;
+}
+
+static struct ipt_match pool_match
+= { { NULL, NULL }, "pool", &match, &checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	return ipt_register_match(&pool_match);
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_match(&pool_match);
+}
+
+module_init(init);
+module_exit(fini);
diff -urN -X /tmp/fileoREb5i --minimal linux-2.4.0-test8-1/net/ipv4/netfilter/ipt_POOL.c tmp2/net/ipv4/netfilter/ipt_POOL.c
--- linux-2.4.0-test8-1/net/ipv4/netfilter/ipt_POOL.c	Thu Jan  1 10:00:00 1970
+++ tmp2/net/ipv4/netfilter/ipt_POOL.c	Wed Aug 30 19:29:16 2000
@@ -0,0 +1,116 @@
+/* ipt_POOL.c - netfilter target to manipulate IP pools
+ *
+ * This target can be used almost everywhere. It acts on some specified
+ * IP pool, adding or deleting some IP address in the pool. The address
+ * can be either the source (--addsrc, --delsrc), or destination (--add/deldst)
+ * of the packet under inspection.
+ *
+ * The target normally returns IPT_CONTINUE.
+ */
+
+#include <linux/types.h>
+#include <linux/ip.h>
+#include <linux/timer.h>
+#include <linux/module.h>
+#include <linux/netfilter.h>
+#include <linux/netdevice.h>
+#include <linux/if.h>
+#include <linux/inetdevice.h>
+#include <net/protocol.h>
+#include <net/checksum.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv4/ip_nat_rule.h>
+#include <linux/netfilter_ipv4/ipt_pool.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+/*** NOTE NOTE NOTE NOTE ***
+**
+** By sheer luck, I get away with using the "struct ipt_pool_info", as defined
+** in <linux/netfilter_ipv4/ipt_pool.h>, both as the match and target info.
+** Here, in the target implementation, ipt_pool_info.src, if not IP_POOL_NONE,
+** is modified for the source IP address of the packet under inspection.
+** The same way, the ipt_pool_info.dst pool is modified for the destination.
+**
+** The address is added to the pool normally. However, if IPT_POOL_DEL_dir
+** flag is set in ipt_pool_info.flags, the address is deleted from the pool.
+**
+** If a modification was done to the pool, we possibly return ACCEPT or DROP,
+** if the right IPT_POOL_MOD_dir_ACCEPT or _MOD_dir_DROP flags are set.
+** The IPT_POOL_INV_MOD_dir flag inverts the sense of the check (i.e. the
+** ACCEPT and DROP flags are evaluated when the pool was not modified.)
+*/
+
+static int
+do_check(const char *tablename,
+	       const struct ipt_entry *e,
+	       void *targinfo,
+	       unsigned int targinfosize,
+	       unsigned int hook_mask)
+{
+	const struct ipt_pool_info *ipi = targinfo;
+
+	if (targinfosize != IPT_ALIGN(sizeof(*ipi))) {
+		DEBUGP("POOL_check: size %u.\n", targinfosize);
+		return 0;
+	}
+	DEBUGP("ipt_POOL:do_check(%d,%d,%d)\n",ipi->src,ipi->dst,ipi->flags);
+	return 1;
+}
+
+static unsigned int
+do_target(struct sk_buff **pskb,
+		unsigned int hooknum,
+		const struct net_device *in,
+		const struct net_device *out,
+		const void *targinfo,
+		void *userinfo)
+{
+	const struct ipt_pool_info *ipi = targinfo;
+	int modified;
+	unsigned int verdict = IPT_CONTINUE;
+
+	if (ipi->src != IP_POOL_NONE) {
+		modified = ip_pool_mod(ipi->src, ntohl((*pskb)->nh.iph->saddr),
+					ipi->flags & IPT_POOL_DEL_SRC);
+		if (!!modified ^ !!(ipi->flags & IPT_POOL_INV_MOD_SRC)) {
+			if (ipi->flags & IPT_POOL_MOD_SRC_ACCEPT)
+				verdict = NF_ACCEPT;
+			else if (ipi->flags & IPT_POOL_MOD_SRC_DROP)
+				verdict = NF_DROP;
+		}
+	}
+	if (verdict == IPT_CONTINUE && ipi->dst != IP_POOL_NONE) {
+		modified = ip_pool_mod(ipi->dst, ntohl((*pskb)->nh.iph->daddr),
+					ipi->flags & IPT_POOL_DEL_DST);
+		if (!!modified ^ !!(ipi->flags & IPT_POOL_INV_MOD_DST)) {
+			if (ipi->flags & IPT_POOL_MOD_DST_ACCEPT)
+				verdict = NF_ACCEPT;
+			else if (ipi->flags & IPT_POOL_MOD_DST_DROP)
+				verdict = NF_DROP;
+		}
+	}
+	return verdict;
+}
+
+static struct ipt_target pool_reg
+= { { NULL, NULL }, "POOL", do_target, do_check, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	DEBUGP("init ipt_POOL\n");
+	return ipt_register_target(&pool_reg);
+}
+
+static void __exit fini(void)
+{
+	DEBUGP("fini ipt_POOL\n");
+	ipt_unregister_target(&pool_reg);
+}
+
+module_init(init);
+module_exit(fini);
