entered into RCS
authorroland <roland>
Wed, 19 May 1993 19:45:44 +0000 (19:45 +0000)
committerroland <roland>
Wed, 19 May 1993 19:45:44 +0000 (19:45 +0000)
resolv/res_comp.c [new file with mode: 0644]
resolv/res_debug.c [new file with mode: 0644]
resolv/res_init.c [new file with mode: 0644]
resolv/res_mkquery.c [new file with mode: 0644]
resolv/res_query.c [new file with mode: 0644]
resolv/res_send.c [new file with mode: 0644]

diff --git a/resolv/res_comp.c b/resolv/res_comp.c
new file mode 100644 (file)
index 0000000..f8890f3
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * ++Copyright++ 1985
+ * -
+ * Copyright (c) 1985 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 sccsid[] = "@(#)res_comp.c 6.22 (Berkeley) 3/19/91";
+static char rcsid[] = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+#include <arpa/nameser.h>
+#include <netinet/in.h>
+#include <resolv.h>
+#include <stdio.h>
+#include "../conf/portability.h"
+
+static int dn_find();
+
+/*
+ * Expand compressed domain name 'comp_dn' to full domain name.
+ * 'msg' is a pointer to the begining of the message,
+ * 'eomorig' points to the first location after the message,
+ * '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.
+ */
+dn_expand(msg, eomorig, comp_dn, exp_dn, length)
+       const u_char *msg, *eomorig, *comp_dn;
+       u_char *exp_dn;
+       int length;
+{
+       register u_char *cp, *dn;
+       register int n, c;
+       u_char *eom;
+       int len = -1, checked = 0;
+
+       dn = exp_dn;
+       cp = (u_char *)comp_dn;
+       eom = exp_dn + length;
+       /*
+        * fetch next label in domain name
+        */
+       while (n = *cp++) {
+               /*
+                * Check for indirection
+                */
+               switch (n & INDIR_MASK) {
+               case 0:
+                       if (dn != exp_dn) {
+                               if (dn >= eom)
+                                       return (-1);
+                               *dn++ = '.';
+                       }
+                       if (dn+n >= eom)
+                               return (-1);
+                       checked += n + 1;
+                       while (--n >= 0) {
+                               if ((c = *cp++) == '.') {
+                                       if (dn + n + 2 >= eom)
+                                               return (-1);
+                                       *dn++ = '\\';
+                               }
+                               *dn++ = c;
+                               if (cp >= eomorig)      /* out of range */
+                                       return(-1);
+                       }
+                       break;
+
+               case INDIR_MASK:
+                       if (len < 0)
+                               len = cp - comp_dn + 1;
+                       cp = (u_char *)msg + (((n & 0x3f) << 8) | (*cp & 0xff));
+                       if (cp < msg || cp >= eomorig)  /* out of range */
+                               return(-1);
+                       checked += 2;
+                       /*
+                        * Check for loops in the compressed name;
+                        * if we've looked at the whole message,
+                        * there must be a loop.
+                        */
+                       if (checked >= eomorig - msg)
+                               return (-1);
+                       break;
+
+               default:
+                       return (-1);                    /* flag error */
+               }
+       }
+       *dn = '\0';
+       if (len < 0)
+               len = cp - comp_dn;
+       return (len);
+}
+
+/*
+ * Compress domain name 'exp_dn' into 'comp_dn'.
+ * Return the size of the compressed name or -1.
+ * 'length' is the size of the array pointed to by 'comp_dn'.
+ * 'dnptrs' is a list of pointers to previous compressed names. dnptrs[0]
+ * is a pointer to the beginning of the message. The list ends with NULL.
+ * 'lastdnptr' is a pointer to the end of the arrary pointed to
+ * by 'dnptrs'. Side effect is to update the list of pointers for
+ * labels inserted into the message as we compress the name.
+ * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
+ * is NULL, we don't update the list.
+ */
+dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr)
+       const u_char *exp_dn;
+       u_char *comp_dn, **dnptrs, **lastdnptr;
+       int length;
+{
+       register u_char *cp, *dn;
+       register int c, l;
+       u_char **cpp, **lpp, *sp, *eob;
+       u_char *msg;
+
+       dn = (u_char *)exp_dn;
+       cp = comp_dn;
+       eob = cp + length;
+       if (dnptrs != NULL) {
+               if ((msg = *dnptrs++) != NULL) {
+                       for (cpp = dnptrs; *cpp != NULL; cpp++)
+                               ;
+                       lpp = cpp;      /* end of list to search */
+               }
+       } else
+               msg = NULL;
+       for (c = *dn++; c != '\0'; ) {
+               /* look to see if we can use pointers */
+               if (msg != NULL) {
+                       if ((l = dn_find(dn-1, msg, dnptrs, lpp)) >= 0) {
+                               if (cp+1 >= eob)
+                                       return (-1);
+                               *cp++ = (l >> 8) | INDIR_MASK;
+                               *cp++ = l % 256;
+                               return (cp - comp_dn);
+                       }
+                       /* not found, save it */
+                       if (lastdnptr != NULL && cpp < lastdnptr-1) {
+                               *cpp++ = cp;
+                               *cpp = NULL;
+                       }
+               }
+               sp = cp++;      /* save ptr to length byte */
+               do {
+                       if (c == '.') {
+                               c = *dn++;
+                               break;
+                       }
+                       if (c == '\\') {
+                               if ((c = *dn++) == '\0')
+                                       break;
+                       }
+                       if (cp >= eob) {
+                               if (msg != NULL)
+                                       *lpp = NULL;
+                               return (-1);
+                       }
+                       *cp++ = c;
+               } while ((c = *dn++) != '\0');
+               /* catch trailing '.'s but not '..' */
+               if ((l = cp - sp - 1) == 0 && c == '\0') {
+                       cp--;
+                       break;
+               }
+               if (l <= 0 || l > MAXLABEL) {
+                       if (msg != NULL)
+                               *lpp = NULL;
+                       return (-1);
+               }
+               *sp = l;
+       }
+       if (cp >= eob) {
+               if (msg != NULL)
+                       *lpp = NULL;
+               return (-1);
+       }
+       *cp++ = '\0';
+       return (cp - comp_dn);
+}
+
+/*
+ * Skip over a compressed domain name. Return the size or -1.
+ */
+__dn_skipname(comp_dn, eom)
+       const u_char *comp_dn, *eom;
+{
+       register u_char *cp;
+       register int n;
+
+       cp = (u_char *)comp_dn;
+       while (cp < eom && (n = *cp++)) {
+               /*
+                * check for indirection
+                */
+               switch (n & INDIR_MASK) {
+               case 0:         /* normal case, n == len */
+                       cp += n;
+                       continue;
+               default:        /* illegal type */
+                       return (-1);
+               case INDIR_MASK:        /* indirection */
+                       cp++;
+               }
+               break;
+       }
+       return (cp - comp_dn);
+}
+
+/*
+ * Search for expanded name from a list of previously compressed names.
+ * Return the offset from msg if found or -1.
+ * dnptrs is the pointer to the first name on the list,
+ * not the pointer to the start of the message.
+ */
+static int
+dn_find(exp_dn, msg, dnptrs, lastdnptr)
+       u_char *exp_dn, *msg;
+       u_char **dnptrs, **lastdnptr;
+{
+       register u_char *dn, *cp, **cpp;
+       register int n;
+       u_char *sp;
+
+       for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
+               dn = exp_dn;
+               sp = cp = *cpp;
+               while (n = *cp++) {
+                       /*
+                        * check for indirection
+                        */
+                       switch (n & INDIR_MASK) {
+                       case 0:         /* normal case, n == len */
+                               while (--n >= 0) {
+                                       if (*dn == '.')
+                                               goto next;
+                                       if (*dn == '\\')
+                                               dn++;
+                                       if (*dn++ != *cp++)
+                                               goto next;
+                               }
+                               if ((n = *dn++) == '\0' && *cp == '\0')
+                                       return (sp - msg);
+                               if (n == '.')
+                                       continue;
+                               goto next;
+
+                       default:        /* illegal type */
+                               return (-1);
+
+                       case INDIR_MASK:        /* indirection */
+                               cp = msg + (((n & 0x3f) << 8) | *cp);
+                       }
+               }
+               if (*dn == '\0')
+                       return (sp - msg);
+       next:   ;
+       }
+       return (-1);
+}
+
+/*
+ * 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.
+ */
+
+u_short
+_getshort(msgp)
+       register u_char *msgp;
+{
+       register u_short u;
+
+       GETSHORT(u, msgp);
+       return u;
+}
+
+u_int32_t
+_getlong(msgp)
+       register u_char *msgp;
+{
+       register u_int32_t u;
+
+       GETLONG(u, msgp);
+       return u;
+}
+
+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);
+}
+
+void
+__putlong(l, msgp)
+       register u_int32_t l;
+       register u_char *msgp;
+{
+       PUTLONG(l, msgp);
+}
diff --git a/resolv/res_debug.c b/resolv/res_debug.c
new file mode 100644 (file)
index 0000000..15e7169
--- /dev/null
@@ -0,0 +1,747 @@
+/*
+ * ++Copyright++ 1985, 1990
+ * -
+ * Copyright (c) 1985, 1990 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 sccsid[] = "@(#)res_debug.c        5.36 (Berkeley) 3/6/91";
+static char rcsid[] = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <stdio.h>
+#include "../conf/portability.h"
+
+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 *
+dewks(wks)
+       int wks;
+{
+       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);
+       }
+}
+
+static char *
+deproto(protonum)
+       int protonum;
+{
+       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);
+       }
+}
+
+static char *
+do_rrset(msg, cp, cnt, pflag, file, hs)
+       int cnt, pflag;
+       char *cp,*msg, *hs;
+       FILE *file;
+{
+       int n;
+       char *t1, *t2, *list[100],**tt;
+       int sflag;
+       /*
+        * Print  answer records
+        */
+       sflag = (_res.pfcode & pflag);
+       if (n = ntohs(cnt)) {
+               *list=NULL;
+               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)
+                               return (NULL);
+               }
+               if ((!_res.pfcode) || ((sflag) && (_res.pfcode & RES_PRF_HEAD1)))
+                       putc('\n', file);
+       }
+       return(cp);
+}
+
+__p_query(msg)
+       char *msg;
+{
+       __fp_query(msg, stdout);
+}
+
+/*
+ * Print the current options.
+ * This is intended to be primarily a debugging routine.
+ */
+void
+__fp_resstat(statp, file)
+       struct __res_state *statp;
+       FILE *file;
+{
+       int bit;
+
+       fprintf(file, ";; res options:");
+       if (!statp)
+               statp = &_res;
+       for (bit = 0;  bit < 32;  bit++) {      /* XXX 32 - bad assumption! */
+               if (statp->options & (1<<bit))
+                       fprintf(file, " %s", p_option(1<<bit));
+       }
+       putc('\n', file);
+}
+
+/*
+ * Print the contents of a query.
+ * This is intended to be primarily a debugging routine.
+ */
+void
+__fp_query(msg,file)
+       char *msg;
+       FILE *file;
+{
+       register char *cp;
+       register HEADER *hp;
+       register int n;
+
+       /*
+        * Print header fields.
+        */
+       hp = (HEADER *)msg;
+       cp = msg + sizeof(HEADER);
+       if ((!_res.pfcode) || (_res.pfcode & RES_PRF_HEADX) || hp->rcode) {
+               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_HEAD2)) {
+               fprintf(file,"; flags:");
+               if (hp->qr)
+                       fprintf(file," qr");
+               if (hp->aa)
+                       fprintf(file," aa");
+               if (hp->tc)
+                       fprintf(file," tc");
+               if (hp->rd)
+                       fprintf(file," rd");
+               if (hp->ra)
+                       fprintf(file," ra");
+               if (hp->pr)
+                       fprintf(file," pr");
+       }
+       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));
+       }
+#if 0
+       if (_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");
+               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, ", type = %s",
+                                       __p_type(_getshort(cp)));
+                       cp += sizeof(u_short);
+                       if ((!_res.pfcode) || (_res.pfcode & RES_PRF_QUES))
+                               fprintf(file, ", class = %s\n\n",
+                                       __p_class(_getshort(cp)));
+                       cp += sizeof(u_short);
+               }
+       }
+       /*
+        * Print authoritative answer records
+        */
+       cp = do_rrset(msg, cp, hp->ancount, RES_PRF_ANS, file,
+                     ";; ANSWERS:\n");
+       if (cp == NULL)
+               return;
+
+       /*
+        * print name server records
+        */
+       cp = do_rrset(msg, cp, hp->nscount, RES_PRF_AUTH, file,
+                     ";; AUTHORITY RECORDS:\n");
+       if (!cp)
+               return;
+
+       /*
+        * print additional records
+        */
+       cp = do_rrset(msg, cp, hp->arcount, RES_PRF_ADD, file,
+                     ";; ADDITIONAL RECORDS:\n");
+       if (!cp)
+               return;
+}
+
+char *
+p_cdname(cp, msg, file)
+       char *cp, *msg;
+       FILE *file;
+{
+       char name[MAXDNAME];
+       int n;
+
+       if ((n = dn_expand((u_char *)msg, (u_char *)msg + 512, (u_char *)cp,
+           (u_char *)name, sizeof(name))) < 0)
+               return (NULL);
+       if (name[0] == '\0') {
+               putc('.', file);
+       } else {
+               fputs(name, file);
+       }
+       return (cp + n);
+}
+
+char *
+p_fqname(cp, msg, file)
+       char *cp, *msg;
+       FILE *file;
+{
+       char name[MAXDNAME];
+       int n, len;
+
+       if ((n = dn_expand((u_char *)msg, (u_char *)msg + 512, (u_char *)cp,
+           (u_char *)name, sizeof(name))) < 0)
+               return (NULL);
+       if (name[0] == '\0') {
+               putc('.', file);
+       } else {
+               fputs(name, file);
+               if (name[strlen(name) - 1] != '.')
+                       putc('.', file);
+       }
+       return (cp + n);
+}
+
+
+
+/*
+ * Print resource record fields in human readable form.
+ */
+char *
+p_rr(cp, msg, file)
+       char *cp, *msg;
+       FILE *file;
+{
+       int type, class, dlen, n, c;
+       struct in_addr inaddr;
+       char *cp1, *cp2;
+       u_int32_t tmpttl, t;
+       int lcnt;
+
+       if ((cp = p_fqname(cp, msg, file)) == NULL)
+               return (NULL);                  /* compression error */
+       type = _getshort(cp);
+       cp += sizeof(u_short);
+       class = _getshort(cp);
+       cp += sizeof(u_short);
+       tmpttl = _getlong(cp);
+       cp += sizeof(u_int32_t);
+       dlen = _getshort(cp);
+       cp += sizeof(u_short);
+       cp1 = cp;
+       if ((!_res.pfcode) || (_res.pfcode & RES_PRF_TTLID))
+               fprintf(file, "\t%lu", tmpttl);
+       if ((!_res.pfcode) || (_res.pfcode & RES_PRF_CLASS))
+               fprintf(file, "\t%s", __p_class(class));
+       fprintf(file, "\t%s", __p_type(type));
+       /*
+        * Print type specific data, if appropriate
+        */
+       switch (type) {
+       case T_A:
+               switch (class) {
+               case C_IN:
+               case C_HS:
+                       bcopy(cp, (char *)&inaddr, sizeof(inaddr));
+                       if (dlen == 4) {
+                               fprintf(file,"\t%s", inet_ntoa(inaddr));
+                               cp += dlen;
+                       } else if (dlen == 7) {
+                               char *address;
+                               u_char protocol;
+                               u_short port;
+
+                               address = inet_ntoa(inaddr);
+                               cp += sizeof(inaddr);
+                               protocol = *(u_char*)cp;
+                               cp += sizeof(u_char);
+                               port = _getshort(cp);
+                               cp += sizeof(u_short);
+                               fprintf(file, "\t%s\t; proto %d, port %d",
+                                       address, protocol, port);
+                       }
+                       break;
+               default:
+                       cp += dlen;
+               }
+               break;
+       case T_CNAME:
+       case T_MB:
+       case T_MG:
+       case T_MR:
+       case T_NS:
+       case T_PTR:
+               putc('\t', file);
+               cp = p_fqname(cp, msg, file);
+               break;
+
+       case T_HINFO:
+               if (n = *cp++) {
+                       fprintf(file,"\t%.*s", n, cp);
+                       cp += n;
+               }
+               if (n = *cp++) {
+                       fprintf(file,"\t%.*s", n, cp);
+                       cp += n;
+               }
+               break;
+
+       case T_SOA:
+               putc('\t', file);
+               cp = p_fqname(cp, msg, file);   /* origin */
+               putc(' ', file);
+               cp = p_fqname(cp, msg, file);   /* mail addr */
+               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));
+               break;
+
+       case T_MX:
+               fprintf(file,"\t%d ", _getshort(cp));
+               cp += sizeof(u_short);
+               cp = p_fqname(cp, msg, file);
+               break;
+
+       case T_TXT:
+               (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') {
+                                           (void) putc('\\', file);
+                                           (void) putc(*cp++, file);
+                                       } else
+                                           (void) putc(*cp++, file);
+                       }
+               }
+               putc('"', file);
+               break;
+
+       case T_MINFO:
+       case T_RP:
+               putc('\t', file);
+               cp = p_fqname(cp, msg, file);
+               putc(' ', file);
+               cp = p_fqname(cp, msg, file);
+               break;
+
+       case T_UINFO:
+               putc('\t', file);
+               fputs(cp, file);
+               cp += dlen;
+               break;
+
+       case T_UID:
+       case T_GID:
+               if (dlen == 4) {
+                       fprintf(file,"\t%u", _getlong(cp));
+                       cp += sizeof(int32_t);
+               }
+               break;
+
+       case T_WKS:
+               if (dlen < sizeof(u_int32_t) + 1)
+                       break;
+               bcopy(cp, (char *)&inaddr, sizeof(inaddr));
+               cp += sizeof(u_int32_t);
+               fprintf(file, "\t%s %s ( ",
+                       inet_ntoa(inaddr),
+                       deproto((int) *cp));
+               cp += sizeof(u_char);
+               n = 0;
+               lcnt = 0;
+               while (cp < cp1 + dlen) {
+                       c = *cp++;
+                       do {
+                               if (c & 0200) {
+                                       if (lcnt == 0) {
+                                               fputs("\n\t\t\t", file);
+                                               lcnt = 5;
+                                       }
+                                       fputs(dewks(n), file);
+                                       putc(' ', file);
+                                       lcnt--;
+                               }
+                               c <<= 1;
+                       } while (++n & 07);
+               }
+               putc(')', file);
+               break;
+
+#ifdef ALLOW_T_UNSPEC
+       case T_UNSPEC:
+               {
+                       int NumBytes = 8;
+                       char *DataPtr;
+                       int i;
+
+                       if (dlen < NumBytes) NumBytes = dlen;
+                       fprintf(file, "\tFirst %d bytes of hex data:",
+                               NumBytes);
+                       for (i = 0, DataPtr = cp; i < NumBytes; i++, DataPtr++)
+                               fprintf(file, " %x", *DataPtr);
+                       cp += dlen;
+               }
+               break;
+#endif /* ALLOW_T_UNSPEC */
+
+       default:
+               fprintf(file,"\t?%d?", type);
+               cp += dlen;
+       }
+#if 0
+       fprintf(file, "\t; dlen=%d, ttl %s\n", dlen, __p_time(tmpttl));
+#else
+       putc('\n', file);
+#endif
+       if (cp - cp1 != dlen) {
+               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 *
+__p_type(type)
+       int type;
+{
+       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");
+#ifdef ALLOW_T_UNSPEC
+       case T_UNSPEC:
+               return("UNSPEC");
+#endif /* ALLOW_T_UNSPEC */
+       default:
+               (void)sprintf(nbuf, "%d", type);
+               return(nbuf);
+       }
+}
+
+/*
+ * Return a mnemonic for class
+ */
+char *
+__p_class(class)
+       int class;
+{
+
+       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);
+       }
+}
+
+/*
+ * Return a mnemonic for an option
+ */
+static char *
+p_option(option)
+       u_int32_t option;
+{
+       switch (option) {
+       case RES_INIT:          return "init";
+       case RES_DEBUG:         return "debug";
+       case RES_AAONLY:        return "aaonly";
+       case RES_USEVC:         return "usevc";
+       case RES_PRIMARY:       return "primry";
+       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;
+       }
+}
+
+/*
+ * Return a mnemonic for a time to live
+ */
+char *
+__p_time(value)
+       u_int32_t value;
+{
+       int secs, mins, hours, days;
+       register char *p;
+
+       if (value == 0) {
+               strcpy(nbuf, "0 secs");
+               return(nbuf);
+       }
+
+       secs = value % 60;
+       value /= 60;
+       mins = value % 60;
+       value /= 60;
+       hours = value % 24;
+       value /= 24;
+       days = value;
+       value = 0;
+
+#define        PLURALIZE(x)    x, (x == 1) ? "" : "s"
+       p = nbuf;
+       if (days) {
+               (void)sprintf(p, "%d day%s", PLURALIZE(days));
+               while (*++p);
+       }
+       if (hours) {
+               if (days)
+                       *p++ = ' ';
+               (void)sprintf(p, "%d hour%s", PLURALIZE(hours));
+               while (*++p);
+       }
+       if (mins) {
+               if (days || hours)
+                       *p++ = ' ';
+               (void)sprintf(p, "%d min%s", PLURALIZE(mins));
+               while (*++p);
+       }
+       if (secs || ! (days || hours || mins)) {
+               if (days || hours || mins)
+                       *p++ = ' ';
+               (void)sprintf(p, "%d sec%s", PLURALIZE(secs));
+       }
+       return(nbuf);
+}
diff --git a/resolv/res_init.c b/resolv/res_init.c
new file mode 100644 (file)
index 0000000..f3bcebc
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * ++Copyright++ 1985, 1989
+ * -
+ * Copyright (c) 1985, 1989 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 sccsid[] = "@(#)res_init.c 6.15 (Berkeley) 2/24/91";
+static char rcsid[] = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <stdio.h>
+#include "../conf/portability.h"
+
+
+/*
+ * 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 */
+};
+
+/*
+ * Set up default settings.  If the configuration file exist, the values
+ * there will have precedence.  Otherwise, the server address is set to
+ * 127.0.0.1 and the default domain name comes from the gethostname().
+ *
+ * Previous resolver versions used INADDR_ANY rather than IN_LOOPBACKNET.
+ * This has bad side-effects in the kernel since 0.0.0.0 means "any interface"
+ * and the first one found may or may not be the loopback interface.
+ * If it is a point-to-point interface, then the SLIP or PPP or DDCMP state
+ * must be "up" in order for the packets to loop correctly.  This is deemed
+ * "bad".  
+ *
+ * The configuration file should only be used if you want to redefine your
+ * domain or run without a server on your machine.
+ *
+ * Return 0 if completes successfully, -1 on error
+ */
+res_init()
+{
+       register FILE *fp;
+       register char *cp, **pp;
+       register int n;
+       char buf[BUFSIZ];
+       int nserv = 0;    /* number of nameserver records read from file */
+       int haveenv = 0;
+       int havesearch = 0;
+
+       _res.nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1);
+       _res.nsaddr.sin_family = AF_INET;
+       _res.nsaddr.sin_port = htons(NAMESERVER_PORT);
+       _res.nscount = 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';
+               haveenv++;
+       }
+
+       if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
+           /* read the config file */
+           while (fgets(buf, sizeof(buf), fp) != NULL) {
+               /* skip comments */
+               if ((*buf == ';') || (*buf == '#'))
+                       continue;
+               /* read default domain name */
+               if (!strncmp(buf, "domain", sizeof("domain") - 1)) {
+                   if (haveenv)        /* skip if have from environ */
+                           continue;
+                   cp = buf + sizeof("domain") - 1;
+                   while (*cp == ' ' || *cp == '\t')
+                           cp++;
+                   if ((*cp == '\0') || (*cp == '\n'))
+                           continue;
+                   (void)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 (haveenv)        /* skip if have from environ */
+                           continue;
+                   cp = buf + sizeof("search") - 1;
+                   while (*cp == ' ' || *cp == '\t')
+                           cp++;
+                   if ((*cp == '\0') || (*cp == '\n'))
+                           continue;
+                   (void)strncpy(_res.defdname, cp,
+                                 sizeof(_res.defdname) - 1);
+                   if ((cp = strchr(_res.defdname, '\n')) != NULL)
+                           *cp = '\0';
+                   /*
+                    * Set search list to be blank-separated strings
+                    * on rest of line.
+                    */
+                   cp = _res.defdname;
+                   pp = _res.dnsrch;
+                   *pp++ = cp;
+                   for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) {
+                           if (*cp == ' ' || *cp == '\t') {
+                                   *cp = 0;
+                                   n = 1;
+                           } else if (n) {
+                                   *pp++ = cp;
+                                   n = 0;
+                           }
+                   }
+                   /* null terminate last domain if there are excess */
+                   while (*cp != '\0' && *cp != ' ' && *cp != '\t')
+                           cp++;
+                   *cp = '\0';
+                   *pp++ = 0;
+                   havesearch = 1;
+                   continue;
+               }
+               /* read nameservers to query */
+               if (!strncmp(buf, "nameserver", sizeof("nameserver") - 1) &&
+                  nserv < MAXNS) {
+                  struct in_addr a;
+
+                   cp = buf + sizeof("nameserver") - 1;
+                   while (*cp == ' ' || *cp == '\t')
+                       cp++;
+                   if ((*cp != '\0') && (*cp != '\n') && inet_aton(cp, &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++;
+                   }
+                   continue;
+               }
+           }
+           if (nserv > 1) 
+               _res.nscount = nserv;
+           (void) fclose(fp);
+       }
+       if (_res.defdname[0] == 0) {
+               if (gethostname(buf, sizeof(_res.defdname)) == 0 &&
+                  (cp = strchr(buf, '.')))
+                       (void)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++;
+               cp = _res.defdname;
+               for (;
+                    n >= LOCALDOMAINPARTS && pp < _res.dnsrch + MAXDFLSRCH;
+                    n--) {
+                       cp = strchr(cp, '.');
+                       *pp++ = ++cp;
+               }
+               *pp++ = 0;
+       }
+       _res.options |= RES_INIT;
+       return (0);
+}
diff --git a/resolv/res_mkquery.c b/resolv/res_mkquery.c
new file mode 100644 (file)
index 0000000..8d0e768
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * ++Copyright++ 1985
+ * -
+ * Copyright (c) 1985 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 sccsid[] = "@(#)res_mkquery.c      6.16 (Berkeley) 3/6/91";
+static char rcsid[] = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <stdio.h>
+#include "../conf/portability.h"
+
+/*
+ * Form all types of queries.
+ * Returns the size of the result or -1.
+ */
+res_mkquery(op, dname, class, type, data, datalen, newrr_in, buf, buflen)
+       int op;                 /* opcode of query */
+       const char *dname;              /* domain name */
+       int class, type;        /* class and type of query */
+       const 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 */
+       int buflen;             /* size of buffer */
+{
+       register HEADER *hp;
+       register char *cp;
+       register int n;
+       struct rrec *newrr = (struct rrec *) newrr_in;
+       char *dnptrs[10], **dpp, **lastdnptr;
+
+#ifdef DEBUG
+       if (_res.options & RES_DEBUG)
+               printf(";; res_mkquery(%d, %s, %d, %d)\n",
+                      op, dname, class, type);
+#endif
+       /*
+        * Initialize header fields.
+        */
+       if ((buf == NULL) || (buflen < sizeof(HEADER)))
+               return(-1);
+       bzero(buf, sizeof(HEADER));
+       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);
+       dpp = dnptrs;
+       *dpp++ = buf;
+       *dpp++ = NULL;
+       lastdnptr = dnptrs + sizeof(dnptrs)/sizeof(dnptrs[0]);
+       /*
+        * perform opcode specific processing
+        */
+       switch (op) {
+       case QUERY:
+               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);
+               cp += n;
+               buflen -= n;
+               __putshort(type, (u_char *)cp);
+               cp += sizeof(u_short);
+               __putshort(class, (u_char *)cp);
+               cp += sizeof(u_short);
+               hp->qdcount = htons(1);
+               if (op == QUERY || data == NULL)
+                       break;
+               /*
+                * 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)
+                       return (-1);
+               cp += n;
+               buflen -= n;
+               __putshort(T_NULL, (u_char *)cp);
+               cp += sizeof(u_short);
+               __putshort(class, (u_char *)cp);
+               cp += sizeof(u_short);
+               __putlong(0, (u_char *)cp);
+               cp += sizeof(u_int32_t);
+               __putshort(0, (u_char *)cp);
+               cp += sizeof(u_short);
+               hp->arcount = htons(1);
+               break;
+
+       case IQUERY:
+               /*
+                * Initialize answer section
+                */
+               if (buflen < 1 + RRFIXEDSZ + datalen)
+                       return (-1);
+               *cp++ = '\0';   /* no domain name */
+               __putshort(type, (u_char *)cp);
+               cp += sizeof(u_short);
+               __putshort(class, (u_char *)cp);
+               cp += sizeof(u_short);
+               __putlong(0, (u_char *)cp);
+               cp += sizeof(u_int32_t);
+               __putshort(datalen, (u_char *)cp);
+               cp += sizeof(u_short);
+               if (datalen) {
+                       bcopy(data, cp, datalen);
+                       cp += datalen;
+               }
+               hp->ancount = htons(1);
+               break;
+
+#ifdef ALLOW_UPDATES
+       /*
+        * For UPDATEM/UPDATEMA, do UPDATED/UPDATEDA followed by UPDATEA
+        * (Record to be modified is followed by its replacement in msg.)
+        */
+       case UPDATEM:
+       case UPDATEMA:
+
+       case UPDATED:
+               /*
+                * The res code for UPDATED and UPDATEDA is the same; user
+                * calls them differently: specifies data for UPDATED; server
+                * ignores data if specified for UPDATEDA.
+                */
+       case UPDATEDA:
+               buflen -= RRFIXEDSZ + datalen;
+               if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
+                       return (-1);
+               cp += n;
+               __putshort(type, cp);
+                cp += sizeof(u_short);
+                __putshort(class, cp);
+                cp += sizeof(u_short);
+               __putlong(0, cp);
+               cp += sizeof(u_int32_t);
+               __putshort(datalen, cp);
+                cp += sizeof(u_short);
+               if (datalen) {
+                       bcopy(data, cp, datalen);
+                       cp += datalen;
+               }
+               if ( (op == UPDATED) || (op == UPDATEDA) ) {
+                       hp->ancount = htons(0);
+                       break;
+               }
+               /* Else UPDATEM/UPDATEMA, so drop into code for UPDATEA */
+
+       case UPDATEA:   /* Add new resource record */
+               buflen -= RRFIXEDSZ + datalen;
+               if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
+                       return (-1);
+               cp += n;
+               __putshort(newrr->r_type, cp);
+                cp += sizeof(u_short);
+                __putshort(newrr->r_class, cp);
+                cp += sizeof(u_short);
+               __putlong(0, cp);
+               cp += sizeof(u_int32_t);
+               __putshort(newrr->r_size, cp);
+                cp += sizeof(u_short);
+               if (newrr->r_size) {
+                       bcopy(newrr->r_data, cp, newrr->r_size);
+                       cp += newrr->r_size;
+               }
+               hp->ancount = htons(0);
+               break;
+
+#endif /* ALLOW_UPDATES */
+       }
+       return (cp - buf);
+}
diff --git a/resolv/res_query.c b/resolv/res_query.c
new file mode 100644 (file)
index 0000000..782e183
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * ++Copyright++ 1988
+ * -
+ * Copyright (c) 1988 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 sccsid[] = "@(#)res_query.c        5.11 (Berkeley) 3/6/91";
+static char rcsid[] = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include "../conf/portability.h"
+
+#if PACKETSZ > 1024
+#define MAXPACKET      PACKETSZ
+#else
+#define MAXPACKET      1024
+#endif
+
+int h_errno;
+
+/*
+ * Formulate a normal query, send, and await answer.
+ * Returned answer is placed in supplied buffer "answer".
+ * Perform preliminary check of answer, returning success only
+ * 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.
+ */
+res_query(name, class, type, answer, anslen)
+       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;
+       int n;
+
+       if ((_res.options & RES_INIT) == 0 && res_init() == -1)
+               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));
+
+       if (n <= 0) {
+#ifdef DEBUG
+               if (_res.options & RES_DEBUG)
+                       printf(";; res_query: mkquery failed\n");
+#endif
+               h_errno = NO_RECOVERY;
+               return (n);
+       }
+       n = res_send(buf, n, (char *)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);
+       }
+
+       hp = (HEADER *) answer;
+       if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
+#ifdef DEBUG
+               if (_res.options & RES_DEBUG)
+                       printf(";; rcode = %d, ancount=%d\n", hp->rcode,
+                           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;
+               }
+               return (-1);
+       }
+       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).
+ */
+int
+res_search(name, class, type, answer, anslen)
+       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();
+
+       if ((_res.options & RES_INIT) == 0 && res_init() == -1)
+               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)))
+               return (res_query(cp, class, type, answer, anslen));
+
+       /*
+        * 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 (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 (n && (ret = res_querydomain(name, (char *)NULL, class, type,
+           answer, anslen)) > 0)
+               return (ret);
+       if (got_nodata)
+               h_errno = NO_DATA;
+       return (-1);
+}
+
+/*
+ * Perform a call on res_query on the concatenation of name and domain,
+ * removing a trailing dot from name if domain is NULL.
+ */
+res_querydomain(name, domain, class, type, answer, anslen)
+       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;
+       int n;
+
+#ifdef DEBUG
+       if (_res.options & RES_DEBUG)
+               printf(";; res_querydomain(%s, %s, %d, %d)\n",
+                   name, domain, class, type);
+#endif
+       if (domain == NULL) {
+               /*
+                * Check for trailing '.';
+                * copy without '.' if present.
+                */
+               n = strlen(name) - 1;
+               if (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);
+
+       return (res_query(longname, class, type, answer, anslen));
+}
+
+char *
+__hostalias(name)
+       register const char *name;
+{
+       register char *C1, *C2;
+       FILE *fp;
+       char *file, *getenv(), *strcpy(), *strncpy();
+       char buf[BUFSIZ];
+       static char abuf[MAXDNAME];
+
+       file = getenv("HOSTALIASES");
+       if (file == NULL || (fp = fopen(file, "r")) == NULL)
+               return (NULL);
+       buf[sizeof(buf) - 1] = '\0';
+       while (fgets(buf, sizeof(buf), fp)) {
+               for (C1 = buf; *C1 && !isspace(*C1); ++C1);
+               if (!*C1)
+                       break;
+               *C1 = '\0';
+               if (!strcasecmp(buf, name)) {
+                       while (isspace(*++C1));
+                       if (!*C1)
+                               break;
+                       for (C2 = C1 + 1; *C2 && !isspace(*C2); ++C2);
+                       abuf[sizeof(abuf) - 1] = *C2 = '\0';
+                       (void)strncpy(abuf, C1, sizeof(abuf) - 1);
+                       fclose(fp);
+                       return (abuf);
+               }
+       }
+       fclose(fp);
+       return (NULL);
+}
diff --git a/resolv/res_send.c b/resolv/res_send.c
new file mode 100644 (file)
index 0000000..65763fd
--- /dev/null
@@ -0,0 +1,478 @@
+/*
+ * ++Copyright++ 1985, 1989
+ * -
+ * Copyright (c) 1985, 1989 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 sccsid[] = "@(#)res_send.c 6.27 (Berkeley) 2/24/91";
+static char rcsid[] = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Send query to name server and wait for reply.
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <errno.h>
+#include <resolv.h>
+#include "../conf/portability.h"
+
+static int s = -1;     /* socket used for communications */
+static struct sockaddr no_addr;
+
+#ifndef FD_SET
+#define        NFDBITS         32
+#define        FD_SETSIZE      32
+#define        FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
+#define        FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
+#define        FD_ISSET(n, p)  ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
+#define FD_ZERO(p)     bzero((char *)(p), sizeof(*(p)))
+#endif
+
+res_send(buf, buflen, answer, anslen)
+       const char *buf;
+       int buflen;
+       char *answer;
+       int anslen;
+{
+       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);
+       }
+#endif
+       if (!(_res.options & RES_INIT))
+               if (res_init() == -1) {
+                       return(-1);
+               }
+       v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
+       id = hp->id;
+       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<<ns))
+                       continue;
+#ifdef DEBUG
+               if (_res.options & RES_DEBUG)
+                       printf(";; Querying server (# %d) address = %s\n",
+                              ns+1,
+                              inet_ntoa(_res.nsaddr_list[ns].sin_addr));
+#endif
+       usevc:
+               if (v_circuit) {
+                       int truncated = 0;
+
+                       /*
+                        * Use virtual circuit;
+                        * at most one attempt per server.
+                        */
+                       try = _res.retry;
+                       if (s < 0) {
+                               s = socket(AF_INET, SOCK_STREAM, 0);
+                               if (s < 0) {
+                                       terrno = errno;
+#ifdef DEBUG
+                                       if (_res.options & RES_DEBUG)
+                                           perror("socket (vc) failed");
+#endif
+                                       continue;
+                               }
+                               if (connect(s,
+                                   (struct sockaddr *)&(_res.nsaddr_list[ns]),
+                                   sizeof(struct sockaddr)) < 0) {
+                                       terrno = errno;
+#ifdef DEBUG
+                                       if (_res.options & RES_DEBUG)
+                                           perror("connect failed");
+#endif
+                                       (void) close(s);
+                                       s = -1;
+                                       continue;
+                               }
+                       }
+                       /*
+                        * Send length & message
+                        */
+                       len = htons((u_short)buflen);
+                       iov[0].iov_base = (caddr_t)&len;
+                       iov[0].iov_len = sizeof(len);
+                       iov[1].iov_base = (char *)buf;
+                       iov[1].iov_len = buflen;
+                       if (writev(s, iov, 2) != sizeof(len) + buflen) {
+                               terrno = errno;
+#ifdef DEBUG
+                               if (_res.options & RES_DEBUG)
+                                       perror("write failed");
+#endif
+                               (void) close(s);
+                               s = -1;
+                               continue;
+                       }
+                       /*
+                        * Receive length & response
+                        */
+                       cp = answer;
+                       len = sizeof(short);
+                       while (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;
+                               /*
+                                * A long running process might get its TCP
+                                * connection reset if the remote server was
+                                * restarted.  Requery the server instead of
+                                * trying a new one.  When there is only one
+                                * server, this means that a query might work
+                                * instead of failing.  We only allow one reset
+                                * per query to prevent looping.
+                                */
+                               if (terrno == ECONNRESET && !connreset) {
+                                       connreset = 1;
+                                       ns--;
+                               }
+                               continue;
+                       }
+                       cp = answer;
+                       if ((resplen = ntohs(*(u_short *)cp)) > anslen) {
+#ifdef DEBUG
+                               if (_res.options & RES_DEBUG)
+                                       fprintf(stderr,
+                                               ";; response truncated\n");
+#endif
+                               len = anslen;
+                               truncated = 1;
+                       } else
+                               len = resplen;
+                       while (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;
+                       }
+                       if (truncated) {
+                               /*
+                                * Flush rest of answer
+                                * so connection stays in synch.
+                                */
+                               anhp->tc = 1;
+                               len = resplen - anslen;
+                               while (len != 0) {
+                                       n = (len > sizeof(junk) ?
+                                           sizeof(junk) : len);
+                                       if ((n = read(s, junk, n)) > 0)
+                                               len -= n;
+                                       else
+                                               break;
+                               }
+                       }
+               } else {
+                       /*
+                        * Use datagrams.
+                        */
+                       if (s < 0) {
+                               s = socket(AF_INET, SOCK_DGRAM, 0);
+                               if (s < 0) {
+                                       terrno = errno;
+#ifdef DEBUG
+                                       if (_res.options & RES_DEBUG)
+                                           perror("socket (dg) failed");
+#endif
+                                       continue;
+                               }
+                       }
+#if    BSD >= 43
+                       /*
+                        * 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
+                        * ICMP port unreachable message to be returned.
+                        * If our datagram socket is "connected" to the
+                        * server, we get an ECONNREFUSED error on the next
+                        * socket operation, and select returns if the
+                        * error message is received.  We can thus detect
+                        * the absence of a nameserver without timing out.
+                        * If we have sent queries to at least two servers,
+                        * however, we don't want to remain connected,
+                        * as we wish to receive answers from the first
+                        * server to respond.
+                        */
+                       if (_res.nscount == 1 || (try == 0 && ns == 0)) {
+                               /*
+                                * Don't use connect if we might
+                                * still 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;
+                                       }
+                                       connected = 1;
+                               }
+                               if (send(s, buf, buflen, 0) != buflen) {
+#ifdef DEBUG
+                                       if (_res.options & RES_DEBUG)
+                                               perror("send");
+#endif
+                                       continue;
+                               }
+                       } else {
+                               /*
+                                * Disconnect if we want to listen
+                                * for responses from more than one server.
+                                */
+                               if (connected) {
+                                       (void) connect(s, &no_addr,
+                                           sizeof(no_addr));
+                                       connected = 0;
+                               }
+#endif /* BSD */
+                               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    BSD >= 43
+                       }
+#endif
+
+                       /*
+                        * Wait for reply
+                        */
+                       timeout.tv_sec = (_res.retrans << try);
+                       if (try > 0)
+                               timeout.tv_sec /= _res.nscount;
+                       if ((long) timeout.tv_sec <= 0)
+                               timeout.tv_sec = 1;
+                       timeout.tv_usec = 0;
+wait:
+                       FD_ZERO(&dsmask);
+                       FD_SET(s, &dsmask);
+                       n = select(s+1, &dsmask, (fd_set *)NULL,
+                               (fd_set *)NULL, &timeout);
+                       if (n < 0) {
+#ifdef DEBUG
+                               if (_res.options & RES_DEBUG)
+                                       perror("select");
+#endif
+                               continue;
+                       }
+                       if (n == 0) {
+                               /*
+                                * timeout
+                                */
+#ifdef DEBUG
+                               if (_res.options & RES_DEBUG)
+                                       printf(";; timeout\n");
+#endif
+#if BSD >= 43
+                               gotsomewhere = 1;
+#endif
+                               continue;
+                       }
+                       if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
+#ifdef DEBUG
+                               if (_res.options & RES_DEBUG)
+                                       perror("recvfrom");
+#endif
+                               continue;
+                       }
+                       gotsomewhere = 1;
+                       if (id != anhp->id) {
+                               /*
+                                * response from old query, ignore it
+                                */
+#ifdef DEBUG
+                               if ((_res.options & RES_DEBUG) ||
+                                   (_res.pfcode & RES_PRF_REPLY)) {
+                                       printf(";; old answer:\n");
+                                       __p_query(answer);
+                               }
+#endif
+                               goto wait;
+                       }
+                       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 DEBUG
+                               badns |= (1<<ns);
+                               continue;
+                       }
+                       if (!(_res.options & RES_IGNTC) && anhp->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;
+                               v_circuit = 1;
+                               goto usevc;
+                       }
+               }
+#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 using virtual circuits, we assume that the first server
+                * 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;
+               }
+               return (resplen);
+          }
+       }
+       if (s >= 0) {
+               (void) close(s);
+               s = -1;
+       }
+       if (v_circuit == 0)
+               if (gotsomewhere == 0)
+                       errno = ECONNREFUSED;   /* no nameservers found */
+               else
+                       errno = ETIMEDOUT;      /* no answer obtained */
+       else
+               errno = terrno;
+       return (-1);
+}
+
+/*
+ * This routine is for closing the socket if a virtual circuit is used and
+ * the program wants to close it.  This provides support for endhostent()
+ * which expects to close the socket.
+ *
+ * This routine is not expected to be user visible.
+ */
+_res_close()
+{
+       if (s != -1) {
+               (void) close(s);
+               s = -1;
+       }
+}