/* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* Imports */ #include "port_before.h" #if !defined(__BIND_NOSTATIC) #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "port_after.h" #include "irs_p.h" #include "irs_data.h" /* Definitions */ struct pvt { char * aliases[1]; char * addrs[2]; char addr[NS_IN6ADDRSZ]; char name[NS_MAXDNAME + 1]; struct hostent host; }; /* Forward */ static struct net_data *init(void); static void freepvt(struct net_data *); static struct hostent *fakeaddr(const char *, int, struct net_data *); #ifdef SUNW_OVERRIDE_RETRY extern int __res_retry(int); extern int __res_retry_reset(void); #endif /* SUNW_OVERRIDE_RETRY */ /* Public */ struct hostent * gethostbyname(const char *name) { struct net_data *net_data = init(); return (gethostbyname_p(name, net_data)); } struct hostent * gethostbyname2(const char *name, int af) { struct net_data *net_data = init(); return (gethostbyname2_p(name, af, net_data)); } struct hostent * gethostbyaddr(const char *addr, int len, int af) { struct net_data *net_data = init(); return (gethostbyaddr_p(addr, len, af, net_data)); } struct hostent * gethostent() { struct net_data *net_data = init(); return (gethostent_p(net_data)); } void sethostent(int stayopen) { struct net_data *net_data = init(); sethostent_p(stayopen, net_data); } void endhostent() { struct net_data *net_data = init(); endhostent_p(net_data); } /* Shared private. */ struct hostent * gethostbyname_p(const char *name, struct net_data *net_data) { struct hostent *hp; if (!net_data) return (NULL); if (net_data->res->options & RES_USE_INET6) { hp = gethostbyname2_p(name, AF_INET6, net_data); if (hp) return (hp); } return (gethostbyname2_p(name, AF_INET, net_data)); } struct hostent * gethostbyname2_p(const char *name, int af, struct net_data *net_data) { struct irs_ho *ho; char tmp[NS_MAXDNAME]; struct hostent *hp; const char *cp; char **hap; if (!net_data || !(ho = net_data->ho)) return (NULL); if (net_data->ho_stayopen && net_data->ho_last && net_data->ho_last->h_addrtype == af) { if (ns_samename(name, net_data->ho_last->h_name) == 1) return (net_data->ho_last); for (hap = net_data->ho_last->h_aliases; hap && *hap; hap++) if (ns_samename(name, *hap) == 1) return (net_data->ho_last); } if (!strchr(name, '.') && (cp = res_hostalias(net_data->res, name, tmp, sizeof tmp))) name = cp; if ((hp = fakeaddr(name, af, net_data)) != NULL) return (hp); #ifdef SUNW_OVERRIDE_RETRY net_data->res->retry = __res_retry(net_data->res->retry); #endif /* SUNW_OVERRIDE_RETRY */ net_data->ho_last = (*ho->byname2)(ho, name, af); #ifdef SUNW_OVERRIDE_RETRY net_data->res->retry = __res_retry_reset(); #endif /* SUNW_OVERRIDE_RETRY */ if (!net_data->ho_stayopen) endhostent(); return (net_data->ho_last); } struct hostent * gethostbyaddr_p(const char *addr, int len, int af, struct net_data *net_data) { struct irs_ho *ho; char **hap; if (!net_data || !(ho = net_data->ho)) return (NULL); if (net_data->ho_stayopen && net_data->ho_last && net_data->ho_last->h_length == len) for (hap = net_data->ho_last->h_addr_list; hap && *hap; hap++) if (!memcmp(addr, *hap, len)) return (net_data->ho_last); net_data->ho_last = (*ho->byaddr)(ho, addr, len, af); if (!net_data->ho_stayopen) endhostent(); return (net_data->ho_last); } struct hostent * gethostent_p(struct net_data *net_data) { struct irs_ho *ho; struct hostent *hp; if (!net_data || !(ho = net_data->ho)) return (NULL); while ((hp = (*ho->next)(ho)) != NULL && hp->h_addrtype == AF_INET6 && (net_data->res->options & RES_USE_INET6) == 0U) continue; net_data->ho_last = hp; return (net_data->ho_last); } void sethostent_p(int stayopen, struct net_data *net_data) { struct irs_ho *ho; if (!net_data || !(ho = net_data->ho)) return; freepvt(net_data); (*ho->rewind)(ho); net_data->ho_stayopen = (stayopen != 0); if (stayopen == 0) net_data_minimize(net_data); } void endhostent_p(struct net_data *net_data) { struct irs_ho *ho; if ((net_data != NULL) && ((ho = net_data->ho) != NULL)) (*ho->minimize)(ho); } #ifndef IN6_IS_ADDR_V4COMPAT static const unsigned char in6addr_compat[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; #define IN6_IS_ADDR_V4COMPAT(x) (!memcmp((x)->s6_addr, in6addr_compat, 12) && \ ((x)->s6_addr[12] != 0 || \ (x)->s6_addr[13] != 0 || \ (x)->s6_addr[14] != 0 || \ ((x)->s6_addr[15] != 0 && \ (x)->s6_addr[15] != 1))) #endif #ifndef IN6_IS_ADDR_V4MAPPED #define IN6_IS_ADDR_V4MAPPED(x) (!memcmp((x)->s6_addr, in6addr_mapped, 12)) #endif static const unsigned char in6addr_mapped[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff }; static int scan_interfaces(int *, int *); static struct hostent *copyandmerge(struct hostent *, struct hostent *, int, int *); /*% * Public functions */ /*% * AI_V4MAPPED + AF_INET6 * If no IPv6 address then a query for IPv4 and map returned values. * * AI_ALL + AI_V4MAPPED + AF_INET6 * Return IPv6 and IPv4 mapped. * * AI_ADDRCONFIG * Only return IPv6 / IPv4 address if there is an interface of that * type active. */ struct hostent * getipnodebyname(const char *name, int af, int flags, int *error_num) { int have_v4 = 1, have_v6 = 1; struct in_addr in4; struct in6_addr in6; struct hostent he, *he1 = NULL, *he2 = NULL, *he3; int v4 = 0, v6 = 0; struct net_data *net_data = init(); u_long options; int tmp_err; if (net_data == NULL) { *error_num = NO_RECOVERY; return (NULL); } /* If we care about active interfaces then check. */ if ((flags & AI_ADDRCONFIG) != 0) if (scan_interfaces(&have_v4, &have_v6) == -1) { *error_num = NO_RECOVERY; return (NULL); } /* Check for literal address. */ if ((v4 = inet_pton(AF_INET, name, &in4)) != 1) v6 = inet_pton(AF_INET6, name, &in6); /* Impossible combination? */ if ((af == AF_INET6 && (flags & AI_V4MAPPED) == 0 && v4 == 1) || (af == AF_INET && v6 == 1) || (have_v4 == 0 && v4 == 1) || (have_v6 == 0 && v6 == 1) || (have_v4 == 0 && af == AF_INET) || (have_v6 == 0 && af == AF_INET6)) { *error_num = HOST_NOT_FOUND; return (NULL); } /* Literal address? */ if (v4 == 1 || v6 == 1) { char *addr_list[2]; char *aliases[1]; DE_CONST(name, he.h_name); he.h_addr_list = addr_list; he.h_addr_list[0] = (v4 == 1) ? (char *)&in4 : (char *)&in6; he.h_addr_list[1] = NULL; he.h_aliases = aliases; he.h_aliases[0] = NULL; he.h_length = (v4 == 1) ? INADDRSZ : IN6ADDRSZ; he.h_addrtype = (v4 == 1) ? AF_INET : AF_INET6; return (copyandmerge(&he, NULL, af, error_num)); } options = net_data->res->options; net_data->res->options &= ~RES_USE_INET6; tmp_err = NO_RECOVERY; if (have_v6 && af == AF_INET6) { he2 = gethostbyname2_p(name, AF_INET6, net_data); if (he2 != NULL) { he1 = copyandmerge(he2, NULL, af, error_num); if (he1 == NULL) return (NULL); he2 = NULL; } else { tmp_err = net_data->res->res_h_errno; } } if (have_v4 && ((af == AF_INET) || (af == AF_INET6 && (flags & AI_V4MAPPED) != 0 && (he1 == NULL || (flags & AI_ALL) != 0)))) { he2 = gethostbyname2_p(name, AF_INET, net_data); if (he1 == NULL && he2 == NULL) { *error_num = net_data->res->res_h_errno; return (NULL); } } else *error_num = tmp_err; net_data->res->options = options; he3 = copyandmerge(he1, he2, af, error_num); if (he1 != NULL) freehostent(he1); return (he3); } struct hostent * getipnodebyaddr(const void *src, size_t len, int af, int *error_num) { struct hostent *he1, *he2; struct net_data *net_data = init(); /* Sanity Checks. */ #ifdef ORIGINAL_ISC_CODE if (src == NULL) { #else /* this change was added circa May 2009, but not in ISC libbind 6.0 */ if (src == NULL|| net_data == NULL) { #endif /* ORIGINAL_ISC_CODE */ *error_num = NO_RECOVERY; return (NULL); } switch (af) { case AF_INET: if (len != (size_t)INADDRSZ) { *error_num = NO_RECOVERY; return (NULL); } break; case AF_INET6: if (len != (size_t)IN6ADDRSZ) { *error_num = NO_RECOVERY; return (NULL); } break; default: *error_num = NO_RECOVERY; return (NULL); } /* * Lookup IPv4 and IPv4 mapped/compatible addresses */ if ((af == AF_INET6 && IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)src)) || (af == AF_INET6 && IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)src)) || (af == AF_INET)) { const char *cp = src; if (af == AF_INET6) cp += 12; he1 = gethostbyaddr_p(cp, 4, AF_INET, net_data); if (he1 == NULL) { *error_num = net_data->res->res_h_errno; return (NULL); } he2 = copyandmerge(he1, NULL, af, error_num); if (he2 == NULL) return (NULL); /* * Restore original address if mapped/compatible. */ if (af == AF_INET6) memcpy(he1->h_addr, src, len); return (he2); } /* * Lookup IPv6 address. */ if (memcmp((const struct in6_addr *)src, &in6addr_any, 16) == 0) { *error_num = HOST_NOT_FOUND; return (NULL); } he1 = gethostbyaddr_p(src, 16, AF_INET6, net_data); if (he1 == NULL) { *error_num = net_data->res->res_h_errno; return (NULL); } return (copyandmerge(he1, NULL, af, error_num)); } void freehostent(struct hostent *he) { char **cpp; int names = 1; int addresses = 1; memput(he->h_name, strlen(he->h_name) + 1); cpp = he->h_addr_list; while (*cpp != NULL) { memput(*cpp, (he->h_addrtype == AF_INET) ? INADDRSZ : IN6ADDRSZ); *cpp = NULL; cpp++; addresses++; } cpp = he->h_aliases; while (*cpp != NULL) { memput(*cpp, strlen(*cpp) + 1); cpp++; names++; } memput(he->h_aliases, sizeof(char *) * (names)); memput(he->h_addr_list, sizeof(char *) * (addresses)); memput(he, sizeof *he); } /*% * Private */ /*% * Scan the interface table and set have_v4 and have_v6 depending * upon whether there are IPv4 and IPv6 interface addresses. * * Returns: * 0 on success * -1 on failure. */ #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \ !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF) #ifdef __hpux #define lifc_len iflc_len #define lifc_buf iflc_buf #define lifc_req iflc_req #define LIFCONF if_laddrconf #else #define SETFAMILYFLAGS #define LIFCONF lifconf #endif #ifdef __hpux #define lifr_addr iflr_addr #define lifr_name iflr_name #define lifr_dstaddr iflr_dstaddr #define lifr_flags iflr_flags #define ss_family sa_family #define LIFREQ if_laddrreq #else #define LIFREQ lifreq #endif static void scan_interfaces6(int *have_v4, int *have_v6) { struct LIFCONF lifc; struct LIFREQ lifreq; struct in_addr in4; struct in6_addr in6; char *buf = NULL, *cp, *cplim; static unsigned int bufsiz = 4095; int s, cpsize, n; /* Get interface list from system. */ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) == -1) goto cleanup; /* * Grow buffer until large enough to contain all interface * descriptions. */ for (;;) { buf = memget(bufsiz); if (buf == NULL) goto cleanup; #ifdef SETFAMILYFLAGS lifc.lifc_family = AF_UNSPEC; /*%< request all families */ lifc.lifc_flags = 0; #endif lifc.lifc_len = bufsiz; lifc.lifc_buf = buf; if ((n = ioctl(s, SIOCGLIFCONF, (char *)&lifc)) != -1) { /* * Some OS's just return what will fit rather * than set EINVAL if the buffer is too small * to fit all the interfaces in. If * lifc.lifc_len is too near to the end of the * buffer we will grow it just in case and * retry. */ if (lifc.lifc_len + 2 * sizeof(lifreq) < bufsiz) break; } if ((n == -1) && errno != EINVAL) goto cleanup; if (bufsiz > 1000000) goto cleanup; memput(buf, bufsiz); bufsiz += 4096; } /* Parse system's interface list. */ cplim = buf + lifc.lifc_len; /*%< skip over if's with big ifr_addr's */ for (cp = buf; (*have_v4 == 0 || *have_v6 == 0) && cp < cplim; cp += cpsize) { memcpy(&lifreq, cp, sizeof lifreq); #ifdef HAVE_SA_LEN #ifdef FIX_ZERO_SA_LEN if (lifreq.lifr_addr.sa_len == 0) lifreq.lifr_addr.sa_len = 16; #endif #ifdef HAVE_MINIMUM_IFREQ cpsize = sizeof lifreq; if (lifreq.lifr_addr.sa_len > sizeof (struct sockaddr)) cpsize += (int)lifreq.lifr_addr.sa_len - (int)(sizeof (struct sockaddr)); #else cpsize = sizeof lifreq.lifr_name + lifreq.lifr_addr.sa_len; #endif /* HAVE_MINIMUM_IFREQ */ #elif defined SIOCGIFCONF_ADDR cpsize = sizeof lifreq; #else cpsize = sizeof lifreq.lifr_name; /* XXX maybe this should be a hard error? */ if (ioctl(s, SIOCGLIFADDR, (char *)&lifreq) < 0) continue; #endif switch (lifreq.lifr_addr.ss_family) { case AF_INET: if (*have_v4 == 0) { memcpy(&in4, &((struct sockaddr_in *) &lifreq.lifr_addr)->sin_addr, sizeof in4); if (in4.s_addr == INADDR_ANY) break; n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq); if (n < 0) break; if ((lifreq.lifr_flags & IFF_UP) == 0) break; *have_v4 = 1; } break; case AF_INET6: if (*have_v6 == 0) { memcpy(&in6, &((struct sockaddr_in6 *) &lifreq.lifr_addr)->sin6_addr, sizeof in6); if (memcmp(&in6, &in6addr_any, sizeof in6) == 0) break; n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq); if (n < 0) break; if ((lifreq.lifr_flags & IFF_UP) == 0) break; *have_v6 = 1; } break; } } if (buf != NULL) memput(buf, bufsiz); close(s); /* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */ return; cleanup: if (buf != NULL) memput(buf, bufsiz); if (s != -1) close(s); /* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */ return; } #endif #if ( defined(__linux__) || defined(__linux) || defined(LINUX) ) #ifndef IF_NAMESIZE # ifdef IFNAMSIZ # define IF_NAMESIZE IFNAMSIZ # else # define IF_NAMESIZE 16 # endif #endif static void scan_linux6(int *have_v6) { FILE *proc = NULL; char address[33]; char name[IF_NAMESIZE+1]; int ifindex, prefix, flag3, flag4; proc = fopen("/proc/net/if_inet6", "r"); if (proc == NULL) return; if (fscanf(proc, "%32[a-f0-9] %x %x %x %x %16s\n", address, &ifindex, &prefix, &flag3, &flag4, name) == 6) *have_v6 = 1; fclose(proc); return; } #endif static int scan_interfaces(int *have_v4, int *have_v6) { struct ifconf ifc; union { char _pad[256]; /*%< leave space for IPv6 addresses */ struct ifreq ifreq; } u; struct in_addr in4; struct in6_addr in6; char *buf = NULL, *cp, *cplim; static unsigned int bufsiz = 4095; int s, n; size_t cpsize; /* Set to zero. Used as loop terminators below. */ *have_v4 = *have_v6 = 0; #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \ !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF) /* * Try to scan the interfaces using IPv6 ioctls(). */ scan_interfaces6(have_v4, have_v6); if (*have_v4 != 0 && *have_v6 != 0) return (0); #endif #ifdef __linux scan_linux6(have_v6); #endif /* Get interface list from system. */ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) goto err_ret; /* * Grow buffer until large enough to contain all interface * descriptions. */ for (;;) { buf = memget(bufsiz); if (buf == NULL) goto err_ret; ifc.ifc_len = bufsiz; ifc.ifc_buf = buf; #ifdef IRIX_EMUL_IOCTL_SIOCGIFCONF /* * This is a fix for IRIX OS in which the call to ioctl with * the flag SIOCGIFCONF may not return an entry for all the * interfaces like most flavors of Unix. */ if (emul_ioctl(&ifc) >= 0) break; #else if ((n = ioctl(s, SIOCGIFCONF, (char *)&ifc)) != -1) { /* * Some OS's just return what will fit rather * than set EINVAL if the buffer is too small * to fit all the interfaces in. If * ifc.ifc_len is too near to the end of the * buffer we will grow it just in case and * retry. */ if (ifc.ifc_len + 2 * sizeof(u.ifreq) < bufsiz) break; } #endif if ((n == -1) && errno != EINVAL) goto err_ret; if (bufsiz > 1000000) goto err_ret; memput(buf, bufsiz); bufsiz += 4096; } /* Parse system's interface list. */ cplim = buf + ifc.ifc_len; /*%< skip over if's with big ifr_addr's */ for (cp = buf; (*have_v4 == 0 || *have_v6 == 0) && cp < cplim; cp += cpsize) { memcpy(&u.ifreq, cp, sizeof u.ifreq); #ifdef HAVE_SA_LEN #ifdef FIX_ZERO_SA_LEN if (u.ifreq.ifr_addr.sa_len == 0) u.ifreq.ifr_addr.sa_len = 16; #endif #ifdef HAVE_MINIMUM_IFREQ cpsize = sizeof u.ifreq; if (u.ifreq.ifr_addr.sa_len > sizeof (struct sockaddr)) cpsize += (int)u.ifreq.ifr_addr.sa_len - (int)(sizeof (struct sockaddr)); #else cpsize = sizeof u.ifreq.ifr_name + u.ifreq.ifr_addr.sa_len; #endif /* HAVE_MINIMUM_IFREQ */ if (cpsize > sizeof u.ifreq && cpsize <= sizeof u) memcpy(&u.ifreq, cp, cpsize); #elif defined SIOCGIFCONF_ADDR cpsize = sizeof u.ifreq; #else cpsize = sizeof u.ifreq.ifr_name; /* XXX maybe this should be a hard error? */ if (ioctl(s, SIOCGIFADDR, (char *)&u.ifreq) < 0) continue; #endif switch (u.ifreq.ifr_addr.sa_family) { case AF_INET: if (*have_v4 == 0) { memcpy(&in4, &((struct sockaddr_in *) &u.ifreq.ifr_addr)->sin_addr, sizeof in4); if (in4.s_addr == INADDR_ANY) break; n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq); if (n < 0) break; if ((u.ifreq.ifr_flags & IFF_UP) == 0) break; *have_v4 = 1; } break; case AF_INET6: if (*have_v6 == 0) { memcpy(&in6, &((struct sockaddr_in6 *) &u.ifreq.ifr_addr)->sin6_addr, sizeof in6); if (memcmp(&in6, &in6addr_any, sizeof in6) == 0) break; n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq); if (n < 0) break; if ((u.ifreq.ifr_flags & IFF_UP) == 0) break; *have_v6 = 1; } break; } } if (buf != NULL) memput(buf, bufsiz); close(s); /* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */ return (0); err_ret: if (buf != NULL) memput(buf, bufsiz); if (s != -1) close(s); /* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */ return (-1); } static struct hostent * copyandmerge(struct hostent *he1, struct hostent *he2, int af, int *error_num) { struct hostent *he = NULL; int addresses = 1; /*%< NULL terminator */ int names = 1; /*%< NULL terminator */ int len = 0; char **cpp, **npp; /* * Work out array sizes; */ if (he1 != NULL) { cpp = he1->h_addr_list; while (*cpp != NULL) { addresses++; cpp++; } cpp = he1->h_aliases; while (*cpp != NULL) { names++; cpp++; } } if (he2 != NULL) { cpp = he2->h_addr_list; while (*cpp != NULL) { addresses++; cpp++; } if (he1 == NULL) { cpp = he2->h_aliases; while (*cpp != NULL) { names++; cpp++; } } } if (addresses == 1) { *error_num = NO_ADDRESS; return (NULL); } he = memget(sizeof *he); if (he == NULL) goto no_recovery; he->h_addr_list = memget(sizeof(char *) * (addresses)); if (he->h_addr_list == NULL) goto cleanup0; memset(he->h_addr_list, 0, sizeof(char *) * (addresses)); /* copy addresses */ npp = he->h_addr_list; if (he1 != NULL) { cpp = he1->h_addr_list; while (*cpp != NULL) { *npp = memget((af == AF_INET) ? INADDRSZ : IN6ADDRSZ); if (*npp == NULL) goto cleanup1; /* convert to mapped if required */ if (af == AF_INET6 && he1->h_addrtype == AF_INET) { memcpy(*npp, in6addr_mapped, sizeof in6addr_mapped); memcpy(*npp + sizeof in6addr_mapped, *cpp, INADDRSZ); } else { memcpy(*npp, *cpp, (af == AF_INET) ? INADDRSZ : IN6ADDRSZ); } cpp++; npp++; } } if (he2 != NULL) { cpp = he2->h_addr_list; while (*cpp != NULL) { *npp = memget((af == AF_INET) ? INADDRSZ : IN6ADDRSZ); if (*npp == NULL) goto cleanup1; /* convert to mapped if required */ if (af == AF_INET6 && he2->h_addrtype == AF_INET) { memcpy(*npp, in6addr_mapped, sizeof in6addr_mapped); memcpy(*npp + sizeof in6addr_mapped, *cpp, INADDRSZ); } else { memcpy(*npp, *cpp, (af == AF_INET) ? INADDRSZ : IN6ADDRSZ); } cpp++; npp++; } } he->h_aliases = memget(sizeof(char *) * (names)); if (he->h_aliases == NULL) goto cleanup1; memset(he->h_aliases, 0, sizeof(char *) * (names)); /* copy aliases */ npp = he->h_aliases; cpp = (he1 != NULL) ? he1->h_aliases : he2->h_aliases; while (*cpp != NULL) { len = strlen (*cpp) + 1; *npp = memget(len); if (*npp == NULL) goto cleanup2; strcpy(*npp, *cpp); npp++; cpp++; } /* copy hostname */ he->h_name = memget(strlen((he1 != NULL) ? he1->h_name : he2->h_name) + 1); if (he->h_name == NULL) goto cleanup2; strcpy(he->h_name, (he1 != NULL) ? he1->h_name : he2->h_name); /* set address type and length */ he->h_addrtype = af; he->h_length = (af == AF_INET) ? INADDRSZ : IN6ADDRSZ; return(he); cleanup2: cpp = he->h_aliases; while (*cpp != NULL) { memput(*cpp, strlen(*cpp) + 1); cpp++; } memput(he->h_aliases, sizeof(char *) * (names)); cleanup1: cpp = he->h_addr_list; while (*cpp != NULL) { memput(*cpp, (af == AF_INET) ? INADDRSZ : IN6ADDRSZ); *cpp = NULL; cpp++; } memput(he->h_addr_list, sizeof(char *) * (addresses)); cleanup0: memput(he, sizeof *he); no_recovery: *error_num = NO_RECOVERY; return (NULL); } static struct net_data * init() { struct net_data *net_data; if (!(net_data = net_data_init(NULL))) goto error; if (!net_data->ho) { net_data->ho = (*net_data->irs->ho_map)(net_data->irs); if (!net_data->ho || !net_data->res) { error: errno = EIO; #ifdef SUNW_SETHERRNO h_errno = NETDB_INTERNAL; #endif /* SUNW_SETHERRNO */ if (net_data && net_data->res) RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL); return (NULL); } (*net_data->ho->res_set)(net_data->ho, net_data->res, NULL); } return (net_data); } static void freepvt(struct net_data *net_data) { if (net_data->ho_data) { free(net_data->ho_data); net_data->ho_data = NULL; } } static struct hostent * fakeaddr(const char *name, int af, struct net_data *net_data) { struct pvt *pvt; freepvt(net_data); net_data->ho_data = malloc(sizeof (struct pvt)); if (!net_data->ho_data) { errno = ENOMEM; RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL); return (NULL); } pvt = net_data->ho_data; #ifndef __bsdi__ /* * Unlike its forebear(inet_aton), our friendly inet_pton() is strict * in its interpretation of its input, and it will only return "1" if * the input string is a formally valid(and thus unambiguous with * respect to host names) internet address specification for this AF. * * This means "telnet 0xdeadbeef" and "telnet 127.1" are dead now. */ if (inet_pton(af, name, pvt->addr) != 1) { #else /* BSDI XXX * We put this back to inet_aton -- we really want the old behavior * Long live 127.1... */ if ((af != AF_INET || inet_aton(name, (struct in_addr *)pvt->addr) != 1) && inet_pton(af, name, pvt->addr) != 1) { #endif RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND); return (NULL); } strncpy(pvt->name, name, NS_MAXDNAME); pvt->name[NS_MAXDNAME] = '\0'; if (af == AF_INET && (net_data->res->options & RES_USE_INET6) != 0U) { map_v4v6_address(pvt->addr, pvt->addr); af = AF_INET6; } pvt->host.h_addrtype = af; switch(af) { case AF_INET: pvt->host.h_length = NS_INADDRSZ; break; case AF_INET6: pvt->host.h_length = NS_IN6ADDRSZ; break; default: errno = EAFNOSUPPORT; RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL); return (NULL); } pvt->host.h_name = pvt->name; pvt->host.h_aliases = pvt->aliases; pvt->aliases[0] = NULL; pvt->addrs[0] = (char *)pvt->addr; pvt->addrs[1] = NULL; pvt->host.h_addr_list = pvt->addrs; RES_SET_H_ERRNO(net_data->res, NETDB_SUCCESS); return (&pvt->host); } #ifdef grot /*%< for future use in gethostbyaddr(), for "SUNSECURITY" */ struct hostent *rhp; char **haddr; u_long old_options; char hname2[MAXDNAME+1]; if (af == AF_INET) { /* * turn off search as the name should be absolute, * 'localhost' should be matched by defnames */ strncpy(hname2, hp->h_name, MAXDNAME); hname2[MAXDNAME] = '\0'; old_options = net_data->res->options; net_data->res->options &= ~RES_DNSRCH; net_data->res->options |= RES_DEFNAMES; if (!(rhp = gethostbyname(hname2))) { net_data->res->options = old_options; RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND); return (NULL); } net_data->res->options = old_options; for (haddr = rhp->h_addr_list; *haddr; haddr++) if (!memcmp(*haddr, addr, INADDRSZ)) break; if (!*haddr) { RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND); return (NULL); } } #endif /* grot */ #endif /*__BIND_NOSTATIC*/ /*! \file */