iptables hashlimit ipmask support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello,

Recently i needed to be able to do exactly what iptables with hashlimit does,
but instead of hashing by IP i wanted it to hash on arbitrary network mask.
So, i've hacked up this, and i hope that you could find it useful.

It adds one more hashlimit option : "--hashlimit-ipmask", and if it is
supplied all src/dst ip addresses
are masked with it, and so you can easily do hashlimit on a per /24(or
any else between /1 and /31) network basis.

One example :

iptables -A INPUT -p tcp --dport 22 -m state --state NEW \
    -m hashlimit --hashlimit-mode srcip --hashlimit-ipmask 24 \
    --hashlimit-name ssh --hashlimit-burst 3 --hashlimit 12/hour \
    --hashlimit-htable-expire 1800000 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -j DROP


P.S. : There is no ipv6 support, and the manpage is not updated to
reflect the new hashlimit option --hashlimit-ipmask
P.S.2: I know that this probably can be done with connlimit, but
hashlimit can also do limiting on the destination ip (dstip mode)
which i think is not possible with connlimit.

-- Niki
diff -ur iptables-1.4.0rc1/extensions/libxt_hashlimit.c iptables-1.4.0rc1-hashlimitmask/extensions/libxt_hashlimit.c
--- iptables-1.4.0rc1/extensions/libxt_hashlimit.c	2007-10-15 15:45:09.000000000 +0300
+++ iptables-1.4.0rc1-hashlimitmask/extensions/libxt_hashlimit.c	2008-02-28 13:41:54.000000000 +0200
@@ -37,6 +37,7 @@
 "--hashlimit-mode <mode>		mode is a comma-separated list of\n"
 "					dstip,srcip,dstport,srcport\n"
 "--hashlimit-name <name>		name for /proc/net/ipt_hashlimit/\n"
+"[--hashlimit-ipmask <bits>]    mask to apply on ip addresses\n"
 "[--hashlimit-burst <num>]	number to match in a burst, default %u\n"
 "[--hashlimit-htable-size <num>]	number of hashtable buckets\n"
 "[--hashlimit-htable-max <num>]	number of hashtable entries\n"
@@ -54,6 +55,7 @@
 	{ "hashlimit-htable-expire", 1, NULL, ')' },
 	{ "hashlimit-mode", 1, NULL, '_' },
 	{ "hashlimit-name", 1, NULL, '"' },
+	{ "hashlimit-ipmask", 1, NULL, '!' }, 
 	{ }
 };
 
@@ -93,6 +95,25 @@
 	return 1;
 }
 
+static
+int parse_ipmask(const char *ipmask, u_int32_t *val)
+{
+	int i;
+	uint bits;
+	u_int32_t mask;
+
+	mask = 0;
+
+	if (string_to_number(ipmask, 1, 31, &bits) == -1)
+		return 0;
+
+	for (i = 0; i < bits; i++)
+		mask |= (1 << (31 - i));
+	
+	*val = mask;
+	return 1;
+}
+
 /* Initialize the match. */
 static void hashlimit_init(struct xt_entry_match *m)
 {
@@ -101,6 +122,7 @@
 	r->cfg.burst = XT_HASHLIMIT_BURST;
 	r->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
 	r->cfg.expire = XT_HASHLIMIT_EXPIRE;
+	r->cfg.ipmask = 0; /* disabled by default */
 
 }
 
@@ -144,6 +166,7 @@
 #define PARAM_MAX		0x00000020
 #define PARAM_GCINTERVAL	0x00000040
 #define PARAM_EXPIRE		0x00000080
+#define	PARAM_IPMASK		0x00000100
 
 /* Function which parses command options; returns true if it
    ate an option */
@@ -221,6 +244,13 @@
 		strncpy(r->name, optarg, sizeof(r->name));
 		*flags |= PARAM_NAME;
 		break;
+	case '!':
+		if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
+		if (!parse_ipmask(optarg, &r->cfg.ipmask))
+			exit_error(PARAMETER_PROBLEM,
+				   "bad --hashlimit-ipmask: `%s'", optarg);
+		*flags |= PARAM_IPMASK;
+		break;
 	default:
 		return 0;
 	}
