summaryrefslogtreecommitdiff
path: root/src/lib/libc/net/getnameinfo.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libc/net/getnameinfo.c')
-rw-r--r--src/lib/libc/net/getnameinfo.c562
1 files changed, 562 insertions, 0 deletions
diff --git a/src/lib/libc/net/getnameinfo.c b/src/lib/libc/net/getnameinfo.c
new file mode 100644
index 0000000000..15aa67d464
--- /dev/null
+++ b/src/lib/libc/net/getnameinfo.c
@@ -0,0 +1,562 @@
1/*
2 * %%% copyright-cmetz-96-bsd
3 * Copyright (c) 1996-1999, Craig Metz, 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. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Craig Metz and
16 * by other contributors.
17 * 4. Neither the name of the author nor the names of contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * 3. All advertising materials mentioning features or use of this software
42 * must display the following acknowledgement:
43 * This product includes software developed by Craig Metz and
44 * by other contributors.
45 * 4. Neither the name of the author nor the names of contributors
46 * may be used to endorse or promote products derived from this software
47 * without specific prior written permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE.
60 *
61 * Redistribution and use in source and binary forms, with or without
62 * modification, are permitted provided that the following conditions
63 * are met:
64 * 1. Redistributions of source code must retain the above copyright
65 * notice, this list of conditions and the following disclaimer.
66 * 2. Redistributions in binary form must reproduce the above copyright
67 * notice, this list of conditions and the following disclaimer in the
68 * documentation and/or other materials provided with the distribution.
69 * 3. All advertising materials mentioning features or use of this software
70 * must display the following acknowledgement:
71 * This product includes software developed by Craig Metz and
72 * by other contributors.
73 * 4. Neither the name of the author nor the names of contributors
74 * may be used to endorse or promote products derived from this software
75 * without specific prior written permission.
76 *
77 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
78 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
79 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
80 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
81 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
82 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
83 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
84 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
85 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
86 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
87 * SUCH DAMAGE.
88 */
89
90/* getnameinfo() v1.38 */
91
92/* To enable debugging support (REQUIRES NRL support library), define: */
93/* #define DEBUG 1 */
94
95#ifdef __OpenBSD__
96#define HAVE_POSIX1G_TYPES 1
97#define INET6 1
98#define LOCAL 1
99#define NETDB 1
100#define SALEN 1
101#undef RESOLVER
102#undef HOSTTABLE
103#undef DEBUG
104#undef HAVE_GETSERVBYNAME_R
105#undef HAVE_GETHOSTBYNAME2_R
106#endif /* __OpenBSD__ */
107
108#include <sys/types.h>
109#include <sys/socket.h>
110
111#include <netinet/in.h>
112#if LOCAL
113#include <sys/un.h>
114#include <sys/utsname.h>
115#endif /* LOCAL */
116#include <netdb.h>
117#include <errno.h>
118#include <string.h>
119#if RESOLVER
120#include <arpa/nameser.h>
121#include <resolv.h>
122#endif /* RESOLVER */
123
124#include "support.h"
125
126#ifndef AF_LOCAL
127#define AF_LOCAL AF_UNIX
128#endif /* AF_LOCAL */
129
130#ifndef min
131#define min(x,y) (((x) > (y)) ? (y) : (x))
132#endif /* min */
133
134#if DEBUG
135#if RESOLVER
136#define DEBUG_MESSAGES (_res.options & RES_DEBUG)
137#else /* RESOLVER */
138int __getnameinfo_debug = 0;
139#define DEBUG_MESSAGES (__getnameinfo_debug)
140#endif /* RESOLVER */
141#endif /* DEBUG */
142
143#if DEBUG
144#define RETURN_ERROR(x) do { \
145 if (DEBUG_MESSAGES) \
146 fprintf(stderr, "%s:%d: returning %s\n", __FILE__, __LINE__, #x); \
147 rval = (x); \
148 goto ret; \
149 } while(0)
150#else /* DEBUG */
151#define RETURN_ERROR(x) do { \
152 rval = (x); \
153 goto ret; \
154 } while(0)
155#endif /* DEBUG */
156
157#if HOSTTABLE
158static int hosttable_lookup_name(int family, void *addr, char *name, int namelen, int flags)
159{
160 int rval;
161 FILE *f;
162 char buffer[1024];
163 char addrbuf[16];
164 char *c, *c2;
165 int i;
166 char *prevcname = NULL;
167
168 if (!(f = fopen("/etc/hosts", "r")))
169 RETURN_ERROR(EAI_SYSTEM);
170
171 while(fgets(buffer, sizeof(buffer), f)) {
172 if (c = strchr(buffer, '#'))
173 *c = 0;
174
175 c = buffer;
176 while(*c && !isspace(*c)) c++;
177 if (!*c)
178 continue;
179
180 *(c++) = 0;
181
182 if (family == AF_INET)
183 if (inet_pton(AF_INET, buffer, addrbuf) > 0)
184 if (!memcmp(addrbuf, addr, sizeof(struct in_addr)))
185 goto build;
186
187#if INET6
188 if (family == AF_INET6)
189 if (inet_pton(AF_INET6, buffer, addrbuf) > 0)
190 if (!memcmp(addrbuf, addr, sizeof(struct in6_addr)))
191 goto build;
192#endif /* INET6 */
193
194 continue;
195
196build:
197 while(*c && isspace(*c)) c++;
198 if (!*c)
199 continue;
200
201 c2 = c;
202 while(*c2 && !isspace(*c2)) c2++;
203 if (!*c2)
204 continue;
205 *c2 = 0;
206
207 if ((flags & NI_NOFQDN) && (_res.options & RES_INIT) && _res.defdname[0] && (c2 = strstr(c + 1, _res.defdname)) && (*(--c2) == '.')) {
208 *c2 = 0;
209 i = min(c2 - c, namelen) - 1;
210 strncpy(name, c, i);
211 } else
212 strncpy(name, c, namelen - 1);
213
214 rval = 0;
215 goto ret;
216 };
217
218 RETURN_ERROR(1);
219
220ret:
221 fclose(f);
222 return rval;
223};
224#endif /* HOSTTABLE */
225
226#if RESOLVER
227#if INET6
228static char hextab[] = { '0', '1', '2', '3', '4', '5', '6', '7',
229 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
230#endif /* INET6 */
231
232struct rrheader {
233 int16_t type;
234 int16_t class;
235 u_int32_t ttl;
236 int16_t size;
237};
238#define RRHEADER_SZ 10
239
240int resolver_lookup_name(const char *ptrname, char *name, int namelen, int flags)
241{
242 int rval;
243 char answer[PACKETSZ];
244 int answerlen;
245 char dn[MAXDNAME];
246 char *prevcname = NULL;
247 void *p, *ep;
248 int answers, i;
249 uint16_t rtype, rclass;
250
251 if ((answerlen = res_search(ptrname, C_IN, T_PTR, answer, sizeof(answer))) < 0) {
252 switch(h_errno) {
253 case NETDB_INTERNAL:
254 RETURN_ERROR(EAI_SYSTEM);
255 case HOST_NOT_FOUND:
256 RETURN_ERROR(1);
257 case TRY_AGAIN:
258 RETURN_ERROR(EAI_AGAIN);
259 case NO_RECOVERY:
260 RETURN_ERROR(EAI_FAIL);
261 case NO_DATA:
262 RETURN_ERROR(1);
263 default:
264 RETURN_ERROR(EAI_FAIL);
265 };
266 };
267
268 p = answer;
269 ep = answer + answerlen;
270
271 if (answerlen < sizeof(HEADER))
272 RETURN_ERROR(EAI_FAIL);
273
274 {
275 HEADER *h = (HEADER *)p;
276 if (!h->qr || (h->opcode != QUERY) || (h->qdcount != htons(1)) || !h->ancount)
277 RETURN_ERROR(EAI_FAIL);
278
279 answers = ntohs(h->ancount);
280 };
281 p += sizeof(HEADER);
282
283 if ((i = dn_expand(answer, ep, p, dn, sizeof(dn))) < 0)
284 RETURN_ERROR(EAI_FAIL);
285
286 p += i;
287
288 if (p + 2*sizeof(u_int16_t) >= ep)
289 RETURN_ERROR(EAI_FAIL);
290
291 GETSHORT(rtype, p);
292 GETSHORT(rclass, p);
293
294 if ((rtype != T_PTR) || (rclass != C_IN))
295 RETURN_ERROR(EAI_FAIL);
296
297 while(answers--) {
298 if ((i = dn_expand(answer, ep, p, dn, sizeof(dn))) < 0)
299 RETURN_ERROR(EAI_FAIL);
300
301 p += i;
302
303 if (p + RRHEADER_SZ >= ep)
304 RETURN_ERROR(EAI_FAIL);
305
306 GETSHORT(rtype, p);
307 GETSHORT(rclass, p);
308 p += sizeof(uint32_t);
309 if (rclass != C_IN)
310 RETURN_ERROR(EAI_FAIL);
311 GETSHORT(rclass, p);
312 i = rclass;
313
314 if (p + i > ep)
315 RETURN_ERROR(EAI_FAIL);
316
317 if (rtype == T_PTR) {
318 if (dn_expand(answer, ep, p, dn, sizeof(dn)) != i)
319 RETURN_ERROR(EAI_FAIL);
320
321 {
322 char *c2;
323
324 if ((flags & NI_NOFQDN) && (_res.options & RES_INIT) && _res.defdname[0] && (c2 = strstr(dn + 1, _res.defdname)) && (*(--c2) == '.')) {
325 *c2 = 0;
326 strncpy(name, dn, min(c2 - dn, namelen) - 1);
327 } else
328 strncpy(name, dn, namelen - 1);
329 };
330 };
331 p += i;
332 };
333
334 rval = 0;
335
336ret:
337 return rval;
338};
339#endif /* RESOLVER */
340
341#if NETDB
342static int netdb_lookup_name(int family, void *addr, int addrlen, char *name,
343 int namelen)
344{
345 struct hostent *hostent;
346 char *c, *c2;
347 int rval, i;
348
349 if (!(hostent = gethostbyaddr(addr, addrlen, family))) {
350 switch(h_errno) {
351 case NETDB_INTERNAL:
352 RETURN_ERROR(EAI_SYSTEM);
353 case HOST_NOT_FOUND:
354 RETURN_ERROR(1);
355 case TRY_AGAIN:
356 RETURN_ERROR(EAI_AGAIN);
357 case NO_RECOVERY:
358 RETURN_ERROR(EAI_FAIL);
359 case NO_DATA:
360 RETURN_ERROR(1);
361 default:
362 RETURN_ERROR(EAI_FAIL);
363 };
364 };
365
366 endhostent();
367
368 c = hostent->h_name;
369 if ((flags & NI_NOFQDN) && (_res.options & RES_INIT) && _res.defdname[0] &&
370 (c2 = strstr(c + 1, _res.defdname)) && (*(--c2) == '.')) {
371 *c2 = 0;
372 i = min(c2 - c, namelen) - 1;
373 strncpy(name, c, i);
374 } else
375 strncpy(name, c, namelen - 1);
376
377 rval = 0;
378
379ret:
380 return rval;
381}
382#endif /* NETDB */
383
384int getnameinfo(const struct sockaddr *sa, size_t addrlen, char *host, size_t hostlen, char *serv, size_t servlen, int flags)
385{
386 int rval;
387 int serrno = errno;
388
389 if (!sa || (addrlen != SA_LEN(sa)))
390 RETURN_ERROR(EAI_FAIL);
391
392 if (host && (hostlen > 0))
393 switch(sa->sa_family) {
394#if INET6
395 case AF_INET6:
396 if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)sa)->sin6_addr)) {
397 if (flags & NI_NUMERICHOST)
398 goto inet6_noname;
399 else
400 strncpy(host, "*", hostlen - 1);
401 break;
402 };
403
404 if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)sa)->sin6_addr)) {
405 struct sockaddr_in sin;
406 memset(&sin, 0, sizeof(struct sockaddr_in));
407#if SALEN
408 sin.sin_len = sizeof(struct sockaddr_in);
409#endif /* SALEN */
410 sin.sin_family = AF_INET;
411 sin.sin_port = ((struct sockaddr_in6 *)sa)->sin6_port;
412 sin.sin_addr.s_addr = ((u_int32_t *)&((struct sockaddr_in6 *)sa)->sin6_addr)[3];
413 if (!(rval = getnameinfo((struct sockaddr *)&sin, sizeof(struct sockaddr_in), host, hostlen, serv, servlen, flags | NI_NAMEREQD)))
414 goto ret;
415 if (rval != EAI_NONAME)
416 goto ret;
417 goto inet6_noname;
418 };
419
420 if (flags & NI_NUMERICHOST)
421 goto inet6_noname;
422
423#if HOSTTABLE
424 if ((rval = hosttable_lookup_name(AF_INET6, &((struct sockaddr_in6 *)sa)->sin6_addr, host, hostlen, flags)) < 0)
425 goto ret;
426
427 if (!rval)
428 break;
429#endif /* HOSTTABLE */
430#if RESOLVER
431 {
432 char ptrname[sizeof("0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.ip6.int.")];
433 {
434 int i;
435 char *c = ptrname;
436 u_int8_t *p = (u_int8_t *)&((struct sockaddr_in6 *)sa)->sin6_addr + sizeof(struct in6_addr) - 1;
437
438 for (i = sizeof(struct in6_addr) / sizeof(u_int8_t); i > 0; i--, p--) {
439 *(c++) = hextab[*p & 0x0f];
440 *(c++) = '.';
441 *(c++) = hextab[(*p & 0xf0) >> 4];
442 *(c++) = '.';
443 };
444 strcpy(c, "ip6.int.");
445 };
446
447 if ((rval = resolver_lookup_name(ptrname, host, hostlen, flags)) < 0)
448 goto ret;
449
450 if (!rval)
451 break;
452 };
453#endif /* RESOLVER */
454
455inet6_noname:
456 if (flags & NI_NAMEREQD)
457 RETURN_ERROR(EAI_NONAME);
458
459 if (!inet_ntop(AF_INET6, &((struct sockaddr_in6 *)sa)->sin6_addr, host, hostlen))
460 RETURN_ERROR(EAI_NONAME);
461
462 break;
463#endif /* INET6 */
464 case AF_INET:
465 if (flags & NI_NUMERICHOST)
466 goto inet_noname;
467
468 if (!((struct sockaddr_in *)sa)->sin_addr.s_addr) {
469 strncpy(host, "*", hostlen - 1);
470 break;
471 };
472
473#if HOSTTABLE
474 if ((rval = hosttable_lookup_name(AF_INET, &((struct sockaddr_in *)sa)->sin_addr, host, hostlen, flags)) < 0)
475 goto ret;
476
477 if (!rval)
478 break;
479#endif /* HOSTTABLE */
480#if RESOLVER
481 {
482 char ptrname[30];
483 u_int8_t *p = (u_int8_t *)&((struct sockaddr_in *)sa)->sin_addr;
484 sprintf(ptrname, "%d.%d.%d.%d.in-addr.arpa.", p[3], p[2], p[1], p[0]);
485
486 if ((rval = resolver_lookup_name(ptrname, host, hostlen, flags)) < 0)
487 goto ret;
488
489 if (!rval)
490 break;
491 };
492#endif /* RESOLVER */
493
494inet_noname:
495 if (flags & NI_NAMEREQD)
496 RETURN_ERROR(EAI_NONAME);
497
498 if (!inet_ntop(AF_INET, &((struct sockaddr_in *)sa)->sin_addr, host, hostlen))
499 RETURN_ERROR(EAI_NONAME);
500
501 break;
502#if LOCAL
503 case AF_LOCAL:
504 if (!(flags & NI_NUMERICHOST)) {
505 struct utsname utsname;
506
507 if (!uname(&utsname)) {
508 strncpy(host, utsname.nodename, hostlen - 1);
509 break;
510 };
511 };
512
513 if (flags & NI_NAMEREQD)
514 RETURN_ERROR(EAI_NONAME);
515
516 strncpy(host, "localhost", hostlen - 1);
517 break;
518#endif /* LOCAL */
519 default:
520 RETURN_ERROR(EAI_FAMILY);
521 };
522
523 if (serv && (servlen > 0))
524 switch(sa->sa_family) {
525 case AF_INET:
526#if INET6
527 case AF_INET6:
528#endif /* INET6 */
529 if (!(flags & NI_NUMERICSERV)) {
530 struct servent *s;
531 if (s = getservbyport(((struct sockaddr_in *)sa)->sin_port, (flags & NI_DGRAM) ? "udp" : "tcp")) {
532 strncpy(serv, s->s_name, servlen - 1);
533 break;
534 };
535 if (!((struct sockaddr_in *)sa)->sin_port) {
536 strncpy(serv, "*", servlen - 1);
537 break;
538 };
539 };
540 snprintf(serv, servlen - 1, "%d", ntohs(((struct sockaddr_in *)sa)->sin_port));
541 break;
542#if LOCAL
543 case AF_LOCAL:
544 strncpy(serv, ((struct sockaddr_un *)sa)->sun_path, servlen - 1);
545 break;
546#endif /* LOCAL */
547 };
548
549 if (host && (hostlen > 0))
550 host[hostlen-1] = 0;
551 if (serv && (servlen > 0))
552 serv[servlen-1] = 0;
553 rval = 0;
554
555ret:
556 if (rval == 1)
557 rval = EAI_FAIL;
558
559 errno = serrno;
560
561 return rval;
562};