Coverage Report

Created: 2023-09-25 06:23

/src/resiprocate/rutil/DnsUtil.cxx
Line
Count
Source (jump to first uncovered line)
1
#ifdef HAVE_CONFIG_H
2
#include "config.h"
3
#endif
4
5
#if !defined(WIN32)
6
#if defined(__SUNPRO_CC) || defined (__sun__)
7
#define BSD_COMP /* !rk! needed to enable SIOCGIFCONF */
8
#endif
9
#include <sys/types.h>
10
#include <sys/socket.h>
11
#include <netinet/in.h>
12
#include <arpa/inet.h>
13
#include <sys/ioctl.h>
14
#include <net/if.h>
15
#include <errno.h>
16
#include <netdb.h>
17
#endif
18
19
#include <stdio.h>
20
#include <memory>
21
22
#include "rutil/compat.hxx"
23
#include "rutil/Socket.hxx"
24
#include "rutil/DnsUtil.hxx"
25
#include "rutil/Logger.hxx"
26
#include "rutil/Inserter.hxx"
27
#include "rutil/WinCompat.hxx"
28
#include "rutil/WinLeakCheck.hxx"
29
30
#define RESIPROCATE_SUBSYSTEM resip::Subsystem::DNS
31
32
#ifndef MAXHOSTNAMELEN
33
0
#define MAXHOSTNAMELEN 256
34
#endif
35
36
using namespace resip;
37
using namespace std;
38
39
40
list<Data> 
41
DnsUtil::lookupARecords(const Data& host)
42
0
{
43
0
   list<Data> names;
44
45
0
   if (DnsUtil::isIpV4Address(host))
46
0
   {
47
0
      names.push_back(host);
48
0
      return names;
49
0
   }
50
51
0
   struct hostent* result=0;
52
0
   int ret=0;
53
0
   int herrno=0;
54
55
0
#if defined(__linux__)
56
0
   struct hostent hostbuf; 
57
0
   char buffer[8192];
58
0
   ret = gethostbyname_r( host.c_str(), &hostbuf, buffer, sizeof(buffer), &result, &herrno);
59
0
   resip_assert (ret != ERANGE);
60
#elif defined(__QNX__) || defined(__SUNPRO_CC)
61
   struct hostent hostbuf; 
62
   char buffer[8192];
63
   result = gethostbyname_r( host.c_str(), &hostbuf, buffer, sizeof(buffer), &herrno );
64
#elif defined(__APPLE__)
65
   // gethostbyname in os/x is thread-safe...
66
   // http://developer.apple.com/technotes/tn2002/pdf/tn2053.pdf
67
   result = gethostbyname( host.c_str() );
68
   ret = (result == 0);
69
#else
70
   resip_assert(0);
71
   return names;
72
#endif
73
   
74
0
   if (ret != 0 || result == 0)
75
0
   {
76
0
      Data msg;
77
0
      switch (herrno)
78
0
      {
79
0
         case HOST_NOT_FOUND:
80
0
            msg = "host not found: ";
81
0
            break;
82
0
         case NO_DATA:
83
0
            msg = "no data found for: ";
84
0
            break;
85
0
         case NO_RECOVERY:
86
0
            msg = "no recovery lookup up: ";
87
0
            break;
88
0
         case TRY_AGAIN:
89
0
            msg = "try again: ";
90
0
            break;
91
0
      }
92
0
      msg += host;
93
94
0
      DebugLog (<< "DNS lookup of " << host << " resulted in " << msg);
95
0
      throw Exception("no dns resolution:" + msg, __FILE__, __LINE__);
96
0
   }
97
0
   else
98
0
   {
99
0
      resip_assert(result);
100
0
      resip_assert(result->h_length == 4);
101
0
      char str[256];
102
0
      for (char** pptr = result->h_addr_list; *pptr != 0; pptr++)
103
0
      {
104
0
         inet_ntop(result->h_addrtype, (u_int32_t*)(*pptr), str, sizeof(str));
105
0
         names.push_back(str);
106
0
      }
107
108
0
      StackLog (<< "DNS lookup of " << host << ": canonical name: " << result->h_name 
109
0
                << " "
110
0
                << Inserter(names));
111
      
112
0
      return names;
113
0
   }
114
0
}
115
116
const Data&
117
DnsUtil::getLocalHostName()
118
0
{
119
   // The function-local static ensures we can initialize the static storage of
120
   // localHostName at runtime, instead of at global static initialization time.
121
   // Under windows, when building a DLL you cannot call initNetwork and 
122
   // other socket API's reliably from DLLMain, so we need to delay this call.
123
   // We rely on C++11 thread-safe initialization guarantees for local statics
124
   // to ensure that the localHostName is initialized in a thread-safe
125
   // manner exactly once before use, even if the initial getLocalHostName() is
126
   // invoked by multiple threads. Since localHostName is immutable, the returned
127
   // variable reference can be safely read by multiple threads.
128
0
   static const Data localHostName = lookupLocalHostName();
129
0
   return localHostName;
130
0
}
131
132
Data
133
DnsUtil::lookupLocalHostName()
134
0
{
135
0
   char buffer[MAXHOSTNAMELEN + 1];
136
0
   initNetwork();
137
   // can't assume the name is NUL terminated when truncation occurs,
138
   // so insert trailing NUL here
139
0
   buffer[0] = buffer[MAXHOSTNAMELEN] = '\0';
140
0
   if (gethostname(buffer,sizeof(buffer)-1) == -1)
141
0
   {
142
0
      int err = getErrno();
143
0
      switch (err)
144
0
      {
145
         // !RjS! This makes no sense for non-windows. The
146
         //       current hack (see the #define in .hxx) needs
147
         //       to be reworked.
148
0
         case WSANOTINITIALISED:
149
0
            CritLog( << "could not find local hostname because network not initialized:" << strerror(err) );
150
0
            break;
151
0
         default:
152
0
            CritLog( << "could not find local hostname:" << strerror(err) );
153
0
            break;
154
0
      }
155
0
         throw Exception("could not find local hostname",__FILE__,__LINE__);
156
0
   }
157
158
0
   struct addrinfo* result=0;
159
0
   struct addrinfo hints;
160
0
   memset(&hints, 0, sizeof(hints));
161
0
   hints.ai_flags |= AI_CANONNAME;
162
0
   hints.ai_family |= AF_UNSPEC;
163
0
   int res = getaddrinfo(buffer, 0, &hints, &result);
164
0
   if (!res) 
165
0
   {
166
      // !jf! this should really use the Data class 
167
0
      if (strchr(result->ai_canonname, '.') != 0) 
168
0
      {
169
0
         snprintf(buffer, sizeof(buffer), "%s", result->ai_canonname);
170
0
      }
171
0
      else 
172
0
      {
173
0
         InfoLog( << "local hostname does not contain a domain part " << buffer);
174
0
      }
175
0
      freeaddrinfo(result);
176
0
   }
177
0
   else
178
0
   {
179
0
      InfoLog (<< "Couldn't determine local hostname. Error was: " << gai_strerror(res) << ". Returning empty string");
180
0
   }
181
182
0
   return buffer;
183
0
}
184
185
Data
186
DnsUtil::getLocalDomainName()
187
0
{
188
0
   Data lhn(getLocalHostName());
189
0
   size_t dpos = lhn.find(".");
190
0
   if (dpos != Data::npos)
191
0
   {
192
0
      return lhn.substr(dpos+1);
193
0
   }
194
0
   else
195
0
   {
196
#if defined( __APPLE__ ) || defined( WIN32 ) || defined(__SUNPRO_CC) || defined(__sun__) || defined( __ANDROID__ )
197
      throw Exception("Could not find domainname in local hostname",__FILE__,__LINE__);
198
#else
199
0
      DebugLog( << "No domain portion in hostname <" << lhn << ">, so using getdomainname");
200
0
      char buffer[MAXHOSTNAMELEN + 1];
201
      // can't assume the name is NUL terminated when truncation occurs,
202
      // so insert trailing NUL here
203
0
      buffer[0] = buffer[MAXHOSTNAMELEN] = '\0';
204
0
      if (int e = getdomainname(buffer,sizeof(buffer)-1) == -1)
205
0
      {
206
0
         if ( e != 0 )
207
0
         {
208
0
            int err = getErrno();
209
0
            CritLog(<< "Couldn't find domainname: " << strerror(err));
210
0
            throw Exception(strerror(err), __FILE__,__LINE__);
211
0
         }
212
0
      }
213
0
      DebugLog (<< "Found local domain name " << buffer);
214
     
215
0
      return Data(buffer);
216
0
#endif
217
0
   }
218
0
}
219
220
Data
221
DnsUtil::getLocalIpAddress(const Data& myInterface)
222
0
{
223
0
   Data result;
224
0
   std::list<std::pair<Data,Data> > ifs = DnsUtil::getInterfaces(myInterface);
225
226
0
   if (ifs.empty())
227
0
   {
228
0
      WarningLog( << "No interfaces matching "  << myInterface << " were found" );
229
0
      throw Exception("No interfaces matching", __FILE__, __LINE__);
230
0
   }
231
0
   else
232
0
   {
233
0
      InfoLog (<< "Local IP address for " << myInterface << " is " << ifs.begin()->second);
234
0
      return ifs.begin()->second;
235
0
   }
236
0
}
237
238
Data
239
DnsUtil::inet_ntop(const struct in_addr& addr)
240
0
{
241
0
   char str[256];
242
0
   inet_ntop(AF_INET, &addr, str, sizeof(str));
243
0
   return Data(str);
244
0
}
245
246
#ifdef USE_IPV6
247
Data
248
DnsUtil::inet_ntop(const struct in6_addr& addr)
249
88
{
250
88
   char str[256];
251
88
   inet_ntop(AF_INET6, &addr, str, sizeof(str));
252
88
   return Data(str);
253
88
}
254
#endif
255
256
Data
257
DnsUtil::inet_ntop(const struct sockaddr& addr)
258
0
{
259
0
#ifdef USE_IPV6
260
0
   if (addr.sa_family == AF_INET6)
261
0
   {
262
0
      const struct sockaddr_in6* addr6 = reinterpret_cast<const sockaddr_in6*>(&addr);
263
0
      return DnsUtil::inet_ntop(addr6->sin6_addr);
264
0
   }
265
0
   else
266
0
#endif
267
0
   {
268
0
      const struct sockaddr_in* addr4 = reinterpret_cast<const sockaddr_in*>(&addr);
269
0
      return DnsUtil::inet_ntop(addr4->sin_addr);
270
0
   }
271
0
}
272
273
int
274
DnsUtil::inet_pton(const Data& printableIp, struct in_addr& dst)
275
10
{
276
10
   return DnsUtil::inet_pton(AF_INET, printableIp.c_str(), &dst);
277
10
}
278
279
#ifdef USE_IPV6
280
int
281
DnsUtil::inet_pton(const Data& printableIp, struct in6_addr& dst)
282
120
{
283
120
   return DnsUtil::inet_pton(AF_INET6, printableIp.c_str(), &dst);
284
120
}
285
#endif
286
287
288
bool
289
DnsUtil::isIpV4Address(const Data& ipAddress)
290
12
{
291
   // ok, this is fairly monstrous but it works. It is also more than 10 times 
292
   // faster than the commented-out code below, in the worst case scenario.
293
294
12
   const char* first = ipAddress.data();
295
12
   const char* end = first + ipAddress.size();
296
12
   int octets = 0;
297
52
   while(octets++ < 4)
298
42
   {
299
42
      const char* last=first;
300
301
      // .bwc. I have tried using std::bitset instead of the 0 <= *last <= 9
302
      // check, but it is slower.
303
108
      while(last != end && *last >= '0' && *last <= '9' && last - first <= 3)
304
66
      {
305
         // Skip at most 3 decimals, without going past the end of the buffer.
306
66
         ++last;
307
66
      }
308
309
      // last should now point to either a '.', or the end of the buffer.
310
311
42
      switch(last-first) // number of decimals in this octet
312
42
      {
313
6
         case 2:
314
6
            if(*first == '0')
315
0
            {
316
               // Two-decimal octet can't begin with 0...
317
               // ?bwc? Maybe let this slide?
318
0
               return false;
319
0
            }
320
30
         case 1:
321
            // ... but a one-decimal octet can begin with a 0.
322
30
            break; // x. or xx.
323
10
         case 3:
324
            // xxx. (could be too large)
325
            // .bwc. I have tried implementing this with a reinterpret_cast 
326
            // and a UInt32 comparison (accounting for endianness), and memcmp, 
327
            // but both appear to be slower, even when using 
328
            // "255.255.255.255" (which maximizes the number of comparisons).
329
10
            if(*first != '1')
330
0
            {
331
0
               if(*first == '2')
332
0
               {
333
                  // Might have overflow if first digit is 2
334
0
                  if(*(first+1)>'5' || (*(first+1)=='5' && *(first+2)>'5'))
335
0
                  {
336
0
                     return false;
337
0
                  }
338
0
               }
339
0
               else
340
0
               {
341
                  // First digit greater than 2 means overflow, 0 not allowed.
342
0
                  return false;
343
0
               }
344
0
            }
345
10
            break;
346
10
         default:
347
2
            return false;
348
42
      }
349
350
40
      if(octets < 4)
351
30
      {
352
30
         if(last != end && *last == '.')
353
30
         {
354
            // Skip over the '.'
355
30
            ++last;
356
30
         }
357
0
         else
358
0
         {
359
0
            return false;
360
0
         }
361
30
      }
362
40
      first = last; // is now pointing at either the first digit in the next
363
                     // octet, or the end of the buffer.
364
40
   }
365
366
10
   return first==end;
367
//   unsigned int p1,p2,p3,p4;
368
//   int count=0;
369
//   int result = sscanf( ipAddress.c_str(),
370
//                        "%u.%u.%u.%u%n",
371
//                        &p1, &p2, &p3, &p4, &count );
372
//
373
//   if ( (result == 4) && (p1 <= 255) && (p2 <= 255) && (p3 <= 255) && (p4 <= 255) && (count == int(ipAddress.size())) )
374
//   {
375
//      return true;
376
//   }
377
//   else
378
//   {
379
//      return false;
380
//   }
381
12
}
382
383
// RFC 1884
384
bool
385
DnsUtil::isIpV6Address(const Data& ipAddress)
386
2
{
387
2
   if (ipAddress.empty())
388
0
   {
389
0
      return false;
390
0
   }
391
392
   // first character must be a hex digit or colon
393
2
   if (!isxdigit(*ipAddress.data()) &&
394
2
       *ipAddress.data() != ':')
395
0
   {
396
0
      return false;
397
0
   }
398
399
2
   switch (ipAddress.size())
400
2
   {
401
0
      case 1:
402
0
         return false;
403
0
      case 2:
404
0
         return (*(ipAddress.data()+1) == ':' ||
405
0
                 *(ipAddress.data()+0) == ':');
406
0
      case 3:
407
0
         return (*(ipAddress.data()+2) == ':' ||
408
0
                 *(ipAddress.data()+1) == ':' ||
409
0
                 *(ipAddress.data()+0) == ':');
410
0
      case 4:
411
0
         return (*(ipAddress.data()+3) == ':' ||
412
0
                 *(ipAddress.data()+2) == ':' ||
413
0
                 *(ipAddress.data()+1) == ':' ||
414
0
                 *(ipAddress.data()+0) == ':');
415
2
      default:
416
417
2
         return (*(ipAddress.data()+4) == ':' ||
418
2
                 *(ipAddress.data()+3) == ':' ||
419
2
                 *(ipAddress.data()+2) == ':' ||
420
2
                 *(ipAddress.data()+1) == ':' ||
421
2
                 *(ipAddress.data()+0) == ':');
422
2
   }
423
2
}
424
425
Data
426
DnsUtil::canonicalizeIpV6Address(const Data& ipV6Address)
427
118
{
428
118
#ifdef USE_IPV6
429
118
   struct in6_addr dst;
430
118
   int res = DnsUtil::inet_pton(ipV6Address, dst);
431
118
   if (res <= 0)
432
30
   {
433
      // .bwc. Until we supply an isIpV6Address that works, this is not an
434
      // error on anyone's part but our own. Don't log as a warning/error.
435
30
      InfoLog(<< ipV6Address << " is not a well formed IPV6 address");
436
      // .bwc. We should not assert in this function, because 
437
      // DnsUtil::isIpV6Address does not do a full validity check. If we have no
438
      // way of determining whether a V6 addr is valid before making this call,
439
      // this call _needs_ to be safe.
440
      // assert(0);
441
30
      return Data::Empty;
442
30
   }
443
88
   return DnsUtil::inet_ntop(dst);
444
#else
445
   // assert(0);
446
447
   return ipV6Address;
448
#endif
449
118
}
450
451
bool
452
DnsUtil::isIpAddress(const Data& ipAddress)
453
0
{
454
0
   return isIpV4Address(ipAddress) || isIpV6Address(ipAddress);
455
0
}
456
457
458
std::list<std::pair<Data,Data> >
459
DnsUtil::getInterfaces(const Data& matching)
460
0
{
461
0
   std::list<std::pair<Data,Data> > results;
462
463
0
#if !defined(WIN32)
464
465
0
   struct ifconf ifc;
466
467
0
   int s = socket( AF_INET, SOCK_DGRAM, 0 );
468
0
   resip_assert( s != INVALID_SOCKET );  // can run out of file descs
469
0
   const int len = 100 * sizeof(struct ifreq);
470
0
   int maxRet = 40;
471
472
0
   char buf[ len ];
473
0
   ifc.ifc_len = len;
474
0
   ifc.ifc_buf = buf;
475
476
0
   int e = ioctl(s,SIOCGIFCONF,&ifc);
477
0
   char *ptr = buf;
478
0
   int tl = ifc.ifc_len;
479
0
   int count=0;
480
  
481
0
   while ( (tl > 0) && ( count < maxRet) )
482
0
   {
483
0
      struct ifreq* ifr = (struct ifreq *)ptr;
484
485
0
      count++;
486
487
#if defined(__NetBSD__) || defined(__APPLE__)
488
      int si = sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
489
#else
490
0
      int si = sizeof(ifr->ifr_name) + sizeof(ifr->ifr_ifru);
491
0
#endif
492
      
493
0
      tl -= si;
494
0
      ptr += si;
495
496
0
      char* name = ifr->ifr_name;
497
498
0
      struct ifreq ifr2;
499
0
      ifr2 = *ifr;
500
501
0
      e = ioctl(s,SIOCGIFADDR,&ifr2);
502
0
      if ( e == -1 )
503
0
      {
504
         // no valid address for this interface, skip it    
505
0
         DebugLog (<< "Ignoring interface  " << name << " as there is no valid address" );
506
0
         continue;
507
0
      }
508
0
      struct sockaddr a = ifr2.ifr_addr;
509
0
      Data ip = DnsUtil::inet_ntop(a);
510
      
511
0
      e = ioctl(s,SIOCGIFFLAGS,&ifr2);
512
0
      if ( e == -1 )
513
0
      {
514
         // no valid flags for this interface, skip it 
515
0
         DebugLog (<< "Ignoring interface  " << name << " as there is no valid flags" );
516
0
         continue;
517
0
      }
518
0
      short flags = ifr2.ifr_flags;
519
520
#if 0
521
      // if this does not work on your OS, it is not used yet, 
522
      // comment it out and put a note of what OS it does not work for 
523
      struct ifmediareq media; 
524
      e = ioctl(s,SIOCGIFMEDIA,&media);
525
      int status = media.ifm_status;
526
      int active = media.ifm_active;
527
      DebugLog (<< "Media status=" << hex << status 
528
                << " active=" << hex << active << dec );  
529
#endif
530
531
#if 0
532
      // if this does not work on your OS, it is not used yet, 
533
      // comment it out and put a note of what OS it does not work for 
534
      e = ioctl(s,SIOCGIFPHYS,&ifr2);
535
      int phys= ifr2.ifr_phys;
536
      DebugLog (<< "Phys=" << hex << phys << dec );  
537
#endif
538
539
0
      DebugLog (<< "Considering: " << name << " -> " << ip
540
0
                << " flags=0x" << hex << flags << dec );
541
   
542
0
      if (  (flags & IFF_UP) == 0 ) 
543
0
      {  
544
0
         DebugLog (<< "  ignore because: interface is not up");
545
0
         continue;
546
0
      }
547
548
0
      if (  (flags & IFF_LOOPBACK) != 0 ) 
549
0
      {
550
0
         DebugLog (<< "  ignore because: interface is loopback");
551
0
         continue;
552
0
      }
553
      
554
0
      if (  (flags & IFF_RUNNING) == 0 ) 
555
0
      {
556
0
         DebugLog (<< "  ignore because: interface is not running");
557
0
         continue;
558
0
      }
559
      
560
0
      if ( ( (name[0]<'A') || (name[0]>'z') )
561
#if defined(__MACH__) && defined(__GNU__)   // for GNU HURD
562
            && (name[0] != '/')
563
#endif
564
0
         ) // should never happen
565
0
      {  
566
0
         DebugLog (<< "  ignore because: name looks bogus");
567
0
         resip_assert(0);
568
0
         continue;
569
0
      }
570
571
0
      if (matching == Data::Empty || matching == name)
572
0
      {
573
0
         DebugLog (<< "  using this");
574
0
         results.push_back(std::make_pair(Data(name), ip));
575
0
      }
576
0
   }
577
578
0
   close(s);
579
#else 
580
#if defined(WIN32)
581
   try
582
   {
583
      return WinCompat::getInterfaces(matching);
584
   }
585
   catch(WinCompat::Exception& e)
586
   {
587
      DebugLog (<< "  WinCompat::getInterfaces throws " << e.getMessage());
588
      return results;
589
   }
590
#else
591
   resip_assert(0);
592
#endif
593
#endif
594
595
0
   return results;
596
0
}
597
598
#ifdef __APPLE__
599
const Data DnsUtil::UInt8ToStr[]={
600
  "0.",  "1.",  "2.",  "3.",  "4.",  "5.",  "6.",  "7.",
601
  "8.",  "9.", "10.", "11.", "12.", "13.", "14.", "15.",
602
 "16.", "17.", "18.", "19.", "20.", "21.", "22.", "23.",
603
 "24.", "25.", "26.", "27.", "28.", "29.", "30.", "31.",
604
 "32.", "33.", "34.", "35.", "36.", "37.", "38.", "39.",
605
 "40.", "41.", "42.", "43.", "44.", "45.", "46.", "47.",
606
 "48.", "49.", "50.", "51.", "52.", "53.", "54.", "55.",
607
 "56.", "57.", "58.", "59.", "60.", "61.", "62.", "63.",
608
 "64.", "65.", "66.", "67.", "68.", "69.", "70.", "71.",
609
 "72.", "73.", "74.", "75.", "76.", "77.", "78.", "79.",
610
 "80.", "81.", "82.", "83.", "84.", "85.", "86.", "87.",
611
 "88.", "89.", "90.", "91.", "92.", "93.", "94.", "95.",
612
 "96.", "97.", "98.", "99.","100.","101.","102.","103.",
613
"104.","105.","106.","107.","108.","109.","110.","111.",
614
"112.","113.","114.","115.","116.","117.","118.","119.",
615
"120.","121.","122.","123.","124.","125.","126.","127.",
616
"128.","129.","130.","131.","132.","133.","134.","135.",
617
"136.","137.","138.","139.","140.","141.","142.","143.",
618
"144.","145.","146.","147.","148.","149.","150.","151.",
619
"152.","153.","154.","155.","156.","157.","158.","159.",
620
"160.","161.","162.","163.","164.","165.","166.","167.",
621
"168.","169.","170.","171.","172.","173.","174.","175.",
622
"176.","177.","178.","179.","180.","181.","182.","183.",
623
"184.","185.","186.","187.","188.","189.","190.","191.",
624
"192.","193.","194.","195.","196.","197.","198.","199.",
625
"200.","201.","202.","203.","204.","205.","206.","207.",
626
"208.","209.","210.","211.","212.","213.","214.","215.",
627
"216.","217.","218.","219.","220.","221.","222.","223.",
628
"224.","225.","226.","227.","228.","229.","230.","231.",
629
"232.","233.","234.","235.","236.","237.","238.","239.",
630
"240.","241.","242.","243.","244.","245.","246.","247.",
631
"248.","249.","250.","251.","252.","253.","254.","255."
632
};
633
#endif // __APPLE__
634
635
#if !(defined(WIN32) || defined(__CYGWIN__))
636
const char *DnsUtil::inet_ntop(int af, const void* src, char* dst,
637
                               size_t size)
