From 9a7fc1bd7a4961793bfb4340a4c4819e217fcb70 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Thu, 11 May 2017 11:26:40 +0200 Subject: [PATCH] lib: cli: fix IPv6 address partial matching A partially-entered IPv6 address would never return a "partly_match", meaning some possible completions weren't listed by the matcher. This specifically breaks autocompleting BGP IPv6 neighbor addresses. Before: aegaeon# show ip bg ne 2001: WORD Neighbor on BGP configured interface After: aegaeon# show ip bg ne 2001: WORD Neighbor on BGP configured interface X:X::X:X Neighbor to display information about 2001:db8::2 Signed-off-by: David Lamparter --- lib/command_match.c | 39 +++++++++++--------------------- tests/lib/cli/test_cli.refout.in | 8 ++++--- 2 files changed, 18 insertions(+), 29 deletions(-) diff --git a/lib/command_match.c b/lib/command_match.c index df1a8bb72..d1f9ef1cb 100644 --- a/lib/command_match.c +++ b/lib/command_match.c @@ -78,10 +78,7 @@ static enum match_type match_ipv4_prefix (const char *); static enum match_type -match_ipv6 (const char *); - -static enum match_type -match_ipv6_prefix (const char *); +match_ipv6_prefix (const char *, bool); static enum match_type match_range (struct cmd_token *, const char *); @@ -677,9 +674,9 @@ match_token (struct cmd_token *token, char *input_token) case IPV4_PREFIX_TKN: return match_ipv4_prefix (input_token); case IPV6_TKN: - return match_ipv6 (input_token); + return match_ipv6_prefix (input_token, false); case IPV6_PREFIX_TKN: - return match_ipv6_prefix (input_token); + return match_ipv6_prefix (input_token, true); case RANGE_TKN: return match_range (token, input_token); case VARIABLE_TKN: @@ -835,35 +832,18 @@ match_ipv4_prefix (const char *str) #define STATE_MASK 7 static enum match_type -match_ipv6 (const char *str) -{ - struct sockaddr_in6 sin6_dummy; - int ret; - - if (strspn (str, IPV6_ADDR_STR) != strlen (str)) - return no_match; - - ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr); - - if (ret == 1) - return exact_match; - - return no_match; -} - -static enum match_type -match_ipv6_prefix (const char *str) +match_ipv6_prefix (const char *str, bool prefix) { int state = STATE_START; int colons = 0, nums = 0, double_colon = 0; int mask; - const char *sp = NULL; + const char *sp = NULL, *start = str; char *endptr = NULL; if (str == NULL) return partly_match; - if (strspn (str, IPV6_PREFIX_STR) != strlen (str)) + if (strspn (str, prefix ? IPV6_PREFIX_STR : IPV6_ADDR_STR) != strlen (str)) return no_match; while (*str != '\0' && state != STATE_MASK) @@ -966,6 +946,13 @@ match_ipv6_prefix (const char *str) str++; } + if (!prefix) + { + struct sockaddr_in6 sin6_dummy; + int ret = inet_pton(AF_INET6, start, &sin6_dummy.sin6_addr); + return ret == 1 ? exact_match : partly_match; + } + if (state < STATE_MASK) return partly_match; diff --git a/tests/lib/cli/test_cli.refout.in b/tests/lib/cli/test_cli.refout.in index 18822c150..db9da429a 100644 --- a/tests/lib/cli/test_cli.refout.in +++ b/tests/lib/cli/test_cli.refout.in @@ -61,7 +61,7 @@ cmd2 with 3 args. [01]: ipv6 [02]: de4d:b33f::cafe test# arg ipv6 de4d:b3 -% There is no matched command. + X:X::X:X 02 test# arg ipv6 de4d:b33f::caf X:X::X:X 02 test# arg ipv6 de4d:b33f::cafe @@ -264,7 +264,8 @@ cmd10 with 3 args. test# test# alt a test# alt a a - WORD 02 + WORD 02 + X:X::X:X 02 test# alt a ab cmd11 with 3 args. [00]: alt @@ -281,7 +282,8 @@ cmd12 with 3 args. [02]: 1.2.3.4 test# alt a 1 test# alt a 1:2 - WORD 02 + WORD 02 + X:X::X:X 02 test# alt a 1:2 test# alt a 1:2:: WORD 02 -- 2.39.2