diff options
author | Quentin Young <qlyoung@cumulusnetworks.com> | 2016-12-06 19:54:04 +0100 |
---|---|---|
committer | Quentin Young <qlyoung@cumulusnetworks.com> | 2016-12-06 19:54:04 +0100 |
commit | 2d21bc75bee876c2029989887b3a33477990d617 (patch) | |
tree | 3f1af8962e943f19afc0351ff015ac4b511251b3 /lib/command_match.c | |
parent | lib: add command_lex.h to .gitignore (diff) | |
download | frr-2d21bc75bee876c2029989887b3a33477990d617.tar.xz frr-2d21bc75bee876c2029989887b3a33477990d617.zip |
lib: add back original ipv6 matcher
inet_pton is not suitable for well behaved cli completions
Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
Diffstat (limited to 'lib/command_match.c')
-rw-r--r-- | lib/command_match.c | 146 |
1 files changed, 121 insertions, 25 deletions
diff --git a/lib/command_match.c b/lib/command_match.c index f3f7d3998..e75910c27 100644 --- a/lib/command_match.c +++ b/lib/command_match.c @@ -780,44 +780,140 @@ match_ipv6 (const char *str) return no_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 static enum match_type match_ipv6_prefix (const char *str) { - struct sockaddr_in6 sin6_dummy; - const char *delim = "/\0"; - char *tofree, *dupe, *prefix, *mask, *endptr; - int nmask = -1; + int state = STATE_START; + int colons = 0, nums = 0, double_colon = 0; + int mask; + const char *sp = NULL; + char *endptr = NULL; + + if (str == NULL) + return partly_match; if (strspn (str, IPV6_PREFIX_STR) != strlen (str)) return no_match; - /* tokenize to prefix + mask */ - tofree = dupe = XSTRDUP (MTYPE_TMP, str); - prefix = strsep (&dupe, delim); - mask = dupe; + 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; + + 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; - /* validate prefix */ - if (inet_pton (AF_INET6, prefix, &sin6_dummy.sin6_addr) != 1) - { - XFREE (MTYPE_TMP, tofree); - return no_match; - } + str++; + } - /* validate mask */ - if (!mask) - { - XFREE (MTYPE_TMP, tofree); + if (state < STATE_MASK) return partly_match; - } - nmask = strtoimax (mask, &endptr, 10); - if (*endptr != '\0' || nmask < 0 || nmask > 128) - { - XFREE (MTYPE_TMP, tofree); + mask = strtol (str, &endptr, 10); + if (*endptr != '\0') + return no_match; + + if (mask < 0 || mask > 128) return no_match; - } - XFREE (MTYPE_TMP, tofree); return exact_match; } #endif |