638
88
{
639
640
#ifdef __APPLE__
641
   if(af==AF_INET)
642
   {
643
      // .bwc. inet_ntop4 seems to be implemented with sprintf on OS X.
644
      // This code is about 5-6 times faster. Linux has a well-optimized 
645
      // inet_ntop, however.
646
      const uint8_t* bytes=(const uint8_t*)src;
647
      Data dest(Data::Borrow, dst, sizeof("xxx.xxx.xxx.xxx."));
648
      dest.clear();
649
      dest.append(UInt8ToStr[bytes[0]].data(), UInt8ToStr[bytes[0]].size());
650
      dest.append(UInt8ToStr[bytes[1]].data(), UInt8ToStr[bytes[1]].size());
651
      dest.append(UInt8ToStr[bytes[2]].data(), UInt8ToStr[bytes[2]].size());
652
      dest.append(UInt8ToStr[bytes[3]].data(), UInt8ToStr[bytes[3]].size()-1);
653
      return dst;
654
   }
655
   else
656
#endif // __APPLE__
657
88
   {
658
88
      return ::inet_ntop(af, src, dst, size);
659
88
   }
660
88
}
661
662
int DnsUtil::inet_pton(int af, const char* src, void* dst)
663
130
{
664
130
   return ::inet_pton(af, src, dst);
665
130
}
666
#else
667
#define __restrict
668
669
#define  NS_INT16SZ   2
670
#define  NS_INADDRSZ  4
671
#define  NS_IN6ADDRSZ 16
672
673
const char* inet_ntop4(const u_char *src, char *dst, size_t size);
674
#ifdef USE_IPV6
675
const char * inet_ntop6(const u_char *src, char *dst, size_t size);
676
#endif
677
//adapted from freebsd inet_ntop.c(1.12) and inet_pton.c(1.5) for windows(non-compliant snprinf workaround)
678
/* const char *
679
 * inet_ntop4(src, dst, size)
680
 *  format an IPv4 address, more or less like inet_ntoa()
681
 * return:
682
 *  `dst' (as a const)
683
 * notes:
684
 *  (1) uses no statics
685
 *  (2) takes a u_char* not an in_addr as input
686
 * author:
687
 *  Paul Vixie, 1996.
688
 */
