[libvirt] [PATCH] Use libvirt's existing ipv6/ipv4 parser/printer rather than self-written ones

Stefan Berger stefanb at us.ibm.com
Tue Mar 30 14:50:20 UTC 2010


This patch changes the network filtering code to use libvirt's existing
IPv4 and IPv6 address parsers/printers rather than my self-written ones.

I am introducing a new function in network.c that counts the number of
bits in a netmask and ensures that the given address is indeed a
netmask, return -1 on error or values of 0-32 for IPv4 addresses and
0-128 for IPv6 addresses. I then based the function checking for valid
netmask on invoking this function.

Signed-off-by: Stefan Berger <stefanb at us.ibm.com>

---
 src/conf/nwfilter_conf.c                  |  181 ++----------------------------
 src/conf/nwfilter_conf.h                  |    8 -
 src/nwfilter/nwfilter_ebiptables_driver.c |   46 ++++---
 src/util/network.c                        |  173 +++++++++++++++-------------
 src/util/network.h                        |    3 
 5 files changed, 142 insertions(+), 269 deletions(-)

Index: libvirt-acl/src/conf/nwfilter_conf.h
===================================================================
--- libvirt-acl.orig/src/conf/nwfilter_conf.h
+++ libvirt-acl/src/conf/nwfilter_conf.h
@@ -33,6 +33,8 @@
 # include "util.h"
 # include "hash.h"
 # include "xml.h"
