home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / ip / dns / resolv+2.1.1 / res_query.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-28  |  7.7 KB  |  281 lines

  1. /*
  2.  * Copyright (c) 1988 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that: (1) source distributions retain this entire copyright
  7.  * notice and comment, and (2) distributions including binaries display
  8.  * the following acknowledgement:  ``This product includes software
  9.  * developed by the University of California, Berkeley and its contributors''
  10.  * in the documentation or other materials provided with the distribution
  11.  * and in all advertising materials mentioning features or use of this
  12.  * software. Neither the name of the University nor the names of its
  13.  * contributors may be used to endorse or promote products derived
  14.  * from this software without specific prior written permission.
  15.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  16.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  17.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  18.  */
  19.  
  20. #if defined(LIBC_SCCS) && !defined(lint)
  21. static char sccsid[] = "@(#)res_query.c    5.7 (Berkeley) 6/1/90";
  22. #endif /* LIBC_SCCS and not lint */
  23.  
  24. #include <sys/param.h>
  25. #include <sys/socket.h>
  26. #include <netinet/in.h>
  27. #include <ctype.h>
  28. #include <netdb.h>
  29. #include <stdio.h>
  30. #include <errno.h>
  31. #include <string.h>
  32. #include <arpa/inet.h>
  33. #include <arpa/nameser.h>
  34. #include <resolv.h>
  35.  
  36. #if PACKETSZ > 1024
  37. #define MAXPACKET    PACKETSZ
  38. #else
  39. #define MAXPACKET    1024
  40. #endif
  41.  
  42. extern int errno;
  43. #ifdef SHLIB
  44. extern int h_errno;
  45. #else
  46. int h_errno;
  47. #endif
  48.  
  49. /*
  50.  * Formulate a normal query, send, and await answer.
  51.  * Returned answer is placed in supplied buffer "answer".
  52.  * Perform preliminary check of answer, returning success only
  53.  * if no error is indicated and the answer count is nonzero.
  54.  * Return the size of the response on success, -1 on error.
  55.  * Error number is left in h_errno.
  56.  * Caller must parse answer and determine whether it answers the question.
  57.  */
  58. res_query(name, class, type, answer, anslen)
  59.     char *name;        /* domain name */
  60.     int class, type;    /* class and type of query */
  61.     u_char *answer;        /* buffer to put answer */
  62.     int anslen;        /* size of answer buffer */
  63. {
  64.     char buf[MAXPACKET];
  65.     HEADER *hp;
  66.     int n;
  67.  
  68.     if ((_res.options & RES_INIT) == 0 && res_init() == -1)
  69.         return (-1);
  70. #ifdef DEBUG
  71.     if (_res.options & RES_DEBUG)
  72.         printf("res_query(%s, %d, %d)\n", name, class, type);
  73. #endif
  74.     n = res_mkquery(QUERY, name, class, type, (char *)NULL, 0, NULL,
  75.         buf, sizeof(buf));
  76.  
  77.     if (n <= 0) {
  78. #ifdef DEBUG
  79.         if (_res.options & RES_DEBUG)
  80.             printf("res_query: mkquery failed\n");
  81. #endif
  82.         h_errno = NO_RECOVERY;
  83.         return (n);
  84.     }
  85.     n = res_send(buf, n, answer, anslen);
  86.     if (n < 0) {
  87. #ifdef DEBUG
  88.         if (_res.options & RES_DEBUG)
  89.             printf("res_query: send error\n");
  90. #endif
  91.         h_errno = TRY_AGAIN;
  92.         return(n);
  93.     }
  94.  
  95.     hp = (HEADER *) answer;
  96.     if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
  97. #ifdef DEBUG
  98.         if (_res.options & RES_DEBUG)
  99.             printf("rcode = %d, ancount=%d\n", hp->rcode,
  100.                 ntohs(hp->ancount));
  101. #endif
  102.         switch (hp->rcode) {
  103.             case NXDOMAIN:
  104.                 h_errno = HOST_NOT_FOUND;
  105.                 break;
  106.             case SERVFAIL:
  107.                 h_errno = TRY_AGAIN;
  108.                 break;
  109.             case NOERROR:
  110.                 h_errno = NO_DATA;
  111.                 break;
  112.             case FORMERR:
  113.             case NOTIMP:
  114.             case REFUSED:
  115.             default:
  116.                 h_errno = NO_RECOVERY;
  117.                 break;
  118.         }
  119.         return (-1);
  120.     }
  121.     return(n);
  122. }
  123.  
  124. /*
  125.  * Formulate a normal query, send, and retrieve answer in supplied buffer.
  126.  * Return the size of the response on success, -1 on error.
  127.  * If enabled, implement search rules until answer or unrecoverable failure
  128.  * is detected.  Error number is left in h_errno.
  129.  * Only useful for queries in the same name hierarchy as the local host
  130.  * (not, for example, for host address-to-name lookups in domain in-addr.arpa).
  131.  */
  132. res_search(name, class, type, answer, anslen)
  133.     char *name;        /* domain name */
  134.     int class, type;    /* class and type of query */
  135.     u_char *answer;        /* buffer to put answer */
  136.     int anslen;        /* size of answer */
  137. {
  138.     register char *cp, **domain;
  139.     int n, ret, got_nodata = 0;
  140.     char *hostalias();
  141.  
  142.     if ((_res.options & RES_INIT) == 0 && res_init() == -1)
  143.         return (-1);
  144.  
  145.     errno = 0;
  146.     h_errno = HOST_NOT_FOUND;        /* default, if we never query */
  147.     for (cp = name, n = 0; *cp; cp++)
  148.         if (*cp == '.')
  149.             n++;
  150.     if (n == 0 && (cp = hostalias(name)))
  151.         return (res_query(cp, class, type, answer, anslen));
  152.  
  153.     /*
  154.      * If it has two or more dots there is a good change it is
  155.      * fully qualified so try it first.
  156.      */
  157.     if ((n >= 2) && (ret = res_querydomain(name, (char *)NULL, class,
  158.                            type, answer, anslen)) > 0)
  159.         return (ret);
  160.  
  161.     /*
  162.      * We do at least one level of search if
  163.      *    - there is no dot and RES_DEFNAME is set, or
  164.      *    - there is at least one dot, there is no trailing dot,
  165.      *      and RES_DNSRCH is set.
  166.      */
  167.     if ((n == 0 && _res.options & RES_DEFNAMES) ||
  168.        (n != 0 && *--cp != '.' && _res.options & RES_DNSRCH))
  169.          for (domain = _res.dnsrch; *domain; domain++) {
  170.         ret = res_querydomain(name, *domain, class, type,
  171.             answer, anslen);
  172.         if (ret > 0)
  173.             return (ret);
  174.         /*
  175.          * If no server present, give up.
  176.          * If name isn't found in this domain,
  177.          * keep trying higher domains in the search list
  178.          * (if that's enabled).
  179.          * On a NO_DATA error, keep trying, otherwise
  180.          * a wildcard entry of another type could keep us
  181.          * from finding this entry higher in the domain.
  182.          * If we get some other error (negative answer or
  183.          * server failure), then stop searching up,
  184.          * but try the input name below in case it's fully-qualified.
  185.          */
  186.         if (errno == ECONNREFUSED) {
  187.             h_errno = TRY_AGAIN;
  188.             return (-1);
  189.         }
  190.         if (h_errno == NO_DATA)
  191.             got_nodata++;
  192.         if ((h_errno != HOST_NOT_FOUND && h_errno != NO_DATA) ||
  193.             (_res.options & RES_DNSRCH) == 0)
  194.             break;
  195.     }
  196.     /*
  197.      * If the search/default failed, try the name as fully-qualified,
  198.      * but only if it contained at least one dot (even trailing).
  199.      * This is purely a heuristic; we assume that any reasonable query
  200.      * about a top-level domain (for servers, SOA, etc) will not use
  201.      * res_search.
  202.      */
  203.     if (n && (ret = res_querydomain(name, (char *)NULL, class, type,
  204.         answer, anslen)) > 0)
  205.         return (ret);
  206.     if (got_nodata)
  207.         h_errno = NO_DATA;
  208.     return (-1);
  209. }
  210.  
  211. /*
  212.  * Perform a call on res_query on the concatenation of name and domain,
  213.  * removing a trailing dot from name if domain is NULL.
  214.  */
  215. res_querydomain(name, domain, class, type, answer, anslen)
  216.     char *name, *domain;
  217.     int class, type;    /* class and type of query */
  218.     u_char *answer;        /* buffer to put answer */
  219.     int anslen;        /* size of answer */
  220. {
  221.     char nbuf[2*MAXDNAME+2];
  222.     char *longname = nbuf;
  223.     int n;
  224.  
  225. #ifdef DEBUG
  226.     if (_res.options & RES_DEBUG)
  227.         printf("res_querydomain(%s, %s, %d, %d)\n",
  228.             name, domain, class, type);
  229. #endif
  230.     if (domain == NULL) {
  231.         /*
  232.          * Check for trailing '.';
  233.          * copy without '.' if present.
  234.          */
  235.         n = strlen(name) - 1;
  236.         if (name[n] == '.' && n < sizeof(nbuf) - 1) {
  237.             bcopy(name, nbuf, n);
  238.             nbuf[n] = '\0';
  239.         } else
  240.             longname = name;
  241.     } else
  242.         (void)sprintf(nbuf, "%.*s.%.*s",
  243.             MAXDNAME, name, MAXDNAME, domain);
  244.  
  245.     return (res_query(longname, class, type, answer, anslen));
  246. }
  247.  
  248. char *
  249. hostalias(name)
  250.     register char *name;
  251. {
  252.     register char *C1, *C2;
  253.     FILE *fp;
  254.     char *file, *getenv(), *strcpy(), *strncpy();
  255.     char buf[BUFSIZ];
  256.     static char abuf[MAXDNAME];
  257.  
  258.     file = getenv("HOSTALIASES");
  259.     if (file == NULL || (fp = fopen(file, "r")) == NULL)
  260.         return (NULL);
  261.     buf[sizeof(buf) - 1] = '\0';
  262.     while (fgets(buf, sizeof(buf), fp)) {
  263.         for (C1 = buf; *C1 && !isspace(*C1); ++C1);
  264.         if (!*C1)
  265.             break;
  266.         *C1 = '\0';
  267.         if (!strcasecmp(buf, name)) {
  268.             while (isspace(*++C1));
  269.             if (!*C1)
  270.                 break;
  271.             for (C2 = C1 + 1; *C2 && !isspace(*C2); ++C2);
  272.             abuf[sizeof(abuf) - 1] = *C2 = '\0';
  273.             (void)strncpy(abuf, C1, sizeof(abuf) - 1);
  274.             fclose(fp);
  275.             return (abuf);
  276.         }
  277.     }
  278.     fclose(fp);
  279.     return (NULL);
  280. }
  281.