// // IsValidStrict // // Determine whether a name is a valid IPv6 address. Rules are: // // * 8 groups of 16-bit hex numbers, separated by ':' // * a *single* run of zeros can be compressed using the symbol '::' // * an optional string of a ScopeID delimited by '%' // * the last 32 bits in an address can be represented as an IPv4 address // // Difference between IsValid() and IsValidStrict() is that IsValid() expects part of the string to // be ipv6 address where as IsValidStrict() expects strict ipv6 address. // // Inputs: // <argument> name // IPv6 address in string format // // Outputs: // Nothing // // Assumes: // the correct name is terminated by ']' character // // Returns: // true if <name> is IPv6 address, else false // // Throws: // Nothing // // Remarks: MUST NOT be used unless all input indexes are verified and trusted. // start must be next to '[' position, or error is reported internal unsafe static bool IsValidStrict(char *name, int start, ref int end) { int sequenceCount = 0; int sequenceLength = 0; bool haveCompressor = false; bool haveIPv4Address = false; bool expectingNumber = true; int lastSequence = 1; bool needsClosingBracket = false; if (start < end && name[start] == '[') { start++; needsClosingBracket = true; } int i; for (i = start; i < end; ++i) { if (Uri.IsHexDigit(name[i])) { ++sequenceLength; expectingNumber = false; } else { if (sequenceLength > 4) { return(false); } if (sequenceLength != 0) { ++sequenceCount; lastSequence = i - sequenceLength; sequenceLength = 0; } switch (name[i]) { case '%': while (i + 1 < end) { i++; if (name[i] == ']') { goto case ']'; } else if (name[i] == '/') { goto case '/'; } else if (name[i] < '0' || name[i] > '9') { // scope ID must only contain digits return(false); } } break; case ']': if (!needsClosingBracket) { return(false); } needsClosingBracket = false; // If there's more after the closing bracket, it must be a port. // We don't use the port, but we still validate it. if (i + 1 < end && name[i + 1] != ':') { return(false); } // If there is a port, it must either be a hexadecimal or decimal number. if (i + 3 < end && name[i + 2] == '0' && name[i + 3] == 'x') { i += 4; for (; i < end; i++) { if (!Uri.IsHexDigit(name[i])) { return(false); } } } else { i += 2; for (; i < end; i++) { if (name[i] < '0' || name[i] > '9') { return(false); } } } continue; case ':': if ((i > 0) && (name[i - 1] == ':')) { if (haveCompressor) { // can only have one per IPv6 address return(false); } haveCompressor = true; expectingNumber = false; } else { expectingNumber = true; } break; case '/': return(false); case '.': if (haveIPv4Address) { return(false); } i = end; if (!IPv4AddressHelper.IsValid(name, lastSequence, ref i, true, false, false)) { return(false); } // ipv4 address takes 2 slots in ipv6 address, one was just counted meeting the '.' ++sequenceCount; lastSequence = i - sequenceLength; sequenceLength = 0; haveIPv4Address = true; --i; // it will be incremented back on the next loop break; default: return(false); } sequenceLength = 0; } } if (sequenceLength != 0) { if (sequenceLength > 4) { return(false); } ++sequenceCount; } // these sequence counts are -1 because it is implied in end-of-sequence const int ExpectedSequenceCount = 8; return (!expectingNumber && (haveCompressor ? (sequenceCount < ExpectedSequenceCount) : (sequenceCount == ExpectedSequenceCount)) && !needsClosingBracket); }
// // IsValid // // Determine whether a name is a valid IPv6 address. Rules are: // // * 8 groups of 16-bit hex numbers, separated by ':' // * a *single* run of zeros can be compressed using the symbol '::' // * an optional string of a ScopeID delimited by '%' // * an optional (last) 1 or 2 character prefix length field delimited by '/' // * the last 32 bits in an address can be represented as an IPv4 address // // Inputs: // <argument> name // Domain name field of a URI to check for pattern match with // IPv6 address // // Outputs: // Nothing // // Assumes: // the correct name is terminated by ']' character // // Returns: // true if <name> has IPv6 format, else false // // Throws: // Nothing // // Remarks: MUST NOT be used unless all input indexes are are verified and trusted. // start must be next to '[' position, or error is reported internal unsafe static bool IsValid(char *name, int start, ref int end) { int sequenceCount = 0; int sequenceLength = 0; bool haveCompressor = false; bool haveIPv4Address = false; bool havePrefix = false; bool expectingNumber = true; int lastSequence = 1; int i; for (i = start; i < end; ++i) { if (havePrefix ? (name[i] >= '0' && name[i] <= '9') : Uri.IsHexDigit(name[i])) { ++sequenceLength; expectingNumber = false; } else { if (sequenceLength > 4) { return(false); } if (sequenceLength != 0) { ++sequenceCount; lastSequence = i - sequenceLength; } switch (name[i]) { case '%': while (true) { //accept anything in scopeID if (++i == end) { // no closing ']', fail return(false); } if (name[i] == ']') { goto case ']'; } else if (name[i] == '/') { goto case '/'; } } case ']': start = i; i = end; //this will make i = end+1 continue; case ':': if ((i > 0) && (name[i - 1] == ':')) { if (haveCompressor) { // // can only have one per IPv6 address // return(false); } haveCompressor = true; expectingNumber = false; } else { expectingNumber = true; } break; case '/': if ((sequenceCount == 0) || havePrefix) { return(false); } havePrefix = true; expectingNumber = true; break; case '.': if (haveIPv4Address) { return(false); } i = end; if (!IPv4AddressHelper.IsValid(name, lastSequence, ref i, true, false)) { return(false); } // ipv4 address takes 2 slots in ipv6 address, one was just counted meeting the '.' ++sequenceCount; haveIPv4Address = true; --i; // it will be incremented back on the next loop break; default: return(false); } sequenceLength = 0; } } // // if the last token was a prefix, check number of digits // if (havePrefix && ((sequenceLength < 1) || (sequenceLength > 2))) { return(false); } // // these sequence counts are -1 because it is implied in end-of-sequence // int expectedSequenceCount = 8 + (havePrefix ? 1 : 0); if (!expectingNumber && (sequenceLength <= 4) && (haveCompressor ? (sequenceCount < expectedSequenceCount) : (sequenceCount == expectedSequenceCount))) { if (i == end + 1) { // ']' was found end = start + 1; return(true); } return(false); } return(false); }
private static unsafe bool InternalIsValid(char *name, int start, ref int end, bool validateStrictAddress) { int num = 0; int num2 = 0; bool flag = false; bool flag2 = false; bool flag3 = false; bool flag4 = true; int num3 = 1; int index = start; while (index < end) { if (flag3 ? ((name[index] >= '0') && (name[index] <= '9')) : Uri.IsHexDigit(name[index])) { num2++; flag4 = false; goto Label_013F; } if (num2 <= 4) { if (num2 != 0) { num++; num3 = index - num2; } switch (name[index]) { case ':': if ((index <= 0) || (name[index - 1] != ':')) { goto Label_00F9; } if (flag) { return(false); } flag = true; flag4 = false; goto Label_013D; case ']': goto Label_00D0; case '.': if (!flag2) { goto Label_0119; } return(false); case '/': goto Label_00FE; case '%': goto Label_00A9; } } return(false); Label_00A9: if (++index == end) { return(false); } if (name[index] != ']') { if (name[index] != '/') { goto Label_00A9; } goto Label_00FE; } Label_00D0: start = index; index = end; goto Label_013F; Label_00F9: flag4 = true; goto Label_013D; Label_00FE: if (validateStrictAddress) { return(false); } if ((num == 0) || flag3) { return(false); } flag3 = true; flag4 = true; goto Label_013D; Label_0119: index = end; if (!IPv4AddressHelper.IsValid(name, num3, ref index, true, false)) { return(false); } num++; flag2 = true; index--; Label_013D: num2 = 0; Label_013F: index++; } if (!flag3 || ((num2 >= 1) && (num2 <= 2))) { int num5 = 8 + (flag3 ? 1 : 0); if ((flag4 || (num2 > 4)) || !(flag ? (num < num5) : (num == num5))) { return(false); } if (index == (end + 1)) { end = start + 1; return(true); } } return(false); }