name6.c revision 92889
1255570Strasz/* $FreeBSD: head/lib/libc/net/name6.c 92889 2002-03-21 18:49:23Z obrien $ */ 2255570Strasz/* $KAME: name6.c,v 1.25 2000/06/26 16:44:40 itojun Exp $ */ 3255570Strasz 4255570Strasz/* 5255570Strasz * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. 6255570Strasz * All rights reserved. 7255570Strasz * 8255570Strasz * Redistribution and use in source and binary forms, with or without 9255570Strasz * modification, are permitted provided that the following conditions 10255570Strasz * are met: 11255570Strasz * 1. Redistributions of source code must retain the above copyright 12255570Strasz * notice, this list of conditions and the following disclaimer. 13255570Strasz * 2. Redistributions in binary form must reproduce the above copyright 14255570Strasz * notice, this list of conditions and the following disclaimer in the 15255570Strasz * documentation and/or other materials provided with the distribution. 16255570Strasz * 3. Neither the name of the project nor the names of its contributors 17255570Strasz * may be used to endorse or promote products derived from this software 18255570Strasz * without specific prior written permission. 19255570Strasz * 20255570Strasz * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21255570Strasz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22255570Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23255570Strasz * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24255570Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25255570Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26255570Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27255570Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28255570Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29255570Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30255570Strasz * SUCH DAMAGE. 31255570Strasz */ 32255570Strasz/* 33255570Strasz * ++Copyright++ 1985, 1988, 1993 34255570Strasz * - 35255570Strasz * Copyright (c) 1985, 1988, 1993 36255570Strasz * The Regents of the University of California. All rights reserved. 37255570Strasz * 38255570Strasz * Redistribution and use in source and binary forms, with or without 39255570Strasz * modification, are permitted provided that the following conditions 40255570Strasz * are met: 41255570Strasz * 1. Redistributions of source code must retain the above copyright 42255570Strasz * notice, this list of conditions and the following disclaimer. 43255570Strasz * 2. Redistributions in binary form must reproduce the above copyright 44255570Strasz * notice, this list of conditions and the following disclaimer in the 45255570Strasz * documentation and/or other materials provided with the distribution. 46255570Strasz * 3. All advertising materials mentioning features or use of this software 47255570Strasz * must display the following acknowledgement: 48255570Strasz * This product includes software developed by the University of 49255570Strasz * California, Berkeley and its contributors. 50255570Strasz * 4. Neither the name of the University nor the names of its contributors 51255570Strasz * may be used to endorse or promote products derived from this software 52255570Strasz * without specific prior written permission. 53255570Strasz * 54255570Strasz * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 55255570Strasz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 56255570Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 57255570Strasz * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 58255570Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 59255570Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 60255570Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 61255570Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 62255570Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 63255570Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 64255570Strasz * SUCH DAMAGE. 65255570Strasz * - 66255570Strasz * Portions Copyright (c) 1993 by Digital Equipment Corporation. 67255570Strasz * 68265508Strasz * Permission to use, copy, modify, and distribute this software for any 69265508Strasz * purpose with or without fee is hereby granted, provided that the above 70265508Strasz * copyright notice and this permission notice appear in all copies, and that 71265508Strasz * the name of Digital Equipment Corporation not be used in advertising or 72255570Strasz * publicity pertaining to distribution of the document or software without 73255570Strasz * specific, written prior permission. 74255570Strasz * 75255570Strasz * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL 76255570Strasz * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES 77255570Strasz * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT 78255570Strasz * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 79255570Strasz * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 80255570Strasz * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 81265501Strasz * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 82265531Strasz * SOFTWARE. 83255570Strasz * - 84255570Strasz * --Copyright-- 85265501Strasz */ 86265531Strasz 87255570Strasz/* 88255570Strasz * Atsushi Onoe <onoe@sm.sony.co.jp> 89265501Strasz */ 90265531Strasz 91255570Strasz/* 92255570Strasz * TODO for thread safe 93265501Strasz * use mutex for _hostconf, _hostconf_init. 94265531Strasz * rewrite resolvers to be thread safe 95255570Strasz */ 96255570Strasz 97265501Strasz#include "namespace.h" 98265531Strasz#include <sys/param.h> 99265523Strasz#include <sys/socket.h> 100265523Strasz#include <sys/time.h> 101265523Strasz#include <sys/queue.h> 102265523Strasz#include <netinet/in.h> 103255570Strasz 104255570Strasz#include <arpa/inet.h> 105255570Strasz#include <arpa/nameser.h> 106255570Strasz 107255570Strasz#include <errno.h> 108255570Strasz#include <netdb.h> 109255570Strasz#include <resolv.h> 110265505Strasz#include <stdio.h> 111265505Strasz#include <stdlib.h> 112265505Strasz#include <string.h> 113265505Strasz#include <stdarg.h> 114255570Strasz#include <nsswitch.h> 115255570Strasz#include <unistd.h> 116265505Strasz#include "un-namespace.h" 117265505Strasz 118265505Strasz#ifndef _PATH_HOSTS 119265505Strasz#define _PATH_HOSTS "/etc/hosts" 120265505Strasz#endif 121265505Strasz 122255570Strasz#ifndef MAXALIASES 123255570Strasz#define MAXALIASES 10 124265505Strasz#endif 125265505Strasz#ifndef MAXADDRS 126265505Strasz#define MAXADDRS 20 127265505Strasz#endif 128265505Strasz#ifndef MAXDNAME 129265505Strasz#define MAXDNAME 1025 130265505Strasz#endif 131255570Strasz 132255570Strasz#ifdef INET6 133265505Strasz#define ADDRLEN(af) ((af) == AF_INET6 ? sizeof(struct in6_addr) : \ 134265505Strasz sizeof(struct in_addr)) 135265505Strasz#else 136265505Strasz#define ADDRLEN(af) sizeof(struct in_addr) 137265505Strasz#endif 138265505Strasz 139265505Strasz#define MAPADDR(ab, ina) \ 140255570Straszdo { \ 141255570Strasz memcpy(&(ab)->map_inaddr, ina, sizeof(struct in_addr)); \ 142255570Strasz memset((ab)->map_zero, 0, sizeof((ab)->map_zero)); \ 143255570Strasz memset((ab)->map_one, 0xff, sizeof((ab)->map_one)); \ 144255570Strasz} while (0) 145255570Strasz#define MAPADDRENABLED(flags) \ 146255570Strasz (((flags) & AI_V4MAPPED) || \ 147255570Strasz (((flags) & AI_V4MAPPED_CFG) && _mapped_addr_enabled())) 148255570Strasz 149255570Straszunion inx_addr { 150255570Strasz struct in_addr in_addr; 151255570Strasz#ifdef INET6 152255570Strasz struct in6_addr in6_addr; 153255570Strasz#endif 154255570Strasz struct { 155255570Strasz u_char mau_zero[10]; 156255570Strasz u_char mau_one[2]; 157255570Strasz struct in_addr mau_inaddr; 158255570Strasz } map_addr_un; 159255570Strasz#define map_zero map_addr_un.mau_zero 160255570Strasz#define map_one map_addr_un.mau_one 161255570Strasz#define map_inaddr map_addr_un.mau_inaddr 162255570Strasz}; 163255570Strasz 164255570Straszstatic struct hostent *_hpcopy(struct hostent *hp, int *errp); 165255570Straszstatic struct hostent *_hpaddr(int af, const char *name, void *addr, int *errp); 166255570Straszstatic struct hostent *_hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp); 167255570Strasz#ifdef INET6 168255570Straszstatic struct hostent *_hpmapv6(struct hostent *hp, int *errp); 169255570Strasz#endif 170255570Straszstatic struct hostent *_hpsort(struct hostent *hp); 171255570Straszstatic struct hostent *_ghbyname(const char *name, int af, int flags, int *errp); 172255570Straszstatic char *_hgetword(char **pp); 173255570Straszstatic int _mapped_addr_enabled(void); 174255570Strasz 175255570Straszstatic FILE *_files_open(int *errp); 176255570Straszstatic int _files_ghbyname(void *, void *, va_list); 177255570Straszstatic int _files_ghbyaddr(void *, void *, va_list); 178255570Straszstatic void _files_shent(int stayopen); 179255570Straszstatic void _files_ehent(void); 180255570Strasz#ifdef YP 181255570Straszstatic int _nis_ghbyname(void *, void *, va_list); 182255570Straszstatic int _nis_ghbyaddr(void *, void *, va_list); 183255570Strasz#endif 184255570Straszstatic int _dns_ghbyname(void *, void *, va_list); 185255570Straszstatic int _dns_ghbyaddr(void *, void *, va_list); 186255570Straszstatic void _dns_shent(int stayopen); 187255570Straszstatic void _dns_ehent(void); 188255570Strasz#ifdef ICMPNL 189255570Straszstatic int _icmp_ghbyaddr(void *, void *, va_list); 190255570Strasz#endif /* ICMPNL */ 191255570Strasz 192255570Strasz/* Host lookup order if nsswitch.conf is broken or nonexistant */ 193255570Straszstatic const ns_src default_src[] = { 194255570Strasz { NSSRC_FILES, NS_SUCCESS }, 195255570Strasz { NSSRC_DNS, NS_SUCCESS }, 196255570Strasz#ifdef ICMPNL 197255570Strasz#define NSSRC_ICMP "icmp" 198255570Strasz { NSSRC_ICMP, NS_SUCCESS }, 199255570Strasz#endif 200255570Strasz { 0 } 201255570Strasz}; 202255570Strasz 203255570Strasz/* 204255570Strasz * Check if kernel supports mapped address. 205255570Strasz * implementation dependent 206255570Strasz */ 207255570Strasz#ifdef __KAME__ 208255570Strasz#include <sys/sysctl.h> 209255570Strasz#endif /* __KAME__ */ 210255570Strasz 211255570Straszstatic int 212255570Strasz_mapped_addr_enabled(void) 213255570Strasz{ 214255570Strasz /* implementation dependent check */ 215255570Strasz#if defined(__KAME__) && defined(IPV6CTL_MAPPED_ADDR) 216255570Strasz int mib[4]; 217255570Strasz size_t len; 218255570Strasz int val; 219255570Strasz 220255570Strasz mib[0] = CTL_NET; 221255570Strasz mib[1] = PF_INET6; 222255570Strasz mib[2] = IPPROTO_IPV6; 223255570Strasz mib[3] = IPV6CTL_MAPPED_ADDR; 224255570Strasz len = sizeof(val); 225255570Strasz if (sysctl(mib, 4, &val, &len, 0, 0) == 0 && val != 0) 226255570Strasz return 1; 227265500Strasz#endif /* __KAME__ && IPV6CTL_MAPPED_ADDR */ 228265500Strasz return 0; 229255570Strasz} 230255570Strasz 231255570Strasz/* 232265500Strasz * Functions defined in RFC2553 233255570Strasz * getipnodebyname, getipnodebyaddr, freehostent 234255570Strasz */ 235255570Strasz 236255570Straszstatic struct hostent * 237255570Strasz_ghbyname(const char *name, int af, int flags, int *errp) 238255570Strasz{ 239255570Strasz struct hostent *hp; 240255570Strasz int rval; 241255570Strasz 242255570Strasz static const ns_dtab dtab[] = { 243255570Strasz NS_FILES_CB(_files_ghbyname, NULL) 244255570Strasz { NSSRC_DNS, _dns_ghbyname, NULL }, 245255570Strasz NS_NIS_CB(_nis_ghbyname, NULL) 246255570Strasz { 0 } 247255570Strasz }; 248265500Strasz 249255570Strasz if (flags & AI_ADDRCONFIG) { 250255570Strasz int s; 251255570Strasz 252255570Strasz /* 253255570Strasz * TODO: 254255570Strasz * Note that implementation dependent test for address 255255570Strasz * configuration should be done everytime called 256255570Strasz * (or apropriate interval), 257255570Strasz * because addresses will be dynamically assigned or deleted. 258255570Strasz */ 259255570Strasz if (af == AF_UNSPEC) { 260255570Strasz if ((s = _socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 261255570Strasz af = AF_INET; 262255570Strasz else { 263255570Strasz _close(s); 264255570Strasz if ((s = _socket(AF_INET, SOCK_DGRAM, 0)) < 0) 265255570Strasz af = AF_INET6; 266255570Strasz else 267255570Strasz _close(s); 268255570Strasz } 269255570Strasz 270255570Strasz } 271255570Strasz if (af != AF_UNSPEC) { 272255570Strasz if ((s = _socket(af, SOCK_DGRAM, 0)) < 0) 273255570Strasz return NULL; 274255570Strasz _close(s); 275255570Strasz } 276255570Strasz } 277255570Strasz 278255570Strasz rval = nsdispatch(&hp, dtab, NSDB_HOSTS, "ghbyname", default_src, 279255570Strasz name, af, errp); 280255570Strasz return (rval == NS_SUCCESS) ? hp : NULL; 281255570Strasz} 282255570Strasz 283255570Strasz/* getipnodebyname() internal routine for multiple query(PF_UNSPEC) support. */ 284255570Straszstruct hostent * 285255570Strasz_getipnodebyname_multi(const char *name, int af, int flags, int *errp) 286255570Strasz{ 287255570Strasz struct hostent *hp; 288255570Strasz union inx_addr addrbuf; 289255570Strasz 290255570Strasz /* XXX: PF_UNSPEC is only supposed to be passed from getaddrinfo() */ 291255570Strasz if (af != AF_INET 292255570Strasz#ifdef INET6 293255570Strasz && af != AF_INET6 294255570Strasz#endif 295255570Strasz && af != PF_UNSPEC 296255570Strasz ) 297255570Strasz { 298255570Strasz *errp = NO_RECOVERY; 299255570Strasz return NULL; 300255570Strasz } 301255570Strasz 302255570Strasz#ifdef INET6 303255570Strasz /* special case for literal address */ 304255570Strasz if (inet_pton(AF_INET6, name, &addrbuf) == 1) { 305255570Strasz if (af != AF_INET6) { 306255570Strasz *errp = HOST_NOT_FOUND; 307265523Strasz return NULL; 308255570Strasz } 309255570Strasz return _hpaddr(af, name, &addrbuf, errp); 310255570Strasz } 311265523Strasz#endif 312255570Strasz if (inet_aton(name, (struct in_addr *)&addrbuf) == 1) { 313255570Strasz if (af != AF_INET) { 314255570Strasz if (MAPADDRENABLED(flags)) { 315255570Strasz MAPADDR(&addrbuf, &addrbuf.in_addr); 316255570Strasz } else { 317255570Strasz *errp = HOST_NOT_FOUND; 318255570Strasz return NULL; 319255570Strasz } 320255570Strasz } 321255570Strasz return _hpaddr(af, name, &addrbuf, errp); 322255570Strasz } 323255570Strasz 324255570Strasz *errp = HOST_NOT_FOUND; 325265500Strasz hp = _ghbyname(name, af, flags, errp); 326265500Strasz 327265500Strasz#ifdef INET6 328255570Strasz if (af == AF_INET6 329255570Strasz && ((flags & AI_ALL) || hp == NULL) 330255570Strasz && (MAPADDRENABLED(flags))) { 331265523Strasz struct hostent *hp2 = _ghbyname(name, AF_INET, flags, errp); 332265523Strasz if (hp == NULL) 333265523Strasz hp = _hpmapv6(hp2, errp); 334265523Strasz else { 335265523Strasz if (hp2 && strcmp(hp->h_name, hp2->h_name) != 0) { 336265523Strasz freehostent(hp2); 337265523Strasz hp2 = NULL; 338255570Strasz } 339265523Strasz hp = _hpmerge(hp, hp2, errp); 340265523Strasz } 341265523Strasz } 342265523Strasz#endif 343265523Strasz return _hpsort(hp); 344265523Strasz} 345265523Strasz 346265523Straszstruct hostent * 347265523Straszgetipnodebyname(const char *name, int af, int flags, int *errp) 348265523Strasz{ 349265523Strasz if (af != AF_INET 350265523Strasz#ifdef INET6 351265523Strasz && af != AF_INET6 352265523Strasz#endif 353265523Strasz ) 354265523Strasz { 355265523Strasz *errp = NO_RECOVERY; 356265523Strasz return NULL; 357265523Strasz } 358265523Strasz return(_getipnodebyname_multi(name, af ,flags, errp)); 359265523Strasz} 360265523Strasz 361265523Straszstruct hostent * 362265523Straszgetipnodebyaddr(const void *src, size_t len, int af, int *errp) 363265523Strasz{ 364265523Strasz struct hostent *hp; 365265523Strasz int rval; 366265523Strasz#ifdef INET6 367265523Strasz struct in6_addr addrbuf; 368265523Strasz#else 369265523Strasz struct in_addr addrbuf; 370265523Strasz#endif 371265523Strasz 372265523Strasz static const ns_dtab dtab[] = { 373265523Strasz NS_FILES_CB(_files_ghbyaddr, NULL) 374265523Strasz { NSSRC_DNS, _dns_ghbyaddr, NULL }, 375265523Strasz NS_NIS_CB(_nis_ghbyaddr, NULL) 376265523Strasz#ifdef ICMPNL 377265523Strasz { NSSRC_ICMP, _icmp_ghbyaddr, NULL }, 378265523Strasz#endif 379265523Strasz { 0 } 380265523Strasz }; 381265523Strasz 382265523Strasz *errp = HOST_NOT_FOUND; 383265523Strasz 384265523Strasz switch (af) { 385265523Strasz case AF_INET: 386265523Strasz if (len != sizeof(struct in_addr)) { 387265523Strasz *errp = NO_RECOVERY; 388255570Strasz return NULL; 389255570Strasz } 390265500Strasz if ((long)src & ~(sizeof(struct in_addr) - 1)) { 391255570Strasz memcpy(&addrbuf, src, len); 392255570Strasz src = &addrbuf; 393255570Strasz } 394255570Strasz if (((struct in_addr *)src)->s_addr == 0) 395255570Strasz return NULL; 396255570Strasz break; 397255570Strasz#ifdef INET6 398255570Strasz case AF_INET6: 399255570Strasz if (len != sizeof(struct in6_addr)) { 400255570Strasz *errp = NO_RECOVERY; 401255570Strasz return NULL; 402255570Strasz } 403255570Strasz if ((long)src & ~(sizeof(struct in6_addr) / 2 - 1)) { /*XXX*/ 404255570Strasz memcpy(&addrbuf, src, len); 405255570Strasz src = &addrbuf; 406255570Strasz } 407255570Strasz if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)src)) 408255570Strasz return NULL; 409255570Strasz if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)src) 410255570Strasz || IN6_IS_ADDR_V4COMPAT((struct in6_addr *)src)) { 411255570Strasz src = (char *)src + 412255570Strasz (sizeof(struct in6_addr) - sizeof(struct in_addr)); 413255570Strasz af = AF_INET; 414255570Strasz len = sizeof(struct in_addr); 415255570Strasz } 416255570Strasz break; 417255570Strasz#endif 418255570Strasz default: 419255570Strasz *errp = NO_RECOVERY; 420255570Strasz return NULL; 421255570Strasz } 422255570Strasz 423255570Strasz rval = nsdispatch(&hp, dtab, NSDB_HOSTS, "ghbyaddr", default_src, 424255570Strasz src, len, af, errp); 425255570Strasz return (rval == NS_SUCCESS) ? hp : NULL; 426255570Strasz} 427255570Strasz 428255570Straszvoid 429255570Straszfreehostent(struct hostent *ptr) 430265523Strasz{ 431255570Strasz free(ptr); 432255570Strasz} 433255570Strasz 434265500Strasz#if 0 435255570Strasz 436255570Strasz/* XXX: should be deprecated */ 437255570Straszstruct hostent * 438255570Straszgetnodebyname(const char *name, int af, int flags) 439255570Strasz{ 440255570Strasz return getipnodebyname(name, af, flags, &h_errno); 441255570Strasz} 442255570Strasz 443255570Strasz#ifdef __warn_references 444255570Strasz__warn_references(getnodebyname, 445255570Strasz "warning: getnodebyname() deprecated, " 446255570Strasz "should use getaddrinfo() or getipnodebyname()"); 447255570Strasz#endif 448255570Strasz 449255570Straszstruct hostent * 450255570Straszgetnodebyaddr(const void *src, size_t len, int af) 451255570Strasz{ 452255570Strasz return getipnodebyaddr(src, len, af, &h_errno); 453255570Strasz} 454255570Strasz 455255570Strasz#ifdef __warn_references 456255570Strasz__warn_references(getnodebyaddr, 457255570Strasz "warning: getnodebyaddr() deprecated, " 458255570Strasz "should use getnameinfo() or getipnodebyaddr()"); 459255570Strasz#endif 460255570Strasz 461255570Strasz#endif 462255570Strasz 463255570Strasz/* 464255570Strasz * Private utility functions 465265500Strasz */ 466255570Strasz 467255570Strasz/* 468255570Strasz * _hpcopy: allocate and copy hostent structure 469255570Strasz */ 470255570Straszstatic struct hostent * 471255570Strasz_hpcopy(struct hostent *hp, int *errp) 472255570Strasz{ 473255570Strasz struct hostent *nhp; 474255570Strasz char *cp, **pp; 475255570Strasz int size, addrsize; 476255570Strasz int nalias = 0, naddr = 0; 477255570Strasz int al_off; 478255570Strasz int i; 479255570Strasz 480255570Strasz if (hp == NULL) 481255570Strasz return hp; 482255570Strasz 483255570Strasz /* count size to be allocated */ 484255570Strasz size = sizeof(struct hostent); 485255570Strasz if (hp->h_name != NULL) 486255570Strasz size += strlen(hp->h_name) + 1; 487255570Strasz if ((pp = hp->h_aliases) != NULL) { 488255570Strasz for (i = 0; *pp != NULL; i++, pp++) { 489255570Strasz if (**pp != '\0') { 490255570Strasz size += strlen(*pp) + 1; 491255570Strasz nalias++; 492255570Strasz } 493255570Strasz } 494255570Strasz } 495255570Strasz /* adjust alignment */ 496255570Strasz size = ALIGN(size); 497255570Strasz al_off = size; 498255570Strasz size += sizeof(char *) * (nalias + 1); 499255570Strasz addrsize = ALIGN(hp->h_length); 500255570Strasz if ((pp = hp->h_addr_list) != NULL) { 501255570Strasz while (*pp++ != NULL) 502255570Strasz naddr++; 503255570Strasz } 504255570Strasz size += addrsize * naddr; 505255570Strasz size += sizeof(char *) * (naddr + 1); 506255570Strasz 507255570Strasz /* copy */ 508255570Strasz if ((nhp = (struct hostent *)malloc(size)) == NULL) { 509255570Strasz *errp = TRY_AGAIN; 510255570Strasz return NULL; 511255570Strasz } 512255570Strasz cp = (char *)&nhp[1]; 513255570Strasz if (hp->h_name != NULL) { 514255570Strasz nhp->h_name = cp; 515255570Strasz strcpy(cp, hp->h_name); 516255570Strasz cp += strlen(cp) + 1; 517255570Strasz } else 518255570Strasz nhp->h_name = NULL; 519255570Strasz nhp->h_aliases = (char **)((char *)nhp + al_off); 520255570Strasz if ((pp = hp->h_aliases) != NULL) { 521255570Strasz for (i = 0; *pp != NULL; pp++) { 522255570Strasz if (**pp != '\0') { 523255570Strasz nhp->h_aliases[i++] = cp; 524255570Strasz strcpy(cp, *pp); 525255570Strasz cp += strlen(cp) + 1; 526255570Strasz } 527255570Strasz } 528255570Strasz } 529255570Strasz nhp->h_aliases[nalias] = NULL; 530255570Strasz cp = (char *)&nhp->h_aliases[nalias + 1]; 531255570Strasz nhp->h_addrtype = hp->h_addrtype; 532255570Strasz nhp->h_length = hp->h_length; 533255570Strasz nhp->h_addr_list = (char **)cp; 534255570Strasz if ((pp = hp->h_addr_list) != NULL) { 535255570Strasz cp = (char *)&nhp->h_addr_list[naddr + 1]; 536255570Strasz for (i = 0; *pp != NULL; pp++) { 537255570Strasz nhp->h_addr_list[i++] = cp; 538255570Strasz memcpy(cp, *pp, hp->h_length); 539255570Strasz cp += addrsize; 540255570Strasz } 541255570Strasz } 542255570Strasz nhp->h_addr_list[naddr] = NULL; 543255570Strasz return nhp; 544255570Strasz} 545255570Strasz 546255570Strasz/* 547255570Strasz * _hpaddr: construct hostent structure with one address 548255570Strasz */ 549255570Straszstatic struct hostent * 550255570Strasz_hpaddr(int af, const char *name, void *addr, int *errp) 551255570Strasz{ 552255570Strasz struct hostent *hp, hpbuf; 553255570Strasz char *addrs[2]; 554255570Strasz 555255570Strasz hp = &hpbuf; 556255570Strasz hp->h_name = (char *)name; 557255570Strasz hp->h_aliases = NULL; 558255570Strasz hp->h_addrtype = af; 559255570Strasz hp->h_length = ADDRLEN(af); 560255570Strasz hp->h_addr_list = addrs; 561255570Strasz addrs[0] = (char *)addr; 562255570Strasz addrs[1] = NULL; 563255570Strasz return _hpcopy(hp, errp); 564255570Strasz} 565255570Strasz 566255570Strasz/* 567255570Strasz * _hpmerge: merge 2 hostent structure, arguments will be freed 568255570Strasz */ 569255570Straszstatic struct hostent * 570255570Strasz_hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp) 571255570Strasz{ 572255570Strasz int i, j; 573255824Strasz int naddr, nalias; 574255824Strasz char **pp; 575255824Strasz struct hostent *hp, hpbuf; 576255824Strasz char *aliases[MAXALIASES + 1], *addrs[MAXADDRS + 1]; 577255824Strasz union inx_addr addrbuf[MAXADDRS]; 578255570Strasz 579255570Strasz if (hp1 == NULL) 580255570Strasz return hp2; 581255570Strasz if (hp2 == NULL) 582255570Strasz return hp1; 583255570Strasz 584255570Strasz#define HP(i) (i == 1 ? hp1 : hp2) 585255570Strasz hp = &hpbuf; 586255570Strasz hp->h_name = (hp1->h_name != NULL ? hp1->h_name : hp2->h_name); 587255570Strasz hp->h_aliases = aliases; 588255570Strasz nalias = 0; 589255570Strasz for (i = 1; i <= 2; i++) { 590255570Strasz if ((pp = HP(i)->h_aliases) == NULL) 591255570Strasz continue; 592255570Strasz for (; nalias < MAXALIASES && *pp != NULL; pp++) { 593255570Strasz /* check duplicates */ 594255570Strasz for (j = 0; j < nalias; j++) 595255570Strasz if (strcasecmp(*pp, aliases[j]) == 0) 596255570Strasz break; 597255570Strasz if (j == nalias) 598255570Strasz aliases[nalias++] = *pp; 599255570Strasz } 600255570Strasz } 601255570Strasz aliases[nalias] = NULL; 602255570Strasz#ifdef INET6 603255570Strasz if (hp1->h_length != hp2->h_length) { 604255570Strasz hp->h_addrtype = AF_INET6; 605255570Strasz hp->h_length = sizeof(struct in6_addr); 606255570Strasz } else { 607255570Strasz#endif 608255570Strasz hp->h_addrtype = hp1->h_addrtype; 609255570Strasz hp->h_length = hp1->h_length; 610255570Strasz#ifdef INET6 611255570Strasz } 612255570Strasz#endif 613255570Strasz hp->h_addr_list = addrs; 614255570Strasz naddr = 0; 615255570Strasz for (i = 1; i <= 2; i++) { 616255570Strasz if ((pp = HP(i)->h_addr_list) == NULL) 617255570Strasz continue; 618255570Strasz if (HP(i)->h_length == hp->h_length) { 619255570Strasz while (naddr < MAXADDRS && *pp != NULL) 620255570Strasz addrs[naddr++] = *pp++; 621255570Strasz } else { 622255570Strasz /* copy IPv4 addr as mapped IPv6 addr */ 623255570Strasz while (naddr < MAXADDRS && *pp != NULL) { 624255570Strasz MAPADDR(&addrbuf[naddr], *pp++); 625255570Strasz addrs[naddr] = (char *)&addrbuf[naddr]; 626255570Strasz naddr++; 627255570Strasz } 628255570Strasz } 629255570Strasz } 630255570Strasz addrs[naddr] = NULL; 631255570Strasz hp = _hpcopy(hp, errp); 632255570Strasz freehostent(hp1); 633255570Strasz freehostent(hp2); 634255570Strasz return hp; 635255570Strasz} 636255570Strasz 637255570Strasz/* 638255570Strasz * _hpmapv6: convert IPv4 hostent into IPv4-mapped IPv6 addresses 639255570Strasz */ 640255570Strasz#ifdef INET6 641255570Straszstatic struct hostent * 642255570Strasz_hpmapv6(struct hostent *hp, int *errp) 643265500Strasz{ 644255570Strasz struct hostent *hp6; 645255570Strasz 646255570Strasz if (hp == NULL) 647255570Strasz return NULL; 648255570Strasz if (hp->h_addrtype == AF_INET6) 649255570Strasz return hp; 650255570Strasz 651255570Strasz /* make dummy hostent to convert IPv6 address */ 652255570Strasz if ((hp6 = (struct hostent *)malloc(sizeof(struct hostent))) == NULL) { 653255570Strasz *errp = TRY_AGAIN; 654255570Strasz return NULL; 655255570Strasz } 656255570Strasz hp6->h_name = NULL; 657255570Strasz hp6->h_aliases = NULL; 658255570Strasz hp6->h_addrtype = AF_INET6; 659255570Strasz hp6->h_length = sizeof(struct in6_addr); 660255570Strasz hp6->h_addr_list = NULL; 661255570Strasz return _hpmerge(hp6, hp, errp); 662255570Strasz} 663255570Strasz#endif 664255570Strasz 665255570Strasz/* 666255570Strasz * _hpsort: sort address by sortlist 667255570Strasz */ 668255570Straszstatic struct hostent * 669255570Strasz_hpsort(struct hostent *hp) 670255570Strasz{ 671255570Strasz int i, j, n; 672255570Strasz u_char *ap, *sp, *mp, **pp; 673255570Strasz char t; 674255570Strasz char order[MAXADDRS]; 675255570Strasz int nsort = _res.nsort; 676255570Strasz 677255570Strasz if (hp == NULL || hp->h_addr_list[1] == NULL || nsort == 0) 678255570Strasz return hp; 679255570Strasz for (i = 0; (ap = (u_char *)hp->h_addr_list[i]); i++) { 680255570Strasz for (j = 0; j < nsort; j++) { 681255570Strasz#ifdef INET6 682255570Strasz if (_res_ext.sort_list[j].af != hp->h_addrtype) 683255570Strasz continue; 684255570Strasz sp = (u_char *)&_res_ext.sort_list[j].addr; 685255570Strasz mp = (u_char *)&_res_ext.sort_list[j].mask; 686255570Strasz#else 687255570Strasz sp = (u_char *)&_res.sort_list[j].addr; 688255570Strasz mp = (u_char *)&_res.sort_list[j].mask; 689255570Strasz#endif 690255570Strasz for (n = 0; n < hp->h_length; n++) { 691255570Strasz if ((ap[n] & mp[n]) != sp[n]) 692255570Strasz break; 693255570Strasz } 694255570Strasz if (n == hp->h_length) 695255570Strasz break; 696255570Strasz } 697255570Strasz order[i] = j; 698255570Strasz } 699255570Strasz n = i; 700255570Strasz pp = (u_char **)hp->h_addr_list; 701255570Strasz for (i = 0; i < n - 1; i++) { 702255570Strasz for (j = i + 1; j < n; j++) { 703255570Strasz if (order[i] > order[j]) { 704255570Strasz ap = pp[i]; 705255570Strasz pp[i] = pp[j]; 706255570Strasz pp[j] = ap; 707255570Strasz t = order[i]; 708255570Strasz order[i] = order[j]; 709255570Strasz order[j] = t; 710255570Strasz } 711255570Strasz } 712255570Strasz } 713255570Strasz return hp; 714255570Strasz} 715255570Strasz 716255570Straszstatic char * 717255570Strasz_hgetword(char **pp) 718255570Strasz{ 719255570Strasz char c, *p, *ret; 720255570Strasz const char *sp; 721255570Strasz static const char sep[] = "# \t\n"; 722255570Strasz 723255570Strasz ret = NULL; 724255570Strasz for (p = *pp; (c = *p) != '\0'; p++) { 725255570Strasz for (sp = sep; *sp != '\0'; sp++) { 726255570Strasz if (c == *sp) 727255570Strasz break; 728255570Strasz } 729255570Strasz if (c == '#') 730255570Strasz p[1] = '\0'; /* ignore rest of line */ 731255570Strasz if (ret == NULL) { 732255570Strasz if (*sp == '\0') 733255570Strasz ret = p; 734255570Strasz } else { 735255570Strasz if (*sp != '\0') { 736255570Strasz *p++ = '\0'; 737255570Strasz break; 738255570Strasz } 739255570Strasz } 740255570Strasz } 741256187Strasz *pp = p; 742255570Strasz if (ret == NULL || *ret == '\0') 743255570Strasz return NULL; 744255570Strasz return ret; 745256187Strasz} 746256187Strasz 747256187Strasz/* 748255570Strasz * FILES (/etc/hosts) 749256187Strasz */ 750255570Strasz 751255570Straszstatic FILE * 752255570Strasz_files_open(int *errp) 753255570Strasz{ 754255570Strasz FILE *fp; 755255570Strasz fp = fopen(_PATH_HOSTS, "r"); 756255570Strasz if (fp == NULL) 757255570Strasz *errp = NO_RECOVERY; 758255570Strasz return fp; 759255570Strasz} 760255570Strasz 761256187Straszstatic int 762256187Strasz_files_ghbyname(void *rval, void *cb_data, va_list ap) 763256187Strasz{ 764256187Strasz const char *name; 765256187Strasz int af; 766256187Strasz int *errp; 767256187Strasz int match, nalias; 768256187Strasz char *p, *line, *addrstr, *cname; 769256187Strasz FILE *fp; 770256187Strasz struct hostent *rethp, *hp, hpbuf; 771256187Strasz char *aliases[MAXALIASES + 1], *addrs[2]; 772256187Strasz union inx_addr addrbuf; 773256187Strasz char buf[BUFSIZ]; 774255570Strasz int af0; 775255570Strasz 776256187Strasz name = va_arg(ap, const char *); 777256187Strasz af = va_arg(ap, int); 778256187Strasz errp = va_arg(ap, int *); 779255570Strasz 780256187Strasz *(struct hostent **)rval = NULL; 781255570Strasz 782255570Strasz if ((fp = _files_open(errp)) == NULL) 783255570Strasz return NS_UNAVAIL; 784255570Strasz rethp = hp = NULL; 785255570Strasz 786255570Strasz af0 = af; 787256187Strasz while (fgets(buf, sizeof(buf), fp)) { 788255570Strasz line = buf; 789256187Strasz if ((addrstr = _hgetword(&line)) == NULL 790256187Strasz || (cname = _hgetword(&line)) == NULL) 791256187Strasz continue; 792256187Strasz match = (strcasecmp(cname, name) == 0); 793256187Strasz nalias = 0; 794256187Strasz while ((p = _hgetword(&line)) != NULL) { 795256187Strasz if (!match) 796256187Strasz match = (strcasecmp(p, name) == 0); 797256187Strasz if (nalias < MAXALIASES) 798256187Strasz aliases[nalias++] = p; 799256187Strasz } 800256187Strasz if (!match) 801256187Strasz continue; 802255570Strasz switch (af0) { 803255570Strasz case AF_INET: 804255570Strasz if (inet_aton(addrstr, (struct in_addr *)&addrbuf) 805255570Strasz != 1) { 806255570Strasz *errp = NO_DATA; /* name found */ 807255570Strasz continue; 808255570Strasz } 809255570Strasz af = af0; 810255570Strasz break; 811255570Strasz#ifdef INET6 812255570Strasz case AF_INET6: 813255570Strasz if (inet_pton(af, addrstr, &addrbuf) != 1) { 814255570Strasz *errp = NO_DATA; /* name found */ 815255570Strasz continue; 816255570Strasz } 817255570Strasz af = af0; 818255570Strasz break; 819255570Strasz#endif 820255570Strasz case AF_UNSPEC: 821255570Strasz if (inet_aton(addrstr, (struct in_addr *)&addrbuf) 822255570Strasz == 1) { 823255570Strasz af = AF_INET; 824255570Strasz break; 825255570Strasz } 826255570Strasz#ifdef INET6 827255570Strasz if (inet_pton(AF_INET6, addrstr, &addrbuf) == 1) { 828255570Strasz af = AF_INET6; 829255570Strasz break; 830255570Strasz } 831255570Strasz#endif 832255570Strasz *errp = NO_DATA; /* name found */ 833255570Strasz continue; 834255570Strasz /* NOTREACHED */ 835255570Strasz } 836255570Strasz hp = &hpbuf; 837255570Strasz hp->h_name = cname; 838255570Strasz hp->h_aliases = aliases; 839255570Strasz aliases[nalias] = NULL; 840255570Strasz hp->h_addrtype = af; 841255570Strasz hp->h_length = ADDRLEN(af); 842255570Strasz hp->h_addr_list = addrs; 843255570Strasz addrs[0] = (char *)&addrbuf; 844255570Strasz addrs[1] = NULL; 845255570Strasz hp = _hpcopy(hp, errp); 846255570Strasz rethp = _hpmerge(rethp, hp, errp); 847255570Strasz } 848255570Strasz fclose(fp); 849255570Strasz *(struct hostent **)rval = rethp; 850255570Strasz return (rethp != NULL) ? NS_SUCCESS : NS_NOTFOUND; 851255570Strasz} 852255570Strasz 853255570Straszstatic int 854255570Strasz_files_ghbyaddr(void *rval, void *cb_data, va_list ap) 855255570Strasz{ 856255570Strasz const void *addr; 857255570Strasz int addrlen; 858255570Strasz int af; 859255570Strasz int *errp; 860255570Strasz int nalias; 861255570Strasz char *p, *line; 862255570Strasz FILE *fp; 863255570Strasz struct hostent *hp, hpbuf; 864255570Strasz char *aliases[MAXALIASES + 1], *addrs[2]; 865255570Strasz union inx_addr addrbuf; 866255570Strasz char buf[BUFSIZ]; 867255570Strasz 868255570Strasz addr = va_arg(ap, const void *); 869255570Strasz addrlen = va_arg(ap, int); 870255570Strasz af = va_arg(ap, int); 871255570Strasz errp = va_arg(ap, int *); 872255570Strasz 873255570Strasz *(struct hostent**)rval = NULL; 874255570Strasz 875255570Strasz if ((fp = _files_open(errp)) == NULL) 876255570Strasz return NS_UNAVAIL; 877255570Strasz hp = NULL; 878255570Strasz while (fgets(buf, sizeof(buf), fp)) { 879255570Strasz line = buf; 880255570Strasz if ((p = _hgetword(&line)) == NULL 881255570Strasz || (af == AF_INET 882255570Strasz ? inet_aton(p, (struct in_addr *)&addrbuf) 883255570Strasz : inet_pton(af, p, &addrbuf)) != 1 884255570Strasz || memcmp(addr, &addrbuf, addrlen) != 0 885255570Strasz || (p = _hgetword(&line)) == NULL) 886255570Strasz continue; 887255570Strasz hp = &hpbuf; 888255570Strasz hp->h_name = p; 889255570Strasz hp->h_aliases = aliases; 890255570Strasz nalias = 0; 891255570Strasz while ((p = _hgetword(&line)) != NULL) { 892255570Strasz if (nalias < MAXALIASES) 893255570Strasz aliases[nalias++] = p; 894255570Strasz } 895255570Strasz aliases[nalias] = NULL; 896255570Strasz hp->h_addrtype = af; 897255570Strasz hp->h_length = addrlen; 898255570Strasz hp->h_addr_list = addrs; 899255570Strasz addrs[0] = (char *)&addrbuf; 900255570Strasz addrs[1] = NULL; 901255570Strasz hp = _hpcopy(hp, errp); 902255570Strasz break; 903255570Strasz } 904255570Strasz fclose(fp); 905255570Strasz *(struct hostent **)rval = hp; 906255570Strasz return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND; 907255570Strasz} 908255570Strasz 909255570Strasz#ifdef YP 910255570Strasz/* 911255570Strasz * NIS 912255570Strasz * 913255570Strasz * XXX actually a hack, these are INET4 specific. 914255570Strasz */ 915255570Straszstatic int 916255570Strasz_nis_ghbyname(void *rval, void *cb_data, va_list ap) 917255570Strasz{ 918255570Strasz const char *name; 919255570Strasz int af; 920255570Strasz int *errp; 921255570Strasz struct hostent *hp = NULL; 922255570Strasz 923255570Strasz name = va_arg(ap, const char *); 924255570Strasz af = va_arg(ap, int); 925255570Strasz errp = va_arg(ap, int *); 926255570Strasz 927255570Strasz if (af == AF_UNSPEC) 928255570Strasz af = AF_INET; 929255570Strasz if (af == AF_INET) { 930255570Strasz hp = _gethostbynisname(name, af); 931255570Strasz if (hp != NULL) 932255570Strasz hp = _hpcopy(hp, errp); 933255570Strasz } 934255570Strasz 935255570Strasz *(struct hostent **)rval = hp; 936255570Strasz return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND; 937255570Strasz 938255570Strasz} 939255570Strasz 940255570Straszstatic int 941255570Strasz_nis_ghbyaddr(void *rval, void *cb_data, va_list ap) 942255570Strasz{ 943255570Strasz const void *addr; 944255570Strasz int addrlen; 945255570Strasz int af; 946255570Strasz int *errp; 947255570Strasz struct hostent *hp = NULL; 948255570Strasz 949255570Strasz addr = va_arg(ap, const void *); 950255570Strasz addrlen = va_arg(ap, int); 951255570Strasz af = va_arg(ap, int); 952255570Strasz 953255570Strasz if (af == AF_INET) { 954255570Strasz hp = _gethostbynisaddr(addr, addrlen, af); 955255570Strasz if (hp != NULL) 956255570Strasz hp = _hpcopy(hp, errp); 957255570Strasz } 958255570Strasz *(struct hostent **)rval = hp; 959255570Strasz return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND; 960255570Strasz} 961255570Strasz#endif 962255570Strasz 963255570Straszstruct __res_type_list { 964255570Strasz SLIST_ENTRY(__res_type_list) rtl_entry; 965256229Strasz int rtl_type; 966255570Strasz}; 967256229Strasz 968256229Strasz#if PACKETSZ > 1024 969255570Strasz#define MAXPACKET PACKETSZ 970255570Strasz#else 971255570Strasz#define MAXPACKET 1024 972255570Strasz#endif 973255570Strasz 974256229Strasztypedef union { 975255570Strasz HEADER hdr; 976255570Strasz u_char buf[MAXPACKET]; 977255570Strasz} querybuf; 978255570Strasz 979255570Straszstatic struct hostent *getanswer __P((const querybuf *, int, const char *, 980255570Strasz int, struct hostent *, int *)); 981256238Strasz 982256238Strasz/* 983256238Strasz * we don't need to take care about sorting, nor IPv4 mapped address here. 984256238Strasz */ 985256238Straszstatic struct hostent * 986256238Straszgetanswer(answer, anslen, qname, qtype, template, errp) 987256238Strasz const querybuf *answer; 988256238Strasz int anslen; 989256238Strasz const char *qname; 990256238Strasz int qtype; 991256238Strasz struct hostent *template; 992256238Strasz int *errp; 993256238Strasz{ 994256238Strasz const HEADER *hp; 995256238Strasz const u_char *cp; 996256238Strasz int n; 997256238Strasz const u_char *eom, *erdata; 998256238Strasz char *bp, **ap, **hap; 999256238Strasz int type, class, buflen, ancount, qdcount; 1000256238Strasz int haveanswer, had_error; 1001256238Strasz char tbuf[MAXDNAME]; 1002256238Strasz const char *tname; 1003256238Strasz int (*name_ok) __P((const char *)); 1004256238Strasz static char *h_addr_ptrs[MAXADDRS + 1]; 1005256238Strasz static char *host_aliases[MAXALIASES]; 1006256238Strasz static char hostbuf[8*1024]; 1007256238Strasz 1008256238Strasz#define BOUNDED_INCR(x) \ 1009256238Strasz do { \ 1010256238Strasz cp += x; \ 1011255570Strasz if (cp > eom) { \ 1012256238Strasz *errp = NO_RECOVERY; \ 1013255570Strasz return (NULL); \ 1014255570Strasz } \ 1015255570Strasz } while (0) 1016256238Strasz 1017256238Strasz#define BOUNDS_CHECK(ptr, count) \ 1018255570Strasz do { \ 1019255570Strasz if ((ptr) + (count) > eom) { \ 1020255570Strasz *errp = NO_RECOVERY; \ 1021255570Strasz return (NULL); \ 1022255570Strasz } \ 1023255570Strasz } while (0) 1024255570Strasz 1025255570Strasz/* XXX do {} while (0) cannot be put here */ 1026255570Strasz#define DNS_ASSERT(x) \ 1027255570Strasz { \ 1028255570Strasz if (!(x)) { \ 1029255570Strasz cp += n; \ 1030255570Strasz continue; \ 1031255570Strasz } \ 1032255570Strasz } 1033255570Strasz 1034255570Strasz/* XXX do {} while (0) cannot be put here */ 1035255570Strasz#define DNS_FATAL(x) \ 1036255570Strasz { \ 1037255570Strasz if (!(x)) { \ 1038255570Strasz had_error++; \ 1039255570Strasz continue; \ 1040255570Strasz } \ 1041255570Strasz } 1042255570Strasz 1043255570Strasz tname = qname; 1044255570Strasz template->h_name = NULL; 1045255570Strasz eom = answer->buf + anslen; 1046255570Strasz switch (qtype) { 1047255570Strasz case T_A: 1048255570Strasz case T_AAAA: 1049255570Strasz name_ok = res_hnok; 1050255570Strasz break; 1051255570Strasz case T_PTR: 1052255570Strasz name_ok = res_dnok; 1053255570Strasz break; 1054255570Strasz default: 1055255570Strasz return (NULL); /* XXX should be abort(); */ 1056255570Strasz } 1057255570Strasz /* 1058255570Strasz * find first satisfactory answer 1059255570Strasz */ 1060255570Strasz hp = &answer->hdr; 1061255570Strasz ancount = ntohs(hp->ancount); 1062255570Strasz qdcount = ntohs(hp->qdcount); 1063255570Strasz bp = hostbuf; 1064255570Strasz buflen = sizeof hostbuf; 1065255570Strasz cp = answer->buf; 1066255570Strasz BOUNDED_INCR(HFIXEDSZ); 1067256229Strasz if (qdcount != 1) { 1068255570Strasz *errp = NO_RECOVERY; 1069256229Strasz return (NULL); 1070256229Strasz } 1071256229Strasz n = dn_expand(answer->buf, eom, cp, bp, buflen); 1072256229Strasz if ((n < 0) || !(*name_ok)(bp)) { 1073256229Strasz *errp = NO_RECOVERY; 1074256229Strasz return (NULL); 1075256229Strasz } 1076256229Strasz BOUNDED_INCR(n + QFIXEDSZ); 1077255570Strasz if (qtype == T_A || qtype == T_AAAA) { 1078256229Strasz /* res_send() has already verified that the query name is the 1079256229Strasz * same as the one we sent; this just gets the expanded name 1080256229Strasz * (i.e., with the succeeding search-domain tacked on). 1081256229Strasz */ 1082256229Strasz n = strlen(bp) + 1; /* for the \0 */ 1083256229Strasz if (n >= MAXHOSTNAMELEN) { 1084256229Strasz *errp = NO_RECOVERY; 1085255570Strasz return (NULL); 1086255570Strasz } 1087255570Strasz template->h_name = bp; 1088255570Strasz bp += n; 1089255570Strasz buflen -= n; 1090255570Strasz /* The qname can be abbreviated, but h_name is now absolute. */ 1091255570Strasz qname = template->h_name; 1092255570Strasz } 1093255570Strasz ap = host_aliases; 1094255570Strasz *ap = NULL; 1095256229Strasz template->h_aliases = host_aliases; 1096256229Strasz hap = h_addr_ptrs; 1097255570Strasz *hap = NULL; 1098255570Strasz template->h_addr_list = h_addr_ptrs; 1099255570Strasz haveanswer = 0; 1100255570Strasz had_error = 0; 1101255570Strasz while (ancount-- > 0 && cp < eom && !had_error) { 1102255570Strasz n = dn_expand(answer->buf, eom, cp, bp, buflen); 1103255570Strasz DNS_FATAL(n >= 0); 1104255570Strasz DNS_FATAL((*name_ok)(bp)); 1105255570Strasz cp += n; /* name */ 1106255570Strasz BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ); 1107255570Strasz type = _getshort(cp); 1108255570Strasz cp += INT16SZ; /* type */ 1109255570Strasz class = _getshort(cp); 1110255570Strasz cp += INT16SZ + INT32SZ; /* class, TTL */ 1111255570Strasz n = _getshort(cp); 1112255570Strasz cp += INT16SZ; /* len */ 1113255570Strasz BOUNDS_CHECK(cp, n); 1114255570Strasz erdata = cp + n; 1115255570Strasz DNS_ASSERT(class == C_IN); 1116255570Strasz if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) { 1117255570Strasz if (ap >= &host_aliases[MAXALIASES-1]) 1118255570Strasz continue; 1119256229Strasz n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); 1120256229Strasz DNS_FATAL(n >= 0); 1121255570Strasz DNS_FATAL((*name_ok)(tbuf)); 1122256229Strasz cp += n; 1123256229Strasz if (cp != erdata) { 1124255570Strasz *errp = NO_RECOVERY; 1125255570Strasz return (NULL); 1126255570Strasz } 1127255570Strasz /* Store alias. */ 1128255570Strasz *ap++ = bp; 1129255570Strasz n = strlen(bp) + 1; /* for the \0 */ 1130255570Strasz DNS_FATAL(n < MAXHOSTNAMELEN); 1131255570Strasz bp += n; 1132255570Strasz buflen -= n; 1133255570Strasz /* Get canonical name. */ 1134255570Strasz n = strlen(tbuf) + 1; /* for the \0 */ 1135255570Strasz DNS_FATAL(n <= buflen); 1136255570Strasz DNS_FATAL(n < MAXHOSTNAMELEN); 1137255570Strasz strcpy(bp, tbuf); 1138255570Strasz template->h_name = bp; 1139255570Strasz bp += n; 1140255570Strasz buflen -= n; 1141255570Strasz continue; 1142255570Strasz } 1143255570Strasz if (qtype == T_PTR && type == T_CNAME) { 1144255570Strasz n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); 1145255570Strasz if (n < 0 || !res_dnok(tbuf)) { 1146255570Strasz had_error++; 1147255570Strasz continue; 1148255570Strasz } 1149255570Strasz cp += n; 1150255570Strasz if (cp != erdata) { 1151255570Strasz *errp = NO_RECOVERY; 1152255570Strasz return (NULL); 1153255570Strasz } 1154255570Strasz /* Get canonical name. */ 1155255570Strasz n = strlen(tbuf) + 1; /* for the \0 */ 1156255570Strasz if (n > buflen || n >= MAXHOSTNAMELEN) { 1157255570Strasz had_error++; 1158255570Strasz continue; 1159255570Strasz } 1160255570Strasz strcpy(bp, tbuf); 1161255570Strasz tname = bp; 1162255570Strasz bp += n; 1163255570Strasz buflen -= n; 1164255570Strasz continue; 1165255570Strasz } 1166255570Strasz DNS_ASSERT(type == qtype); 1167255570Strasz switch (type) { 1168255570Strasz case T_PTR: 1169255570Strasz DNS_ASSERT(strcasecmp(tname, bp) == 0); 1170255570Strasz n = dn_expand(answer->buf, eom, cp, bp, buflen); 1171255570Strasz DNS_FATAL(n >= 0); 1172255570Strasz DNS_FATAL(res_hnok(bp)); 1173255570Strasz#if MULTI_PTRS_ARE_ALIASES 1174255570Strasz cp += n; 1175255570Strasz if (cp != erdata) { 1176255570Strasz *errp = NO_RECOVERY; 1177255570Strasz return (NULL); 1178255570Strasz } 1179255570Strasz if (!haveanswer) 1180255570Strasz template->h_name = bp; 1181255570Strasz else if (ap < &host_aliases[MAXALIASES-1]) 1182255570Strasz *ap++ = bp; 1183255570Strasz else 1184255570Strasz n = -1; 1185255570Strasz if (n != -1) { 1186255570Strasz n = strlen(bp) + 1; /* for the \0 */ 1187255570Strasz if (n >= MAXHOSTNAMELEN) { 1188255570Strasz had_error++; 1189255570Strasz break; 1190255570Strasz } 1191255570Strasz bp += n; 1192255570Strasz buflen -= n; 1193255570Strasz } 1194255570Strasz break; 1195255570Strasz#else 1196255570Strasz template->h_name = bp; 1197255570Strasz *errp = NETDB_SUCCESS; 1198255570Strasz return (template); 1199255570Strasz#endif 1200255570Strasz case T_A: 1201255570Strasz case T_AAAA: 1202255570Strasz DNS_ASSERT(strcasecmp(template->h_name, bp) == 0); 1203255570Strasz DNS_ASSERT(n == template->h_length); 1204255570Strasz if (!haveanswer) { 1205265521Strasz int nn; 1206255570Strasz 1207255570Strasz template->h_name = bp; 1208265521Strasz nn = strlen(bp) + 1; /* for the \0 */ 1209255570Strasz bp += nn; 1210255570Strasz buflen -= nn; 1211255570Strasz } 1212255570Strasz bp = (char *)ALIGN(bp); 1213255570Strasz 1214255570Strasz DNS_FATAL(bp + n < &hostbuf[sizeof hostbuf]); 1215255570Strasz DNS_ASSERT(hap < &h_addr_ptrs[MAXADDRS-1]); 1216255570Strasz#ifdef FILTER_V4MAPPED 1217255570Strasz if (type == T_AAAA) { 1218255570Strasz struct in6_addr in6; 1219255570Strasz memcpy(&in6, cp, sizeof(in6)); 1220255570Strasz DNS_ASSERT(IN6_IS_ADDR_V4MAPPED(&in6) == 0); 1221255570Strasz } 1222255570Strasz#endif 1223255570Strasz bcopy(cp, *hap++ = bp, n); 1224255570Strasz bp += n; 1225255570Strasz buflen -= n; 1226255570Strasz cp += n; 1227255570Strasz if (cp != erdata) { 1228255570Strasz *errp = NO_RECOVERY; 1229255570Strasz return (NULL); 1230255570Strasz } 1231255570Strasz break; 1232255570Strasz default: 1233255570Strasz abort(); 1234255570Strasz } 1235255570Strasz if (!had_error) 1236255570Strasz haveanswer++; 1237255570Strasz } 1238255570Strasz if (haveanswer) { 1239255570Strasz *ap = NULL; 1240255570Strasz *hap = NULL; 1241255570Strasz if (!template->h_name) { 1242255570Strasz n = strlen(qname) + 1; /* for the \0 */ 1243255570Strasz if (n > buflen || n >= MAXHOSTNAMELEN) 1244255570Strasz goto no_recovery; 1245255570Strasz strcpy(bp, qname); 1246255570Strasz template->h_name = bp; 1247255570Strasz bp += n; 1248255570Strasz buflen -= n; 1249255570Strasz } 1250255570Strasz *errp = NETDB_SUCCESS; 1251255570Strasz return (template); 1252255570Strasz } 1253255570Strasz no_recovery: 1254255570Strasz *errp = NO_RECOVERY; 1255255570Strasz return (NULL); 1256255570Strasz 1257255570Strasz#undef BOUNDED_INCR 1258255570Strasz#undef BOUNDS_CHECK 1259255570Strasz#undef DNS_ASSERT 1260255570Strasz#undef DNS_FATAL 1261255570Strasz} 1262255570Strasz 1263259306Strasz/* res_search() variant with multiple query support. */ 1264259306Straszstatic struct hostent * 1265259306Strasz_res_search_multi(name, rtl, errp) 1266259306Strasz const char *name; /* domain name */ 1267259306Strasz struct __res_type_list *rtl; /* list of query types */ 1268259306Strasz int *errp; 1269259306Strasz{ 1270259306Strasz const char *cp, * const *domain; 1271259306Strasz struct hostent *hp0 = NULL, *hp; 1272259306Strasz struct hostent hpbuf; 1273259306Strasz u_int dots; 1274259306Strasz int trailing_dot, ret, saved_herrno; 1275255570Strasz int got_nodata = 0, got_servfail = 0, tried_as_is = 0; 1276255570Strasz struct __res_type_list *rtl0 = rtl; 1277255570Strasz querybuf buf; 1278255570Strasz 1279255570Strasz if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 1280255570Strasz *errp = NETDB_INTERNAL; 1281255570Strasz return (NULL); 1282255570Strasz } 1283255570Strasz dots = 0; 1284255570Strasz for (cp = name; *cp; cp++) 1285255570Strasz dots += (*cp == '.'); 1286255570Strasz trailing_dot = 0; 1287255570Strasz if (cp > name && *--cp == '.') 1288255570Strasz trailing_dot++; 1289255570Strasz 1290255570Strasz /* If there aren't any dots, it could be a user-level alias */ 1291255570Strasz if (!dots && (cp = hostalias(name)) != NULL) { 1292255570Strasz for(rtl = rtl0; rtl != NULL; 1293255570Strasz rtl = SLIST_NEXT(rtl, rtl_entry)) { 1294255570Strasz ret = res_query(cp, C_IN, rtl->rtl_type, buf.buf, 1295255570Strasz sizeof(buf.buf)); 1296265487Strasz if (ret > 0) { 1297265487Strasz hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA) 1298255570Strasz ? AF_INET6 : AF_INET; 1299255570Strasz hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype); 1300255570Strasz hp = getanswer(&buf, ret, name, rtl->rtl_type, 1301255570Strasz &hpbuf, errp); 1302255570Strasz if (!hp) 1303255570Strasz continue; 1304255570Strasz hp = _hpcopy(&hpbuf, errp); 1305255570Strasz hp0 = _hpmerge(hp0, hp, errp); 1306265526Strasz } 1307265526Strasz } 1308265526Strasz return (hp0); 1309265526Strasz } 1310265526Strasz 1311265526Strasz /* 1312265526Strasz * If there are dots in the name already, let's just give it a try 1313265526Strasz * 'as is'. The threshold can be set with the "ndots" option. 1314265526Strasz */ 1315265526Strasz saved_herrno = -1; 1316265526Strasz if (dots >= _res.ndots) { 1317265526Strasz for(rtl = rtl0; rtl != NULL; 1318265526Strasz rtl = SLIST_NEXT(rtl, rtl_entry)) { 1319255570Strasz ret = res_querydomain(name, NULL, C_IN, rtl->rtl_type, 1320255570Strasz buf.buf, sizeof(buf.buf)); 1321255570Strasz if (ret > 0) { 1322255570Strasz hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA) 1323255570Strasz ? AF_INET6 : AF_INET; 1324255570Strasz hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype); 1325255570Strasz hp = getanswer(&buf, ret, name, rtl->rtl_type, 1326255570Strasz &hpbuf, errp); 1327255570Strasz if (!hp) 1328255570Strasz continue; 1329255570Strasz hp = _hpcopy(&hpbuf, errp); 1330255570Strasz hp0 = _hpmerge(hp0, hp, errp); 1331255570Strasz } 1332255570Strasz } 1333255570Strasz if (hp0 != NULL) 1334255570Strasz return (hp0); 1335255570Strasz saved_herrno = *errp; 1336255570Strasz tried_as_is++; 1337255570Strasz } 1338255570Strasz 1339255570Strasz /* 1340255570Strasz * We do at least one level of search if 1341255570Strasz * - there is no dot and RES_DEFNAME is set, or 1342255570Strasz * - there is at least one dot, there is no trailing dot, 1343255570Strasz * and RES_DNSRCH is set. 1344255570Strasz */ 1345255570Strasz if ((!dots && (_res.options & RES_DEFNAMES)) || 1346255570Strasz (dots && !trailing_dot && (_res.options & RES_DNSRCH))) { 1347255570Strasz int done = 0; 1348255570Strasz 1349255570Strasz for (domain = (const char * const *)_res.dnsrch; 1350255570Strasz *domain && !done; 1351255570Strasz domain++) { 1352255570Strasz 1353255570Strasz for(rtl = rtl0; rtl != NULL; 1354255570Strasz rtl = SLIST_NEXT(rtl, rtl_entry)) { 1355255570Strasz ret = res_querydomain(name, *domain, C_IN, 1356255570Strasz rtl->rtl_type, 1357255570Strasz buf.buf, sizeof(buf.buf)); 1358255570Strasz if (ret > 0) { 1359255570Strasz hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA) 1360255570Strasz ? AF_INET6 : AF_INET; 1361255570Strasz hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype); 1362255570Strasz hp = getanswer(&buf, ret, name, 1363255570Strasz rtl->rtl_type, &hpbuf, errp); 1364255570Strasz if (!hp) 1365255570Strasz continue; 1366255570Strasz hp = _hpcopy(&hpbuf, errp); 1367255570Strasz hp0 = _hpmerge(hp0, hp, errp); 1368255570Strasz } 1369255570Strasz } 1370255570Strasz if (hp0 != NULL) 1371255570Strasz return (hp0); 1372255570Strasz 1373255570Strasz /* 1374255570Strasz * If no server present, give up. 1375255570Strasz * If name isn't found in this domain, 1376255570Strasz * keep trying higher domains in the search list 1377255570Strasz * (if that's enabled). 1378255570Strasz * On a NO_DATA error, keep trying, otherwise 1379255570Strasz * a wildcard entry of another type could keep us 1380255570Strasz * from finding this entry higher in the domain. 1381255570Strasz * If we get some other error (negative answer or 1382255570Strasz * server failure), then stop searching up, 1383255570Strasz * but try the input name below in case it's 1384255570Strasz * fully-qualified. 1385255570Strasz */ 1386255570Strasz if (errno == ECONNREFUSED) { 1387255570Strasz *errp = TRY_AGAIN; 1388255570Strasz return (NULL); 1389255570Strasz } 1390255570Strasz 1391255570Strasz switch (*errp) { 1392255570Strasz case NO_DATA: 1393255570Strasz got_nodata++; 1394255570Strasz /* FALLTHROUGH */ 1395255570Strasz case HOST_NOT_FOUND: 1396255570Strasz /* keep trying */ 1397255570Strasz break; 1398255570Strasz case TRY_AGAIN: 1399255570Strasz if (buf.hdr.rcode == SERVFAIL) { 1400255570Strasz /* try next search element, if any */ 1401255570Strasz got_servfail++; 1402255570Strasz break; 1403255570Strasz } 1404255570Strasz /* FALLTHROUGH */ 1405255570Strasz default: 1406255570Strasz /* anything else implies that we're done */ 1407255570Strasz done++; 1408255570Strasz } 1409255570Strasz 1410255570Strasz /* if we got here for some reason other than DNSRCH, 1411255570Strasz * we only wanted one iteration of the loop, so stop. 1412255570Strasz */ 1413255570Strasz if (!(_res.options & RES_DNSRCH)) 1414255570Strasz done++; 1415255570Strasz } 1416255570Strasz } 1417255570Strasz 1418255570Strasz /* 1419255570Strasz * If we have not already tried the name "as is", do that now. 1420255570Strasz * note that we do this regardless of how many dots were in the 1421255570Strasz * name or whether it ends with a dot unless NOTLDQUERY is set. 1422255570Strasz */ 1423255570Strasz if (!tried_as_is && (dots || !(_res.options & RES_NOTLDQUERY))) { 1424255570Strasz for(rtl = rtl0; rtl != NULL; 1425255570Strasz rtl = SLIST_NEXT(rtl, rtl_entry)) { 1426255570Strasz ret = res_querydomain(name, NULL, C_IN, rtl->rtl_type, 1427255570Strasz buf.buf, sizeof(buf.buf)); 1428255570Strasz if (ret > 0) { 1429265526Strasz hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA) 1430265526Strasz ? AF_INET6 : AF_INET; 1431265526Strasz hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype); 1432255570Strasz hp = getanswer(&buf, ret, name, rtl->rtl_type, 1433265526Strasz &hpbuf, errp); 1434255570Strasz if (!hp) 1435255570Strasz continue; 1436255570Strasz hp = _hpcopy(&hpbuf, errp); 1437255570Strasz hp0 = _hpmerge(hp0, hp, errp); 1438255570Strasz } 1439265526Strasz } 1440265526Strasz if (hp0 != NULL) 1441255570Strasz return (hp0); 1442255570Strasz } 1443255570Strasz 1444255570Strasz /* if we got here, we didn't satisfy the search. 1445255570Strasz * if we did an initial full query, return that query's h_errno 1446255570Strasz * (note that we wouldn't be here if that query had succeeded). 1447255570Strasz * else if we ever got a nodata, send that back as the reason. 1448255570Strasz * else send back meaningless h_errno, that being the one from 1449255570Strasz * the last DNSRCH we did. 1450255570Strasz */ 1451255570Strasz if (saved_herrno != -1) 1452255570Strasz *errp = saved_herrno; 1453255570Strasz else if (got_nodata) 1454255570Strasz *errp = NO_DATA; 1455255570Strasz else if (got_servfail) 1456255570Strasz *errp = TRY_AGAIN; 1457255570Strasz return (NULL); 1458255570Strasz} 1459255570Strasz 1460255570Straszstatic int 1461255570Strasz_dns_ghbyname(void *rval, void *cb_data, va_list ap) 1462255570Strasz{ 1463255570Strasz const char *name; 1464255570Strasz int af; 1465255570Strasz int *errp; 1466255570Strasz struct __res_type_list *rtl, rtl4; 1467255570Strasz#ifdef INET6 1468255570Strasz struct __res_type_list rtl6; 1469255570Strasz#endif 1470255570Strasz 1471255570Strasz name = va_arg(ap, const char *); 1472255570Strasz af = va_arg(ap, int); 1473255570Strasz errp = va_arg(ap, int *); 1474255570Strasz 1475255570Strasz#ifdef INET6 1476255570Strasz switch (af) { 1477255570Strasz case AF_UNSPEC: 1478255570Strasz SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A; 1479255570Strasz SLIST_NEXT(&rtl6, rtl_entry) = &rtl4; rtl6.rtl_type = T_AAAA; 1480255570Strasz rtl = &rtl6; 1481255570Strasz break; 1482255570Strasz case AF_INET6: 1483255570Strasz SLIST_NEXT(&rtl6, rtl_entry) = NULL; rtl6.rtl_type = T_AAAA; 1484255570Strasz rtl = &rtl6; 1485255570Strasz break; 1486255570Strasz case AF_INET: 1487255570Strasz SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A; 1488255570Strasz rtl = &rtl4; 1489255570Strasz break; 1490255570Strasz } 1491255570Strasz#else 1492255570Strasz SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A; 1493255570Strasz rtl = &rtl4; 1494255570Strasz#endif 1495255570Strasz *(struct hostent **)rval = _res_search_multi(name, rtl, errp); 1496255570Strasz return (*(struct hostent **)rval != NULL) ? NS_SUCCESS : NS_NOTFOUND; 1497255570Strasz} 1498255570Strasz 1499255570Straszstatic int 1500255570Strasz_dns_ghbyaddr(void *rval, void *cb_data, va_list ap) 1501255570Strasz{ 1502255570Strasz const void *addr; 1503255570Strasz int addrlen; 1504255570Strasz int af; 1505255570Strasz int *errp; 1506255570Strasz int n; 1507255570Strasz struct hostent *hp; 1508255570Strasz u_char c, *cp; 1509255570Strasz char *bp; 1510255570Strasz struct hostent hbuf; 1511255570Strasz int na; 1512255570Strasz#ifdef INET6 1513255570Strasz static const char hex[] = "0123456789abcdef"; 1514255570Strasz#endif 1515255570Strasz querybuf buf; 1516255570Strasz char qbuf[MAXDNAME+1]; 1517255570Strasz char *hlist[2]; 1518255570Strasz 1519255570Strasz addr = va_arg(ap, const void *); 1520255570Strasz addrlen = va_arg(ap, int); 1521255570Strasz af = va_arg(ap, int); 1522255570Strasz errp = va_arg(ap, int *); 1523255570Strasz 1524255570Strasz *(struct hostent **)rval = NULL; 1525255570Strasz 1526255570Strasz#ifdef INET6 1527255570Strasz /* XXX */ 1528255570Strasz if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr)) 1529255570Strasz return NS_NOTFOUND; 1530255570Strasz#endif 1531255570Strasz 1532255570Strasz if ((_res.options & RES_INIT) == 0) { 1533255570Strasz if (res_init() < 0) { 1534255570Strasz *errp = h_errno; 1535255570Strasz return NS_UNAVAIL; 1536255570Strasz } 1537255570Strasz } 1538255570Strasz memset(&hbuf, 0, sizeof(hbuf)); 1539255570Strasz hbuf.h_name = NULL; 1540255570Strasz hbuf.h_addrtype = af; 1541255570Strasz hbuf.h_length = addrlen; 1542255570Strasz na = 0; 1543255570Strasz 1544255570Strasz /* XXX assumes that MAXDNAME is big enough */ 1545255570Strasz n = 0; 1546255570Strasz bp = qbuf; 1547255570Strasz cp = (u_char *)addr+addrlen-1; 1548255570Strasz switch (af) { 1549255570Strasz#ifdef INET6 1550255570Strasz case AF_INET6: 1551255570Strasz for (; n < addrlen; n++, cp--) { 1552255570Strasz c = *cp; 1553255570Strasz *bp++ = hex[c & 0xf]; 1554255570Strasz *bp++ = '.'; 1555255570Strasz *bp++ = hex[c >> 4]; 1556255570Strasz *bp++ = '.'; 1557255570Strasz } 1558255570Strasz strcpy(bp, "ip6.int"); 1559255570Strasz break; 1560255570Strasz#endif 1561255570Strasz default: 1562255570Strasz for (; n < addrlen; n++, cp--) { 1563255570Strasz c = *cp; 1564255570Strasz if (c >= 100) 1565255570Strasz *bp++ = '0' + c / 100; 1566255570Strasz if (c >= 10) 1567255570Strasz *bp++ = '0' + (c % 100) / 10; 1568255570Strasz *bp++ = '0' + c % 10; 1569255570Strasz *bp++ = '.'; 1570255570Strasz } 1571255570Strasz strcpy(bp, "in-addr.arpa"); 1572255570Strasz break; 1573255570Strasz } 1574255570Strasz 1575255570Strasz n = res_query(qbuf, C_IN, T_PTR, buf.buf, sizeof buf.buf); 1576255570Strasz if (n < 0) { 1577255570Strasz *errp = h_errno; 1578255570Strasz return NS_UNAVAIL; 1579255570Strasz } 1580255570Strasz hp = getanswer(&buf, n, qbuf, T_PTR, &hbuf, errp); 1581255570Strasz if (!hp) 1582255570Strasz return NS_NOTFOUND; 1583255570Strasz hbuf.h_addrtype = af; 1584255570Strasz hbuf.h_length = addrlen; 1585255570Strasz hbuf.h_addr_list = hlist; 1586255570Strasz hlist[0] = (char *)addr; 1587255570Strasz hlist[1] = NULL; 1588255570Strasz *(struct hostent **)rval = _hpcopy(&hbuf, errp); 1589255570Strasz return NS_SUCCESS; 1590255570Strasz} 1591255570Strasz 1592255570Straszstatic void 1593255570Strasz_dns_shent(int stayopen) 1594255570Strasz{ 1595255570Strasz if ((_res.options & RES_INIT) == 0) { 1596255570Strasz if (res_init() < 0) 1597255570Strasz return; 1598255570Strasz } 1599255570Strasz if (stayopen) 1600255570Strasz _res.options |= RES_STAYOPEN | RES_USEVC; 1601255570Strasz} 1602255570Strasz 1603255570Straszstatic void 1604255678Strasz_dns_ehent(void) 1605255570Strasz{ 1606255570Strasz _res.options &= ~(RES_STAYOPEN | RES_USEVC); 1607255570Strasz res_close(); 1608255570Strasz} 1609255678Strasz 1610255678Strasz#ifdef ICMPNL 1611255678Strasz 1612255678Strasz/* 1613255678Strasz * experimental: 1614255678Strasz * draft-ietf-ipngwg-icmp-namelookups-02.txt 1615255570Strasz * ifindex is assumed to be encoded in addr. 1616255570Strasz */ 1617255570Strasz#include <sys/uio.h> 1618255570Strasz#include <netinet/ip6.h> 1619255570Strasz#include <netinet/icmp6.h> 1620255570Strasz 1621255678Straszstruct _icmp_host_cache { 1622255678Strasz struct _icmp_host_cache *hc_next; 1623255678Strasz int hc_ifindex; 1624255678Strasz struct in6_addr hc_addr; 1625255678Strasz char *hc_name; 1626255678Strasz}; 1627255678Strasz 1628255678Straszstatic char * 1629255678Strasz_icmp_fqdn_query(const struct in6_addr *addr, int ifindex) 1630255678Strasz{ 1631255678Strasz int s; 1632255678Strasz struct icmp6_filter filter; 1633255678Strasz struct msghdr msg; 1634255678Strasz struct cmsghdr *cmsg; 1635255678Strasz struct in6_pktinfo *pkt; 1636255678Strasz char cbuf[256]; 1637255570Strasz char buf[1024]; 1638255570Strasz int cc; 1639265496Strasz struct icmp6_fqdn_query *fq; 1640255570Strasz struct icmp6_fqdn_reply *fr; 1641255570Strasz struct _icmp_host_cache *hc; 1642255570Strasz struct sockaddr_in6 sin6; 1643255570Strasz struct iovec iov; 1644265500Strasz fd_set s_fds, fds; 1645255570Strasz struct timeval tout; 1646255570Strasz int len; 1647255570Strasz char *name; 1648255570Strasz static int pid; 1649255570Strasz static struct _icmp_host_cache *hc_head; 1650255570Strasz 1651255570Strasz for (hc = hc_head; hc; hc = hc->hc_next) { 1652255570Strasz if (hc->hc_ifindex == ifindex 1653255570Strasz && IN6_ARE_ADDR_EQUAL(&hc->hc_addr, addr)) 1654255570Strasz return hc->hc_name; 1655255570Strasz } 1656255570Strasz 1657255570Strasz if (pid == 0) 1658255570Strasz pid = getpid(); 1659255570Strasz 1660255570Strasz ICMP6_FILTER_SETBLOCKALL(&filter); 1661255570Strasz ICMP6_FILTER_SETPASS(ICMP6_FQDN_REPLY, &filter); 1662255570Strasz 1663255570Strasz FD_ZERO(&s_fds); 1664255570Strasz tout.tv_sec = 0; 1665255570Strasz tout.tv_usec = 200000; /*XXX: 200ms*/ 1666255570Strasz 1667265521Strasz fq = (struct icmp6_fqdn_query *)buf; 1668255570Strasz fq->icmp6_fqdn_type = ICMP6_FQDN_QUERY; 1669255570Strasz fq->icmp6_fqdn_code = 0; 1670265521Strasz fq->icmp6_fqdn_cksum = 0; 1671255570Strasz fq->icmp6_fqdn_id = (u_short)pid; 1672255570Strasz fq->icmp6_fqdn_unused = 0; 1673255570Strasz fq->icmp6_fqdn_cookie[0] = 0; 1674255570Strasz fq->icmp6_fqdn_cookie[1] = 0; 1675255570Strasz 1676255570Strasz memset(&sin6, 0, sizeof(sin6)); 1677255570Strasz sin6.sin6_family = AF_INET6; 1678255570Strasz sin6.sin6_addr = *addr; 1679255570Strasz 1680255570Strasz memset(&msg, 0, sizeof(msg)); 1681255570Strasz msg.msg_name = (caddr_t)&sin6; 1682255570Strasz msg.msg_namelen = sizeof(sin6); 1683255570Strasz msg.msg_iov = &iov; 1684255570Strasz msg.msg_iovlen = 1; 1685255570Strasz msg.msg_control = NULL; 1686255570Strasz msg.msg_controllen = 0; 1687255570Strasz iov.iov_base = (caddr_t)buf; 1688255570Strasz iov.iov_len = sizeof(struct icmp6_fqdn_query); 1689255570Strasz 1690255570Strasz if (ifindex) { 1691255570Strasz msg.msg_control = cbuf; 1692255570Strasz msg.msg_controllen = sizeof(cbuf); 1693255570Strasz cmsg = CMSG_FIRSTHDR(&msg); 1694255570Strasz cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 1695255570Strasz cmsg->cmsg_level = IPPROTO_IPV6; 1696255570Strasz cmsg->cmsg_type = IPV6_PKTINFO; 1697255570Strasz pkt = (struct in6_pktinfo *)&cmsg[1]; 1698255570Strasz memset(&pkt->ipi6_addr, 0, sizeof(struct in6_addr)); 1699255570Strasz pkt->ipi6_ifindex = ifindex; 1700255570Strasz cmsg = CMSG_NXTHDR(&msg, cmsg); 1701255570Strasz msg.msg_controllen = (char *)cmsg - cbuf; 1702255570Strasz } 1703255570Strasz 1704255570Strasz if ((s = _socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) 1705255570Strasz return NULL; 1706255570Strasz (void)_setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, 1707255570Strasz (char *)&filter, sizeof(filter)); 1708255570Strasz cc = _sendmsg(s, &msg, 0); 1709255570Strasz if (cc < 0) { 1710255570Strasz _close(s); 1711255570Strasz return NULL; 1712255570Strasz } 1713255570Strasz FD_SET(s, &s_fds); 1714255570Strasz for (;;) { 1715255570Strasz fds = s_fds; 1716255570Strasz if (_select(s + 1, &fds, NULL, NULL, &tout) <= 0) { 1717255570Strasz _close(s); 1718255570Strasz return NULL; 1719255570Strasz } 1720255570Strasz len = sizeof(sin6); 1721255570Strasz cc = _recvfrom(s, buf, sizeof(buf), 0, 1722255570Strasz (struct sockaddr *)&sin6, &len); 1723255570Strasz if (cc <= 0) { 1724255570Strasz _close(s); 1725255570Strasz return NULL; 1726255570Strasz } 1727255570Strasz if (cc < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr)) 1728255570Strasz continue; 1729255570Strasz if (!IN6_ARE_ADDR_EQUAL(addr, &sin6.sin6_addr)) 1730255570Strasz continue; 1731255570Strasz fr = (struct icmp6_fqdn_reply *)(buf + sizeof(struct ip6_hdr)); 1732255570Strasz if (fr->icmp6_fqdn_type == ICMP6_FQDN_REPLY) 1733255570Strasz break; 1734255570Strasz } 1735255570Strasz _close(s); 1736255570Strasz if (fr->icmp6_fqdn_cookie[1] != 0) { 1737255570Strasz /* rfc1788 type */ 1738255570Strasz name = buf + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + 4; 1739255570Strasz len = (buf + cc) - name; 1740255570Strasz } else { 1741255570Strasz len = fr->icmp6_fqdn_namelen; 1742255570Strasz name = fr->icmp6_fqdn_name; 1743255570Strasz } 1744255570Strasz if (len <= 0) 1745255570Strasz return NULL; 1746255570Strasz name[len] = 0; 1747255570Strasz 1748255570Strasz if ((hc = (struct _icmp_host_cache *)malloc(sizeof(*hc))) == NULL) 1749255570Strasz return NULL; 1750255570Strasz /* XXX: limit number of cached entries */ 1751255570Strasz hc->hc_ifindex = ifindex; 1752255570Strasz hc->hc_addr = *addr; 1753255570Strasz hc->hc_name = strdup(name); 1754255570Strasz hc->hc_next = hc_head; 1755255570Strasz hc_head = hc; 1756255570Strasz return hc->hc_name; 1757255570Strasz} 1758255570Strasz 1759255570Straszstatic struct hostent * 1760255570Strasz_icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp) 1761255570Strasz{ 1762255570Strasz char *hname; 1763255570Strasz int ifindex; 1764255570Strasz struct in6_addr addr6; 1765255570Strasz 1766255570Strasz if (af != AF_INET6) { 1767255570Strasz /* 1768255570Strasz * Note: rfc1788 defines Who Are You for IPv4, 1769255570Strasz * but no one implements it. 1770255570Strasz */ 1771255570Strasz return NULL; 1772255570Strasz } 1773255570Strasz 1774255570Strasz memcpy(&addr6, addr, addrlen); 1775255570Strasz ifindex = (addr6.s6_addr[2] << 8) | addr6.s6_addr[3]; 1776255570Strasz addr6.s6_addr[2] = addr6.s6_addr[3] = 0; 1777255570Strasz 1778255570Strasz if (!IN6_IS_ADDR_LINKLOCAL(&addr6)) 1779255570Strasz return NULL; /*XXX*/ 1780255570Strasz 1781255570Strasz if ((hname = _icmp_fqdn_query(&addr6, ifindex)) == NULL) 1782255570Strasz return NULL; 1783255570Strasz return _hpaddr(af, hname, &addr6, errp); 1784255570Strasz} 1785255570Strasz#endif /* ICMPNL */ 1786255570Strasz