summaryrefslogtreecommitdiff
path: root/lib/command.c
diff options
context:
space:
mode:
authorQuentin Young <qlyoung@cumulusnetworks.com>2016-06-27 14:51:17 +0000
committerQuentin Young <qlyoung@cumulusnetworks.com>2016-07-12 13:41:27 +0000
commitd4dc41b6a23d5156b0d9068006a1eeb3ba32e301 (patch)
tree16de03df91c51d1258283a2dcf46386742939af5 /lib/command.c
parent4d91343a45839480e006e2cc7c0dfd0725e1d0c8 (diff)
lib: Rewrite ipv4 address and prefix validator
Simplify ipv4 prefix and address 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>
Diffstat (limited to 'lib/command.c')
-rw-r--r--lib/command.c144
1 files changed, 36 insertions, 108 deletions
diff --git a/lib/command.c b/lib/command.c
index 500b377aba..34864e9d3f 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -865,59 +865,29 @@ enum match_type
exact_match
};
+#define IPV4_ADDR_STR "0123456789."
+#define IPV4_PREFIX_STR "0123456789./"
+
+/**
+ * Determines whether a string is a valid ipv4 token.
+ *
+ * @param[in] str the string to match
+ * @return exact_match if the string is an exact match, no_match/partly_match
+ * otherwise
+ */
static enum match_type
cmd_ipv4_match (const char *str)
{
- const char *sp;
- int dots = 0, nums = 0;
- char buf[4];
+ struct sockaddr_in sin_dummy;
if (str == NULL)
return partly_match;
- for (;;)
- {
- memset (buf, 0, sizeof (buf));
- sp = str;
- while (*str != '\0')
- {
- if (*str == '.')
- {
- if (dots >= 3)
- return no_match;
-
- if (*(str + 1) == '.')
- return no_match;
-
- if (*(str + 1) == '\0')
- return partly_match;
-
- dots++;
- break;
- }
- if (!isdigit ((int) *str))
- return no_match;
-
- str++;
- }
-
- if (str - sp > 3)
- return no_match;
-
- strncpy (buf, sp, str - sp);
- if (atoi (buf) > 255)
- return no_match;
-
- nums++;
-
- if (*str == '\0')
- break;
-
- str++;
- }
+ if (strspn (str, IPV4_ADDR_STR) != strlen (str))
+ return no_match;
- if (nums < 4)
- return partly_match;
+ if (inet_pton(AF_INET, str, &sin_dummy.sin_addr) != 1)
+ return no_match;
return exact_match;
}
@@ -925,79 +895,37 @@ cmd_ipv4_match (const char *str)
static enum match_type
cmd_ipv4_prefix_match (const char *str)
{
- const char *sp;
- int dots = 0;
- char buf[4];
+ struct sockaddr_in sin_dummy;
+ const char *delim = "/\0";
+ char *dupe, *prefix, *mask, *context, *endptr;
+ int nmask = -1;
if (str == NULL)
return partly_match;
- for (;;)
- {
- memset (buf, 0, sizeof (buf));
- sp = str;
- while (*str != '\0' && *str != '/')
- {
- if (*str == '.')
- {
- if (dots == 3)
- return no_match;
-
- if (*(str + 1) == '.' || *(str + 1) == '/')
- return no_match;
-
- if (*(str + 1) == '\0')
- return partly_match;
-
- dots++;
- break;
- }
-
- if (!isdigit ((int) *str))
- return no_match;
-
- str++;
- }
-
- if (str - sp > 3)
- return no_match;
-
- strncpy (buf, sp, str - sp);
- if (atoi (buf) > 255)
- return no_match;
-
- if (dots == 3)
- {
- if (*str == '/')
- {
- if (*(str + 1) == '\0')
- return partly_match;
-
- str++;
- break;
- }
- else if (*str == '\0')
- return partly_match;
- }
-
- if (*str == '\0')
- return partly_match;
+ if (strspn (str, IPV4_PREFIX_STR) != strlen (str))
+ return no_match;
- str++;
- }
+ /* 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);
- sp = str;
- while (*str != '\0')
- {
- if (!isdigit ((int) *str))
- return no_match;
+ if (!mask)
+ return partly_match;
- str++;
- }
+ /* validate prefix */
+ if (inet_pton(AF_INET, prefix, &sin_dummy.sin_addr) != 1)
+ return no_match;
- if (atoi (sp) > 32)
+ /* validate mask */
+ nmask = strtol (mask, &endptr, 10);
+ if (*endptr != '\0' || nmask < 0 || nmask > 32)
return no_match;
+ XFREE(MTYPE_TMP, dupe);
+
return exact_match;
}