689
const char *
690
DnsUtil::inet_ntop(int af, const void * __restrict src, char * __restrict dst,
691
                   size_t size)
692
{
693
   switch (af) 
694
   {
695
      case AF_INET:
696
         return (inet_ntop4((const u_char *)src, dst, size));
697
#ifdef USE_IPV6
698
      case AF_INET6:
699
         return (inet_ntop6((const u_char *)src, dst, size));
700
#endif
701
      default:
702
         errno = EAFNOSUPPORT;
703
         return (NULL);
704
   }
705
   /* NOTREACHED */
706
}
707
708
709
static const char fmt[] = "%u.%u.%u.%u";
710
const char*
711
inet_ntop4(const u_char *src, char *dst, size_t size)
712
{
713
#ifdef WIN32
714
   if ( _snprintf(dst, size, fmt, src[0], src[1], src[2], src[3]) < 0)
715
#else
716
   if ( snprintf(dst, size, fmt, src[0], src[1], src[2], src[3]) < 0)
717
#endif
718
   {
719
      errno = ENOSPC;
720
      dst[size-1] = 0;
721
      return NULL;
722
   }
723
   return (dst);
724
}
725
726
727
#ifdef USE_IPV6
728
/* const char *
729
 * inet_ntop6(src, dst, size)
730
 *  convert IPv6 binary address into presentation (printable) format
731
 * author:
732
 *  Paul Vixie, 1996.
733
 */
