diff -u --new-file --recursive linux-2.4.18_iptables-1.2.7-20020511/include/linux/netfilter_ipv4/ipt_RMARK.h linux-2.4.18_iptables-1.2.7-20020511-special/include/linux/netfilter_ipv4/ipt_RMARK.h
--- linux-2.4.18_iptables-1.2.7-20020511/include/linux/netfilter_ipv4/ipt_RMARK.h	Thu Jan  1 02:00:00 1970
+++ linux-2.4.18_iptables-1.2.7-20020511-special/include/linux/netfilter_ipv4/ipt_RMARK.h	Mon May 13 13:59:14 2002
@@ -0,0 +1,13 @@
+#ifndef _IPT_RMARK_H_target
+#define _IPT_RMARK_H_target
+
+// Max number of routing tables allowed
+#define MAX_RMARK_TABLES 8192
+
+struct ipt_rmark_target_info {
+	unsigned char table_id;
+	unsigned char limit;
+	unsigned char offset;
+};
+
+#endif /*_IPT_RMARK_H_target*/
diff -u --new-file --recursive linux-2.4.18_iptables-1.2.7-20020511/include/linux/netfilter_ipv4/ipt_SMASQ.h linux-2.4.18_iptables-1.2.7-20020511-special/include/linux/netfilter_ipv4/ipt_SMASQ.h
--- linux-2.4.18_iptables-1.2.7-20020511/include/linux/netfilter_ipv4/ipt_SMASQ.h	Thu Jan  1 02:00:00 1970
+++ linux-2.4.18_iptables-1.2.7-20020511-special/include/linux/netfilter_ipv4/ipt_SMASQ.h	Mon May 13 13:59:14 2002
@@ -0,0 +1,12 @@
+#ifndef _IPT_SMASQ_H_target
+#define _IPT_SMASQ_H_target
+
+#define IPT_SMASQ_DEVICENAME 0x01  // Device name specified
+#define IPT_SMASQ_PORTMAPPING 0x02  //Port mapping specified
+
+struct ipt_smasq_target_info {
+	struct ip_nat_multi_range multi_range;
+	char deviceName[IFNAMSIZ];
+};
+
+#endif /*_IPT_SMASQ_H_target*/
diff -u --new-file --recursive linux-2.4.18_iptables-1.2.7-20020511/include/linux/netfilter_ipv4/ipt_isdev.h linux-2.4.18_iptables-1.2.7-20020511-special/include/linux/netfilter_ipv4/ipt_isdev.h
--- linux-2.4.18_iptables-1.2.7-20020511/include/linux/netfilter_ipv4/ipt_isdev.h	Thu Jan  1 02:00:00 1970
+++ linux-2.4.18_iptables-1.2.7-20020511-special/include/linux/netfilter_ipv4/ipt_isdev.h	Mon May 13 13:59:14 2002
@@ -0,0 +1,8 @@
+#ifndef _IPT_MARK_H
+#define _IPT_MARK_H
+
+struct ipt_isdev_info {
+	char deviceName[IFNAMSIZ];
+};
+
+#endif /*_IPT_MARK_H*/
diff -u --new-file --recursive linux-2.4.18_iptables-1.2.7-20020511/net/ipv4/netfilter/Config.in linux-2.4.18_iptables-1.2.7-20020511-special/net/ipv4/netfilter/Config.in
--- linux-2.4.18_iptables-1.2.7-20020511/net/ipv4/netfilter/Config.in	Sun May 12 02:21:53 2002
+++ linux-2.4.18_iptables-1.2.7-20020511-special/net/ipv4/netfilter/Config.in	Mon May 13 15:50:45 2002
@@ -30,6 +30,7 @@
   dep_tristate '  MAC address match support' CONFIG_IP_NF_MATCH_MAC $CONFIG_IP_NF_IPTABLES
   dep_tristate '  Packet type match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_PKTTYPE $CONFIG_IP_NF_IPTABLES
   dep_tristate '  netfilter MARK match support' CONFIG_IP_NF_MATCH_MARK $CONFIG_IP_NF_IPTABLES
+  dep_tristate '  ISDEV match support' CONFIG_IP_NF_MATCH_ISDEV $CONFIG_IP_NF_IPTABLES
   dep_tristate '  Multiple port match support' CONFIG_IP_NF_MATCH_MULTIPORT $CONFIG_IP_NF_IPTABLES
   dep_tristate '  Multiple port with ranges match support' CONFIG_IP_NF_MATCH_MPORT $CONFIG_IP_NF_IPTABLES
   dep_tristate '  TOS match support' CONFIG_IP_NF_MATCH_TOS $CONFIG_IP_NF_IPTABLES
@@ -75,6 +76,7 @@
     if [ "$CONFIG_IP_NF_NAT" != "n" ]; then
       define_bool CONFIG_IP_NF_NAT_NEEDED y
       dep_tristate '    MASQUERADE target support' CONFIG_IP_NF_TARGET_MASQUERADE $CONFIG_IP_NF_NAT
+      dep_tristate '    SMASQ target support' CONFIG_IP_NF_TARGET_SMASQ $CONFIG_IP_NF_NAT
       dep_tristate '    REDIRECT target support' CONFIG_IP_NF_TARGET_REDIRECT $CONFIG_IP_NF_NAT
       # If they want talk, set to $CONFIG_IP_NF_NAT (m or y), 
       # or $CONFIG_IP_NF_TALK (m or y), whichever is weaker.  Argh.
@@ -123,6 +125,7 @@
     dep_tristate '    DSCP target support' CONFIG_IP_NF_TARGET_DSCP $CONFIG_IP_NF_MANGLE
  
     dep_tristate '    MARK target support' CONFIG_IP_NF_TARGET_MARK $CONFIG_IP_NF_MANGLE
+    dep_tristate '    RMARK target support' CONFIG_IP_NF_TARGET_RMARK $CONFIG_IP_NF_MANGLE
   fi
   dep_tristate '  LOG target support' CONFIG_IP_NF_TARGET_LOG $CONFIG_IP_NF_IPTABLES
   dep_tristate '  TTL target support' CONFIG_IP_NF_TARGET_TTL $CONFIG_IP_NF_IPTABLES
diff -u --new-file --recursive linux-2.4.18_iptables-1.2.7-20020511/net/ipv4/netfilter/Makefile linux-2.4.18_iptables-1.2.7-20020511-special/net/ipv4/netfilter/Makefile
--- linux-2.4.18_iptables-1.2.7-20020511/net/ipv4/netfilter/Makefile	Sun May 12 02:22:06 2002
+++ linux-2.4.18_iptables-1.2.7-20020511-special/net/ipv4/netfilter/Makefile	Mon May 13 13:59:14 2002
@@ -82,6 +82,7 @@
 obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o
 obj-$(CONFIG_IP_NF_MATCH_QUOTA) += ipt_quota.o
 obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o
+obj-$(CONFIG_IP_NF_MATCH_ISDEV) += ipt_isdev.o
 obj-$(CONFIG_IP_NF_POOL) += ipt_pool.o ipt_POOL.o ip_pool.o
 obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o
 
@@ -128,7 +129,9 @@
 obj-$(CONFIG_IP_NF_TARGET_TOS) += ipt_TOS.o
 obj-$(CONFIG_IP_NF_TARGET_DSCP) += ipt_DSCP.o
 obj-$(CONFIG_IP_NF_TARGET_MARK) += ipt_MARK.o
+obj-$(CONFIG_IP_NF_TARGET_RMARK) += ipt_RMARK.o
 obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
+obj-$(CONFIG_IP_NF_TARGET_SMASQ) += ipt_SMASQ.o
 obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
 obj-$(CONFIG_IP_NF_TARGET_SAME) += ipt_SAME.o
 obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
