bb2d391712fb0208347ffc0b88abe146df14dc0a
galt
  Fri Jun 21 18:21:50 2019 -0700
Adding Support for CIDR specification of subnets, e.g. 192.168.1.255/31. It still supports the older subnet format too, e.g. 192.168

diff --git src/lib/internet.c src/lib/internet.c
index 6a4c673..81cbc51 100644
--- src/lib/internet.c
+++ src/lib/internet.c
@@ -133,30 +133,132 @@
     }
 }
 
 void internetUnpackIp(bits32 packed, unsigned char unpacked[4])
 /* Convert from 32 bit to 4-byte format with most significant
  * byte first. */
 {
 int i;
 for (i=3; i>=0; --i)
     {
     unpacked[i] = (packed&0xff);
     packed >>= 8;
     }
 }
 
-boolean internetIpInSubnet(unsigned char unpackedIp[4], unsigned char subnet[4])
-/* Return true if unpacked IP address is in subnet. */
+bits32 internetPackIp(unsigned char unpacked[4])
+/* Convert from 4-byte format with most significant
+ * byte first to native 32-bit format. */
 {
 int i;
-for (i=0; i<4; ++i)
+bits32 packed = 0;
+for (i=0; i<=3; ++i)
+    {
+    packed <<= 8;
+    packed |= unpacked[i];
+    }
+return packed;
+}
+
+void internetCidrRange(struct cidr *cidr, bits32 *pStartIp, bits32 *pEndIp)
+/* get range of CIDR formatted subnet as start and end IPs. */
 {
-    unsigned char c = subnet[i];
-    if (c == 255)
+bits32 packedIp = cidr->ip;
+int bits = cidr->subnetLength;
+int r = 32 - bits;
+bits32 start = packedIp & (((unsigned int) 0xFFFFFFFF) << r);
+bits32 end;
+// shr or shl 32 of a 32-bit value 
+//  does nothing at all rather than turning it to zeroes.
+if (bits == 32)
+    end = packedIp;
+else
+    end = packedIp | (((unsigned int) 0xFFFFFFFF) >> bits);
+
+*pStartIp = start;
+*pEndIp = end;
+
+}
+
+boolean internetIpInSubnetCidr(unsigned char unpackedIp[4], struct cidr *cidr)
+/* Return true if unpacked IP address is in subnet cidr. */
+{
+bits32 subnetIp = cidr->ip;
+//printf("packed32 bits=%u %08x\n", subnetIp, subnetIp);   // DEBUG REMOVE
+int r = 32 - cidr->subnetLength;
+bits32 caremask = subnetIp & (((unsigned int) 0xFFFFFFFF) << r);
+
+bits32 packedIp = internetPackIp(unpackedIp);
+
+if ((subnetIp & caremask) == (packedIp & caremask))
     return TRUE;
-    if (c != unpackedIp[i])
+
 return FALSE;
 }
-return TRUE;
+
+static void notGoodSubnetCidr(char *sns)
+/* Complain about subnet format. */
+{
+errAbort("'%s' is not a properly formatted subnet.  Subnets must consist of\n"
+         "one to four dot-separated numbers between 0 and 255 \n"
+	 "optionally followed by an slash and subnet bit length integer between 1 and 32.\n"
+	 "A trailing dot on the subnet IP address is not allowed.", sns);
+}
+
+struct cidr *internetParseSubnetCidr(char *cidr)
+/* parse input CIDR format IP for range or subnet */
+{
+if (!cidr)
+    return NULL;  
+char *s = cloneString(cidr);
+char *c = strchr(s, '/');
+char *ip = s;
+int bits = -1;
+if (c) // has slash
+    {
+    *c++ = 0;
+    bits = atoi(c);
+    }
+if (ip[strlen(ip)-1] == '.')  // trailing dot not allowed in subnet ip
+    notGoodSubnetCidr(cidr);
+char *snsCopy = cloneString(ip);
+char expIp[17];
+char *words[5];
+int wordCount, i;
+expIp[0] = 0;
+wordCount = chopByChar(snsCopy, '.', words, ArraySize(words));
+if (wordCount > 4 || wordCount < 1)
+    notGoodSubnetCidr(cidr);
+for (i=0; i<4; ++i)
+    {
+    int x = 0; // does not matter what these bits are, it is just filler.
+    char *s = "0";
+    if (i<wordCount)
+	{
+	s = words[i];
+	if (!isdigit(s[0]))
+	    notGoodSubnetCidr(cidr);
+	x = atoi(s);
+	if (x > 255)
+	    notGoodSubnetCidr(cidr);
+	}
+    safecat(expIp, sizeof expIp, s);
+    if (i < 3)
+	safecat(expIp, sizeof expIp, ".");
+    }
+if (bits == -1)
+    bits = 8 * wordCount;
+if ((bits > 32) || (bits < 1))
+    notGoodSubnetCidr(cidr);
+ip = expIp;
+
+unsigned char quadIp[4];
+internetParseDottedQuad(ip, quadIp);
+bits32 packedIp = 0;
+packedIp = internetPackIp(quadIp);
+struct cidr *result;
+AllocVar(result);
+result->ip = packedIp;
+result->subnetLength = bits;
+return result;
 }