]> git.puffer.fish Git - matthieu/frr.git/commitdiff
lib: Rewrite ipv6 prefix matcher
authorQuentin Young <qlyoung@cumulusnetworks.com>
Mon, 27 Jun 2016 13:14:18 +0000 (13:14 +0000)
committerQuentin Young <qlyoung@cumulusnetworks.com>
Tue, 12 Jul 2016 13:33:56 +0000 (13:33 +0000)
Simplify ipv6 prefix matcher / validator to use standard Linux
networking functions instead of a state machine.

Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Don Slice <dslice@cumulusnetworks.com>
lib/command.c

index 3b5b8feba4955c80b0e5c321895ee6fe16ba0ade..d8a3149c14919970f1627ca103ecac4c407d617a 100644 (file)
@@ -1001,15 +1001,8 @@ cmd_ipv4_prefix_match (const char *str)
   return exact_match;
 }
 
-#define IPV6_ADDR_STR          "0123456789abcdefABCDEF:.%"
-#define IPV6_PREFIX_STR                "0123456789abcdefABCDEF:.%/"
-#define STATE_START            1
-#define STATE_COLON            2
-#define STATE_DOUBLE           3
-#define STATE_ADDR             4
-#define STATE_DOT               5
-#define STATE_SLASH            6
-#define STATE_MASK             7
+#define IPV6_ADDR_STR       "0123456789abcdefABCDEF:.%"
+#define IPV6_PREFIX_STR     "0123456789abcdefABCDEF:.%/"
 
 #ifdef HAVE_IPV6
 
@@ -1040,11 +1033,10 @@ cmd_ipv6_match (const char *str)
 static enum match_type
 cmd_ipv6_prefix_match (const char *str)
 {
-  int state = STATE_START;
-  int colons = 0, nums = 0, double_colon = 0;
-  int mask;
-  const char *sp = NULL;
-  char *endptr = NULL;
+  struct sockaddr_in6 sin6_dummy;
+  const char *delim = "/\0";
+  char *dupe, *prefix, *mask, *context, *endptr;
+  int nmask = -1;
 
   if (str == NULL)
     return partly_match;
@@ -1052,116 +1044,26 @@ cmd_ipv6_prefix_match (const char *str)
   if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
     return no_match;
 
-  while (*str != '\0' && state != STATE_MASK)
-    {
-      switch (state)
-       {
-       case STATE_START:
-         if (*str == ':')
-           {
-             if (*(str + 1) != ':' && *(str + 1) != '\0')
-               return no_match;
-             colons--;
-             state = STATE_COLON;
-           }
-         else
-           {
-             sp = str;
-             state = STATE_ADDR;
-           }
-
-         continue;
-       case STATE_COLON:
-         colons++;
-         if (*(str + 1) == '/')
-           return no_match;
-         else if (*(str + 1) == ':')
-           state = STATE_DOUBLE;
-         else
-           {
-             sp = str + 1;
-             state = STATE_ADDR;
-           }
-         break;
-       case STATE_DOUBLE:
-         if (double_colon)
-           return no_match;
-
-         if (*(str + 1) == ':')
-           return no_match;
-         else
-           {
-             if (*(str + 1) != '\0' && *(str + 1) != '/')
-               colons++;
-             sp = str + 1;
-
-             if (*(str + 1) == '/')
-               state = STATE_SLASH;
-             else
-               state = STATE_ADDR;
-           }
-
-         double_colon++;
-         nums += 1;
-         break;
-       case STATE_ADDR:
-         if (*(str + 1) == ':' || *(str + 1) == '.'
-             || *(str + 1) == '\0' || *(str + 1) == '/')
-           {
-             if (str - sp > 3)
-               return no_match;
-
-             for (; sp <= str; sp++)
-               if (*sp == '/')
-                 return no_match;
+  /* tokenize to address + mask */
+  dupe = XMALLOC(MTYPE_TMP, strlen(str)+1);
+  strncpy(dupe, str, strlen(str)+1);
+  prefix = strtok_r(dupe, delim, &context);
+  mask   = strtok_r(NULL, delim, &context);
 
-             nums++;
-
-             if (*(str + 1) == ':')
-               state = STATE_COLON;
-             else if (*(str + 1) == '.')
-               {
-                 if (colons || double_colon)
-                   state = STATE_DOT;
-                 else
-                   return no_match;
-               }
-             else if (*(str + 1) == '/')
-               state = STATE_SLASH;
-           }
-         break;
-       case STATE_DOT:
-         state = STATE_ADDR;
-         break;
-       case STATE_SLASH:
-         if (*(str + 1) == '\0')
-           return partly_match;
-
-         state = STATE_MASK;
-         break;
-       default:
-         break;
-       }
-
-      if (nums > 11)
-       return no_match;
-
-      if (colons > 7)
-       return no_match;
-
-      str++;
-    }
-
-  if (state < STATE_MASK)
+  if (!mask)
     return partly_match;
 
-  mask = strtol (str, &endptr, 10);
-  if (*endptr != '\0')
+  /* validate prefix */
+  if (inet_pton(AF_INET6, prefix, &sin6_dummy.sin6_addr) != 1)
     return no_match;
 
-  if (mask < 0 || mask > 128)
+  /* validate mask */
+  nmask = strtol (mask, &endptr, 10);
+  if (*endptr != '\0' || nmask < 0 || nmask > 128)
     return no_match;
-  
+
+  XFREE(MTYPE_TMP, dupe);
+
   return exact_match;
 }