From 65550ab4bf1a40a68b3fe1a06c5a21e96df6c811 Mon Sep 17 00:00:00 2001 From: peter Date: Sun, 7 Jan 1996 06:57:27 +0000 Subject: Part of bind-4.9.3-rel.. This is for my convenience and reference. This import to the vendor branch changes no files... --- lib/libc/net/res_comp.c | 148 +++++++--- lib/libc/net/res_data.c | 114 +++++++ lib/libc/net/res_debug.c | 690 ++++++++++++++++++++++++------------------- lib/libc/net/res_init.c | 517 +++++++++++++++++++++++++++++--- lib/libc/net/res_mkquery.c | 137 +++++---- lib/libc/net/res_query.c | 288 +++++++++++------- lib/libc/net/res_send.c | 717 ++++++++++++++++++++++++++++++++------------- 7 files changed, 1851 insertions(+), 760 deletions(-) create mode 100644 lib/libc/net/res_data.c (limited to 'lib/libc') diff --git a/lib/libc/net/res_comp.c b/lib/libc/net/res_comp.c index 66f37ba..6250f8f 100644 --- a/lib/libc/net/res_comp.c +++ b/lib/libc/net/res_comp.c @@ -1,7 +1,9 @@ -/*- +/* + * ++Copyright++ 1985, 1993 + * - * Copyright (c) 1985, 1993 - * The Regents of the University of California. All rights reserved. - * + * 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: @@ -12,12 +14,12 @@ * 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. + * 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 @@ -53,16 +55,26 @@ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)res_comp.c 8.1 (Berkeley) 6/4/93"; -static char rcsid[] = "$Id: res_comp.c,v 4.9.1.1 1993/05/02 22:43:03 vixie Rel $"; +static char rcsid[] = "$Id: res_comp.c,v 8.3 1995/12/06 20:34:50 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ #include -#include #include -#include +#include + #include +#include +#include + +#if defined(BSD) && (BSD >= 199103) +# include +# include +#else +# include "../conf/portability.h" +#endif -static int dn_find(); +static int dn_find __P((u_char *exp_dn, u_char *msg, + u_char **dnptrs, u_char **lastdnptr)); /* * Expand compressed domain name 'comp_dn' to full domain name. @@ -71,18 +83,20 @@ static int dn_find(); * 'exp_dn' is a pointer to a buffer of size 'length' for the result. * Return size of compressed name or -1 if there was an error. */ +int dn_expand(msg, eomorig, comp_dn, exp_dn, length) const u_char *msg, *eomorig, *comp_dn; - u_char *exp_dn; + char *exp_dn; int length; { - register u_char *cp, *dn; + register const u_char *cp; + register char *dn; register int n, c; - u_char *eom; + char *eom; int len = -1, checked = 0; dn = exp_dn; - cp = (u_char *)comp_dn; + cp = comp_dn; eom = exp_dn + length; /* * fetch next label in domain name @@ -102,23 +116,23 @@ dn_expand(msg, eomorig, comp_dn, exp_dn, length) return (-1); checked += n + 1; while (--n >= 0) { - if ((c = *cp++) == '.') { + if (((c = *cp++) == '.') || (c == '\\')) { if (dn + n + 2 >= eom) return (-1); *dn++ = '\\'; } *dn++ = c; if (cp >= eomorig) /* out of range */ - return(-1); + return (-1); } break; case INDIR_MASK: if (len < 0) len = cp - comp_dn + 1; - cp = (u_char *)msg + (((n & 0x3f) << 8) | (*cp & 0xff)); + cp = msg + (((n & 0x3f) << 8) | (*cp & 0xff)); if (cp < msg || cp >= eomorig) /* out of range */ - return(-1); + return (-1); checked += 2; /* * Check for loops in the compressed name; @@ -134,6 +148,9 @@ dn_expand(msg, eomorig, comp_dn, exp_dn, length) } } *dn = '\0'; + for (dn = exp_dn; (c = *dn) != '\0'; dn++) + if (isascii(c) && isspace(c)) + return (-1); if (len < 0) len = cp - comp_dn; return (len); @@ -151,8 +168,9 @@ dn_expand(msg, eomorig, comp_dn, exp_dn, length) * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr' * is NULL, we don't update the list. */ +int dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr) - const u_char *exp_dn; + const char *exp_dn; u_char *comp_dn, **dnptrs, **lastdnptr; int length; { @@ -164,6 +182,7 @@ dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr) dn = (u_char *)exp_dn; cp = comp_dn; eob = cp + length; + lpp = cpp = NULL; if (dnptrs != NULL) { if ((msg = *dnptrs++) != NULL) { for (cpp = dnptrs; *cpp != NULL; cpp++) @@ -229,31 +248,44 @@ dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr) /* * Skip over a compressed domain name. Return the size or -1. */ +int __dn_skipname(comp_dn, eom) const u_char *comp_dn, *eom; { - register u_char *cp; + register const u_char *cp; register int n; - cp = (u_char *)comp_dn; + cp = comp_dn; while (cp < eom && (n = *cp++)) { /* * check for indirection */ switch (n & INDIR_MASK) { - case 0: /* normal case, n == len */ + case 0: /* normal case, n == len */ cp += n; continue; - default: /* illegal type */ - return (-1); case INDIR_MASK: /* indirection */ cp++; + break; + default: /* illegal type */ + return (-1); } break; } + if (cp > eom) + return (-1); return (cp - comp_dn); } +static int +mklower(ch) + register int ch; +{ + if (isascii(ch) && isupper(ch)) + return (tolower(ch)); + return (ch); +} + /* * Search for expanded name from a list of previously compressed names. * Return the offset from msg if found or -1. @@ -283,7 +315,7 @@ dn_find(exp_dn, msg, dnptrs, lastdnptr) goto next; if (*dn == '\\') dn++; - if (*dn++ != *cp++) + if (mklower(*dn++) != mklower(*cp++)) goto next; } if ((n = *dn++) == '\0' && *cp == '\0') @@ -292,11 +324,12 @@ dn_find(exp_dn, msg, dnptrs, lastdnptr) continue; goto next; - default: /* illegal type */ - return (-1); - case INDIR_MASK: /* indirection */ cp = msg + (((n & 0x3f) << 8) | *cp); + break; + + default: /* illegal type */ + return (-1); } } if (*dn == '\0') @@ -307,16 +340,12 @@ dn_find(exp_dn, msg, dnptrs, lastdnptr) } /* - * Routines to insert/extract short/long's. Must account for byte - * order and non-alignment problems. This code at least has the - * advantage of being portable. - * - * used by sendmail. + * Routines to insert/extract short/long's. */ -u_short +u_int16_t _getshort(msgp) - register u_char *msgp; + register const u_char *msgp; { register u_int16_t u; @@ -324,9 +353,21 @@ _getshort(msgp) return (u); } +#ifdef NeXT +/* + * nExt machines have some funky library conventions, which we must maintain. + */ +u_int16_t +res_getshort(msgp) + register const u_char *msgp; +{ + return (_getshort(msgp)); +} +#endif + u_int32_t _getlong(msgp) - register u_char *msgp; + register const u_char *msgp; { register u_int32_t u; @@ -336,7 +377,7 @@ _getlong(msgp) void #if defined(__STDC__) || defined(__cplusplus) -__putshort(register u_short s, register u_char *msgp) +__putshort(register u_int16_t s, register u_char *msgp) /* must match proto */ #else __putshort(s, msgp) register u_int16_t s; @@ -353,3 +394,36 @@ __putlong(l, msgp) { PUTLONG(l, msgp); } + +#ifdef ultrix +/* ultrix 4.0 had some icky packaging in its libc.a. alias for it here. + * there is more gunk of this kind over in res_debug.c. + */ +#undef putshort +void +#if defined(__STDC__) || defined(__cplusplus) +putshort(register u_short s, register u_char *msgp) +#else +putshort(s, msgp) + register u_short s; + register u_char *msgp; +#endif +{ + __putshort(s, msgp); +} +#undef putlong +void +putlong(l, msgp) + register u_int32_t l; + register u_char *msgp; +{ + __putlong(l, msgp); +} + +#undef dn_skipname +dn_skipname(comp_dn, eom) + const u_char *comp_dn, *eom; +{ + return (__dn_skipname(comp_dn, eom)); +} +#endif /* Ultrix 4.0 hackery */ diff --git a/lib/libc/net/res_data.c b/lib/libc/net/res_data.c new file mode 100644 index 0000000..0d17bc2 --- /dev/null +++ b/lib/libc/net/res_data.c @@ -0,0 +1,114 @@ +/* + * ++Copyright++ 1995 + * - + * Copyright (c) 1995 + * 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-- + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char rcsid[] = "$Id: res_data.c,v 8.1 1995/12/22 10:21:29 vixie Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#if defined(BSD) && (BSD >= 199103) +# include +# include +# include +#else +# include "../conf/portability.h" +#endif + +const char *_res_opcodes[] = { + "QUERY", + "IQUERY", + "CQUERYM", + "CQUERYU", /* experimental */ + "NOTIFY", /* experimental */ + "5", + "6", + "7", + "8", + "UPDATEA", + "UPDATED", + "UPDATEDA", + "UPDATEM", + "UPDATEMA", + "ZONEINIT", + "ZONEREF", +}; + +const char *_res_resultcodes[] = { + "NOERROR", + "FORMERR", + "SERVFAIL", + "NXDOMAIN", + "NOTIMP", + "REFUSED", + "6", + "7", + "8", + "9", + "10", + "11", + "12", + "13", + "14", + "NOCHANGE", +}; diff --git a/lib/libc/net/res_debug.c b/lib/libc/net/res_debug.c index 0bd882a..aff28a4 100644 --- a/lib/libc/net/res_debug.c +++ b/lib/libc/net/res_debug.c @@ -1,7 +1,9 @@ -/*- +/* + * ++Copyright++ 1985, 1990, 1993 + * - * Copyright (c) 1985, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * + * 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: @@ -12,12 +14,12 @@ * 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. + * 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 @@ -53,169 +55,172 @@ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)res_debug.c 8.1 (Berkeley) 6/4/93"; +static char rcsid[] = "$Id: res_debug.c,v 8.7 1995/12/22 10:20:39 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ #include #include #include #include -#include + #include -#include - -void __fp_query(); -char *__p_class(), *__p_time(), *__p_type(); -char *p_cdname(), *p_fqname(), *p_rr(); -static char *p_option __P((u_int32_t)); - -char *_res_opcodes[] = { - "QUERY", - "IQUERY", - "CQUERYM", - "CQUERYU", - "4", - "5", - "6", - "7", - "8", - "UPDATEA", - "UPDATED", - "UPDATEDA", - "UPDATEM", - "UPDATEMA", - "ZONEINIT", - "ZONEREF", -}; - -char *_res_resultcodes[] = { - "NOERROR", - "FORMERR", - "SERVFAIL", - "NXDOMAIN", - "NOTIMP", - "REFUSED", - "6", - "7", - "8", - "9", - "10", - "11", - "12", - "13", - "14", - "NOCHANGE", -}; - -static char retbuf[16]; - -static char * +#include +#include +#if defined(BSD) && (BSD >= 199103) +# include +#else +# include "../conf/portability.h" +#endif + +#if defined(USE_OPTIONS_H) +# include "../conf/options.h" +#endif + +extern const char *_res_opcodes[]; +extern const char *_res_resultcodes[]; + +/* XXX: we should use getservbyport() instead. */ +static const char * dewks(wks) int wks; { + static char nbuf[20]; + switch (wks) { - case 5: return("rje"); - case 7: return("echo"); - case 9: return("discard"); - case 11: return("systat"); - case 13: return("daytime"); - case 15: return("netstat"); - case 17: return("qotd"); - case 19: return("chargen"); - case 20: return("ftp-data"); - case 21: return("ftp"); - case 23: return("telnet"); - case 25: return("smtp"); - case 37: return("time"); - case 39: return("rlp"); - case 42: return("name"); - case 43: return("whois"); - case 53: return("domain"); - case 57: return("apts"); - case 59: return("apfs"); - case 67: return("bootps"); - case 68: return("bootpc"); - case 69: return("tftp"); - case 77: return("rje"); - case 79: return("finger"); - case 87: return("link"); - case 95: return("supdup"); - case 100: return("newacct"); - case 101: return("hostnames"); - case 102: return("iso-tsap"); - case 103: return("x400"); - case 104: return("x400-snd"); - case 105: return("csnet-ns"); - case 109: return("pop-2"); - case 111: return("sunrpc"); - case 113: return("auth"); - case 115: return("sftp"); - case 117: return("uucp-path"); - case 119: return("nntp"); - case 121: return("erpc"); - case 123: return("ntp"); - case 133: return("statsrv"); - case 136: return("profile"); - case 144: return("NeWS"); - case 161: return("snmp"); - case 162: return("snmp-trap"); - case 170: return("print-srv"); - default: (void) sprintf(retbuf, "%d", wks); return(retbuf); + case 5: return "rje"; + case 7: return "echo"; + case 9: return "discard"; + case 11: return "systat"; + case 13: return "daytime"; + case 15: return "netstat"; + case 17: return "qotd"; + case 19: return "chargen"; + case 20: return "ftp-data"; + case 21: return "ftp"; + case 23: return "telnet"; + case 25: return "smtp"; + case 37: return "time"; + case 39: return "rlp"; + case 42: return "name"; + case 43: return "whois"; + case 53: return "domain"; + case 57: return "apts"; + case 59: return "apfs"; + case 67: return "bootps"; + case 68: return "bootpc"; + case 69: return "tftp"; + case 77: return "rje"; + case 79: return "finger"; + case 87: return "link"; + case 95: return "supdup"; + case 100: return "newacct"; + case 101: return "hostnames"; + case 102: return "iso-tsap"; + case 103: return "x400"; + case 104: return "x400-snd"; + case 105: return "csnet-ns"; + case 109: return "pop-2"; + case 111: return "sunrpc"; + case 113: return "auth"; + case 115: return "sftp"; + case 117: return "uucp-path"; + case 119: return "nntp"; + case 121: return "erpc"; + case 123: return "ntp"; + case 133: return "statsrv"; + case 136: return "profile"; + case 144: return "NeWS"; + case 161: return "snmp"; + case 162: return "snmp-trap"; + case 170: return "print-srv"; + default: (void) sprintf(nbuf, "%d", wks); return (nbuf); } } -static char * +/* XXX: we should use getprotobynumber() instead. */ +static const char * deproto(protonum) int protonum; { + static char nbuf[20]; + switch (protonum) { - case 1: return("icmp"); - case 2: return("igmp"); - case 3: return("ggp"); - case 5: return("st"); - case 6: return("tcp"); - case 7: return("ucl"); - case 8: return("egp"); - case 9: return("igp"); - case 11: return("nvp-II"); - case 12: return("pup"); - case 16: return("chaos"); - case 17: return("udp"); - default: (void) sprintf(retbuf, "%d", protonum); return(retbuf); + case 1: return "icmp"; + case 2: return "igmp"; + case 3: return "ggp"; + case 5: return "st"; + case 6: return "tcp"; + case 7: return "ucl"; + case 8: return "egp"; + case 9: return "igp"; + case 11: return "nvp-II"; + case 12: return "pup"; + case 16: return "chaos"; + case 17: return "udp"; + default: (void) sprintf(nbuf, "%d", protonum); return (nbuf); } } -static char * -do_rrset(msg, cp, cnt, pflag, file, hs) - int cnt, pflag; - char *cp,*msg, *hs; +static const u_char * +do_rrset(msg, len, cp, cnt, pflag, file, hs) + int cnt, pflag, len; + const u_char *cp, *msg; + const char *hs; FILE *file; { int n; int sflag; + /* - * Print answer records + * Print answer records. */ sflag = (_res.pfcode & pflag); if (n = ntohs(cnt)) { - if ((!_res.pfcode) || ((sflag) && (_res.pfcode & RES_PRF_HEAD1))) + if ((!_res.pfcode) || + ((sflag) && (_res.pfcode & RES_PRF_HEAD1))) fprintf(file, hs); while (--n >= 0) { - cp = p_rr(cp, msg, file); - if ((cp-msg) > PACKETSZ) + if ((!_res.pfcode) || sflag) { + cp = p_rr(cp, msg, file); + } else { + unsigned int dlen; + cp += __dn_skipname(cp, cp + MAXCDNAME); + cp += INT16SZ; + cp += INT16SZ; + cp += INT32SZ; + dlen = _getshort((u_char*)cp); + cp += INT16SZ; + cp += dlen; + } + if ((cp - msg) > len) return (NULL); } - if ((!_res.pfcode) || ((sflag) && (_res.pfcode & RES_PRF_HEAD1))) + if ((!_res.pfcode) || + ((sflag) && (_res.pfcode & RES_PRF_HEAD1))) putc('\n', file); } - return(cp); + return (cp); } +void __p_query(msg) - char *msg; + const u_char *msg; { __fp_query(msg, stdout); } +#ifdef ultrix +/* ultrix 4.0's packaging has some icky packaging. alias for it here. + * there is more junk of this kind over in res_comp.c. + */ +void +p_query(msg) + const u_char *msg; +{ + __p_query(msg); +} +#endif + /* * Print the current options. * This is intended to be primarily a debugging routine. @@ -225,15 +230,14 @@ __fp_resstat(statp, file) struct __res_state *statp; FILE *file; { - int bit; + register u_long mask; fprintf(file, ";; res options:"); if (!statp) statp = &_res; - for (bit = 0; bit < 32; bit++) { /* XXX 32 - bad assumption! */ - if (statp->options & (1<options & mask) + fprintf(file, " %s", p_option(mask)); putc('\n', file); } @@ -242,109 +246,145 @@ __fp_resstat(statp, file) * This is intended to be primarily a debugging routine. */ void -__fp_query(msg,file) - char *msg; +__fp_nquery(msg, len, file) + const u_char *msg; + int len; FILE *file; { - register char *cp; - register HEADER *hp; + register const u_char *cp, *endMark; + register const HEADER *hp; register int n; + if ((_res.options & RES_INIT) == 0 && res_init() == -1) + return; + +#define TruncTest(x) if (x >= endMark) goto trunc +#define ErrorTest(x) if (x == NULL) goto error + /* * Print header fields. */ hp = (HEADER *)msg; - cp = msg + sizeof(HEADER); + cp = msg + HFIXEDSZ; + endMark = cp + len; if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEADX) || hp->rcode) { - fprintf(file,";; ->>HEADER<<- opcode: %s, status: %s, id: %d", + fprintf(file, ";; ->>HEADER<<- opcode: %s, status: %s, id: %d", _res_opcodes[hp->opcode], _res_resultcodes[hp->rcode], ntohs(hp->id)); putc('\n', file); } - putc(';', file); + if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEADX)) + putc(';', file); if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD2)) { - fprintf(file,"; flags:"); + fprintf(file, "; flags:"); if (hp->qr) - fprintf(file," qr"); + fprintf(file, " qr"); if (hp->aa) - fprintf(file," aa"); + fprintf(file, " aa"); if (hp->tc) - fprintf(file," tc"); + fprintf(file, " tc"); if (hp->rd) - fprintf(file," rd"); + fprintf(file, " rd"); if (hp->ra) - fprintf(file," ra"); - if (hp->pr) - fprintf(file," pr"); + fprintf(file, " ra"); } if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEAD1)) { - fprintf(file,"; Ques: %d", ntohs(hp->qdcount)); - fprintf(file,", Ans: %d", ntohs(hp->ancount)); - fprintf(file,", Auth: %d", ntohs(hp->nscount)); - fprintf(file,", Addit: %d\n", ntohs(hp->arcount)); + fprintf(file, "; Ques: %d", ntohs(hp->qdcount)); + fprintf(file, ", Ans: %d", ntohs(hp->ancount)); + fprintf(file, ", Auth: %d", ntohs(hp->nscount)); + fprintf(file, ", Addit: %d", ntohs(hp->arcount)); } -#if 0 - if (_res.pfcode & (RES_PRF_HEADX | RES_PRF_HEAD2 | RES_PRF_HEAD1)) { + if ((!_res.pfcode) || (_res.pfcode & + (RES_PRF_HEADX | RES_PRF_HEAD2 | RES_PRF_HEAD1))) { putc('\n',file); } -#endif /* * Print question records. */ if (n = ntohs(hp->qdcount)) { if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES)) - fprintf(file,";; QUESTIONS:\n"); + fprintf(file, ";; QUESTIONS:\n"); while (--n >= 0) { - fprintf(file,";;\t"); - cp = p_cdname(cp, msg, file); - if (cp == NULL) - return; + if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES)) + fprintf(file, ";;\t"); + TruncTest(cp); + if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES)) + cp = p_cdnname(cp, msg, len, file); + else { + int n; + char name[MAXDNAME]; + + if ((n = dn_expand(msg, msg+len, cp, name, + sizeof name)) < 0) + cp = NULL; + else + cp += n; + } + ErrorTest(cp); + TruncTest(cp); if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES)) fprintf(file, ", type = %s", - __p_type(_getshort(cp))); - cp += sizeof(u_int16_t); + __p_type(_getshort((u_char*)cp))); + cp += INT16SZ; + TruncTest(cp); if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES)) - fprintf(file, ", class = %s\n\n", - __p_class(_getshort(cp))); - cp += sizeof(u_int16_t); + fprintf(file, ", class = %s\n", + __p_class(_getshort((u_char*)cp))); + cp += INT16SZ; + if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES)) + putc('\n', file); } } /* * Print authoritative answer records */ - cp = do_rrset(msg, cp, hp->ancount, RES_PRF_ANS, file, + TruncTest(cp); + cp = do_rrset(msg, len, cp, hp->ancount, RES_PRF_ANS, file, ";; ANSWERS:\n"); - if (cp == NULL) - return; + ErrorTest(cp); /* * print name server records */ - cp = do_rrset(msg, cp, hp->nscount, RES_PRF_AUTH, file, + TruncTest(cp); + cp = do_rrset(msg, len, cp, hp->nscount, RES_PRF_AUTH, file, ";; AUTHORITY RECORDS:\n"); - if (!cp) - return; + ErrorTest(cp); + TruncTest(cp); /* * print additional records */ - cp = do_rrset(msg, cp, hp->arcount, RES_PRF_ADD, file, + cp = do_rrset(msg, len, cp, hp->arcount, RES_PRF_ADD, file, ";; ADDITIONAL RECORDS:\n"); - if (!cp) - return; + ErrorTest(cp); + return; + trunc: + fprintf(file, "\n;; ...truncated\n"); + return; + error: + fprintf(file, "\n;; ...malformed\n"); } -char * -p_cdname(cp, msg, file) - char *cp, *msg; +void +__fp_query(msg, file) + const u_char *msg; + FILE *file; +{ + fp_nquery(msg, PACKETSZ, file); +} + +const u_char * +__p_cdnname(cp, msg, len, file) + const u_char *cp, *msg; + int len; FILE *file; { char name[MAXDNAME]; int n; - if ((n = dn_expand((u_char *)msg, (u_char *)msg + MAXCDNAME, - (u_char *)cp, (u_char *)name, sizeof(name))) < 0) + if ((n = dn_expand(msg, msg + len, cp, name, sizeof name)) < 0) return (NULL); if (name[0] == '\0') putc('.', file); @@ -353,16 +393,26 @@ p_cdname(cp, msg, file) return (cp + n); } -char * -p_fqname(cp, msg, file) - char *cp, *msg; +const u_char * +__p_cdname(cp, msg, file) + const u_char *cp, *msg; + FILE *file; +{ + return (p_cdnname(cp, msg, PACKETSZ, file)); +} + +/* XXX: the rest of these functions need to become length-limited, too. (vix) + */ + +const u_char * +__p_fqname(cp, msg, file) + const u_char *cp, *msg; FILE *file; { char name[MAXDNAME]; - int n, len; + int n; - if ((n = dn_expand((u_char *)msg, (u_char *)msg + MAXCDNAME, - (u_char *)cp, (u_char *)name, sizeof(name))) < 0) + if ((n = dn_expand(msg, cp + MAXCDNAME, cp, name, sizeof name)) < 0) return (NULL); if (name[0] == '\0') { putc('.', file); @@ -377,30 +427,34 @@ p_fqname(cp, msg, file) /* * Print resource record fields in human readable form. */ -char * -p_rr(cp, msg, file) - char *cp, *msg; +const u_char * +__p_rr(cp, msg, file) + const u_char *cp, *msg; FILE *file; { int type, class, dlen, n, c; struct in_addr inaddr; - char *cp1, *cp2; + const u_char *cp1, *cp2; u_int32_t tmpttl, t; int lcnt; + if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + h_errno = NETDB_INTERNAL; + return (NULL); + } if ((cp = p_fqname(cp, msg, file)) == NULL) return (NULL); /* compression error */ - type = _getshort(cp); - cp += sizeof(u_int16_t); - class = _getshort(cp); - cp += sizeof(u_int16_t); - tmpttl = _getlong(cp); - cp += sizeof(u_int32_t); - dlen = _getshort(cp); - cp += sizeof(u_int16_t); + type = _getshort((u_char*)cp); + cp += INT16SZ; + class = _getshort((u_char*)cp); + cp += INT16SZ; + tmpttl = _getlong((u_char*)cp); + cp += INT32SZ; + dlen = _getshort((u_char*)cp); + cp += INT16SZ; cp1 = cp; if ((!_res.pfcode) || (_res.pfcode & RES_PRF_TTLID)) - fprintf(file, "\t%lu", tmpttl); + fprintf(file, "\t%lu", (u_long)tmpttl); if ((!_res.pfcode) || (_res.pfcode & RES_PRF_CLASS)) fprintf(file, "\t%s", __p_class(class)); fprintf(file, "\t%s", __p_type(type)); @@ -412,9 +466,9 @@ p_rr(cp, msg, file) switch (class) { case C_IN: case C_HS: - bcopy(cp, (char *)&inaddr, sizeof(inaddr)); + bcopy(cp, (char *)&inaddr, INADDRSZ); if (dlen == 4) { - fprintf(file,"\t%s", inet_ntoa(inaddr)); + fprintf(file, "\t%s", inet_ntoa(inaddr)); cp += dlen; } else if (dlen == 7) { char *address; @@ -422,11 +476,11 @@ p_rr(cp, msg, file) u_short port; address = inet_ntoa(inaddr); - cp += sizeof(inaddr); + cp += INADDRSZ; protocol = *(u_char*)cp; cp += sizeof(u_char); - port = _getshort(cp); - cp += sizeof(u_int16_t); + port = _getshort((u_char*)cp); + cp += INT16SZ; fprintf(file, "\t%s\t; proto %d, port %d", address, protocol, port); } @@ -442,51 +496,75 @@ p_rr(cp, msg, file) case T_NS: case T_PTR: putc('\t', file); - cp = p_fqname(cp, msg, file); + if ((cp = p_fqname(cp, msg, file)) == NULL) + return (NULL); break; case T_HINFO: + case T_ISDN: + cp2 = cp + dlen; if (n = *cp++) { - fprintf(file,"\t%.*s", n, cp); + fprintf(file, "\t%.*s", n, cp); cp += n; } - if (n = *cp++) { - fprintf(file,"\t%.*s", n, cp); + if ((cp < cp2) && (n = *cp++)) { + fprintf(file, "\t%.*s", n, cp); cp += n; - } + } else if (type == T_HINFO) + fprintf(file, "\n;; *** Warning *** OS-type missing"); break; case T_SOA: putc('\t', file); - cp = p_fqname(cp, msg, file); /* origin */ + if ((cp = p_fqname(cp, msg, file)) == NULL) + return (NULL); putc(' ', file); - cp = p_fqname(cp, msg, file); /* mail addr */ + if ((cp = p_fqname(cp, msg, file)) == NULL) + return (NULL); fputs(" (\n", file); - t = _getlong(cp); cp += sizeof(u_int32_t); - fprintf(file,"\t\t\t%lu\t; serial\n", t); - t = _getlong(cp); cp += sizeof(u_int32_t); - fprintf(file,"\t\t\t%lu\t; refresh (%s)\n", t, __p_time(t)); - t = _getlong(cp); cp += sizeof(u_int32_t); - fprintf(file,"\t\t\t%lu\t; retry (%s)\n", t, __p_time(t)); - t = _getlong(cp); cp += sizeof(u_int32_t); - fprintf(file,"\t\t\t%lu\t; expire (%s)\n", t, __p_time(t)); - t = _getlong(cp); cp += sizeof(u_int32_t); - fprintf(file,"\t\t\t%lu )\t; minimum (%s)", t, __p_time(t)); + t = _getlong((u_char*)cp); cp += INT32SZ; + fprintf(file, "\t\t\t%lu\t; serial\n", (u_long)t); + t = _getlong((u_char*)cp); cp += INT32SZ; + fprintf(file, "\t\t\t%lu\t; refresh (%s)\n", + (u_long)t, __p_time(t)); + t = _getlong((u_char*)cp); cp += INT32SZ; + fprintf(file, "\t\t\t%lu\t; retry (%s)\n", + (u_long)t, __p_time(t)); + t = _getlong((u_char*)cp); cp += INT32SZ; + fprintf(file, "\t\t\t%lu\t; expire (%s)\n", + (u_long)t, __p_time(t)); + t = _getlong((u_char*)cp); cp += INT32SZ; + fprintf(file, "\t\t\t%lu )\t; minimum (%s)", + (u_long)t, __p_time(t)); break; case T_MX: - fprintf(file,"\t%d ", _getshort(cp)); - cp += sizeof(u_int16_t); - cp = p_fqname(cp, msg, file); + case T_AFSDB: + case T_RT: + fprintf(file, "\t%d ", _getshort((u_char*)cp)); + cp += INT16SZ; + if ((cp = p_fqname(cp, msg, file)) == NULL) + return (NULL); break; - case T_TXT: + case T_PX: + fprintf(file, "\t%d ", _getshort((u_char*)cp)); + cp += INT16SZ; + if ((cp = p_fqname(cp, msg, file)) == NULL) + return (NULL); + putc(' ', file); + if ((cp = p_fqname(cp, msg, file)) == NULL) + return (NULL); + break; + + case T_TXT: + case T_X25: (void) fputs("\t\"", file); cp2 = cp1 + dlen; while (cp < cp2) { if (n = (unsigned char) *cp++) { for (c = n; c > 0 && cp < cp2; c--) - if (*cp == '\n') { + if ((*cp == '\n') || (*cp == '"')) { (void) putc('\\', file); (void) putc(*cp++, file); } else @@ -494,35 +572,42 @@ p_rr(cp, msg, file) } } putc('"', file); - break; + break; + + case T_NSAP: + (void) fprintf(file, "\t%s", inet_nsap_ntoa(dlen, cp, NULL)); + cp += dlen; + break; case T_MINFO: case T_RP: putc('\t', file); - cp = p_fqname(cp, msg, file); + if ((cp = p_fqname(cp, msg, file)) == NULL) + return (NULL); putc(' ', file); - cp = p_fqname(cp, msg, file); + if ((cp = p_fqname(cp, msg, file)) == NULL) + return (NULL); break; case T_UINFO: putc('\t', file); - fputs(cp, file); + fputs((char *)cp, file); cp += dlen; break; case T_UID: case T_GID: if (dlen == 4) { - fprintf(file,"\t%u", _getlong(cp)); - cp += sizeof(int32_t); + fprintf(file, "\t%u", _getlong((u_char*)cp)); + cp += INT32SZ; } break; case T_WKS: - if (dlen < sizeof(u_int32_t) + 1) + if (dlen < INT32SZ + 1) break; - bcopy(cp, (char *)&inaddr, sizeof(inaddr)); - cp += sizeof(u_int32_t); + bcopy(cp, (char *)&inaddr, INADDRSZ); + cp += INT32SZ; fprintf(file, "\t%s %s ( ", inet_ntoa(inaddr), deproto((int) *cp)); @@ -532,7 +617,7 @@ p_rr(cp, msg, file) while (cp < cp1 + dlen) { c = *cp++; do { - if (c & 0200) { + if (c & 0200) { if (lcnt == 0) { fputs("\n\t\t\t", file); lcnt = 5; @@ -541,7 +626,7 @@ p_rr(cp, msg, file) putc(' ', file); lcnt--; } - c <<= 1; + c <<= 1; } while (++n & 07); } putc(')', file); @@ -551,7 +636,7 @@ p_rr(cp, msg, file) case T_UNSPEC: { int NumBytes = 8; - char *DataPtr; + u_char *DataPtr; int i; if (dlen < NumBytes) NumBytes = dlen; @@ -565,7 +650,7 @@ p_rr(cp, msg, file) #endif /* ALLOW_T_UNSPEC */ default: - fprintf(file,"\t?%d?", type); + fprintf(file, "\t?%d?", type); cp += dlen; } #if 0 @@ -574,117 +659,105 @@ p_rr(cp, msg, file) putc('\n', file); #endif if (cp - cp1 != dlen) { - fprintf(file,";; packet size error (found %d, dlen was %d)\n", + fprintf(file, ";; packet size error (found %d, dlen was %d)\n", cp - cp1, dlen); cp = NULL; } return (cp); } -static char nbuf[40]; - /* * Return a string for the type */ -char * +const char * __p_type(type) int type; { + static char nbuf[20]; + switch (type) { - case T_A: - return("A"); - case T_NS: /* authoritative server */ - return("NS"); - case T_CNAME: /* canonical name */ - return("CNAME"); - case T_SOA: /* start of authority zone */ - return("SOA"); - case T_MB: /* mailbox domain name */ - return("MB"); - case T_MG: /* mail group member */ - return("MG"); - case T_MR: /* mail rename name */ - return("MR"); - case T_NULL: /* null resource record */ - return("NULL"); - case T_WKS: /* well known service */ - return("WKS"); - case T_PTR: /* domain name pointer */ - return("PTR"); - case T_HINFO: /* host information */ - return("HINFO"); - case T_MINFO: /* mailbox information */ - return("MINFO"); - case T_MX: /* mail routing info */ - return("MX"); - case T_TXT: /* text */ - return("TXT"); - case T_RP: /* responsible person */ - return("RP"); - case T_AXFR: /* zone transfer */ - return("AXFR"); - case T_MAILB: /* mail box */ - return("MAILB"); - case T_MAILA: /* mail address */ - return("MAILA"); - case T_ANY: /* matches any type */ - return("ANY"); - case T_UINFO: - return("UINFO"); - case T_UID: - return("UID"); - case T_GID: - return("GID"); + case T_A: return "A"; + case T_NS: return "NS"; + case T_CNAME: return "CNAME"; + case T_SOA: return "SOA"; + case T_MB: return "MB"; + case T_MG: return "MG"; + case T_MR: return "MR"; + case T_NULL: return "NULL"; + case T_WKS: return "WKS"; + case T_PTR: return "PTR"; + case T_HINFO: return "HINFO"; + case T_MINFO: return "MINFO"; + case T_MX: return "MX"; + case T_TXT: return "TXT"; + case T_RP: return "RP"; + case T_AFSDB: return "AFSDB"; + case T_X25: return "X25"; + case T_ISDN: return "ISDN"; + case T_RT: return "RT"; + case T_NSAP: return "NSAP"; + case T_NSAP_PTR: return "NSAP_PTR"; + case T_SIG: return "SIG"; + case T_KEY: return "KEY"; + case T_PX: return "PX"; + case T_GPOS: return "GPOS"; + case T_AAAA: return "AAAA"; + case T_LOC: return "LOC"; + case T_AXFR: return "AXFR"; + case T_MAILB: return "MAILB"; + case T_MAILA: return "MAILA"; + case T_ANY: return "ANY"; + case T_UINFO: return "UINFO"; + case T_UID: return "UID"; + case T_GID: return "GID"; #ifdef ALLOW_T_UNSPEC - case T_UNSPEC: - return("UNSPEC"); + case T_UNSPEC: return "UNSPEC"; #endif /* ALLOW_T_UNSPEC */ - default: - (void)sprintf(nbuf, "%d", type); - return(nbuf); + default: (void)sprintf(nbuf, "%d", type); return (nbuf); } } /* * Return a mnemonic for class */ -char * +const char * __p_class(class) int class; { + static char nbuf[20]; switch (class) { - case C_IN: /* internet class */ - return("IN"); - case C_HS: /* hesiod class */ - return("HS"); - case C_ANY: /* matches any class */ - return("ANY"); - default: - (void)sprintf(nbuf, "%d", class); - return(nbuf); + case C_IN: return "IN"; + case C_HS: return "HS"; + case C_ANY: return "ANY"; + default: (void)sprintf(nbuf, "%d", class); return (nbuf); } } /* * Return a mnemonic for an option */ -static char * -p_option(option) - u_int32_t option; +const char * +__p_option(option) + u_long option; { + static char nbuf[40]; + switch (option) { case RES_INIT: return "init"; case RES_DEBUG: return "debug"; - case RES_AAONLY: return "aaonly"; + case RES_AAONLY: return "aaonly(unimpl)"; case RES_USEVC: return "usevc"; - case RES_PRIMARY: return "primry"; + case RES_PRIMARY: return "primry(unimpl)"; case RES_IGNTC: return "igntc"; case RES_RECURSE: return "recurs"; case RES_DEFNAMES: return "defnam"; case RES_STAYOPEN: return "styopn"; case RES_DNSRCH: return "dnsrch"; - default: sprintf(nbuf, "?0x%x?", option); return nbuf; + case RES_INSECURE1: return "insecure1"; + case RES_INSECURE2: return "insecure2"; + default: sprintf(nbuf, "?0x%lx?", (u_long)option); + return (nbuf); } } @@ -695,12 +768,13 @@ char * __p_time(value) u_int32_t value; { + static char nbuf[40]; int secs, mins, hours, days; register char *p; if (value == 0) { strcpy(nbuf, "0 secs"); - return(nbuf); + return (nbuf); } secs = value % 60; @@ -735,5 +809,5 @@ __p_time(value) *p++ = ' '; (void)sprintf(p, "%d sec%s", PLURALIZE(secs)); } - return(nbuf); + return (nbuf); } diff --git a/lib/libc/net/res_init.c b/lib/libc/net/res_init.c index 1e0fd05..c1f120d 100644 --- a/lib/libc/net/res_init.c +++ b/lib/libc/net/res_init.c @@ -1,7 +1,9 @@ -/*- +/* + * ++Copyright++ 1985, 1989, 1993 + * - * Copyright (c) 1985, 1989, 1993 - * The Regents of the University of California. All rights reserved. - * + * 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: @@ -12,12 +14,12 @@ * 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. + * 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 @@ -53,41 +55,100 @@ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)res_init.c 8.1 (Berkeley) 6/7/93"; -static char rcsid[] = "$Id: res_init.c,v 4.9.1.1 1993/05/02 22:43:03 vixie Rel $"; +static char rcsid[] = "$Id: res_init.c,v 8.3 1995/06/29 09:26:28 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ #include #include +#include #include #include #include -#include -#include + #include -#include -#include +#include +#include +#if defined(BSD) && (BSD >= 199103) +# include +# include +# include +#else +# include "../conf/portability.h" +#endif + +/*-------------------------------------- info about "sortlist" -------------- + * Marc Majka 1994/04/16 + * Allan Nathanson 1994/10/29 (BIND 4.9.3.x) + * + * NetInfo resolver configuration directory support. + * + * Allow a NetInfo directory to be created in the hierarchy which + * contains the same information as the resolver configuration file. + * + * - The local domain name is stored as the value of the "domain" property. + * - The Internet address(es) of the name server(s) are stored as values + * of the "nameserver" property. + * - The name server addresses are stored as values of the "nameserver" + * property. + * - The search list for host-name lookup is stored as values of the + * "search" property. + * - The sortlist comprised of IP address netmask pairs are stored as + * values of the "sortlist" property. The IP address and optional netmask + * should be seperated by a slash (/) or ampersand (&) character. + * - Internal resolver variables can be set from the value of the "options" + * property. + */ +#if defined(NeXT) +# include +# define NI_PATH_RESCONF "/locations/resolver" +# define NI_TIMEOUT 10 +static int netinfo_res_init __P((int *haveenv, int *havesearch)); +#endif + +#if defined(USE_OPTIONS_H) +# include "../conf/options.h" +#endif + +static void res_setoptions __P((char *, char *)); + +#ifdef RESOLVSORT +static const char sort_mask[] = "/&"; +#define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL) +static u_int32_t net_mask __P((struct in_addr)); +#endif + +#if !defined(isascii) /* XXX - could be a function */ +# define isascii(c) (!(c & 0200)) +#endif /* - * Resolver state default settings + * Resolver state default settings. */ -struct __res_state _res = { - RES_TIMEOUT, /* retransmition time interval */ - 4, /* number of times to retransmit */ - RES_DEFAULT, /* options flags */ - 1, /* number of name servers */ -}; +struct __res_state _res; /* * Set up default settings. If the configuration file exist, the values * there will have precedence. Otherwise, the server address is set to * INADDR_ANY and the default domain name comes from the gethostname(). * - * The configuration file should only be used if you want to redefine your - * domain or run without a server on your machine. + * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1 + * rather than INADDR_ANY ("0.0.0.0") as the default name server address + * since it was noted that INADDR_ANY actually meant ``the first interface + * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface, + * it had to be "up" in order for you to reach your own name server. It + * was later decided that since the recommended practice is to always + * install local static routes through 127.0.0.1 for all your network + * interfaces, that we could solve this problem without a code change. + * + * The configuration file should always be used, since it is the only way + * to specify a default domain. If you are running a server on your local + * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1" + * in the configuration file. * * Return 0 if completes successfully, -1 on error */ +int res_init() { register FILE *fp; @@ -97,6 +158,46 @@ res_init() int nserv = 0; /* number of nameserver records read from file */ int haveenv = 0; int havesearch = 0; +#ifdef RESOLVSORT + int nsort = 0; + char *net; +#endif +#ifndef RFC1535 + int dots; +#endif + + /* + * These three fields used to be statically initialized. This made + * it hard to use this code in a shared library. It is necessary, + * now that we're doing dynamic initialization here, that we preserve + * the old semantics: if an application modifies one of these three + * fields of _res before res_init() is called, res_init() will not + * alter them. Of course, if an application is setting them to + * _zero_ before calling res_init(), hoping to override what used + * to be the static default, we can't detect it and unexpected results + * will follow. Zero for any of these fields would make no sense, + * so one can safely assume that the applications were already getting + * unexpected results. + * + * _res.options is tricky since some apps were known to diddle the bits + * before res_init() was first called. We can't replicate that semantic + * with dynamic initialization (they may have turned bits off that are + * set in RES_DEFAULT). Our solution is to declare such applications + * "broken". They could fool us by setting RES_INIT but none do (yet). + */ + if (!_res.retrans) + _res.retrans = RES_TIMEOUT; + if (!_res.retry) + _res.retry = 4; + if (!(_res.options & RES_INIT)) + _res.options = RES_DEFAULT; + + /* + * This one used to initialize implicitly to zero, so unless the app + * has set it to something in particular, we can randomize it now. + */ + if (!_res.id) + _res.id = res_randomid(); #ifdef USELOOPBACK _res.nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1); @@ -106,24 +207,59 @@ res_init() _res.nsaddr.sin_family = AF_INET; _res.nsaddr.sin_port = htons(NAMESERVER_PORT); _res.nscount = 1; + _res.ndots = 1; _res.pfcode = 0; /* Allow user to override the local domain definition */ if ((cp = getenv("LOCALDOMAIN")) != NULL) { - (void)strncpy(_res.defdname, cp, sizeof(_res.defdname)); - if ((cp = strpbrk(_res.defdname, " \t\n")) != NULL) - *cp = '\0'; + (void)strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1); haveenv++; + + /* + * Set search list to be blank-separated strings + * from rest of env value. Permits users of LOCALDOMAIN + * to still have a search list, and anyone to set the + * one that they want to use as an individual (even more + * important now that the rfc1535 stuff restricts searches) + */ + cp = _res.defdname; + pp = _res.dnsrch; + *pp++ = cp; + for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) { + if (*cp == '\n') /* silly backwards compat */ + break; + else if (*cp == ' ' || *cp == '\t') { + *cp = 0; + n = 1; + } else if (n) { + *pp++ = cp; + n = 0; + havesearch = 1; + } + } + /* null terminate last domain if there are excess */ + while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n') + cp++; + *cp = '\0'; + *pp++ = 0; } +#define MATCH(line, name) \ + (!strncmp(line, name, sizeof(name) - 1) && \ + (line[sizeof(name) - 1] == ' ' || \ + line[sizeof(name) - 1] == '\t')) + +#ifdef NeXT + if (netinfo_res_init(&haveenv, &havesearch) == 0) +#endif if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { /* read the config file */ while (fgets(buf, sizeof(buf), fp) != NULL) { /* skip comments */ - if ((*buf == ';') || (*buf == '#')) + if (*buf == ';' || *buf == '#') continue; /* read default domain name */ - if (!strncmp(buf, "domain", sizeof("domain") - 1)) { + if (MATCH(buf, "domain")) { if (haveenv) /* skip if have from environ */ continue; cp = buf + sizeof("domain") - 1; @@ -131,15 +267,14 @@ res_init() cp++; if ((*cp == '\0') || (*cp == '\n')) continue; - (void)strncpy(_res.defdname, cp, - sizeof(_res.defdname) - 1); + strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1); if ((cp = strpbrk(_res.defdname, " \t\n")) != NULL) *cp = '\0'; havesearch = 0; continue; } /* set search list */ - if (!strncmp(buf, "search", sizeof("search") - 1)) { + if (MATCH(buf, "search")) { if (haveenv) /* skip if have from environ */ continue; cp = buf + sizeof("search") - 1; @@ -147,8 +282,7 @@ res_init() cp++; if ((*cp == '\0') || (*cp == '\n')) continue; - (void)strncpy(_res.defdname, cp, - sizeof(_res.defdname) - 1); + strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1); if ((cp = strchr(_res.defdname, '\n')) != NULL) *cp = '\0'; /* @@ -176,9 +310,8 @@ res_init() continue; } /* read nameservers to query */ - if (!strncmp(buf, "nameserver", sizeof("nameserver") - 1) && - nserv < MAXNS) { - struct in_addr a; + if (MATCH(buf, "nameserver") && nserv < MAXNS) { + struct in_addr a; cp = buf + sizeof("nameserver") - 1; while (*cp == ' ' || *cp == '\t') @@ -192,32 +325,324 @@ res_init() } continue; } +#ifdef RESOLVSORT + if (MATCH(buf, "sortlist")) { + struct in_addr a; + + cp = buf + sizeof("sortlist") - 1; + while (nsort < MAXRESOLVSORT) { + while (*cp == ' ' || *cp == '\t') + cp++; + if (*cp == '\0' || *cp == '\n' || *cp == ';') + break; + net = cp; + while (*cp && !ISSORTMASK(*cp) && *cp != ';' && + isascii(*cp) && !isspace(*cp)) + cp++; + n = *cp; + *cp = 0; + if (inet_aton(net, &a)) { + _res.sort_list[nsort].addr = a; + if (ISSORTMASK(n)) { + *cp++ = n; + net = cp; + while (*cp && *cp != ';' && + isascii(*cp) && !isspace(*cp)) + cp++; + n = *cp; + *cp = 0; + if (inet_aton(net, &a)) { + _res.sort_list[nsort].mask = a.s_addr; + } else { + _res.sort_list[nsort].mask = + net_mask(_res.sort_list[nsort].addr); + } + } else { + _res.sort_list[nsort].mask = + net_mask(_res.sort_list[nsort].addr); + } + nsort++; + } + *cp = n; + } + continue; + } +#endif + if (MATCH(buf, "options")) { + res_setoptions(buf + sizeof("options") - 1, "conf"); + continue; + } } if (nserv > 1) _res.nscount = nserv; +#ifdef RESOLVSORT + _res.nsort = nsort; +#endif (void) fclose(fp); } - if (_res.defdname[0] == 0) { - if (gethostname(buf, sizeof(_res.defdname)) == 0 && - (cp = strchr(buf, '.'))) - (void)strcpy(_res.defdname, cp + 1); - } + if (_res.defdname[0] == 0 && + gethostname(buf, sizeof(_res.defdname) - 1) == 0 && + (cp = strchr(buf, '.')) != NULL) + strcpy(_res.defdname, cp + 1); /* find components of local domain that might be searched */ if (havesearch == 0) { pp = _res.dnsrch; *pp++ = _res.defdname; - for (cp = _res.defdname, n = 0; *cp; cp++) - if (*cp == '.') - n++; + *pp = NULL; + +#ifndef RFC1535 + dots = 0; + for (cp = _res.defdname; *cp; cp++) + dots += (*cp == '.'); + cp = _res.defdname; - for (; n >= LOCALDOMAINPARTS && pp < _res.dnsrch + MAXDFLSRCH; - n--) { - cp = strchr(cp, '.'); - *pp++ = ++cp; + while (pp < _res.dnsrch + MAXDFLSRCH) { + if (dots < LOCALDOMAINPARTS) + break; + cp = strchr(cp, '.') + 1; /* we know there is one */ + *pp++ = cp; + dots--; } - *pp++ = 0; + *pp = NULL; +#ifdef DEBUG + if (_res.options & RES_DEBUG) { + printf(";; res_init()... default dnsrch list:\n"); + for (pp = _res.dnsrch; *pp; pp++) + printf(";;\t%s\n", *pp); + printf(";;\t..END..\n"); + } +#endif /* DEBUG */ +#endif /* !RFC1535 */ } + + if ((cp = getenv("RES_OPTIONS")) != NULL) + res_setoptions(cp, "env"); _res.options |= RES_INIT; return (0); } + +static void +res_setoptions(options, source) + char *options, *source; +{ + char *cp = options; + int i; + +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf(";; res_setoptions(\"%s\", \"%s\")...\n", + options, source); +#endif + while (*cp) { + /* skip leading and inner runs of spaces */ + while (*cp == ' ' || *cp == '\t') + cp++; + /* search for and process individual options */ + if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) { + i = atoi(cp + sizeof("ndots:") - 1); + if (i <= RES_MAXNDOTS) + _res.ndots = i; + else + _res.ndots = RES_MAXNDOTS; +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf(";;\tndots=%d\n", _res.ndots); +#endif + } else if (!strncmp(cp, "debug", sizeof("debug") - 1)) { +#ifdef DEBUG + if (!(_res.options & RES_DEBUG)) { + printf(";; res_setoptions(\"%s\", \"%s\")..\n", + options, source); + _res.options |= RES_DEBUG; + } + printf(";;\tdebug\n"); +#endif + } else { + /* XXX - print a warning here? */ + } + /* skip to next run of spaces */ + while (*cp && *cp != ' ' && *cp != '\t') + cp++; + } +} + +#ifdef RESOLVSORT +/* XXX - should really support CIDR which means explicit masks always. */ +static u_int32_t +net_mask(in) /* XXX - should really use system's version of this */ + struct in_addr in; +{ + register u_int32_t i = ntohl(in.s_addr); + + if (IN_CLASSA(i)) + return (htonl(IN_CLASSA_NET)); + else if (IN_CLASSB(i)) + return (htonl(IN_CLASSB_NET)); + return (htonl(IN_CLASSC_NET)); +} +#endif + +#ifdef NeXT +static int +netinfo_res_init(haveenv, havesearch) + int *haveenv; + int *havesearch; +{ + register int n; + void *domain, *parent; + ni_id dir; + ni_status status; + ni_namelist nl; + int nserv = 0; +#ifdef RESOLVSORT + int nsort = 0; +#endif + + status = ni_open(NULL, ".", &domain); + if (status == NI_OK) { + ni_setreadtimeout(domain, NI_TIMEOUT); + ni_setabort(domain, 1); + + /* climb the NetInfo hierarchy to find a resolver directory */ + while (status == NI_OK) { + status = ni_pathsearch(domain, &dir, NI_PATH_RESCONF); + if (status == NI_OK) { + /* found a resolver directory */ + + if (*haveenv == 0) { + /* get the default domain name */ + status = ni_lookupprop(domain, &dir, "domain", &nl); + if (status == NI_OK && nl.ni_namelist_len > 0) { + (void)strncpy(_res.defdname, + nl.ni_namelist_val[0], + sizeof(_res.defdname) - 1); + _res.defdname[sizeof(_res.defdname) - 1] = '\0'; + ni_namelist_free(&nl); + *havesearch = 0; + } + + /* get search list */ + status = ni_lookupprop(domain, &dir, "search", &nl); + if (status == NI_OK && nl.ni_namelist_len > 0) { + (void)strncpy(_res.defdname, + nl.ni_namelist_val[0], + sizeof(_res.defdname) - 1); + _res.defdname[sizeof(_res.defdname) - 1] = '\0'; + /* copy */ + for (n = 0; + n < nl.ni_namelist_len && n < MAXDNSRCH; + n++) { + /* duplicate up to MAXDNSRCH servers */ + char *cp = nl.ni_namelist_val[n]; + _res.dnsrch[n] = + strcpy((char *)malloc(strlen(cp) + 1), cp); + } + ni_namelist_free(&nl); + *havesearch = 1; + } + } + + /* get list of nameservers */ + status = ni_lookupprop(domain, &dir, "nameserver", &nl); + if (status == NI_OK && nl.ni_namelist_len > 0) { + /* copy up to MAXNS servers */ + for (n = 0; + n < nl.ni_namelist_len && nserv < MAXNS; + n++) { + struct in_addr a; + + if (inet_aton(nl.ni_namelist_val[n], &a)) { + _res.nsaddr_list[nserv].sin_addr = a; + _res.nsaddr_list[nserv].sin_family = AF_INET; + _res.nsaddr_list[nserv].sin_port = + htons(NAMESERVER_PORT); + nserv++; + } + } + ni_namelist_free(&nl); + } + + if (nserv > 1) + _res.nscount = nserv; + +#ifdef RESOLVSORT + /* get sort order */ + status = ni_lookupprop(domain, &dir, "sortlist", &nl); + if (status == NI_OK && nl.ni_namelist_len > 0) { + + /* copy up to MAXRESOLVSORT address/netmask pairs */ + for (n = 0; + n < nl.ni_namelist_len && nsort < MAXRESOLVSORT; + n++) { + char ch; + char *cp; + const char *sp; + struct in_addr a; + + cp = NULL; + for (sp = sort_mask; *sp; sp++) { + char *cp1; + cp1 = strchr(nl.ni_namelist_val[n], *sp); + if (cp && cp1) + cp = (cp < cp1)? cp : cp1; + else if (cp1) + cp = cp1; + } + if (cp != NULL) { + ch = *cp; + *cp = '\0'; + break; + } + if (inet_aton(nl.ni_namelist_val[n], &a)) { + _res.sort_list[nsort].addr = a; + if (*cp && ISSORTMASK(ch)) { + *cp++ = ch; + if (inet_aton(cp, &a)) { + _res.sort_list[nsort].mask = a.s_addr; + } else { + _res.sort_list[nsort].mask = + net_mask(_res.sort_list[nsort].addr); + } + } else { + _res.sort_list[nsort].mask = + net_mask(_res.sort_list[nsort].addr); + } + nsort++; + } + } + ni_namelist_free(&nl); + } + + _res.nsort = nsort; +#endif + + /* get resolver options */ + status = ni_lookupprop(domain, &dir, "options", &nl); + if (status == NI_OK && nl.ni_namelist_len > 0) { + res_setoptions(nl.ni_namelist_val[0], "conf"); + ni_namelist_free(&nl); + } + + ni_free(domain); + return(1); /* using DNS configuration from NetInfo */ + } + + status = ni_open(domain, "..", &parent); + ni_free(domain); + if (status == NI_OK) + domain = parent; + } + } + return(0); /* if not using DNS configuration from NetInfo */ +} +#endif /* NeXT */ + +u_int16_t +res_randomid() +{ + struct timeval now; + + gettimeofday(&now, NULL); + return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid())); +} diff --git a/lib/libc/net/res_mkquery.c b/lib/libc/net/res_mkquery.c index a284562..76786db 100644 --- a/lib/libc/net/res_mkquery.c +++ b/lib/libc/net/res_mkquery.c @@ -1,7 +1,9 @@ -/*- +/* + * ++Copyright++ 1985, 1993 + * - * Copyright (c) 1985, 1993 - * The Regents of the University of California. All rights reserved. - * + * 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: @@ -12,12 +14,12 @@ * 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. + * 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 @@ -53,36 +55,53 @@ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)res_mkquery.c 8.1 (Berkeley) 6/4/93"; -static char rcsid[] = "$Id: res_mkquery.c,v 4.9.1.2 1993/05/17 10:00:01 vixie Exp $"; +static char rcsid[] = "$Id: res_mkquery.c,v 8.3 1995/06/29 09:26:28 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ #include #include #include -#include + #include -#include +#include +#include +#if defined(BSD) && (BSD >= 199103) +# include +#else +# include "../conf/portability.h" +#endif + +#if defined(USE_OPTIONS_H) +# include <../conf/options.h> +#endif /* * Form all types of queries. * Returns the size of the result or -1. */ +int res_mkquery(op, dname, class, type, data, datalen, newrr_in, buf, buflen) int op; /* opcode of query */ - const char *dname; /* domain name */ + const char *dname; /* domain name */ int class, type; /* class and type of query */ - const char *data; /* resource record data */ + const u_char *data; /* resource record data */ int datalen; /* length of data */ - const char *newrr_in; /* new rr for modify or append */ - char *buf; /* buffer to put query */ + const u_char *newrr_in; /* new rr for modify or append */ + u_char *buf; /* buffer to put query */ int buflen; /* size of buffer */ { register HEADER *hp; - register char *cp; + register u_char *cp; register int n; +#ifdef ALLOW_UPDATES struct rrec *newrr = (struct rrec *) newrr_in; - char *dnptrs[10], **dpp, **lastdnptr; +#endif + u_char *dnptrs[20], **dpp, **lastdnptr; + if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + h_errno = NETDB_INTERNAL; + return (-1); + } #ifdef DEBUG if (_res.options & RES_DEBUG) printf(";; res_mkquery(%d, %s, %d, %d)\n", @@ -91,37 +110,36 @@ res_mkquery(op, dname, class, type, data, datalen, newrr_in, buf, buflen) /* * Initialize header fields. */ - if ((buf == NULL) || (buflen < sizeof(HEADER))) - return(-1); - bzero(buf, sizeof(HEADER)); + if ((buf == NULL) || (buflen < HFIXEDSZ)) + return (-1); + bzero(buf, HFIXEDSZ); hp = (HEADER *) buf; hp->id = htons(++_res.id); hp->opcode = op; - hp->pr = (_res.options & RES_PRIMARY) != 0; hp->rd = (_res.options & RES_RECURSE) != 0; hp->rcode = NOERROR; - cp = buf + sizeof(HEADER); - buflen -= sizeof(HEADER); + cp = buf + HFIXEDSZ; + buflen -= HFIXEDSZ; dpp = dnptrs; *dpp++ = buf; *dpp++ = NULL; - lastdnptr = dnptrs + sizeof(dnptrs)/sizeof(dnptrs[0]); + lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0]; /* * perform opcode specific processing */ switch (op) { - case QUERY: + case QUERY: /*FALLTHROUGH*/ + case NS_NOTIFY_OP: if ((buflen -= QFIXEDSZ) < 0) - return(-1); - if ((n = dn_comp((u_char *)dname, (u_char *)cp, buflen, - (u_char **)dnptrs, (u_char **)lastdnptr)) < 0) + return (-1); + if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0) return (-1); cp += n; buflen -= n; - __putshort(type, (u_char *)cp); - cp += sizeof(u_int16_t); - __putshort(class, (u_char *)cp); - cp += sizeof(u_int16_t); + __putshort(type, cp); + cp += INT16SZ; + __putshort(class, cp); + cp += INT16SZ; hp->qdcount = htons(1); if (op == QUERY || data == NULL) break; @@ -129,19 +147,19 @@ res_mkquery(op, dname, class, type, data, datalen, newrr_in, buf, buflen) * Make an additional record for completion domain. */ buflen -= RRFIXEDSZ; - if ((n = dn_comp((u_char *)data, (u_char *)cp, buflen, - (u_char **)dnptrs, (u_char **)lastdnptr)) < 0) + n = dn_comp((char *)data, cp, buflen, dnptrs, lastdnptr); + if (n < 0) return (-1); cp += n; buflen -= n; - __putshort(T_NULL, (u_char *)cp); - cp += sizeof(u_int16_t); - __putshort(class, (u_char *)cp); - cp += sizeof(u_int16_t); - __putlong(0, (u_char *)cp); - cp += sizeof(u_int32_t); - __putshort(0, (u_char *)cp); - cp += sizeof(u_int16_t); + __putshort(T_NULL, cp); + cp += INT16SZ; + __putshort(class, cp); + cp += INT16SZ; + __putlong(0, cp); + cp += INT32SZ; + __putshort(0, cp); + cp += INT16SZ; hp->arcount = htons(1); break; @@ -152,14 +170,14 @@ res_mkquery(op, dname, class, type, data, datalen, newrr_in, buf, buflen) if (buflen < 1 + RRFIXEDSZ + datalen) return (-1); *cp++ = '\0'; /* no domain name */ - __putshort(type, (u_char *)cp); - cp += sizeof(u_int16_t); - __putshort(class, (u_char *)cp); - cp += sizeof(u_int16_t); - __putlong(0, (u_char *)cp); - cp += sizeof(u_int32_t); - __putshort(datalen, (u_char *)cp); - cp += sizeof(u_int16_t); + __putshort(type, cp); + cp += INT16SZ; + __putshort(class, cp); + cp += INT16SZ; + __putlong(0, cp); + cp += INT32SZ; + __putshort(datalen, cp); + cp += INT16SZ; if (datalen) { bcopy(data, cp, datalen); cp += datalen; @@ -187,13 +205,13 @@ res_mkquery(op, dname, class, type, data, datalen, newrr_in, buf, buflen) return (-1); cp += n; __putshort(type, cp); - cp += sizeof(u_int16_t); - __putshort(class, cp); - cp += sizeof(u_int16_t); + cp += INT16SZ; + __putshort(class, cp); + cp += INT16SZ; __putlong(0, cp); - cp += sizeof(u_int32_t); + cp += INT32SZ; __putshort(datalen, cp); - cp += sizeof(u_int16_t); + cp += INT16SZ; if (datalen) { bcopy(data, cp, datalen); cp += datalen; @@ -210,21 +228,22 @@ res_mkquery(op, dname, class, type, data, datalen, newrr_in, buf, buflen) return (-1); cp += n; __putshort(newrr->r_type, cp); - cp += sizeof(u_int16_t); - __putshort(newrr->r_class, cp); - cp += sizeof(u_int16_t); + cp += INT16SZ; + __putshort(newrr->r_class, cp); + cp += INT16SZ; __putlong(0, cp); - cp += sizeof(u_int32_t); + cp += INT32SZ; __putshort(newrr->r_size, cp); - cp += sizeof(u_int16_t); + cp += INT16SZ; if (newrr->r_size) { bcopy(newrr->r_data, cp, newrr->r_size); cp += newrr->r_size; } hp->ancount = htons(0); break; - #endif /* ALLOW_UPDATES */ + default: + return (-1); } return (cp - buf); } diff --git a/lib/libc/net/res_query.c b/lib/libc/net/res_query.c index 4980af1..8229fbc 100644 --- a/lib/libc/net/res_query.c +++ b/lib/libc/net/res_query.c @@ -1,7 +1,9 @@ -/*- +/* + * ++Copyright++ 1988, 1993 + * - * Copyright (c) 1988, 1993 - * The Regents of the University of California. All rights reserved. - * + * 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: @@ -12,12 +14,12 @@ * 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. + * 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 @@ -53,20 +55,29 @@ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)res_query.c 8.1 (Berkeley) 6/4/93"; -static char rcsid[] = "$Id: res_query.c,v 1.1 1993/06/01 09:42:14 vixie Exp vixie $"; +static char rcsid[] = "$Id: res_query.c,v 8.6 1995/06/29 09:26:28 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ #include #include #include #include + +#include #include #include -#include #include #include -#include -#include +#if defined(BSD) && (BSD >= 199306) +# include +# include +#else +# include "../conf/portability.h" +#endif + +#if defined(USE_OPTIONS_H) +# include <../conf/options.h> +#endif #if PACKETSZ > 1024 #define MAXPACKET PACKETSZ @@ -74,6 +85,7 @@ static char rcsid[] = "$Id: res_query.c,v 1.1 1993/06/01 09:42:14 vixie Exp vixi #define MAXPACKET 1024 #endif +char *__hostalias __P((const char *)); int h_errno; /* @@ -83,27 +95,33 @@ int h_errno; * if no error is indicated and the answer count is nonzero. * Return the size of the response on success, -1 on error. * Error number is left in h_errno. + * * Caller must parse answer and determine whether it answers the question. */ +int res_query(name, class, type, answer, anslen) - char *name; /* domain name */ + const char *name; /* domain name */ int class, type; /* class and type of query */ u_char *answer; /* buffer to put answer */ int anslen; /* size of answer buffer */ { - char buf[MAXPACKET]; - HEADER *hp; + u_char buf[MAXPACKET]; + register HEADER *hp = (HEADER *) answer; int n; - if ((_res.options & RES_INIT) == 0 && res_init() == -1) + hp->rcode = NOERROR; /* default */ + + if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + h_errno = NETDB_INTERNAL; return (-1); + } #ifdef DEBUG if (_res.options & RES_DEBUG) printf(";; res_query(%s, %d, %d)\n", name, class, type); #endif - n = res_mkquery(QUERY, name, class, type, (char *)NULL, 0, NULL, - buf, sizeof(buf)); + n = res_mkquery(QUERY, name, class, type, NULL, 0, NULL, + buf, sizeof(buf)); if (n <= 0) { #ifdef DEBUG if (_res.options & RES_DEBUG) @@ -112,17 +130,16 @@ res_query(name, class, type, answer, anslen) h_errno = NO_RECOVERY; return (n); } - n = res_send(buf, n, (char *)answer, anslen); + n = res_send(buf, n, answer, anslen); if (n < 0) { #ifdef DEBUG if (_res.options & RES_DEBUG) printf(";; res_query: send error\n"); #endif h_errno = TRY_AGAIN; - return(n); + return (n); } - hp = (HEADER *) answer; if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { #ifdef DEBUG if (_res.options & RES_DEBUG) @@ -130,104 +147,165 @@ res_query(name, class, type, answer, anslen) ntohs(hp->ancount)); #endif switch (hp->rcode) { - case NXDOMAIN: - h_errno = HOST_NOT_FOUND; - break; - case SERVFAIL: - h_errno = TRY_AGAIN; - break; - case NOERROR: - h_errno = NO_DATA; - break; - case FORMERR: - case NOTIMP: - case REFUSED: - default: - h_errno = NO_RECOVERY; - break; + case NXDOMAIN: + h_errno = HOST_NOT_FOUND; + break; + case SERVFAIL: + h_errno = TRY_AGAIN; + break; + case NOERROR: + h_errno = NO_DATA; + break; + case FORMERR: + case NOTIMP: + case REFUSED: + default: + h_errno = NO_RECOVERY; + break; } return (-1); } - return(n); + return (n); } /* * Formulate a normal query, send, and retrieve answer in supplied buffer. * Return the size of the response on success, -1 on error. * If enabled, implement search rules until answer or unrecoverable failure - * is detected. Error number is left in h_errno. - * Only useful for queries in the same name hierarchy as the local host - * (not, for example, for host address-to-name lookups in domain in-addr.arpa). + * is detected. Error code, if any, is left in h_errno. */ int res_search(name, class, type, answer, anslen) - char *name; /* domain name */ + const char *name; /* domain name */ int class, type; /* class and type of query */ u_char *answer; /* buffer to put answer */ int anslen; /* size of answer */ { - register char *cp, **domain; - int n, ret, got_nodata = 0; - char *__hostalias(); + register const char *cp, * const *domain; + HEADER *hp = (HEADER *) answer; + u_int dots; + int trailing_dot, ret, saved_herrno; + int got_nodata = 0, got_servfail = 0, tried_as_is = 0; - if ((_res.options & RES_INIT) == 0 && res_init() == -1) + if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + h_errno = NETDB_INTERNAL; return (-1); - + } errno = 0; h_errno = HOST_NOT_FOUND; /* default, if we never query */ - for (cp = name, n = 0; *cp; cp++) - if (*cp == '.') - n++; - if (n == 0 && (cp = __hostalias(name))) + dots = 0; + for (cp = name; *cp; cp++) + dots += (*cp == '.'); + trailing_dot = 0; + if (cp > name && *--cp == '.') + trailing_dot++; + + /* + * if there aren't any dots, it could be a user-level alias + */ + if (!dots && (cp = __hostalias(name)) != NULL) return (res_query(cp, class, type, answer, anslen)); /* + * If there are dots in the name already, let's just give it a try + * 'as is'. The threshold can be set with the "ndots" option. + */ + saved_herrno = -1; + if (dots >= _res.ndots) { + ret = res_querydomain(name, NULL, class, type, answer, anslen); + if (ret > 0) + return (ret); + saved_herrno = h_errno; + tried_as_is++; + } + + /* * We do at least one level of search if * - there is no dot and RES_DEFNAME is set, or * - there is at least one dot, there is no trailing dot, * and RES_DNSRCH is set. */ - if ((n == 0 && _res.options & RES_DEFNAMES) || - (n != 0 && *--cp != '.' && _res.options & RES_DNSRCH)) - for (domain = _res.dnsrch; *domain; domain++) { - ret = res_querydomain(name, *domain, class, type, - answer, anslen); + if ((!dots && (_res.options & RES_DEFNAMES)) || + (dots && !trailing_dot && (_res.options & RES_DNSRCH))) { + int done = 0; + + for (domain = (const char * const *)_res.dnsrch; + *domain && !done; + domain++) { + + ret = res_querydomain(name, *domain, class, type, + answer, anslen); + if (ret > 0) + return (ret); + + /* + * If no server present, give up. + * If name isn't found in this domain, + * keep trying higher domains in the search list + * (if that's enabled). + * On a NO_DATA error, keep trying, otherwise + * a wildcard entry of another type could keep us + * from finding this entry higher in the domain. + * If we get some other error (negative answer or + * server failure), then stop searching up, + * but try the input name below in case it's + * fully-qualified. + */ + if (errno == ECONNREFUSED) { + h_errno = TRY_AGAIN; + return (-1); + } + + switch (h_errno) { + case NO_DATA: + got_nodata++; + /* FALLTHROUGH */ + case HOST_NOT_FOUND: + /* keep trying */ + break; + case TRY_AGAIN: + if (hp->rcode == SERVFAIL) { + /* try next search element, if any */ + got_servfail++; + break; + } + /* FALLTHROUGH */ + default: + /* anything else implies that we're done */ + done++; + } + + /* if we got here for some reason other than DNSRCH, + * we only wanted one iteration of the loop, so stop. + */ + if (!(_res.options & RES_DNSRCH)) + done++; + } + } + + /* if we have not already tried the name "as is", do that now. + * note that we do this regardless of how many dots were in the + * name or whether it ends with a dot. + */ + if (!tried_as_is) { + ret = res_querydomain(name, NULL, class, type, answer, anslen); if (ret > 0) return (ret); - /* - * If no server present, give up. - * If name isn't found in this domain, - * keep trying higher domains in the search list - * (if that's enabled). - * On a NO_DATA error, keep trying, otherwise - * a wildcard entry of another type could keep us - * from finding this entry higher in the domain. - * If we get some other error (negative answer or - * server failure), then stop searching up, - * but try the input name below in case it's fully-qualified. - */ - if (errno == ECONNREFUSED) { - h_errno = TRY_AGAIN; - return (-1); - } - if (h_errno == NO_DATA) - got_nodata++; - if ((h_errno != HOST_NOT_FOUND && h_errno != NO_DATA) || - (_res.options & RES_DNSRCH) == 0) - break; } - /* - * If the search/default failed, try the name as fully-qualified, - * but only if it contained at least one dot (even trailing). - * This is purely a heuristic; we assume that any reasonable query - * about a top-level domain (for servers, SOA, etc) will not use - * res_search. + + /* if we got here, we didn't satisfy the search. + * if we did an initial full query, return that query's h_errno + * (note that we wouldn't be here if that query had succeeded). + * else if we ever got a nodata, send that back as the reason. + * else send back meaningless h_errno, that being the one from + * the last DNSRCH we did. */ - if (n && (ret = res_querydomain(name, (char *)NULL, class, type, - answer, anslen)) > 0) - return (ret); - if (got_nodata) + if (saved_herrno != -1) + h_errno = saved_herrno; + else if (got_nodata) h_errno = NO_DATA; + else if (got_servfail) + h_errno = TRY_AGAIN; return (-1); } @@ -235,20 +313,25 @@ res_search(name, class, type, answer, anslen) * Perform a call on res_query on the concatenation of name and domain, * removing a trailing dot from name if domain is NULL. */ +int res_querydomain(name, domain, class, type, answer, anslen) - char *name, *domain; + const char *name, *domain; int class, type; /* class and type of query */ u_char *answer; /* buffer to put answer */ int anslen; /* size of answer */ { char nbuf[2*MAXDNAME+2]; - char *longname = nbuf; + const char *longname = nbuf; int n; + if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + h_errno = NETDB_INTERNAL; + return (-1); + } #ifdef DEBUG if (_res.options & RES_DEBUG) printf(";; res_querydomain(%s, %s, %d, %d)\n", - name, domain, class, type); + name, domain?domain:"", class, type); #endif if (domain == NULL) { /* @@ -256,14 +339,13 @@ res_querydomain(name, domain, class, type, answer, anslen) * copy without '.' if present. */ n = strlen(name) - 1; - if (name[n] == '.' && n < sizeof(nbuf) - 1) { + if (n != (0 - 1) && name[n] == '.' && n < sizeof(nbuf) - 1) { bcopy(name, nbuf, n); nbuf[n] = '\0'; } else longname = name; } else - (void)sprintf(nbuf, "%.*s.%.*s", - MAXDNAME, name, MAXDNAME, domain); + sprintf(nbuf, "%.*s.%.*s", MAXDNAME, name, MAXDNAME, domain); return (res_query(longname, class, type, answer, anslen)); } @@ -272,28 +354,34 @@ char * __hostalias(name) register const char *name; { - register char *C1, *C2; + register char *cp1, *cp2; FILE *fp; - char *file, *getenv(), *strcpy(), *strncpy(); + char *file; char buf[BUFSIZ]; static char abuf[MAXDNAME]; + if (_res.options & RES_NOALIASES) + return (NULL); file = getenv("HOSTALIASES"); if (file == NULL || (fp = fopen(file, "r")) == NULL) return (NULL); + setbuf(fp, NULL); buf[sizeof(buf) - 1] = '\0'; while (fgets(buf, sizeof(buf), fp)) { - for (C1 = buf; *C1 && !isspace(*C1); ++C1); - if (!*C1) + for (cp1 = buf; *cp1 && !isspace(*cp1); ++cp1) + ; + if (!*cp1) break; - *C1 = '\0'; + *cp1 = '\0'; if (!strcasecmp(buf, name)) { - while (isspace(*++C1)); - if (!*C1) + while (isspace(*++cp1)) + ; + if (!*cp1) break; - for (C2 = C1 + 1; *C2 && !isspace(*C2); ++C2); - abuf[sizeof(abuf) - 1] = *C2 = '\0'; - (void)strncpy(abuf, C1, sizeof(abuf) - 1); + for (cp2 = cp1 + 1; *cp2 && !isspace(*cp2); ++cp2) + ; + abuf[sizeof(abuf) - 1] = *cp2 = '\0'; + strncpy(abuf, cp1, sizeof(abuf) - 1); fclose(fp); return (abuf); } diff --git a/lib/libc/net/res_send.c b/lib/libc/net/res_send.c index 5c80cf4..427e82a 100644 --- a/lib/libc/net/res_send.c +++ b/lib/libc/net/res_send.c @@ -1,7 +1,9 @@ -/*- +/* + * ++Copyright++ 1985, 1989, 1993 + * - * Copyright (c) 1985, 1989, 1993 - * The Regents of the University of California. All rights reserved. - * + * 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: @@ -12,12 +14,12 @@ * 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. + * 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 @@ -53,9 +55,16 @@ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93"; -static char rcsid[] = "$Id: res_send.c,v 4.9.1.1 1993/05/02 22:43:03 vixie Rel $"; +static char rcsid[] = "$Id: res_send.c,v 8.7 1995/12/03 08:31:17 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ + /* change this to "0" + * if you talk to a lot + * of multi-homed SunOS + * ("broken") name servers. + */ +#define CHECK_SRVR_ADDR 1 /* XXX - should be in options.h */ + /* * Send query to name server and wait for reply. */ @@ -67,16 +76,31 @@ static char rcsid[] = "$Id: res_send.c,v 4.9.1.1 1993/05/02 22:43:03 vixie Rel $ #include #include #include + #include +#include #include #include -#include -#include +#if defined(BSD) && (BSD >= 199306) +# include +# include +# include +#else +# include "../conf/portability.h" +#endif + +#if defined(USE_OPTIONS_H) +# include <../conf/options.h> +#endif + +void _res_close __P((void)); static int s = -1; /* socket used for communications */ -static struct sockaddr no_addr; +static int connected = 0; /* is the socket connected */ +static int vc = 0; /* is the socket a virtual ciruit? */ #ifndef FD_SET +/* XXX - should be in portability.h */ #define NFDBITS 32 #define FD_SETSIZE 32 #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) @@ -85,121 +109,317 @@ static struct sockaddr no_addr; #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) #endif -res_send(buf, buflen, answer, anslen) - const char *buf; +/* XXX - this should be done in portability.h */ +#if (defined(BSD) && (BSD >= 199103)) || defined(linux) +# define CAN_RECONNECT 1 +#else +# define CAN_RECONNECT 0 +#endif + +#ifndef DEBUG +# define Dprint(cond, args) /*empty*/ +# define DprintQ(cond, args, query, size) /*empty*/ +# define Aerror(file, string, error, address) /*empty*/ +# define Perror(file, string, error) /*empty*/ +#else +# define Dprint(cond, args) if (cond) {fprintf args;} else {} +# define DprintQ(cond, args, query, size) if (cond) {\ + fprintf args;\ + __fp_nquery(query, size, stdout);\ + } else {} + static void + Aerror(file, string, error, address) + FILE *file; + char *string; + int error; + struct sockaddr_in address; + { + int save = errno; + + if (_res.options & RES_DEBUG) { + fprintf(file, "res_send: %s ([%s].%u): %s\n", + string, + inet_ntoa(address.sin_addr), + ntohs(address.sin_port), + strerror(error)); + } + errno = save; + } + static void + Perror(file, string, error) + FILE *file; + char *string; + int error; + { + int save = errno; + + if (_res.options & RES_DEBUG) { + fprintf(file, "res_send: %s: %s\n", + string, strerror(error)); + } + errno = save; + } +#endif + +static res_send_qhook Qhook = NULL; +static res_send_rhook Rhook = NULL; + +void +res_send_setqhook(hook) + res_send_qhook hook; +{ + + Qhook = hook; +} + +void +res_send_setrhook(hook) + res_send_rhook hook; +{ + + Rhook = hook; +} + +/* int + * res_isourserver(ina) + * looks up "ina" in _res.ns_addr_list[] + * returns: + * 0 : not found + * >0 : found + * author: + * paul vixie, 29may94 + */ +int +res_isourserver(inp) + const struct sockaddr_in *inp; +{ + struct sockaddr_in ina; + register int ns, ret; + + ina = *inp; + ret = 0; + for (ns = 0; ns < _res.nscount; ns++) { + register const struct sockaddr_in *srv = &_res.nsaddr_list[ns]; + + if (srv->sin_family == ina.sin_family && + srv->sin_port == ina.sin_port && + (srv->sin_addr.s_addr == INADDR_ANY || + srv->sin_addr.s_addr == ina.sin_addr.s_addr)) { + ret++; + break; + } + } + return (ret); +} + +/* int + * res_nameinquery(name, type, class, buf, eom) + * look for (name,type,class) in the query section of packet (buf,eom) + * returns: + * -1 : format error + * 0 : not found + * >0 : found + * author: + * paul vixie, 29may94 + */ +int +res_nameinquery(name, type, class, buf, eom) + const char *name; + register int type, class; + const u_char *buf, *eom; +{ + register const u_char *cp = buf + HFIXEDSZ; + int qdcount = ntohs(((HEADER*)buf)->qdcount); + + while (qdcount-- > 0) { + char tname[MAXDNAME+1]; + register int n, ttype, tclass; + + n = dn_expand(buf, eom, cp, tname, sizeof tname); + if (n < 0) + return (-1); + cp += n; + ttype = _getshort(cp); cp += INT16SZ; + tclass = _getshort(cp); cp += INT16SZ; + if (ttype == type && + tclass == class && + strcasecmp(tname, name) == 0) + 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 + */ +int +res_queriesmatch(buf1, eom1, buf2, eom2) + const u_char *buf1, *eom1; + const u_char *buf2, *eom2; +{ + register const u_char *cp = buf1 + HFIXEDSZ; + int qdcount = ntohs(((HEADER*)buf1)->qdcount); + + if (qdcount != ntohs(((HEADER*)buf2)->qdcount)) + return (0); + while (qdcount-- > 0) { + char tname[MAXDNAME+1]; + register int n, ttype, tclass; + + n = dn_expand(buf1, eom1, cp, tname, sizeof tname); + if (n < 0) + return (-1); + cp += n; + ttype = _getshort(cp); cp += INT16SZ; + tclass = _getshort(cp); cp += INT16SZ; + if (!res_nameinquery(tname, ttype, tclass, buf2, eom2)) + return (0); + } + return (1); +} + +int +res_send(buf, buflen, ans, anssiz) + const u_char *buf; int buflen; - char *answer; - int anslen; + u_char *ans; + int anssiz; { - register int n; - int try, v_circuit, resplen, ns; - int gotsomewhere = 0, connected = 0; - int connreset = 0; - u_short id, len; - char *cp; - fd_set dsmask; - struct timeval timeout; HEADER *hp = (HEADER *) buf; - HEADER *anhp = (HEADER *) answer; - u_int badns; /* XXX NSMAX can't exceed #/bits per this */ - struct iovec iov[2]; - int terrno = ETIMEDOUT; - char junk[512]; - -#ifdef DEBUG - if ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_QUERY)) { - printf(";; res_send()\n"); - __p_query(buf); + HEADER *anhp = (HEADER *) ans; + int gotsomewhere, connreset, terrno, try, v_circuit, resplen, ns; + register int n; + u_int badns; /* XXX NSMAX can't exceed #/bits in this var */ + + if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + /* errno should have been set by res_init() in this case. */ + return (-1); } -#endif - if (!(_res.options & RES_INIT)) - if (res_init() == -1) { - return(-1); - } + DprintQ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_QUERY), + (stdout, ";; res_send()\n"), buf, buflen); v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; - id = hp->id; + gotsomewhere = 0; + connreset = 0; + terrno = ETIMEDOUT; badns = 0; + /* * Send request, RETRY times, or until successful */ for (try = 0; try < _res.retry; try++) { for (ns = 0; ns < _res.nscount; ns++) { - if (badns & (1<sin_addr))); + if (v_circuit) { - int truncated = 0; + int truncated; + struct iovec iov[2]; + u_short len; + u_char *cp; /* * Use virtual circuit; * at most one attempt per server. */ try = _res.retry; - if (s < 0) { - s = socket(AF_INET, SOCK_STREAM, 0); + truncated = 0; + if ((s < 0) || (!vc)) { + if (s >= 0) + _res_close(); + + s = socket(PF_INET, SOCK_STREAM, 0); if (s < 0) { terrno = errno; -#ifdef DEBUG - if (_res.options & RES_DEBUG) - perror("socket (vc) failed"); -#endif - continue; + Perror(stderr, "socket(vc)", errno); + return (-1); } - if (connect(s, - (struct sockaddr *)&(_res.nsaddr_list[ns]), - sizeof(struct sockaddr)) < 0) { + errno = 0; + if (connect(s, (struct sockaddr *)nsap, + sizeof(struct sockaddr)) < 0) { terrno = errno; -#ifdef DEBUG - if (_res.options & RES_DEBUG) - perror("connect failed"); -#endif - (void) close(s); - s = -1; - continue; + Aerror(stderr, "connect/vc", + errno, *nsap); + badns |= (1 << ns); + _res_close(); + goto next_ns; } + vc = 1; } /* * Send length & message */ - len = htons((u_short)buflen); + putshort((u_short)buflen, (u_char*)&len); iov[0].iov_base = (caddr_t)&len; - iov[0].iov_len = sizeof(len); - iov[1].iov_base = (char *)buf; + iov[0].iov_len = INT16SZ; + iov[1].iov_base = (caddr_t)buf; iov[1].iov_len = buflen; - if (writev(s, iov, 2) != sizeof(len) + buflen) { + if (writev(s, iov, 2) != (INT16SZ + buflen)) { terrno = errno; -#ifdef DEBUG - if (_res.options & RES_DEBUG) - perror("write failed"); -#endif - (void) close(s); - s = -1; - continue; + Perror(stderr, "write failed", errno); + badns |= (1 << ns); + _res_close(); + goto next_ns; } /* * Receive length & response */ - cp = answer; - len = sizeof(short); - while (len != 0 && - (n = read(s, (char *)cp, (int)len)) > 0) { + cp = ans; + len = INT16SZ; + while ((n = read(s, (char *)cp, (int)len)) > 0) { cp += n; - len -= n; + if ((len -= n) <= 0) + break; } if (n <= 0) { terrno = errno; -#ifdef DEBUG - if (_res.options & RES_DEBUG) - perror("read failed"); -#endif - (void) close(s); - s = -1; + Perror(stderr, "read failed", errno); + _res_close(); /* * A long running process might get its TCP * connection reset if the remote server was @@ -211,35 +431,32 @@ res_send(buf, buflen, answer, anslen) */ if (terrno == ECONNRESET && !connreset) { connreset = 1; - ns--; + _res_close(); + goto same_ns; } - continue; + _res_close(); + goto next_ns; } - cp = answer; - if ((resplen = ntohs(*(u_short *)cp)) > anslen) { -#ifdef DEBUG - if (_res.options & RES_DEBUG) - fprintf(stderr, - ";; response truncated\n"); -#endif - len = anslen; + resplen = _getshort(ans); + if (resplen > anssiz) { + Dprint(_res.options & RES_DEBUG, + (stdout, ";; response truncated\n") + ); truncated = 1; + len = anssiz; } else len = resplen; + cp = ans; while (len != 0 && - (n = read(s, (char *)cp, (int)len)) > 0) { + (n = read(s, (char *)cp, (int)len)) > 0) { cp += n; len -= n; } if (n <= 0) { terrno = errno; -#ifdef DEBUG - if (_res.options & RES_DEBUG) - perror("read failed"); -#endif - (void) close(s); - s = -1; - continue; + Perror(stderr, "read(vc)", errno); + _res_close(); + goto next_ns; } if (truncated) { /* @@ -247,10 +464,13 @@ res_send(buf, buflen, answer, anslen) * so connection stays in synch. */ anhp->tc = 1; - len = resplen - anslen; + len = resplen - anssiz; while (len != 0) { - n = (len > sizeof(junk) ? - sizeof(junk) : len); + char junk[PACKETSZ]; + + n = (len > sizeof(junk) + ? sizeof(junk) + : len); if ((n = read(s, junk, n)) > 0) len -= n; else @@ -261,19 +481,26 @@ res_send(buf, buflen, answer, anslen) /* * Use datagrams. */ - if (s < 0) { - s = socket(AF_INET, SOCK_DGRAM, 0); + struct timeval timeout; + fd_set dsmask; + struct sockaddr_in from; + int fromlen; + + if ((s < 0) || vc) { + if (vc) + _res_close(); + s = socket(PF_INET, SOCK_DGRAM, 0); if (s < 0) { - terrno = errno; -#ifdef DEBUG - if (_res.options & RES_DEBUG) - perror("socket (dg) failed"); +#if !CAN_RECONNECT + bad_dg_sock: #endif - continue; + terrno = errno; + Perror(stderr, "socket(dg)", errno); + return (-1); } + connected = 0; } /* - * I'm tired of answering this question, so: * On a 4.3BSD+ machine (client and server, * actually), sending to a nameserver datagram * port with no nameserver will cause an @@ -290,29 +517,27 @@ res_send(buf, buflen, answer, anslen) */ if (_res.nscount == 1 || (try == 0 && ns == 0)) { /* - * Don't use connect if we might - * still receive a response - * from another server. + * Connect only if we are sure we won't + * receive a response from another server. */ - if (connected == 0) { - if (connect(s, - (struct sockaddr *) - &_res.nsaddr_list[ns], - sizeof(struct sockaddr)) < 0) { -#ifdef DEBUG - if (_res.options & RES_DEBUG) - perror("connect"); -#endif - continue; + if (!connected) { + if (connect(s, (struct sockaddr *)nsap, + sizeof(struct sockaddr) + ) < 0) { + Aerror(stderr, + "connect(dg)", + errno, *nsap); + badns |= (1 << ns); + _res_close(); + goto next_ns; } connected = 1; } - if (send(s, buf, buflen, 0) != buflen) { -#ifdef DEBUG - if (_res.options & RES_DEBUG) - perror("send"); -#endif - continue; + if (send(s, (char*)buf, buflen, 0) != buflen) { + Perror(stderr, "send", errno); + badns |= (1 << ns); + _res_close(); + goto next_ns; } } else { /* @@ -320,18 +545,36 @@ res_send(buf, buflen, answer, anslen) * for responses from more than one server. */ if (connected) { - (void) connect(s, &no_addr, - sizeof(no_addr)); +#if CAN_RECONNECT + struct sockaddr_in no_addr; + + no_addr.sin_family = AF_INET; + no_addr.sin_addr.s_addr = INADDR_ANY; + no_addr.sin_port = 0; + (void) connect(s, + (struct sockaddr *) + &no_addr, + sizeof(no_addr)); +#else + int s1 = socket(PF_INET, SOCK_DGRAM,0); + if (s1 < 0) + goto bad_dg_sock; + (void) dup2(s1, s); + (void) close(s1); + Dprint(_res.options & RES_DEBUG, + (stdout, ";; new DG socket\n")) +#endif connected = 0; + errno = 0; } - if (sendto(s, buf, buflen, 0, - (struct sockaddr *)&_res.nsaddr_list[ns], - sizeof(struct sockaddr)) != buflen) { -#ifdef DEBUG - if (_res.options & RES_DEBUG) - perror("sendto"); -#endif - continue; + if (sendto(s, (char*)buf, buflen, 0, + (struct sockaddr *)nsap, + sizeof(struct sockaddr)) + != buflen) { + Aerror(stderr, "sendto", errno, *nsap); + badns |= (1 << ns); + _res_close(); + goto next_ns; } } @@ -344,106 +587,157 @@ res_send(buf, buflen, answer, anslen) if ((long) timeout.tv_sec <= 0) timeout.tv_sec = 1; timeout.tv_usec = 0; -wait: + wait: FD_ZERO(&dsmask); FD_SET(s, &dsmask); n = select(s+1, &dsmask, (fd_set *)NULL, - (fd_set *)NULL, &timeout); + (fd_set *)NULL, &timeout); if (n < 0) { -#ifdef DEBUG - if (_res.options & RES_DEBUG) - perror("select"); -#endif - continue; + Perror(stderr, "select", errno); + _res_close(); + goto next_ns; } if (n == 0) { /* * timeout */ -#ifdef DEBUG - if (_res.options & RES_DEBUG) - printf(";; timeout\n"); -#endif + Dprint(_res.options & RES_DEBUG, + (stdout, ";; timeout\n")); gotsomewhere = 1; - continue; + _res_close(); + goto next_ns; } - if ((resplen = recv(s, answer, anslen, 0)) <= 0) { -#ifdef DEBUG - if (_res.options & RES_DEBUG) - perror("recvfrom"); -#endif - continue; + errno = 0; + fromlen = sizeof(struct sockaddr_in); + resplen = recvfrom(s, (char*)ans, anssiz, 0, + (struct sockaddr *)&from, &fromlen); + if (resplen <= 0) { + Perror(stderr, "recvfrom", errno); + _res_close(); + goto next_ns; } gotsomewhere = 1; - if (id != anhp->id) { + if (hp->id != anhp->id) { /* - * response from old query, ignore it + * response from old query, ignore it. + * XXX - potential security hazard could + * be detected here. */ -#ifdef DEBUG - if ((_res.options & RES_DEBUG) || - (_res.pfcode & RES_PRF_REPLY)) { - printf(";; old answer:\n"); - __p_query(answer); - } + DprintQ((_res.options & RES_DEBUG) || + (_res.pfcode & RES_PRF_REPLY), + (stdout, ";; old answer:\n"), + ans, resplen); + goto wait; + } +#if CHECK_SRVR_ADDR + if (!(_res.options & RES_INSECURE1) && + !res_isourserver(&from)) { + /* + * response from wrong server? ignore it. + * XXX - potential security hazard could + * be detected here. + */ + DprintQ((_res.options & RES_DEBUG) || + (_res.pfcode & RES_PRF_REPLY), + (stdout, ";; not our server:\n"), + ans, resplen); + goto wait; + } #endif + if (!(_res.options & RES_INSECURE2) && + !res_queriesmatch(buf, buf + buflen, + ans, ans + anssiz)) { + /* + * response contains wrong query? ignore it. + * XXX - potential security hazard could + * be detected here. + */ + DprintQ((_res.options & RES_DEBUG) || + (_res.pfcode & RES_PRF_REPLY), + (stdout, ";; wrong query name:\n"), + ans, resplen); goto wait; } - if (anhp->rcode == SERVFAIL || anhp->rcode == NOTIMP || + if (anhp->rcode == SERVFAIL || + anhp->rcode == NOTIMP || anhp->rcode == REFUSED) { -#ifdef DEBUG - if (_res.options & RES_DEBUG) { - printf("server rejected query:\n"); - __p_query(answer); - } -#endif - badns |= (1<tc) { /* * get rest of answer; * use TCP with same server. */ -#ifdef DEBUG - if (_res.options & RES_DEBUG) - printf(";; truncated answer\n"); -#endif - (void) close(s); - s = -1; + Dprint(_res.options & RES_DEBUG, + (stdout, ";; truncated answer\n")); v_circuit = 1; - goto usevc; + _res_close(); + goto same_ns; } - } -#ifdef DEBUG - if (_res.options & RES_DEBUG) - printf(";; got answer:\n"); - if ((_res.options & RES_DEBUG) || - (_res.pfcode & RES_PRF_REPLY)) - __p_query(answer); -#endif + } /*if vc/dg*/ + Dprint((_res.options & RES_DEBUG) || + ((_res.pfcode & RES_PRF_REPLY) && + (_res.pfcode & RES_PRF_HEAD1)), + (stdout, ";; got answer:\n")); + DprintQ((_res.options & RES_DEBUG) || + (_res.pfcode & RES_PRF_REPLY), + (stdout, ""), + ans, resplen); /* * If using virtual circuits, we assume that the first server - * is preferred * over the rest (i.e. it is on the local + * is preferred over the rest (i.e. it is on the local * machine) and only keep that one open. * 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 && - ((_res.options & RES_USEVC) == 0 || ns != 0)) || - (_res.options & RES_STAYOPEN) == 0) { - (void) close(s); - s = -1; + if ((v_circuit && (!(_res.options & RES_USEVC) || ns != 0)) || + !(_res.options & RES_STAYOPEN)) { + _res_close(); + } + if (Rhook) { + int done = 0, loops = 0; + + do { + res_sendhookact act; + + act = (*Rhook)(nsap, buf, buflen, + ans, anssiz, &resplen); + switch (act) { + case res_goahead: + case res_done: + done = 1; + break; + case res_nextns: + _res_close(); + goto next_ns; + case res_modified: + /* give the hook another try */ + if (++loops < 42) /*doug adams*/ + break; + /*FALLTHROUGH*/ + case res_error: + /*FALLTHROUGH*/ + default: + return (-1); + } + } while (!done); + } return (resplen); - } - } - if (s >= 0) { - (void) close(s); - s = -1; - } - if (v_circuit == 0) - if (gotsomewhere == 0) + next_ns: ; + } /*foreach ns*/ + } /*foreach retry*/ + _res_close(); + if (!v_circuit) + if (!gotsomewhere) errno = ECONNREFUSED; /* no nameservers found */ else errno = ETIMEDOUT; /* no answer obtained */ @@ -459,10 +753,13 @@ wait: * * This routine is not expected to be user visible. */ +void _res_close() { - if (s != -1) { + if (s >= 0) { (void) close(s); s = -1; + connected = 0; + vc = 0; } } -- cgit v1.1