(file) Return to HostAddress.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

  1 martin 1.4 //%LICENSE////////////////////////////////////////////////////////////////
  2 martin 1.5 //
  3 martin 1.4 // Licensed to The Open Group (TOG) under one or more contributor license
  4            // agreements.  Refer to the OpenPegasusNOTICE.txt file distributed with
  5            // this work for additional information regarding copyright ownership.
  6            // Each contributor licenses this file to you under the OpenPegasus Open
  7            // Source License; you may not use this file except in compliance with the
  8            // License.
  9 martin 1.5 //
 10 martin 1.4 // Permission is hereby granted, free of charge, to any person obtaining a
 11            // copy of this software and associated documentation files (the "Software"),
 12            // to deal in the Software without restriction, including without limitation
 13            // the rights to use, copy, modify, merge, publish, distribute, sublicense,
 14            // and/or sell copies of the Software, and to permit persons to whom the
 15            // Software is furnished to do so, subject to the following conditions:
 16 martin 1.5 //
 17 martin 1.4 // The above copyright notice and this permission notice shall be included
 18            // in all copies or substantial portions of the Software.
 19 martin 1.5 //
 20 martin 1.4 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 21 martin 1.5 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 22 martin 1.4 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 23            // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 24            // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 25            // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 26            // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 27 martin 1.5 //
 28 martin 1.4 //////////////////////////////////////////////////////////////////////////
 29 dave.sudlik 1.2 //
 30                 //%/////////////////////////////////////////////////////////////////////////////
 31                 
 32                 #include <Pegasus/Common/HostAddress.h>
 33 dev.meetei  1.7 #include <Pegasus/Common/Tracer.h>
 34 dave.sudlik 1.2 
 35                 PEGASUS_NAMESPACE_BEGIN
 36                 
 37                 #if defined (PEGASUS_OS_TYPE_WINDOWS) || !defined (PEGASUS_ENABLE_IPV6)
 38                 
 39                 /*
 40                     Address conversion utility functions.
 41                 */
 42                 
 43                 /*
 44 kumpf       1.6     Converts given "src" text address (Ex: 127.0.0.1) to equivalent binary form
 45 dave.sudlik 1.2     and stores in "dst"  buffer (Ex 0x7f000001). Returns 1 if given ipv4 address
 46                     is valid or returns -1 if invalid. Returns value in network byte order.
 47                 */
 48                 
 49                 static int _inet_ptonv4(const char *src, void *dst)
 50                 {
 51                     Boolean isValid = true;
 52                     Uint16 octetValue[4] = {0};
 53                      // Check for valid IPV4 address.
 54                     for (Uint32 octet = 1, i = 0; octet <= 4; octet++)
 55                     {
 56                         int j = 0;
 57                         if (!(isascii(src[i]) && isdigit(src[i])))
 58                         {
 59                             isValid = false;
 60                             break;
 61                         }
 62                         while (isascii(src[i]) && isdigit(src[i]))
 63                         {
 64                             if (j == 3)
 65                             {
 66 dave.sudlik 1.2                 isValid = false;
 67                                 break;
 68                             }
 69                             octetValue[octet-1] = octetValue[octet-1]*10 + (src[i] - '0');
 70                             i++;
 71                             j++;
 72                         }
 73                         if (octetValue[octet-1] > 255)
 74                         {
 75                             isValid = false;
 76                             break;
 77                         }
 78                         // Check for invalid character in IP address
 79                         if ((octet != 4) && (src[i++] != '.'))
 80                         {
 81                             isValid = false;
 82                             break;
 83                         }
 84                         // Check for the case where it's a valid host name that happens
 85                         // to have 4 (or more) leading all-numeric host segments.
 86                         if ((octet == 4) && (src[i] != ':') &&
 87 dave.sudlik 1.2             src[i] != char(0))
 88                         {
 89                             isValid = false;
 90                             break;
 91                         }
 92                     }
 93                     if (!isValid)
 94                     {
 95                         return 0;
 96                     }
 97                 
 98                     // Return the value in network byte order.
 99                     Uint32 value;
100                     value = octetValue[0];
101                     value = (value << 8) + octetValue[1];
102                     value = (value << 8) + octetValue[2];
103                     value = (value << 8) + octetValue[3];
104                     value = htonl(value);
105                     memcpy (dst, &value, sizeof(Uint32));
106                 
107                     return 1;
108 dave.sudlik 1.2 }
109                 
110                 /*
111 dev.meetei  1.7      Converts given ipv6 text address (ex. ::1) to binary form and stores
112 dave.sudlik 1.2      in "dst" buffer (ex. 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1). Returns 1
113                      if src ipv6 address is valid or returns -1 if invalid. Returns value
114                      in network byte order.
115                 */
116                 static int _inet_ptonv6(const char *src, void *dst)
117                 {
118                     int ccIndex = -1;
119                     int sNumber = 0;
120                     Uint16 sValues[8] = {0};
121 kumpf       1.6     Boolean ipv4Mapped = false;
122 dave.sudlik 1.2 
123                     while (*src && sNumber < 8)
124                     {
125                         if (*src == ':')
126                         {
127                             if (!*++src)
128                             {
129                                 return 0;
130 kumpf       1.6             }
131 dave.sudlik 1.2             if (*src == ':')
132                             {
133                                 if (ccIndex != -1)
134                                 {
135                                     return 0;
136                                 }
137                                 ccIndex = sNumber;
138                                 if (!*++src)
139                                 {
140                                     break;
141 kumpf       1.6                 }
142                             }
143                         }
144 dave.sudlik 1.2         if ((isalpha(*src) && tolower(*src) <= 'f') || isdigit(*src))
145                         {
146                             // Check for ipv4 compatible ipv6 or ipv4 mapped ipv6 addresses
147                             if(!strchr(src, ':') && strchr(src, '.'))
148                             {
149 kumpf       1.6                 if ( _inet_ptonv4 (src, sValues + sNumber) != 1)
150 dave.sudlik 1.2                 {
151                                     return 0;
152 kumpf       1.6                 }
153                                 sNumber += 2;
154 dave.sudlik 1.2                 ipv4Mapped = true;
155                                 break;
156                             }
157 kumpf       1.6             int chars = 0;
158 dave.sudlik 1.2             while (*src && *src != ':')
159                             {
160                                 if (chars++ == 4)
161                                 {
162                                     return 0;
163                                 }
164                                 if (!((isalpha(*src) && tolower(*src) <= 'f') || isdigit(*src)))
165                                 {
166                                     return 0;
167                                 }
168                                 sValues[sNumber] = sValues[sNumber] * 16 +
169                                     (isdigit(*src) ? *src - '0' : (tolower(*src) - 'a' + 10));
170                                 ++src;
171                             }
172                             sValues[sNumber] = htons(sValues[sNumber]);
173                             ++sNumber;
174                         }
175                         else
176                         {
177                             return 0;
178 kumpf       1.6         }
179 dave.sudlik 1.2     }
180                 
181 kumpf       1.6     if ((!ipv4Mapped &&*src) || (ccIndex == -1 && sNumber < 8) ||
182 dave.sudlik 1.2         (ccIndex != -1 && sNumber == 8) )
183                     {
184                         return 0;
185                     }
186                     memset(dst, 0, PEGASUS_IN6_ADDR_SIZE);
187                     for (int i = 0, j = 0; i < 8 ; ++i)
188                     {
189                         if (ccIndex == i)
190                         {
191                             i += 7 - sNumber;
192                         }
193                         else
194                         {
195                             memcpy ((char*) dst + i * 2, sValues + j++ , 2);
196                         }
197                     }
198                     return 1;
199                 }
200                 
201                 /*
202                     Converts given ipv4 address in binary form to text form. Ex. 0x7f000001
203 dave.sudlik 1.2     to 127.0.0.1.
204                 */
205                 static const char *_inet_ntopv4(const void *src, char *dst, Uint32 size)
206                 {
207                 
208                    Uint32 n;
209                 
210 kumpf       1.6    memset(dst, 0, size);
211                    memcpy(&n, src, sizeof (Uint32));
212 dave.sudlik 1.2    n = ntohl(n);
213 kumpf       1.6    sprintf(dst, "%u.%u.%u.%u", n >> 24 & 0xFF ,
214                        n >> 16 & 0xFF, n >> 8 & 0xFF, n & 0xFF);
215 dave.sudlik 1.2 
216 kumpf       1.6    return dst;
217 dave.sudlik 1.2 }
218                 
219 kumpf       1.6 /*
220                     Converts given ipv6 address in binary form to text form. Ex.
221 dave.sudlik 1.2     0000000000000001 to ::1.
222                 */
223                 static const char *_inet_ntopv6(const void *src, char *dst, Uint32 size)
224                 {
225                 
226                     Uint16 n[8];
227                     int ccIndex = -1;
228                     int maxZeroCnt = 0;
229                     int zeroCnt = 0;
230                     int index = 0;
231                 
232                     memcpy (n, src, PEGASUS_IN6_ADDR_SIZE);
233 kumpf       1.6     memset(dst, 0, size);
234 dave.sudlik 1.2     for (int i = 0; i < 8 ; ++i)
235                     {
236                         if (n[i])
237                         {
238                             if (zeroCnt)
239                             {
240                                 if (zeroCnt > maxZeroCnt)
241                                 {
242 kumpf       1.6                     ccIndex = index;
243 dave.sudlik 1.2                     maxZeroCnt = zeroCnt;
244                                 }
245                                 zeroCnt = index = 0;
246                             }
247                             n[i] = ntohs (n[i]);
248                         }
249                         else
250                         {
251                             if(!zeroCnt++)
252                             {
253                                 if (ccIndex == -1)
254                                 {
255 kumpf       1.6                     ccIndex = i;
256 dave.sudlik 1.2                 }
257                                 index = i;
258                             }
259                         }
260                     }
261 kumpf       1.6     char tmp[50];
262 dave.sudlik 1.2     *dst = 0;
263                     zeroCnt = 0;
264                 
265                     for (int i = 0; i < 8 ; ++i)
266                     {
267                         if (i == ccIndex)
268                         {
269                             sprintf(tmp, "::");
270                             while ( i < 8 && !n[i])
271                             {
272                                 ++i;
273                                 ++zeroCnt;
274                             }
275                             --i;
276 kumpf       1.6         }
277 dave.sudlik 1.2         else
278                         {
279                             Boolean mapped = false;
280                             if (ccIndex == 0 && zeroCnt > 4)
281                             {
282 kumpf       1.6                 // check for ipv4 mapped ipv6 and ipv4 compatible ipv6
283 dave.sudlik 1.2                 // addresses.
284                                 if (zeroCnt == 5 && n[i] == 0xffff)
285                                 {
286 kumpf       1.6                     strcat(dst,"ffff:");
287 dave.sudlik 1.2                     mapped = true;
288                                 }
289                                 else if (zeroCnt == 6 && n[6])
290                                 {
291                                     mapped = true;
292 kumpf       1.6                 }
293 dave.sudlik 1.2             }
294                             if (mapped)
295                             {
296                                 Uint32 m;
297                                 m = htons(n[7]);
298                                 m = (m << 16) + htons(n[6]);
299                                 HostAddress::convertBinaryToText(AF_INET, &m, tmp, 50);
300                                 i += 2;
301                             }
302                             else
303                             {
304                                 sprintf(tmp, i < 7 && ccIndex != i + 1 ? "%x:" : "%x", n[i]);
305                             }
306                         }
307                         strcat(dst,tmp);
308                     }
309                 
310                     return dst;
311                 }
312                 #endif  // defined (PEGASUS_OS_TYPE_WINDOWS) || !defined (PEGASUS_ENABLE_IPV6)
313                 
314 dev.meetei  1.7 HostAddress::HostAddress():    
315                     _hostAddrStr(),
316                     _addrType(AT_INVALID),
317                     _isValid(false),
318                     _isAddrLinkLocal(false),
319                     _scopeID(0)
320                     
321 dave.sudlik 1.2 {
322                 }
323                 
324                 HostAddress& HostAddress::operator =(const HostAddress &rhs)
325                 {
326                     if (this != &rhs)
327                     {
328                         _hostAddrStr = rhs._hostAddrStr;
329                         _isValid = rhs._isValid;
330                         _addrType = rhs._addrType;
331 dev.meetei  1.7         _scopeID = rhs._scopeID;
332                         _isAddrLinkLocal = rhs._isAddrLinkLocal;
333 dave.sudlik 1.2     }
334                 
335                     return *this;
336                 }
337                 
338                 HostAddress::HostAddress(const HostAddress &rhs)
339                 {
340                     *this = rhs;
341                 }
342                 
343                 HostAddress::~HostAddress()
344                 {
345                 }
346                 
347 dev.meetei  1.7 Boolean HostAddress::setHostAddress(const String &addrStr)
348 dave.sudlik 1.2 {
349 dev.meetei  1.7 
350                     if (addrStr.size() != 0)
351                     {
352                 
353                         if (isValidIPV4Address(addrStr))
354                         {
355                             _isValid = true;
356                             _addrType = AT_IPV4;
357                             _hostAddrStr = addrStr;
358                             _scopeID = 0;
359                             _isAddrLinkLocal = false;
360                             return _isValid;
361                         }
362                 
363                         if (isValidHostName(addrStr))
364                         {
365                             _isValid = true;
366                             _addrType = AT_HOSTNAME;
367                             _hostAddrStr = addrStr;
368                             _scopeID = 0;
369                             _isAddrLinkLocal = false;
370 dev.meetei  1.7             return _isValid;
371                         }
372                 
373                         if (_checkIPv6AndLinkLocal( addrStr ))
374                         {
375                             _isValid = true;
376                             _addrType = AT_IPV6;
377                             return _isValid;
378                         }
379                 
380                     } // if addrStr == 0 or no valid address specified.
381                 
382                     _hostAddrStr.clear();
383                     _isValid = false;
384                     _addrType = AT_INVALID;
385                     _scopeID = 0;
386                     _isAddrLinkLocal = false;
387                     return _isValid;
388 dave.sudlik 1.2 }
389                 
390 dev.meetei  1.7 Uint32 HostAddress::getAddressType() const
391 dave.sudlik 1.2 {
392                     return _addrType;
393                 }
394                 
395 dev.meetei  1.7 Boolean HostAddress::isValid() const
396 dave.sudlik 1.2 {
397                     return _isValid;
398                 }
399                 
400 dev.meetei  1.7 String HostAddress::getHost() const
401 dave.sudlik 1.2 {
402                     return _hostAddrStr;
403                 }
404                 
405                 Boolean HostAddress::equal(int af, void *p1, void *p2)
406                 {
407                     switch (af)
408                     {
409                         case AT_IPV6:
410                              return !memcmp(p1, p2, PEGASUS_IN6_ADDR_SIZE);
411                         case AT_IPV4:
412                              return !memcmp(p1, p2, sizeof(struct in_addr));
413 kumpf       1.6     }
414 dave.sudlik 1.2 
415                     return false;
416                 }
417                 
418 dev.meetei  1.7 Boolean HostAddress::_checkIPv6AndLinkLocal( const String &ip6add2check)
419 dave.sudlik 1.2 {
420 dev.meetei  1.7     _isValid = false;
421                     _isAddrLinkLocal = false;
422                     _scopeID = 0;
423 marek       1.3 
424 dev.meetei  1.7     String iptmp = ip6add2check;
425                     String tmp = iptmp.subString(0, 4);
426                     // If the IP address starts with "fe80" it is a link-local address
427                     if(String::equalNoCase(tmp, "fe80"))
428                     {
429                         Uint32 idx = iptmp.find('%');
430                         if(idx != PEG_NOT_FOUND)
431                         {
432                 #if defined PEGASUS_OS_TYPE_WINDOWS
433                             // On Windows the zone ID/inteface index for link-local is an 
434                             // integer value starting with 1.
435                             _scopeID = atoi(
436                                     (const char *)(iptmp.subString(idx+1).getCString()));
437                 #else
438                             // if_nametoindex() retruns 0 when zone ID was not valid/found.
439                             _scopeID = if_nametoindex(
440                                     (const char *)(iptmp.subString(idx+1).getCString()));
441                 #endif
442                             // The scope ID should not be 0, even RFC4007 specifies 0 as the 
443                             // default interface. But 
444                             if (0 == _scopeID) 
445 dev.meetei  1.7             {
446                                 PEG_TRACE((TRC_HTTP,Tracer::LEVEL1,
447                                     "The zone index of IPv6 link-local address %s is invalid.",
448                                     (const char*)ip6add2check.getCString()));
449                                 return false;
450                             }
451                             // Remove the zone id before checkeing for a valid IPv6 address.
452                             iptmp.remove(idx);
453                             _isAddrLinkLocal = true; 
454                         }
455                         else
456                         {
457                             PEG_TRACE((TRC_HTTP,Tracer::LEVEL1,
458                                 "The IPv6 link-local address %s has no zone index specified.",
459                                 (const char*)ip6add2check.getCString()));
460                             return false;
461                         }
462 kumpf       1.6     }
463 dev.meetei  1.7 
464                     if (isValidIPV6Address(iptmp))
465 dave.sudlik 1.2     {
466 dev.meetei  1.7         _hostAddrStr = iptmp;
467 marek       1.3         _isValid = true;
468 dev.meetei  1.7         return true;
469 dave.sudlik 1.2     }
470 dev.meetei  1.7     PEG_TRACE((TRC_HTTP,Tracer::LEVEL1,
471                         "Invalid IPv6 address %s specified.",
472                         (const char*)ip6add2check.getCString()));
473                     return false;
474                 }
475                 
476                 Uint32 HostAddress::getScopeID() const
477                 {
478                     return _scopeID;
479                 }
480                 
481                 Boolean HostAddress::isHostAddLinkLocal() const
482                 {
483                     return _isAddrLinkLocal;
484 dave.sudlik 1.2 }
485                 
486                 Boolean HostAddress::isValidIPV6Address (const String &ipv6Address)
487                 {
488 marek       1.3     const Uint16* p = (const Uint16*)ipv6Address.getChar16Data();
489                     int numColons = 0;
490                 
491                     while (*p)
492 dave.sudlik 1.2     {
493 marek       1.3         if (*p > 127)
494 dave.sudlik 1.2             return false;
495 marek       1.3 
496                         if (*p == ':')
497                             numColons++;
498                 
499                         p++;
500 dave.sudlik 1.2     }
501                 
502 marek       1.3     // No need to check whether IPV6 if no colons found.
503                 
504                     if (numColons == 0)
505                         return false;
506                 
507 dave.sudlik 1.2     CString addr = ipv6Address.getCString();
508                 #ifdef PEGASUS_ENABLE_IPV6
509                     struct in6_addr iaddr;
510                 #else
511                     char iaddr[PEGASUS_IN6_ADDR_SIZE];
512                 #endif
513 marek       1.3     return  convertTextToBinary(AT_IPV6, (const char*)addr, (void*)&iaddr) == 1;
514 dave.sudlik 1.2 }
515                 
516                 Boolean HostAddress::isValidIPV4Address (const String &ipv4Address)
517                 {
518 marek       1.3     const Uint16* src = (const Uint16*)ipv4Address.getChar16Data();
519                     Uint16 octetValue[4] = {0};
520                 
521                     for (Uint32 octet = 1, i = 0; octet <= 4; octet++)
522 dave.sudlik 1.2     {
523 marek       1.3         int j = 0;
524                 
525                         if (!(isascii(src[i]) && isdigit(src[i])))
526                             return false;
527                 
528                         while (isascii(src[i]) && isdigit(src[i]))
529 dave.sudlik 1.2         {
530 marek       1.3             if (j == 3)
531                                 return false;
532                 
533                             octetValue[octet-1] = octetValue[octet-1] * 10 + (src[i] - '0');
534                             i++;
535                             j++;
536                         }
537                 
538                         if (octetValue[octet-1] > 255)
539                             return false;
540                 
541                         if ((octet != 4) && (src[i++] != '.'))
542                             return false;
543                 
544                         if ((octet == 4) && (src[i] != ':') && src[i] != char(0))
545 dave.sudlik 1.2             return false;
546                     }
547 marek       1.3     return true;
548 dave.sudlik 1.2 }
549                 
550 marek       1.3 Boolean HostAddress::isValidHostName (const String &hostName_)
551 dave.sudlik 1.2 {
552 marek       1.3     const Uint16* hostName = (const Uint16*)hostName_.getChar16Data();
553                 
554 dave.sudlik 1.2     Uint32 i = 0;
555                     Boolean expectHostSegment = true;
556                     Boolean hostSegmentIsNumeric;
557                     while (expectHostSegment)
558                     {
559                         expectHostSegment = false;
560                         hostSegmentIsNumeric = true; // assume all-numeric host segment
561                         if (!(isascii(hostName[i]) &&
562                             (isalnum(hostName[i]) || (hostName[i] == '_'))))
563                         {
564                             return false;
565                         }
566                         while (isascii(hostName[i]) &&
567                             (isalnum(hostName[i]) || (hostName[i] == '-') ||
568                                 (hostName[i] == '_')))
569                         {
570                             // If a non-digit is encountered, set "all-numeric"
571                             // flag to false
572                             if (isalpha(hostName[i]) || (hostName[i] == '-') ||
573                                 (hostName[i] == '_'))
574                             {
575 dave.sudlik 1.2                 hostSegmentIsNumeric = false;
576                             }
577                             i++;
578                         }
579                         if (hostName[i] == '.')
580                         {
581                             i++;
582                             expectHostSegment = true;
583                         }
584                     }
585                     // If the last Host Segment is all numeric, then return false.
586                     // RFC 1123 says "highest-level component label will be alphabetic".
587                     if (hostSegmentIsNumeric || hostName[i] != char(0))
588                     {
589                         return false;
590                     }
591                 
592                     return true;
593                 }
594                 
595                 
596 dave.sudlik 1.2 int HostAddress::convertTextToBinary(int af, const char *src, void *dst)
597                 {
598                 #if defined (PEGASUS_OS_TYPE_WINDOWS) || !defined (PEGASUS_ENABLE_IPV6)
599                     if (af == AT_IPV4)
600                     {
601                         return _inet_ptonv4(src, dst);
602                     }
603                     else if(af == AT_IPV6)
604                     {
605                         return _inet_ptonv6(src, dst);
606                     }
607                     return -1; // Unsupported address family.
608                 #else
609                     return ::inet_pton(af, src, dst);
610 kumpf       1.6 #endif
611 dave.sudlik 1.2 }
612                 
613                 const char * HostAddress::convertBinaryToText(int af, const void *src,
614                     char *dst, Uint32 size)
615                 {
616                 #if defined (PEGASUS_OS_TYPE_WINDOWS) || !defined (PEGASUS_ENABLE_IPV6)
617                     if (af == AT_IPV6)
618                     {
619                         return _inet_ntopv6(src, dst, size);
620                     }
621                     else if (af == AT_IPV4)
622                     {
623                         return _inet_ntopv4(src, dst, size);
624                     }
625                     return 0; // Unsupported address family.
626                 #else
627                     return ::inet_ntop(af, src, dst, size);
628 kumpf       1.6 #endif
629 dave.sudlik 1.2 }
630                 
631                 PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2