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
34 PEGASUS_NAMESPACE_BEGIN
35
36 #if defined (PEGASUS_OS_TYPE_WINDOWS) || !defined (PEGASUS_ENABLE_IPV6)
37
38 /*
39 Address conversion utility functions.
40 */
41
42 /*
|
43 kumpf 1.6 Converts given "src" text address (Ex: 127.0.0.1) to equivalent binary form
|
44 dave.sudlik 1.2 and stores in "dst" buffer (Ex 0x7f000001). Returns 1 if given ipv4 address
45 is valid or returns -1 if invalid. Returns value in network byte order.
46 */
47
48 static int _inet_ptonv4(const char *src, void *dst)
49 {
50 Boolean isValid = true;
51 Uint16 octetValue[4] = {0};
52 // Check for valid IPV4 address.
53 for (Uint32 octet = 1, i = 0; octet <= 4; octet++)
54 {
55 int j = 0;
56 if (!(isascii(src[i]) && isdigit(src[i])))
57 {
58 isValid = false;
59 break;
60 }
61 while (isascii(src[i]) && isdigit(src[i]))
62 {
63 if (j == 3)
64 {
65 dave.sudlik 1.2 isValid = false;
66 break;
67 }
68 octetValue[octet-1] = octetValue[octet-1]*10 + (src[i] - '0');
69 i++;
70 j++;
71 }
72 if (octetValue[octet-1] > 255)
73 {
74 isValid = false;
75 break;
76 }
77 // Check for invalid character in IP address
78 if ((octet != 4) && (src[i++] != '.'))
79 {
80 isValid = false;
81 break;
82 }
83 // Check for the case where it's a valid host name that happens
84 // to have 4 (or more) leading all-numeric host segments.
85 if ((octet == 4) && (src[i] != ':') &&
86 dave.sudlik 1.2 src[i] != char(0))
87 {
88 isValid = false;
89 break;
90 }
91 }
92 if (!isValid)
93 {
94 return 0;
95 }
96
97 // Return the value in network byte order.
98 Uint32 value;
99 value = octetValue[0];
100 value = (value << 8) + octetValue[1];
101 value = (value << 8) + octetValue[2];
102 value = (value << 8) + octetValue[3];
103 value = htonl(value);
104 memcpy (dst, &value, sizeof(Uint32));
105
106 return 1;
107 dave.sudlik 1.2 }
108
109 /*
110 Converts given ipv6 text address (ex. ::1) to binary form and stroes
111 in "dst" buffer (ex. 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1). Returns 1
112 if src ipv6 address is valid or returns -1 if invalid. Returns value
113 in network byte order.
114 */
115 static int _inet_ptonv6(const char *src, void *dst)
116 {
117 int ccIndex = -1;
118 int sNumber = 0;
119 Uint16 sValues[8] = {0};
|
120 kumpf 1.6 Boolean ipv4Mapped = false;
|
121 dave.sudlik 1.2
122 while (*src && sNumber < 8)
123 {
124 if (*src == ':')
125 {
126 if (!*++src)
127 {
128 return 0;
|
129 kumpf 1.6 }
|
130 dave.sudlik 1.2 if (*src == ':')
131 {
132 if (ccIndex != -1)
133 {
134 return 0;
135 }
136 ccIndex = sNumber;
137 if (!*++src)
138 {
139 break;
|
140 kumpf 1.6 }
141 }
142 }
|
143 dave.sudlik 1.2 if ((isalpha(*src) && tolower(*src) <= 'f') || isdigit(*src))
144 {
145 // Check for ipv4 compatible ipv6 or ipv4 mapped ipv6 addresses
146 if(!strchr(src, ':') && strchr(src, '.'))
147 {
|
148 kumpf 1.6 if ( _inet_ptonv4 (src, sValues + sNumber) != 1)
|
149 dave.sudlik 1.2 {
150 return 0;
|
151 kumpf 1.6 }
152 sNumber += 2;
|
153 dave.sudlik 1.2 ipv4Mapped = true;
154 break;
155 }
|
156 kumpf 1.6 int chars = 0;
|
157 dave.sudlik 1.2 while (*src && *src != ':')
158 {
159 if (chars++ == 4)
160 {
161 return 0;
162 }
163 if (!((isalpha(*src) && tolower(*src) <= 'f') || isdigit(*src)))
164 {
165 return 0;
166 }
167 sValues[sNumber] = sValues[sNumber] * 16 +
168 (isdigit(*src) ? *src - '0' : (tolower(*src) - 'a' + 10));
169 ++src;
170 }
171 sValues[sNumber] = htons(sValues[sNumber]);
172 ++sNumber;
173 }
174 else
175 {
176 return 0;
|
177 kumpf 1.6 }
|
178 dave.sudlik 1.2 }
179
|
180 kumpf 1.6 if ((!ipv4Mapped &&*src) || (ccIndex == -1 && sNumber < 8) ||
|
181 dave.sudlik 1.2 (ccIndex != -1 && sNumber == 8) )
182 {
183 return 0;
184 }
185 memset(dst, 0, PEGASUS_IN6_ADDR_SIZE);
186 for (int i = 0, j = 0; i < 8 ; ++i)
187 {
188 if (ccIndex == i)
189 {
190 i += 7 - sNumber;
191 }
192 else
193 {
194 memcpy ((char*) dst + i * 2, sValues + j++ , 2);
195 }
196 }
197 return 1;
198 }
199
200 /*
201 Converts given ipv4 address in binary form to text form. Ex. 0x7f000001
202 dave.sudlik 1.2 to 127.0.0.1.
203 */
204 static const char *_inet_ntopv4(const void *src, char *dst, Uint32 size)
205 {
206
207 Uint32 n;
208
|
209 kumpf 1.6 memset(dst, 0, size);
210 memcpy(&n, src, sizeof (Uint32));
|
211 dave.sudlik 1.2 n = ntohl(n);
|
212 kumpf 1.6 sprintf(dst, "%u.%u.%u.%u", n >> 24 & 0xFF ,
213 n >> 16 & 0xFF, n >> 8 & 0xFF, n & 0xFF);
|
214 dave.sudlik 1.2
|
215 kumpf 1.6 return dst;
|
216 dave.sudlik 1.2 }
217
|
218 kumpf 1.6 /*
219 Converts given ipv6 address in binary form to text form. Ex.
|
220 dave.sudlik 1.2 0000000000000001 to ::1.
221 */
222 static const char *_inet_ntopv6(const void *src, char *dst, Uint32 size)
223 {
224
225 Uint16 n[8];
226 int ccIndex = -1;
227 int maxZeroCnt = 0;
228 int zeroCnt = 0;
229 int index = 0;
230
231 memcpy (n, src, PEGASUS_IN6_ADDR_SIZE);
|
232 kumpf 1.6 memset(dst, 0, size);
|
233 dave.sudlik 1.2 for (int i = 0; i < 8 ; ++i)
234 {
235 if (n[i])
236 {
237 if (zeroCnt)
238 {
239 if (zeroCnt > maxZeroCnt)
240 {
|
241 kumpf 1.6 ccIndex = index;
|
242 dave.sudlik 1.2 maxZeroCnt = zeroCnt;
243 }
244 zeroCnt = index = 0;
245 }
246 n[i] = ntohs (n[i]);
247 }
248 else
249 {
250 if(!zeroCnt++)
251 {
252 if (ccIndex == -1)
253 {
|
254 kumpf 1.6 ccIndex = i;
|
255 dave.sudlik 1.2 }
256 index = i;
257 }
258 }
259 }
|
260 kumpf 1.6 char tmp[50];
|
261 dave.sudlik 1.2 *dst = 0;
262 zeroCnt = 0;
263
264 for (int i = 0; i < 8 ; ++i)
265 {
266 if (i == ccIndex)
267 {
268 sprintf(tmp, "::");
269 while ( i < 8 && !n[i])
270 {
271 ++i;
272 ++zeroCnt;
273 }
274 --i;
|
275 kumpf 1.6 }
|
276 dave.sudlik 1.2 else
277 {
278 Boolean mapped = false;
279 if (ccIndex == 0 && zeroCnt > 4)
280 {
|
281 kumpf 1.6 // check for ipv4 mapped ipv6 and ipv4 compatible ipv6
|
282 dave.sudlik 1.2 // addresses.
283 if (zeroCnt == 5 && n[i] == 0xffff)
284 {
|
285 kumpf 1.6 strcat(dst,"ffff:");
|
286 dave.sudlik 1.2 mapped = true;
287 }
288 else if (zeroCnt == 6 && n[6])
289 {
290 mapped = true;
|
291 kumpf 1.6 }
|
292 dave.sudlik 1.2 }
293 if (mapped)
294 {
295 Uint32 m;
296 m = htons(n[7]);
297 m = (m << 16) + htons(n[6]);
298 HostAddress::convertBinaryToText(AF_INET, &m, tmp, 50);
299 i += 2;
300 }
301 else
302 {
303 sprintf(tmp, i < 7 && ccIndex != i + 1 ? "%x:" : "%x", n[i]);
304 }
305 }
306 strcat(dst,tmp);
307 }
308
309 return dst;
310 }
311 #endif // defined (PEGASUS_OS_TYPE_WINDOWS) || !defined (PEGASUS_ENABLE_IPV6)
312
313 dave.sudlik 1.2 void HostAddress::_init()
314 {
315 _hostAddrStr = String::EMPTY;
316 _isValid = false;
317 _addrType = AT_INVALID;
318 }
319
320 HostAddress::HostAddress()
321 {
322 _init();
323 }
324
325 HostAddress::HostAddress(const String &addrStr)
326 {
327 _init();
328 _hostAddrStr = addrStr;
329 _parseAddress();
330 }
331
332 HostAddress& HostAddress::operator =(const HostAddress &rhs)
333 {
334 dave.sudlik 1.2 if (this != &rhs)
335 {
336 _hostAddrStr = rhs._hostAddrStr;
337 _isValid = rhs._isValid;
338 _addrType = rhs._addrType;
339 }
340
341 return *this;
342 }
343
344 HostAddress::HostAddress(const HostAddress &rhs)
345 {
346 *this = rhs;
347 }
348
349 HostAddress::~HostAddress()
350 {
351 }
352
353 void HostAddress::setHostAddress(const String &addrStr)
354 {
355 dave.sudlik 1.2 _init();
356 _hostAddrStr = addrStr;
357 _parseAddress();
358 }
359
360 Uint32 HostAddress::getAddressType()
361 {
362 return _addrType;
363 }
364
365 Boolean HostAddress::isValid()
366 {
367 return _isValid;
368 }
369
370 String HostAddress::getHost()
371 {
372 return _hostAddrStr;
373 }
374
375 Boolean HostAddress::equal(int af, void *p1, void *p2)
376 dave.sudlik 1.2 {
377 switch (af)
378 {
379 case AT_IPV6:
380 return !memcmp(p1, p2, PEGASUS_IN6_ADDR_SIZE);
381 case AT_IPV4:
382 return !memcmp(p1, p2, sizeof(struct in_addr));
|
383 kumpf 1.6 }
|
384 dave.sudlik 1.2
385 return false;
386 }
387
388 void HostAddress::_parseAddress()
389 {
|
390 marek 1.3 if (_hostAddrStr.size() == 0)
391 return;
392
393 if (isValidIPV4Address(_hostAddrStr))
|
394 dave.sudlik 1.2 {
|
395 marek 1.3 _isValid = true;
396 _addrType = AT_IPV4;
|
397 kumpf 1.6 }
|
398 marek 1.3 else if (isValidIPV6Address(_hostAddrStr))
|
399 dave.sudlik 1.2 {
|
400 marek 1.3 _isValid = true;
|
401 dave.sudlik 1.2 _addrType = AT_IPV6;
|
402 kumpf 1.6 }
|
403 marek 1.3 else if (isValidHostName(_hostAddrStr))
|
404 dave.sudlik 1.2 {
|
405 marek 1.3 _isValid = true;
|
406 dave.sudlik 1.2 _addrType = AT_HOSTNAME;
407 }
408 }
409
410 Boolean HostAddress::isValidIPV6Address (const String &ipv6Address)
411 {
|
412 marek 1.3 const Uint16* p = (const Uint16*)ipv6Address.getChar16Data();
413 int numColons = 0;
414
415 while (*p)
|
416 dave.sudlik 1.2 {
|
417 marek 1.3 if (*p > 127)
|
418 dave.sudlik 1.2 return false;
|
419 marek 1.3
420 if (*p == ':')
421 numColons++;
422
423 p++;
|
424 dave.sudlik 1.2 }
425
|
426 marek 1.3 // No need to check whether IPV6 if no colons found.
427
428 if (numColons == 0)
429 return false;
430
|
431 dave.sudlik 1.2 CString addr = ipv6Address.getCString();
432 #ifdef PEGASUS_ENABLE_IPV6
433 struct in6_addr iaddr;
434 #else
435 char iaddr[PEGASUS_IN6_ADDR_SIZE];
436 #endif
|
437 marek 1.3 return convertTextToBinary(AT_IPV6, (const char*)addr, (void*)&iaddr) == 1;
|
438 dave.sudlik 1.2 }
439
440 Boolean HostAddress::isValidIPV4Address (const String &ipv4Address)
441 {
|
442 marek 1.3 const Uint16* src = (const Uint16*)ipv4Address.getChar16Data();
443 Uint16 octetValue[4] = {0};
444
445 for (Uint32 octet = 1, i = 0; octet <= 4; octet++)
|
446 dave.sudlik 1.2 {
|
447 marek 1.3 int j = 0;
448
449 if (!(isascii(src[i]) && isdigit(src[i])))
450 return false;
451
452 while (isascii(src[i]) && isdigit(src[i]))
|
453 dave.sudlik 1.2 {
|
454 marek 1.3 if (j == 3)
455 return false;
456
457 octetValue[octet-1] = octetValue[octet-1] * 10 + (src[i] - '0');
458 i++;
459 j++;
460 }
461
462 if (octetValue[octet-1] > 255)
463 return false;
464
465 if ((octet != 4) && (src[i++] != '.'))
466 return false;
467
468 if ((octet == 4) && (src[i] != ':') && src[i] != char(0))
|
469 dave.sudlik 1.2 return false;
470 }
471
|
472 marek 1.3 return true;
|
473 dave.sudlik 1.2 }
474
|
475 marek 1.3 Boolean HostAddress::isValidHostName (const String &hostName_)
|
476 dave.sudlik 1.2 {
|
477 marek 1.3 const Uint16* hostName = (const Uint16*)hostName_.getChar16Data();
478
|
479 dave.sudlik 1.2 Uint32 i = 0;
480 Boolean expectHostSegment = true;
481 Boolean hostSegmentIsNumeric;
482 while (expectHostSegment)
483 {
484 expectHostSegment = false;
485 hostSegmentIsNumeric = true; // assume all-numeric host segment
486 if (!(isascii(hostName[i]) &&
487 (isalnum(hostName[i]) || (hostName[i] == '_'))))
488 {
489 return false;
490 }
491 while (isascii(hostName[i]) &&
492 (isalnum(hostName[i]) || (hostName[i] == '-') ||
493 (hostName[i] == '_')))
494 {
495 // If a non-digit is encountered, set "all-numeric"
496 // flag to false
497 if (isalpha(hostName[i]) || (hostName[i] == '-') ||
498 (hostName[i] == '_'))
499 {
500 dave.sudlik 1.2 hostSegmentIsNumeric = false;
501 }
502 i++;
503 }
504 if (hostName[i] == '.')
505 {
506 i++;
507 expectHostSegment = true;
508 }
509 }
510 // If the last Host Segment is all numeric, then return false.
511 // RFC 1123 says "highest-level component label will be alphabetic".
512 if (hostSegmentIsNumeric || hostName[i] != char(0))
513 {
514 return false;
515 }
516
517 return true;
518 }
519
520
521 dave.sudlik 1.2 int HostAddress::convertTextToBinary(int af, const char *src, void *dst)
522 {
523 #if defined (PEGASUS_OS_TYPE_WINDOWS) || !defined (PEGASUS_ENABLE_IPV6)
524 if (af == AT_IPV4)
525 {
526 return _inet_ptonv4(src, dst);
527 }
528 else if(af == AT_IPV6)
529 {
530 return _inet_ptonv6(src, dst);
531 }
532 return -1; // Unsupported address family.
533 #else
534 return ::inet_pton(af, src, dst);
|
535 kumpf 1.6 #endif
|
536 dave.sudlik 1.2 }
537
538 const char * HostAddress::convertBinaryToText(int af, const void *src,
539 char *dst, Uint32 size)
540 {
541 #if defined (PEGASUS_OS_TYPE_WINDOWS) || !defined (PEGASUS_ENABLE_IPV6)
542 if (af == AT_IPV6)
543 {
544 return _inet_ntopv6(src, dst, size);
545 }
546 else if (af == AT_IPV4)
547 {
548 return _inet_ntopv4(src, dst, size);
549 }
550 return 0; // Unsupported address family.
551 #else
552 return ::inet_ntop(af, src, dst, size);
|
553 kumpf 1.6 #endif
|
554 dave.sudlik 1.2 }
555
556 PEGASUS_NAMESPACE_END
|