From e7b98bc79bf8e01d6e2897a95502827ce2a83e7d Mon Sep 17 00:00:00 2001
From: Dmitry Kozlov <xeb@mail.ru>
Date: Mon, 12 May 2014 18:32:51 +0400
Subject: ippool: introduced shuffle option

By default list of IP address is serial at startup.
This option shuffles initial IP list so it becomes more random.
---
 accel-pppd/accel-ppp.conf.5 |  3 +++
 accel-pppd/extra/ippool.c   | 60 +++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 61 insertions(+), 2 deletions(-)

diff --git a/accel-pppd/accel-ppp.conf.5 b/accel-pppd/accel-ppp.conf.5
index d5fcb7ac..0b3ac31d 100644
--- a/accel-pppd/accel-ppp.conf.5
+++ b/accel-pppd/accel-ppp.conf.5
@@ -747,6 +747,9 @@ Configuration of ippool module.
 .BI "gw-ip-address=" x.x.x.x
 Specifies single IP address to be used as local address of ppp interfaces.
 .TP
+.BI "shuffle=" 1|0
+Specifies whether to shuffle initial address list.
+.TP
 .BI "gw=" range
 Specifies range of local address of ppp interfaces if form:
 .br
diff --git a/accel-pppd/extra/ippool.c b/accel-pppd/extra/ippool.c
index 825b8f37..15238025 100644
--- a/accel-pppd/extra/ippool.c
+++ b/accel-pppd/extra/ippool.c
@@ -51,6 +51,7 @@ static struct ipdb_t ipdb;
 static in_addr_t conf_gw_ip_address;
 static int conf_vendor = 0;
 static int conf_attr = 88; // Framed-Pool
+static int conf_shuffle;
 
 static int cnt;
 static LIST_HEAD(pool_list);
@@ -175,18 +176,71 @@ static void add_range(struct ippool_t *p, struct list_head *list, const char *na
 	p->generate = generate;
 }
 
+static uint8_t get_random()
+{
+	static uint8_t buf[128];
+	static int pos = 0;
+	int r;
+
+	if (pos == 0)
+		read(urandom_fd, buf, 128);
+	
+	r = buf[pos++];
+
+	if (pos == 128)
+		pos = 0;
+	
+	return r;
+}
+
 static void generate_pool_p2p(struct ippool_t *p)
 {
 	struct ippool_item_t *it;
 	struct ipaddr_t *addr = NULL;
 	struct ipaddr_t *peer_addr;
+	struct list_head *pos, *pos1 = p->tunnel_list.next, *pos2 = p->tunnel_list.prev;
+	uint8_t r, t = 0;
 
 	while (1) {
 		if (list_empty(&p->tunnel_list))
 			break;
 		else {
-			peer_addr = list_entry(p->tunnel_list.next, typeof(*peer_addr), entry);
-			list_del(&peer_addr->entry);
+			if (conf_shuffle) {
+				if (pos1 == &p->tunnel_list)
+					pos1 = pos1->next;
+
+				if (pos2 == &p->tunnel_list)
+					pos2 = pos2->prev;
+
+				if (t++ < 10)
+					r = get_random();
+				else
+					r = get_random()%64;
+
+				if (r < 32)
+					pos = pos1;
+				else if (r < 64)
+					pos = pos2;
+
+				pos1 = pos1->next;
+				pos2 = pos2->prev;
+				
+				if (r >= 64)
+					continue;
+				
+				peer_addr = list_entry(pos, typeof(*peer_addr), entry);
+				if (pos == pos1)
+					pos1 = pos1->next;
+				
+				if (pos == pos2)
+					pos2 = pos2->prev;
+				
+				list_del(&peer_addr->entry);
+				t = 0;
+			} else {
+				peer_addr = list_entry(p->tunnel_list.next, typeof(*peer_addr), entry);
+				list_del(&peer_addr->entry);
+			}
 		}
 
 		if (!conf_gw_ip_address) {
@@ -536,6 +590,8 @@ static void ippool_init2(void)
 #endif
 		if (!strcmp(opt->name, "gw-ip-address"))
 			parse_gw_ip_address(opt->val);
+		else if (!strcmp(opt->name, "shuffle"))
+			conf_shuffle = atoi(opt->val);
 		else {
 			pool_name = NULL;
 			allocator = NULL;
-- 
cgit v1.2.3