@@ -268,6 +298,21 @@
 	printf("%u/%s ", rates[i-1].mult / period, rates[i-1].name);
 }
 
+static void print_ipmask(u_int32_t ipmask)
+{
+	unsigned int i;
+	unsigned int bits;
+
+	bits = 1;
+
+	for (i=0; i < 31; i++) {
+		if (ipmask & (1 << i))
+			bits++;
+	}
+
+	printf("%u ", bits);
+}
+
 static void print_mode(const struct xt_hashlimit_info *r, char separator)
 {
 	int prevmode = 0;
@@ -308,6 +353,10 @@
 	printf("burst %u ", r->cfg.burst);
 	fputs("mode ", stdout);
 	print_mode(r, '-');
+	if (r->cfg.ipmask) {
+		fputs("ipmask: ", stdout);
+		print_ipmask(r->cfg.ipmask);
+	}
 	if (r->cfg.size)
 		printf("htable-size %u ", r->cfg.size);
 	if (r->cfg.max)
@@ -328,6 +377,11 @@
 	if (r->cfg.burst != XT_HASHLIMIT_BURST)
 		printf("--hashlimit-burst %u ", r->cfg.burst);
 
+	if (r->cfg.ipmask) {
+		fputs("--hashlimit-ipmask ", stdout);
+		print_ipmask(r->cfg.ipmask);
+	}
+
 	fputs("--hashlimit-mode ", stdout);
 	print_mode(r, ',');
 	
diff -ur iptables-1.4.0rc1/include/linux/netfilter/xt_hashlimit.h iptables-1.4.0rc1-hashlimitmask/include/linux/netfilter/xt_hashlimit.h
--- iptables-1.4.0rc1/include/linux/netfilter/xt_hashlimit.h	2007-08-06 11:51:02.000000000 +0300
+++ iptables-1.4.0rc1-hashlimitmask/include/linux/netfilter/xt_hashlimit.h	2008-02-28 11:48:36.000000000 +0200
@@ -24,6 +24,7 @@
 	u_int32_t max;		/* max number of entries */
 	u_int32_t gc_interval;	/* gc interval */
 	u_int32_t expire;	/* when do entries expire? */
+	u_int32_t ipmask;	/* ip mask */
 };
 
 struct xt_hashlimit_info {
--- linux/net/netfilter/xt_hashlimit.c.orig	2008-02-28 12:32:27.000000000 +0200
+++ linux/net/netfilter/xt_hashlimit.c	2008-02-28 13:25:57.000000000 +0200
@@ -385,9 +385,18 @@
 	switch (hinfo->family) {
 	case AF_INET:
 		if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_DIP)
-			dst->addr.ip.dst = ip_hdr(skb)->daddr;
+			if (hinfo->cfg.ipmask)
+				dst->addr.ip.dst = (ip_hdr(skb)->daddr &
+					htonl(hinfo->cfg.ipmask));
+			else
+				dst->addr.ip.dst = ip_hdr(skb)->daddr;
+
 		if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_SIP)
-			dst->addr.ip.src = ip_hdr(skb)->saddr;
+			if (hinfo->cfg.ipmask)
+				dst->addr.ip.src = (ip_hdr(skb)->saddr &
+					htonl(hinfo->cfg.ipmask));
+			else
+				dst->addr.ip.src = ip_hdr(skb)->saddr;
 
 		if (!(hinfo->cfg.mode &
 		      (XT_HASHLIMIT_HASH_DPT | XT_HASHLIMIT_HASH_SPT)))
--- linux/include/linux/netfilter/xt_hashlimit.h.orig	2008-02-28 12:32:49.000000000 +0200
+++ linux/include/linux/netfilter/xt_hashlimit.h	2008-02-28 11:48:56.000000000 +0200
@@ -24,6 +24,7 @@
 	u_int32_t max;		/* max number of entries */
 	u_int32_t gc_interval;	/* gc interval */
 	u_int32_t expire;	/* when do entries expire? */
+	u_int32_t ipmask;	/* ip mask */
 };
 
 struct xt_hashlimit_info {

[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux