diff options
author | H. Peter Anvin <hpa@zytor.com> | 2008-07-30 16:34:44 -0700 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2008-07-30 16:34:44 -0700 |
commit | 77fbfeebee4d9d4d176f416e2c516fdd74a36b3f (patch) | |
tree | e5cd975be7115eb74102519cb34cb77a923a605c | |
parent | 0c6f7f86d38c66d9d855f5f9cf3441912783c5e7 (diff) | |
download | tftp-hpa-77fbfeebee4d9d4d176f416e2c516fdd74a36b3f.tar.gz |
Implement is_numeric_ipv6() as a state machine
Implement is_numeric_ipv6() as a state machine, so we can avoid
in-place modification.
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r-- | common/tftpsubs.c | 68 | ||||
-rw-r--r-- | common/tftpsubs.h | 8 |
2 files changed, 48 insertions, 28 deletions
diff --git a/common/tftpsubs.c b/common/tftpsubs.c index 1c91e89..9958184 100644 --- a/common/tftpsubs.c +++ b/common/tftpsubs.c @@ -331,7 +331,7 @@ set_sock_addr(char *host,union sock_addr *s, char **name) } #ifdef HAVE_IPV6 -int is_numeric_ipv6(char *addr) +int is_numeric_ipv6(const char *p) { /* A numeric IPv6 address consist at least of 2 ':' and * it may have sequences of hex-digits and maybe contain @@ -339,31 +339,55 @@ int is_numeric_ipv6(char *addr) * we do not check here, if it is a valid IPv6 address * only if is something like a numeric IPv6 address or something else */ - size_t l; - char *p, s = 0; + int colon = 0; + int dot = 0; + int bracket = 0; + char c; - if (!addr) + if (!p) return 0; - p = strrchr(addr, ']'); - if (p) { - s = *p; - *p = 0; + + if (*p == '[') { + bracket = 1; + p++; } - l = strlen(addr); - if (p) - *p = s; - if (l<2) - return 0; - if (l != strspn(addr, "0123456789ABCDEFabcdef:.[")) - return 0; - p = strchr(addr, ':'); - if (p) { - p++; - p = strchr(addr, ':'); - if (p) - return 1; + + while ((c = *p++) && c != ']') { + switch (c) { + case ':': + colon++; + break; + case '.': + dot++; + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + break; + default: + return 0; /* Invalid character */ + } } - return 0; + + if (colon < 2 || colon > 7) + return 0; + + if (dot) { + /* An IPv4-mapped address in dot-quad form will have 3 dots */ + if (dot != 3) + return 0; + /* The IPv4-mapped address takes the space of one colon */ + if (colon > 6) + return 0; + } + + /* If bracketed, must be closed, and vice versa */ + if (bracket ^ (c == ']')) + return 0; + + /* Otherwise, assume we're okay */ + return 1; } /* strip [] from numeric IPv6 addreses */ diff --git a/common/tftpsubs.h b/common/tftpsubs.h index 887a4ab..b3a3bf3 100644 --- a/common/tftpsubs.h +++ b/common/tftpsubs.h @@ -74,15 +74,11 @@ union sock_addr { #endif #ifdef HAVE_IPV6 -int is_numeric_ipv6(char *); +int is_numeric_ipv6(const char *); char *strip_address(char *); #else #define is_numeric_ipv6(a) 0 - -static inline char *strip_address(char *addr) -{ - return addr; -} +#define strip_address(a) (a) #endif static inline int sa_set_port(union sock_addr *s, u_short port) |