ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-7.2/src/irc_getaddrinfo.c
Revision: 33
Committed: Sun Oct 2 20:50:00 2005 UTC (19 years, 10 months ago) by knight
Content type: text/x-csrc
Original Path: ircd-hybrid/src/irc_getaddrinfo.c
File size: 14738 byte(s)
Log Message:
- svn:keywords

File Contents

# User Rev Content
1 adx 30 /*
2     * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3     * All rights reserved.
4     *
5     * Redistribution and use in source and binary forms, with or without
6     * modification, are permitted provided that the following conditions
7     * are met:
8     * 1. Redistributions of source code must retain the above copyright
9     * notice, this list of conditions and the following disclaimer.
10     * 2. Redistributions in binary form must reproduce the above copyright
11     * notice, this list of conditions and the following disclaimer in the
12     * documentation and/or other materials provided with the distribution.
13     * 3. Neither the name of the project nor the names of its contributors
14     * may be used to endorse or promote products derived from this software
15     * without specific prior written permission.
16     *
17     * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20     * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27     * SUCH DAMAGE.
28     */
29    
30     #include "stdinc.h"
31    
32     #include <stdarg.h>
33     #include "irc_getaddrinfo.h"
34     #include "ircd_defs.h"
35    
36 knight 31 /* $Id$ */
37 adx 30
38     static const char in_addrany[] = { 0, 0, 0, 0 };
39     static const char in_loopback[] = { 127, 0, 0, 1 };
40     static const char in6_addrany[] = {
41     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
42     };
43     static const char in6_loopback[] = {
44     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
45     };
46    
47     static const struct afd {
48     int a_af;
49     int a_addrlen;
50     int a_socklen;
51     int a_off;
52     const char *a_addrany;
53     const char *a_loopback;
54     int a_scoped;
55     } afdl [] = {
56     #define N_INET6 0
57     #ifdef IPV6
58     {PF_INET6, sizeof(struct in6_addr),
59     sizeof(struct sockaddr_in6),
60     offsetof(struct sockaddr_in6, sin6_addr),
61     in6_addrany, in6_loopback, 1},
62     #endif
63     #define N_INET 1
64     {PF_INET, sizeof(struct in_addr),
65     sizeof(struct sockaddr_in),
66     offsetof(struct sockaddr_in, sin_addr),
67     in_addrany, in_loopback, 0},
68     {0, 0, 0, 0, NULL, NULL, 0},
69     };
70    
71     struct explore {
72     int e_af;
73     int e_socktype;
74     int e_protocol;
75     const char *e_protostr;
76     int e_wild;
77     #define WILD_AF(ex) ((ex)->e_wild & 0x01)
78     #define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02)
79     #define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04)
80     };
81    
82     static const struct explore explore[] = {
83     #ifdef IPV6
84     { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
85     { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
86     { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 },
87     #endif
88     { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
89     { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
90     { PF_INET, SOCK_RAW, ANY, NULL, 0x05 },
91     { PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
92     { PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
93     { PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 },
94     { -1, 0, 0, NULL, 0 },
95     };
96    
97     #define PTON_MAX 16
98    
99     static int str_isnumber(const char *);
100     static int explore_null(const struct addrinfo *,
101     const char *, struct addrinfo **);
102     static int explore_numeric(const struct addrinfo *, const char *,
103     const char *, struct addrinfo **);
104     static struct addrinfo *get_ai(const struct addrinfo *,
105     const struct afd *, const char *);
106     static int get_portmatch(const struct addrinfo *, const char *);
107     static int get_port(struct addrinfo *, const char *, int);
108     static const struct afd *find_afd(int);
109     #if 0
110     /* We will need this should we ever want gai_strerror() */
111     static char *ai_errlist[] = {
112     "Success",
113     "Address family for hostname not supported", /* EAI_ADDRFAMILY */
114     "Temporary failure in name resolution", /* EAI_AGAIN */
115     "Invalid value for ai_flags", /* EAI_BADFLAGS */
116     "Non-recoverable failure in name resolution", /* EAI_FAIL */
117     "ai_family not supported", /* EAI_FAMILY */
118     "Memory allocation failure", /* EAI_MEMORY */
119     "No address associated with hostname", /* EAI_NODATA */
120     "hostname nor servname provided, or not known", /* EAI_NONAME */
121     "servname not supported for ai_socktype", /* EAI_SERVICE */
122     "ai_socktype not supported", /* EAI_SOCKTYPE */
123     "System error returned in errno", /* EAI_SYSTEM */
124     "Invalid value for hints", /* EAI_BADHINTS */
125     "Resolved protocol is unknown", /* EAI_PROTOCOL */
126     "Unknown error", /* EAI_MAX */
127     };
128     #endif
129     /* XXX macros that make external reference is BAD. */
130    
131     #define GET_AI(ai, afd, addr) \
132     do { \
133     /* external reference: pai, error, and label free */ \
134     (ai) = get_ai(pai, (afd), (addr)); \
135     if ((ai) == NULL) { \
136     error = EAI_MEMORY; \
137     goto free; \
138     } \
139     } while (/*CONSTCOND*/0)
140    
141     #define GET_PORT(ai, serv) \
142     do { \
143     /* external reference: error and label free */ \
144     error = get_port((ai), (serv), 0); \
145     if (error != 0) \
146     goto free; \
147     } while (/*CONSTCOND*/0)
148    
149     #define ERR(err) \
150     do { \
151     /* external reference: error, and label bad */ \
152     error = (err); \
153     goto bad; \
154     /*NOTREACHED*/ \
155     } while (/*CONSTCOND*/0)
156    
157     #define MATCH_FAMILY(x, y, w) \
158     ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC)))
159     #define MATCH(x, y, w) \
160     ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY)))
161    
162     #if 0
163     /* We will need this should we ever want gai_strerror() */
164     char *
165     irc_gai_strerror(int ecode)
166     {
167     if (ecode < 0 || ecode > EAI_MAX)
168     ecode = EAI_MAX;
169     return ai_errlist[ecode];
170     }
171     #endif
172    
173     void
174     irc_freeaddrinfo(struct addrinfo *ai)
175     {
176     struct addrinfo *next;
177    
178     do {
179     next = ai->ai_next;
180     if (ai->ai_canonname)
181     free(ai->ai_canonname);
182     /* no need to free(ai->ai_addr) */
183     free(ai);
184     ai = next;
185     } while (ai);
186     }
187    
188     static int
189     str_isnumber(const char *p)
190     {
191     char *ep;
192    
193     if (*p == '\0')
194     return NO;
195     ep = NULL;
196     errno = 0;
197     (void)strtoul(p, &ep, 10);
198     if (errno == 0 && ep && *ep == '\0')
199     return YES;
200     else
201     return NO;
202     }
203    
204     int
205     irc_getaddrinfo(const char *hostname, const char *servname,
206     const struct addrinfo *hints, struct addrinfo **res)
207     {
208     struct addrinfo sentinel;
209     struct addrinfo *cur;
210     int error = 0;
211     struct addrinfo ai;
212     struct addrinfo ai0;
213     struct addrinfo *pai;
214     const struct explore *ex;
215    
216     memset(&sentinel, 0, sizeof(sentinel));
217     cur = &sentinel;
218     pai = &ai;
219     pai->ai_flags = 0;
220     pai->ai_family = PF_UNSPEC;
221     pai->ai_socktype = ANY;
222     pai->ai_protocol = ANY;
223     pai->ai_addrlen = 0;
224     pai->ai_canonname = NULL;
225     pai->ai_addr = NULL;
226     pai->ai_next = NULL;
227    
228     if (hostname == NULL && servname == NULL)
229     return EAI_NONAME;
230     if (hints) {
231     /* error check for hints */
232     if (hints->ai_addrlen || hints->ai_canonname ||
233     hints->ai_addr || hints->ai_next)
234     ERR(EAI_BADHINTS); /* xxx */
235     if (hints->ai_flags & ~AI_MASK)
236     ERR(EAI_BADFLAGS);
237     switch (hints->ai_family) {
238     case PF_UNSPEC:
239     case PF_INET:
240     #ifdef IPV6
241     case PF_INET6:
242     #endif
243     break;
244     default:
245     ERR(EAI_FAMILY);
246     }
247     memcpy(pai, hints, sizeof(*pai));
248    
249     /*
250     * if both socktype/protocol are specified, check if they
251     * are meaningful combination.
252     */
253     if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
254     for (ex = explore; ex->e_af >= 0; ex++) {
255     if (pai->ai_family != ex->e_af)
256     continue;
257     if (ex->e_socktype == ANY)
258     continue;
259     if (ex->e_protocol == ANY)
260     continue;
261     if (pai->ai_socktype == ex->e_socktype &&
262     pai->ai_protocol != ex->e_protocol) {
263     ERR(EAI_BADHINTS);
264     }
265     }
266     }
267     }
268    
269     /*
270     * check for special cases. (1) numeric servname is disallowed if
271     * socktype/protocol are left unspecified. (2) servname is disallowed
272     * for raw and other inet{,6} sockets.
273     */
274     if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
275     #ifdef IPV6
276     || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
277     #endif
278     ) {
279     ai0 = *pai; /* backup *pai */
280    
281     if (pai->ai_family == PF_UNSPEC) {
282     #ifdef IPV6
283     pai->ai_family = PF_INET6;
284     #else
285     pai->ai_family = PF_INET;
286     #endif
287     }
288     error = get_portmatch(pai, servname);
289     if (error)
290     ERR(error);
291    
292     *pai = ai0;
293     }
294    
295     ai0 = *pai;
296    
297     /* NULL hostname, or numeric hostname */
298     for (ex = explore; ex->e_af >= 0; ex++) {
299     *pai = ai0;
300    
301     /* PF_UNSPEC entries are prepared for DNS queries only */
302     if (ex->e_af == PF_UNSPEC)
303     continue;
304    
305     if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
306     continue;
307     if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
308     continue;
309     if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
310     continue;
311    
312     if (pai->ai_family == PF_UNSPEC)
313     pai->ai_family = ex->e_af;
314     if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
315     pai->ai_socktype = ex->e_socktype;
316     if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
317     pai->ai_protocol = ex->e_protocol;
318    
319     if (hostname == NULL)
320     error = explore_null(pai, servname, &cur->ai_next);
321     else
322     error = explore_numeric(pai, hostname, servname, &cur->ai_next);
323    
324     if (error)
325     goto free;
326    
327     while (cur && cur->ai_next)
328     cur = cur->ai_next;
329     }
330    
331     /*
332     * XXX
333     * If numreic representation of AF1 can be interpreted as FQDN
334     * representation of AF2, we need to think again about the code below.
335     */
336     if (sentinel.ai_next)
337     goto good;
338    
339     if (pai->ai_flags & AI_NUMERICHOST)
340     ERR(EAI_NONAME);
341     if (hostname == NULL)
342     ERR(EAI_NODATA);
343    
344     /* XXX */
345     if (sentinel.ai_next)
346     error = 0;
347    
348     if (error)
349     goto free;
350     if (error == 0) {
351     if (sentinel.ai_next) {
352     good:
353     *res = sentinel.ai_next;
354     return SUCCESS;
355     } else
356     error = EAI_FAIL;
357     }
358     free:
359     bad:
360     if (sentinel.ai_next)
361     irc_freeaddrinfo(sentinel.ai_next);
362     *res = NULL;
363     return error;
364     }
365    
366     /*
367     * hostname == NULL.
368     * passive socket -> anyaddr (0.0.0.0 or ::)
369     * non-passive socket -> localhost (127.0.0.1 or ::1)
370     */
371     static int
372     explore_null(const struct addrinfo *pai, const char *servname, struct addrinfo **res)
373     {
374     int s;
375     const struct afd *afd;
376     struct addrinfo *cur;
377     struct addrinfo sentinel;
378     int error;
379    
380     *res = NULL;
381     sentinel.ai_next = NULL;
382     cur = &sentinel;
383    
384     /*
385     * filter out AFs that are not supported by the kernel
386     * XXX errno?
387     */
388     s = socket(pai->ai_family, SOCK_DGRAM, 0);
389     if (s < 0) {
390     #ifdef _WIN32
391     errno = WSAGetLastError();
392     #endif
393     if (errno != EMFILE)
394     return 0;
395     } else
396     #ifdef _WIN32
397     closesocket(s);
398     #else
399     close(s);
400     #endif
401    
402     /*
403     * if the servname does not match socktype/protocol, ignore it.
404     */
405     if (get_portmatch(pai, servname) != 0)
406     return 0;
407    
408     afd = find_afd(pai->ai_family);
409     if (afd == NULL)
410     return 0;
411    
412     if (pai->ai_flags & AI_PASSIVE) {
413     GET_AI(cur->ai_next, afd, afd->a_addrany);
414     GET_PORT(cur->ai_next, servname);
415     } else {
416     GET_AI(cur->ai_next, afd, afd->a_loopback);
417     GET_PORT(cur->ai_next, servname);
418     }
419     cur = cur->ai_next;
420    
421     *res = sentinel.ai_next;
422     return 0;
423    
424     free:
425     if (sentinel.ai_next)
426     irc_freeaddrinfo(sentinel.ai_next);
427     return error;
428     }
429    
430     /*
431     * numeric hostname
432     */
433     static int
434     explore_numeric(const struct addrinfo *pai, const char *hostname,
435     const char *servname, struct addrinfo **res)
436     {
437     const struct afd *afd;
438     struct addrinfo *cur;
439     struct addrinfo sentinel;
440     int error;
441     char pton[PTON_MAX];
442    
443     *res = NULL;
444     sentinel.ai_next = NULL;
445     cur = &sentinel;
446    
447     /*
448     * if the servname does not match socktype/protocol, ignore it.
449     */
450     if (get_portmatch(pai, servname) != 0)
451     return 0;
452    
453     afd = find_afd(pai->ai_family);
454     if (afd == NULL)
455     return 0;
456    
457     switch (afd->a_af) {
458     #if 1 /*X/Open spec*/
459     case AF_INET:
460     if (inet_aton(hostname, (struct in_addr *)pton) == 1) {
461     if (pai->ai_family == afd->a_af ||
462     pai->ai_family == PF_UNSPEC /*?*/) {
463     GET_AI(cur->ai_next, afd, pton);
464     GET_PORT(cur->ai_next, servname);
465     while (cur && cur->ai_next)
466     cur = cur->ai_next;
467     } else
468     ERR(EAI_FAMILY); /*xxx*/
469     }
470     break;
471     #endif
472     default:
473     if (inet_pton(afd->a_af, hostname, pton) == 1) {
474     if (pai->ai_family == afd->a_af ||
475     pai->ai_family == PF_UNSPEC /*?*/) {
476     GET_AI(cur->ai_next, afd, pton);
477     GET_PORT(cur->ai_next, servname);
478     while (cur && cur->ai_next)
479     cur = cur->ai_next;
480     } else
481     ERR(EAI_FAMILY); /* XXX */
482     }
483     break;
484     }
485    
486     *res = sentinel.ai_next;
487     return 0;
488    
489     free:
490     bad:
491     if (sentinel.ai_next)
492     irc_freeaddrinfo(sentinel.ai_next);
493     return error;
494     }
495    
496     static struct addrinfo *
497     get_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr)
498     {
499     char *p;
500     struct addrinfo *ai;
501    
502     ai = (struct addrinfo *)malloc(sizeof(struct addrinfo)
503     + (afd->a_socklen));
504     if (ai == NULL)
505     return NULL;
506    
507     memcpy(ai, pai, sizeof(struct addrinfo));
508     ai->ai_addr = (struct sockaddr *)(void *)(ai + 1);
509     memset(ai->ai_addr, 0, (size_t)afd->a_socklen);
510     ai->ai_addrlen = afd->a_socklen;
511     ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
512     p = (char *)(void *)(ai->ai_addr);
513     memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
514     return ai;
515     }
516    
517     static int
518     get_portmatch(const struct addrinfo *ai, const char *servname)
519     {
520     /* get_port does not touch first argument. when matchonly == 1. */
521     /* LINTED const cast */
522     return(get_port((struct addrinfo *)ai, servname, 1));
523     }
524    
525     static int
526     get_port(struct addrinfo *ai, const char *servname, int matchonly)
527     {
528     const char *proto;
529     struct servent *sp;
530     int port;
531     int allownumeric;
532    
533     if (servname == NULL)
534     return 0;
535     switch (ai->ai_family) {
536     case AF_INET:
537     #ifdef AF_INET6
538     case AF_INET6:
539     #endif
540     break;
541     default:
542     return 0;
543     }
544    
545     switch (ai->ai_socktype) {
546     case SOCK_RAW:
547     return EAI_SERVICE;
548     case SOCK_DGRAM:
549     case SOCK_STREAM:
550     allownumeric = 1;
551     break;
552     case ANY:
553     allownumeric = 0;
554     break;
555     default:
556     return EAI_SOCKTYPE;
557     }
558    
559     if (str_isnumber(servname)) {
560     if (!allownumeric)
561     return EAI_SERVICE;
562     port = atoi(servname);
563     if (port < 0 || port > 65535)
564     return EAI_SERVICE;
565     port = htons(port);
566     } else {
567     switch (ai->ai_socktype) {
568     case SOCK_DGRAM:
569     proto = "udp";
570     break;
571     case SOCK_STREAM:
572     proto = "tcp";
573     break;
574     default:
575     proto = NULL;
576     break;
577     }
578    
579     if ((sp = getservbyname(servname, proto)) == NULL)
580     return EAI_SERVICE;
581     port = sp->s_port;
582     }
583    
584     if (!matchonly) {
585     switch (ai->ai_family) {
586     case AF_INET:
587     ((struct sockaddr_in *)(void *)
588     ai->ai_addr)->sin_port = port;
589     break;
590     #ifdef IPV6
591     case AF_INET6:
592     ((struct sockaddr_in6 *)(void *)
593     ai->ai_addr)->sin6_port = port;
594     break;
595     #endif
596     }
597     }
598    
599     return 0;
600     }
601    
602     static const struct afd *
603     find_afd(int af)
604     {
605     const struct afd *afd;
606    
607     if (af == PF_UNSPEC)
608     return(NULL);
609    
610     for (afd = afdl; afd->a_af; afd++)
611     {
612     if (afd->a_af == af)
613     return(afd);
614     }
615    
616     return(NULL);
617     }

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision