From d867f32a7aefe6694dbbc4c6370a36a30bfc8318 Mon Sep 17 00:00:00 2001
From: Denis Vlasenko
Date: Sun, 19 Aug 2007 21:15:42 +0000
Subject: httpd: explain IP/mask parsing, and simplify it a bit.

parse_conf                                          1258    1247     -11
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-11)             Total: -11 bytes
   text    data     bss     dec     hex filename
 772602    1058   11092  784752   bf970 busybox_old
 772594    1058   11092  784744   bf968 busybox_unstripped

---
 networking/httpd.c | 81 ++++++++++++++++++++++++++++++++----------------------
 1 file changed, 48 insertions(+), 33 deletions(-)

(limited to 'networking')

diff --git a/networking/httpd.c b/networking/httpd.c
index a7473ed..0b4e305 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -289,17 +289,26 @@ static ALWAYS_INLINE void free_Htaccess_IP_list(Htaccess_IP **pptr)
 	free_llist((has_next_ptr**)pptr);
 }
 
-static int scan_ip(const char **ep, unsigned *ip, unsigned char endc)
+//#undef isdigit
+//#define isdigit(a) ((unsigned)((a) - '0') <= 9)
+//#define notdigit(a) ((unsigned)((a) - '0') > 9)
+
+/* Returns presumed mask width in bits or < 0 on error.
+ * Updates strp, stores IP at provided pointer */
+static int scan_ip(const char **strp, unsigned *ipp, unsigned char endc)
 {
-	const char *p = *ep;
+	const char *p = *strp;
 	int auto_mask = 8;
+	unsigned ip = 0;
 	int j;
 
-	*ip = 0;
+	if (*p == '/')
+		return -auto_mask;
+
 	for (j = 0; j < 4; j++) {
 		unsigned octet;
 
-		if ((*p < '0' || *p > '9') && (*p != '/' || j == 0) && *p != '\0')
+		if ((*p < '0' || *p > '9') && *p != '/' && *p)
 			return -auto_mask;
 		octet = 0;
 		while (*p >= '0' && *p <= '9') {
@@ -311,55 +320,61 @@ static int scan_ip(const char **ep, unsigned *ip, unsigned char endc)
 		}
 		if (*p == '.')
 			p++;
-		if (*p != '/' && *p != '\0')
+		if (*p != '/' && *p)
 			auto_mask += 8;
-		*ip = ((*ip) << 8) | octet;
+		ip = (ip << 8) | octet;
 	}
-	if (*p != '\0') {
+	if (*p) {
 		if (*p != endc)
 			return -auto_mask;
 		p++;
 		if (*p == '\0')
 			return -auto_mask;
 	}
-	*ep = p;
+	*ipp = ip;
+	*strp = p;
 	return auto_mask;
 }
 
-static int scan_ip_mask(const char *ipm, unsigned *ip, unsigned *mask)
+/* Returns 0 on success. Stores IP and mask at provided pointers */
+static int scan_ip_mask(const char *str, unsigned *ipp, unsigned *maskp)
 {
 	int i;
-	unsigned msk;
+	unsigned mask;
+	char *p;
 
-	i = scan_ip(&ipm, ip, '/');
+	i = scan_ip(&str, ipp, '/');
 	if (i < 0)
 		return i;
-	if (*ipm) {
-		const char *p = ipm;
-
-		i = 0;
-		while (*p) {
-			if (*p < '0' || *p > '9') {
-				if (*p == '.') {
-					i = scan_ip(&ipm, mask, 0);
-					return i != 32;
-				}
-				return -1;
-			}
-			i *= 10;
-			i += *p - '0';
-			p++;
+
+	if (*str) {
+		/* there is /xxx after dotted-IP address */
+		i = bb_strtou(str, &p, 10);
+		if (*p == '.') {
+			/* 'xxx' itself is dotted-IP mask, parse it */
+			/* (return 0 (success) only if it has N.N.N.N form) */
+			return scan_ip(&str, maskp, '\0') - 32;
 		}
+		if (*p)
+			return -1;
 	}
-	if (i > 32 || i < 0)
+
+	if (i > 32)
 		return -1;
-	msk = 0x80000000;
-	*mask = 0;
-	while (i > 0) {
-		*mask |= msk;
-		msk >>= 1;
-		i--;
+
+	if (sizeof(unsigned) == 4 && i == 32) {
+		/* mask >>= 32 below may not work */
+		mask = 0;
+	} else {
+		mask = 0xffffffff;
+		mask >>= i;
 	}
+	/* i == 0 -> *maskp = 0x00000000
+	 * i == 1 -> *maskp = 0x80000000
+	 * i == 4 -> *maskp = 0xf0000000
+	 * i == 31 -> *maskp = 0xfffffffe
+	 * i == 32 -> *maskp = 0xffffffff */
+	*maskp = (uint32_t)(~mask);
 	return 0;
 }
 
-- 
cgit v1.1