Fixed an embarrassing bug if we want to generate a netmask from a prefix == 0.
authorBernd Petrovitsch <bernd@firmix.at>
Sun, 30 Nov 2008 22:50:56 +0000 (23:50 +0100)
committerBernd Petrovitsch <bernd@firmix.at>
Sun, 30 Nov 2008 22:50:56 +0000 (23:50 +0100)
Added an inline function to avoid someone else making the same mistake

All credits belong to Markus Kittenberger <Markus.Kittenberger@gmx.at> for finding,
reporting and hunting it down to the root cause.

lib/quagga/test/quagga.try1.c
src/ipcalc.c
src/ipcalc.h

index 197cf80..7ee040d 100644 (file)
@@ -514,6 +514,7 @@ int zebra_disable_redistribute (unsigned char type) {
 
 }
   
+/* this is buggy. see prefix_to_netmask4() for a working version. */
 static uint32_t prefixlentomask (uint8_t prefix) {
   uint32_t mask;
   mask = 0xffffffff<<(32-prefix);
index 8a1853e..3340407 100644 (file)
@@ -119,7 +119,7 @@ int ip_in_net(const union olsr_ip_addr *ipaddr, const struct olsr_ip_prefix *net
 {
   int rv;
   if(olsr_cnf->ip_version == AF_INET) {
-    uint32_t netmask = ntohl(~0 << (32 - net->prefix_len));
+    uint32_t netmask = ntohl(prefix_to_netmask4(net->prefix_len));
     rv = (ipaddr->v4.s_addr & netmask) == (net->prefix.v4.s_addr & netmask);
   } else {
     /* IPv6 */
@@ -127,6 +127,7 @@ int ip_in_net(const union olsr_ip_addr *ipaddr, const struct olsr_ip_prefix *net
     const uint32_t *i = (const uint32_t *)&ipaddr->v6.s6_addr;
     const uint32_t *n = (const uint32_t *)&net->prefix.v6.s6_addr;
     unsigned int prefix_len;
+    /* First we compare whole unsigned int's */
     for (prefix_len = net->prefix_len; prefix_len > 32; prefix_len -= 32) {
       if (*i != *n) {
         return false;
@@ -134,7 +135,8 @@ int ip_in_net(const union olsr_ip_addr *ipaddr, const struct olsr_ip_prefix *net
       i++;
       n++;
     }
-    netmask = ntohl(~0 << (32 - prefix_len));
+    /* And the remaining is the same as in the IPv4 case */
+    netmask = ntohl(prefix_to_netmask4(prefix_len));
     rv = (*i & netmask) == (*n & netmask);
   }
   return rv;
index b42b3f2..68d1024 100644 (file)
@@ -103,6 +103,11 @@ const char *sockaddr6_to_string(char * const buf, int bufsize, const struct sock
 
 const char *sockaddr_to_string(char *buf, int bufsize, const struct sockaddr * const addr, unsigned int addrsize);
 
+/* we need to handle one value specifically since shifting 32 bits of a 32 bit integer is the same as shifting 0 bits.
+ * The result is in host-byte-order.
+ */
+static INLINE uint32_t prefix_to_netmask4(uint8_t prefixlen) { return prefixlen == 0 ? 0 : (~0U << (32 - prefixlen)); }
+
 #endif
 /*
  * Local Variables: