📄 dns_ho.c
字号:
/* * Copyright (c) 1985, 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. *//* * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") * Portions 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. *//* from gethostnamadr.c 8.1 (Berkeley) 6/4/93 *//* BIND Id: gethnamaddr.c,v 8.15 1996/05/22 04:56:30 vixie Exp $ */#if defined(LIBC_SCCS) && !defined(lint)static const char rcsid[] = "$Id: dns_ho.c,v 1.5.2.7.4.5 2004/08/24 00:32:15 marka Exp $";#endif /* LIBC_SCCS and not lint *//* Imports. */#include "port_before.h"#include <sys/types.h>#include <sys/param.h>#include <sys/socket.h>#include <netinet/in.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 <syslog.h>#include <isc/memcluster.h>#include <irs.h>#include "port_after.h"#include "irs_p.h"#include "dns_p.h"#ifdef SPRINTF_CHAR# define SPRINTF(x) strlen(sprintf/**/x)#else# define SPRINTF(x) sprintf x#endif/* Definitions. */#define MAXALIASES 35#define MAXADDRS 35#define MAXPACKET (65535) /* Maximum TCP message size */#define BOUNDS_CHECK(ptr, count) \ if ((ptr) + (count) > eom) { \ had_error++; \ continue; \ } else (void)0typedef union { HEADER hdr; u_char buf[MAXPACKET];} querybuf;struct dns_res_target { struct dns_res_target *next; querybuf qbuf; /* query buffer */ u_char *answer; /* buffer to put answer */ int anslen; /* size of answer buffer */ int qclass, qtype; /* class and type of query */ int action; /* condition whether query is really issued */ char qname[MAXDNAME +1]; /* domain name */#if 0 int n; /* result length */#endif};enum {RESTGT_DOALWAYS, RESTGT_AFTERFAILURE, RESTGT_IGNORE};enum {RESQRY_SUCCESS, RESQRY_FAIL};struct pvt { struct hostent host; char * h_addr_ptrs[MAXADDRS + 1]; char * host_aliases[MAXALIASES]; char hostbuf[8*1024]; u_char host_addr[16]; /* IPv4 or IPv6 */ struct __res_state *res; void (*free_res)(void *);};typedef union { int32_t al; char ac;} align;static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };/* Note: the IPv6 loopback address is in the "tunnel" space */static const u_char v6local[] = { 0,0, 0,1 }; /* last 4 bytes of IPv6 addr *//* Forwards. */static void ho_close(struct irs_ho *this);static struct hostent * ho_byname(struct irs_ho *this, const char *name);static struct hostent * ho_byname2(struct irs_ho *this, const char *name, int af);static struct hostent * ho_byaddr(struct irs_ho *this, const void *addr, int len, int af);static struct hostent * ho_next(struct irs_ho *this);static void ho_rewind(struct irs_ho *this);static void ho_minimize(struct irs_ho *this);static struct __res_state * ho_res_get(struct irs_ho *this);static void ho_res_set(struct irs_ho *this, struct __res_state *res, void (*free_res)(void *));static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai);static void map_v4v6_hostent(struct hostent *hp, char **bp, char *ep);static void addrsort(res_state, char **, int);static struct hostent * gethostans(struct irs_ho *this, const u_char *ansbuf, int anslen, const char *qname, int qtype, int af, int size, struct addrinfo **ret_aip, const struct addrinfo *pai);static int add_hostent(struct pvt *pvt, char *bp, char **hap, struct addrinfo *ai);static int init(struct irs_ho *this);/* Exports. */struct irs_ho *irs_dns_ho(struct irs_acc *this) { struct irs_ho *ho; struct pvt *pvt; UNUSED(this); if (!(pvt = memget(sizeof *pvt))) { errno = ENOMEM; return (NULL); } memset(pvt, 0, sizeof *pvt); if (!(ho = memget(sizeof *ho))) { memput(pvt, sizeof *pvt); errno = ENOMEM; return (NULL); } memset(ho, 0x5e, sizeof *ho); ho->private = pvt; ho->close = ho_close; ho->byname = ho_byname; ho->byname2 = ho_byname2; ho->byaddr = ho_byaddr; ho->next = ho_next; ho->rewind = ho_rewind; ho->minimize = ho_minimize; ho->res_get = ho_res_get; ho->res_set = ho_res_set; ho->addrinfo = ho_addrinfo; return (ho);}/* Methods. */static voidho_close(struct irs_ho *this) { struct pvt *pvt = (struct pvt *)this->private; ho_minimize(this); if (pvt->res && pvt->free_res) (*pvt->free_res)(pvt->res); if (pvt) memput(pvt, sizeof *pvt); memput(this, sizeof *this);}static struct hostent *ho_byname(struct irs_ho *this, const char *name) { struct pvt *pvt = (struct pvt *)this->private; struct hostent *hp; if (init(this) == -1) return (NULL); if (pvt->res->options & RES_USE_INET6) { hp = ho_byname2(this, name, AF_INET6); if (hp) return (hp); } return (ho_byname2(this, name, AF_INET));}static struct hostent *ho_byname2(struct irs_ho *this, const char *name, int af){ struct pvt *pvt = (struct pvt *)this->private; struct hostent *hp = NULL; int n, size; char tmp[NS_MAXDNAME]; const char *cp; struct addrinfo ai; struct dns_res_target *q, *p; int querystate = RESQRY_FAIL; if (init(this) == -1) return (NULL); q = memget(sizeof(*q)); if (q == NULL) { RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); errno = ENOMEM; goto cleanup; } memset(q, 0, sizeof(q)); switch (af) { case AF_INET: size = INADDRSZ; q->qclass = C_IN; q->qtype = T_A; q->answer = q->qbuf.buf; q->anslen = sizeof(q->qbuf); q->action = RESTGT_DOALWAYS; break; case AF_INET6: size = IN6ADDRSZ; q->qclass = C_IN; q->qtype = T_AAAA; q->answer = q->qbuf.buf; q->anslen = sizeof(q->qbuf); q->action = RESTGT_DOALWAYS; break; default: RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); errno = EAFNOSUPPORT; hp = NULL; goto cleanup; } /* * if there aren't any dots, it could be a user-level alias. * this is also done in res_nquery() since we are not the only * function that looks up host names. */ if (!strchr(name, '.') && (cp = res_hostalias(pvt->res, name, tmp, sizeof tmp))) name = cp; for (p = q; p; p = p->next) { switch(p->action) { case RESTGT_DOALWAYS: break; case RESTGT_AFTERFAILURE: if (querystate == RESQRY_SUCCESS) continue; break; case RESTGT_IGNORE: continue; } if ((n = res_nsearch(pvt->res, name, p->qclass, p->qtype, p->answer, p->anslen)) < 0) { querystate = RESQRY_FAIL; continue; } memset(&ai, 0, sizeof(ai)); ai.ai_family = af; if ((hp = gethostans(this, p->answer, n, name, p->qtype, af, size, NULL, (const struct addrinfo *)&ai)) != NULL) goto cleanup; /* no more loop is necessary */ querystate = RESQRY_FAIL; continue; } cleanup: if (q != NULL) memput(q, sizeof(*q)); return(hp);}static struct hostent *ho_byaddr(struct irs_ho *this, const void *addr, int len, int af){ struct pvt *pvt = (struct pvt *)this->private; const u_char *uaddr = addr; char *qp; struct hostent *hp = NULL; struct addrinfo ai; struct dns_res_target *q, *q2, *p; int n, size, i; int querystate = RESQRY_FAIL; if (init(this) == -1) return (NULL); q = memget(sizeof(*q)); q2 = memget(sizeof(*q2)); if (q == NULL || q2 == NULL) { RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); errno = ENOMEM; goto cleanup; } memset(q, 0, sizeof(q)); memset(q2, 0, sizeof(q2)); if (af == AF_INET6 && len == IN6ADDRSZ && (!memcmp(uaddr, mapped, sizeof mapped) || (!memcmp(uaddr, tunnelled, sizeof tunnelled) && memcmp(&uaddr[sizeof tunnelled], v6local, sizeof(v6local))))) { /* Unmap. */ addr = (const char *)addr + sizeof mapped; uaddr += sizeof mapped; af = AF_INET; len = INADDRSZ; } switch (af) { case AF_INET: size = INADDRSZ; q->qclass = C_IN; q->qtype = T_PTR; q->answer = q->qbuf.buf; q->anslen = sizeof(q->qbuf); q->action = RESTGT_DOALWAYS; break; case AF_INET6: size = IN6ADDRSZ; q->qclass = C_IN; q->qtype = T_PTR; q->answer = q->qbuf.buf; q->anslen = sizeof(q->qbuf); q->next = q2; q->action = RESTGT_DOALWAYS; q2->qclass = C_IN; q2->qtype = T_PTR; q2->answer = q2->qbuf.buf; q2->anslen = sizeof(q2->qbuf); if ((pvt->res->options & RES_NO_NIBBLE2) != 0U) q2->action = RESTGT_IGNORE; else q2->action = RESTGT_AFTERFAILURE; break; default: errno = EAFNOSUPPORT; RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); hp = NULL; goto cleanup; } if (size > len) { errno = EINVAL; RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); hp = NULL; goto cleanup; } switch (af) { case AF_INET: qp = q->qname; (void) sprintf(qp, "%u.%u.%u.%u.in-addr.arpa", (uaddr[3] & 0xff), (uaddr[2] & 0xff), (uaddr[1] & 0xff), (uaddr[0] & 0xff)); break; case AF_INET6: if (q->action != RESTGT_IGNORE) { const char *nibsuff = res_get_nibblesuffix(pvt->res); qp = q->qname; for (n = IN6ADDRSZ - 1; n >= 0; n--) { i = SPRINTF((qp, "%x.%x.", uaddr[n] & 0xf, (uaddr[n] >> 4) & 0xf)); if (i != 4) abort(); qp += i; } if (strlen(q->qname) + strlen(nibsuff) + 1 > sizeof q->qname) { errno = ENAMETOOLONG; RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); hp = NULL; goto cleanup; } strcpy(qp, nibsuff); /* (checked) */ } if (q2->action != RESTGT_IGNORE) { const char *nibsuff2 = res_get_nibblesuffix2(pvt->res); qp = q2->qname; for (n = IN6ADDRSZ - 1; n >= 0; n--) { i = SPRINTF((qp, "%x.%x.", uaddr[n] & 0xf, (uaddr[n] >> 4) & 0xf)); if (i != 4) abort(); qp += i; } if (strlen(q2->qname) + strlen(nibsuff2) + 1 > sizeof q2->qname) { errno = ENAMETOOLONG; RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); hp = NULL; goto cleanup; } strcpy(qp, nibsuff2); /* (checked) */ } break; default: abort(); } for (p = q; p; p = p->next) { switch(p->action) { case RESTGT_DOALWAYS: break; case RESTGT_AFTERFAILURE: if (querystate == RESQRY_SUCCESS) continue; break; case RESTGT_IGNORE: continue; } if ((n = res_nquery(pvt->res, p->qname, p->qclass, p->qtype, p->answer, p->anslen)) < 0) { querystate = RESQRY_FAIL; continue; } memset(&ai, 0, sizeof(ai)); ai.ai_family = af; hp = gethostans(this, p->answer, n, p->qname, T_PTR, af, size, NULL, (const struct addrinfo *)&ai); if (!hp) { querystate = RESQRY_FAIL; continue; } memcpy(pvt->host_addr, addr, len); pvt->h_addr_ptrs[0] = (char *)pvt->host_addr; pvt->h_addr_ptrs[1] = NULL; if (af == AF_INET && (pvt->res->options & RES_USE_INET6)) { map_v4v6_address((char*)pvt->host_addr, (char*)pvt->host_addr); pvt->host.h_addrtype = AF_INET6; pvt->host.h_length = IN6ADDRSZ; } RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS); goto cleanup; /* no more loop is necessary. */ } hp = NULL; /* H_ERRNO was set by subroutines */ cleanup: if (q != NULL) memput(q, sizeof(*q)); if (q2 != NULL) memput(q2, sizeof(*q2)); return(hp);}static struct hostent *ho_next(struct irs_ho *this) { UNUSED(this); return (NULL);}static voidho_rewind(struct irs_ho *this) { UNUSED(this); /* NOOP */}static voidho_minimize(struct irs_ho *this) { struct pvt *pvt = (struct pvt *)this->private; if (pvt->res) res_nclose(pvt->res);}static struct __res_state *ho_res_get(struct irs_ho *this) { struct pvt *pvt = (struct pvt *)this->private; if (!pvt->res) { struct __res_state *res; res = (struct __res_state *)malloc(sizeof *res); if (!res) { errno = ENOMEM; return (NULL); } memset(res, 0, sizeof *res); ho_res_set(this, res, free); } return (pvt->res);}/* XXX */extern struct addrinfo *addr2addrinfo __P((const struct addrinfo *, const char *));static struct addrinfo *ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai){ struct pvt *pvt = (struct pvt *)this->private; int n; char tmp[NS_MAXDNAME]; const char *cp; struct dns_res_target *q, *q2, *p; struct addrinfo sentinel, *cur; int querystate = RESQRY_FAIL; if (init(this) == -1) return (NULL); memset(&sentinel, 0, sizeof(sentinel)); cur = &sentinel; q = memget(sizeof(*q)); q2 = memget(sizeof(*q2)); if (q == NULL || q2 == NULL) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -