📄 gethostent.c
字号:
/* * 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. */#if !defined(LINT) && !defined(CODECENTER)static const char rcsid[] = "$Id: gethostent.c,v 1.1.2.2.4.2 2004/03/17 01:49:40 marka Exp $";#endif/* Imports */#include "port_before.h"#if !defined(__BIND_NOSTATIC)#include <sys/types.h>#include <sys/param.h>#include <sys/socket.h>#include <sys/ioctl.h>#include <netinet/in.h>#include <net/if.h>#include <arpa/inet.h>#include <arpa/nameser.h>#include <ctype.h>#include <errno.h>#include <stdlib.h>#include <netdb.h>#include <resolv.h>#include <stdio.h>#include <string.h>#include <unistd.h>#include <irs.h>#include <isc/memcluster.h>#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 *);/* 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));}voidsethostent(int stayopen) { struct net_data *net_data = init(); sethostent_p(stayopen, net_data);}voidendhostent() { 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); net_data->ho_last = (*ho->byname2)(ho, name, af); 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);}voidsethostent_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);}voidendhostent_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_V4COMPATstatic 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))#endifstatic 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. */ if (src == NULL) { *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));}voidfreehostent(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#endifstatic voidscan_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. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -