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
|