734
735
const char *
736
inet_ntop6(const u_char *src, char *dst, size_t size)
737
{
738
   /*
739
    * Note that int32_t and int16_t need only be "at least" large enough
740
    * to contain a value of the specified size.  On some systems, like
741
    * Crays, there is no such thing as an integer variable with 16 bits.
742
    * Keep this in mind if you think this function should have been coded
743
    * to use pointer overlays.  All the world's not a VAX.
744
    */
745
   char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
746
   struct { int base, len; } best, cur;
747
   u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
748
   int i;
749
750
   /*
751
    * Preprocess:
752
    * Copy the input (bytewise) array into a wordwise array.
753
    * Find the longest run of 0x00's in src[] for :: shorthanding.
754
    */
755
   memset(words, '\0', sizeof words);
756
   for (i = 0; i < NS_IN6ADDRSZ; i++)
757
      words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
758
   best.base = -1;
759
   cur.base = -1;
760
   for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
761
      if (words[i] == 0) {
762
         if (cur.base == -1)
763
            cur.base = i, cur.len = 1;
764
         else
765
            cur.len++;
766
      } else {
767
         if (cur.base != -1) {
768
            if (best.base == -1 || cur.len > best.len)
769
               best = cur;
770
            cur.base = -1;
771
         }
772
      }
773
   }
774
   if (cur.base != -1) {
775
      if (best.base == -1 || cur.len > best.len)
776
         best = cur;
777
   }
778
   if (best.base != -1 && best.len < 2)
779
      best.base = -1;
780
781
   /*
782
    * Format the result.
783
    */
784
   tp = tmp;
785
   for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
786
      /* Are we inside the best run of 0x00's? */
787
      if (best.base != -1 && i >= best.base &&
788
          i < (best.base + best.len)) {
789
         if (i == best.base)
790
            *tp++ = ':';
791
         continue;
792
      }
793
      /* Are we following an initial run of 0x00s or any real hex? */
794
      if (i != 0)
795
         *tp++ = ':';
796
      /* Is this address an encapsulated IPv4? */
797
      if (i == 6 && best.base == 0 &&
798
          (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
799
         if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
800
            return (NULL);
801
         tp += strlen(tp);
802
         break;
803
      }
804
      tp += sprintf(tp, "%x", words[i]);
805
   }
806
   /* Was it a trailing run of 0x00's? */
807
   if (best.base != -1 && (best.base + best.len) ==
808
       (NS_IN6ADDRSZ / NS_INT16SZ))
809
      *tp++ = ':';
810
   *tp++ = '\0';
811
812
   /*
813
    * Check for overflow, copy, and we're done.
814
    */
