Deleted Added
full compact
name6.c (55877) name6.c (56698)
1/*
2 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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 *
1/*
2 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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 * $FreeBSD: head/lib/libc/net/name6.c 55877 2000-01-13 05:47:11Z shin $
29 * $FreeBSD: head/lib/libc/net/name6.c 56698 2000-01-27 23:07:25Z jasone $
30 */
31/* $Id: name6.c,v 1.9 1999/10/29 03:04:26 itojun Exp $ */
32/*
33 * Atsushi Onoe <onoe@sm.sony.co.jp>
34 */
35
36/*
37 * TODO for thread safe
38 * use mutex for _hostconf, _hostconf_init.
39 * rewrite resolvers to be thread safe
40 */
41
42#include <sys/param.h>
43#include <sys/socket.h>
44#include <sys/time.h>
45#include <netinet/in.h>
46
47#include <arpa/inet.h>
48#include <arpa/nameser.h>
49
50#include <netdb.h>
51#include <resolv.h>
52#include <stdio.h>
53#include <stdlib.h>
54#include <string.h>
55#include <unistd.h>
56
57#ifndef _PATH_HOSTS
58#define _PATH_HOSTS "/etc/hosts"
59#endif
60
61#ifndef MAXALIASES
62#define MAXALIASES 10
63#endif
64#ifndef MAXADDRS
65#define MAXADDRS 20
66#endif
67#ifndef MAXDNAME
68#define MAXDNAME 1025
69#endif
70
71#ifdef INET6
72#define ADDRLEN(af) ((af) == AF_INET6 ? sizeof(struct in6_addr) : \
73 sizeof(struct in_addr))
74#else
75#define ADDRLEN(af) sizeof(struct in_addr)
76#endif
77
78#define MAPADDR(ab, ina) \
79do { \
80 memcpy(&(ab)->map_inaddr, ina, sizeof(struct in_addr)); \
81 memset((ab)->map_zero, 0, sizeof((ab)->map_zero)); \
82 memset((ab)->map_one, 0xff, sizeof((ab)->map_one)); \
83} while (0)
84#define MAPADDRENABLED(flags) \
85 (((flags) & AI_V4MAPPED) || \
86 (((flags) & AI_V4MAPPED_CFG) && _mapped_addr_enabled()))
87
88union inx_addr {
89 struct in_addr in_addr;
90#ifdef INET6
91 struct in6_addr in6_addr;
92#endif
93 struct {
94 u_char mau_zero[10];
95 u_char mau_one[2];
96 struct in_addr mau_inaddr;
97 } map_addr_un;
98#define map_zero map_addr_un.mau_zero
99#define map_one map_addr_un.mau_one
100#define map_inaddr map_addr_un.mau_inaddr
101};
102
103static struct hostent *_hpcopy(struct hostent *hp, int *errp);
104static struct hostent *_hpaddr(int af, const char *name, void *addr, int *errp);
105static struct hostent *_hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp);
106#ifdef INET6
107static struct hostent *_hpmapv6(struct hostent *hp, int *errp);
108#endif
109static struct hostent *_hpsort(struct hostent *hp);
110static struct hostent *_ghbyname(const char *name, int af, int flags, int *errp);
111static char *_hgetword(char **pp);
112static int _mapped_addr_enabled(void);
113
114static FILE *_files_open(int *errp);
115static struct hostent *_files_ghbyname(const char *name, int af, int *errp);
116static struct hostent *_files_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
117static void _files_shent(int stayopen);
118static void _files_ehent(void);
119static struct hostent *_dns_ghbyname(const char *name, int af, int *errp);
120static struct hostent *_dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
121static void _dns_shent(int stayopen);
122static void _dns_ehent(void);
123#ifdef ICMPNL
124static struct hostent *_icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
125#endif /* ICMPNL */
126
127/*
128 * Select order host function.
129 */
130#define MAXHOSTCONF 4
131
132#ifndef HOSTCONF
133# define HOSTCONF "/etc/host.conf"
134#endif /* !HOSTCONF */
135
136struct _hostconf {
137 struct hostent *(*byname)(const char *name, int af, int *errp);
138 struct hostent *(*byaddr)(const void *addr, int addrlen, int af, int *errp);
139};
140
141/* default order */
142static struct _hostconf _hostconf[MAXHOSTCONF] = {
143 { _dns_ghbyname, _dns_ghbyaddr },
144 { _files_ghbyname, _files_ghbyaddr },
145#ifdef ICMPNL
146 { NULL, _icmp_ghbyaddr },
147#endif /* ICMPNL */
148};
149
150static int _hostconf_init_done;
151static void _hostconf_init(void);
152
153/*
154 * Initialize hostconf structure.
155 */
156
157static void
158_hostconf_init(void)
159{
160 FILE *fp;
161 int n;
162 char *p, *line;
163 char buf[BUFSIZ];
164
165 _hostconf_init_done = 1;
166 n = 0;
167 p = HOSTCONF;
168 if ((fp = fopen(p, "r")) == NULL)
169 return;
170 while (n < MAXHOSTCONF && fgets(buf, sizeof(buf), fp)) {
171 line = buf;
172 if ((p = _hgetword(&line)) == NULL)
173 continue;
174 do {
175 if (strcmp(p, "hosts") == 0
176 || strcmp(p, "local") == 0
177 || strcmp(p, "file") == 0
178 || strcmp(p, "files") == 0) {
179 _hostconf[n].byname = _files_ghbyname;
180 _hostconf[n].byaddr = _files_ghbyaddr;
181 n++;
182 }
183 else if (strcmp(p, "dns") == 0
184 || strcmp(p, "bind") == 0) {
185 _hostconf[n].byname = _dns_ghbyname;
186 _hostconf[n].byaddr = _dns_ghbyaddr;
187 n++;
188 }
189#ifdef ICMPNL
190 else if (strcmp(p, "icmp") == 0) {
191 _hostconf[n].byname = NULL;
192 _hostconf[n].byaddr = _icmp_ghbyaddr;
193 n++;
194 }
195#endif /* ICMPNL */
196 } while ((p = _hgetword(&line)) != NULL);
197 }
198 fclose(fp);
199 if (n < 0) {
200 /* no keyword found. do not change default configuration */
201 return;
202 }
203 for (; n < MAXHOSTCONF; n++) {
204 _hostconf[n].byname = NULL;
205 _hostconf[n].byaddr = NULL;
206 }
207}
208
209/*
210 * Check if kernel supports mapped address.
211 * implementation dependent
212 */
213#ifdef __KAME__
214#include <sys/sysctl.h>
215#endif /* __KAME__ */
216
217static int
218_mapped_addr_enabled(void)
219{
220 /* implementation dependent check */
221#if defined(__KAME__) && defined(IPV6CTL_MAPPED_ADDR)
222 int mib[4];
223 size_t len;
224 int val;
225
226 mib[0] = CTL_NET;
227 mib[1] = PF_INET6;
228 mib[2] = IPPROTO_IPV6;
229 mib[3] = IPV6CTL_MAPPED_ADDR;
230 len = sizeof(val);
231 if (sysctl(mib, 4, &val, &len, 0, 0) == 0 && val != 0)
232 return 1;
233#endif /* __KAME__ && IPV6CTL_MAPPED_ADDR */
234 return 0;
235}
236
237/*
238 * Functions defined in RFC2553
239 * getipnodebyname, getipnodebyadr, freehostent
240 */
241
242static struct hostent *
243_ghbyname(const char *name, int af, int flags, int *errp)
244{
245 struct hostent *hp;
246 int i;
247
248 if (flags & AI_ADDRCONFIG) {
249 int s;
250
251 if ((s = socket(af, SOCK_DGRAM, 0)) < 0)
252 return NULL;
253 /*
254 * TODO:
255 * Note that implementation dependent test for address
256 * configuration should be done everytime called
257 * (or apropriate interval),
258 * because addresses will be dynamically assigned or deleted.
259 */
30 */
31/* $Id: name6.c,v 1.9 1999/10/29 03:04:26 itojun Exp $ */
32/*
33 * Atsushi Onoe <onoe@sm.sony.co.jp>
34 */
35
36/*
37 * TODO for thread safe
38 * use mutex for _hostconf, _hostconf_init.
39 * rewrite resolvers to be thread safe
40 */
41
42#include <sys/param.h>
43#include <sys/socket.h>
44#include <sys/time.h>
45#include <netinet/in.h>
46
47#include <arpa/inet.h>
48#include <arpa/nameser.h>
49
50#include <netdb.h>
51#include <resolv.h>
52#include <stdio.h>
53#include <stdlib.h>
54#include <string.h>
55#include <unistd.h>
56
57#ifndef _PATH_HOSTS
58#define _PATH_HOSTS "/etc/hosts"
59#endif
60
61#ifndef MAXALIASES
62#define MAXALIASES 10
63#endif
64#ifndef MAXADDRS
65#define MAXADDRS 20
66#endif
67#ifndef MAXDNAME
68#define MAXDNAME 1025
69#endif
70
71#ifdef INET6
72#define ADDRLEN(af) ((af) == AF_INET6 ? sizeof(struct in6_addr) : \
73 sizeof(struct in_addr))
74#else
75#define ADDRLEN(af) sizeof(struct in_addr)
76#endif
77
78#define MAPADDR(ab, ina) \
79do { \
80 memcpy(&(ab)->map_inaddr, ina, sizeof(struct in_addr)); \
81 memset((ab)->map_zero, 0, sizeof((ab)->map_zero)); \
82 memset((ab)->map_one, 0xff, sizeof((ab)->map_one)); \
83} while (0)
84#define MAPADDRENABLED(flags) \
85 (((flags) & AI_V4MAPPED) || \
86 (((flags) & AI_V4MAPPED_CFG) && _mapped_addr_enabled()))
87
88union inx_addr {
89 struct in_addr in_addr;
90#ifdef INET6
91 struct in6_addr in6_addr;
92#endif
93 struct {
94 u_char mau_zero[10];
95 u_char mau_one[2];
96 struct in_addr mau_inaddr;
97 } map_addr_un;
98#define map_zero map_addr_un.mau_zero
99#define map_one map_addr_un.mau_one
100#define map_inaddr map_addr_un.mau_inaddr
101};
102
103static struct hostent *_hpcopy(struct hostent *hp, int *errp);
104static struct hostent *_hpaddr(int af, const char *name, void *addr, int *errp);
105static struct hostent *_hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp);
106#ifdef INET6
107static struct hostent *_hpmapv6(struct hostent *hp, int *errp);
108#endif
109static struct hostent *_hpsort(struct hostent *hp);
110static struct hostent *_ghbyname(const char *name, int af, int flags, int *errp);
111static char *_hgetword(char **pp);
112static int _mapped_addr_enabled(void);
113
114static FILE *_files_open(int *errp);
115static struct hostent *_files_ghbyname(const char *name, int af, int *errp);
116static struct hostent *_files_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
117static void _files_shent(int stayopen);
118static void _files_ehent(void);
119static struct hostent *_dns_ghbyname(const char *name, int af, int *errp);
120static struct hostent *_dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
121static void _dns_shent(int stayopen);
122static void _dns_ehent(void);
123#ifdef ICMPNL
124static struct hostent *_icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
125#endif /* ICMPNL */
126
127/*
128 * Select order host function.
129 */
130#define MAXHOSTCONF 4
131
132#ifndef HOSTCONF
133# define HOSTCONF "/etc/host.conf"
134#endif /* !HOSTCONF */
135
136struct _hostconf {
137 struct hostent *(*byname)(const char *name, int af, int *errp);
138 struct hostent *(*byaddr)(const void *addr, int addrlen, int af, int *errp);
139};
140
141/* default order */
142static struct _hostconf _hostconf[MAXHOSTCONF] = {
143 { _dns_ghbyname, _dns_ghbyaddr },
144 { _files_ghbyname, _files_ghbyaddr },
145#ifdef ICMPNL
146 { NULL, _icmp_ghbyaddr },
147#endif /* ICMPNL */
148};
149
150static int _hostconf_init_done;
151static void _hostconf_init(void);
152
153/*
154 * Initialize hostconf structure.
155 */
156
157static void
158_hostconf_init(void)
159{
160 FILE *fp;
161 int n;
162 char *p, *line;
163 char buf[BUFSIZ];
164
165 _hostconf_init_done = 1;
166 n = 0;
167 p = HOSTCONF;
168 if ((fp = fopen(p, "r")) == NULL)
169 return;
170 while (n < MAXHOSTCONF && fgets(buf, sizeof(buf), fp)) {
171 line = buf;
172 if ((p = _hgetword(&line)) == NULL)
173 continue;
174 do {
175 if (strcmp(p, "hosts") == 0
176 || strcmp(p, "local") == 0
177 || strcmp(p, "file") == 0
178 || strcmp(p, "files") == 0) {
179 _hostconf[n].byname = _files_ghbyname;
180 _hostconf[n].byaddr = _files_ghbyaddr;
181 n++;
182 }
183 else if (strcmp(p, "dns") == 0
184 || strcmp(p, "bind") == 0) {
185 _hostconf[n].byname = _dns_ghbyname;
186 _hostconf[n].byaddr = _dns_ghbyaddr;
187 n++;
188 }
189#ifdef ICMPNL
190 else if (strcmp(p, "icmp") == 0) {
191 _hostconf[n].byname = NULL;
192 _hostconf[n].byaddr = _icmp_ghbyaddr;
193 n++;
194 }
195#endif /* ICMPNL */
196 } while ((p = _hgetword(&line)) != NULL);
197 }
198 fclose(fp);
199 if (n < 0) {
200 /* no keyword found. do not change default configuration */
201 return;
202 }
203 for (; n < MAXHOSTCONF; n++) {
204 _hostconf[n].byname = NULL;
205 _hostconf[n].byaddr = NULL;
206 }
207}
208
209/*
210 * Check if kernel supports mapped address.
211 * implementation dependent
212 */
213#ifdef __KAME__
214#include <sys/sysctl.h>
215#endif /* __KAME__ */
216
217static int
218_mapped_addr_enabled(void)
219{
220 /* implementation dependent check */
221#if defined(__KAME__) && defined(IPV6CTL_MAPPED_ADDR)
222 int mib[4];
223 size_t len;
224 int val;
225
226 mib[0] = CTL_NET;
227 mib[1] = PF_INET6;
228 mib[2] = IPPROTO_IPV6;
229 mib[3] = IPV6CTL_MAPPED_ADDR;
230 len = sizeof(val);
231 if (sysctl(mib, 4, &val, &len, 0, 0) == 0 && val != 0)
232 return 1;
233#endif /* __KAME__ && IPV6CTL_MAPPED_ADDR */
234 return 0;
235}
236
237/*
238 * Functions defined in RFC2553
239 * getipnodebyname, getipnodebyadr, freehostent
240 */
241
242static struct hostent *
243_ghbyname(const char *name, int af, int flags, int *errp)
244{
245 struct hostent *hp;
246 int i;
247
248 if (flags & AI_ADDRCONFIG) {
249 int s;
250
251 if ((s = socket(af, SOCK_DGRAM, 0)) < 0)
252 return NULL;
253 /*
254 * TODO:
255 * Note that implementation dependent test for address
256 * configuration should be done everytime called
257 * (or apropriate interval),
258 * because addresses will be dynamically assigned or deleted.
259 */
260 _libc_close(s);
260 _close(s);
261 }
262
263 for (i = 0; i < MAXHOSTCONF; i++) {
264 if (_hostconf[i].byname
265 && (hp = (*_hostconf[i].byname)(name, af, errp))
266 != NULL)
267 return hp;
268 }
269
270 return NULL;
271}
272
273struct hostent *
274getipnodebyname(const char *name, int af, int flags, int *errp)
275{
276 struct hostent *hp;
277 union inx_addr addrbuf;
278
279 if (af != AF_INET
280#ifdef INET6
281 && af != AF_INET6
282#endif
283 )
284 {
285 *errp = NO_RECOVERY;
286 return NULL;
287 }
288
289#ifdef INET6
290 /* special case for literal address */
291 if (inet_pton(AF_INET6, name, &addrbuf) == 1) {
292 if (af != AF_INET6) {
293 *errp = HOST_NOT_FOUND;
294 return NULL;
295 }
296 return _hpaddr(af, name, &addrbuf, errp);
297 }
298#endif
299 if (inet_pton(AF_INET, name, &addrbuf) == 1) {
300 if (af != AF_INET) {
301 if (MAPADDRENABLED(flags)) {
302 MAPADDR(&addrbuf, &addrbuf.in_addr);
303 } else {
304 *errp = HOST_NOT_FOUND;
305 return NULL;
306 }
307 }
308 return _hpaddr(af, name, &addrbuf, errp);
309 }
310
311 if (!_hostconf_init_done)
312 _hostconf_init();
313
314 *errp = HOST_NOT_FOUND;
315 hp = _ghbyname(name, af, flags, errp);
316
317#ifdef INET6
318 if (af == AF_INET6
319 && ((flags & AI_ALL) || hp == NULL)
320 && (MAPADDRENABLED(flags))) {
321 struct hostent *hp2 = _ghbyname(name, AF_INET, flags, errp);
322 if (hp == NULL)
323 hp = _hpmapv6(hp2, errp);
324 else {
325 if (hp2 && strcmp(hp->h_name, hp2->h_name) != 0) {
326 freehostent(hp2);
327 hp2 = NULL;
328 }
329 hp = _hpmerge(hp, hp2, errp);
330 }
331 }
332#endif
333 return _hpsort(hp);
334}
335
336struct hostent *
337getipnodebyaddr(const void *src, size_t len, int af, int *errp)
338{
339 struct hostent *hp;
340 int i;
341#ifdef INET6
342 struct in6_addr addrbuf;
343#else
344 struct in_addr addrbuf;
345#endif
346
347 *errp = HOST_NOT_FOUND;
348
349 switch (af) {
350 case AF_INET:
351 if (len != sizeof(struct in_addr)) {
352 *errp = NO_RECOVERY;
353 return NULL;
354 }
355 if ((long)src & ~(sizeof(struct in_addr) - 1)) {
356 memcpy(&addrbuf, src, len);
357 src = &addrbuf;
358 }
359 if (((struct in_addr *)src)->s_addr == 0)
360 return NULL;
361 break;
362#ifdef INET6
363 case AF_INET6:
364 if (len != sizeof(struct in6_addr)) {
365 *errp = NO_RECOVERY;
366 return NULL;
367 }
368 if ((long)src & ~(sizeof(struct in6_addr) / 2 - 1)) { /*XXX*/
369 memcpy(&addrbuf, src, len);
370 src = &addrbuf;
371 }
372 if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)src))
373 return NULL;
374 if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)src)
375 || IN6_IS_ADDR_V4COMPAT((struct in6_addr *)src)) {
376 src = (char *)src +
377 (sizeof(struct in6_addr) - sizeof(struct in_addr));
378 af = AF_INET;
379 len = sizeof(struct in_addr);
380 }
381 break;
382#endif
383 default:
384 *errp = NO_RECOVERY;
385 return NULL;
386 }
387
388 if (!_hostconf_init_done)
389 _hostconf_init();
390 for (i = 0; i < MAXHOSTCONF; i++) {
391 if (_hostconf[i].byaddr
392 && (hp = (*_hostconf[i].byaddr)(src, len, af, errp)) != NULL)
393 return hp;
394 }
395
396 return NULL;
397}
398
399void
400freehostent(struct hostent *ptr)
401{
402 free(ptr);
403}
404
405#if 0
406
407/* XXX: should be deprecated */
408struct hostent *
409getnodebyname(const char *name, int af, int flags)
410{
411 return getipnodebyname(name, af, flags, &h_errno);
412}
413
414#ifdef __warn_references
415__warn_references(getnodebyname,
416 "warning: getnodebyname() deprecated, "
417 "should use getaddrinfo() or getipnodebyname()");
418#endif
419
420struct hostent *
421getnodebyaddr(const void *src, size_t len, int af)
422{
423 return getipnodebyaddr(src, len, af, &h_errno);
424}
425
426#ifdef __warn_references
427__warn_references(getnodebyaddr,
428 "warning: getnodebyaddr() deprecated, "
429 "should use getnameinfo() or getipnodebyaddr()");
430#endif
431
432#endif
433
434/*
435 * Private utility functions
436 */
437
438/*
439 * _hpcopy: allocate and copy hostent structure
440 */
441static struct hostent *
442_hpcopy(struct hostent *hp, int *errp)
443{
444 struct hostent *nhp;
445 char *cp, **pp;
446 int size, addrsize;
447 int nalias = 0, naddr = 0;
448 int al_off;
449 int i;
450
451 if (hp == NULL)
452 return hp;
453
454 /* count size to be allocated */
455 size = sizeof(struct hostent);
456 if (hp->h_name != NULL && *hp->h_name != '\0')
457 size += strlen(hp->h_name) + 1;
458 if ((pp = hp->h_aliases) != NULL) {
459 for (i = 0; *pp != NULL; i++, pp++) {
460 if (**pp != '\0') {
461 size += strlen(*pp) + 1;
462 nalias++;
463 }
464 }
465 }
466 /* adjust alignment */
467 size = ALIGN(size);
468 al_off = size;
469 size += sizeof(char *) * (nalias + 1);
470 addrsize = ALIGN(hp->h_length);
471 if ((pp = hp->h_addr_list) != NULL) {
472 while (*pp++ != NULL)
473 naddr++;
474 }
475 size += addrsize * naddr;
476 size += sizeof(char *) * (naddr + 1);
477
478 /* copy */
479 if ((nhp = (struct hostent *)malloc(size)) == NULL) {
480 *errp = TRY_AGAIN;
481 return NULL;
482 }
483 cp = (char *)&nhp[1];
484 if (hp->h_name != NULL && *hp->h_name != '\0') {
485 nhp->h_name = cp;
486 strcpy(cp, hp->h_name);
487 cp += strlen(cp) + 1;
488 } else
489 nhp->h_name = NULL;
490 nhp->h_aliases = (char **)((char *)nhp + al_off);
491 if ((pp = hp->h_aliases) != NULL) {
492 for (i = 0; *pp != NULL; pp++) {
493 if (**pp != '\0') {
494 nhp->h_aliases[i++] = cp;
495 strcpy(cp, *pp);
496 cp += strlen(cp) + 1;
497 }
498 }
499 }
500 nhp->h_aliases[nalias] = NULL;
501 cp = (char *)&nhp->h_aliases[nalias + 1];
502 nhp->h_addrtype = hp->h_addrtype;
503 nhp->h_length = hp->h_length;
504 nhp->h_addr_list = (char **)cp;
505 if ((pp = hp->h_addr_list) != NULL) {
506 cp = (char *)&nhp->h_addr_list[naddr + 1];
507 for (i = 0; *pp != NULL; pp++) {
508 nhp->h_addr_list[i++] = cp;
509 memcpy(cp, *pp, hp->h_length);
510 cp += addrsize;
511 }
512 }
513 nhp->h_addr_list[naddr] = NULL;
514 return nhp;
515}
516
517/*
518 * _hpaddr: construct hostent structure with one address
519 */
520static struct hostent *
521_hpaddr(int af, const char *name, void *addr, int *errp)
522{
523 struct hostent *hp, hpbuf;
524 char *addrs[2];
525
526 hp = &hpbuf;
527 hp->h_name = (char *)name;
528 hp->h_aliases = NULL;
529 hp->h_addrtype = af;
530 hp->h_length = ADDRLEN(af);
531 hp->h_addr_list = addrs;
532 addrs[0] = (char *)addr;
533 addrs[1] = NULL;
534 return _hpcopy(hp, errp);
535}
536
537/*
538 * _hpmerge: merge 2 hostent structure, arguments will be freed
539 */
540static struct hostent *
541_hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp)
542{
543 int i, j;
544 int naddr, nalias;
545 char **pp;
546 struct hostent *hp, hpbuf;
547 char *aliases[MAXALIASES + 1], *addrs[MAXADDRS + 1];
548 union inx_addr addrbuf[MAXADDRS];
549
550 if (hp1 == NULL)
551 return hp2;
552 if (hp2 == NULL)
553 return hp1;
554
555#define HP(i) (i == 1 ? hp1 : hp2)
556 hp = &hpbuf;
557 hp->h_name = (hp1->h_name != NULL ? hp1->h_name : hp2->h_name);
558 hp->h_aliases = aliases;
559 nalias = 0;
560 for (i = 1; i <= 2; i++) {
561 if ((pp = HP(i)->h_aliases) == NULL)
562 continue;
563 for (; nalias < MAXALIASES && *pp != NULL; pp++) {
564 /* check duplicates */
565 for (j = 0; j < nalias; j++)
566 if (strcasecmp(*pp, aliases[j]) == 0)
567 break;
568 if (j == nalias)
569 aliases[nalias++] = *pp;
570 }
571 }
572 aliases[nalias] = NULL;
573#ifdef INET6
574 if (hp1->h_length != hp2->h_length) {
575 hp->h_addrtype = AF_INET6;
576 hp->h_length = sizeof(struct in6_addr);
577 } else {
578#endif
579 hp->h_addrtype = hp1->h_addrtype;
580 hp->h_length = hp1->h_length;
581#ifdef INET6
582 }
583#endif
584 hp->h_addr_list = addrs;
585 naddr = 0;
586 for (i = 1; i <= 2; i++) {
587 if ((pp = HP(i)->h_addr_list) == NULL)
588 continue;
589 if (HP(i)->h_length == hp->h_length) {
590 while (naddr < MAXADDRS && *pp != NULL)
591 addrs[naddr++] = *pp++;
592 } else {
593 /* copy IPv4 addr as mapped IPv6 addr */
594 while (naddr < MAXADDRS && *pp != NULL) {
595 MAPADDR(&addrbuf[naddr], *pp++);
596 addrs[naddr] = (char *)&addrbuf[naddr];
597 naddr++;
598 }
599 }
600 }
601 addrs[naddr] = NULL;
602 hp = _hpcopy(hp, errp);
603 freehostent(hp1);
604 freehostent(hp2);
605 return hp;
606}
607
608/*
609 * _hpmapv6: convert IPv4 hostent into IPv4-mapped IPv6 addresses
610 */
611#ifdef INET6
612static struct hostent *
613_hpmapv6(struct hostent *hp, int *errp)
614{
615 struct hostent *hp6;
616
617 if (hp == NULL)
618 return NULL;
619 if (hp->h_addrtype == AF_INET6)
620 return hp;
621
622 /* make dummy hostent to convert IPv6 address */
623 if ((hp6 = (struct hostent *)malloc(sizeof(struct hostent))) == NULL) {
624 *errp = TRY_AGAIN;
625 return NULL;
626 }
627 hp6->h_name = NULL;
628 hp6->h_aliases = NULL;
629 hp6->h_addrtype = AF_INET6;
630 hp6->h_length = sizeof(struct in6_addr);
631 hp6->h_addr_list = NULL;
632 return _hpmerge(hp6, hp, errp);
633}
634#endif
635
636/*
637 * _hpsort: sort address by sortlist
638 */
639static struct hostent *
640_hpsort(struct hostent *hp)
641{
642 int i, j, n;
643 u_char *ap, *sp, *mp, **pp;
644 char t;
645 char order[MAXADDRS];
646 int nsort = _res.nsort;
647
648 if (hp == NULL || hp->h_addr_list[1] == NULL || nsort == 0)
649 return hp;
650 for (i = 0; (ap = (u_char *)hp->h_addr_list[i]); i++) {
651 for (j = 0; j < nsort; j++) {
652#ifdef INET6
653 if (_res_ext.sort_list[j].af != hp->h_addrtype)
654 continue;
655 sp = (u_char *)&_res_ext.sort_list[j].addr;
656 mp = (u_char *)&_res_ext.sort_list[j].mask;
657#else
658 sp = (u_char *)&_res.sort_list[j].addr;
659 mp = (u_char *)&_res.sort_list[j].mask;
660#endif
661 for (n = 0; n < hp->h_length; n++) {
662 if ((ap[n] & mp[n]) != sp[n])
663 break;
664 }
665 if (n == hp->h_length)
666 break;
667 }
668 order[i] = j;
669 }
670 n = i;
671 pp = (u_char **)hp->h_addr_list;
672 for (i = 0; i < n - 1; i++) {
673 for (j = i + 1; j < n; j++) {
674 if (order[i] > order[j]) {
675 ap = pp[i];
676 pp[i] = pp[j];
677 pp[j] = ap;
678 t = order[i];
679 order[i] = order[j];
680 order[j] = t;
681 }
682 }
683 }
684 return hp;
685}
686
687static char *
688_hgetword(char **pp)
689{
690 char c, *p, *ret;
691 const char *sp;
692 static const char sep[] = "# \t\n";
693
694 ret = NULL;
695 for (p = *pp; (c = *p) != '\0'; p++) {
696 for (sp = sep; *sp != '\0'; sp++) {
697 if (c == *sp)
698 break;
699 }
700 if (c == '#')
701 p[1] = '\0'; /* ignore rest of line */
702 if (ret == NULL) {
703 if (*sp == '\0')
704 ret = p;
705 } else {
706 if (*sp != '\0') {
707 *p++ = '\0';
708 break;
709 }
710 }
711 }
712 *pp = p;
713 if (ret == NULL || *ret == '\0')
714 return NULL;
715 return ret;
716}
717
718/*
719 * FILES (/etc/hosts)
720 */
721
722static FILE *
723_files_open(int *errp)
724{
725 FILE *fp;
726 fp = fopen(_PATH_HOSTS, "r");
727 if (fp == NULL)
728 *errp = NO_RECOVERY;
729 return fp;
730}
731
732static struct hostent *
733_files_ghbyname(const char *name, int af, int *errp)
734{
735 int match, nalias;
736 char *p, *line, *addrstr, *cname;
737 FILE *fp;
738 struct hostent *rethp, *hp, hpbuf;
739 char *aliases[MAXALIASES + 1], *addrs[2];
740 union inx_addr addrbuf;
741 char buf[BUFSIZ];
742
743 if ((fp = _files_open(errp)) == NULL)
744 return NULL;
745 rethp = hp = NULL;
746
747 while (fgets(buf, sizeof(buf), fp)) {
748 line = buf;
749 if ((addrstr = _hgetword(&line)) == NULL
750 || (cname = _hgetword(&line)) == NULL)
751 continue;
752 match = (strcasecmp(cname, name) == 0);
753 nalias = 0;
754 while ((p = _hgetword(&line)) != NULL) {
755 if (!match)
756 match = (strcasecmp(p, name) == 0);
757 if (nalias < MAXALIASES)
758 aliases[nalias++] = p;
759 }
760 if (!match)
761 continue;
762 if (inet_pton(af, addrstr, &addrbuf) != 1) {
763 *errp = NO_DATA; /* name found */
764 continue;
765 }
766 hp = &hpbuf;
767 hp->h_name = cname;
768 hp->h_aliases = aliases;
769 aliases[nalias] = NULL;
770 hp->h_addrtype = af;
771 hp->h_length = ADDRLEN(af);
772 hp->h_addr_list = addrs;
773 addrs[0] = (char *)&addrbuf;
774 addrs[1] = NULL;
775 hp = _hpcopy(hp, errp);
776 rethp = _hpmerge(rethp, hp, errp);
777 }
778 fclose(fp);
779 return rethp;
780}
781
782static struct hostent *
783_files_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
784{
785 int nalias;
786 char *p, *line;
787 FILE *fp;
788 struct hostent *hp, hpbuf;
789 char *aliases[MAXALIASES + 1], *addrs[2];
790 union inx_addr addrbuf;
791 char buf[BUFSIZ];
792
793 if ((fp = _files_open(errp)) == NULL)
794 return NULL;
795 hp = NULL;
796 while (fgets(buf, sizeof(buf), fp)) {
797 line = buf;
798 if ((p = _hgetword(&line)) == NULL
799 || inet_pton(af, p, &addrbuf) != 1
800 || memcmp(addr, &addrbuf, addrlen) != 0
801 || (p = _hgetword(&line)) == NULL)
802 continue;
803 hp = &hpbuf;
804 hp->h_name = p;
805 hp->h_aliases = aliases;
806 nalias = 0;
807 while ((p = _hgetword(&line)) != NULL) {
808 if (nalias < MAXALIASES)
809 aliases[nalias++] = p;
810 }
811 aliases[nalias] = NULL;
812 hp->h_addrtype = af;
813 hp->h_length = addrlen;
814 hp->h_addr_list = addrs;
815 addrs[0] = (char *)&addrbuf;
816 addrs[1] = NULL;
817 hp = _hpcopy(hp, errp);
818 break;
819 }
820 fclose(fp);
821 return hp;
822}
823
824#ifdef DEBUG
825#define DNS_ASSERT(X) if (!(X)) { fprintf(stderr, "ASSFAIL: %s %d: %s\n", __FILE__, __LINE__, #X); goto badanswer; }
826#else
827#define DNS_ASSERT(X) if (!(X)) { goto badanswer; }
828#endif
829
830static struct hostent *
831_dns_ghbyname(const char *name, int af, int *errp)
832{
833 int n;
834 u_char answer[BUFSIZ];
835 char tbuf[MAXDNAME+1];
836 HEADER *hp;
837 u_char *cp, *eom;
838 int qtype;
839 int type, class, ancount, qdcount;
840 u_long ttl;
841 char hostbuf[BUFSIZ];
842 char *bp;
843 char *alist[MAXALIASES];
844 char *hlist[MAXADDRS];
845 struct hostent hbuf;
846 int buflen;
847 int na, nh;
848
849 if ((_res.options & RES_INIT) == 0) {
850 if (res_init() < 0) {
851 *errp = h_errno;
852 return NULL;
853 }
854 }
855 hbuf.h_aliases = alist;
856 hbuf.h_addrtype = af;
857 hbuf.h_length = ADDRLEN(af);
858 hbuf.h_addr_list = hlist;
859 na = nh = 0;
860
861#ifdef INET6
862 qtype = (af == AF_INET6 ? T_AAAA : T_A);
863#else
864 qtype = T_A;
865#endif
866 n = res_search(name, C_IN, qtype, answer, sizeof(answer));
867 if (n < 0) {
868 *errp = h_errno;
869 return NULL;
870 }
871 hp = (HEADER *)answer;
872 eom = answer + n;
873 ancount = ntohs(hp->ancount);
874 qdcount = ntohs(hp->qdcount);
875 DNS_ASSERT(qdcount == 1);
876 cp = answer + sizeof(HEADER);
877 bp = hostbuf;
878 buflen = sizeof(hostbuf);
879
880 n = dn_expand(answer, eom, cp, bp, buflen);
881 DNS_ASSERT(n >= 0);
882 cp += n + QFIXEDSZ;
883 hbuf.h_name = bp;
884 n = strlen(bp) + 1;
885 bp += n;
886 buflen -= n;
887 while (ancount-- > 0 && cp < eom) {
888 n = dn_expand(answer, eom, cp, bp, buflen);
889 DNS_ASSERT(n >= 0);
890 cp += n; /* name */
891 type = _getshort(cp);
892 cp += 2; /* type */
893 class = _getshort(cp);
894 cp += 2; /* class */
895 ttl = _getlong(cp);
896 cp += 4; /* ttl */
897 n = _getshort(cp);
898 cp += 2; /* len */
899 DNS_ASSERT(class == C_IN);
900 switch (type) {
901 case T_CNAME:
902 if (na >= MAXALIASES-1) {
903 cp += n;
904 break;
905 }
906 n = dn_expand(answer, eom, cp, tbuf, sizeof(tbuf));
907 DNS_ASSERT(n >= 0);
908 cp += n;
909 /* alias */
910 alist[na++] = bp;
911 n = strlen(bp) + 1;
912 bp += n;
913 buflen -= n;
914 /* canon */
915 n = strlen(tbuf) + 1;
916 DNS_ASSERT(n < buflen);
917 strcpy(bp, tbuf);
918 hbuf.h_name = bp;
919 bp += n;
920 buflen -= n;
921 break;
922 case T_A:
923#ifdef INET6
924 case T_AAAA:
925#endif
926 DNS_ASSERT(type == qtype);
927 bp = (char *)ALIGN(bp);
928 DNS_ASSERT(n == hbuf.h_length);
929 DNS_ASSERT(n < buflen);
930 if (nh < MAXADDRS-1) {
931 hlist[nh++] = bp;
932 memcpy(bp, cp, n);
933 bp += n;
934 buflen -= n;
935 }
936 cp += n;
937 break;
938 default:
939 DNS_ASSERT(0);
940 cp += n;
941 break;
942 }
943 }
944 if (nh == 0) {
945 badanswer:
946 *errp = NO_RECOVERY;
947 return NULL;
948 }
949 alist[na] = NULL;
950 hlist[nh] = NULL;
951 return _hpcopy(&hbuf, errp);
952}
953
954static struct hostent *
955_dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
956{
957 int n;
958 u_char answer[BUFSIZ];
959 HEADER *hp;
960 u_char c, *cp, *eom;
961 int type, class, ancount, qdcount;
962 u_long ttl;
963 char hostbuf[BUFSIZ];
964 char *bp;
965 char *alist[MAXALIASES];
966 char *hlist[2];
967 struct hostent hbuf;
968 int buflen;
969 int na;
970#ifdef INET6
971 static const char hex[] = "0123456789abcdef";
972#endif
973
974#ifdef INET6
975 /* XXX */
976 if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr))
977 return NULL;
978#endif
979
980 if ((_res.options & RES_INIT) == 0) {
981 if (res_init() < 0) {
982 *errp = h_errno;
983 return NULL;
984 }
985 }
986 hbuf.h_name = NULL;
987 hbuf.h_aliases = alist;
988 hbuf.h_addrtype = af;
989 hbuf.h_length = addrlen;
990 hbuf.h_addr_list = hlist;
991 hlist[0] = (char *)addr;
992 hlist[1] = NULL;
993 na = 0;
994
995 n = 0;
996 bp = hostbuf;
997 cp = (u_char *)addr+addrlen-1;
998 switch (af) {
999#ifdef INET6
1000 case AF_INET6:
1001 for (; n < addrlen; n++, cp--) {
1002 c = *cp;
1003 *bp++ = hex[c & 0xf];
1004 *bp++ = '.';
1005 *bp++ = hex[c >> 4];
1006 *bp++ = '.';
1007 }
1008 strcpy(bp, "ip6.int");
1009 break;
1010#endif
1011 default:
1012 for (; n < addrlen; n++, cp--) {
1013 c = *cp;
1014 if (c >= 100)
1015 *bp++ = '0' + c / 100;
1016 if (c >= 10)
1017 *bp++ = '0' + (c % 100) / 10;
1018 *bp++ = '0' + c % 10;
1019 *bp++ = '.';
1020 }
1021 strcpy(bp, "in-addr.arpa");
1022 break;
1023 }
1024
1025 n = res_query(hostbuf, C_IN, T_PTR, answer, sizeof(answer));
1026 if (n < 0) {
1027 *errp = h_errno;
1028 return NULL;
1029 }
1030 hp = (HEADER *)answer;
1031 eom = answer + n;
1032 ancount = ntohs(hp->ancount);
1033 qdcount = ntohs(hp->qdcount);
1034 DNS_ASSERT(qdcount == 1);
1035 cp = answer + sizeof(HEADER);
1036 bp = hostbuf;
1037 buflen = sizeof(hostbuf);
1038
1039 n = dn_expand(answer, eom, cp, bp, buflen);
1040 DNS_ASSERT(n >= 0);
1041 cp += n + QFIXEDSZ;
1042 while (ancount-- > 0 && cp < eom) {
1043 n = dn_expand(answer, eom, cp, bp, buflen);
1044 DNS_ASSERT(n >= 0);
1045 cp += n; /* name */
1046 type = _getshort(cp);
1047 cp += 2; /* type */
1048 class = _getshort(cp);
1049 cp += 2; /* class */
1050 ttl = _getlong(cp);
1051 cp += 4; /* ttl */
1052 n = _getshort(cp);
1053 cp += 2; /* len */
1054 DNS_ASSERT(class == C_IN);
1055 switch (type) {
1056 case T_PTR:
1057 n = dn_expand(answer, eom, cp, bp, buflen);
1058 DNS_ASSERT(n >= 0);
1059 cp += n;
1060 if (na >= MAXALIASES-1)
1061 break;
1062 if (hbuf.h_name == NULL)
1063 hbuf.h_name = bp;
1064 else
1065 alist[na++] = bp;
1066 n = strlen(bp) + 1;
1067 bp += n;
1068 buflen -= n;
1069 break;
1070 case T_CNAME:
1071 cp += n;
1072 break;
1073 default:
1074 badanswer:
1075 *errp = NO_RECOVERY;
1076 return NULL;
1077 }
1078 }
1079 if (hbuf.h_name == NULL) {
1080 *errp = h_errno;
1081 return NULL;
1082 }
1083 alist[na] = NULL;
1084 return _hpcopy(&hbuf, errp);
1085}
1086
1087#ifdef ICMPNL
1088
1089/*
1090 * experimental:
1091 * draft-ietf-ipngwg-icmp-namelookups-02.txt
1092 * ifindex is assumed to be encoded in addr.
1093 */
1094#include <sys/uio.h>
1095#include <netinet/ip6.h>
1096#include <netinet/icmp6.h>
1097
1098struct _icmp_host_cache {
1099 struct _icmp_host_cache *hc_next;
1100 int hc_ifindex;
1101 struct in6_addr hc_addr;
1102 char *hc_name;
1103};
1104
1105static char *
1106_icmp_fqdn_query(const struct in6_addr *addr, int ifindex)
1107{
1108 int s;
1109 struct icmp6_filter filter;
1110 struct msghdr msg;
1111 struct cmsghdr *cmsg;
1112 struct in6_pktinfo *pkt;
1113 char cbuf[256];
1114 char buf[1024];
1115 int cc;
1116 struct icmp6_fqdn_query *fq;
1117 struct icmp6_fqdn_reply *fr;
1118 struct _icmp_host_cache *hc;
1119 struct sockaddr_in6 sin6;
1120 struct iovec iov;
1121 fd_set s_fds, fds;
1122 struct timeval tout;
1123 int len;
1124 char *name;
1125 static int pid;
1126 static struct _icmp_host_cache *hc_head;
1127
1128 for (hc = hc_head; hc; hc = hc->hc_next) {
1129 if (hc->hc_ifindex == ifindex
1130 && IN6_ARE_ADDR_EQUAL(&hc->hc_addr, addr))
1131 return hc->hc_name;
1132 }
1133
1134 if (pid == 0)
1135 pid = getpid();
1136
1137 ICMP6_FILTER_SETBLOCKALL(&filter);
1138 ICMP6_FILTER_SETPASS(ICMP6_FQDN_REPLY, &filter);
1139
1140 FD_ZERO(&s_fds);
1141 tout.tv_sec = 0;
1142 tout.tv_usec = 200000; /*XXX: 200ms*/
1143
1144 fq = (struct icmp6_fqdn_query *)buf;
1145 fq->icmp6_fqdn_type = ICMP6_FQDN_QUERY;
1146 fq->icmp6_fqdn_code = 0;
1147 fq->icmp6_fqdn_cksum = 0;
1148 fq->icmp6_fqdn_id = (u_short)pid;
1149 fq->icmp6_fqdn_unused = 0;
1150 fq->icmp6_fqdn_cookie[0] = 0;
1151 fq->icmp6_fqdn_cookie[1] = 0;
1152
1153 memset(&sin6, 0, sizeof(sin6));
1154 sin6.sin6_family = AF_INET6;
1155 sin6.sin6_addr = *addr;
1156
1157 memset(&msg, 0, sizeof(msg));
1158 msg.msg_name = (caddr_t)&sin6;
1159 msg.msg_namelen = sizeof(sin6);
1160 msg.msg_iov = &iov;
1161 msg.msg_iovlen = 1;
1162 msg.msg_control = NULL;
1163 msg.msg_controllen = 0;
1164 iov.iov_base = (caddr_t)buf;
1165 iov.iov_len = sizeof(struct icmp6_fqdn_query);
1166
1167 if (ifindex) {
1168 msg.msg_control = cbuf;
1169 msg.msg_controllen = sizeof(cbuf);
1170 cmsg = CMSG_FIRSTHDR(&msg);
1171 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
1172 cmsg->cmsg_level = IPPROTO_IPV6;
1173 cmsg->cmsg_type = IPV6_PKTINFO;
1174 pkt = (struct in6_pktinfo *)&cmsg[1];
1175 memset(&pkt->ipi6_addr, 0, sizeof(struct in6_addr));
1176 pkt->ipi6_ifindex = ifindex;
1177 cmsg = CMSG_NXTHDR(&msg, cmsg);
1178 msg.msg_controllen = (char *)cmsg - cbuf;
1179 }
1180
1181 if ((s = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0)
1182 return NULL;
1183 (void)setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER,
1184 (char *)&filter, sizeof(filter));
1185 cc = sendmsg(s, &msg, 0);
1186 if (cc < 0) {
261 }
262
263 for (i = 0; i < MAXHOSTCONF; i++) {
264 if (_hostconf[i].byname
265 && (hp = (*_hostconf[i].byname)(name, af, errp))
266 != NULL)
267 return hp;
268 }
269
270 return NULL;
271}
272
273struct hostent *
274getipnodebyname(const char *name, int af, int flags, int *errp)
275{
276 struct hostent *hp;
277 union inx_addr addrbuf;
278
279 if (af != AF_INET
280#ifdef INET6
281 && af != AF_INET6
282#endif
283 )
284 {
285 *errp = NO_RECOVERY;
286 return NULL;
287 }
288
289#ifdef INET6
290 /* special case for literal address */
291 if (inet_pton(AF_INET6, name, &addrbuf) == 1) {
292 if (af != AF_INET6) {
293 *errp = HOST_NOT_FOUND;
294 return NULL;
295 }
296 return _hpaddr(af, name, &addrbuf, errp);
297 }
298#endif
299 if (inet_pton(AF_INET, name, &addrbuf) == 1) {
300 if (af != AF_INET) {
301 if (MAPADDRENABLED(flags)) {
302 MAPADDR(&addrbuf, &addrbuf.in_addr);
303 } else {
304 *errp = HOST_NOT_FOUND;
305 return NULL;
306 }
307 }
308 return _hpaddr(af, name, &addrbuf, errp);
309 }
310
311 if (!_hostconf_init_done)
312 _hostconf_init();
313
314 *errp = HOST_NOT_FOUND;
315 hp = _ghbyname(name, af, flags, errp);
316
317#ifdef INET6
318 if (af == AF_INET6
319 && ((flags & AI_ALL) || hp == NULL)
320 && (MAPADDRENABLED(flags))) {
321 struct hostent *hp2 = _ghbyname(name, AF_INET, flags, errp);
322 if (hp == NULL)
323 hp = _hpmapv6(hp2, errp);
324 else {
325 if (hp2 && strcmp(hp->h_name, hp2->h_name) != 0) {
326 freehostent(hp2);
327 hp2 = NULL;
328 }
329 hp = _hpmerge(hp, hp2, errp);
330 }
331 }
332#endif
333 return _hpsort(hp);
334}
335
336struct hostent *
337getipnodebyaddr(const void *src, size_t len, int af, int *errp)
338{
339 struct hostent *hp;
340 int i;
341#ifdef INET6
342 struct in6_addr addrbuf;
343#else
344 struct in_addr addrbuf;
345#endif
346
347 *errp = HOST_NOT_FOUND;
348
349 switch (af) {
350 case AF_INET:
351 if (len != sizeof(struct in_addr)) {
352 *errp = NO_RECOVERY;
353 return NULL;
354 }
355 if ((long)src & ~(sizeof(struct in_addr) - 1)) {
356 memcpy(&addrbuf, src, len);
357 src = &addrbuf;
358 }
359 if (((struct in_addr *)src)->s_addr == 0)
360 return NULL;
361 break;
362#ifdef INET6
363 case AF_INET6:
364 if (len != sizeof(struct in6_addr)) {
365 *errp = NO_RECOVERY;
366 return NULL;
367 }
368 if ((long)src & ~(sizeof(struct in6_addr) / 2 - 1)) { /*XXX*/
369 memcpy(&addrbuf, src, len);
370 src = &addrbuf;
371 }
372 if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)src))
373 return NULL;
374 if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)src)
375 || IN6_IS_ADDR_V4COMPAT((struct in6_addr *)src)) {
376 src = (char *)src +
377 (sizeof(struct in6_addr) - sizeof(struct in_addr));
378 af = AF_INET;
379 len = sizeof(struct in_addr);
380 }
381 break;
382#endif
383 default:
384 *errp = NO_RECOVERY;
385 return NULL;
386 }
387
388 if (!_hostconf_init_done)
389 _hostconf_init();
390 for (i = 0; i < MAXHOSTCONF; i++) {
391 if (_hostconf[i].byaddr
392 && (hp = (*_hostconf[i].byaddr)(src, len, af, errp)) != NULL)
393 return hp;
394 }
395
396 return NULL;
397}
398
399void
400freehostent(struct hostent *ptr)
401{
402 free(ptr);
403}
404
405#if 0
406
407/* XXX: should be deprecated */
408struct hostent *
409getnodebyname(const char *name, int af, int flags)
410{
411 return getipnodebyname(name, af, flags, &h_errno);
412}
413
414#ifdef __warn_references
415__warn_references(getnodebyname,
416 "warning: getnodebyname() deprecated, "
417 "should use getaddrinfo() or getipnodebyname()");
418#endif
419
420struct hostent *
421getnodebyaddr(const void *src, size_t len, int af)
422{
423 return getipnodebyaddr(src, len, af, &h_errno);
424}
425
426#ifdef __warn_references
427__warn_references(getnodebyaddr,
428 "warning: getnodebyaddr() deprecated, "
429 "should use getnameinfo() or getipnodebyaddr()");
430#endif
431
432#endif
433
434/*
435 * Private utility functions
436 */
437
438/*
439 * _hpcopy: allocate and copy hostent structure
440 */
441static struct hostent *
442_hpcopy(struct hostent *hp, int *errp)
443{
444 struct hostent *nhp;
445 char *cp, **pp;
446 int size, addrsize;
447 int nalias = 0, naddr = 0;
448 int al_off;
449 int i;
450
451 if (hp == NULL)
452 return hp;
453
454 /* count size to be allocated */
455 size = sizeof(struct hostent);
456 if (hp->h_name != NULL && *hp->h_name != '\0')
457 size += strlen(hp->h_name) + 1;
458 if ((pp = hp->h_aliases) != NULL) {
459 for (i = 0; *pp != NULL; i++, pp++) {
460 if (**pp != '\0') {
461 size += strlen(*pp) + 1;
462 nalias++;
463 }
464 }
465 }
466 /* adjust alignment */
467 size = ALIGN(size);
468 al_off = size;
469 size += sizeof(char *) * (nalias + 1);
470 addrsize = ALIGN(hp->h_length);
471 if ((pp = hp->h_addr_list) != NULL) {
472 while (*pp++ != NULL)
473 naddr++;
474 }
475 size += addrsize * naddr;
476 size += sizeof(char *) * (naddr + 1);
477
478 /* copy */
479 if ((nhp = (struct hostent *)malloc(size)) == NULL) {
480 *errp = TRY_AGAIN;
481 return NULL;
482 }
483 cp = (char *)&nhp[1];
484 if (hp->h_name != NULL && *hp->h_name != '\0') {
485 nhp->h_name = cp;
486 strcpy(cp, hp->h_name);
487 cp += strlen(cp) + 1;
488 } else
489 nhp->h_name = NULL;
490 nhp->h_aliases = (char **)((char *)nhp + al_off);
491 if ((pp = hp->h_aliases) != NULL) {
492 for (i = 0; *pp != NULL; pp++) {
493 if (**pp != '\0') {
494 nhp->h_aliases[i++] = cp;
495 strcpy(cp, *pp);
496 cp += strlen(cp) + 1;
497 }
498 }
499 }
500 nhp->h_aliases[nalias] = NULL;
501 cp = (char *)&nhp->h_aliases[nalias + 1];
502 nhp->h_addrtype = hp->h_addrtype;
503 nhp->h_length = hp->h_length;
504 nhp->h_addr_list = (char **)cp;
505 if ((pp = hp->h_addr_list) != NULL) {
506 cp = (char *)&nhp->h_addr_list[naddr + 1];
507 for (i = 0; *pp != NULL; pp++) {
508 nhp->h_addr_list[i++] = cp;
509 memcpy(cp, *pp, hp->h_length);
510 cp += addrsize;
511 }
512 }
513 nhp->h_addr_list[naddr] = NULL;
514 return nhp;
515}
516
517/*
518 * _hpaddr: construct hostent structure with one address
519 */
520static struct hostent *
521_hpaddr(int af, const char *name, void *addr, int *errp)
522{
523 struct hostent *hp, hpbuf;
524 char *addrs[2];
525
526 hp = &hpbuf;
527 hp->h_name = (char *)name;
528 hp->h_aliases = NULL;
529 hp->h_addrtype = af;
530 hp->h_length = ADDRLEN(af);
531 hp->h_addr_list = addrs;
532 addrs[0] = (char *)addr;
533 addrs[1] = NULL;
534 return _hpcopy(hp, errp);
535}
536
537/*
538 * _hpmerge: merge 2 hostent structure, arguments will be freed
539 */
540static struct hostent *
541_hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp)
542{
543 int i, j;
544 int naddr, nalias;
545 char **pp;
546 struct hostent *hp, hpbuf;
547 char *aliases[MAXALIASES + 1], *addrs[MAXADDRS + 1];
548 union inx_addr addrbuf[MAXADDRS];
549
550 if (hp1 == NULL)
551 return hp2;
552 if (hp2 == NULL)
553 return hp1;
554
555#define HP(i) (i == 1 ? hp1 : hp2)
556 hp = &hpbuf;
557 hp->h_name = (hp1->h_name != NULL ? hp1->h_name : hp2->h_name);
558 hp->h_aliases = aliases;
559 nalias = 0;
560 for (i = 1; i <= 2; i++) {
561 if ((pp = HP(i)->h_aliases) == NULL)
562 continue;
563 for (; nalias < MAXALIASES && *pp != NULL; pp++) {
564 /* check duplicates */
565 for (j = 0; j < nalias; j++)
566 if (strcasecmp(*pp, aliases[j]) == 0)
567 break;
568 if (j == nalias)
569 aliases[nalias++] = *pp;
570 }
571 }
572 aliases[nalias] = NULL;
573#ifdef INET6
574 if (hp1->h_length != hp2->h_length) {
575 hp->h_addrtype = AF_INET6;
576 hp->h_length = sizeof(struct in6_addr);
577 } else {
578#endif
579 hp->h_addrtype = hp1->h_addrtype;
580 hp->h_length = hp1->h_length;
581#ifdef INET6
582 }
583#endif
584 hp->h_addr_list = addrs;
585 naddr = 0;
586 for (i = 1; i <= 2; i++) {
587 if ((pp = HP(i)->h_addr_list) == NULL)
588 continue;
589 if (HP(i)->h_length == hp->h_length) {
590 while (naddr < MAXADDRS && *pp != NULL)
591 addrs[naddr++] = *pp++;
592 } else {
593 /* copy IPv4 addr as mapped IPv6 addr */
594 while (naddr < MAXADDRS && *pp != NULL) {
595 MAPADDR(&addrbuf[naddr], *pp++);
596 addrs[naddr] = (char *)&addrbuf[naddr];
597 naddr++;
598 }
599 }
600 }
601 addrs[naddr] = NULL;
602 hp = _hpcopy(hp, errp);
603 freehostent(hp1);
604 freehostent(hp2);
605 return hp;
606}
607
608/*
609 * _hpmapv6: convert IPv4 hostent into IPv4-mapped IPv6 addresses
610 */
611#ifdef INET6
612static struct hostent *
613_hpmapv6(struct hostent *hp, int *errp)
614{
615 struct hostent *hp6;
616
617 if (hp == NULL)
618 return NULL;
619 if (hp->h_addrtype == AF_INET6)
620 return hp;
621
622 /* make dummy hostent to convert IPv6 address */
623 if ((hp6 = (struct hostent *)malloc(sizeof(struct hostent))) == NULL) {
624 *errp = TRY_AGAIN;
625 return NULL;
626 }
627 hp6->h_name = NULL;
628 hp6->h_aliases = NULL;
629 hp6->h_addrtype = AF_INET6;
630 hp6->h_length = sizeof(struct in6_addr);
631 hp6->h_addr_list = NULL;
632 return _hpmerge(hp6, hp, errp);
633}
634#endif
635
636/*
637 * _hpsort: sort address by sortlist
638 */
639static struct hostent *
640_hpsort(struct hostent *hp)
641{
642 int i, j, n;
643 u_char *ap, *sp, *mp, **pp;
644 char t;
645 char order[MAXADDRS];
646 int nsort = _res.nsort;
647
648 if (hp == NULL || hp->h_addr_list[1] == NULL || nsort == 0)
649 return hp;
650 for (i = 0; (ap = (u_char *)hp->h_addr_list[i]); i++) {
651 for (j = 0; j < nsort; j++) {
652#ifdef INET6
653 if (_res_ext.sort_list[j].af != hp->h_addrtype)
654 continue;
655 sp = (u_char *)&_res_ext.sort_list[j].addr;
656 mp = (u_char *)&_res_ext.sort_list[j].mask;
657#else
658 sp = (u_char *)&_res.sort_list[j].addr;
659 mp = (u_char *)&_res.sort_list[j].mask;
660#endif
661 for (n = 0; n < hp->h_length; n++) {
662 if ((ap[n] & mp[n]) != sp[n])
663 break;
664 }
665 if (n == hp->h_length)
666 break;
667 }
668 order[i] = j;
669 }
670 n = i;
671 pp = (u_char **)hp->h_addr_list;
672 for (i = 0; i < n - 1; i++) {
673 for (j = i + 1; j < n; j++) {
674 if (order[i] > order[j]) {
675 ap = pp[i];
676 pp[i] = pp[j];
677 pp[j] = ap;
678 t = order[i];
679 order[i] = order[j];
680 order[j] = t;
681 }
682 }
683 }
684 return hp;
685}
686
687static char *
688_hgetword(char **pp)
689{
690 char c, *p, *ret;
691 const char *sp;
692 static const char sep[] = "# \t\n";
693
694 ret = NULL;
695 for (p = *pp; (c = *p) != '\0'; p++) {
696 for (sp = sep; *sp != '\0'; sp++) {
697 if (c == *sp)
698 break;
699 }
700 if (c == '#')
701 p[1] = '\0'; /* ignore rest of line */
702 if (ret == NULL) {
703 if (*sp == '\0')
704 ret = p;
705 } else {
706 if (*sp != '\0') {
707 *p++ = '\0';
708 break;
709 }
710 }
711 }
712 *pp = p;
713 if (ret == NULL || *ret == '\0')
714 return NULL;
715 return ret;
716}
717
718/*
719 * FILES (/etc/hosts)
720 */
721
722static FILE *
723_files_open(int *errp)
724{
725 FILE *fp;
726 fp = fopen(_PATH_HOSTS, "r");
727 if (fp == NULL)
728 *errp = NO_RECOVERY;
729 return fp;
730}
731
732static struct hostent *
733_files_ghbyname(const char *name, int af, int *errp)
734{
735 int match, nalias;
736 char *p, *line, *addrstr, *cname;
737 FILE *fp;
738 struct hostent *rethp, *hp, hpbuf;
739 char *aliases[MAXALIASES + 1], *addrs[2];
740 union inx_addr addrbuf;
741 char buf[BUFSIZ];
742
743 if ((fp = _files_open(errp)) == NULL)
744 return NULL;
745 rethp = hp = NULL;
746
747 while (fgets(buf, sizeof(buf), fp)) {
748 line = buf;
749 if ((addrstr = _hgetword(&line)) == NULL
750 || (cname = _hgetword(&line)) == NULL)
751 continue;
752 match = (strcasecmp(cname, name) == 0);
753 nalias = 0;
754 while ((p = _hgetword(&line)) != NULL) {
755 if (!match)
756 match = (strcasecmp(p, name) == 0);
757 if (nalias < MAXALIASES)
758 aliases[nalias++] = p;
759 }
760 if (!match)
761 continue;
762 if (inet_pton(af, addrstr, &addrbuf) != 1) {
763 *errp = NO_DATA; /* name found */
764 continue;
765 }
766 hp = &hpbuf;
767 hp->h_name = cname;
768 hp->h_aliases = aliases;
769 aliases[nalias] = NULL;
770 hp->h_addrtype = af;
771 hp->h_length = ADDRLEN(af);
772 hp->h_addr_list = addrs;
773 addrs[0] = (char *)&addrbuf;
774 addrs[1] = NULL;
775 hp = _hpcopy(hp, errp);
776 rethp = _hpmerge(rethp, hp, errp);
777 }
778 fclose(fp);
779 return rethp;
780}
781
782static struct hostent *
783_files_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
784{
785 int nalias;
786 char *p, *line;
787 FILE *fp;
788 struct hostent *hp, hpbuf;
789 char *aliases[MAXALIASES + 1], *addrs[2];
790 union inx_addr addrbuf;
791 char buf[BUFSIZ];
792
793 if ((fp = _files_open(errp)) == NULL)
794 return NULL;
795 hp = NULL;
796 while (fgets(buf, sizeof(buf), fp)) {
797 line = buf;
798 if ((p = _hgetword(&line)) == NULL
799 || inet_pton(af, p, &addrbuf) != 1
800 || memcmp(addr, &addrbuf, addrlen) != 0
801 || (p = _hgetword(&line)) == NULL)
802 continue;
803 hp = &hpbuf;
804 hp->h_name = p;
805 hp->h_aliases = aliases;
806 nalias = 0;
807 while ((p = _hgetword(&line)) != NULL) {
808 if (nalias < MAXALIASES)
809 aliases[nalias++] = p;
810 }
811 aliases[nalias] = NULL;
812 hp->h_addrtype = af;
813 hp->h_length = addrlen;
814 hp->h_addr_list = addrs;
815 addrs[0] = (char *)&addrbuf;
816 addrs[1] = NULL;
817 hp = _hpcopy(hp, errp);
818 break;
819 }
820 fclose(fp);
821 return hp;
822}
823
824#ifdef DEBUG
825#define DNS_ASSERT(X) if (!(X)) { fprintf(stderr, "ASSFAIL: %s %d: %s\n", __FILE__, __LINE__, #X); goto badanswer; }
826#else
827#define DNS_ASSERT(X) if (!(X)) { goto badanswer; }
828#endif
829
830static struct hostent *
831_dns_ghbyname(const char *name, int af, int *errp)
832{
833 int n;
834 u_char answer[BUFSIZ];
835 char tbuf[MAXDNAME+1];
836 HEADER *hp;
837 u_char *cp, *eom;
838 int qtype;
839 int type, class, ancount, qdcount;
840 u_long ttl;
841 char hostbuf[BUFSIZ];
842 char *bp;
843 char *alist[MAXALIASES];
844 char *hlist[MAXADDRS];
845 struct hostent hbuf;
846 int buflen;
847 int na, nh;
848
849 if ((_res.options & RES_INIT) == 0) {
850 if (res_init() < 0) {
851 *errp = h_errno;
852 return NULL;
853 }
854 }
855 hbuf.h_aliases = alist;
856 hbuf.h_addrtype = af;
857 hbuf.h_length = ADDRLEN(af);
858 hbuf.h_addr_list = hlist;
859 na = nh = 0;
860
861#ifdef INET6
862 qtype = (af == AF_INET6 ? T_AAAA : T_A);
863#else
864 qtype = T_A;
865#endif
866 n = res_search(name, C_IN, qtype, answer, sizeof(answer));
867 if (n < 0) {
868 *errp = h_errno;
869 return NULL;
870 }
871 hp = (HEADER *)answer;
872 eom = answer + n;
873 ancount = ntohs(hp->ancount);
874 qdcount = ntohs(hp->qdcount);
875 DNS_ASSERT(qdcount == 1);
876 cp = answer + sizeof(HEADER);
877 bp = hostbuf;
878 buflen = sizeof(hostbuf);
879
880 n = dn_expand(answer, eom, cp, bp, buflen);
881 DNS_ASSERT(n >= 0);
882 cp += n + QFIXEDSZ;
883 hbuf.h_name = bp;
884 n = strlen(bp) + 1;
885 bp += n;
886 buflen -= n;
887 while (ancount-- > 0 && cp < eom) {
888 n = dn_expand(answer, eom, cp, bp, buflen);
889 DNS_ASSERT(n >= 0);
890 cp += n; /* name */
891 type = _getshort(cp);
892 cp += 2; /* type */
893 class = _getshort(cp);
894 cp += 2; /* class */
895 ttl = _getlong(cp);
896 cp += 4; /* ttl */
897 n = _getshort(cp);
898 cp += 2; /* len */
899 DNS_ASSERT(class == C_IN);
900 switch (type) {
901 case T_CNAME:
902 if (na >= MAXALIASES-1) {
903 cp += n;
904 break;
905 }
906 n = dn_expand(answer, eom, cp, tbuf, sizeof(tbuf));
907 DNS_ASSERT(n >= 0);
908 cp += n;
909 /* alias */
910 alist[na++] = bp;
911 n = strlen(bp) + 1;
912 bp += n;
913 buflen -= n;
914 /* canon */
915 n = strlen(tbuf) + 1;
916 DNS_ASSERT(n < buflen);
917 strcpy(bp, tbuf);
918 hbuf.h_name = bp;
919 bp += n;
920 buflen -= n;
921 break;
922 case T_A:
923#ifdef INET6
924 case T_AAAA:
925#endif
926 DNS_ASSERT(type == qtype);
927 bp = (char *)ALIGN(bp);
928 DNS_ASSERT(n == hbuf.h_length);
929 DNS_ASSERT(n < buflen);
930 if (nh < MAXADDRS-1) {
931 hlist[nh++] = bp;
932 memcpy(bp, cp, n);
933 bp += n;
934 buflen -= n;
935 }
936 cp += n;
937 break;
938 default:
939 DNS_ASSERT(0);
940 cp += n;
941 break;
942 }
943 }
944 if (nh == 0) {
945 badanswer:
946 *errp = NO_RECOVERY;
947 return NULL;
948 }
949 alist[na] = NULL;
950 hlist[nh] = NULL;
951 return _hpcopy(&hbuf, errp);
952}
953
954static struct hostent *
955_dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
956{
957 int n;
958 u_char answer[BUFSIZ];
959 HEADER *hp;
960 u_char c, *cp, *eom;
961 int type, class, ancount, qdcount;
962 u_long ttl;
963 char hostbuf[BUFSIZ];
964 char *bp;
965 char *alist[MAXALIASES];
966 char *hlist[2];
967 struct hostent hbuf;
968 int buflen;
969 int na;
970#ifdef INET6
971 static const char hex[] = "0123456789abcdef";
972#endif
973
974#ifdef INET6
975 /* XXX */
976 if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr))
977 return NULL;
978#endif
979
980 if ((_res.options & RES_INIT) == 0) {
981 if (res_init() < 0) {
982 *errp = h_errno;
983 return NULL;
984 }
985 }
986 hbuf.h_name = NULL;
987 hbuf.h_aliases = alist;
988 hbuf.h_addrtype = af;
989 hbuf.h_length = addrlen;
990 hbuf.h_addr_list = hlist;
991 hlist[0] = (char *)addr;
992 hlist[1] = NULL;
993 na = 0;
994
995 n = 0;
996 bp = hostbuf;
997 cp = (u_char *)addr+addrlen-1;
998 switch (af) {
999#ifdef INET6
1000 case AF_INET6:
1001 for (; n < addrlen; n++, cp--) {
1002 c = *cp;
1003 *bp++ = hex[c & 0xf];
1004 *bp++ = '.';
1005 *bp++ = hex[c >> 4];
1006 *bp++ = '.';
1007 }
1008 strcpy(bp, "ip6.int");
1009 break;
1010#endif
1011 default:
1012 for (; n < addrlen; n++, cp--) {
1013 c = *cp;
1014 if (c >= 100)
1015 *bp++ = '0' + c / 100;
1016 if (c >= 10)
1017 *bp++ = '0' + (c % 100) / 10;
1018 *bp++ = '0' + c % 10;
1019 *bp++ = '.';
1020 }
1021 strcpy(bp, "in-addr.arpa");
1022 break;
1023 }
1024
1025 n = res_query(hostbuf, C_IN, T_PTR, answer, sizeof(answer));
1026 if (n < 0) {
1027 *errp = h_errno;
1028 return NULL;
1029 }
1030 hp = (HEADER *)answer;
1031 eom = answer + n;
1032 ancount = ntohs(hp->ancount);
1033 qdcount = ntohs(hp->qdcount);
1034 DNS_ASSERT(qdcount == 1);
1035 cp = answer + sizeof(HEADER);
1036 bp = hostbuf;
1037 buflen = sizeof(hostbuf);
1038
1039 n = dn_expand(answer, eom, cp, bp, buflen);
1040 DNS_ASSERT(n >= 0);
1041 cp += n + QFIXEDSZ;
1042 while (ancount-- > 0 && cp < eom) {
1043 n = dn_expand(answer, eom, cp, bp, buflen);
1044 DNS_ASSERT(n >= 0);
1045 cp += n; /* name */
1046 type = _getshort(cp);
1047 cp += 2; /* type */
1048 class = _getshort(cp);
1049 cp += 2; /* class */
1050 ttl = _getlong(cp);
1051 cp += 4; /* ttl */
1052 n = _getshort(cp);
1053 cp += 2; /* len */
1054 DNS_ASSERT(class == C_IN);
1055 switch (type) {
1056 case T_PTR:
1057 n = dn_expand(answer, eom, cp, bp, buflen);
1058 DNS_ASSERT(n >= 0);
1059 cp += n;
1060 if (na >= MAXALIASES-1)
1061 break;
1062 if (hbuf.h_name == NULL)
1063 hbuf.h_name = bp;
1064 else
1065 alist[na++] = bp;
1066 n = strlen(bp) + 1;
1067 bp += n;
1068 buflen -= n;
1069 break;
1070 case T_CNAME:
1071 cp += n;
1072 break;
1073 default:
1074 badanswer:
1075 *errp = NO_RECOVERY;
1076 return NULL;
1077 }
1078 }
1079 if (hbuf.h_name == NULL) {
1080 *errp = h_errno;
1081 return NULL;
1082 }
1083 alist[na] = NULL;
1084 return _hpcopy(&hbuf, errp);
1085}
1086
1087#ifdef ICMPNL
1088
1089/*
1090 * experimental:
1091 * draft-ietf-ipngwg-icmp-namelookups-02.txt
1092 * ifindex is assumed to be encoded in addr.
1093 */
1094#include <sys/uio.h>
1095#include <netinet/ip6.h>
1096#include <netinet/icmp6.h>
1097
1098struct _icmp_host_cache {
1099 struct _icmp_host_cache *hc_next;
1100 int hc_ifindex;
1101 struct in6_addr hc_addr;
1102 char *hc_name;
1103};
1104
1105static char *
1106_icmp_fqdn_query(const struct in6_addr *addr, int ifindex)
1107{
1108 int s;
1109 struct icmp6_filter filter;
1110 struct msghdr msg;
1111 struct cmsghdr *cmsg;
1112 struct in6_pktinfo *pkt;
1113 char cbuf[256];
1114 char buf[1024];
1115 int cc;
1116 struct icmp6_fqdn_query *fq;
1117 struct icmp6_fqdn_reply *fr;
1118 struct _icmp_host_cache *hc;
1119 struct sockaddr_in6 sin6;
1120 struct iovec iov;
1121 fd_set s_fds, fds;
1122 struct timeval tout;
1123 int len;
1124 char *name;
1125 static int pid;
1126 static struct _icmp_host_cache *hc_head;
1127
1128 for (hc = hc_head; hc; hc = hc->hc_next) {
1129 if (hc->hc_ifindex == ifindex
1130 && IN6_ARE_ADDR_EQUAL(&hc->hc_addr, addr))
1131 return hc->hc_name;
1132 }
1133
1134 if (pid == 0)
1135 pid = getpid();
1136
1137 ICMP6_FILTER_SETBLOCKALL(&filter);
1138 ICMP6_FILTER_SETPASS(ICMP6_FQDN_REPLY, &filter);
1139
1140 FD_ZERO(&s_fds);
1141 tout.tv_sec = 0;
1142 tout.tv_usec = 200000; /*XXX: 200ms*/
1143
1144 fq = (struct icmp6_fqdn_query *)buf;
1145 fq->icmp6_fqdn_type = ICMP6_FQDN_QUERY;
1146 fq->icmp6_fqdn_code = 0;
1147 fq->icmp6_fqdn_cksum = 0;
1148 fq->icmp6_fqdn_id = (u_short)pid;
1149 fq->icmp6_fqdn_unused = 0;
1150 fq->icmp6_fqdn_cookie[0] = 0;
1151 fq->icmp6_fqdn_cookie[1] = 0;
1152
1153 memset(&sin6, 0, sizeof(sin6));
1154 sin6.sin6_family = AF_INET6;
1155 sin6.sin6_addr = *addr;
1156
1157 memset(&msg, 0, sizeof(msg));
1158 msg.msg_name = (caddr_t)&sin6;
1159 msg.msg_namelen = sizeof(sin6);
1160 msg.msg_iov = &iov;
1161 msg.msg_iovlen = 1;
1162 msg.msg_control = NULL;
1163 msg.msg_controllen = 0;
1164 iov.iov_base = (caddr_t)buf;
1165 iov.iov_len = sizeof(struct icmp6_fqdn_query);
1166
1167 if (ifindex) {
1168 msg.msg_control = cbuf;
1169 msg.msg_controllen = sizeof(cbuf);
1170 cmsg = CMSG_FIRSTHDR(&msg);
1171 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
1172 cmsg->cmsg_level = IPPROTO_IPV6;
1173 cmsg->cmsg_type = IPV6_PKTINFO;
1174 pkt = (struct in6_pktinfo *)&cmsg[1];
1175 memset(&pkt->ipi6_addr, 0, sizeof(struct in6_addr));
1176 pkt->ipi6_ifindex = ifindex;
1177 cmsg = CMSG_NXTHDR(&msg, cmsg);
1178 msg.msg_controllen = (char *)cmsg - cbuf;
1179 }
1180
1181 if ((s = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0)
1182 return NULL;
1183 (void)setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER,
1184 (char *)&filter, sizeof(filter));
1185 cc = sendmsg(s, &msg, 0);
1186 if (cc < 0) {
1187 _libc_close(s);
1187 _close(s);
1188 return NULL;
1189 }
1190 FD_SET(s, &s_fds);
1191 for (;;) {
1192 fds = s_fds;
1193 if (select(s + 1, &fds, NULL, NULL, &tout) <= 0) {
1188 return NULL;
1189 }
1190 FD_SET(s, &s_fds);
1191 for (;;) {
1192 fds = s_fds;
1193 if (select(s + 1, &fds, NULL, NULL, &tout) <= 0) {
1194 _libc_close(s);
1194 _close(s);
1195 return NULL;
1196 }
1197 len = sizeof(sin6);
1198 cc = recvfrom(s, buf, sizeof(buf), 0,
1199 (struct sockaddr *)&sin6, &len);
1200 if (cc <= 0) {
1195 return NULL;
1196 }
1197 len = sizeof(sin6);
1198 cc = recvfrom(s, buf, sizeof(buf), 0,
1199 (struct sockaddr *)&sin6, &len);
1200 if (cc <= 0) {
1201 _libc_close(s);
1201 _close(s);
1202 return NULL;
1203 }
1204 if (cc < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr))
1205 continue;
1206 if (!IN6_ARE_ADDR_EQUAL(addr, &sin6.sin6_addr))
1207 continue;
1208 fr = (struct icmp6_fqdn_reply *)(buf + sizeof(struct ip6_hdr));
1209 if (fr->icmp6_fqdn_type == ICMP6_FQDN_REPLY)
1210 break;
1211 }
1202 return NULL;
1203 }
1204 if (cc < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr))
1205 continue;
1206 if (!IN6_ARE_ADDR_EQUAL(addr, &sin6.sin6_addr))
1207 continue;
1208 fr = (struct icmp6_fqdn_reply *)(buf + sizeof(struct ip6_hdr));
1209 if (fr->icmp6_fqdn_type == ICMP6_FQDN_REPLY)
1210 break;
1211 }
1212 _libc_close(s);
1212 _close(s);
1213 if (fr->icmp6_fqdn_cookie[1] != 0) {
1214 /* rfc1788 type */
1215 name = buf + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + 4;
1216 len = (buf + cc) - name;
1217 } else {
1218 len = fr->icmp6_fqdn_namelen;
1219 name = fr->icmp6_fqdn_name;
1220 }
1221 if (len <= 0)
1222 return NULL;
1223 name[len] = 0;
1224
1225 if ((hc = (struct _icmp_host_cache *)malloc(sizeof(*hc))) == NULL)
1226 return NULL;
1227 /* XXX: limit number of cached entries */
1228 hc->hc_ifindex = ifindex;
1229 hc->hc_addr = *addr;
1230 hc->hc_name = strdup(name);
1231 hc->hc_next = hc_head;
1232 hc_head = hc;
1233 return hc->hc_name;
1234}
1235
1236static struct hostent *
1237_icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
1238{
1239 char *hname;
1240 int ifindex;
1241 struct in6_addr addr6;
1242
1243 if (af != AF_INET6) {
1244 /*
1245 * Note: rfc1788 defines Who Are You for IPv4,
1246 * but no one implements it.
1247 */
1248 return NULL;
1249 }
1250
1251 memcpy(&addr6, addr, addrlen);
1252 ifindex = (addr6.s6_addr[2] << 8) | addr6.s6_addr[3];
1253 addr6.s6_addr[2] = addr6.s6_addr[3] = 0;
1254
1255 if (!IN6_IS_ADDR_LINKLOCAL(&addr6))
1256 return NULL; /*XXX*/
1257
1258 if ((hname = _icmp_fqdn_query(&addr6, ifindex)) == NULL)
1259 return NULL;
1260 return _hpaddr(af, hname, &addr6, errp);
1261}
1262#endif /* ICMPNL */
1213 if (fr->icmp6_fqdn_cookie[1] != 0) {
1214 /* rfc1788 type */
1215 name = buf + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + 4;
1216 len = (buf + cc) - name;
1217 } else {
1218 len = fr->icmp6_fqdn_namelen;
1219 name = fr->icmp6_fqdn_name;
1220 }
1221 if (len <= 0)
1222 return NULL;
1223 name[len] = 0;
1224
1225 if ((hc = (struct _icmp_host_cache *)malloc(sizeof(*hc))) == NULL)
1226 return NULL;
1227 /* XXX: limit number of cached entries */
1228 hc->hc_ifindex = ifindex;
1229 hc->hc_addr = *addr;
1230 hc->hc_name = strdup(name);
1231 hc->hc_next = hc_head;
1232 hc_head = hc;
1233 return hc->hc_name;
1234}
1235
1236static struct hostent *
1237_icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
1238{
1239 char *hname;
1240 int ifindex;
1241 struct in6_addr addr6;
1242
1243 if (af != AF_INET6) {
1244 /*
1245 * Note: rfc1788 defines Who Are You for IPv4,
1246 * but no one implements it.
1247 */
1248 return NULL;
1249 }
1250
1251 memcpy(&addr6, addr, addrlen);
1252 ifindex = (addr6.s6_addr[2] << 8) | addr6.s6_addr[3];
1253 addr6.s6_addr[2] = addr6.s6_addr[3] = 0;
1254
1255 if (!IN6_IS_ADDR_LINKLOCAL(&addr6))
1256 return NULL; /*XXX*/
1257
1258 if ((hname = _icmp_fqdn_query(&addr6, ifindex)) == NULL)
1259 return NULL;
1260 return _hpaddr(af, hname, &addr6, errp);
1261}
1262#endif /* ICMPNL */