+# include "network.h"
+
 
 /**
  * Chain suffix size is:
@@ -85,11 +87,7 @@ struct _nwMACAddress {
 typedef struct _nwIPAddress nwIPAddress;
 typedef nwIPAddress *nwIPAddressPtr;
 struct _nwIPAddress {
-    int isIPv6;
-    union {
-        unsigned char ipv4Addr[4];
-        unsigned char ipv6Addr[16];
-    } addr;
+    virSocketAddr addr;
 };
 
 
Index: libvirt-acl/src/util/network.c
===================================================================
--- libvirt-acl.orig/src/util/network.c
+++ libvirt-acl/src/util/network.c
@@ -219,88 +219,10 @@ virSocketGetPort(virSocketAddrPtr addr) 
  * Returns 0 in case of success and -1 in case of error
  */
 int virSocketAddrIsNetmask(virSocketAddrPtr netmask) {
-    int i;
-
-    if (netmask == NULL)
-        return(-1);
-
-    if (netmask->stor.ss_family == AF_INET) {
-        virIPv4Addr tm;
-        unsigned char tmp;
-        int ok = 0;
-
-        if (getIPv4Addr(netmask, &tm) < 0)
-            return(-1);
-
-        for (i = 0;i < 4;i++) {
-           if (tm[i] != 0)
-               break;
-        }
-
-        if (i >= 4)
-            return(0);
-
-        tmp = 0xFF;
-        do {
-            if (tm[i] == tmp) {
-                ok = 1;
-                break;
-            }
-            tmp <<= 1;
-        } while (tmp != 0);
-        if (ok == 0)
-            return(-1);
-        i++;
-
-        if (i >= 4)
-            return(0);
-
-        for (;i < 4;i++) {
-            if (tm[i] != 0xFF)
-                return(-1);
-        }
-    } else if (netmask->stor.ss_family == AF_INET6) {
-        virIPv6Addr tm;
-        unsigned short tmp;
-        int ok = 0;
-
-        /*
-         * Hum, on IPv6 people use prefixes instead of netmask
-         */
-        if (getIPv6Addr(netmask, &tm) < 0)
-            return(-1);
-
-        for (i = 0;i < 8;i++) {
-           if (tm[i] != 0)
-               break;
-        }
-
-        if (i >= 8)
-            return(0);
-
-        tmp = 0xFFFF;
-        do {
-            if (tm[i] == tmp) {
-                ok = 1;
-                break;
-            }
-            tmp <<= 1;
-        } while (tmp != 0);
-        if (ok == 0)
-            return(-1);
-        i++;
-
-        if (i >= 8)
-            return(0);
-
-        for (;i < 8;i++) {
-            if (tm[i] != 0xFFFF)
-                return(-1);
-        }
-    } else {
-        return(-1);
-    }
-    return(0);
+    int n = virSocketGetNumNetmaskBits(netmask);
+    if (n < 0)
+        return -1;
+    return 0;
 }
 
 /**
@@ -415,3 +337,90 @@ int virSocketGetRange(virSocketAddrPtr s
     }
     return(ret);
 }
+
+
+/**
+ * virGetNumNetmaskBits
+ * @netmask: the presumed netmask
+ *
+ * Get the number of netmask bits in a netmask.
+ *
+ * Returns the number of bits in the netmask or -1 if an error occurred
+ * or the netmask is invalid.
+ */
+int virSocketGetNumNetmaskBits(const virSocketAddrPtr netmask)
+{
+    int i, j;
+    int c = 0;
+
+    if (netmask->stor.ss_family == AF_INET) {
+        virIPv4Addr tm;
+        uint8_t bit;
+
+        if (getIPv4Addr(netmask, &tm) < 0)
+            return -1;
+
+        for (i = 0; i < 4; i++)
+            if (tm[i] == 0xff)
+                c += 8;
+            else
+                break;
+
+        if (c == 8 * 4)
+            return c;
+
+        j = i << 3;
+        while (j < (8 * 4)) {
+            bit = 1 << (7 - (j & 7));
+            if ((tm[j >> 3] & bit)) {
+                c++;
+            } else
+                break;
+            j++;
+        }
+
+        while (j < (8 * 4)) {
+            bit = 1 << (7 - (j & 7));
+            if ((tm[j >> 3] & bit))
+                return -1;
+            j++;
+        }
+
+        return c;
+    } else if (netmask->stor.ss_family == AF_INET6) {
+        virIPv6Addr tm;
+        uint16_t bit;
+
+        if (getIPv6Addr(netmask, &tm) < 0)
+            return -1;
+
+        for (i = 0; i < 8; i++)
+            if (tm[i] == 0xffff)
+                c += 16;
+            else
+                break;
+
+        if (c == 16 * 8)
+            return c;
+
+        j = i << 4;
+        while (j < (16 * 8)) {
+            bit = 1 << (15 - (j & 0xf));
+            if ((tm[j >> 4] & bit)) {
+                c++;
+            } else
+                break;
+            j++;
+        }
+
+        while (j < (16 * 8)) {
+            bit = 1 << (15 - (j & 0xf));
+            if ((tm[j >> 4]) & bit)
+                return -1;
+            j++;
+        }
+
+        return c;
+    }
+    return -1;
+}
Index: libvirt-acl/src/util/network.h
===================================================================
--- libvirt-acl.orig/src/util/network.h
+++ libvirt-acl/src/util/network.h
@@ -48,4 +48,7 @@ int virSocketAddrIsNetmask(virSocketAddr
 int virSocketCheckNetmask (virSocketAddrPtr addr1,
                            virSocketAddrPtr addr2,
                            virSocketAddrPtr netmask);
+
+int virSocketGetNumNetmaskBits(const virSocketAddrPtr netmask);
+
 #endif /* __VIR_NETWORK_H__ */
Index: libvirt-acl/src/conf/nwfilter_conf.c
===================================================================
--- libvirt-acl.orig/src/conf/nwfilter_conf.c
+++ libvirt-acl/src/conf/nwfilter_conf.c
@@ -473,22 +473,6 @@ checkValidMask(unsigned char *data, int 
 }
 
 
-/* check for a valid IPv4 mask */
-static bool
-checkIPv4Mask(enum attrDatatype datatype ATTRIBUTE_UNUSED, void *maskptr,
-              virNWFilterRuleDefPtr nwf ATTRIBUTE_UNUSED)
-{
-    return checkValidMask(maskptr, 4);
-}
-
-static bool
-checkIPv6Mask(enum attrDatatype datatype ATTRIBUTE_UNUSED, void *maskptr,
-              virNWFilterRuleDefPtr nwf ATTRIBUTE_UNUSED)
-{
-    return checkValidMask(maskptr, 16);
-}
-
-
 static bool
 checkMACMask(enum attrDatatype datatype ATTRIBUTE_UNUSED,
              void *macMask,
@@ -498,16 +482,6 @@ checkMACMask(enum attrDatatype datatype 
 }
 
 
-static int getMaskNumBits(const unsigned char *mask, int len) {
-     int i = 0;
-     while (i < (len << 3)) {
-         if (!(mask[i>>3] & (0x80 >> (i & 3))))
-             break;
-         i++;
-     }
-     return i;
-}
-
 /*
  * supported arp opcode -- see 'ebtables -h arp' for the naming
  */
@@ -1227,21 +1201,8 @@ static bool
 virNWIPv4AddressParser(const char *input,
                        nwIPAddressPtr output)
 {
-    int i;
-    char *endptr;
-    const char *n = input;
-    long int d;
-
-    for (i = 0; i < 4; i++) {
-        d = strtol(n, &endptr, 10);
-        if (d < 0 || d > 255            ||
-            (endptr - n        > 3    ) ||
-            (i <= 2 && *endptr != '.' ) ||
-            (i == 3 && *endptr != '\0'))
-            return 0;
-        output->addr.ipv4Addr[i] = (unsigned char)d;
-        n = endptr + 1;
-    }
+    if (virSocketParseIpv4Addr(input, &output->addr) == -1)
+        return 0;
     return 1;
 }
 
@@ -1250,81 +1211,8 @@ static bool
 virNWIPv6AddressParser(const char *input,
                        nwIPAddressPtr output)
 {
-    int i, j, pos;
-    uint16_t n;
-    int shiftpos = -1;
-    char prevchar;
-    char base;
-
-    memset(output, 0x0, sizeof(*output));
-
-    output->isIPv6 = 1;
-
-    pos = 0;
-    i = 0;
-
-    while (i < 8) {
-        j = 0;
-        n = 0;
-        while (1) {
-            prevchar = input[pos++];
-            if (prevchar == ':' || prevchar == 0) {
-                if (j > 0) {
-                    output->addr.ipv6Addr[i * 2 + 0] = n >> 8;
-                    output->addr.ipv6Addr[i * 2 + 1] = n;
-                    i++;
-                }
-                break;
-            }
-
-            if (j >= 4)
-                return 0;
-
-            if (prevchar >= '0' && prevchar <= '9')
-                base = '0';
-            else if (prevchar >= 'a' && prevchar <= 'f')
-                base = 'a' - 10;
-            else if (prevchar >= 'A' && prevchar <= 'F')
-                base = 'A' - 10;
-            else
-                return 0;
-            n <<= 4;
-            n |= (prevchar - base);
-            j++;
-        }
-
-        if (prevchar == 0)
-            break;
-
-        if (input[pos] == ':') {
-            pos ++;
-            // sequence of zeros
-            if (prevchar != ':')
-                return 0;
-
-            if (shiftpos != -1)
-                return 0;
-
-            shiftpos = i;
-        }
-    }
-
-    if (shiftpos != -1) {
-        if (i >= 7)
-            return 0;
-        i--;
-        j = 0;
-        while (i >= shiftpos) {
-            output->addr.ipv6Addr[15 - (j*2) - 1] =
-                              output->addr.ipv6Addr[i * 2 + 0];
-            output->addr.ipv6Addr[15 - (j*2) - 0] =
-                              output->addr.ipv6Addr[i * 2 + 1];
-            output->addr.ipv6Addr[i * 2 + 0] = 0;
-            output->addr.ipv6Addr[i * 2 + 1] = 0;
-            i--;
-            j++;
-        }
-    }
+    if (virSocketParseIpv6Addr(input, &output->addr) == -1)
+        return 0;
     return 1;
 }
 
@@ -1442,11 +1330,10 @@ virNWFilterRuleDetailsParse(virConnectPt
                                 } else
                                     rc = -1;
                             } else {
-                                if (checkIPv4Mask(datatype,
-                                                  ipaddr.addr.ipv4Addr, nwf))
-                                    *(uint8_t *)storage_ptr =
-                                       getMaskNumBits(ipaddr.addr.ipv4Addr,
-                                                 sizeof(ipaddr.addr.ipv4Addr));
+                                int_val = virSocketGetNumNetmaskBits(
+                                                     &ipaddr.addr);
+                                if (int_val >= 0)
+                                    *(uint8_t *)storage_ptr = int_val;
                                 else
                                     rc = -1;
                                 found = 1;
@@ -1497,11 +1384,10 @@ virNWFilterRuleDetailsParse(virConnectPt
                                 } else
                                     rc = -1;
                             } else {
-                                if (checkIPv6Mask(datatype,
-                                                  ipaddr.addr.ipv6Addr, nwf))
-                                    *(uint8_t *)storage_ptr =
-                                       getMaskNumBits(ipaddr.addr.ipv6Addr,
-                                                 sizeof(ipaddr.addr.ipv6Addr));
+                                int_val = virSocketGetNumNetmaskBits(
+                                                     &ipaddr.addr);
+                                if (int_val >= 0)
+                                    *(uint8_t *)storage_ptr = int_val;
                                 else
                                     rc = -1;
                                 found = 1;
@@ -2571,43 +2457,12 @@ virNWFilterPoolObjDeleteDef(virConnectPt
 static void
 virNWIPAddressFormat(virBufferPtr buf, nwIPAddressPtr ipaddr)
 {
-    if (!ipaddr->isIPv6) {
-        virBufferVSprintf(buf, "%d.%d.%d.%d",
-                          ipaddr->addr.ipv4Addr[0],
-                          ipaddr->addr.ipv4Addr[1],
-                          ipaddr->addr.ipv4Addr[2],
-                          ipaddr->addr.ipv4Addr[3]);
-    } else {
-        int i;
-        int dcshown = 0, in_dc = 0;
-        unsigned short n;
-        while (i < 8) {
-            n = (ipaddr->addr.ipv6Addr[i * 2 + 0] << 8) |
-                 ipaddr->addr.ipv6Addr[i * 2 + 1];
-            if (n == 0) {
-                if (!dcshown) {
-                    in_dc = 1;
-                    if (i == 0)
-                        virBufferAddLit(buf, ":");
-                    dcshown = 1;
-                }
-                if (in_dc) {
-                    i++;
-                    continue;
-                }
-            }
-            if (in_dc) {
-                dcshown = 1;
-                virBufferAddLit(buf, ":");
-                in_dc = 0;
-            }
-            i++;
-            virBufferVSprintf(buf, "%x", n);
-            if (i < 8)
-                virBufferAddLit(buf, ":");
-        }
-        if (in_dc)
-            virBufferAddLit(buf, ":");
+    virSocketAddrPtr addr = &ipaddr->addr;
+    char *output = virSocketFormatAddr(addr);
+
+    if (output) {
+        virBufferVSprintf(buf, "%s", output);
+        VIR_FREE(output);
     }
 }
 
Index: libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.c
===================================================================
--- libvirt-acl.orig/src/nwfilter/nwfilter_ebiptables_driver.c
+++ libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.c
@@ -144,7 +144,7 @@ printDataType(virConnectPtr conn,
               nwItemDescPtr item)
 {
     int done;
-    int i, pos, s;
+    char *data;
 
     if (printVar(conn, vars, buf, bufsize, item, &done))
         return 1;
@@ -154,30 +154,38 @@ printDataType(virConnectPtr conn,
 
     switch (item->datatype) {
     case DATATYPE_IPADDR:
-        if (snprintf(buf, bufsize, "%d.%d.%d.%d",
-                    item->u.ipaddr.addr.ipv4Addr[0],
-                    item->u.ipaddr.addr.ipv4Addr[1],
-                    item->u.ipaddr.addr.ipv4Addr[2],
-                    item->u.ipaddr.addr.ipv4Addr[3]) >= bufsize) {
-            virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
-                                   _("Buffer too small for IP address"));
+        data = virSocketFormatAddr(&item->u.ipaddr.addr);
+        if (!data) {
+            virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                   _("internal IPv4 address representation "
+                                     "is bad"));
+            return 1;
+        }
+        if (snprintf(buf, bufsize, "%s", data) >= bufsize) {
+            virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                   _("buffer too small for IP address"));
+            VIR_FREE(data);
             return 1;
         }
+        VIR_FREE(data);
     break;
 
     case DATATYPE_IPV6ADDR:
-        pos = 0;
-        for (i = 0; i < 16; i++) {
-            s = snprintf(&buf[pos], bufsize - pos, "%x%s",
-                         (unsigned int)item->u.ipaddr.addr.ipv6Addr[i],
-                         ((i & 1) && (i < 15)) ? ":" : "" );
-            if (s >= bufsize - pos) {
-                virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
-                                       _("Buffer too small for IPv6 address"));
-                return 1;
-            }
-            pos += s;
+        data = virSocketFormatAddr(&item->u.ipaddr.addr);
+        if (!data) {
+            virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                   _("internal IPv6 address representation "
+                                     "is bad"));
+            return 1;
+        }
+
+        if (snprintf(buf, bufsize, "%s", data) >= bufsize) {
+            virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                   _("buffer too small for IPv6 address"));
+            VIR_FREE(data);
+            return 1;
         }
+        VIR_FREE(data);
     break;
 
     case DATATYPE_MACADDR:




More information about the libvir-list mailing list