815
   if ((size_t)(tp - tmp) > size) {
816
      errno = ENOSPC;
817
      return (NULL);
818
   }
819
   strcpy(dst, tmp);
820
   return (dst);
821
}
822
823
static int  inet_pton6(const char *src, u_char *dst);
824
#endif //USE_IPV6
825
826
static int  inet_pton4(const char *src, u_char *dst);
827
828
/* int
829
 * inet_pton(af, src, dst)
830
 *  convert from presentation format (which usually means ASCII printable)
831
 *  to network format (which is usually some kind of binary format).
832
 * return:
833
 *  1 if the address was valid for the specified address family
834
 *  0 if the address wasn't valid (`dst' is untouched in this case)
835
 *  -1 if some other error occurred (`dst' is untouched in this case, too)
836
 * author:
837
 *  Paul Vixie, 1996.
838
 */
839
int
840
DnsUtil::inet_pton(int af, const char* src, void* dst)
841
{
842
   switch (af) {
843
      case AF_INET:
844
         return (inet_pton4(src, (u_char*) dst));
845
#ifdef USE_IPV6
846
      case AF_INET6:
847
         return (inet_pton6(src, (u_char*) dst));
848
#endif
849
      default:
850
         errno = EAFNOSUPPORT;
851
         return (-1);
852
   }
853
   /* NOTREACHED */
854
}
855
856
/* int
857
 * inet_pton4(src, dst)
858
 *  like inet_aton() but without all the hexadecimal and shorthand.
859
 * return:
860
 *  1 if `src' is a valid dotted quad, else 0.
861
 * notice:
862
 *  does not touch `dst' unless it's returning 1.
863
 * author:
864
 *  Paul Vixie, 1996.
865
 */
