]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/unbound/compat/fake-rfc2553.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / unbound / compat / fake-rfc2553.c
1 /* From openssh 4.3p2 filename openbsd-compat/fake-rfc2553.h */
2 /*
3  * Copyright (C) 2000-2003 Damien Miller.  All rights reserved.
4  * Copyright (C) 1999 WIDE Project.  All rights reserved.
5  * 
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the project nor the names of its contributors
15  *    may be used to endorse or promote products derived from this software
16  *    without specific prior written permission.
17  * 
18  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30
31 /*
32  * Pseudo-implementation of RFC2553 name / address resolution functions
33  *
34  * But these functions are not implemented correctly. The minimum subset
35  * is implemented for ssh use only. For example, this routine assumes
36  * that ai_family is AF_INET. Don't use it for another purpose.
37  */
38
39 #include <unistd.h>
40 #include <string.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include "compat/fake-rfc2553.h"
44
45 #ifndef HAVE_GETNAMEINFO
46 int getnameinfo(const struct sockaddr *sa, size_t ATTR_UNUSED(salen), char *host, 
47                 size_t hostlen, char *serv, size_t servlen, int flags)
48 {
49         struct sockaddr_in *sin = (struct sockaddr_in *)sa;
50         struct hostent *hp;
51         char tmpserv[16];
52
53         if (serv != NULL) {
54                 snprintf(tmpserv, sizeof(tmpserv), "%d", ntohs(sin->sin_port));
55                 if (strlcpy(serv, tmpserv, servlen) >= servlen)
56                         return (EAI_MEMORY);
57         }
58
59         if (host != NULL) {
60                 if (flags & NI_NUMERICHOST) {
61                         if (strlcpy(host, inet_ntoa(sin->sin_addr),
62                             hostlen) >= hostlen)
63                                 return (EAI_MEMORY);
64                         else
65                                 return (0);
66                 } else {
67                         hp = gethostbyaddr((char *)&sin->sin_addr, 
68                             sizeof(struct in_addr), AF_INET);
69                         if (hp == NULL)
70                                 return (EAI_NODATA);
71                         
72                         if (strlcpy(host, hp->h_name, hostlen) >= hostlen)
73                                 return (EAI_MEMORY);
74                         else
75                                 return (0);
76                 }
77         }
78         return (0);
79 }
80 #endif /* !HAVE_GETNAMEINFO */
81
82 #ifndef HAVE_GAI_STRERROR
83 #ifdef HAVE_CONST_GAI_STRERROR_PROTO
84 const char *
85 #else
86 char *
87 #endif
88 gai_strerror(int err)
89 {
90         switch (err) {
91         case EAI_NODATA:
92                 return ("no address associated with name");
93         case EAI_MEMORY:
94                 return ("memory allocation failure.");
95         case EAI_NONAME:
96                 return ("nodename nor servname provided, or not known");
97         default:
98                 return ("unknown/invalid error.");
99         }
100 }    
101 #endif /* !HAVE_GAI_STRERROR */
102
103 #ifndef HAVE_FREEADDRINFO
104 void
105 freeaddrinfo(struct addrinfo *ai)
106 {
107         struct addrinfo *next;
108
109         for(; ai != NULL;) {
110                 next = ai->ai_next;
111                 free(ai);
112                 ai = next;
113         }
114 }
115 #endif /* !HAVE_FREEADDRINFO */
116
117 #ifndef HAVE_GETADDRINFO
118 static struct
119 addrinfo *malloc_ai(int port, u_long addr, const struct addrinfo *hints)
120 {
121         struct addrinfo *ai;
122
123         ai = calloc(1, sizeof(*ai) + sizeof(struct sockaddr_in));
124         if (ai == NULL)
125                 return (NULL);
126         
127         ai->ai_addr = (struct sockaddr *)(ai + 1);
128         /* XXX -- ssh doesn't use sa_len */
129         ai->ai_addrlen = sizeof(struct sockaddr_in);
130         ai->ai_addr->sa_family = ai->ai_family = AF_INET;
131
132         ((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port;
133         ((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr;
134         
135         /* XXX: the following is not generally correct, but does what we want */
136         if (hints->ai_socktype)
137                 ai->ai_socktype = hints->ai_socktype;
138         else
139                 ai->ai_socktype = SOCK_STREAM;
140
141         if (hints->ai_protocol)
142                 ai->ai_protocol = hints->ai_protocol;
143
144         return (ai);
145 }
146
147 int
148 getaddrinfo(const char *hostname, const char *servname, 
149     const struct addrinfo *hints, struct addrinfo **res)
150 {
151         struct hostent *hp;
152         struct servent *sp;
153         struct in_addr in;
154         int i;
155         long int port;
156         u_long addr;
157
158         port = 0;
159         if (servname != NULL) {
160                 char *cp;
161
162                 port = strtol(servname, &cp, 10);
163                 if (port > 0 && port <= 65535 && *cp == '\0')
164                         port = htons(port);
165                 else if ((sp = getservbyname(servname, NULL)) != NULL)
166                         port = sp->s_port;
167                 else
168                         port = 0;
169         }
170
171         if (hints && hints->ai_flags & AI_PASSIVE) {
172                 addr = htonl(0x00000000);
173                 if (hostname && inet_aton(hostname, &in) != 0)
174                         addr = in.s_addr;
175                 *res = malloc_ai(port, addr, hints);
176                 if (*res == NULL) 
177                         return (EAI_MEMORY);
178                 return (0);
179         }
180                 
181         if (!hostname) {
182                 *res = malloc_ai(port, htonl(0x7f000001), hints);
183                 if (*res == NULL) 
184                         return (EAI_MEMORY);
185                 return (0);
186         }
187         
188         if (inet_aton(hostname, &in)) {
189                 *res = malloc_ai(port, in.s_addr, hints);
190                 if (*res == NULL) 
191                         return (EAI_MEMORY);
192                 return (0);
193         }
194         
195         /* Don't try DNS if AI_NUMERICHOST is set */
196         if (hints && hints->ai_flags & AI_NUMERICHOST)
197                 return (EAI_NONAME);
198         
199         hp = gethostbyname(hostname);
200         if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
201                 struct addrinfo *cur, *prev;
202
203                 cur = prev = *res = NULL;
204                 for (i = 0; hp->h_addr_list[i]; i++) {
205                         struct in_addr *in = (struct in_addr *)hp->h_addr_list[i];
206
207                         cur = malloc_ai(port, in->s_addr, hints);
208                         if (cur == NULL) {
209                                 if (*res != NULL)
210                                         freeaddrinfo(*res);
211                                 return (EAI_MEMORY);
212                         }
213                         if (prev)
214                                 prev->ai_next = cur;
215                         else
216                                 *res = cur;
217
218                         prev = cur;
219                 }
220                 return (0);
221         }
222         
223         return (EAI_NODATA);
224 }
225 #endif /* !HAVE_GETADDRINFO */