1 /* $USAGI: getaddrinfo.c,v 1.16 2001/10/04 09:52:03 sekiya Exp $ */
2
3 /* The Inner Net License, Version 2.00
4
5 The author(s) grant permission for redistribution and use in source and
6 binary forms, with or without modification, of the software and documentation
7 provided that the following conditions are met:
8
9 0. If you receive a version of the software that is specifically labelled
10 as not being for redistribution (check the version message and/or README),
11 you are not permitted to redistribute that version of the software in any
12 way or form.
13 1. All terms of the all other applicable copyrights and licenses must be
14 followed.
15 2. Redistributions of source code must retain the authors' copyright
16 notice(s), this list of conditions, and the following disclaimer.
17 3. Redistributions in binary form must reproduce the authors' copyright
18 notice(s), this list of conditions, and the following disclaimer in the
19 documentation and/or other materials provided with the distribution.
20 4. All advertising materials mentioning features or use of this software
21 must display the following acknowledgement with the name(s) of the
22 authors as specified in the copyright notice(s) substituted where
23 indicated:
24
25 This product includes software developed by <name(s)>, The Inner
26 Net, and other contributors.
27
28 5. Neither the name(s) of the author(s) nor the names of its contributors
29 may be used to endorse or promote products derived from this software
30 without specific prior written permission.
31
32 THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY
33 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
34 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
35 DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
36 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
37 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
39 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42
43 If these license terms cause you a real problem, contact the author. */
44
45 /* This software is Copyright 1996 by Craig Metz, All Rights Reserved. */
46
47 #include <config.h>
48 #include "owfs_config.h"
49
50 #ifdef HAVE_PTHREAD
51 #include <pthread.h>
52 #endif
53
54 #ifndef HAVE_GETADDRINFO
55
56 #define _GNU_SOURCE 1
57 #define __FORCE_GLIBC
58 #ifdef HAVE_FEATURES_H
59 #include <features.h>
60 #endif
61 #include <assert.h>
62 #include <errno.h>
63 #include <netdb.h>
64 #include "compat_netdb.h"
65
66 #include <stdio.h>
67 #include <stdlib.h>
68 #include <string.h>
69 #include <unistd.h>
70 #include <arpa/inet.h>
71 #include <sys/socket.h>
72 #include <netinet/in.h>
73 #include <sys/types.h>
74 #include <sys/un.h>
75 #include <sys/utsname.h>
76 #include <net/if.h>
77
78 #ifdef HAVE_RESOLV_H
79 #include <resolv.h>
80 #endif
81
82 #include "ow_debug.h"
83
84
85 /* The following declarations and definitions have been removed from
86 * the public header since we don't want people to use them. */
87 #define AI_V4MAPPED 0x0008 /* IPv4-mapped addresses are acceptable. */
88 #define AI_ALL 0x0010 /* Return both IPv4 and IPv6 addresses. */
89 #define AI_ADDRCONFIG 0x0020 /* Use configuration of this host to choose
90 returned address type. */
91 #define AI_DEFAULT (AI_V4MAPPED | AI_ADDRCONFIG)
92
93
94 #define GAIH_OKIFUNSPEC 0x0100
95 #define GAIH_EAI ~(GAIH_OKIFUNSPEC)
96
97 struct gaih_service {
98 const char *name;
99 int num;
100 };
101
102 struct gaih_servtuple {
103 struct gaih_servtuple *next;
104 int socktype;
105 int protocol;
106 int port;
107 };
108
109 static const struct gaih_servtuple nullserv;
110
111 struct gaih_addrtuple {
112 struct gaih_addrtuple *next;
113 int family;
114 char addr[16];
115 uint32_t scopeid;
116 };
117
118 struct gaih_typeproto {
119 int socktype;
120 int protocol;
121 char name[4];
122 int protoflag;
123 };
124
125 /* Values for `protoflag'. */
126 #define GAI_PROTO_NOSERVICE 1
127 #define GAI_PROTO_PROTOANY 2
128
129 static const struct gaih_typeproto gaih_inet_typeproto[] = {
130 {0, 0, "", 0},
131 {SOCK_STREAM, IPPROTO_TCP, "tcp", 0},
132 {SOCK_DGRAM, IPPROTO_UDP, "udp", 0},
133 {SOCK_RAW, 0, "raw", GAI_PROTO_PROTOANY | GAI_PROTO_NOSERVICE},
134 {0, 0, "", 0}
135 };
136
137 struct gaih {
138 int family;
139 int (*gaih) (const char *name, const struct gaih_service * service, const struct addrinfo * req, struct addrinfo ** pai);
140 };
141
142 #if PF_UNSPEC == 0
143 static const struct addrinfo default_hints;
144 #else
145 static const struct addrinfo default_hints = { 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL };
146 #endif
147
148
addrconfig(sa_family_t af)149 static int addrconfig(sa_family_t af)
150 {
151 int s;
152 int ret;
153 int saved_errno = errno;
154 s = socket(af, SOCK_DGRAM, 0);
155 if (s < 0)
156 ret = (errno == EMFILE) ? 1 : 0;
157 else {
158 close(s);
159 ret = 1;
160 }
161 __set_errno(saved_errno);
162 return ret;
163 }
164
165 #if 0
166 #ifndef UNIX_PATH_MAX
167 #define UNIX_PATH_MAX 108
168 #endif
169
170 /* Using Unix sockets this way is a security risk. */
171 static int gaih_local(const char *name, const struct gaih_service *service, const struct addrinfo *req, struct addrinfo **pai)
172 {
173 struct utsname utsname;
174
175 if ((name != NULL) && (req->ai_flags & AI_NUMERICHOST))
176 return GAIH_OKIFUNSPEC | -EAI_NONAME;
177
178 if ((name != NULL) || (req->ai_flags & AI_CANONNAME))
179 if (uname(&utsname) < 0)
180 return -EAI_SYSTEM;
181
182 if (name != NULL) {
183 if (strcmp(name, "localhost") && strcmp(name, "local") && strcmp(name, "unix") && strcmp(name, utsname.nodename))
184 return GAIH_OKIFUNSPEC | -EAI_NONAME;
185 }
186
187 if (req->ai_protocol || req->ai_socktype) {
188 const struct gaih_typeproto *tp = gaih_inet_typeproto + 1;
189
190 while (tp->name[0]
191 && ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0 || (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
192 || (req->ai_protocol != 0 && !(tp->protoflag & GAI_PROTO_PROTOANY)
193 && req->ai_protocol != tp->protocol)))
194 ++tp;
195
196 if (!tp->name[0]) {
197 if (req->ai_socktype)
198 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
199 else
200 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
201 }
202 }
203
204 *pai = malloc(sizeof(struct addrinfo) + sizeof(struct sockaddr_un)
205 + ((req->ai_flags & AI_CANONNAME)
206 ? (strlen(utsname.nodename) + 1) : 0));
207 if (*pai == NULL)
208 return -EAI_MEMORY;
209
210 (*pai)->ai_next = NULL;
211 (*pai)->ai_flags = req->ai_flags;
212 (*pai)->ai_family = AF_LOCAL;
213 (*pai)->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
214 (*pai)->ai_protocol = req->ai_protocol;
215 (*pai)->ai_addrlen = sizeof(struct sockaddr_un);
216 (*pai)->ai_addr = (void *) (*pai) + sizeof(struct addrinfo);
217
218 #ifdef HAVE_SA_LEN
219 ((struct sockaddr_un *) (*pai)->ai_addr)->sun_len = sizeof(struct sockaddr_un);
220 #endif /* HAVE_SA_LEN */
221
222 ((struct sockaddr_un *) (*pai)->ai_addr)->sun_family = AF_LOCAL;
223 memset(((struct sockaddr_un *) (*pai)->ai_addr)->sun_path, 0, UNIX_PATH_MAX);
224
225 if (service) {
226 struct sockaddr_un *sunp = (struct sockaddr_un *) (*pai)->ai_addr;
227
228 if (strchr(service->name, '/') != NULL) {
229 if (strlen(service->name) >= sizeof(sunp->sun_path))
230 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
231
232 strcpy(sunp->sun_path, service->name);
233 } else {
234 if (strlen(P_tmpdir "/") + 1 + strlen(service->name) >= sizeof(sunp->sun_path))
235 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
236
237 __stpcpy(__stpcpy(sunp->sun_path, P_tmpdir "/"), service->name);
238 }
239 } else {
240 /* This is a dangerous use of the interface since there is a time
241 window between the test for the file and the actual creation
242 (done by the caller) in which a file with the same name could
243 be created. */
244 char *buf = ((struct sockaddr_un *) (*pai)->ai_addr)->sun_path;
245
246 if (__builtin_expect(__path_search(buf, L_tmpnam, NULL, NULL, 0), 0) != 0 || __builtin_expect(__gen_tempname(buf, __GT_NOCREATE), 0) != 0)
247 return -EAI_SYSTEM;
248 }
249
250 if (req->ai_flags & AI_CANONNAME)
251 (*pai)->ai_canonname = strcpy((char *) *pai + sizeof(struct addrinfo)
252 + sizeof(struct sockaddr_un), utsname.nodename);
253 else
254 (*pai)->ai_canonname = NULL;
255 return 0;
256 }
257 #endif /* 0 */
258
259 #ifndef HAVE_GETHOSTBYNAME_R
gethostbyname_r(const char * name,struct hostent * result,char * buf,size_t buflen,int * h_errnop)260 struct hostent *gethostbyname_r(const char *name, struct hostent *result, char *buf, size_t buflen, int *h_errnop)
261 {
262 #ifdef HAVE_PTHREAD
263 static pthread_mutex_t gethostbyname_lock = PTHREAD_MUTEX_INITIALIZER;
264 #endif
265 struct hostent *res;
266 (void) buf; // not used
267 (void) buflen; // not used
268
269 #ifdef HAVE_PTHREAD
270 pthread_mutex_lock(&gethostbyname_lock);
271 #endif
272 res = gethostbyname(name);
273 if (res) {
274 memcpy(result, res, sizeof(struct hostent));
275 } else {
276 *h_errnop = errno;
277 }
278 #ifdef HAVE_PTHREAD
279 pthread_mutex_unlock(&gethostbyname_lock);
280 #endif
281 return res;
282 }
283 #endif
284
285 #ifndef HAVE_GETSERVBYNAME_R
getservbyname_r(const char * name,const char * proto,struct servent * result,char * buf,size_t buflen)286 struct servent *getservbyname_r(const char *name, const char *proto, struct servent *result, char *buf, size_t buflen)
287 {
288 #ifdef HAVE_PTHREAD
289 static pthread_mutex_t getservbyname_lock = PTHREAD_MUTEX_INITIALIZER;
290 #endif
291 struct servent *res;
292 (void) buf; // not used
293 (void) buflen; // not used
294
295 #ifdef HAVE_PTHREAD
296 pthread_mutex_lock(&getservbyname_lock);
297 #endif
298 res = getservbyname(name, proto);
299 if (res)
300 memcpy(result, res, sizeof(struct servent));
301 #ifdef HAVE_PTHREAD
302 pthread_mutex_unlock(&getservbyname_lock);
303 #endif
304 return res;
305 }
306 #endif
307
308
309
310
311
gaih_inet_serv(const char * servicename,const struct gaih_typeproto * tp,const struct addrinfo * req,struct gaih_servtuple * st)312 static int gaih_inet_serv(const char *servicename, const struct gaih_typeproto *tp, const struct addrinfo *req, struct gaih_servtuple *st)
313 {
314 struct servent *s;
315 size_t tmpbuflen = 1024;
316 struct servent ts;
317 char *tmpbuf;
318 int r;
319
320 do {
321 tmpbuf = alloca(tmpbuflen);
322 #if 0
323 r = getservbyname_r(servicename, tp->name, &ts, tmpbuf, tmpbuflen, &s);
324 if (!s)
325 r = errno;
326 if (r != 0 || s == NULL) {
327 if (r == ERANGE)
328 tmpbuflen *= 2;
329 else
330 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
331 }
332 #else
333 s = getservbyname_r(servicename, tp->name, &ts, tmpbuf, tmpbuflen);
334 if (s == NULL) {
335 r = errno;
336 if (r == ERANGE)
337 tmpbuflen *= 2;
338 else
339 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
340 } else {
341 r = 0;
342 }
343 #endif
344 }
345 while (r);
346
347 st->next = NULL;
348 st->socktype = tp->socktype;
349 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
350 ? req->ai_protocol : tp->protocol);
351 st->port = s->s_port;
352
353 return 0;
354 }
355
356 #define gethosts(_family, _type) \
357 { \
358 int i, herrno; \
359 size_t tmpbuflen; \
360 struct hostent th; \
361 char *tmpbuf; \
362 tmpbuflen = 512; \
363 no_data = 0; \
364 do { \
365 tmpbuflen *= 2; \
366 tmpbuf = alloca (tmpbuflen); \
367 rc = 0; \
368 h = gethostbyname_r (name, &th, tmpbuf, \
369 tmpbuflen, &herrno); \
370 if(!h) rc = errno; \
371 } while (rc == ERANGE && herrno == NETDB_INTERNAL); \
372 if (rc != 0) \
373 { \
374 if (herrno == NETDB_INTERNAL) \
375 { \
376 __set_h_errno (herrno); \
377 return -EAI_SYSTEM; \
378 } \
379 if (herrno == TRY_AGAIN) \
380 no_data = EAI_AGAIN; \
381 else \
382 no_data = herrno == NO_DATA; \
383 } \
384 else if (h != NULL) \
385 { \
386 for (i = 0; h->h_addr_list[i]; i++) \
387 { \
388 if (*pat == NULL) { \
389 *pat = alloca (sizeof(struct gaih_addrtuple)); \
390 (*pat)->scopeid = 0; \
391 } \
392 (*pat)->next = NULL; \
393 (*pat)->family = _family; \
394 memcpy ((*pat)->addr, h->h_addr_list[i], \
395 sizeof(_type)); \
396 pat = &((*pat)->next); \
397 } \
398 } \
399 }
400
401 #ifndef HAVE_GETHOSTBYNAME2_R
gethostbyname2_r(const char * name,int af,struct hostent * ret,char * buf,size_t buflen,struct hostent ** result,int * h_errnop)402 struct hostenv *gethostbyname2_r(const char *name, int af, struct hostent *ret, char *buf, size_t buflen, struct hostent **result, int *h_errnop)
403 {
404 /* Don't support this if it doesn't exists...
405 (eg. IPV6 will fail on cygwin for example) */
406 (void) name;
407 (void) af;
408 (void) ret;
409 (void) buf;
410 (void) buflen;
411 (void) result;
412 (void) h_errnop;
413 return NULL;
414 }
415 #endif
416
417
418 #if __HAS_IPV6__
419 #define gethosts2(_family, _type) \
420 { \
421 int i, herrno; \
422 size_t tmpbuflen; \
423 struct hostent th; \
424 char *tmpbuf; \
425 tmpbuflen = 512; \
426 no_data = 0; \
427 do { \
428 tmpbuflen *= 2; \
429 tmpbuf = alloca (tmpbuflen); \
430 rc = gethostbyname2_r (name, _family, &th, tmpbuf, \
431 tmpbuflen, &h, &herrno); \
432 } while (rc == ERANGE && herrno == NETDB_INTERNAL); \
433 if (rc != 0) \
434 { \
435 if (herrno == NETDB_INTERNAL) \
436 { \
437 __set_h_errno (herrno); \
438 return -EAI_SYSTEM; \
439 } \
440 if (herrno == TRY_AGAIN) \
441 no_data = EAI_AGAIN; \
442 else \
443 no_data = herrno == NO_DATA; \
444 } \
445 else if (h != NULL) \
446 { \
447 for (i = 0; h->h_addr_list[i]; i++) \
448 { \
449 if (*pat == NULL) { \
450 *pat = alloca (sizeof(struct gaih_addrtuple)); \
451 (*pat)->scopeid = 0; \
452 } \
453 (*pat)->next = NULL; \
454 (*pat)->family = _family; \
455 memcpy ((*pat)->addr, h->h_addr_list[i], \
456 sizeof(_type)); \
457 pat = &((*pat)->next); \
458 } \
459 } \
460 }
461 #endif
462
463 #ifndef HAVE_GETHOSTBYADDR_R
gethostbyaddr_r(const char * name,int len,int type,struct hostent * result,char * buf,size_t buflen,int * h_errnop)464 struct hostent *gethostbyaddr_r(const char *name, int len, int type, struct hostent *result, char *buf, size_t buflen, int *h_errnop)
465 {
466 #ifdef HAVE_PTHREAD
467 static pthread_mutex_t gethostbyaddr_lock = PTHREAD_MUTEX_INITIALIZER;
468 #endif
469 struct hostent *res;
470 (void) buf; // not used
471 (void) buflen; // not used
472
473 #ifdef HAVE_PTHREAD
474 pthread_mutex_lock(&gethostbyaddr_lock);
475 #endif
476 res = gethostbyaddr(name, len, type);
477 if (res) {
478 memcpy(result, res, sizeof(struct hostent));
479 } else {
480 *h_errnop = errno;
481 }
482 #ifdef HAVE_PTHREAD
483 pthread_mutex_unlock(&gethostbyaddr_lock);
484 #endif
485 return res;
486 }
487 #endif
488
gaih_inet(const char * name,const struct gaih_service * service,const struct addrinfo * req,struct addrinfo ** pai)489 static int gaih_inet(const char *name, const struct gaih_service *service, const struct addrinfo *req, struct addrinfo **pai)
490 {
491 const struct gaih_typeproto *tp = gaih_inet_typeproto;
492 struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;
493 struct gaih_addrtuple *at = NULL;
494 int rc;
495 int v4mapped = (req->ai_family == PF_UNSPEC
496 #if __HAS_IPV6__
497 || req->ai_family == PF_INET6
498 #endif
499 ) && (req->ai_flags & AI_V4MAPPED);
500
501 if (req->ai_protocol || req->ai_socktype) {
502 ++tp;
503
504 while (tp->name[0]
505 && ((req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
506 || (req->ai_protocol != 0 && !(tp->protoflag & GAI_PROTO_PROTOANY)
507 && req->ai_protocol != tp->protocol)))
508 ++tp;
509
510 if (!tp->name[0]) {
511 if (req->ai_socktype)
512 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
513 else
514 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
515 }
516 }
517
518 if (service != NULL) {
519 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
520 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
521
522 if (service->num < 0) {
523 if (tp->name[0]) {
524 st = (struct gaih_servtuple *)
525 alloca(sizeof(struct gaih_servtuple));
526
527 if ((rc = gaih_inet_serv(service->name, tp, req, st)))
528 return rc;
529 } else {
530 struct gaih_servtuple **pst = &st;
531 for (tp++; tp->name[0]; tp++) {
532 struct gaih_servtuple *newp;
533
534 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
535 continue;
536
537 if (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
538 continue;
539 if (req->ai_protocol != 0 && !(tp->protoflag & GAI_PROTO_PROTOANY)
540 && req->ai_protocol != tp->protocol)
541 continue;
542
543 newp = (struct gaih_servtuple *)
544 alloca(sizeof(struct gaih_servtuple));
545
546 if ((rc = gaih_inet_serv(service->name, tp, req, newp))) {
547 if (rc & GAIH_OKIFUNSPEC)
548 continue;
549 return rc;
550 }
551
552 *pst = newp;
553 pst = &(newp->next);
554 }
555 if (st == (struct gaih_servtuple *) &nullserv)
556 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
557 }
558 } else {
559 st = alloca(sizeof(struct gaih_servtuple));
560 st->next = NULL;
561 st->socktype = tp->socktype;
562 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
563 ? req->ai_protocol : tp->protocol);
564 st->port = htons(service->num);
565 }
566 } else if (req->ai_socktype || req->ai_protocol) {
567 st = alloca(sizeof(struct gaih_servtuple));
568 st->next = NULL;
569 st->socktype = tp->socktype;
570 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
571 ? req->ai_protocol : tp->protocol);
572 st->port = 0;
573 } else {
574 /*
575 * Neither socket type nor protocol is set. Return all socket types
576 * we know about.
577 */
578 struct gaih_servtuple **lastp = &st;
579 for (++tp; tp->name[0]; ++tp) {
580 struct gaih_servtuple *newp;
581
582 newp = alloca(sizeof(struct gaih_servtuple));
583 newp->next = NULL;
584 newp->socktype = tp->socktype;
585 newp->protocol = tp->protocol;
586 newp->port = 0;
587
588 *lastp = newp;
589 lastp = &newp->next;
590 }
591 }
592
593 if (name != NULL) {
594 at = alloca(sizeof(struct gaih_addrtuple));
595
596 at->family = AF_UNSPEC;
597 at->scopeid = 0;
598 at->next = NULL;
599
600 if (inet_pton(AF_INET, name, at->addr) > 0) {
601 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET || v4mapped)
602 at->family = AF_INET;
603 else
604 return -EAI_FAMILY;
605 }
606 #if __HAS_IPV6__
607 if (at->family == AF_UNSPEC) {
608 char *namebuf = strdupa(name);
609 char *scope_delim;
610
611 scope_delim = strchr(namebuf, SCOPE_DELIMITER);
612 if (scope_delim != NULL)
613 *scope_delim = '\0';
614
615 if (inet_pton(AF_INET6, namebuf, at->addr) > 0) {
616 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
617 at->family = AF_INET6;
618 else
619 return -EAI_FAMILY;
620
621 if (scope_delim != NULL) {
622 int try_numericscope = 0;
623 if (IN6_IS_ADDR_LINKLOCAL(at->addr)
624 || IN6_IS_ADDR_MC_LINKLOCAL(at->addr)) {
625 at->scopeid = if_nametoindex(scope_delim + 1);
626 if (at->scopeid == 0)
627 try_numericscope = 1;
628 } else
629 try_numericscope = 1;
630
631 if (try_numericscope != 0) {
632 char *end;
633 assert(sizeof(uint32_t) <= sizeof(unsigned long));
634 at->scopeid = (uint32_t) strtoul(scope_delim + 1, &end, 10);
635 if (*end != '\0')
636 return GAIH_OKIFUNSPEC | -EAI_NONAME;
637 }
638 }
639 }
640 }
641 #endif
642
643 if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0) {
644 struct hostent *h;
645 struct gaih_addrtuple **pat = &at;
646 int no_data = 0;
647 int no_inet6_data;
648
649 /*
650 * If we are looking for both IPv4 and IPv6 address we don't want
651 * the lookup functions to automatically promote IPv4 addresses to
652 * IPv6 addresses.
653 */
654
655 #if __HAS_IPV6__
656 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
657 gethosts(AF_INET6, struct in6_addr);
658 #endif
659 no_inet6_data = no_data;
660
661 if (req->ai_family == AF_INET ||
662 (!v4mapped && req->ai_family == AF_UNSPEC) || (v4mapped && (no_inet6_data != 0 || (req->ai_flags & AI_ALL))))
663 #if __HAS_IPV6__
664 gethosts2(AF_INET, struct in_addr);
665 #else
666 gethosts(AF_INET, struct in_addr);
667 #endif
668 if (no_data != 0 && no_inet6_data != 0) {
669 /* If both requests timed out report this. */
670 if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN)
671 return -EAI_AGAIN;
672
673 /*
674 * We made requests but they turned out no data.
675 * The name is known, though.
676 */
677 return (GAIH_OKIFUNSPEC | -EAI_AGAIN);
678 }
679 }
680
681 if (at->family == AF_UNSPEC)
682 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
683 } else {
684 struct gaih_addrtuple *atr;
685 atr = at = alloca(sizeof(struct gaih_addrtuple));
686 memset(at, '\0', sizeof(struct gaih_addrtuple));
687
688 if (req->ai_family == 0) {
689 at->next = alloca(sizeof(struct gaih_addrtuple));
690 memset(at->next, '\0', sizeof(struct gaih_addrtuple));
691 }
692 #if __HAS_IPV6__
693 if (req->ai_family == 0 || req->ai_family == AF_INET6) {
694 extern const struct in6_addr __in6addr_loopback;
695 at->family = AF_INET6;
696 if ((req->ai_flags & AI_PASSIVE) == 0)
697 memcpy(at->addr, &__in6addr_loopback, sizeof(struct in6_addr));
698 atr = at->next;
699 }
700 #endif
701
702 if (req->ai_family == 0 || req->ai_family == AF_INET) {
703 atr->family = AF_INET;
704 if ((req->ai_flags & AI_PASSIVE) == 0)
705 *(uint32_t *) atr->addr = htonl(INADDR_LOOPBACK);
706 }
707 }
708
709 if (pai == NULL)
710 return 0;
711
712 {
713 const char *c = NULL;
714 struct gaih_servtuple *st2;
715 struct gaih_addrtuple *at2 = at;
716 size_t socklen, namelen;
717 sa_family_t family;
718
719 /*
720 * buffer is the size of an unformatted IPv6 address in
721 * printable format.
722 */
723 char buffer[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
724
725 while (at2 != NULL) {
726 if (req->ai_flags & AI_CANONNAME) {
727 struct hostent *h = NULL;
728
729 int herrno;
730 struct hostent th;
731 size_t tmpbuflen = 512;
732 char *tmpbuf;
733
734 do {
735 tmpbuflen *= 2;
736 tmpbuf = alloca(tmpbuflen);
737
738 if (tmpbuf == NULL)
739 return -EAI_MEMORY;
740
741 rc = 0;
742 h = gethostbyaddr_r(at2->addr,
743 #if __HAS_IPV6__
744 ((at2->family == AF_INET6)
745 ? sizeof(struct in6_addr)
746 : sizeof(struct in_addr)),
747 #else
748 sizeof(struct in_addr),
749 #endif
750 at2->family, &th, tmpbuf, tmpbuflen, &herrno);
751
752 if (!h)
753 rc = errno;
754 }
755 while (rc == errno && herrno == NETDB_INTERNAL);
756
757 if (rc != 0 && herrno == NETDB_INTERNAL) {
758 __set_h_errno(herrno);
759 return -EAI_SYSTEM;
760 }
761
762 if (h == NULL)
763 c = inet_ntop(at2->family, at2->addr, buffer, sizeof(buffer));
764 else
765 c = h->h_name;
766
767 if (c == NULL)
768 return GAIH_OKIFUNSPEC | -EAI_NONAME;
769
770 namelen = strlen(c) + 1;
771 } else
772 namelen = 0;
773
774 #if __HAS_IPV6__
775 if (at2->family == AF_INET6 || v4mapped) {
776 family = AF_INET6;
777 socklen = sizeof(struct sockaddr_in6);
778 } else
779 #endif
780 {
781 family = AF_INET;
782 socklen = sizeof(struct sockaddr_in);
783 }
784
785 for (st2 = st; st2 != NULL; st2 = st2->next) {
786 *pai = malloc(sizeof(struct addrinfo) + socklen + namelen);
787 if (*pai == NULL)
788 return -EAI_MEMORY;
789
790 (*pai)->ai_flags = req->ai_flags;
791 (*pai)->ai_family = family;
792 (*pai)->ai_socktype = st2->socktype;
793 (*pai)->ai_protocol = st2->protocol;
794 (*pai)->ai_addrlen = socklen;
795 (*pai)->ai_addr = (void *) (*pai) + sizeof(struct addrinfo);
796 #ifdef HAVE_SA_LEN
797 (*pai)->ai_addr->sa_len = socklen;
798 #endif /* HAVE_SA_LEN */
799 (*pai)->ai_addr->sa_family = family;
800
801 #if __HAS_IPV6__
802 if (family == AF_INET6) {
803 struct sockaddr_in6 *sin6p = (struct sockaddr_in6 *) (*pai)->ai_addr;
804
805 sin6p->sin6_flowinfo = 0;
806 if (at2->family == AF_INET6) {
807 memcpy(&sin6p->sin6_addr, at2->addr, sizeof(struct in6_addr));
808 } else {
809 sin6p->sin6_addr.s6_addr32[0] = 0;
810 sin6p->sin6_addr.s6_addr32[1] = 0;
811 sin6p->sin6_addr.s6_addr32[2] = htonl(0x0000ffff);
812 memcpy(&sin6p->sin6_addr.s6_addr32[3], at2->addr, sizeof(sin6p->sin6_addr.s6_addr32[3]));
813 }
814 sin6p->sin6_port = st2->port;
815 sin6p->sin6_scope_id = at2->scopeid;
816 } else
817 #endif
818 {
819 struct sockaddr_in *sinp = (struct sockaddr_in *) (*pai)->ai_addr;
820
821 memcpy(&sinp->sin_addr, at2->addr, sizeof(struct in_addr));
822 sinp->sin_port = st2->port;
823 memset(sinp->sin_zero, '\0', sizeof(sinp->sin_zero));
824 }
825
826 if (c) {
827 (*pai)->ai_canonname = ((void *) (*pai) + sizeof(struct addrinfo) + socklen);
828 strcpy((*pai)->ai_canonname, c);
829 } else
830 (*pai)->ai_canonname = NULL;
831
832 (*pai)->ai_next = NULL;
833 pai = &((*pai)->ai_next);
834 }
835
836 at2 = at2->next;
837 }
838 }
839 return 0;
840 }
841
842 static struct gaih gaih[] = {
843 #if __HAS_IPV6__
844 {PF_INET6, gaih_inet},
845 #endif
846 {PF_INET, gaih_inet},
847 #if 0
848 {PF_LOCAL, gaih_local},
849 #endif
850 {PF_UNSPEC, NULL}
851 };
852
getaddrinfo(const char * name,const char * service,const struct addrinfo * hints,struct addrinfo ** pai)853 int getaddrinfo(const char *name, const char *service, const struct addrinfo *hints, struct addrinfo **pai)
854 {
855 int i = 0, j = 0, last_i = 0;
856 struct addrinfo *p = NULL, **end;
857 struct gaih *g = gaih, *pg = NULL;
858 struct gaih_service gaih_service, *pservice;
859
860 if (name != NULL && name[0] == '*' && name[1] == 0)
861 name = NULL;
862
863 if (service != NULL && service[0] == '*' && service[1] == 0)
864 service = NULL;
865
866 if (name == NULL && service == NULL)
867 return EAI_NONAME;
868
869 if (hints == NULL)
870 hints = &default_hints;
871
872 if (hints->ai_flags & ~(AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | AI_ADDRCONFIG | AI_V4MAPPED | AI_ALL))
873 return EAI_BADFLAGS;
874
875 if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
876 return EAI_BADFLAGS;
877
878 if (service && service[0]) {
879 char *c;
880 gaih_service.name = service;
881 gaih_service.num = strtoul(gaih_service.name, &c, 10);
882 if (*c)
883 gaih_service.num = -1;
884 else
885 /*
886 * Can't specify a numerical socket unless a protocol
887 * family was given.
888 */
889 if (hints->ai_socktype == 0 && hints->ai_protocol == 0)
890 return EAI_SERVICE;
891 pservice = &gaih_service;
892 } else
893 pservice = NULL;
894
895 if (pai)
896 end = &p;
897 else
898 end = NULL;
899
900 while (g->gaih) {
901 if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC) {
902 if ((hints->ai_flags & AI_ADDRCONFIG)
903 && !addrconfig(g->family))
904 continue;
905 j++;
906 if (pg == NULL || pg->gaih != g->gaih) {
907 pg = g;
908 i = g->gaih(name, pservice, hints, end);
909 if (i != 0) {
910 last_i = i;
911
912 if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC))
913 continue;
914
915 if (p)
916 freeaddrinfo(p);
917
918 return -(i & GAIH_EAI);
919 }
920 if (end)
921 while (*end)
922 end = &((*end)->ai_next);
923 }
924 }
925 ++g;
926 }
927
928 if (j == 0)
929 return EAI_FAMILY;
930
931 if (p) {
932 *pai = p;
933 return 0;
934 }
935
936 if (pai == NULL && last_i == 0)
937 return 0;
938
939 if (p)
940 freeaddrinfo(p);
941
942 return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME;
943 }
944
freeaddrinfo(struct addrinfo * ai)945 void freeaddrinfo(struct addrinfo *ai)
946 {
947 struct addrinfo *p;
948
949 while (ai != NULL) {
950 p = ai;
951 ai = ai->ai_next;
952 free(p);
953 }
954 }
955
956 #define N_(x) x
957 static struct {
958 int code;
959 const char *msg;
960 } values[] = {
961 {
962 EAI_ADDRFAMILY, N_("Address family for hostname not supported")}, {
963 EAI_AGAIN, N_("Temporary failure in name resolution")}, {
964 EAI_BADFLAGS, N_("Bad value for ai_flags")}, {
965 EAI_FAIL, N_("Non-recoverable failure in name resolution")}, {
966 EAI_FAMILY, N_("ai_family not supported")}, {
967 EAI_MEMORY, N_("Memory allocation failure")}, {
968 EAI_NODATA, N_("No address associated with hostname")}, {
969 EAI_NONAME, N_("Name or service not known")}, {
970 EAI_SERVICE, N_("Servname not supported for ai_socktype")}, {
971 EAI_SOCKTYPE, N_("ai_socktype not supported")}, {
972 EAI_SYSTEM, N_("System error")}, {
973 EAI_INPROGRESS, N_("Processing request in progress")}, {
974 EAI_CANCELED, N_("Request canceled")}, {
975 EAI_NOTCANCELED, N_("Request not canceled")}, {
976 EAI_ALLDONE, N_("All requests done")}, {
977 EAI_INTR, N_("Interrupted by a signal")}
978 };
979
gai_strerror(int code)980 const char *gai_strerror(int code)
981 {
982 size_t i;
983 for (i = 0; i < sizeof(values) / sizeof(values[0]); ++i)
984 if (values[i].code == code)
985 return (values[i].msg);
986
987 return ("Unknown error");
988 }
989
990 #endif /* HAVE_GETADDRINFO */
991
992
993
994 #ifndef HAVE_INET_NTOP
995 /* char *
996 * inet_ntop4(src, dst, size)
997 * format an IPv4 address
998 * return:
999 * `dst' (as a const)
1000 * notes:
1001 * (1) uses no statics
1002 * (2) takes a u_char* not an in_addr as input
1003 * author:
1004 * Paul Vixie, 1996.
1005 */
inet_ntop4(const unsigned char * src,char * dst,size_t size)1006 static const char *inet_ntop4(const unsigned char *src, char *dst, size_t size)
1007 {
1008 char tmp[sizeof("255.255.255.255") + 1] = "\0";
1009 int octet;
1010 int i;
1011
1012 i = 0;
1013 for (octet = 0; octet <= 3; octet++) {
1014
1015 if (src[octet] > 255) {
1016 __set_errno(ENOSPC);
1017 return (NULL);
1018 }
1019 tmp[i++] = '0' + src[octet] / 100;
1020 if (tmp[i - 1] == '0') {
1021 tmp[i - 1] = '0' + (src[octet] / 10 % 10);
1022 if (tmp[i - 1] == '0')
1023 i--;
1024 } else {
1025 tmp[i++] = '0' + (src[octet] / 10 % 10);
1026 }
1027 tmp[i++] = '0' + src[octet] % 10;
1028 tmp[i++] = '.';
1029 }
1030 tmp[i - 1] = '\0';
1031
1032 if (strlen(tmp) > size) {
1033 __set_errno(ENOSPC);
1034 return (NULL);
1035 }
1036
1037 return strcpy(dst, tmp);
1038 }
1039
1040 /* char *
1041 * inet_ntop(af, src, dst, size)
1042 * convert a network format address to presentation format.
1043 * return:
1044 * pointer to presentation format address (`dst'), or NULL (see errno).
1045 * author:
1046 * Paul Vixie, 1996.
1047 */
inet_ntop(af,src,dst,size)1048 const char *inet_ntop(af, src, dst, size)
1049 int af;
1050 const void *src;
1051 char *dst;
1052 socklen_t size;
1053 {
1054 switch (af) {
1055 case AF_INET:
1056 return (inet_ntop4(src, dst, size));
1057 #if __HAS_IPV6__
1058 case AF_INET6:
1059 return (inet_ntop6(src, dst, size));
1060 #endif
1061 default:
1062 __set_errno(EAFNOSUPPORT);
1063 return (NULL);
1064 }
1065 /* NOTREACHED */
1066 }
1067 #endif /* HAVE_INET_NTOP */
1068
1069
1070 #ifndef HAVE_INET_PTON
1071 /* int
1072 * inet_pton4(src, dst)
1073 * like inet_aton() but without all the hexadecimal and shorthand.
1074 * return:
1075 * 1 if `src' is a valid dotted quad, else 0.
1076 * notice:
1077 * does not touch `dst' unless it's returning 1.
1078 * author:
1079 * Paul Vixie, 1996.
1080 */
inet_pton4(const char * src,unsigned char * dst)1081 static int inet_pton4(const char *src, unsigned char *dst)
1082 {
1083 int saw_digit, octets, ch;
1084 unsigned char tmp[4], *tp;
1085
1086 saw_digit = 0;
1087 octets = 0;
1088 *(tp = tmp) = 0;
1089 while ((ch = *src++) != '\0') {
1090
1091 if (ch >= '0' && ch <= '9') {
1092 unsigned int new = *tp * 10 + (ch - '0');
1093
1094 if (new > 255)
1095 return (0);
1096 *tp = new;
1097 if (!saw_digit) {
1098 if (++octets > 4)
1099 return (0);
1100 saw_digit = 1;
1101 }
1102 } else if (ch == '.' && saw_digit) {
1103 if (octets == 4)
1104 return (0);
1105 *++tp = 0;
1106 saw_digit = 0;
1107 } else
1108 return (0);
1109 }
1110 if (octets < 4)
1111 return (0);
1112 memcpy(dst, tmp, 4);
1113 return (1);
1114 }
1115
1116 /* int
1117 * inet_pton(af, src, dst)
1118 * convert from presentation format (which usually means ASCII printable)
1119 * to network format (which is usually some kind of binary format).
1120 * return:
1121 * 1 if the address was valid for the specified address family
1122 * 0 if the address wasn't valid (`dst' is untouched in this case)
1123 * -1 if some other error occurred (`dst' is untouched in this case, too)
1124 * author:
1125 * Paul Vixie, 1996.
1126 */
inet_pton(af,src,dst)1127 int inet_pton(af, src, dst)
1128 int af;
1129 const char *src;
1130 void *dst;
1131 {
1132 switch (af) {
1133 case AF_INET:
1134 return (inet_pton4(src, dst));
1135 #if __HAS_IPV6__
1136 case AF_INET6:
1137 return (inet_pton6(src, dst));
1138 #endif
1139 default:
1140 __set_errno(EAFNOSUPPORT);
1141 return (-1);
1142 }
1143 /* NOTREACHED */
1144 }
1145 #endif /* HAVE_INET_PTON */
1146