866
static const char digits[] = "0123456789";
867
static int
868
inet_pton4(const char *src, u_char *dst)
869
{
870
   int saw_digit, octets, ch;
871
   u_char tmp[NS_INADDRSZ], *tp;
872
873
   saw_digit = 0;
874
   octets = 0;
875
   *(tp = tmp) = 0;
876
   while ((ch = *src++) != '\0') {
877
      const char *pch;
878
879
      if ((pch = strchr(digits, ch)) != NULL) {
880
         u_int newVal = u_int(*tp * 10 + (pch - digits));
881
882
         if (newVal > 255)
883
            return (0);
884
         *tp = newVal;
885
         if (! saw_digit) {
886
            if (++octets > 4)
887
               return (0);
888
            saw_digit = 1;
889
         }
890
      } else if (ch == '.' && saw_digit) {
891
         if (octets == 4)
892
            return (0);
893
         *++tp = 0;
894
         saw_digit = 0;
895
      } else
896
         return (0);
897
   }
898
   if (octets < 4)
899
      return (0);
900
901
   memcpy(dst, tmp, NS_INADDRSZ);
902
   return (1);
903
}
904
905
#ifdef USE_IPV6
906
907
/* int
908
 * inet_pton6(src, dst)
909
 *  convert presentation level address to network order binary form.
910
 * return:
911
 *  1 if `src' is a valid [RFC1884 2.2] address, else 0.
912
 * notice:
913
 *  (1) does not touch `dst' unless it's returning 1.
914
 *  (2) :: in a full address is silently ignored.
915
 * credit:
916
 *  inspired by Mark Andrews.
917
 * author:
918
 *  Paul Vixie, 1996.
919
 */
