//%2007//////////////////////////////////////////////////////////////////////// // // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems. // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.; // IBM Corp.; EMC Corporation, The Open Group. // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.; // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group. // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.; // EMC Corporation; VERITAS Software Corporation; The Open Group. // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.; // EMC Corporation; Symantec Corporation; The Open Group. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //============================================================================== // //%///////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include PEGASUS_NAMESPACE_BEGIN #if defined (PEGASUS_OS_TYPE_WINDOWS) || defined (PEGASUS_DISABLE_IPV6) /* Address conversion utility functions. */ /* Converts given "src" text address (Ex: 127.0.0.1) to equivalent binary form and stores in "dst" buffer (Ex 0x7f000001). Returns 1 if given ipv4 address is valid or returns -1 if invalid. Returns value in network byte order. */ static int _inet_ptonv4(const char *src, void *dst) { Boolean isValid = true; Uint16 octetValue[4] = {0}; // Check for valid IPV4 address. for (Uint32 octet = 1, i = 0; octet <= 4; octet++) { int j = 0; if (!(isascii(src[i]) && isdigit(src[i]))) { isValid = false; break; } while (isascii(src[i]) && isdigit(src[i])) { if (j == 3) { isValid = false; break; } octetValue[octet-1] = octetValue[octet-1]*10 + (src[i] - '0'); i++; j++; } if (octetValue[octet-1] > 255) { isValid = false; break; } // Check for invalid character in IP address if ((octet != 4) && (src[i++] != '.')) { isValid = false; break; } // Check for the case where it's a valid host name that happens // to have 4 (or more) leading all-numeric host segments. if ((octet == 4) && (src[i] != ':') && src[i] != char(0)) { isValid = false; break; } } if (!isValid) { return 0; } // Return the value in network byte order. Uint32 value; value = octetValue[0]; value = (value << 8) + octetValue[1]; value = (value << 8) + octetValue[2]; value = (value << 8) + octetValue[3]; value = htonl(value); memcpy (dst, &value, sizeof(Uint32)); return 1; } #ifndef PEGASUS_DISABLE_IPV6 /* Converts given ipv6 text address (ex. ::1) to binary form and stroes in "dst" buffer (ex. 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1). Returns 1 if src ipv6 address is valid or returns -1 if invalid. Returns value in network byte order. */ static int _inet_ptonv6(const char *src, void *dst) { int ccIndex = -1; int sNumber = 0; Uint16 sValues[8] = {0}; Boolean ipv4Mapped = false; while (*src && sNumber < 8) { if (*src == ':') { if (!*++src) { return 0; } if (*src == ':') { if (ccIndex != -1) { return 0; } ccIndex = sNumber; if (!*++src) { break; } } } if ((isalpha(*src) && tolower(*src) <= 'f') || isdigit(*src)) { // Check for ipv4 compatible ipv6 or ipv4 mapped ipv6 addresses if(!strchr(src, ':') && strchr(src, '.')) { if ( _inet_ptonv4 (src, sValues + sNumber) != 1) { return 0; } sNumber += 2; ipv4Mapped = true; break; } int chars = 0; while (*src && *src != ':') { if (chars++ == 4) { return 0; } if (!((isalpha(*src) && tolower(*src) <= 'f') || isdigit(*src))) { return 0; } sValues[sNumber] = sValues[sNumber] * 16 + (isdigit(*src) ? *src - '0' : (tolower(*src) - 'a' + 10)); ++src; } sValues[sNumber] = htons(sValues[sNumber]); ++sNumber; } else { return 0; } } if ((!ipv4Mapped &&*src) || (ccIndex == -1 && sNumber < 8) || (ccIndex != -1 && sNumber == 8) ) { return 0; } memset(dst, 0, sizeof(struct in6_addr)); for (int i = 0, j = 0; i < 8 ; ++i) { if (ccIndex == i) { i += 7 - sNumber; } else { memcpy ((char*) dst + i * 2, sValues + j++ , 2); } } return 1; } #endif /* Converts given ipv4 address in binary form to text form. Ex. 0x7f000001 to 127.0.0.1. */ static const char *_inet_ntopv4(const void *src, char *dst, Uint32 size) { Uint32 n; memset(dst, 0, size); memcpy(&n, src, sizeof (Uint32)); n = ntohl(n); sprintf(dst, "%u.%u.%u.%u", n >> 24 & 0xFF , n >> 16 & 0xFF, n >> 8 & 0xFF, n & 0xFF); return dst; } #ifndef PEGASUS_DISABLE_IPV6 /* Converts given ipv6 address in binary form to text form. Ex. 0000000000000001 to ::1. */ static const char *_inet_ntopv6(const void *src, char *dst, Uint32 size) { Uint16 n[8]; int ccIndex = -1; int maxZeroCnt = 0; int zeroCnt = 0; int index = 0; memcpy (n, src, sizeof (struct in6_addr)); memset(dst, 0, size); for (int i = 0; i < 8 ; ++i) { if (n[i]) { if (zeroCnt) { if (zeroCnt > maxZeroCnt) { ccIndex = index; maxZeroCnt = zeroCnt; } zeroCnt = index = 0; } n[i] = ntohs (n[i]); } else { if(!zeroCnt++) { if (ccIndex == -1) { ccIndex = i; } index = i; } } } char tmp[50]; *dst = 0; zeroCnt = 0; for (int i = 0; i < 8 ; ++i) { if (i == ccIndex) { sprintf(tmp, "::"); while ( i < 8 && !n[i]) { ++i; ++zeroCnt; } --i; } else { Boolean mapped = false; if (ccIndex == 0 && zeroCnt > 4) { // check for ipv4 mapped ipv6 and ipv4 compatible ipv6 // addresses. if (zeroCnt == 5 && n[i] == 0xffff) { strcat(dst,"ffff:"); mapped = true; } else if (zeroCnt == 6 && n[6]) { mapped = true; } } if (mapped) { Uint32 m; m = htons(n[7]); m = (m << 16) + htons(n[6]); HostAddress::convertBinaryToText(AF_INET, &m, tmp, 50); i += 2; } else { sprintf(tmp, i < 7 && ccIndex != i + 1 ? "%x:" : "%x", n[i]); } } strcat(dst,tmp); } return dst; } #endif #endif // defined (PEGASUS_OS_TYPE_WINDOWS) || defined (PEGASUS_DISABLE_IPV6) void HostAddress::_init() { _hostAddress = String::EMPTY; _hostAddrStr = String::EMPTY; _portNumber = PORT_UNSPECIFIED; _isValid = false; _addrType = AT_INVALID; } HostAddress::HostAddress() { _init(); } HostAddress::HostAddress(const String &addrStr) { _init(); _hostAddrStr = addrStr; _parseAddress(); } HostAddress& HostAddress::operator =(const HostAddress &rhs) { if (this != &rhs) { _hostAddress = rhs._hostAddress; _hostAddrStr = rhs._hostAddrStr; _portNumber = rhs._portNumber; _isValid = rhs._isValid; _addrType = rhs._addrType; } return *this; } HostAddress::HostAddress(const HostAddress &rhs) { *this = rhs; } HostAddress::~HostAddress() { } void HostAddress::setHostAddress(const String &addrStr) { _init(); _hostAddrStr = addrStr; _parseAddress(); } Uint32 HostAddress::getPort() { return _portNumber; } String HostAddress::getPortString() { char portStr[10]; sprintf(portStr, "%u", _portNumber); return String(portStr); } Uint32 HostAddress::getAddressType() { return _addrType; } Boolean HostAddress::isValid() { return _isValid; } String HostAddress::getHost() { return _hostAddress; } Boolean HostAddress::isPortSpecified() { return _portNumber != PORT_UNSPECIFIED && _portNumber != PORT_INVALID; } Boolean HostAddress::equal(int af, void *p1, void *p2) { switch (af) { #ifndef PEGASUS_DISABLE_IPV6 case AF_INET6: return !memcmp(p1, p2, sizeof(struct in6_addr)); #endif case AF_INET: return !memcmp(p1, p2, sizeof(struct in_addr)); } return false; } void HostAddress::_parseAddress() { if (_hostAddrStr == String::EMPTY) { _isValid = false; return; } Uint32 i = 0; #ifndef PEGASUS_DISABLE_IPV6 if (_hostAddrStr[0] == '[') { i = 1; while (_hostAddrStr[i] && _hostAddrStr[i] != ']') { ++i; } if (_hostAddrStr[i] == ']') { _hostAddress = _hostAddrStr.subString (1, i - 1); if( !(_isValid = isValidIPV6Address(_hostAddress))) { return; } _addrType = AT_IPV6; ++i; } else { _hostAddress = _hostAddrStr; return; } } else #endif if (!_isValid) { while (_hostAddrStr[i] && _hostAddrStr[i] != ':') { ++i; } _hostAddress = _hostAddrStr.subString(0, i); if( !(_isValid = isValidIPV4Address(_hostAddress))) { // Not a valid IPV4 address, check for valid hostName if(!(_isValid = isValidHostName(_hostAddress))) { return; } _addrType = AT_HOSTNAME; } else { _addrType = AT_IPV4; } } // Check for Port number. Uint32 port = 0; if (_hostAddrStr[i] == ':') { ++i; while (isascii(_hostAddrStr[i]) && isdigit(_hostAddrStr[i])) { port = port * 10 + ( _hostAddrStr[i] - '0' ); if (port > MAX_PORT_NUMBER) { _portNumber = PORT_INVALID; _isValid = false; return; } ++i; } if (_hostAddrStr[i-1] != ':' && _hostAddrStr[i] == char(0)) { _portNumber = port; } else { _portNumber = PORT_INVALID; _isValid = false; } } } #ifndef PEGASUS_DISABLE_IPV6 Boolean HostAddress::isValidIPV6Address (const String &ipv6Address) { CString addr = ipv6Address.getCString(); struct in6_addr iaddr; return 1 == convertTextToBinary(AF_INET6, (const char*) addr, (void*)&iaddr); } #endif Boolean HostAddress::isValidIPV4Address (const String &ipv4Address) { CString addr = ipv4Address.getCString(); struct in_addr iaddr; return 1 == convertTextToBinary(AF_INET, (const char*) addr, (void*)&iaddr); } Boolean HostAddress::isValidHostName (const String &hostName) { Uint32 i = 0; Boolean expectHostSegment = true; Boolean hostSegmentIsNumeric; while (expectHostSegment) { expectHostSegment = false; hostSegmentIsNumeric = true; // assume all-numeric host segment if (!(isascii(hostName[i]) && (isalnum(hostName[i]) || (hostName[i] == '_')))) { return false; } while (isascii(hostName[i]) && (isalnum(hostName[i]) || (hostName[i] == '-') || (hostName[i] == '_'))) { // If a non-digit is encountered, set "all-numeric" // flag to false if (isalpha(hostName[i]) || (hostName[i] == '-') || (hostName[i] == '_')) { hostSegmentIsNumeric = false; } i++; } if (hostName[i] == '.') { i++; expectHostSegment = true; } } // If the last Host Segment is all numeric, then return false. // RFC 1123 says "highest-level component label will be alphabetic". if (hostSegmentIsNumeric || hostName[i] != char(0)) { return false; } return true; } int HostAddress::convertTextToBinary(int af, const char *src, void *dst) { #ifdef PEGASUS_DISABLE_IPV6 if (af == AF_INET) { return _inet_ptonv4(src, dst); } return -1; #else #ifdef PEGASUS_OS_TYPE_UNIX return ::inet_pton(af, src, dst); #else if (af == AF_INET) { return _inet_ptonv4(src, dst); } else if(af == AF_INET6) { return _inet_ptonv6(src, dst); } else { return -1; // Unsupported address family. } #endif // PEGASUS_OS_TYPE_UNIX #endif // PEGASUS_DISABLE_IPV6 } const char * HostAddress::convertBinaryToText(int af, const void *src, char *dst, Uint32 size) { #ifdef PEGASUS_DISABLE_IPV6 if (af == AF_INET) { return _inet_ntopv4(src, dst, size); } return 0; #else #ifdef PEGASUS_OS_TYPE_UNIX return ::inet_ntop(af, src, dst, size); #else if (af == AF_INET) { return _inet_ntopv4(src, dst, size); } else if (af == AF_INET6) { return _inet_ntopv6(src, dst, size); } else { return 0; // Unsupported address family. } #endif // PEGASUS_OS_TYPE_UNIX #endif // PEGASUS_DISABLE_IPV6 } PEGASUS_NAMESPACE_END