17d56d374SYoshinobu Inoue /* 27d56d374SYoshinobu Inoue * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. 37d56d374SYoshinobu Inoue * All rights reserved. 47d56d374SYoshinobu Inoue * 57d56d374SYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 67d56d374SYoshinobu Inoue * modification, are permitted provided that the following conditions 77d56d374SYoshinobu Inoue * are met: 87d56d374SYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 97d56d374SYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 107d56d374SYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 117d56d374SYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 127d56d374SYoshinobu Inoue * documentation and/or other materials provided with the distribution. 137d56d374SYoshinobu Inoue * 3. Neither the name of the project nor the names of its contributors 147d56d374SYoshinobu Inoue * may be used to endorse or promote products derived from this software 157d56d374SYoshinobu Inoue * without specific prior written permission. 167d56d374SYoshinobu Inoue * 177d56d374SYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 187d56d374SYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 197d56d374SYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 207d56d374SYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 217d56d374SYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 227d56d374SYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 237d56d374SYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 247d56d374SYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 257d56d374SYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 267d56d374SYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 277d56d374SYoshinobu Inoue * SUCH DAMAGE. 287d56d374SYoshinobu Inoue * 297d56d374SYoshinobu Inoue * $FreeBSD$ 307d56d374SYoshinobu Inoue */ 317d56d374SYoshinobu Inoue /* $Id: name6.c,v 1.9 1999/10/29 03:04:26 itojun Exp $ */ 327d56d374SYoshinobu Inoue /* 337d56d374SYoshinobu Inoue * Atsushi Onoe <onoe@sm.sony.co.jp> 347d56d374SYoshinobu Inoue */ 357d56d374SYoshinobu Inoue 367d56d374SYoshinobu Inoue /* 377d56d374SYoshinobu Inoue * TODO for thread safe 387d56d374SYoshinobu Inoue * use mutex for _hostconf, _hostconf_init. 397d56d374SYoshinobu Inoue * rewrite resolvers to be thread safe 407d56d374SYoshinobu Inoue */ 417d56d374SYoshinobu Inoue 427d56d374SYoshinobu Inoue #include <sys/param.h> 437d56d374SYoshinobu Inoue #include <sys/socket.h> 447d56d374SYoshinobu Inoue #include <sys/time.h> 45e6f35403SYoshinobu Inoue #include <sys/queue.h> 467d56d374SYoshinobu Inoue #include <netinet/in.h> 477d56d374SYoshinobu Inoue 487d56d374SYoshinobu Inoue #include <arpa/inet.h> 497d56d374SYoshinobu Inoue #include <arpa/nameser.h> 507d56d374SYoshinobu Inoue 51e6f35403SYoshinobu Inoue #include <errno.h> 527d56d374SYoshinobu Inoue #include <netdb.h> 537d56d374SYoshinobu Inoue #include <resolv.h> 547d56d374SYoshinobu Inoue #include <stdio.h> 557d56d374SYoshinobu Inoue #include <stdlib.h> 567d56d374SYoshinobu Inoue #include <string.h> 577d56d374SYoshinobu Inoue #include <unistd.h> 587d56d374SYoshinobu Inoue 597d56d374SYoshinobu Inoue #ifndef _PATH_HOSTS 607d56d374SYoshinobu Inoue #define _PATH_HOSTS "/etc/hosts" 617d56d374SYoshinobu Inoue #endif 627d56d374SYoshinobu Inoue 637d56d374SYoshinobu Inoue #ifndef MAXALIASES 647d56d374SYoshinobu Inoue #define MAXALIASES 10 657d56d374SYoshinobu Inoue #endif 667d56d374SYoshinobu Inoue #ifndef MAXADDRS 677d56d374SYoshinobu Inoue #define MAXADDRS 20 687d56d374SYoshinobu Inoue #endif 697d56d374SYoshinobu Inoue #ifndef MAXDNAME 707d56d374SYoshinobu Inoue #define MAXDNAME 1025 717d56d374SYoshinobu Inoue #endif 727d56d374SYoshinobu Inoue 737d56d374SYoshinobu Inoue #ifdef INET6 747d56d374SYoshinobu Inoue #define ADDRLEN(af) ((af) == AF_INET6 ? sizeof(struct in6_addr) : \ 757d56d374SYoshinobu Inoue sizeof(struct in_addr)) 767d56d374SYoshinobu Inoue #else 777d56d374SYoshinobu Inoue #define ADDRLEN(af) sizeof(struct in_addr) 787d56d374SYoshinobu Inoue #endif 797d56d374SYoshinobu Inoue 807d56d374SYoshinobu Inoue #define MAPADDR(ab, ina) \ 817d56d374SYoshinobu Inoue do { \ 827d56d374SYoshinobu Inoue memcpy(&(ab)->map_inaddr, ina, sizeof(struct in_addr)); \ 837d56d374SYoshinobu Inoue memset((ab)->map_zero, 0, sizeof((ab)->map_zero)); \ 847d56d374SYoshinobu Inoue memset((ab)->map_one, 0xff, sizeof((ab)->map_one)); \ 857d56d374SYoshinobu Inoue } while (0) 867d56d374SYoshinobu Inoue #define MAPADDRENABLED(flags) \ 877d56d374SYoshinobu Inoue (((flags) & AI_V4MAPPED) || \ 887d56d374SYoshinobu Inoue (((flags) & AI_V4MAPPED_CFG) && _mapped_addr_enabled())) 897d56d374SYoshinobu Inoue 907d56d374SYoshinobu Inoue union inx_addr { 917d56d374SYoshinobu Inoue struct in_addr in_addr; 927d56d374SYoshinobu Inoue #ifdef INET6 937d56d374SYoshinobu Inoue struct in6_addr in6_addr; 947d56d374SYoshinobu Inoue #endif 957d56d374SYoshinobu Inoue struct { 967d56d374SYoshinobu Inoue u_char mau_zero[10]; 977d56d374SYoshinobu Inoue u_char mau_one[2]; 987d56d374SYoshinobu Inoue struct in_addr mau_inaddr; 997d56d374SYoshinobu Inoue } map_addr_un; 1007d56d374SYoshinobu Inoue #define map_zero map_addr_un.mau_zero 1017d56d374SYoshinobu Inoue #define map_one map_addr_un.mau_one 1027d56d374SYoshinobu Inoue #define map_inaddr map_addr_un.mau_inaddr 1037d56d374SYoshinobu Inoue }; 1047d56d374SYoshinobu Inoue 1057d56d374SYoshinobu Inoue static struct hostent *_hpcopy(struct hostent *hp, int *errp); 1067d56d374SYoshinobu Inoue static struct hostent *_hpaddr(int af, const char *name, void *addr, int *errp); 1077d56d374SYoshinobu Inoue static struct hostent *_hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp); 1087d56d374SYoshinobu Inoue #ifdef INET6 1097d56d374SYoshinobu Inoue static struct hostent *_hpmapv6(struct hostent *hp, int *errp); 1107d56d374SYoshinobu Inoue #endif 1117d56d374SYoshinobu Inoue static struct hostent *_hpsort(struct hostent *hp); 1127d56d374SYoshinobu Inoue static struct hostent *_ghbyname(const char *name, int af, int flags, int *errp); 1137d56d374SYoshinobu Inoue static char *_hgetword(char **pp); 1147d56d374SYoshinobu Inoue static int _mapped_addr_enabled(void); 1157d56d374SYoshinobu Inoue 1167d56d374SYoshinobu Inoue static FILE *_files_open(int *errp); 1177d56d374SYoshinobu Inoue static struct hostent *_files_ghbyname(const char *name, int af, int *errp); 1187d56d374SYoshinobu Inoue static struct hostent *_files_ghbyaddr(const void *addr, int addrlen, int af, int *errp); 1197d56d374SYoshinobu Inoue static void _files_shent(int stayopen); 1207d56d374SYoshinobu Inoue static void _files_ehent(void); 12163858012SJonathan Lemon static struct hostent *_nis_ghbyname(const char *name, int af, int *errp); 12263858012SJonathan Lemon static struct hostent *_nis_ghbyaddr(const void *addr, int addrlen, int af, int *errp); 1237d56d374SYoshinobu Inoue static struct hostent *_dns_ghbyname(const char *name, int af, int *errp); 1247d56d374SYoshinobu Inoue static struct hostent *_dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp); 1257d56d374SYoshinobu Inoue static void _dns_shent(int stayopen); 1267d56d374SYoshinobu Inoue static void _dns_ehent(void); 1277d56d374SYoshinobu Inoue #ifdef ICMPNL 1287d56d374SYoshinobu Inoue static struct hostent *_icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp); 1297d56d374SYoshinobu Inoue #endif /* ICMPNL */ 1307d56d374SYoshinobu Inoue 1317d56d374SYoshinobu Inoue /* 1327d56d374SYoshinobu Inoue * Select order host function. 1337d56d374SYoshinobu Inoue */ 1347d56d374SYoshinobu Inoue #define MAXHOSTCONF 4 1357d56d374SYoshinobu Inoue 1367d56d374SYoshinobu Inoue #ifndef HOSTCONF 1377d56d374SYoshinobu Inoue # define HOSTCONF "/etc/host.conf" 1387d56d374SYoshinobu Inoue #endif /* !HOSTCONF */ 1397d56d374SYoshinobu Inoue 1407d56d374SYoshinobu Inoue struct _hostconf { 1417d56d374SYoshinobu Inoue struct hostent *(*byname)(const char *name, int af, int *errp); 1427d56d374SYoshinobu Inoue struct hostent *(*byaddr)(const void *addr, int addrlen, int af, int *errp); 1437d56d374SYoshinobu Inoue }; 1447d56d374SYoshinobu Inoue 1457d56d374SYoshinobu Inoue /* default order */ 1467d56d374SYoshinobu Inoue static struct _hostconf _hostconf[MAXHOSTCONF] = { 1477d56d374SYoshinobu Inoue { _dns_ghbyname, _dns_ghbyaddr }, 1487d56d374SYoshinobu Inoue { _files_ghbyname, _files_ghbyaddr }, 1497d56d374SYoshinobu Inoue #ifdef ICMPNL 1507d56d374SYoshinobu Inoue { NULL, _icmp_ghbyaddr }, 1517d56d374SYoshinobu Inoue #endif /* ICMPNL */ 1527d56d374SYoshinobu Inoue }; 1537d56d374SYoshinobu Inoue 1547d56d374SYoshinobu Inoue static int _hostconf_init_done; 1557d56d374SYoshinobu Inoue static void _hostconf_init(void); 1567d56d374SYoshinobu Inoue 1577d56d374SYoshinobu Inoue /* 1587d56d374SYoshinobu Inoue * Initialize hostconf structure. 1597d56d374SYoshinobu Inoue */ 1607d56d374SYoshinobu Inoue 1617d56d374SYoshinobu Inoue static void 1627d56d374SYoshinobu Inoue _hostconf_init(void) 1637d56d374SYoshinobu Inoue { 1647d56d374SYoshinobu Inoue FILE *fp; 1657d56d374SYoshinobu Inoue int n; 1667d56d374SYoshinobu Inoue char *p, *line; 1677d56d374SYoshinobu Inoue char buf[BUFSIZ]; 1687d56d374SYoshinobu Inoue 1697d56d374SYoshinobu Inoue _hostconf_init_done = 1; 1707d56d374SYoshinobu Inoue n = 0; 1717d56d374SYoshinobu Inoue p = HOSTCONF; 1727d56d374SYoshinobu Inoue if ((fp = fopen(p, "r")) == NULL) 1737d56d374SYoshinobu Inoue return; 1747d56d374SYoshinobu Inoue while (n < MAXHOSTCONF && fgets(buf, sizeof(buf), fp)) { 1757d56d374SYoshinobu Inoue line = buf; 1767d56d374SYoshinobu Inoue if ((p = _hgetword(&line)) == NULL) 1777d56d374SYoshinobu Inoue continue; 1787d56d374SYoshinobu Inoue do { 1797d56d374SYoshinobu Inoue if (strcmp(p, "hosts") == 0 1807d56d374SYoshinobu Inoue || strcmp(p, "local") == 0 1817d56d374SYoshinobu Inoue || strcmp(p, "file") == 0 1827d56d374SYoshinobu Inoue || strcmp(p, "files") == 0) { 1837d56d374SYoshinobu Inoue _hostconf[n].byname = _files_ghbyname; 1847d56d374SYoshinobu Inoue _hostconf[n].byaddr = _files_ghbyaddr; 1857d56d374SYoshinobu Inoue n++; 1867d56d374SYoshinobu Inoue } 1877d56d374SYoshinobu Inoue else if (strcmp(p, "dns") == 0 1887d56d374SYoshinobu Inoue || strcmp(p, "bind") == 0) { 1897d56d374SYoshinobu Inoue _hostconf[n].byname = _dns_ghbyname; 1907d56d374SYoshinobu Inoue _hostconf[n].byaddr = _dns_ghbyaddr; 1917d56d374SYoshinobu Inoue n++; 1927d56d374SYoshinobu Inoue } 19363858012SJonathan Lemon else if (strcmp(p, "nis") == 0) { 19463858012SJonathan Lemon _hostconf[n].byname = _nis_ghbyname; 19563858012SJonathan Lemon _hostconf[n].byaddr = _nis_ghbyaddr; 19663858012SJonathan Lemon n++; 19763858012SJonathan Lemon } 1987d56d374SYoshinobu Inoue #ifdef ICMPNL 1997d56d374SYoshinobu Inoue else if (strcmp(p, "icmp") == 0) { 2007d56d374SYoshinobu Inoue _hostconf[n].byname = NULL; 2017d56d374SYoshinobu Inoue _hostconf[n].byaddr = _icmp_ghbyaddr; 2027d56d374SYoshinobu Inoue n++; 2037d56d374SYoshinobu Inoue } 2047d56d374SYoshinobu Inoue #endif /* ICMPNL */ 2057d56d374SYoshinobu Inoue } while ((p = _hgetword(&line)) != NULL); 2067d56d374SYoshinobu Inoue } 2077d56d374SYoshinobu Inoue fclose(fp); 2087d56d374SYoshinobu Inoue if (n < 0) { 2097d56d374SYoshinobu Inoue /* no keyword found. do not change default configuration */ 2107d56d374SYoshinobu Inoue return; 2117d56d374SYoshinobu Inoue } 2127d56d374SYoshinobu Inoue for (; n < MAXHOSTCONF; n++) { 2137d56d374SYoshinobu Inoue _hostconf[n].byname = NULL; 2147d56d374SYoshinobu Inoue _hostconf[n].byaddr = NULL; 2157d56d374SYoshinobu Inoue } 2167d56d374SYoshinobu Inoue } 2177d56d374SYoshinobu Inoue 2187d56d374SYoshinobu Inoue /* 2197d56d374SYoshinobu Inoue * Check if kernel supports mapped address. 2207d56d374SYoshinobu Inoue * implementation dependent 2217d56d374SYoshinobu Inoue */ 2227d56d374SYoshinobu Inoue #ifdef __KAME__ 2237d56d374SYoshinobu Inoue #include <sys/sysctl.h> 2247d56d374SYoshinobu Inoue #endif /* __KAME__ */ 2257d56d374SYoshinobu Inoue 2267d56d374SYoshinobu Inoue static int 2277d56d374SYoshinobu Inoue _mapped_addr_enabled(void) 2287d56d374SYoshinobu Inoue { 2297d56d374SYoshinobu Inoue /* implementation dependent check */ 2307d56d374SYoshinobu Inoue #if defined(__KAME__) && defined(IPV6CTL_MAPPED_ADDR) 2317d56d374SYoshinobu Inoue int mib[4]; 2327d56d374SYoshinobu Inoue size_t len; 2337d56d374SYoshinobu Inoue int val; 2347d56d374SYoshinobu Inoue 2357d56d374SYoshinobu Inoue mib[0] = CTL_NET; 2367d56d374SYoshinobu Inoue mib[1] = PF_INET6; 2377d56d374SYoshinobu Inoue mib[2] = IPPROTO_IPV6; 2387d56d374SYoshinobu Inoue mib[3] = IPV6CTL_MAPPED_ADDR; 2397d56d374SYoshinobu Inoue len = sizeof(val); 2407d56d374SYoshinobu Inoue if (sysctl(mib, 4, &val, &len, 0, 0) == 0 && val != 0) 2417d56d374SYoshinobu Inoue return 1; 2427d56d374SYoshinobu Inoue #endif /* __KAME__ && IPV6CTL_MAPPED_ADDR */ 2437d56d374SYoshinobu Inoue return 0; 2447d56d374SYoshinobu Inoue } 2457d56d374SYoshinobu Inoue 2467d56d374SYoshinobu Inoue /* 2477d56d374SYoshinobu Inoue * Functions defined in RFC2553 2487d56d374SYoshinobu Inoue * getipnodebyname, getipnodebyadr, freehostent 2497d56d374SYoshinobu Inoue */ 2507d56d374SYoshinobu Inoue 2517d56d374SYoshinobu Inoue static struct hostent * 2527d56d374SYoshinobu Inoue _ghbyname(const char *name, int af, int flags, int *errp) 2537d56d374SYoshinobu Inoue { 2547d56d374SYoshinobu Inoue struct hostent *hp; 2557d56d374SYoshinobu Inoue int i; 2567d56d374SYoshinobu Inoue 2577d56d374SYoshinobu Inoue if (flags & AI_ADDRCONFIG) { 2587d56d374SYoshinobu Inoue int s; 2597d56d374SYoshinobu Inoue 2607d56d374SYoshinobu Inoue /* 2617d56d374SYoshinobu Inoue * TODO: 2627d56d374SYoshinobu Inoue * Note that implementation dependent test for address 2637d56d374SYoshinobu Inoue * configuration should be done everytime called 2647d56d374SYoshinobu Inoue * (or apropriate interval), 2657d56d374SYoshinobu Inoue * because addresses will be dynamically assigned or deleted. 2667d56d374SYoshinobu Inoue */ 267e6f35403SYoshinobu Inoue if (af == AF_UNSPEC) { 268e6f35403SYoshinobu Inoue if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 269e6f35403SYoshinobu Inoue af = AF_INET; 270e6f35403SYoshinobu Inoue else { 2719233c4d9SJason Evans _close(s); 272e6f35403SYoshinobu Inoue if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 273e6f35403SYoshinobu Inoue af = AF_INET6; 274e6f35403SYoshinobu Inoue else 275e6f35403SYoshinobu Inoue _close(s); 276e6f35403SYoshinobu Inoue } 277e6f35403SYoshinobu Inoue 278e6f35403SYoshinobu Inoue } 279e6f35403SYoshinobu Inoue if (af != AF_UNSPEC) { 280e6f35403SYoshinobu Inoue if ((s = socket(af, SOCK_DGRAM, 0)) < 0) 281e6f35403SYoshinobu Inoue return NULL; 282e6f35403SYoshinobu Inoue _close(s); 283e6f35403SYoshinobu Inoue } 2847d56d374SYoshinobu Inoue } 2857d56d374SYoshinobu Inoue 2867d56d374SYoshinobu Inoue for (i = 0; i < MAXHOSTCONF; i++) { 2877d56d374SYoshinobu Inoue if (_hostconf[i].byname 2887d56d374SYoshinobu Inoue && (hp = (*_hostconf[i].byname)(name, af, errp)) 2897d56d374SYoshinobu Inoue != NULL) 2907d56d374SYoshinobu Inoue return hp; 2917d56d374SYoshinobu Inoue } 2927d56d374SYoshinobu Inoue 2937d56d374SYoshinobu Inoue return NULL; 2947d56d374SYoshinobu Inoue } 2957d56d374SYoshinobu Inoue 296e6f35403SYoshinobu Inoue /* getipnodebyname() internal routine for multiple query(PF_UNSPEC) support. */ 2977d56d374SYoshinobu Inoue struct hostent * 298e6f35403SYoshinobu Inoue _getipnodebyname_multi(const char *name, int af, int flags, int *errp) 2997d56d374SYoshinobu Inoue { 3007d56d374SYoshinobu Inoue struct hostent *hp; 3017d56d374SYoshinobu Inoue union inx_addr addrbuf; 3027d56d374SYoshinobu Inoue 303e6f35403SYoshinobu Inoue /* XXX: PF_UNSPEC is only supposed to be passed from getaddrinfo() */ 3047d56d374SYoshinobu Inoue if (af != AF_INET 3057d56d374SYoshinobu Inoue #ifdef INET6 3067d56d374SYoshinobu Inoue && af != AF_INET6 3077d56d374SYoshinobu Inoue #endif 308e6f35403SYoshinobu Inoue && af != PF_UNSPEC 3097d56d374SYoshinobu Inoue ) 3107d56d374SYoshinobu Inoue { 3117d56d374SYoshinobu Inoue *errp = NO_RECOVERY; 3127d56d374SYoshinobu Inoue return NULL; 3137d56d374SYoshinobu Inoue } 3147d56d374SYoshinobu Inoue 3157d56d374SYoshinobu Inoue #ifdef INET6 3167d56d374SYoshinobu Inoue /* special case for literal address */ 3177d56d374SYoshinobu Inoue if (inet_pton(AF_INET6, name, &addrbuf) == 1) { 3187d56d374SYoshinobu Inoue if (af != AF_INET6) { 3197d56d374SYoshinobu Inoue *errp = HOST_NOT_FOUND; 3207d56d374SYoshinobu Inoue return NULL; 3217d56d374SYoshinobu Inoue } 3227d56d374SYoshinobu Inoue return _hpaddr(af, name, &addrbuf, errp); 3237d56d374SYoshinobu Inoue } 3247d56d374SYoshinobu Inoue #endif 325be26adb5SYoshinobu Inoue if (inet_aton(name, (struct in_addr *)&addrbuf) == 1) { 3267d56d374SYoshinobu Inoue if (af != AF_INET) { 3277d56d374SYoshinobu Inoue if (MAPADDRENABLED(flags)) { 3287d56d374SYoshinobu Inoue MAPADDR(&addrbuf, &addrbuf.in_addr); 3297d56d374SYoshinobu Inoue } else { 3307d56d374SYoshinobu Inoue *errp = HOST_NOT_FOUND; 3317d56d374SYoshinobu Inoue return NULL; 3327d56d374SYoshinobu Inoue } 3337d56d374SYoshinobu Inoue } 3347d56d374SYoshinobu Inoue return _hpaddr(af, name, &addrbuf, errp); 3357d56d374SYoshinobu Inoue } 3367d56d374SYoshinobu Inoue 3377d56d374SYoshinobu Inoue if (!_hostconf_init_done) 3387d56d374SYoshinobu Inoue _hostconf_init(); 3397d56d374SYoshinobu Inoue 3407d56d374SYoshinobu Inoue *errp = HOST_NOT_FOUND; 3417d56d374SYoshinobu Inoue hp = _ghbyname(name, af, flags, errp); 3427d56d374SYoshinobu Inoue 3437d56d374SYoshinobu Inoue #ifdef INET6 3447d56d374SYoshinobu Inoue if (af == AF_INET6 3457d56d374SYoshinobu Inoue && ((flags & AI_ALL) || hp == NULL) 3467d56d374SYoshinobu Inoue && (MAPADDRENABLED(flags))) { 3477d56d374SYoshinobu Inoue struct hostent *hp2 = _ghbyname(name, AF_INET, flags, errp); 3487d56d374SYoshinobu Inoue if (hp == NULL) 3497d56d374SYoshinobu Inoue hp = _hpmapv6(hp2, errp); 3507d56d374SYoshinobu Inoue else { 3517d56d374SYoshinobu Inoue if (hp2 && strcmp(hp->h_name, hp2->h_name) != 0) { 3527d56d374SYoshinobu Inoue freehostent(hp2); 3537d56d374SYoshinobu Inoue hp2 = NULL; 3547d56d374SYoshinobu Inoue } 3557d56d374SYoshinobu Inoue hp = _hpmerge(hp, hp2, errp); 3567d56d374SYoshinobu Inoue } 3577d56d374SYoshinobu Inoue } 3587d56d374SYoshinobu Inoue #endif 3597d56d374SYoshinobu Inoue return _hpsort(hp); 3607d56d374SYoshinobu Inoue } 3617d56d374SYoshinobu Inoue 3627d56d374SYoshinobu Inoue struct hostent * 363e6f35403SYoshinobu Inoue getipnodebyname(const char *name, int af, int flags, int *errp) 364e6f35403SYoshinobu Inoue { 365e6f35403SYoshinobu Inoue if (af != AF_INET 366e6f35403SYoshinobu Inoue #ifdef INET6 367e6f35403SYoshinobu Inoue && af != AF_INET6 368e6f35403SYoshinobu Inoue #endif 369e6f35403SYoshinobu Inoue ) 370e6f35403SYoshinobu Inoue { 371e6f35403SYoshinobu Inoue *errp = NO_RECOVERY; 372e6f35403SYoshinobu Inoue return NULL; 373e6f35403SYoshinobu Inoue } 374e6f35403SYoshinobu Inoue return(_getipnodebyname_multi(name, af ,flags, errp)); 375e6f35403SYoshinobu Inoue } 376e6f35403SYoshinobu Inoue 377e6f35403SYoshinobu Inoue struct hostent * 3787d56d374SYoshinobu Inoue getipnodebyaddr(const void *src, size_t len, int af, int *errp) 3797d56d374SYoshinobu Inoue { 3807d56d374SYoshinobu Inoue struct hostent *hp; 3817d56d374SYoshinobu Inoue int i; 3827d56d374SYoshinobu Inoue #ifdef INET6 3837d56d374SYoshinobu Inoue struct in6_addr addrbuf; 3847d56d374SYoshinobu Inoue #else 3857d56d374SYoshinobu Inoue struct in_addr addrbuf; 3867d56d374SYoshinobu Inoue #endif 3877d56d374SYoshinobu Inoue 3887d56d374SYoshinobu Inoue *errp = HOST_NOT_FOUND; 3897d56d374SYoshinobu Inoue 3907d56d374SYoshinobu Inoue switch (af) { 3917d56d374SYoshinobu Inoue case AF_INET: 3927d56d374SYoshinobu Inoue if (len != sizeof(struct in_addr)) { 3937d56d374SYoshinobu Inoue *errp = NO_RECOVERY; 3947d56d374SYoshinobu Inoue return NULL; 3957d56d374SYoshinobu Inoue } 3967d56d374SYoshinobu Inoue if ((long)src & ~(sizeof(struct in_addr) - 1)) { 3977d56d374SYoshinobu Inoue memcpy(&addrbuf, src, len); 3987d56d374SYoshinobu Inoue src = &addrbuf; 3997d56d374SYoshinobu Inoue } 4007d56d374SYoshinobu Inoue if (((struct in_addr *)src)->s_addr == 0) 4017d56d374SYoshinobu Inoue return NULL; 4027d56d374SYoshinobu Inoue break; 4037d56d374SYoshinobu Inoue #ifdef INET6 4047d56d374SYoshinobu Inoue case AF_INET6: 4057d56d374SYoshinobu Inoue if (len != sizeof(struct in6_addr)) { 4067d56d374SYoshinobu Inoue *errp = NO_RECOVERY; 4077d56d374SYoshinobu Inoue return NULL; 4087d56d374SYoshinobu Inoue } 4097d56d374SYoshinobu Inoue if ((long)src & ~(sizeof(struct in6_addr) / 2 - 1)) { /*XXX*/ 4107d56d374SYoshinobu Inoue memcpy(&addrbuf, src, len); 4117d56d374SYoshinobu Inoue src = &addrbuf; 4127d56d374SYoshinobu Inoue } 4133d670abcSYoshinobu Inoue if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)src)) 4143d670abcSYoshinobu Inoue return NULL; 4157d56d374SYoshinobu Inoue if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)src) 4167d56d374SYoshinobu Inoue || IN6_IS_ADDR_V4COMPAT((struct in6_addr *)src)) { 4177d56d374SYoshinobu Inoue src = (char *)src + 4187d56d374SYoshinobu Inoue (sizeof(struct in6_addr) - sizeof(struct in_addr)); 4197d56d374SYoshinobu Inoue af = AF_INET; 4207d56d374SYoshinobu Inoue len = sizeof(struct in_addr); 4217d56d374SYoshinobu Inoue } 4227d56d374SYoshinobu Inoue break; 4237d56d374SYoshinobu Inoue #endif 4247d56d374SYoshinobu Inoue default: 4257d56d374SYoshinobu Inoue *errp = NO_RECOVERY; 4267d56d374SYoshinobu Inoue return NULL; 4277d56d374SYoshinobu Inoue } 4287d56d374SYoshinobu Inoue 4297d56d374SYoshinobu Inoue if (!_hostconf_init_done) 4307d56d374SYoshinobu Inoue _hostconf_init(); 4317d56d374SYoshinobu Inoue for (i = 0; i < MAXHOSTCONF; i++) { 4327d56d374SYoshinobu Inoue if (_hostconf[i].byaddr 4337d56d374SYoshinobu Inoue && (hp = (*_hostconf[i].byaddr)(src, len, af, errp)) != NULL) 4347d56d374SYoshinobu Inoue return hp; 4357d56d374SYoshinobu Inoue } 4367d56d374SYoshinobu Inoue 4377d56d374SYoshinobu Inoue return NULL; 4387d56d374SYoshinobu Inoue } 4397d56d374SYoshinobu Inoue 4407d56d374SYoshinobu Inoue void 4417d56d374SYoshinobu Inoue freehostent(struct hostent *ptr) 4427d56d374SYoshinobu Inoue { 4437d56d374SYoshinobu Inoue free(ptr); 4447d56d374SYoshinobu Inoue } 4457d56d374SYoshinobu Inoue 4467d56d374SYoshinobu Inoue #if 0 4477d56d374SYoshinobu Inoue 4487d56d374SYoshinobu Inoue /* XXX: should be deprecated */ 4497d56d374SYoshinobu Inoue struct hostent * 4507d56d374SYoshinobu Inoue getnodebyname(const char *name, int af, int flags) 4517d56d374SYoshinobu Inoue { 4527d56d374SYoshinobu Inoue return getipnodebyname(name, af, flags, &h_errno); 4537d56d374SYoshinobu Inoue } 4547d56d374SYoshinobu Inoue 4557d56d374SYoshinobu Inoue #ifdef __warn_references 4567d56d374SYoshinobu Inoue __warn_references(getnodebyname, 4577d56d374SYoshinobu Inoue "warning: getnodebyname() deprecated, " 4587d56d374SYoshinobu Inoue "should use getaddrinfo() or getipnodebyname()"); 4597d56d374SYoshinobu Inoue #endif 4607d56d374SYoshinobu Inoue 4617d56d374SYoshinobu Inoue struct hostent * 4627d56d374SYoshinobu Inoue getnodebyaddr(const void *src, size_t len, int af) 4637d56d374SYoshinobu Inoue { 4647d56d374SYoshinobu Inoue return getipnodebyaddr(src, len, af, &h_errno); 4657d56d374SYoshinobu Inoue } 4667d56d374SYoshinobu Inoue 4677d56d374SYoshinobu Inoue #ifdef __warn_references 4687d56d374SYoshinobu Inoue __warn_references(getnodebyaddr, 4697d56d374SYoshinobu Inoue "warning: getnodebyaddr() deprecated, " 4707d56d374SYoshinobu Inoue "should use getnameinfo() or getipnodebyaddr()"); 4717d56d374SYoshinobu Inoue #endif 4727d56d374SYoshinobu Inoue 4737d56d374SYoshinobu Inoue #endif 4747d56d374SYoshinobu Inoue 4757d56d374SYoshinobu Inoue /* 4767d56d374SYoshinobu Inoue * Private utility functions 4777d56d374SYoshinobu Inoue */ 4787d56d374SYoshinobu Inoue 4797d56d374SYoshinobu Inoue /* 4807d56d374SYoshinobu Inoue * _hpcopy: allocate and copy hostent structure 4817d56d374SYoshinobu Inoue */ 4827d56d374SYoshinobu Inoue static struct hostent * 4837d56d374SYoshinobu Inoue _hpcopy(struct hostent *hp, int *errp) 4847d56d374SYoshinobu Inoue { 4857d56d374SYoshinobu Inoue struct hostent *nhp; 4867d56d374SYoshinobu Inoue char *cp, **pp; 4877d56d374SYoshinobu Inoue int size, addrsize; 4887d56d374SYoshinobu Inoue int nalias = 0, naddr = 0; 4897d56d374SYoshinobu Inoue int al_off; 4907d56d374SYoshinobu Inoue int i; 4917d56d374SYoshinobu Inoue 4927d56d374SYoshinobu Inoue if (hp == NULL) 4937d56d374SYoshinobu Inoue return hp; 4947d56d374SYoshinobu Inoue 4957d56d374SYoshinobu Inoue /* count size to be allocated */ 4967d56d374SYoshinobu Inoue size = sizeof(struct hostent); 4977d56d374SYoshinobu Inoue if (hp->h_name != NULL && *hp->h_name != '\0') 4987d56d374SYoshinobu Inoue size += strlen(hp->h_name) + 1; 4997d56d374SYoshinobu Inoue if ((pp = hp->h_aliases) != NULL) { 5007d56d374SYoshinobu Inoue for (i = 0; *pp != NULL; i++, pp++) { 5017d56d374SYoshinobu Inoue if (**pp != '\0') { 5027d56d374SYoshinobu Inoue size += strlen(*pp) + 1; 5037d56d374SYoshinobu Inoue nalias++; 5047d56d374SYoshinobu Inoue } 5057d56d374SYoshinobu Inoue } 5067d56d374SYoshinobu Inoue } 5077d56d374SYoshinobu Inoue /* adjust alignment */ 5087d56d374SYoshinobu Inoue size = ALIGN(size); 5097d56d374SYoshinobu Inoue al_off = size; 5107d56d374SYoshinobu Inoue size += sizeof(char *) * (nalias + 1); 5117d56d374SYoshinobu Inoue addrsize = ALIGN(hp->h_length); 5127d56d374SYoshinobu Inoue if ((pp = hp->h_addr_list) != NULL) { 5137d56d374SYoshinobu Inoue while (*pp++ != NULL) 5147d56d374SYoshinobu Inoue naddr++; 5157d56d374SYoshinobu Inoue } 5167d56d374SYoshinobu Inoue size += addrsize * naddr; 5177d56d374SYoshinobu Inoue size += sizeof(char *) * (naddr + 1); 5187d56d374SYoshinobu Inoue 5197d56d374SYoshinobu Inoue /* copy */ 5207d56d374SYoshinobu Inoue if ((nhp = (struct hostent *)malloc(size)) == NULL) { 5217d56d374SYoshinobu Inoue *errp = TRY_AGAIN; 5227d56d374SYoshinobu Inoue return NULL; 5237d56d374SYoshinobu Inoue } 5247d56d374SYoshinobu Inoue cp = (char *)&nhp[1]; 5257d56d374SYoshinobu Inoue if (hp->h_name != NULL && *hp->h_name != '\0') { 5267d56d374SYoshinobu Inoue nhp->h_name = cp; 5277d56d374SYoshinobu Inoue strcpy(cp, hp->h_name); 5287d56d374SYoshinobu Inoue cp += strlen(cp) + 1; 5297d56d374SYoshinobu Inoue } else 5307d56d374SYoshinobu Inoue nhp->h_name = NULL; 5317d56d374SYoshinobu Inoue nhp->h_aliases = (char **)((char *)nhp + al_off); 5327d56d374SYoshinobu Inoue if ((pp = hp->h_aliases) != NULL) { 5337d56d374SYoshinobu Inoue for (i = 0; *pp != NULL; pp++) { 5347d56d374SYoshinobu Inoue if (**pp != '\0') { 5357d56d374SYoshinobu Inoue nhp->h_aliases[i++] = cp; 5367d56d374SYoshinobu Inoue strcpy(cp, *pp); 5377d56d374SYoshinobu Inoue cp += strlen(cp) + 1; 5387d56d374SYoshinobu Inoue } 5397d56d374SYoshinobu Inoue } 5407d56d374SYoshinobu Inoue } 5417d56d374SYoshinobu Inoue nhp->h_aliases[nalias] = NULL; 5427d56d374SYoshinobu Inoue cp = (char *)&nhp->h_aliases[nalias + 1]; 5437d56d374SYoshinobu Inoue nhp->h_addrtype = hp->h_addrtype; 5447d56d374SYoshinobu Inoue nhp->h_length = hp->h_length; 5457d56d374SYoshinobu Inoue nhp->h_addr_list = (char **)cp; 5467d56d374SYoshinobu Inoue if ((pp = hp->h_addr_list) != NULL) { 5477d56d374SYoshinobu Inoue cp = (char *)&nhp->h_addr_list[naddr + 1]; 5487d56d374SYoshinobu Inoue for (i = 0; *pp != NULL; pp++) { 5497d56d374SYoshinobu Inoue nhp->h_addr_list[i++] = cp; 5507d56d374SYoshinobu Inoue memcpy(cp, *pp, hp->h_length); 5517d56d374SYoshinobu Inoue cp += addrsize; 5527d56d374SYoshinobu Inoue } 5537d56d374SYoshinobu Inoue } 5547d56d374SYoshinobu Inoue nhp->h_addr_list[naddr] = NULL; 5557d56d374SYoshinobu Inoue return nhp; 5567d56d374SYoshinobu Inoue } 5577d56d374SYoshinobu Inoue 5587d56d374SYoshinobu Inoue /* 5597d56d374SYoshinobu Inoue * _hpaddr: construct hostent structure with one address 5607d56d374SYoshinobu Inoue */ 5617d56d374SYoshinobu Inoue static struct hostent * 5627d56d374SYoshinobu Inoue _hpaddr(int af, const char *name, void *addr, int *errp) 5637d56d374SYoshinobu Inoue { 5647d56d374SYoshinobu Inoue struct hostent *hp, hpbuf; 5657d56d374SYoshinobu Inoue char *addrs[2]; 5667d56d374SYoshinobu Inoue 5677d56d374SYoshinobu Inoue hp = &hpbuf; 5687d56d374SYoshinobu Inoue hp->h_name = (char *)name; 5697d56d374SYoshinobu Inoue hp->h_aliases = NULL; 5707d56d374SYoshinobu Inoue hp->h_addrtype = af; 5717d56d374SYoshinobu Inoue hp->h_length = ADDRLEN(af); 5727d56d374SYoshinobu Inoue hp->h_addr_list = addrs; 5737d56d374SYoshinobu Inoue addrs[0] = (char *)addr; 5747d56d374SYoshinobu Inoue addrs[1] = NULL; 5757d56d374SYoshinobu Inoue return _hpcopy(hp, errp); 5767d56d374SYoshinobu Inoue } 5777d56d374SYoshinobu Inoue 5787d56d374SYoshinobu Inoue /* 5797d56d374SYoshinobu Inoue * _hpmerge: merge 2 hostent structure, arguments will be freed 5807d56d374SYoshinobu Inoue */ 5817d56d374SYoshinobu Inoue static struct hostent * 5827d56d374SYoshinobu Inoue _hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp) 5837d56d374SYoshinobu Inoue { 5847d56d374SYoshinobu Inoue int i, j; 5857d56d374SYoshinobu Inoue int naddr, nalias; 5867d56d374SYoshinobu Inoue char **pp; 5877d56d374SYoshinobu Inoue struct hostent *hp, hpbuf; 5887d56d374SYoshinobu Inoue char *aliases[MAXALIASES + 1], *addrs[MAXADDRS + 1]; 5897d56d374SYoshinobu Inoue union inx_addr addrbuf[MAXADDRS]; 5907d56d374SYoshinobu Inoue 5917d56d374SYoshinobu Inoue if (hp1 == NULL) 5927d56d374SYoshinobu Inoue return hp2; 5937d56d374SYoshinobu Inoue if (hp2 == NULL) 5947d56d374SYoshinobu Inoue return hp1; 5957d56d374SYoshinobu Inoue 5967d56d374SYoshinobu Inoue #define HP(i) (i == 1 ? hp1 : hp2) 5977d56d374SYoshinobu Inoue hp = &hpbuf; 5987d56d374SYoshinobu Inoue hp->h_name = (hp1->h_name != NULL ? hp1->h_name : hp2->h_name); 5997d56d374SYoshinobu Inoue hp->h_aliases = aliases; 6007d56d374SYoshinobu Inoue nalias = 0; 6017d56d374SYoshinobu Inoue for (i = 1; i <= 2; i++) { 6027d56d374SYoshinobu Inoue if ((pp = HP(i)->h_aliases) == NULL) 6037d56d374SYoshinobu Inoue continue; 6047d56d374SYoshinobu Inoue for (; nalias < MAXALIASES && *pp != NULL; pp++) { 6057d56d374SYoshinobu Inoue /* check duplicates */ 6067d56d374SYoshinobu Inoue for (j = 0; j < nalias; j++) 6077d56d374SYoshinobu Inoue if (strcasecmp(*pp, aliases[j]) == 0) 6087d56d374SYoshinobu Inoue break; 6097d56d374SYoshinobu Inoue if (j == nalias) 6107d56d374SYoshinobu Inoue aliases[nalias++] = *pp; 6117d56d374SYoshinobu Inoue } 6127d56d374SYoshinobu Inoue } 6137d56d374SYoshinobu Inoue aliases[nalias] = NULL; 6147d56d374SYoshinobu Inoue #ifdef INET6 6157d56d374SYoshinobu Inoue if (hp1->h_length != hp2->h_length) { 6167d56d374SYoshinobu Inoue hp->h_addrtype = AF_INET6; 6177d56d374SYoshinobu Inoue hp->h_length = sizeof(struct in6_addr); 6187d56d374SYoshinobu Inoue } else { 6197d56d374SYoshinobu Inoue #endif 6207d56d374SYoshinobu Inoue hp->h_addrtype = hp1->h_addrtype; 6217d56d374SYoshinobu Inoue hp->h_length = hp1->h_length; 6227d56d374SYoshinobu Inoue #ifdef INET6 6237d56d374SYoshinobu Inoue } 6247d56d374SYoshinobu Inoue #endif 6257d56d374SYoshinobu Inoue hp->h_addr_list = addrs; 6267d56d374SYoshinobu Inoue naddr = 0; 6277d56d374SYoshinobu Inoue for (i = 1; i <= 2; i++) { 6287d56d374SYoshinobu Inoue if ((pp = HP(i)->h_addr_list) == NULL) 6297d56d374SYoshinobu Inoue continue; 6307d56d374SYoshinobu Inoue if (HP(i)->h_length == hp->h_length) { 6317d56d374SYoshinobu Inoue while (naddr < MAXADDRS && *pp != NULL) 6327d56d374SYoshinobu Inoue addrs[naddr++] = *pp++; 6337d56d374SYoshinobu Inoue } else { 6347d56d374SYoshinobu Inoue /* copy IPv4 addr as mapped IPv6 addr */ 6357d56d374SYoshinobu Inoue while (naddr < MAXADDRS && *pp != NULL) { 6367d56d374SYoshinobu Inoue MAPADDR(&addrbuf[naddr], *pp++); 6377d56d374SYoshinobu Inoue addrs[naddr] = (char *)&addrbuf[naddr]; 6387d56d374SYoshinobu Inoue naddr++; 6397d56d374SYoshinobu Inoue } 6407d56d374SYoshinobu Inoue } 6417d56d374SYoshinobu Inoue } 6427d56d374SYoshinobu Inoue addrs[naddr] = NULL; 6437d56d374SYoshinobu Inoue hp = _hpcopy(hp, errp); 6447d56d374SYoshinobu Inoue freehostent(hp1); 6457d56d374SYoshinobu Inoue freehostent(hp2); 6467d56d374SYoshinobu Inoue return hp; 6477d56d374SYoshinobu Inoue } 6487d56d374SYoshinobu Inoue 6497d56d374SYoshinobu Inoue /* 6507d56d374SYoshinobu Inoue * _hpmapv6: convert IPv4 hostent into IPv4-mapped IPv6 addresses 6517d56d374SYoshinobu Inoue */ 6527d56d374SYoshinobu Inoue #ifdef INET6 6537d56d374SYoshinobu Inoue static struct hostent * 6547d56d374SYoshinobu Inoue _hpmapv6(struct hostent *hp, int *errp) 6557d56d374SYoshinobu Inoue { 6567d56d374SYoshinobu Inoue struct hostent *hp6; 6577d56d374SYoshinobu Inoue 6587d56d374SYoshinobu Inoue if (hp == NULL) 6597d56d374SYoshinobu Inoue return NULL; 6607d56d374SYoshinobu Inoue if (hp->h_addrtype == AF_INET6) 6617d56d374SYoshinobu Inoue return hp; 6627d56d374SYoshinobu Inoue 6637d56d374SYoshinobu Inoue /* make dummy hostent to convert IPv6 address */ 6647d56d374SYoshinobu Inoue if ((hp6 = (struct hostent *)malloc(sizeof(struct hostent))) == NULL) { 6657d56d374SYoshinobu Inoue *errp = TRY_AGAIN; 6667d56d374SYoshinobu Inoue return NULL; 6677d56d374SYoshinobu Inoue } 6687d56d374SYoshinobu Inoue hp6->h_name = NULL; 6697d56d374SYoshinobu Inoue hp6->h_aliases = NULL; 6707d56d374SYoshinobu Inoue hp6->h_addrtype = AF_INET6; 6717d56d374SYoshinobu Inoue hp6->h_length = sizeof(struct in6_addr); 6727d56d374SYoshinobu Inoue hp6->h_addr_list = NULL; 6737d56d374SYoshinobu Inoue return _hpmerge(hp6, hp, errp); 6747d56d374SYoshinobu Inoue } 6757d56d374SYoshinobu Inoue #endif 6767d56d374SYoshinobu Inoue 6777d56d374SYoshinobu Inoue /* 6787d56d374SYoshinobu Inoue * _hpsort: sort address by sortlist 6797d56d374SYoshinobu Inoue */ 6807d56d374SYoshinobu Inoue static struct hostent * 6817d56d374SYoshinobu Inoue _hpsort(struct hostent *hp) 6827d56d374SYoshinobu Inoue { 6837d56d374SYoshinobu Inoue int i, j, n; 6847d56d374SYoshinobu Inoue u_char *ap, *sp, *mp, **pp; 6857d56d374SYoshinobu Inoue char t; 6867d56d374SYoshinobu Inoue char order[MAXADDRS]; 6877d56d374SYoshinobu Inoue int nsort = _res.nsort; 6887d56d374SYoshinobu Inoue 6897d56d374SYoshinobu Inoue if (hp == NULL || hp->h_addr_list[1] == NULL || nsort == 0) 6907d56d374SYoshinobu Inoue return hp; 6917d56d374SYoshinobu Inoue for (i = 0; (ap = (u_char *)hp->h_addr_list[i]); i++) { 6927d56d374SYoshinobu Inoue for (j = 0; j < nsort; j++) { 6937d56d374SYoshinobu Inoue #ifdef INET6 6947d56d374SYoshinobu Inoue if (_res_ext.sort_list[j].af != hp->h_addrtype) 6957d56d374SYoshinobu Inoue continue; 6967d56d374SYoshinobu Inoue sp = (u_char *)&_res_ext.sort_list[j].addr; 6977d56d374SYoshinobu Inoue mp = (u_char *)&_res_ext.sort_list[j].mask; 6987d56d374SYoshinobu Inoue #else 6997d56d374SYoshinobu Inoue sp = (u_char *)&_res.sort_list[j].addr; 7007d56d374SYoshinobu Inoue mp = (u_char *)&_res.sort_list[j].mask; 7017d56d374SYoshinobu Inoue #endif 7027d56d374SYoshinobu Inoue for (n = 0; n < hp->h_length; n++) { 7037d56d374SYoshinobu Inoue if ((ap[n] & mp[n]) != sp[n]) 7047d56d374SYoshinobu Inoue break; 7057d56d374SYoshinobu Inoue } 7067d56d374SYoshinobu Inoue if (n == hp->h_length) 7077d56d374SYoshinobu Inoue break; 7087d56d374SYoshinobu Inoue } 7097d56d374SYoshinobu Inoue order[i] = j; 7107d56d374SYoshinobu Inoue } 7117d56d374SYoshinobu Inoue n = i; 7127d56d374SYoshinobu Inoue pp = (u_char **)hp->h_addr_list; 7137d56d374SYoshinobu Inoue for (i = 0; i < n - 1; i++) { 7147d56d374SYoshinobu Inoue for (j = i + 1; j < n; j++) { 7157d56d374SYoshinobu Inoue if (order[i] > order[j]) { 7167d56d374SYoshinobu Inoue ap = pp[i]; 7177d56d374SYoshinobu Inoue pp[i] = pp[j]; 7187d56d374SYoshinobu Inoue pp[j] = ap; 7197d56d374SYoshinobu Inoue t = order[i]; 7207d56d374SYoshinobu Inoue order[i] = order[j]; 7217d56d374SYoshinobu Inoue order[j] = t; 7227d56d374SYoshinobu Inoue } 7237d56d374SYoshinobu Inoue } 7247d56d374SYoshinobu Inoue } 7257d56d374SYoshinobu Inoue return hp; 7267d56d374SYoshinobu Inoue } 7277d56d374SYoshinobu Inoue 7287d56d374SYoshinobu Inoue static char * 7297d56d374SYoshinobu Inoue _hgetword(char **pp) 7307d56d374SYoshinobu Inoue { 7317d56d374SYoshinobu Inoue char c, *p, *ret; 7327d56d374SYoshinobu Inoue const char *sp; 7337d56d374SYoshinobu Inoue static const char sep[] = "# \t\n"; 7347d56d374SYoshinobu Inoue 7357d56d374SYoshinobu Inoue ret = NULL; 7367d56d374SYoshinobu Inoue for (p = *pp; (c = *p) != '\0'; p++) { 7377d56d374SYoshinobu Inoue for (sp = sep; *sp != '\0'; sp++) { 7387d56d374SYoshinobu Inoue if (c == *sp) 7397d56d374SYoshinobu Inoue break; 7407d56d374SYoshinobu Inoue } 7417d56d374SYoshinobu Inoue if (c == '#') 7427d56d374SYoshinobu Inoue p[1] = '\0'; /* ignore rest of line */ 7437d56d374SYoshinobu Inoue if (ret == NULL) { 7447d56d374SYoshinobu Inoue if (*sp == '\0') 7457d56d374SYoshinobu Inoue ret = p; 7467d56d374SYoshinobu Inoue } else { 7477d56d374SYoshinobu Inoue if (*sp != '\0') { 7487d56d374SYoshinobu Inoue *p++ = '\0'; 7497d56d374SYoshinobu Inoue break; 7507d56d374SYoshinobu Inoue } 7517d56d374SYoshinobu Inoue } 7527d56d374SYoshinobu Inoue } 7537d56d374SYoshinobu Inoue *pp = p; 7547d56d374SYoshinobu Inoue if (ret == NULL || *ret == '\0') 7557d56d374SYoshinobu Inoue return NULL; 7567d56d374SYoshinobu Inoue return ret; 7577d56d374SYoshinobu Inoue } 7587d56d374SYoshinobu Inoue 7597d56d374SYoshinobu Inoue /* 7607d56d374SYoshinobu Inoue * FILES (/etc/hosts) 7617d56d374SYoshinobu Inoue */ 7627d56d374SYoshinobu Inoue 7637d56d374SYoshinobu Inoue static FILE * 7647d56d374SYoshinobu Inoue _files_open(int *errp) 7657d56d374SYoshinobu Inoue { 7667d56d374SYoshinobu Inoue FILE *fp; 7677d56d374SYoshinobu Inoue fp = fopen(_PATH_HOSTS, "r"); 7687d56d374SYoshinobu Inoue if (fp == NULL) 7697d56d374SYoshinobu Inoue *errp = NO_RECOVERY; 7707d56d374SYoshinobu Inoue return fp; 7717d56d374SYoshinobu Inoue } 7727d56d374SYoshinobu Inoue 7737d56d374SYoshinobu Inoue static struct hostent * 7747d56d374SYoshinobu Inoue _files_ghbyname(const char *name, int af, int *errp) 7757d56d374SYoshinobu Inoue { 7767d56d374SYoshinobu Inoue int match, nalias; 7777d56d374SYoshinobu Inoue char *p, *line, *addrstr, *cname; 7787d56d374SYoshinobu Inoue FILE *fp; 7797d56d374SYoshinobu Inoue struct hostent *rethp, *hp, hpbuf; 7807d56d374SYoshinobu Inoue char *aliases[MAXALIASES + 1], *addrs[2]; 7817d56d374SYoshinobu Inoue union inx_addr addrbuf; 7827d56d374SYoshinobu Inoue char buf[BUFSIZ]; 783e6f35403SYoshinobu Inoue int af0 = af; 7847d56d374SYoshinobu Inoue 7857d56d374SYoshinobu Inoue if ((fp = _files_open(errp)) == NULL) 7867d56d374SYoshinobu Inoue return NULL; 7877d56d374SYoshinobu Inoue rethp = hp = NULL; 7887d56d374SYoshinobu Inoue 7897d56d374SYoshinobu Inoue while (fgets(buf, sizeof(buf), fp)) { 7907d56d374SYoshinobu Inoue line = buf; 7917d56d374SYoshinobu Inoue if ((addrstr = _hgetword(&line)) == NULL 7927d56d374SYoshinobu Inoue || (cname = _hgetword(&line)) == NULL) 7937d56d374SYoshinobu Inoue continue; 7947d56d374SYoshinobu Inoue match = (strcasecmp(cname, name) == 0); 7957d56d374SYoshinobu Inoue nalias = 0; 7967d56d374SYoshinobu Inoue while ((p = _hgetword(&line)) != NULL) { 7977d56d374SYoshinobu Inoue if (!match) 7987d56d374SYoshinobu Inoue match = (strcasecmp(p, name) == 0); 7997d56d374SYoshinobu Inoue if (nalias < MAXALIASES) 8007d56d374SYoshinobu Inoue aliases[nalias++] = p; 8017d56d374SYoshinobu Inoue } 8027d56d374SYoshinobu Inoue if (!match) 8037d56d374SYoshinobu Inoue continue; 804e6f35403SYoshinobu Inoue switch (af0) { 805e6f35403SYoshinobu Inoue case AF_INET: 806e6f35403SYoshinobu Inoue if (inet_aton(addrstr, (struct in_addr *)&addrbuf) 807e6f35403SYoshinobu Inoue != 1) { 8087d56d374SYoshinobu Inoue *errp = NO_DATA; /* name found */ 8097d56d374SYoshinobu Inoue continue; 8107d56d374SYoshinobu Inoue } 811e6f35403SYoshinobu Inoue af = af0; 812e6f35403SYoshinobu Inoue break; 813e6f35403SYoshinobu Inoue #ifdef INET6 814e6f35403SYoshinobu Inoue case AF_INET6: 815e6f35403SYoshinobu Inoue if (inet_pton(af, addrstr, &addrbuf) != 1) { 816e6f35403SYoshinobu Inoue *errp = NO_DATA; /* name found */ 817e6f35403SYoshinobu Inoue continue; 818e6f35403SYoshinobu Inoue } 819e6f35403SYoshinobu Inoue af = af0; 820e6f35403SYoshinobu Inoue break; 821e6f35403SYoshinobu Inoue #endif 822e6f35403SYoshinobu Inoue case AF_UNSPEC: 823e6f35403SYoshinobu Inoue if (inet_aton(addrstr, (struct in_addr *)&addrbuf) 824e6f35403SYoshinobu Inoue == 1) { 825e6f35403SYoshinobu Inoue af = AF_INET; 826e6f35403SYoshinobu Inoue break; 827e6f35403SYoshinobu Inoue } 828e6f35403SYoshinobu Inoue #ifdef INET6 829e6f35403SYoshinobu Inoue if (inet_pton(AF_INET6, addrstr, &addrbuf) == 1) { 830e6f35403SYoshinobu Inoue af = AF_INET6; 831e6f35403SYoshinobu Inoue break; 832e6f35403SYoshinobu Inoue } 833e6f35403SYoshinobu Inoue #endif 834e6f35403SYoshinobu Inoue *errp = NO_DATA; /* name found */ 835e6f35403SYoshinobu Inoue continue; 836e6f35403SYoshinobu Inoue /* NOTREACHED */ 837e6f35403SYoshinobu Inoue } 8387d56d374SYoshinobu Inoue hp = &hpbuf; 8397d56d374SYoshinobu Inoue hp->h_name = cname; 8407d56d374SYoshinobu Inoue hp->h_aliases = aliases; 8417d56d374SYoshinobu Inoue aliases[nalias] = NULL; 8427d56d374SYoshinobu Inoue hp->h_addrtype = af; 8437d56d374SYoshinobu Inoue hp->h_length = ADDRLEN(af); 8447d56d374SYoshinobu Inoue hp->h_addr_list = addrs; 8457d56d374SYoshinobu Inoue addrs[0] = (char *)&addrbuf; 8467d56d374SYoshinobu Inoue addrs[1] = NULL; 8477d56d374SYoshinobu Inoue hp = _hpcopy(hp, errp); 8487d56d374SYoshinobu Inoue rethp = _hpmerge(rethp, hp, errp); 8497d56d374SYoshinobu Inoue } 8507d56d374SYoshinobu Inoue fclose(fp); 8517d56d374SYoshinobu Inoue return rethp; 8527d56d374SYoshinobu Inoue } 8537d56d374SYoshinobu Inoue 8547d56d374SYoshinobu Inoue static struct hostent * 8557d56d374SYoshinobu Inoue _files_ghbyaddr(const void *addr, int addrlen, int af, int *errp) 8567d56d374SYoshinobu Inoue { 8577d56d374SYoshinobu Inoue int nalias; 8587d56d374SYoshinobu Inoue char *p, *line; 8597d56d374SYoshinobu Inoue FILE *fp; 8607d56d374SYoshinobu Inoue struct hostent *hp, hpbuf; 8617d56d374SYoshinobu Inoue char *aliases[MAXALIASES + 1], *addrs[2]; 8627d56d374SYoshinobu Inoue union inx_addr addrbuf; 8637d56d374SYoshinobu Inoue char buf[BUFSIZ]; 8647d56d374SYoshinobu Inoue 8657d56d374SYoshinobu Inoue if ((fp = _files_open(errp)) == NULL) 8667d56d374SYoshinobu Inoue return NULL; 8677d56d374SYoshinobu Inoue hp = NULL; 8687d56d374SYoshinobu Inoue while (fgets(buf, sizeof(buf), fp)) { 8697d56d374SYoshinobu Inoue line = buf; 8707d56d374SYoshinobu Inoue if ((p = _hgetword(&line)) == NULL 871be26adb5SYoshinobu Inoue || (af == AF_INET 872be26adb5SYoshinobu Inoue ? inet_aton(p, (struct in_addr *)&addrbuf) 873be26adb5SYoshinobu Inoue : inet_pton(af, p, &addrbuf)) != 1 8747d56d374SYoshinobu Inoue || memcmp(addr, &addrbuf, addrlen) != 0 8757d56d374SYoshinobu Inoue || (p = _hgetword(&line)) == NULL) 8767d56d374SYoshinobu Inoue continue; 8777d56d374SYoshinobu Inoue hp = &hpbuf; 8787d56d374SYoshinobu Inoue hp->h_name = p; 8797d56d374SYoshinobu Inoue hp->h_aliases = aliases; 8807d56d374SYoshinobu Inoue nalias = 0; 8817d56d374SYoshinobu Inoue while ((p = _hgetword(&line)) != NULL) { 8827d56d374SYoshinobu Inoue if (nalias < MAXALIASES) 8837d56d374SYoshinobu Inoue aliases[nalias++] = p; 8847d56d374SYoshinobu Inoue } 8857d56d374SYoshinobu Inoue aliases[nalias] = NULL; 8867d56d374SYoshinobu Inoue hp->h_addrtype = af; 8877d56d374SYoshinobu Inoue hp->h_length = addrlen; 8887d56d374SYoshinobu Inoue hp->h_addr_list = addrs; 8897d56d374SYoshinobu Inoue addrs[0] = (char *)&addrbuf; 8907d56d374SYoshinobu Inoue addrs[1] = NULL; 8917d56d374SYoshinobu Inoue hp = _hpcopy(hp, errp); 8927d56d374SYoshinobu Inoue break; 8937d56d374SYoshinobu Inoue } 8947d56d374SYoshinobu Inoue fclose(fp); 8957d56d374SYoshinobu Inoue return hp; 8967d56d374SYoshinobu Inoue } 8977d56d374SYoshinobu Inoue 89863858012SJonathan Lemon /* 89963858012SJonathan Lemon * NIS 90063858012SJonathan Lemon * 90163858012SJonathan Lemon * XXX actually a hack, these are INET4 specific. 90263858012SJonathan Lemon */ 90363858012SJonathan Lemon static struct hostent * 90463858012SJonathan Lemon _nis_ghbyname(const char *name, int af, int *errp) 90563858012SJonathan Lemon { 90638775c5eSJonathan Lemon struct hostent *hp = NULL; 90763858012SJonathan Lemon 908e6f35403SYoshinobu Inoue if (af == AF_UNSPEC) 909e6f35403SYoshinobu Inoue af = AF_INET; 91063858012SJonathan Lemon if (af == AF_INET) { 91163858012SJonathan Lemon hp = _gethostbynisname(name, af); 91263858012SJonathan Lemon if (hp != NULL) 91363858012SJonathan Lemon hp = _hpcopy(hp, errp); 91463858012SJonathan Lemon } 91563858012SJonathan Lemon return (hp); 91663858012SJonathan Lemon 91763858012SJonathan Lemon } 91863858012SJonathan Lemon 91963858012SJonathan Lemon static struct hostent * 92063858012SJonathan Lemon _nis_ghbyaddr(const void *addr, int addrlen, int af, int *errp) 92163858012SJonathan Lemon { 92263858012SJonathan Lemon struct hostent *hp = NULL; 92363858012SJonathan Lemon 92463858012SJonathan Lemon if (af == AF_INET) { 92563858012SJonathan Lemon hp = _gethostbynisaddr(addr, addrlen, af); 92663858012SJonathan Lemon if (hp != NULL) 92763858012SJonathan Lemon hp = _hpcopy(hp, errp); 92863858012SJonathan Lemon } 92963858012SJonathan Lemon return (hp); 93063858012SJonathan Lemon } 93163858012SJonathan Lemon 9327d56d374SYoshinobu Inoue #ifdef DEBUG 9337d56d374SYoshinobu Inoue #define DNS_ASSERT(X) if (!(X)) { fprintf(stderr, "ASSFAIL: %s %d: %s\n", __FILE__, __LINE__, #X); goto badanswer; } 9347d56d374SYoshinobu Inoue #else 9357d56d374SYoshinobu Inoue #define DNS_ASSERT(X) if (!(X)) { goto badanswer; } 9367d56d374SYoshinobu Inoue #endif 9377d56d374SYoshinobu Inoue 938e6f35403SYoshinobu Inoue struct __res_type_list { 939e6f35403SYoshinobu Inoue SLIST_ENTRY(__res_type_list) rtl_entry; 940e6f35403SYoshinobu Inoue int rtl_type; 941e6f35403SYoshinobu Inoue }; 942e6f35403SYoshinobu Inoue 9437d56d374SYoshinobu Inoue static struct hostent * 944e6f35403SYoshinobu Inoue _gethpbyanswer(answer, anslen, qtype, errp) 945e6f35403SYoshinobu Inoue const u_char *answer; 946e6f35403SYoshinobu Inoue int anslen; 947e6f35403SYoshinobu Inoue int qtype; 948e6f35403SYoshinobu Inoue int *errp; 9497d56d374SYoshinobu Inoue { 9507d56d374SYoshinobu Inoue int n; 9517d56d374SYoshinobu Inoue char tbuf[MAXDNAME+1]; 9527d56d374SYoshinobu Inoue HEADER *hp; 953e6f35403SYoshinobu Inoue const u_char *cp, *eom; 9547d56d374SYoshinobu Inoue int type, class, ancount, qdcount; 9557d56d374SYoshinobu Inoue u_long ttl; 9567d56d374SYoshinobu Inoue char hostbuf[BUFSIZ]; 9577d56d374SYoshinobu Inoue char *bp; 9587d56d374SYoshinobu Inoue char *alist[MAXALIASES]; 9597d56d374SYoshinobu Inoue char *hlist[MAXADDRS]; 9607d56d374SYoshinobu Inoue struct hostent hbuf; 9617d56d374SYoshinobu Inoue int buflen; 9627d56d374SYoshinobu Inoue int na, nh; 9637d56d374SYoshinobu Inoue 9647d56d374SYoshinobu Inoue hbuf.h_aliases = alist; 965e6f35403SYoshinobu Inoue hbuf.h_addrtype = 966e6f35403SYoshinobu Inoue #ifdef INET6 967e6f35403SYoshinobu Inoue (qtype == T_AAAA) ? AF_INET6 : 968e6f35403SYoshinobu Inoue #endif 969e6f35403SYoshinobu Inoue AF_INET; 970e6f35403SYoshinobu Inoue hbuf.h_length = ADDRLEN(hbuf.h_addrtype); 9717d56d374SYoshinobu Inoue hbuf.h_addr_list = hlist; 9727d56d374SYoshinobu Inoue na = nh = 0; 9737d56d374SYoshinobu Inoue hp = (HEADER *)answer; 974e6f35403SYoshinobu Inoue eom = answer + anslen; 9757d56d374SYoshinobu Inoue ancount = ntohs(hp->ancount); 9767d56d374SYoshinobu Inoue qdcount = ntohs(hp->qdcount); 9777d56d374SYoshinobu Inoue DNS_ASSERT(qdcount == 1); 9787d56d374SYoshinobu Inoue cp = answer + sizeof(HEADER); 9797d56d374SYoshinobu Inoue bp = hostbuf; 9807d56d374SYoshinobu Inoue buflen = sizeof(hostbuf); 9817d56d374SYoshinobu Inoue 9827d56d374SYoshinobu Inoue n = dn_expand(answer, eom, cp, bp, buflen); 9837d56d374SYoshinobu Inoue DNS_ASSERT(n >= 0); 9847d56d374SYoshinobu Inoue cp += n + QFIXEDSZ; 9857d56d374SYoshinobu Inoue hbuf.h_name = bp; 9867d56d374SYoshinobu Inoue n = strlen(bp) + 1; 9877d56d374SYoshinobu Inoue bp += n; 9887d56d374SYoshinobu Inoue buflen -= n; 9897d56d374SYoshinobu Inoue while (ancount-- > 0 && cp < eom) { 9907d56d374SYoshinobu Inoue n = dn_expand(answer, eom, cp, bp, buflen); 9917d56d374SYoshinobu Inoue DNS_ASSERT(n >= 0); 9927d56d374SYoshinobu Inoue cp += n; /* name */ 9937d56d374SYoshinobu Inoue type = _getshort(cp); 9947d56d374SYoshinobu Inoue cp += 2; /* type */ 9957d56d374SYoshinobu Inoue class = _getshort(cp); 9967d56d374SYoshinobu Inoue cp += 2; /* class */ 9977d56d374SYoshinobu Inoue ttl = _getlong(cp); 9987d56d374SYoshinobu Inoue cp += 4; /* ttl */ 9997d56d374SYoshinobu Inoue n = _getshort(cp); 10007d56d374SYoshinobu Inoue cp += 2; /* len */ 10017d56d374SYoshinobu Inoue DNS_ASSERT(class == C_IN); 10027d56d374SYoshinobu Inoue switch (type) { 10037d56d374SYoshinobu Inoue case T_CNAME: 10047d56d374SYoshinobu Inoue if (na >= MAXALIASES-1) { 10057d56d374SYoshinobu Inoue cp += n; 10067d56d374SYoshinobu Inoue break; 10077d56d374SYoshinobu Inoue } 10087d56d374SYoshinobu Inoue n = dn_expand(answer, eom, cp, tbuf, sizeof(tbuf)); 10097d56d374SYoshinobu Inoue DNS_ASSERT(n >= 0); 10107d56d374SYoshinobu Inoue cp += n; 10117d56d374SYoshinobu Inoue /* alias */ 10127d56d374SYoshinobu Inoue alist[na++] = bp; 10137d56d374SYoshinobu Inoue n = strlen(bp) + 1; 10147d56d374SYoshinobu Inoue bp += n; 10157d56d374SYoshinobu Inoue buflen -= n; 10167d56d374SYoshinobu Inoue /* canon */ 10177d56d374SYoshinobu Inoue n = strlen(tbuf) + 1; 10187d56d374SYoshinobu Inoue DNS_ASSERT(n < buflen); 10197d56d374SYoshinobu Inoue strcpy(bp, tbuf); 10207d56d374SYoshinobu Inoue hbuf.h_name = bp; 10217d56d374SYoshinobu Inoue bp += n; 10227d56d374SYoshinobu Inoue buflen -= n; 10237d56d374SYoshinobu Inoue break; 10247d56d374SYoshinobu Inoue case T_A: 10257d56d374SYoshinobu Inoue #ifdef INET6 10267d56d374SYoshinobu Inoue case T_AAAA: 10277d56d374SYoshinobu Inoue #endif 10287d56d374SYoshinobu Inoue DNS_ASSERT(type == qtype); 10297d56d374SYoshinobu Inoue bp = (char *)ALIGN(bp); 10307d56d374SYoshinobu Inoue DNS_ASSERT(n == hbuf.h_length); 10317d56d374SYoshinobu Inoue DNS_ASSERT(n < buflen); 10327d56d374SYoshinobu Inoue if (nh < MAXADDRS-1) { 10337d56d374SYoshinobu Inoue hlist[nh++] = bp; 10347d56d374SYoshinobu Inoue memcpy(bp, cp, n); 10357d56d374SYoshinobu Inoue bp += n; 10367d56d374SYoshinobu Inoue buflen -= n; 10377d56d374SYoshinobu Inoue } 10387d56d374SYoshinobu Inoue cp += n; 10397d56d374SYoshinobu Inoue break; 10407d56d374SYoshinobu Inoue default: 10417d56d374SYoshinobu Inoue DNS_ASSERT(0); 10427d56d374SYoshinobu Inoue cp += n; 10437d56d374SYoshinobu Inoue break; 10447d56d374SYoshinobu Inoue } 10457d56d374SYoshinobu Inoue } 10467d56d374SYoshinobu Inoue if (nh == 0) { 10477d56d374SYoshinobu Inoue badanswer: 10487d56d374SYoshinobu Inoue *errp = NO_RECOVERY; 10497d56d374SYoshinobu Inoue return NULL; 10507d56d374SYoshinobu Inoue } 10517d56d374SYoshinobu Inoue alist[na] = NULL; 10527d56d374SYoshinobu Inoue hlist[nh] = NULL; 10537d56d374SYoshinobu Inoue return _hpcopy(&hbuf, errp); 10547d56d374SYoshinobu Inoue } 10557d56d374SYoshinobu Inoue 1056e6f35403SYoshinobu Inoue /* res_search() variant with multiple query support. */ 1057e6f35403SYoshinobu Inoue static struct hostent * 1058e6f35403SYoshinobu Inoue _res_search_multi(name, rtl, errp) 1059e6f35403SYoshinobu Inoue const char *name; /* domain name */ 1060e6f35403SYoshinobu Inoue struct __res_type_list *rtl; /* list of query types */ 1061e6f35403SYoshinobu Inoue int *errp; 1062e6f35403SYoshinobu Inoue { 1063e6f35403SYoshinobu Inoue u_char answer[BUFSIZ]; /* buffer to put answer */ 1064e6f35403SYoshinobu Inoue const char *cp, * const *domain; 1065e6f35403SYoshinobu Inoue struct hostent *hp0 = NULL, *hp; 1066e6f35403SYoshinobu Inoue u_int dots; 1067e6f35403SYoshinobu Inoue int trailing_dot, ret, saved_herrno; 1068e6f35403SYoshinobu Inoue int got_nodata = 0, got_servfail = 0, tried_as_is = 0; 1069e6f35403SYoshinobu Inoue struct __res_type_list *rtl0 = rtl; 1070e6f35403SYoshinobu Inoue 1071e6f35403SYoshinobu Inoue if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 1072e6f35403SYoshinobu Inoue *errp = NETDB_INTERNAL; 1073e6f35403SYoshinobu Inoue return (NULL); 1074e6f35403SYoshinobu Inoue } 1075e6f35403SYoshinobu Inoue dots = 0; 1076e6f35403SYoshinobu Inoue for (cp = name; *cp; cp++) 1077e6f35403SYoshinobu Inoue dots += (*cp == '.'); 1078e6f35403SYoshinobu Inoue trailing_dot = 0; 1079e6f35403SYoshinobu Inoue if (cp > name && *--cp == '.') 1080e6f35403SYoshinobu Inoue trailing_dot++; 1081e6f35403SYoshinobu Inoue 1082e6f35403SYoshinobu Inoue /* If there aren't any dots, it could be a user-level alias */ 1083e6f35403SYoshinobu Inoue if (!dots && (cp = hostalias(name)) != NULL) { 1084e6f35403SYoshinobu Inoue for(rtl = rtl0; rtl != NULL; 1085e6f35403SYoshinobu Inoue rtl = SLIST_NEXT(rtl, rtl_entry)) { 1086e6f35403SYoshinobu Inoue ret = res_query(cp, C_IN, rtl->rtl_type, answer, 1087e6f35403SYoshinobu Inoue sizeof(answer)); 1088e6f35403SYoshinobu Inoue if (ret > 0) { 1089e6f35403SYoshinobu Inoue hp = _gethpbyanswer(answer, ret, rtl->rtl_type, 1090e6f35403SYoshinobu Inoue errp); 1091e6f35403SYoshinobu Inoue hp0 = _hpmerge(hp0, hp, errp); 1092e6f35403SYoshinobu Inoue } 1093e6f35403SYoshinobu Inoue } 1094e6f35403SYoshinobu Inoue return (hp0); 1095e6f35403SYoshinobu Inoue } 1096e6f35403SYoshinobu Inoue 1097e6f35403SYoshinobu Inoue /* 1098e6f35403SYoshinobu Inoue * If there are dots in the name already, let's just give it a try 1099e6f35403SYoshinobu Inoue * 'as is'. The threshold can be set with the "ndots" option. 1100e6f35403SYoshinobu Inoue */ 1101e6f35403SYoshinobu Inoue saved_herrno = -1; 1102e6f35403SYoshinobu Inoue if (dots >= _res.ndots) { 1103e6f35403SYoshinobu Inoue for(rtl = rtl0; rtl != NULL; 1104e6f35403SYoshinobu Inoue rtl = SLIST_NEXT(rtl, rtl_entry)) { 1105e6f35403SYoshinobu Inoue ret = res_querydomain(name, NULL, C_IN, rtl->rtl_type, 1106e6f35403SYoshinobu Inoue answer, sizeof(answer)); 1107e6f35403SYoshinobu Inoue if (ret > 0) { 1108e6f35403SYoshinobu Inoue hp = _gethpbyanswer(answer, ret, rtl->rtl_type, 1109e6f35403SYoshinobu Inoue errp); 1110e6f35403SYoshinobu Inoue hp0 = _hpmerge(hp0, hp, errp); 1111e6f35403SYoshinobu Inoue } 1112e6f35403SYoshinobu Inoue } 1113e6f35403SYoshinobu Inoue if (hp0 != NULL) 1114e6f35403SYoshinobu Inoue return (hp0); 1115e6f35403SYoshinobu Inoue saved_herrno = *errp; 1116e6f35403SYoshinobu Inoue tried_as_is++; 1117e6f35403SYoshinobu Inoue } 1118e6f35403SYoshinobu Inoue 1119e6f35403SYoshinobu Inoue /* 1120e6f35403SYoshinobu Inoue * We do at least one level of search if 1121e6f35403SYoshinobu Inoue * - there is no dot and RES_DEFNAME is set, or 1122e6f35403SYoshinobu Inoue * - there is at least one dot, there is no trailing dot, 1123e6f35403SYoshinobu Inoue * and RES_DNSRCH is set. 1124e6f35403SYoshinobu Inoue */ 1125e6f35403SYoshinobu Inoue if ((!dots && (_res.options & RES_DEFNAMES)) || 1126e6f35403SYoshinobu Inoue (dots && !trailing_dot && (_res.options & RES_DNSRCH))) { 1127e6f35403SYoshinobu Inoue int done = 0; 1128e6f35403SYoshinobu Inoue 1129e6f35403SYoshinobu Inoue for (domain = (const char * const *)_res.dnsrch; 1130e6f35403SYoshinobu Inoue *domain && !done; 1131e6f35403SYoshinobu Inoue domain++) { 1132e6f35403SYoshinobu Inoue 1133e6f35403SYoshinobu Inoue for(rtl = rtl0; rtl != NULL; 1134e6f35403SYoshinobu Inoue rtl = SLIST_NEXT(rtl, rtl_entry)) { 1135e6f35403SYoshinobu Inoue ret = res_querydomain(name, *domain, C_IN, 1136e6f35403SYoshinobu Inoue rtl->rtl_type, 1137e6f35403SYoshinobu Inoue answer, sizeof(answer)); 1138e6f35403SYoshinobu Inoue if (ret > 0) { 1139e6f35403SYoshinobu Inoue hp = _gethpbyanswer(answer, ret, 1140e6f35403SYoshinobu Inoue rtl->rtl_type, 1141e6f35403SYoshinobu Inoue errp); 1142e6f35403SYoshinobu Inoue hp0 = _hpmerge(hp0, hp, errp); 1143e6f35403SYoshinobu Inoue } 1144e6f35403SYoshinobu Inoue } 1145e6f35403SYoshinobu Inoue if (hp0 != NULL) 1146e6f35403SYoshinobu Inoue return (hp0); 1147e6f35403SYoshinobu Inoue 1148e6f35403SYoshinobu Inoue /* 1149e6f35403SYoshinobu Inoue * If no server present, give up. 1150e6f35403SYoshinobu Inoue * If name isn't found in this domain, 1151e6f35403SYoshinobu Inoue * keep trying higher domains in the search list 1152e6f35403SYoshinobu Inoue * (if that's enabled). 1153e6f35403SYoshinobu Inoue * On a NO_DATA error, keep trying, otherwise 1154e6f35403SYoshinobu Inoue * a wildcard entry of another type could keep us 1155e6f35403SYoshinobu Inoue * from finding this entry higher in the domain. 1156e6f35403SYoshinobu Inoue * If we get some other error (negative answer or 1157e6f35403SYoshinobu Inoue * server failure), then stop searching up, 1158e6f35403SYoshinobu Inoue * but try the input name below in case it's 1159e6f35403SYoshinobu Inoue * fully-qualified. 1160e6f35403SYoshinobu Inoue */ 1161e6f35403SYoshinobu Inoue if (errno == ECONNREFUSED) { 1162e6f35403SYoshinobu Inoue *errp = TRY_AGAIN; 1163e6f35403SYoshinobu Inoue return (NULL); 1164e6f35403SYoshinobu Inoue } 1165e6f35403SYoshinobu Inoue 1166e6f35403SYoshinobu Inoue switch (*errp) { 1167e6f35403SYoshinobu Inoue case NO_DATA: 1168e6f35403SYoshinobu Inoue got_nodata++; 1169e6f35403SYoshinobu Inoue /* FALLTHROUGH */ 1170e6f35403SYoshinobu Inoue case HOST_NOT_FOUND: 1171e6f35403SYoshinobu Inoue /* keep trying */ 1172e6f35403SYoshinobu Inoue break; 1173e6f35403SYoshinobu Inoue case TRY_AGAIN: 1174e6f35403SYoshinobu Inoue if (((HEADER *)answer)->rcode == SERVFAIL) { 1175e6f35403SYoshinobu Inoue /* try next search element, if any */ 1176e6f35403SYoshinobu Inoue got_servfail++; 1177e6f35403SYoshinobu Inoue break; 1178e6f35403SYoshinobu Inoue } 1179e6f35403SYoshinobu Inoue /* FALLTHROUGH */ 1180e6f35403SYoshinobu Inoue default: 1181e6f35403SYoshinobu Inoue /* anything else implies that we're done */ 1182e6f35403SYoshinobu Inoue done++; 1183e6f35403SYoshinobu Inoue } 1184e6f35403SYoshinobu Inoue 1185e6f35403SYoshinobu Inoue /* if we got here for some reason other than DNSRCH, 1186e6f35403SYoshinobu Inoue * we only wanted one iteration of the loop, so stop. 1187e6f35403SYoshinobu Inoue */ 1188e6f35403SYoshinobu Inoue if (!(_res.options & RES_DNSRCH)) 1189e6f35403SYoshinobu Inoue done++; 1190e6f35403SYoshinobu Inoue } 1191e6f35403SYoshinobu Inoue } 1192e6f35403SYoshinobu Inoue 1193e6f35403SYoshinobu Inoue /* 1194e6f35403SYoshinobu Inoue * If we have not already tried the name "as is", do that now. 1195e6f35403SYoshinobu Inoue * note that we do this regardless of how many dots were in the 1196e6f35403SYoshinobu Inoue * name or whether it ends with a dot unless NOTLDQUERY is set. 1197e6f35403SYoshinobu Inoue */ 1198e6f35403SYoshinobu Inoue if (!tried_as_is && (dots || !(_res.options & RES_NOTLDQUERY))) { 1199e6f35403SYoshinobu Inoue for(rtl = rtl0; rtl != NULL; 1200e6f35403SYoshinobu Inoue rtl = SLIST_NEXT(rtl, rtl_entry)) { 1201e6f35403SYoshinobu Inoue ret = res_querydomain(name, NULL, C_IN, rtl->rtl_type, 1202e6f35403SYoshinobu Inoue answer, sizeof(answer)); 1203e6f35403SYoshinobu Inoue if (ret > 0) { 1204e6f35403SYoshinobu Inoue hp = _gethpbyanswer(answer, ret, rtl->rtl_type, 1205e6f35403SYoshinobu Inoue errp); 1206e6f35403SYoshinobu Inoue hp0 = _hpmerge(hp0, hp, errp); 1207e6f35403SYoshinobu Inoue } 1208e6f35403SYoshinobu Inoue } 1209e6f35403SYoshinobu Inoue if (hp0 != NULL) 1210e6f35403SYoshinobu Inoue return (hp0); 1211e6f35403SYoshinobu Inoue } 1212e6f35403SYoshinobu Inoue 1213e6f35403SYoshinobu Inoue /* if we got here, we didn't satisfy the search. 1214e6f35403SYoshinobu Inoue * if we did an initial full query, return that query's h_errno 1215e6f35403SYoshinobu Inoue * (note that we wouldn't be here if that query had succeeded). 1216e6f35403SYoshinobu Inoue * else if we ever got a nodata, send that back as the reason. 1217e6f35403SYoshinobu Inoue * else send back meaningless h_errno, that being the one from 1218e6f35403SYoshinobu Inoue * the last DNSRCH we did. 1219e6f35403SYoshinobu Inoue */ 1220e6f35403SYoshinobu Inoue if (saved_herrno != -1) 1221e6f35403SYoshinobu Inoue *errp = saved_herrno; 1222e6f35403SYoshinobu Inoue else if (got_nodata) 1223e6f35403SYoshinobu Inoue *errp = NO_DATA; 1224e6f35403SYoshinobu Inoue else if (got_servfail) 1225e6f35403SYoshinobu Inoue *errp = TRY_AGAIN; 1226e6f35403SYoshinobu Inoue return (NULL); 1227e6f35403SYoshinobu Inoue } 1228e6f35403SYoshinobu Inoue 1229e6f35403SYoshinobu Inoue static struct hostent * 1230e6f35403SYoshinobu Inoue _dns_ghbyname(const char *name, int af, int *errp) 1231e6f35403SYoshinobu Inoue { 1232e6f35403SYoshinobu Inoue struct __res_type_list *rtl, rtl4; 1233e6f35403SYoshinobu Inoue #ifdef INET6 1234e6f35403SYoshinobu Inoue struct __res_type_list rtl6; 1235e6f35403SYoshinobu Inoue #endif 1236e6f35403SYoshinobu Inoue 1237e6f35403SYoshinobu Inoue #ifdef INET6 1238e6f35403SYoshinobu Inoue switch (af) { 1239e6f35403SYoshinobu Inoue case AF_UNSPEC: 1240e6f35403SYoshinobu Inoue SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A; 1241e6f35403SYoshinobu Inoue SLIST_NEXT(&rtl6, rtl_entry) = &rtl4; rtl6.rtl_type = T_AAAA; 1242e6f35403SYoshinobu Inoue rtl = &rtl6; 1243e6f35403SYoshinobu Inoue break; 1244e6f35403SYoshinobu Inoue case AF_INET6: 1245e6f35403SYoshinobu Inoue SLIST_NEXT(&rtl6, rtl_entry) = NULL; rtl6.rtl_type = T_AAAA; 1246e6f35403SYoshinobu Inoue rtl = &rtl6; 1247e6f35403SYoshinobu Inoue break; 1248e6f35403SYoshinobu Inoue case AF_INET: 1249e6f35403SYoshinobu Inoue SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A; 1250e6f35403SYoshinobu Inoue rtl = &rtl4; 1251e6f35403SYoshinobu Inoue break; 1252e6f35403SYoshinobu Inoue } 1253e6f35403SYoshinobu Inoue #else 1254e6f35403SYoshinobu Inoue SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A; 1255e6f35403SYoshinobu Inoue rtl = &rtl4; 1256e6f35403SYoshinobu Inoue #endif 1257e6f35403SYoshinobu Inoue return(_res_search_multi(name, rtl, errp)); 1258e6f35403SYoshinobu Inoue } 1259e6f35403SYoshinobu Inoue 12607d56d374SYoshinobu Inoue static struct hostent * 12617d56d374SYoshinobu Inoue _dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp) 12627d56d374SYoshinobu Inoue { 12637d56d374SYoshinobu Inoue int n; 12647d56d374SYoshinobu Inoue u_char answer[BUFSIZ]; 12657d56d374SYoshinobu Inoue HEADER *hp; 12667d56d374SYoshinobu Inoue u_char c, *cp, *eom; 12677d56d374SYoshinobu Inoue int type, class, ancount, qdcount; 12687d56d374SYoshinobu Inoue u_long ttl; 12697d56d374SYoshinobu Inoue char hostbuf[BUFSIZ]; 12707d56d374SYoshinobu Inoue char *bp; 12717d56d374SYoshinobu Inoue char *alist[MAXALIASES]; 12727d56d374SYoshinobu Inoue char *hlist[2]; 12737d56d374SYoshinobu Inoue struct hostent hbuf; 12747d56d374SYoshinobu Inoue int buflen; 12757d56d374SYoshinobu Inoue int na; 12767d56d374SYoshinobu Inoue #ifdef INET6 12777d56d374SYoshinobu Inoue static const char hex[] = "0123456789abcdef"; 12787d56d374SYoshinobu Inoue #endif 12797d56d374SYoshinobu Inoue 12807d56d374SYoshinobu Inoue #ifdef INET6 12817d56d374SYoshinobu Inoue /* XXX */ 12827d56d374SYoshinobu Inoue if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr)) 12837d56d374SYoshinobu Inoue return NULL; 12847d56d374SYoshinobu Inoue #endif 12857d56d374SYoshinobu Inoue 12867d56d374SYoshinobu Inoue if ((_res.options & RES_INIT) == 0) { 12877d56d374SYoshinobu Inoue if (res_init() < 0) { 12887d56d374SYoshinobu Inoue *errp = h_errno; 12897d56d374SYoshinobu Inoue return NULL; 12907d56d374SYoshinobu Inoue } 12917d56d374SYoshinobu Inoue } 12927d56d374SYoshinobu Inoue hbuf.h_name = NULL; 12937d56d374SYoshinobu Inoue hbuf.h_aliases = alist; 12947d56d374SYoshinobu Inoue hbuf.h_addrtype = af; 12957d56d374SYoshinobu Inoue hbuf.h_length = addrlen; 12967d56d374SYoshinobu Inoue hbuf.h_addr_list = hlist; 12977d56d374SYoshinobu Inoue hlist[0] = (char *)addr; 12987d56d374SYoshinobu Inoue hlist[1] = NULL; 12997d56d374SYoshinobu Inoue na = 0; 13007d56d374SYoshinobu Inoue 13017d56d374SYoshinobu Inoue n = 0; 13027d56d374SYoshinobu Inoue bp = hostbuf; 13037d56d374SYoshinobu Inoue cp = (u_char *)addr+addrlen-1; 13047d56d374SYoshinobu Inoue switch (af) { 13057d56d374SYoshinobu Inoue #ifdef INET6 13067d56d374SYoshinobu Inoue case AF_INET6: 13077d56d374SYoshinobu Inoue for (; n < addrlen; n++, cp--) { 13087d56d374SYoshinobu Inoue c = *cp; 13097d56d374SYoshinobu Inoue *bp++ = hex[c & 0xf]; 13107d56d374SYoshinobu Inoue *bp++ = '.'; 13117d56d374SYoshinobu Inoue *bp++ = hex[c >> 4]; 13127d56d374SYoshinobu Inoue *bp++ = '.'; 13137d56d374SYoshinobu Inoue } 13147d56d374SYoshinobu Inoue strcpy(bp, "ip6.int"); 13157d56d374SYoshinobu Inoue break; 13167d56d374SYoshinobu Inoue #endif 13177d56d374SYoshinobu Inoue default: 13187d56d374SYoshinobu Inoue for (; n < addrlen; n++, cp--) { 13197d56d374SYoshinobu Inoue c = *cp; 13207d56d374SYoshinobu Inoue if (c >= 100) 13217d56d374SYoshinobu Inoue *bp++ = '0' + c / 100; 13227d56d374SYoshinobu Inoue if (c >= 10) 13237d56d374SYoshinobu Inoue *bp++ = '0' + (c % 100) / 10; 13247d56d374SYoshinobu Inoue *bp++ = '0' + c % 10; 13257d56d374SYoshinobu Inoue *bp++ = '.'; 13267d56d374SYoshinobu Inoue } 13277d56d374SYoshinobu Inoue strcpy(bp, "in-addr.arpa"); 13287d56d374SYoshinobu Inoue break; 13297d56d374SYoshinobu Inoue } 13307d56d374SYoshinobu Inoue 13317d56d374SYoshinobu Inoue n = res_query(hostbuf, C_IN, T_PTR, answer, sizeof(answer)); 13327d56d374SYoshinobu Inoue if (n < 0) { 13337d56d374SYoshinobu Inoue *errp = h_errno; 13347d56d374SYoshinobu Inoue return NULL; 13357d56d374SYoshinobu Inoue } 13367d56d374SYoshinobu Inoue hp = (HEADER *)answer; 13377d56d374SYoshinobu Inoue eom = answer + n; 13387d56d374SYoshinobu Inoue ancount = ntohs(hp->ancount); 13397d56d374SYoshinobu Inoue qdcount = ntohs(hp->qdcount); 13407d56d374SYoshinobu Inoue DNS_ASSERT(qdcount == 1); 13417d56d374SYoshinobu Inoue cp = answer + sizeof(HEADER); 13427d56d374SYoshinobu Inoue bp = hostbuf; 13437d56d374SYoshinobu Inoue buflen = sizeof(hostbuf); 13447d56d374SYoshinobu Inoue 13457d56d374SYoshinobu Inoue n = dn_expand(answer, eom, cp, bp, buflen); 13467d56d374SYoshinobu Inoue DNS_ASSERT(n >= 0); 13477d56d374SYoshinobu Inoue cp += n + QFIXEDSZ; 13487d56d374SYoshinobu Inoue while (ancount-- > 0 && cp < eom) { 13497d56d374SYoshinobu Inoue n = dn_expand(answer, eom, cp, bp, buflen); 13507d56d374SYoshinobu Inoue DNS_ASSERT(n >= 0); 13517d56d374SYoshinobu Inoue cp += n; /* name */ 13527d56d374SYoshinobu Inoue type = _getshort(cp); 13537d56d374SYoshinobu Inoue cp += 2; /* type */ 13547d56d374SYoshinobu Inoue class = _getshort(cp); 13557d56d374SYoshinobu Inoue cp += 2; /* class */ 13567d56d374SYoshinobu Inoue ttl = _getlong(cp); 13577d56d374SYoshinobu Inoue cp += 4; /* ttl */ 13587d56d374SYoshinobu Inoue n = _getshort(cp); 13597d56d374SYoshinobu Inoue cp += 2; /* len */ 13607d56d374SYoshinobu Inoue DNS_ASSERT(class == C_IN); 13617d56d374SYoshinobu Inoue switch (type) { 13627d56d374SYoshinobu Inoue case T_PTR: 13637d56d374SYoshinobu Inoue n = dn_expand(answer, eom, cp, bp, buflen); 13647d56d374SYoshinobu Inoue DNS_ASSERT(n >= 0); 13657d56d374SYoshinobu Inoue cp += n; 13667d56d374SYoshinobu Inoue if (na >= MAXALIASES-1) 13677d56d374SYoshinobu Inoue break; 13687d56d374SYoshinobu Inoue if (hbuf.h_name == NULL) 13697d56d374SYoshinobu Inoue hbuf.h_name = bp; 13707d56d374SYoshinobu Inoue else 13717d56d374SYoshinobu Inoue alist[na++] = bp; 13727d56d374SYoshinobu Inoue n = strlen(bp) + 1; 13737d56d374SYoshinobu Inoue bp += n; 13747d56d374SYoshinobu Inoue buflen -= n; 13757d56d374SYoshinobu Inoue break; 13767d56d374SYoshinobu Inoue case T_CNAME: 13777d56d374SYoshinobu Inoue cp += n; 13787d56d374SYoshinobu Inoue break; 13797d56d374SYoshinobu Inoue default: 13807d56d374SYoshinobu Inoue badanswer: 13817d56d374SYoshinobu Inoue *errp = NO_RECOVERY; 13827d56d374SYoshinobu Inoue return NULL; 13837d56d374SYoshinobu Inoue } 13847d56d374SYoshinobu Inoue } 13857d56d374SYoshinobu Inoue if (hbuf.h_name == NULL) { 13867d56d374SYoshinobu Inoue *errp = h_errno; 13877d56d374SYoshinobu Inoue return NULL; 13887d56d374SYoshinobu Inoue } 13897d56d374SYoshinobu Inoue alist[na] = NULL; 13907d56d374SYoshinobu Inoue return _hpcopy(&hbuf, errp); 13917d56d374SYoshinobu Inoue } 13927d56d374SYoshinobu Inoue 13937d56d374SYoshinobu Inoue #ifdef ICMPNL 13947d56d374SYoshinobu Inoue 13957d56d374SYoshinobu Inoue /* 13967d56d374SYoshinobu Inoue * experimental: 13977d56d374SYoshinobu Inoue * draft-ietf-ipngwg-icmp-namelookups-02.txt 13987d56d374SYoshinobu Inoue * ifindex is assumed to be encoded in addr. 13997d56d374SYoshinobu Inoue */ 14007d56d374SYoshinobu Inoue #include <sys/uio.h> 14017d56d374SYoshinobu Inoue #include <netinet/ip6.h> 14027d56d374SYoshinobu Inoue #include <netinet/icmp6.h> 14037d56d374SYoshinobu Inoue 14047d56d374SYoshinobu Inoue struct _icmp_host_cache { 14057d56d374SYoshinobu Inoue struct _icmp_host_cache *hc_next; 14067d56d374SYoshinobu Inoue int hc_ifindex; 14077d56d374SYoshinobu Inoue struct in6_addr hc_addr; 14087d56d374SYoshinobu Inoue char *hc_name; 14097d56d374SYoshinobu Inoue }; 14107d56d374SYoshinobu Inoue 14117d56d374SYoshinobu Inoue static char * 14127d56d374SYoshinobu Inoue _icmp_fqdn_query(const struct in6_addr *addr, int ifindex) 14137d56d374SYoshinobu Inoue { 14147d56d374SYoshinobu Inoue int s; 14157d56d374SYoshinobu Inoue struct icmp6_filter filter; 14167d56d374SYoshinobu Inoue struct msghdr msg; 14177d56d374SYoshinobu Inoue struct cmsghdr *cmsg; 14187d56d374SYoshinobu Inoue struct in6_pktinfo *pkt; 14197d56d374SYoshinobu Inoue char cbuf[256]; 14207d56d374SYoshinobu Inoue char buf[1024]; 14217d56d374SYoshinobu Inoue int cc; 14227d56d374SYoshinobu Inoue struct icmp6_fqdn_query *fq; 14237d56d374SYoshinobu Inoue struct icmp6_fqdn_reply *fr; 14247d56d374SYoshinobu Inoue struct _icmp_host_cache *hc; 14257d56d374SYoshinobu Inoue struct sockaddr_in6 sin6; 14267d56d374SYoshinobu Inoue struct iovec iov; 14277d56d374SYoshinobu Inoue fd_set s_fds, fds; 14287d56d374SYoshinobu Inoue struct timeval tout; 14297d56d374SYoshinobu Inoue int len; 14307d56d374SYoshinobu Inoue char *name; 14317d56d374SYoshinobu Inoue static int pid; 14327d56d374SYoshinobu Inoue static struct _icmp_host_cache *hc_head; 14337d56d374SYoshinobu Inoue 14347d56d374SYoshinobu Inoue for (hc = hc_head; hc; hc = hc->hc_next) { 14357d56d374SYoshinobu Inoue if (hc->hc_ifindex == ifindex 14367d56d374SYoshinobu Inoue && IN6_ARE_ADDR_EQUAL(&hc->hc_addr, addr)) 14377d56d374SYoshinobu Inoue return hc->hc_name; 14387d56d374SYoshinobu Inoue } 14397d56d374SYoshinobu Inoue 14407d56d374SYoshinobu Inoue if (pid == 0) 14417d56d374SYoshinobu Inoue pid = getpid(); 14427d56d374SYoshinobu Inoue 14437d56d374SYoshinobu Inoue ICMP6_FILTER_SETBLOCKALL(&filter); 14447d56d374SYoshinobu Inoue ICMP6_FILTER_SETPASS(ICMP6_FQDN_REPLY, &filter); 14457d56d374SYoshinobu Inoue 14467d56d374SYoshinobu Inoue FD_ZERO(&s_fds); 14477d56d374SYoshinobu Inoue tout.tv_sec = 0; 14487d56d374SYoshinobu Inoue tout.tv_usec = 200000; /*XXX: 200ms*/ 14497d56d374SYoshinobu Inoue 14507d56d374SYoshinobu Inoue fq = (struct icmp6_fqdn_query *)buf; 14517d56d374SYoshinobu Inoue fq->icmp6_fqdn_type = ICMP6_FQDN_QUERY; 14527d56d374SYoshinobu Inoue fq->icmp6_fqdn_code = 0; 14537d56d374SYoshinobu Inoue fq->icmp6_fqdn_cksum = 0; 14547d56d374SYoshinobu Inoue fq->icmp6_fqdn_id = (u_short)pid; 14557d56d374SYoshinobu Inoue fq->icmp6_fqdn_unused = 0; 14567d56d374SYoshinobu Inoue fq->icmp6_fqdn_cookie[0] = 0; 14577d56d374SYoshinobu Inoue fq->icmp6_fqdn_cookie[1] = 0; 14587d56d374SYoshinobu Inoue 14597d56d374SYoshinobu Inoue memset(&sin6, 0, sizeof(sin6)); 14607d56d374SYoshinobu Inoue sin6.sin6_family = AF_INET6; 14617d56d374SYoshinobu Inoue sin6.sin6_addr = *addr; 14627d56d374SYoshinobu Inoue 14637d56d374SYoshinobu Inoue memset(&msg, 0, sizeof(msg)); 14647d56d374SYoshinobu Inoue msg.msg_name = (caddr_t)&sin6; 14657d56d374SYoshinobu Inoue msg.msg_namelen = sizeof(sin6); 14667d56d374SYoshinobu Inoue msg.msg_iov = &iov; 14677d56d374SYoshinobu Inoue msg.msg_iovlen = 1; 14687d56d374SYoshinobu Inoue msg.msg_control = NULL; 14697d56d374SYoshinobu Inoue msg.msg_controllen = 0; 14707d56d374SYoshinobu Inoue iov.iov_base = (caddr_t)buf; 14717d56d374SYoshinobu Inoue iov.iov_len = sizeof(struct icmp6_fqdn_query); 14727d56d374SYoshinobu Inoue 14737d56d374SYoshinobu Inoue if (ifindex) { 14747d56d374SYoshinobu Inoue msg.msg_control = cbuf; 14757d56d374SYoshinobu Inoue msg.msg_controllen = sizeof(cbuf); 14767d56d374SYoshinobu Inoue cmsg = CMSG_FIRSTHDR(&msg); 14777d56d374SYoshinobu Inoue cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 14787d56d374SYoshinobu Inoue cmsg->cmsg_level = IPPROTO_IPV6; 14797d56d374SYoshinobu Inoue cmsg->cmsg_type = IPV6_PKTINFO; 14807d56d374SYoshinobu Inoue pkt = (struct in6_pktinfo *)&cmsg[1]; 14817d56d374SYoshinobu Inoue memset(&pkt->ipi6_addr, 0, sizeof(struct in6_addr)); 14827d56d374SYoshinobu Inoue pkt->ipi6_ifindex = ifindex; 14837d56d374SYoshinobu Inoue cmsg = CMSG_NXTHDR(&msg, cmsg); 14847d56d374SYoshinobu Inoue msg.msg_controllen = (char *)cmsg - cbuf; 14857d56d374SYoshinobu Inoue } 14867d56d374SYoshinobu Inoue 14877d56d374SYoshinobu Inoue if ((s = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) 14887d56d374SYoshinobu Inoue return NULL; 14897d56d374SYoshinobu Inoue (void)setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, 14907d56d374SYoshinobu Inoue (char *)&filter, sizeof(filter)); 14917d56d374SYoshinobu Inoue cc = sendmsg(s, &msg, 0); 14927d56d374SYoshinobu Inoue if (cc < 0) { 14939233c4d9SJason Evans _close(s); 14947d56d374SYoshinobu Inoue return NULL; 14957d56d374SYoshinobu Inoue } 14967d56d374SYoshinobu Inoue FD_SET(s, &s_fds); 14977d56d374SYoshinobu Inoue for (;;) { 14987d56d374SYoshinobu Inoue fds = s_fds; 14997d56d374SYoshinobu Inoue if (select(s + 1, &fds, NULL, NULL, &tout) <= 0) { 15009233c4d9SJason Evans _close(s); 15017d56d374SYoshinobu Inoue return NULL; 15027d56d374SYoshinobu Inoue } 15037d56d374SYoshinobu Inoue len = sizeof(sin6); 15047d56d374SYoshinobu Inoue cc = recvfrom(s, buf, sizeof(buf), 0, 15057d56d374SYoshinobu Inoue (struct sockaddr *)&sin6, &len); 15067d56d374SYoshinobu Inoue if (cc <= 0) { 15079233c4d9SJason Evans _close(s); 15087d56d374SYoshinobu Inoue return NULL; 15097d56d374SYoshinobu Inoue } 15107d56d374SYoshinobu Inoue if (cc < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr)) 15117d56d374SYoshinobu Inoue continue; 15127d56d374SYoshinobu Inoue if (!IN6_ARE_ADDR_EQUAL(addr, &sin6.sin6_addr)) 15137d56d374SYoshinobu Inoue continue; 15147d56d374SYoshinobu Inoue fr = (struct icmp6_fqdn_reply *)(buf + sizeof(struct ip6_hdr)); 15157d56d374SYoshinobu Inoue if (fr->icmp6_fqdn_type == ICMP6_FQDN_REPLY) 15167d56d374SYoshinobu Inoue break; 15177d56d374SYoshinobu Inoue } 15189233c4d9SJason Evans _close(s); 15197d56d374SYoshinobu Inoue if (fr->icmp6_fqdn_cookie[1] != 0) { 15207d56d374SYoshinobu Inoue /* rfc1788 type */ 15217d56d374SYoshinobu Inoue name = buf + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + 4; 15227d56d374SYoshinobu Inoue len = (buf + cc) - name; 15237d56d374SYoshinobu Inoue } else { 15247d56d374SYoshinobu Inoue len = fr->icmp6_fqdn_namelen; 15257d56d374SYoshinobu Inoue name = fr->icmp6_fqdn_name; 15267d56d374SYoshinobu Inoue } 15277d56d374SYoshinobu Inoue if (len <= 0) 15287d56d374SYoshinobu Inoue return NULL; 15297d56d374SYoshinobu Inoue name[len] = 0; 15307d56d374SYoshinobu Inoue 15317d56d374SYoshinobu Inoue if ((hc = (struct _icmp_host_cache *)malloc(sizeof(*hc))) == NULL) 15327d56d374SYoshinobu Inoue return NULL; 15337d56d374SYoshinobu Inoue /* XXX: limit number of cached entries */ 15347d56d374SYoshinobu Inoue hc->hc_ifindex = ifindex; 15357d56d374SYoshinobu Inoue hc->hc_addr = *addr; 15367d56d374SYoshinobu Inoue hc->hc_name = strdup(name); 15377d56d374SYoshinobu Inoue hc->hc_next = hc_head; 15387d56d374SYoshinobu Inoue hc_head = hc; 15397d56d374SYoshinobu Inoue return hc->hc_name; 15407d56d374SYoshinobu Inoue } 15417d56d374SYoshinobu Inoue 15427d56d374SYoshinobu Inoue static struct hostent * 15437d56d374SYoshinobu Inoue _icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp) 15447d56d374SYoshinobu Inoue { 15457d56d374SYoshinobu Inoue char *hname; 15467d56d374SYoshinobu Inoue int ifindex; 15477d56d374SYoshinobu Inoue struct in6_addr addr6; 15487d56d374SYoshinobu Inoue 15497d56d374SYoshinobu Inoue if (af != AF_INET6) { 15507d56d374SYoshinobu Inoue /* 15517d56d374SYoshinobu Inoue * Note: rfc1788 defines Who Are You for IPv4, 15527d56d374SYoshinobu Inoue * but no one implements it. 15537d56d374SYoshinobu Inoue */ 15547d56d374SYoshinobu Inoue return NULL; 15557d56d374SYoshinobu Inoue } 15567d56d374SYoshinobu Inoue 15577d56d374SYoshinobu Inoue memcpy(&addr6, addr, addrlen); 15587d56d374SYoshinobu Inoue ifindex = (addr6.s6_addr[2] << 8) | addr6.s6_addr[3]; 15597d56d374SYoshinobu Inoue addr6.s6_addr[2] = addr6.s6_addr[3] = 0; 15607d56d374SYoshinobu Inoue 15617d56d374SYoshinobu Inoue if (!IN6_IS_ADDR_LINKLOCAL(&addr6)) 15627d56d374SYoshinobu Inoue return NULL; /*XXX*/ 15637d56d374SYoshinobu Inoue 15647d56d374SYoshinobu Inoue if ((hname = _icmp_fqdn_query(&addr6, ifindex)) == NULL) 15657d56d374SYoshinobu Inoue return NULL; 15667d56d374SYoshinobu Inoue return _hpaddr(af, hname, &addr6, errp); 15677d56d374SYoshinobu Inoue } 15687d56d374SYoshinobu Inoue #endif /* ICMPNL */ 1569