920
static const char xdigits_l[] = "0123456789abcdef",
921
                  xdigits_u[] = "0123456789ABCDEF";
922
static int
923
inet_pton6(const char *src, u_char *dst)
924
{
925
   u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
926
   const char *xdigits, *curtok;
927
   int ch, saw_xdigit;
928
   u_int val;
929
930
   memset((tp = tmp), '\0', NS_IN6ADDRSZ);
931
   endp = tp + NS_IN6ADDRSZ;
932
   colonp = NULL;
933
   /* Leading :: requires some special handling. */
934
   if (*src == ':')
935
      if (*++src != ':')
936
         return (0);
937
   curtok = src;
938
   saw_xdigit = 0;
939
   val = 0;
940
   while ((ch = *src++) != '\0') {
941
      const char *pch;
942
943
      if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
944
         pch = strchr((xdigits = xdigits_u), ch);
945
      if (pch != NULL) {
946
         val <<= 4;
947
         val |= (pch - xdigits);
948
         if (val > 0xffff)
949
            return (0);
950
         saw_xdigit = 1;
951
         continue;
952
      }
953
      if (ch == ':') {
954
         curtok = src;
955
         if (!saw_xdigit) {
956
            if (colonp)
957
               return (0);
958
            colonp = tp;
959
            continue;
960
         }
961
         if (tp + NS_INT16SZ > endp)
962
            return (0);
963
         *tp++ = (u_char) (val >> 8) & 0xff;
964
         *tp++ = (u_char) val & 0xff;
965
         saw_xdigit = 0;
966
         val = 0;
967
         continue;
968
      }
969
      if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
970
          inet_pton4(curtok, tp) > 0) {
971
         tp += NS_INADDRSZ;
972
         saw_xdigit = 0;
973
         break; /* '\0' was seen by inet_pton4(). */
974
      }
975
      return (0);
976
   }
977
   if (saw_xdigit) {
978
      if (tp + NS_INT16SZ > endp)
979
         return (0);
980
      *tp++ = (u_char) (val >> 8) & 0xff;
981
      *tp++ = (u_char) val & 0xff;
982
   }
983
   if (colonp != NULL) {
984
      /*
985
       * Since some memmove()'s erroneously fail to handle
986
       * overlapping regions, we'll do the shift by hand.
987
       */
988
      const int n = int(tp - colonp);
989
      int i;
990
991
      for (i = 1; i <= n; i++) {
992
         endp[- i] = colonp[n - i];
993
         colonp[n - i] = 0;
994
      }
995
      tp = endp;
996
   }
997
   if (tp != endp)
998
      return (0);
999
   memcpy(dst, tmp, NS_IN6ADDRSZ);
1000
   return (1);
1001
}
1002
1003
1004
#endif
1005
#endif
1006
1007
/* ====================================================================
1008
 * The Vovida Software License, Version 1.0
1009
 *
1010
 * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
1011
 *
1012
 * Redistribution and use in source and binary forms, with or without
1013
 * modification, are permitted provided that the following conditions
1014
 * are met:
1015
 *
1016
 * 1. Redistributions of source code must retain the above copyright
1017
 *    notice, this list of conditions and the following disclaimer.
1018
 *
1019
 * 2. Redistributions in binary form must reproduce the above copyright
1020
 *    notice, this list of conditions and the following disclaimer in
1021
 *    the documentation and/or other materials provided with the
1022
 *    distribution.
1023
 *
1024
 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
1025
 *    and "Vovida Open Communication Application Library (VOCAL)" must
1026
 *    not be used to endorse or promote products derived from this
1027
 *    software without prior written permission. For written
1028
 *    permission, please contact vocal@vovida.org.
1029
 *
1030
 * 4. Products derived from this software may not be called "VOCAL", nor
1031
 *    may "VOCAL" appear in their name, without prior written
1032
 *    permission of Vovida Networks, Inc.
1033
 *
1034
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
1035
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1036
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
1037
 * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
1038
 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
1039
 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
1040
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1041
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1042
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
1043
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1044
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1045
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1046
 * DAMAGE.
1047
 *
1048
 * ====================================================================
1049
 *
1050
 * This software consists of voluntary contributions made by Vovida
1051
 * Networks, Inc. and many individuals on behalf of Vovida Networks,
1052
 * Inc.  For more information on Vovida Networks, Inc., please see
1053
 * <http://www.vovida.org/>.
1054
 *
1055
 */
1056
1057
/* Copyright (c) 1996 by Internet Software Consortium.
1058
 *
1059
 * Permission to use, copy, modify, and distribute this software for any
1060
 * purpose with or without fee is hereby granted, provided that the above
1061
 * copyright notice and this permission notice appear in all copies.
1062
 *
1063
 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
1064
 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
1065
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
1066
 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
1067
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
1068
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
1069
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
1070
 * SOFTWARE.
1071
 */
1072