diff --git a/src/Parser.c b/src/Parser.c index fbb6851..c232cba 100644 --- a/src/Parser.c +++ b/src/Parser.c @@ -126,11 +126,93 @@ ParseIPv4(char **str, char **out) return 1; } static int +IsIPv6Char(char c) +{ + return isxdigit(c) || c == ':' || c == '.'; +} +static int ParseIPv6(char **str, char **out) { - /* TODO */ - (void) str; - (void) out; + char *start; + size_t length; + char c; + + int filled = 0; + int digit = 0; + int digits = 0; + + start = *str; + length = 0; + + if (Iterate(str) != '[') + { + goto fail; + } + + while ((c = Iterate(str)) && IsIPv6Char(c)) + { + char *ipv4; + if (isxdigit(c)) + { + digit++; + length++; + continue; + } + if (c == ':') + { + if (**str == ':') + { + digit = 0; + if (!filled) + { + filled = 1; + length++; + c = Iterate(str); /* Skip over the character */ + continue; + } + /* RFC3513 says the following: + * > 'The "::" can only appear once in an address.' */ + *str = start; + return 0; + } + if (digit < 1 || digit > 4) + { + goto fail; + } + /* We do not have to check whenever the digit here is valid, + * because it has to be .*/ + digit = 0; + digits++; + + length++; + continue; + } + /* The only remaining character being '.', we are probably dealing + * with an IPv4 literal. */ + *str -= digit + 1; + length -= digit + 1; + if (ParseIPv4(str, &ipv4)) + { + length += strlen(ipv4); + Free(ipv4); + c = Iterate(str); + goto end; + } + } +end: + --(*str); + if (Iterate(str) != ']') + { + goto fail; + } + + length = (size_t) (*str - start); + *out = Malloc(length + 1); + memcpy(*out, start, length); + + return 1; +fail: + *str = start; return 0; } static int