📄 res_send.c
字号:
/* * Copyright (c) 1985, 1989, 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. *//* * Portions Copyright (c) 1993 by Digital Equipment Corporation. * * 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, and that * the name of Digital Equipment Corporation not be used in advertising or * publicity pertaining to distribution of the document or software without * specific, written prior permission. * * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT * CORPORATION 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. *//* * 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. */#if defined(LIBC_SCCS) && !defined(lint)static const char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93";static const char rcsid[] = "$Id: res_send.c,v 1.5.2.2.4.5 2004/08/10 02:19:56 marka Exp $";#endif /* LIBC_SCCS and not lint *//* * Send query to name server and wait for reply. */#include "port_before.h"#include "fd_setsize.h"#include <sys/types.h>#include <sys/param.h>#include <sys/time.h>#include <sys/socket.h>#include <sys/uio.h>#include <netinet/in.h>#include <arpa/nameser.h>#include <arpa/inet.h>#include <errno.h>#include <netdb.h>#include <resolv.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <isc/eventlib.h>#include "port_after.h"/* Options. Leave them on. */#define DEBUG#include "res_debug.h"#include "res_private.h"#define EXT(res) ((res)->_u._ext)static const int highestFD = FD_SETSIZE - 1;/* Forward. */static int get_salen __P((const struct sockaddr *));static struct sockaddr * get_nsaddr __P((res_state, size_t));static int send_vc(res_state, const u_char *, int, u_char *, int, int *, int);static int send_dg(res_state, const u_char *, int, u_char *, int, int *, int, int *, int *);static void Aerror(const res_state, FILE *, const char *, int, const struct sockaddr *, int);static void Perror(const res_state, FILE *, const char *, int);static int sock_eq(struct sockaddr *, struct sockaddr *);#ifdef NEED_PSELECTstatic int pselect(int, void *, void *, void *, struct timespec *, const sigset_t *);#endifvoid res_pquery(const res_state, const u_char *, int, FILE *);static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;/* Public. *//* int * res_isourserver(ina) * looks up "ina" in _res.ns_addr_list[] * returns: * 0 : not found * >0 : found * author: * paul vixie, 29may94 */intres_ourserver_p(const res_state statp, const struct sockaddr *sa) { const struct sockaddr_in *inp, *srv; const struct sockaddr_in6 *in6p, *srv6; int ns; switch (sa->sa_family) { case AF_INET: inp = (const struct sockaddr_in *)sa; for (ns = 0; ns < statp->nscount; ns++) { srv = (struct sockaddr_in *)get_nsaddr(statp, ns); if (srv->sin_family == inp->sin_family && srv->sin_port == inp->sin_port && (srv->sin_addr.s_addr == INADDR_ANY || srv->sin_addr.s_addr == inp->sin_addr.s_addr)) return (1); } break; case AF_INET6: if (EXT(statp).ext == NULL) break; in6p = (const struct sockaddr_in6 *)sa; for (ns = 0; ns < statp->nscount; ns++) { srv6 = (struct sockaddr_in6 *)get_nsaddr(statp, ns); if (srv6->sin6_family == in6p->sin6_family && srv6->sin6_port == in6p->sin6_port &&#ifdef HAVE_SIN6_SCOPE_ID (srv6->sin6_scope_id == 0 || srv6->sin6_scope_id == in6p->sin6_scope_id) &&#endif (IN6_IS_ADDR_UNSPECIFIED(&srv6->sin6_addr) || IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr, &in6p->sin6_addr))) return (1); } break; default: break; } return (0);}/* int * res_nameinquery(name, type, class, buf, eom) * look for (name,type,class) in the query section of packet (buf,eom) * requires: * buf + HFIXEDSZ <= eom * returns: * -1 : format error * 0 : not found * >0 : found * author: * paul vixie, 29may94 */intres_nameinquery(const char *name, int type, int class, const u_char *buf, const u_char *eom){ const u_char *cp = buf + HFIXEDSZ; int qdcount = ntohs(((const HEADER*)buf)->qdcount); while (qdcount-- > 0) { char tname[MAXDNAME+1]; int n, ttype, tclass; n = dn_expand(buf, eom, cp, tname, sizeof tname); if (n < 0) return (-1); cp += n; if (cp + 2 * INT16SZ > eom) return (-1); ttype = ns_get16(cp); cp += INT16SZ; tclass = ns_get16(cp); cp += INT16SZ; if (ttype == type && tclass == class && ns_samename(tname, name) == 1) return (1); } return (0);}/* int * res_queriesmatch(buf1, eom1, buf2, eom2) * is there a 1:1 mapping of (name,type,class) * in (buf1,eom1) and (buf2,eom2)? * returns: * -1 : format error * 0 : not a 1:1 mapping * >0 : is a 1:1 mapping * author: * paul vixie, 29may94 */intres_queriesmatch(const u_char *buf1, const u_char *eom1, const u_char *buf2, const u_char *eom2){ const u_char *cp = buf1 + HFIXEDSZ; int qdcount = ntohs(((const HEADER*)buf1)->qdcount); if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2) return (-1); /* * Only header section present in replies to * dynamic update packets. */ if ((((const HEADER *)buf1)->opcode == ns_o_update) && (((const HEADER *)buf2)->opcode == ns_o_update)) return (1); if (qdcount != ntohs(((const HEADER*)buf2)->qdcount)) return (0); while (qdcount-- > 0) { char tname[MAXDNAME+1]; int n, ttype, tclass; n = dn_expand(buf1, eom1, cp, tname, sizeof tname); if (n < 0) return (-1); cp += n; if (cp + 2 * INT16SZ > eom1) return (-1); ttype = ns_get16(cp); cp += INT16SZ; tclass = ns_get16(cp); cp += INT16SZ; if (!res_nameinquery(tname, ttype, tclass, buf2, eom2)) return (0); } return (1);}intres_nsend(res_state statp, const u_char *buf, int buflen, u_char *ans, int anssiz){ int gotsomewhere, terrno, try, v_circuit, resplen, ns, n; char abuf[NI_MAXHOST]; if (statp->nscount == 0) { errno = ESRCH; return (-1); } if (anssiz < HFIXEDSZ) { errno = EINVAL; return (-1); } DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY), (stdout, ";; res_send()\n"), buf, buflen); v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ; gotsomewhere = 0; terrno = ETIMEDOUT; /* * If the ns_addr_list in the resolver context has changed, then * invalidate our cached copy and the associated timing data. */ if (EXT(statp).nscount != 0) { int needclose = 0; struct sockaddr_storage peer; ISC_SOCKLEN_T peerlen; if (EXT(statp).nscount != statp->nscount) needclose++; else for (ns = 0; ns < statp->nscount; ns++) { if (statp->nsaddr_list[ns].sin_family && !sock_eq((struct sockaddr *)&statp->nsaddr_list[ns], (struct sockaddr *)&EXT(statp).ext->nsaddrs[ns])) { needclose++; break; } if (EXT(statp).nssocks[ns] == -1) continue; peerlen = sizeof(peer); if (getsockname(EXT(statp).nssocks[ns], (struct sockaddr *)&peer, &peerlen) < 0) { needclose++; break; } if (!sock_eq((struct sockaddr *)&peer, get_nsaddr(statp, ns))) { needclose++; break; } } if (needclose) { res_nclose(statp); EXT(statp).nscount = 0; } } /* * Maybe initialize our private copy of the ns_addr_list. */ if (EXT(statp).nscount == 0) { for (ns = 0; ns < statp->nscount; ns++) { EXT(statp).nstimes[ns] = RES_MAXTIME; EXT(statp).nssocks[ns] = -1; if (!statp->nsaddr_list[ns].sin_family) continue; EXT(statp).ext->nsaddrs[ns].sin = statp->nsaddr_list[ns]; } EXT(statp).nscount = statp->nscount; } /* * Some resolvers want to even out the load on their nameservers. * Note that RES_BLAST overrides RES_ROTATE. */ if ((statp->options & RES_ROTATE) != 0U && (statp->options & RES_BLAST) == 0U) { union res_sockaddr_union inu; struct sockaddr_in ina; int lastns = statp->nscount - 1; int fd; u_int16_t nstime; if (EXT(statp).ext != NULL) inu = EXT(statp).ext->nsaddrs[0]; ina = statp->nsaddr_list[0]; fd = EXT(statp).nssocks[0]; nstime = EXT(statp).nstimes[0]; for (ns = 0; ns < lastns; ns++) { if (EXT(statp).ext != NULL) EXT(statp).ext->nsaddrs[ns] = EXT(statp).ext->nsaddrs[ns + 1]; statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1]; EXT(statp).nssocks[ns] = EXT(statp).nssocks[ns + 1]; EXT(statp).nstimes[ns] = EXT(statp).nstimes[ns + 1]; } if (EXT(statp).ext != NULL) EXT(statp).ext->nsaddrs[lastns] = inu; statp->nsaddr_list[lastns] = ina; EXT(statp).nssocks[lastns] = fd; EXT(statp).nstimes[lastns] = nstime; } /* * Send request, RETRY times, or until successful. */ for (try = 0; try < statp->retry; try++) { for (ns = 0; ns < statp->nscount; ns++) { struct sockaddr *nsap; int nsaplen; nsap = get_nsaddr(statp, ns); nsaplen = get_salen(nsap); statp->_flags &= ~RES_F_LASTMASK; statp->_flags |= (ns << RES_F_LASTSHIFT); same_ns: if (statp->qhook) { int done = 0, loops = 0; do { res_sendhookact act; act = (*statp->qhook)(&nsap, &buf, &buflen, ans, anssiz, &resplen); switch (act) { case res_goahead: done = 1; break; case res_nextns: res_nclose(statp); goto next_ns; case res_done: return (resplen); case res_modified: /* give the hook another try */ if (++loops < 42) /*doug adams*/ break; /*FALLTHROUGH*/ case res_error: /*FALLTHROUGH*/ default: goto fail; } } while (!done); } Dprint(((statp->options & RES_DEBUG) && getnameinfo(nsap, nsaplen, abuf, sizeof(abuf), NULL, 0, niflags) == 0), (stdout, ";; Querying server (# %d) address = %s\n", ns + 1, abuf)); if (v_circuit) { /* Use VC; at most one attempt per server. */ try = statp->retry; n = send_vc(statp, buf, buflen, ans, anssiz, &terrno, ns); if (n < 0) goto fail; if (n == 0) goto next_ns; resplen = n; } else { /* Use datagrams. */ n = send_dg(statp, buf, buflen, ans, anssiz, &terrno, ns, &v_circuit, &gotsomewhere); if (n < 0) goto fail; if (n == 0) goto next_ns; if (v_circuit) goto same_ns; resplen = n; } Dprint((statp->options & RES_DEBUG) || ((statp->pfcode & RES_PRF_REPLY) && (statp->pfcode & RES_PRF_HEAD1)), (stdout, ";; got answer:\n")); DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_REPLY), (stdout, "%s", ""), ans, (resplen > anssiz) ? anssiz : resplen); /* * If we have temporarily opened a virtual circuit, * or if we haven't been asked to keep a socket open, * close the socket. */ if ((v_circuit && (statp->options & RES_USEVC) == 0U) || (statp->options & RES_STAYOPEN) == 0U) { res_nclose(statp); } if (statp->rhook) { int done = 0, loops = 0; do { res_sendhookact act; act = (*statp->rhook)(nsap, buf, buflen, ans, anssiz, &resplen); switch (act) { case res_goahead: case res_done: done = 1; break; case res_nextns: res_nclose(statp); goto next_ns; case res_modified: /* give the hook another try */ if (++loops < 42) /*doug adams*/ break; /*FALLTHROUGH*/ case res_error: /*FALLTHROUGH*/ default: goto fail; } } while (!done); } return (resplen); next_ns: ; } /*foreach ns*/ } /*foreach retry*/ res_nclose(statp); if (!v_circuit) { if (!gotsomewhere) errno = ECONNREFUSED; /* no nameservers found */ else errno = ETIMEDOUT; /* no answer obtained */ } else errno = terrno; return (-1); fail: res_nclose(statp); return (-1);}/* Private */static intget_salen(sa) const struct sockaddr *sa;{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -