diff -Nurb patch-o-matic-ng-20040621.old/mod/help patch-o-matic-ng-20040621/mod/help
--- patch-o-matic-ng-20040621.old/mod/help	1970-01-01 01:00:00.000000000 +0100
+++ patch-o-matic-ng-20040621/mod/help	2005-06-16 14:19:57.000000000 +0100
@@ -0,0 +1,48 @@
+This patch allows matches based on the modulus of ports and address.  It
+includes the ability to speciy a weighting value.
+
+The primary purpose of this module is to fascilitate load-balancing by
+matchining in the mangle table and marking packets.  This simple
+load-balancing technique does not rely on state infromation because the
+interface that the connection will be load-balanced onto can be determined
+solely by the address and port information.  I belive this technique nicely
+complements the load balancing abilities of the kernel routing code because
+it is much more finer-grained.  Routing decisions can be based on any match
+that iptables is capable of doing.
+
+A weighting factor can also be supplied.  This allows the modulus range to
+be split up into uneven portions.
+
+Example of load balancing outgoing web traffc:
+
+iptables -t mangle -A OUTPUT -p tcp --destination-port 80 \
+	-m mod --src-mod-port --dst-mod-addr --mod 3 --result 0 --weight 2 \
+	-j MARK --set-mark 1
+
+Here the source port (which will generally increment for each outgoing
+connection) and the destination IP are used to generate a modulus.  If the
+result of doing mod 3 is from 0 to 0 + 2 - 1 (ie 0 or 1) the rule will match
+and MARK 0x1 will be applied.
+
+So, the above example would effectivly send "two out of three" requests down
+the alternative route, assuming firewall mark-based routing had also been
+setup.
+
+Note that the above example would also need a SNAT rule to masqurade the
+traffic onto the correct source address, but this is beyond the scope of
+this little document.
+
+Four different tests are available:
+--src-mod-port, --dst-mod-port, --src-mod-addr, --dst-mod-addr
+
+These may be combined as needed.
+
+--mod sets the divisor, --weight sets the weight.
+
+--result means the match is made if the result of the modulus is in the
+range result to result + weight - 1.  It should be from 0 to 1 less then the
+divisor less the weighting.
+
+Non tcp or udp packets will never match.
+
+I am sure this module has other applications, perhaps in DNATing.
diff -Nurb patch-o-matic-ng-20040621.old/mod/info patch-o-matic-ng-20040621/mod/info
--- patch-o-matic-ng-20040621.old/mod/info	1970-01-01 01:00:00.000000000 +0100
+++ patch-o-matic-ng-20040621/mod/info	2005-06-08 09:50:29.000000000 +0100
@@ -0,0 +1,3 @@
+Author: Lawrence Manning <lawrence@smoothwall.net>
+Status: Alpha
+Repository: base
diff -Nurb patch-o-matic-ng-20040621.old/mod/linux/Documentation/Configure.help.ladd patch-o-matic-ng-20040621/mod/linux/Documentation/Configure.help.ladd
--- patch-o-matic-ng-20040621.old/mod/linux/Documentation/Configure.help.ladd	1970-01-01 01:00:00.000000000 +0100
+++ patch-o-matic-ng-20040621/mod/linux/Documentation/Configure.help.ladd	2005-06-16 13:59:44.000000000 +0100
@@ -0,0 +1,8 @@
+CONFIG_IP_NF_MATCH_TOS
+iprange match support
+CONFIG_IP_NF_MATCH_MOD
+  This option makes possible to match ports and address against a modulus.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
diff -Nurb patch-o-matic-ng-20040621.old/mod/linux/include/linux/netfilter_ipv4/ipt_mod.h patch-o-matic-ng-20040621/mod/linux/include/linux/netfilter_ipv4/ipt_mod.h
--- patch-o-matic-ng-20040621.old/mod/linux/include/linux/netfilter_ipv4/ipt_mod.h	1970-01-01 01:00:00.000000000 +0100
+++ patch-o-matic-ng-20040621/mod/linux/include/linux/netfilter_ipv4/ipt_mod.h	2005-06-16 13:59:13.000000000 +0100
@@ -0,0 +1,19 @@
+#ifndef _IPT_MOD_H
+#define _IPT_MOD_H
+
+#define MOD_SRC_PORT		0x01	/* Match source port */
+#define MOD_DST_PORT		0x02	/* Match destination port */
+#define MOD_SRC_ADDR		0x04	/* Match source port */
+#define MOD_DST_ADDR		0x08	/* Match destination port */
+
+struct ipt_mod_info
+{
+	u_int32_t mod;
+	u_int32_t result;
+	u_int32_t weight;
+	
+	/* Flags from above */
+	u_int8_t flags;
+};
+
+#endif /* _IPT_MOD_H */
diff -Nurb patch-o-matic-ng-20040621.old/mod/linux/net/ipv4/netfilter/Config.in.ladd patch-o-matic-ng-20040621/mod/linux/net/ipv4/netfilter/Config.in.ladd
--- patch-o-matic-ng-20040621.old/mod/linux/net/ipv4/netfilter/Config.in.ladd	1970-01-01 01:00:00.000000000 +0100
+++ patch-o-matic-ng-20040621/mod/linux/net/ipv4/netfilter/Config.in.ladd	2005-06-16 13:58:16.000000000 +0100
@@ -0,0 +1,2 @@
+  dep_tristate '  limit match support' CONFIG_IP_NF_MATCH_LIMIT $CONFIG_IP_NF_IPTABLES
+  dep_tristate '  port and address modulus match support' CONFIG_IP_NF_MATCH_MOD $CONFIG_IP_NF_IPTABLES
diff -Nurb patch-o-matic-ng-20040621.old/mod/linux/net/ipv4/netfilter/ipt_mod.c patch-o-matic-ng-20040621/mod/linux/net/ipv4/netfilter/ipt_mod.c
--- patch-o-matic-ng-20040621.old/mod/linux/net/ipv4/netfilter/ipt_mod.c	1970-01-01 01:00:00.000000000 +0100
+++ patch-o-matic-ng-20040621/mod/linux/net/ipv4/netfilter/ipt_mod.c	2005-06-16 13:57:43.000000000 +0100
@@ -0,0 +1,103 @@
+/*
+ * iptables module to match port moduluses.
+ *   (c) Lawrence Manning, SmoothWall Ltd <lawrence@smoothwall.net>
+ *
+ * Released under the terms of GNU GPLv2.
+ *
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/udp.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_mod.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Lawrence Manning, SmoothWall Ltd <lawrence@smoothwall.net>");
+MODULE_DESCRIPTION("iptables port modulus match module");
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+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_mod_info *info = matchinfo;
+	const struct iphdr *iph = skb->nh.iph;
+	const struct udphdr *udp = hdr;
+	int result = 0;
+
+	/* Must be big enough to read ports. */
+	if (offset == 0 && datalen < sizeof(struct udphdr))
+	{
+		/* We've been asked to examine this packet, and we
+		 * can't.  Hence, no choice but to drop. */
+		DEBUGP("ipt_mod: Dropping evil offset=0 tinygram.\n");
+		*hotdrop = 1;
+		return 0;
+	}
+
+	/* Must not be a fragment. */
+	if (offset) return 0;
+	
+	if (info->flags & MOD_SRC_PORT)
+		result += ntohs(udp->source) % info->mod;
+	if (info->flags & MOD_DST_PORT)
+		result += ntohs(udp->dest) % info->mod;
+	if (info->flags & MOD_SRC_ADDR)
+		result += ntohl(iph->saddr) % info->mod;
+	if (info->flags & MOD_DST_ADDR)
+		result += ntohl(iph->daddr) % info->mod;
+
+	result = result % info->mod;
+
+	DEBUGP("after flags: %d mod: %d result: %d looking for %d to %d:\n", info->flags, info->mod, result, info->result, result <= info->result + info->weight - 1);
+	
+	return (result >= info->result && result <= info->result + info->weight - 1);
+}
+
+static int check(const char *tablename,
+		 const struct ipt_ip *ip,
+		 void *matchinfo,
+		 unsigned int matchsize,
+		 unsigned int hook_mask)
+{
+	/* verify size */
+	if (matchsize != IPT_ALIGN(sizeof(struct ipt_mod_info)))
+		return 0;
+
+	return 1;
+}
+
+static struct ipt_match iprange_match = 
+{ 
+	.list = { NULL, NULL }, 
+	.name = "mod", 
+	.match = &match, 
+	.checkentry = &check, 
+	.destroy = NULL, 
+	.me = THIS_MODULE
+};
+
+static int __init init(void)
+{
+	return ipt_register_match(&iprange_match);
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_match(&iprange_match);
+}
+
+module_init(init);
+module_exit(fini);
diff -Nurb patch-o-matic-ng-20040621.old/mod/linux/net/ipv4/netfilter/Makefile.ladd patch-o-matic-ng-20040621/mod/linux/net/ipv4/netfilter/Makefile.ladd
--- patch-o-matic-ng-20040621.old/mod/linux/net/ipv4/netfilter/Makefile.ladd	1970-01-01 01:00:00.000000000 +0100
+++ patch-o-matic-ng-20040621/mod/linux/net/ipv4/netfilter/Makefile.ladd	2005-06-08 09:50:29.000000000 +0100
@@ -0,0 +1,2 @@
+obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o
+obj-$(CONFIG_IP_NF_MATCH_MOD) += ipt_mod.o
