/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 | | |