]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/unbound/compat/fake-rfc2553.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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 = malloc(sizeof(*ai) + sizeof(struct sockaddr_in));
124         if (ai == NULL)
125                 return (NULL);
126         
127         memset(ai, '\0', sizeof(*ai) + sizeof(struct sockaddr_in));
128         
129         ai->ai_addr = (struct sockaddr *)(ai + 1);
130         /* XXX -- ssh doesn't use sa_len */
131         ai->ai_addrlen = sizeof(struct sockaddr_in);
132         ai->ai_addr->sa_family = ai->ai_family = AF_INET;
133
134         ((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port;
135         ((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr;
136         
137         /* XXX: the following is not generally correct, but does what we want */
138         if (hints->ai_socktype)
139                 ai->ai_socktype = hints->ai_socktype;
140         else
141                 ai->ai_socktype = SOCK_STREAM;
142
143         if (hints->ai_protocol)
144                 ai->ai_protocol = hints->ai_protocol;
145
146         return (ai);
147 }
148
149 int
150 getaddrinfo(const char *hostname, const char *servname, 
151     const struct addrinfo *hints, struct addrinfo **res)
152 {
153         struct hostent *hp;
154         struct servent *sp;
155         struct in_addr in;
156         int i;
157         long int port;
158         u_long addr;
159
160         port = 0;
161         if (servname != NULL) {
162                 char *cp;
163
164                 port = strtol(servname, &cp, 10);
165                 if (port > 0 && port <= 65535 && *cp == '\0')
166                         port = htons(port);
167                 else if ((sp = getservbyname(servname, NULL)) != NULL)
168                         port = sp->s_port;
169                 else
170                         port = 0;
171         }
172
173         if (hints && hints->ai_flags & AI_PASSIVE) {
174                 addr = htonl(0x00000000);
175                 if (hostname && inet_aton(hostname, &in) != 0)
176                         addr = in.s_addr;
177                 *res = malloc_ai(port, addr, hints);
178                 if (*res == NULL) 
179                         return (EAI_MEMORY);
180                 return (0);
181         }
182                 
183         if (!hostname) {
184                 *res = malloc_ai(port, htonl(0x7f000001), hints);
185                 if (*res == NULL) 
186                         return (EAI_MEMORY);
187                 return (0);
188         }
189         
190         if (inet_aton(hostname, &in)) {
191                 *res = malloc_ai(port, in.s_addr, hints);
192                 if (*res == NULL) 
193                         return (EAI_MEMORY);
194                 return (0);
195         }
196         
197         /* Don't try DNS if AI_NUMERICHOST is set */
198         if (hints && hints->ai_flags & AI_NUMERICHOST)
199                 return (EAI_NONAME);
200         
201         hp = gethostbyname(hostname);
202         if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
203                 struct addrinfo *cur, *prev;
204
205                 cur = prev = *res = NULL;
206                 for (i = 0; hp->h_addr_list[i]; i++) {
207                         struct in_addr *in = (struct in_addr *)hp->h_addr_list[i];
208
209                         cur = malloc_ai(port, in->s_addr, hints);
210                         if (cur == NULL) {
211                                 if (*res != NULL)
212                                         freeaddrinfo(*res);
213                                 return (EAI_MEMORY);
214                         }
215                         if (prev)
216                                 prev->ai_next = cur;
217                         else
218                                 *res = cur;
219
220                         prev = cur;
221                 }
222                 return (0);
223         }
224         
225         return (EAI_NODATA);
226 }
227 #endif /* !HAVE_GETADDRINFO */