From 4c58c70dcbc3dc5f7274e9b964eecd225cc3c9ef Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Mon, 27 Jun 2016 13:14:18 +0000 Subject: [PATCH] lib: Rewrite ipv6 prefix matcher Simplify ipv6 prefix matcher / validator to use standard Linux networking functions instead of a state machine. Signed-off-by: Quentin Young Reviewed-by: Donald Sharp Reviewed-by: Don Slice --- lib/command.c | 138 ++++++++------------------------------------------ 1 file changed, 20 insertions(+), 118 deletions(-) diff --git a/lib/command.c b/lib/command.c index 3b5b8feba4..d8a3149c14 100644 --- a/lib/command.c +++ b/lib/command.c @@ -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; } -- 2.39.5