diff -u --new-file --recursive linux-2.4.18_iptables-1.2.7-20020511/net/ipv4/netfilter/ipt_RMARK.c linux-2.4.18_iptables-1.2.7-20020511-special/net/ipv4/netfilter/ipt_RMARK.c
--- linux-2.4.18_iptables-1.2.7-20020511/net/ipv4/netfilter/ipt_RMARK.c	Thu Jan  1 02:00:00 1970
+++ linux-2.4.18_iptables-1.2.7-20020511-special/net/ipv4/netfilter/ipt_RMARK.c	Mon May 13 13:59:14 2002
@@ -0,0 +1,92 @@
+/* This is a module which is used for setting the NFMARK field of an skb with a round robin value */
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <net/checksum.h>
+
+#include <linux/netfilter_ipv4/lockhelp.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_RMARK.h>
+
+// Lock to protect marking_table
+static DECLARE_RWLOCK(rmark_lock);
+
+// Declare marking table type
+static unsigned char * marking_table;
+
+
+static unsigned int 
+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_rmark_target_info *markinfo = targinfo;
+
+	// Round robin marking
+	WRITE_LOCK(&rmark_lock);
+	marking_table[markinfo->table_id] = (marking_table[markinfo->table_id] + 1 > markinfo->limit) ? 1 : marking_table[markinfo->table_id] + 1;
+	WRITE_UNLOCK(&rmark_lock);
+
+	// Mark packet if its not already marked
+	if((*pskb)->nfmark != marking_table[markinfo->table_id] + markinfo->offset) 
+	{
+		(*pskb)->nfmark = marking_table[markinfo->table_id] + markinfo->offset;
+		(*pskb)->nfcache |= NFC_ALTERED;
+	}
+
+	// Continue with processing
+	return IPT_CONTINUE;
+}
+
+static int 
+checkentry(const char *tablename, const struct ipt_entry *e, void *targinfo, unsigned int targinfosize, unsigned int hook_mask)
+{
+	// Check if our size is ok, if not go mad!
+	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_rmark_target_info))) 
+	{
+		printk(KERN_WARNING "RMARK: targinfosize %u != %Zu\n", targinfosize, IPT_ALIGN(sizeof(struct ipt_rmark_target_info)));
+		return 0;
+	}
+
+	// We can only be valid if we in the mangle table
+	if (strcmp(tablename, "mangle") != 0) 
+	{
+		printk(KERN_WARNING "RMARK: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct ipt_target ipt_rmark_reg = {{NULL, NULL}, "RMARK", target, checkentry, NULL, THIS_MODULE};
+
+static int 
+__init init(void)
+{
+	int i;
+	
+	if (ipt_register_target(&ipt_rmark_reg))
+	{
+		return -EINVAL;
+	}
+
+	// Allocate our marking tables
+	marking_table  = (unsigned char *) kmalloc(MAX_RMARK_TABLES * sizeof(unsigned char *), GFP_KERNEL);
+	// Initialize table
+	for (i = 0; i < MAX_RMARK_TABLES; i++) {marking_table[i] = 0;}
+
+	printk(KERN_NOTICE "RMARK: %dKB allocated (%d tables)\n", (MAX_RMARK_TABLES * sizeof(unsigned char)) / 1024,	MAX_RMARK_TABLES);
+				
+	return 0;
+}
+
+static void 
+__exit fini(void)
+{
+	// If there is a marking table free it
+	if (marking_table) {kfree(marking_table);}
+
+	ipt_unregister_target(&ipt_rmark_reg);
+}
+
+module_init(init);
+module_exit(fini);
diff -u --new-file --recursive linux-2.4.18_iptables-1.2.7-20020511/net/ipv4/netfilter/ipt_SMASQ.c linux-2.4.18_iptables-1.2.7-20020511-special/net/ipv4/netfilter/ipt_SMASQ.c
--- linux-2.4.18_iptables-1.2.7-20020511/net/ipv4/netfilter/ipt_SMASQ.c	Thu Jan  1 02:00:00 1970
+++ linux-2.4.18_iptables-1.2.7-20020511-special/net/ipv4/netfilter/ipt_SMASQ.c	Mon May 13 13:59:14 2002
@@ -0,0 +1,222 @@
+/* Masquerade.  Simple mapping which alters range to a local IP address
+   (depending on route). */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/ip.h>
+#include <linux/timer.h>
+#include <linux/module.h>
+#include <linux/netfilter.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/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_SMASQ.h>
+#include <linux/netdevice.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+/* Lock protects smasq region inside conntrack */
+static DECLARE_RWLOCK(smasq_lock);
+
+/* FIXME: Multiple targets. --RR */
+static int
+smasq_check(const char *tablename,
+		 const struct ipt_entry *e,
+		 void *targinfo,
+		 unsigned int targinfosize,
+		 unsigned int hook_mask)
+{
+	const struct ipt_smasq_target_info *smasq_info = targinfo;
+
+	if (strcmp(tablename, "nat") != 0) {
+		DEBUGP("smasq_check: Bad table `%s'.\n", tablename);
+		return 0;
+	}
+	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_smasq_target_info))) {
+		DEBUGP("smasq_check: Size %u != %u.\n",
+		       targinfosize, sizeof(struct ipt_smasq_target_info));
+		return 0;
+	}
+	if (hook_mask & ~(1 << NF_IP_POST_ROUTING)) {
+		DEBUGP("smasq_check: Bad hooks %x.\n", hook_mask);
+		return 0;
+	}
+	if (smasq_info->multi_range.range[0].flags & IP_NAT_RANGE_MAP_IPS) {
+		DEBUGP("smasq_check: Bad MAP_IPS.\n");
+		return 0;
+	}
+	if (smasq_info->multi_range.rangesize != 1) {
+		DEBUGP("smasq_check: Bad rangesize %u.\n", smasq_info->multi_range.rangesize);
+		return 0;
+	}
+	return 1;
+}
+
+static unsigned int
+smasq_target(struct sk_buff **pskb,
+		  unsigned int hooknum,
+		  const struct net_device *in,
+		  const struct net_device *out,
+		  const void *targinfo,
+		  void *userinfo)
+{
+	struct ip_conntrack *ct;
+	enum ip_conntrack_info ctinfo;
+	const struct ipt_smasq_target_info *smasq_info = targinfo;
+	struct ip_nat_multi_range newrange;
+	u_int32_t newsrc;
+	struct rtable *rt;
+	struct rt_key key;
+	struct net_device *out_dev;
+
+	IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING);
+
+	/* FIXME: For the moment, don't do local packets, breaks
+	   testsuite for 2.3.49 --RR */
+	if ((*pskb)->sk)
+		return NF_ACCEPT;
+
+	// Get device id
+	out_dev = dev_get_by_name(smasq_info->deviceName);
+
+	// if its null, just accept
+	if (out_dev == NULL)
+	{
+		DEBUGP("SMASQ: Device %s down, no masquarading done\n",smasq_info->deviceName);
+		return NF_ACCEPT;
+	}
+	
+	ct = ip_conntrack_get(*pskb, &ctinfo);
+	IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED));
+
+
+	key.dst = (*pskb)->nh.iph->daddr;
+	key.src = 0; /* Unknown: that's what we're trying to establish */
+	key.tos = RT_TOS((*pskb)->nh.iph->tos)|RTO_CONN;
+	key.oif = out_dev->ifindex;
+#ifdef CONFIG_IP_ROUTE_FWMARK
+	key.fwmark = (*pskb)->nfmark;
+#endif
+	// this should get us the ip of the device we going out as
+	if (ip_route_output_key(&rt, &key) != 0) 
+	{
+		/* Shouldn't happen */
+					// does with this sum times?
+		DEBUGP("SMASQ: No route\n");
+		return NF_DROP;
+	}
+
+	newsrc = rt->rt_src;
+	DEBUGP("SMASQ: newsrc = %u.%u.%u.%u\n",NIPQUAD(newsrc));
+	ip_rt_put(rt);
+
+	WRITE_LOCK(&smasq_lock);
+	ct->nat.masq_index = out_dev->ifindex;
+	WRITE_UNLOCK(&smasq_lock);
+
+	/* Transfer from original range. */
+	newrange = ((struct ip_nat_multi_range)
+		{ 1, { { smasq_info->multi_range.range[0].flags | IP_NAT_RANGE_MAP_IPS,
+			 newsrc, newsrc,
+			 smasq_info->multi_range.range[0].min, smasq_info->multi_range.range[0].max } } });
+
+	/* Hand modified range to generic setup. */
+	return ip_nat_setup_info(ct, &newrange, hooknum);
+}
+
+static inline int
+device_cmp(const struct ip_conntrack *i, void *ifindex)
+{
+	int ret;
+
+	READ_LOCK(&smasq_lock);
+	ret = (i->nat.masq_index == (int)(long)ifindex);
+	READ_UNLOCK(&smasq_lock);
+
+	return ret;
+}
+
+static int smasq_device_event(struct notifier_block *this,
+			     unsigned long event,
+			     void *ptr)
+{
+	struct net_device *dev = ptr;
+
+	if (event == NETDEV_DOWN) {
+		/* Device was downed.  Search entire table for
+		   conntracks which were associated with that device,
+		   and forget them. */
+		IP_NF_ASSERT(dev->ifindex != 0);
+		DEBUGP("SMASQ: Cleaning up after downed device...\n");
+		ip_ct_selective_cleanup(device_cmp, (void *)(long)dev->ifindex);
+		DEBUGP("SMASQ: All connection tracking destroyed\n");
+	}
+
+	return NOTIFY_DONE;
+}
+
+static int smasq_inet_event(struct notifier_block *this,
+			   unsigned long event,
+			   void *ptr)
+{
+	struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev;
+
+	if (event == NETDEV_DOWN) {
+		/* IP address was deleted.  Search entire table for
+		   conntracks which were associated with that device,
+		   and forget them. */
+		IP_NF_ASSERT(dev->ifindex != 0);
+		DEBUGP("SMASQ: Cleaning up after changed ip...\n");
+		ip_ct_selective_cleanup(device_cmp, (void *)(long)dev->ifindex);
+		DEBUGP("SMASQ: All connection tracking destroyed\n");
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block smasq_dev_notifier = {
+	smasq_device_event,
+	NULL,
+	0
+};
+
+static struct notifier_block smasq_inet_notifier = {
+	smasq_inet_event,
+	NULL,
+	0
+};
+
+static struct ipt_target smasq
+= { { NULL, NULL }, "SMASQ", smasq_target, smasq_check, NULL,
+    THIS_MODULE };
+
+static int __init init(void)
+{
+	int ret;
+
+	ret = ipt_register_target(&smasq);
+
+	if (ret == 0) {
+		/* Register for device down reports */
+		register_netdevice_notifier(&smasq_dev_notifier);
+		/* Register IP address change reports */
+		register_inetaddr_notifier(&smasq_inet_notifier);
+	}
+
+	return ret;
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_target(&smasq);
+	unregister_netdevice_notifier(&smasq_dev_notifier);
+	unregister_inetaddr_notifier(&smasq_inet_notifier);	
+}
+
+module_init(init);
+module_exit(fini);
diff -u --new-file --recursive linux-2.4.18_iptables-1.2.7-20020511/net/ipv4/netfilter/ipt_isdev.c linux-2.4.18_iptables-1.2.7-20020511-special/net/ipv4/netfilter/ipt_isdev.c
--- linux-2.4.18_iptables-1.2.7-20020511/net/ipv4/netfilter/ipt_isdev.c	Thu Jan  1 02:00:00 1970
+++ linux-2.4.18_iptables-1.2.7-20020511-special/net/ipv4/netfilter/ipt_isdev.c	Mon May 13 13:59:14 2002
@@ -0,0 +1,52 @@
+/* Kernel module to match if a device exists. */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+
+#include <linux/netfilter_ipv4/ipt_isdev.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+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_isdev_info *info = matchinfo;
+
+	return (dev_get_by_name(info->deviceName) != NULL);
+}
+
+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_isdev_info)))
+		return 0;
+
+	return 1;
+}
+
+static struct ipt_match isdev_match
+= { { NULL, NULL }, "isdev", &match, &checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	return ipt_register_match(&isdev_match);
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_match(&isdev_match);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
