home *** CD-ROM | disk | FTP | other *** search
/ ftp.ee.lbl.gov / 2014.05.ftp.ee.lbl.gov.tar / ftp.ee.lbl.gov / hf-1.2.tar.gz / hf-1.2.tar / hf-1.2 / nb_dns.c < prev    next >
C/C++ Source or Header  |  2010-02-10  |  14KB  |  636 lines

  1. /*
  2.  * Copyright (c) 2000, 2001, 2002, 2009, 2010
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that: (1) source code distributions
  7.  * retain the above copyright notice and this paragraph in its entirety, (2)
  8.  * distributions including binary code include the above copyright notice and
  9.  * this paragraph in its entirety in the documentation or other materials
  10.  * provided with the distribution, and (3) all advertising materials mentioning
  11.  * features or use of this software display the following acknowledgement:
  12.  * ``This product includes software developed by the University of California,
  13.  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
  14.  * the University nor the names of its contributors may be used to endorse
  15.  * or promote products derived from this software without specific prior
  16.  * written permission.
  17.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  18.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  19.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  20.  */
  21. #ifndef lint
  22. static const char rcsid[] =
  23.     "@(#) $Id: nb_dns.c 181 2010-02-10 09:46:47Z leres $ (LBL)";
  24. #endif
  25. /*
  26.  * nb_dns - non-blocking dns routines
  27.  *
  28.  * This version works with BIND 9
  29.  *
  30.  * Note: The code here is way more complicated than it should be but
  31.  * although the interface to send requests is public, the routine to
  32.  * crack reply buffers is private.
  33.  */
  34.  
  35. #ifdef notdef
  36. #include "config.h"            /* must appear before first ifdef */
  37. #endif
  38.  
  39. #include <sys/types.h>
  40. #include <sys/socket.h>
  41.  
  42. #include <netinet/in.h>
  43.  
  44. #include <arpa/inet.h>
  45. #include <arpa/nameser.h>
  46.  
  47. #include <errno.h>
  48. #ifdef HAVE_MEMORY_H
  49. #include <memory.h>
  50. #endif
  51. #include <netdb.h>
  52. #include <resolv.h>
  53. #include <stdio.h>
  54. #include <stdlib.h>
  55. #include <string.h>
  56. #include <unistd.h>
  57.  
  58. #include "gnuc.h"
  59. #ifdef HAVE_OS_PROTO_H
  60. #include "os-proto.h"
  61. #endif
  62.  
  63. #include "nb_dns.h"
  64.  
  65. #if PACKETSZ > 1024
  66. #define MAXPACKET    PACKETSZ
  67. #else
  68. #define MAXPACKET    1024
  69. #endif
  70.  
  71. #ifdef DO_SOCK_DECL
  72. extern int socket(int, int, int);
  73. extern int connect(int, const struct sockaddr *, int);
  74. extern int send(int, const void *, int, int);
  75. extern int recvfrom(int, void *, int, int, struct sockaddr *, int *);
  76. #endif
  77.  
  78. /* Private data */
  79. struct nb_dns_entry {
  80.     struct nb_dns_entry *next;
  81.     char name[NS_MAXDNAME + 1];
  82.     int qtype;            /* query type */
  83.     int atype;            /* address family */
  84.     int asize;            /* address size */
  85.     u_short id;
  86.     void *cookie;
  87. };
  88.  
  89. #ifndef MAXALIASES
  90. #define MAXALIASES    35
  91. #endif
  92. #ifndef MAXADDRS
  93. #define MAXADDRS    35
  94. #endif
  95.  
  96. struct nb_dns_hostent {
  97.     struct hostent hostent;
  98.     int numaliases;
  99.     int numaddrs;
  100.     char *host_aliases[MAXALIASES + 1];
  101.     char *h_addr_ptrs[MAXADDRS + 1];
  102.     char hostbuf[8 * 1024];
  103. };
  104.  
  105. struct nb_dns_info {
  106.     int s;                /* Resolver file descriptor */
  107.     struct sockaddr_in server;    /* server address to bind to */
  108.     struct nb_dns_entry *list;    /* outstanding requests */
  109.     struct nb_dns_hostent dns_hostent;
  110. };
  111.  
  112. /* Forwards */
  113. static int _nb_dns_mkquery(struct nb_dns_info *, const char *, int, int,
  114.     void *, char *);
  115. static int _nb_dns_cmpsockaddr(struct sockaddr *, struct sockaddr *, char *);
  116.  
  117. static char *
  118. my_strerror(int errnum)
  119. {
  120. #if HAVE_STRERROR
  121.     extern char *strerror(int);
  122.     return strerror(errnum);
  123. #else
  124.     static char errnum_buf[32];
  125.     snprintf(errnum_buf, sizeof(errnum_buf), "errno %d", errnum);
  126.     return errnum_buf;
  127. #endif
  128. }
  129.  
  130. struct nb_dns_info *
  131. nb_dns_init(char *errstr)
  132. {
  133.     struct nb_dns_info *nd;
  134.  
  135.     nd = (struct nb_dns_info *)malloc(sizeof(*nd));
  136.     if (nd == NULL) {
  137.         snprintf(errstr, NB_DNS_ERRSIZE, "nb_dns_init: malloc(): %s",
  138.             my_strerror(errno));
  139.         return (NULL);
  140.     }
  141.     memset(nd, 0, sizeof(*nd));
  142.     nd->s = -1;
  143.  
  144.     /* XXX should be able to init static hostent struct some other way */
  145.     (void)gethostbyname("localhost.");
  146.  
  147.     if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
  148.         snprintf(errstr, NB_DNS_ERRSIZE, "res_init() failed");
  149.         free(nd);
  150.         return (NULL);
  151.     }
  152.     nd->s = socket(PF_INET, SOCK_DGRAM, 0);
  153.     if (nd->s < 0) {
  154.         snprintf(errstr, NB_DNS_ERRSIZE, "socket(): %s",
  155.             my_strerror(errno));
  156.         free(nd);
  157.         return (NULL);
  158.     }
  159.  
  160.     /* XXX should use resolver config */
  161.     nd->server = _res.nsaddr_list[0];
  162.  
  163.     if (connect(nd->s, (struct sockaddr *)&nd->server,
  164.         sizeof(struct sockaddr)) < 0) {
  165.         snprintf(errstr, NB_DNS_ERRSIZE, "connect(%s): %s",
  166.             inet_ntoa(nd->server.sin_addr), my_strerror(errno));
  167.         close(nd->s);
  168.         free(nd);
  169.         return (NULL);
  170.     }
  171.  
  172.     return (nd);
  173. }
  174.  
  175. void
  176. nb_dns_finish(struct nb_dns_info *nd)
  177. {
  178.     struct nb_dns_entry *ne, *ne2;
  179.  
  180.     ne = nd->list;
  181.     while (ne != NULL) {
  182.         ne2 = ne;
  183.         ne = ne->next;
  184.         free(ne2);
  185.     }
  186.     close(nd->s);
  187.     free(nd);
  188. }
  189.  
  190. int
  191. nb_dns_fd(struct nb_dns_info *nd)
  192. {
  193.  
  194.     return (nd->s);
  195. }
  196.  
  197. static int
  198. _nb_dns_cmpsockaddr(struct sockaddr *sa1, struct sockaddr *sa2, char *errstr)
  199. {
  200.     struct sockaddr_in *sin1, *sin2;
  201. #ifdef AF_INET6
  202.     struct sockaddr_in6 *sin6a, *sin6b;
  203. #endif
  204.     const static char serr[] = "answer from wrong nameserver (%d)";
  205.  
  206.     if (sa1->sa_family != sa1->sa_family) {
  207.         snprintf(errstr, NB_DNS_ERRSIZE, serr, 1);
  208.         return (-1);
  209.     }
  210.     switch (sa1->sa_family) {
  211.  
  212.     case AF_INET:
  213.         sin1 = (struct sockaddr_in *)sa1;
  214.         sin2 = (struct sockaddr_in *)sa2;
  215.         if (sin1->sin_port != sin2->sin_port) {
  216.             snprintf(errstr, NB_DNS_ERRSIZE, serr, 2);
  217.             return (-1);
  218.         }
  219.         if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) {
  220.             snprintf(errstr, NB_DNS_ERRSIZE, serr, 3);
  221.             return (-1);
  222.         }
  223.         break;
  224.  
  225. #ifdef AF_INET6
  226.     case AF_INET6:
  227.         sin6a = (struct sockaddr_in6 *)sa1;
  228.         sin6b = (struct sockaddr_in6 *)sa2;
  229.         if (sin6a->sin6_port != sin6b->sin6_port) {
  230.             snprintf(errstr, NB_DNS_ERRSIZE, serr, 2);
  231.             return (-1);
  232.         }
  233.         if (memcmp(&sin6a->sin6_addr, &sin6b->sin6_addr,
  234.             sizeof(sin6a->sin6_addr)) != 0) {
  235.             snprintf(errstr, NB_DNS_ERRSIZE, serr, 3);
  236.             return (-1);
  237.         }
  238.         break;
  239. #endif
  240.  
  241.     default:
  242.         snprintf(errstr, NB_DNS_ERRSIZE, serr, 4);
  243.         return (-1);
  244.     }
  245.     return (0);
  246. }
  247.  
  248. static int
  249. _nb_dns_mkquery(struct nb_dns_info *nd, const char *name, int atype,
  250.     int qtype, void * cookie, char *errstr)
  251. {
  252.     HEADER *hp;
  253.     int n;
  254.     u_char *msg;
  255.     struct nb_dns_entry *ne;
  256.  
  257.     /* Allocate an entry */
  258.     ne = (struct nb_dns_entry *)calloc(1, sizeof(*ne));
  259.     if (ne == NULL) {
  260.         snprintf(errstr, NB_DNS_ERRSIZE, "calloc(): %s",
  261.             my_strerror(errno));
  262.         return (-1);
  263.     }
  264.     strncpy(ne->name, name, sizeof(ne->name));
  265.     ne->name[sizeof(ne->name) - 1] = '\0';
  266.     ne->qtype = qtype;
  267.     ne->atype = atype;
  268.     switch (atype) {
  269.  
  270.     case AF_INET:
  271.         ne->asize = NS_INADDRSZ;
  272.         break;
  273.  
  274. #ifdef AF_INET6
  275.     case AF_INET6:
  276.         ne->asize = NS_IN6ADDRSZ;
  277.         break;
  278. #endif
  279.  
  280.     default:
  281.         snprintf(errstr, NB_DNS_ERRSIZE,
  282.             "_nb_dns_mkquery: bad family %d", atype);
  283.         return (-1);
  284.     }
  285.  
  286.     /* Allocate msg buffer */
  287.     msg = calloc(1, MAXPACKET);
  288.     if (msg == NULL) {
  289.         snprintf(errstr, NB_DNS_ERRSIZE, "calloc() msg: %s",
  290.             my_strerror(errno));
  291.         free(ne);
  292.         return (-1);
  293.     }
  294.  
  295.     /* Build the request */
  296.     n = res_mkquery(
  297.         ns_o_query,            /* op code (query) */
  298.         name,            /* domain name */
  299.         ns_c_in,            /* query class (internet) */
  300.         qtype,            /* query type */
  301.         NULL,            /* data */
  302.         0,                /* length of data */
  303.         NULL,            /* new rr */
  304.         (u_char *)msg,        /* buffer */
  305.         MAXPACKET);            /* size of buffer */
  306.     if (n < 0) {
  307.         snprintf(errstr, NB_DNS_ERRSIZE, "res_mkquery() failed (%d)",
  308.             MAXPACKET);
  309.         free(ne);
  310.         free(msg);
  311.         return (-1);
  312.     }
  313.  
  314.     hp = (HEADER *)msg;
  315.     ne->id = htons(hp->id);
  316.  
  317.     if (send(nd->s, (char *)msg, n, 0) != n) {
  318.         snprintf(errstr, NB_DNS_ERRSIZE, "send(): %s",
  319.             my_strerror(errno));
  320.         free(ne);
  321.         free(msg);
  322.         return (-1);
  323.     }
  324.  
  325.     ne->next = nd->list;
  326.     ne->cookie = cookie;
  327.     nd->list = ne;
  328.     free(msg);
  329.  
  330.     return(0);
  331. }
  332.  
  333. int
  334. nb_dns_host_request(struct nb_dns_info *nd, const char *name,
  335.     void *cookie, char *errstr)
  336. {
  337.  
  338.     return (nb_dns_host_request2(nd, name, AF_INET, cookie, errstr));
  339. }
  340.  
  341. int
  342. nb_dns_host_request2(struct nb_dns_info *nd, const char *name,
  343.     int af, void *cookie, char *errstr)
  344. {
  345.     int qtype;
  346.  
  347.     switch (af) {
  348.  
  349.     case AF_INET:
  350.         qtype = T_A;
  351.         break;
  352.  
  353. #ifdef AF_INET6
  354.     case AF_INET6:
  355.         qtype = T_AAAA;
  356.         break;
  357. #endif
  358.  
  359.     default:
  360.         snprintf(errstr, NB_DNS_ERRSIZE,
  361.             "nb_dns_host_request2(): uknown address family %d", af);
  362.         return (-1);
  363.     }
  364.     return (_nb_dns_mkquery(nd, name, af, qtype, cookie, errstr));
  365. }
  366.  
  367. int
  368. nb_dns_addr_request(struct nb_dns_info *nd, nb_uint32_t addr,
  369.     void *cookie, char *errstr)
  370. {
  371.  
  372.     return (nb_dns_addr_request2(nd, (char *)&addr, AF_INET,
  373.         cookie, errstr));
  374. }
  375.  
  376. int
  377. nb_dns_addr_request2(struct nb_dns_info *nd, char *addrp,
  378.     int af, void *cookie, char *errstr)
  379. {
  380. #ifdef AF_INET6
  381.     char *cp;
  382.     int n, i;
  383.     size_t size;
  384. #endif
  385.     u_char *uaddr;
  386.     char name[NS_MAXDNAME + 1];
  387.  
  388.     switch (af) {
  389.  
  390.     case AF_INET:
  391.         uaddr = (u_char *)addrp;
  392.         snprintf(name, sizeof(name), "%u.%u.%u.%u.in-addr.arpa",
  393.             (uaddr[3] & 0xff),
  394.             (uaddr[2] & 0xff),
  395.             (uaddr[1] & 0xff),
  396.             (uaddr[0] & 0xff));
  397.         break;
  398.  
  399. #ifdef AF_INET6
  400.     case AF_INET6:
  401.         uaddr = (u_char *)addrp;
  402.         cp = name;
  403.         size = sizeof(name);
  404.         for (n = NS_IN6ADDRSZ - 1; n >= 0; --n) {
  405.             snprintf(cp, size, "%x.%x.",
  406.                 (uaddr[n] & 0xf),
  407.                 (uaddr[n] >> 4) & 0xf);
  408.             i = strlen(cp);
  409.             size -= i;
  410.             cp += i;
  411.         }
  412.         snprintf(cp, size, "ip6.int");
  413.         break;
  414. #endif
  415.  
  416.     default:
  417.         snprintf(errstr, NB_DNS_ERRSIZE,
  418.             "nb_dns_addr_request2(): uknown address family %d", af);
  419.         return (-1);
  420.     }
  421.  
  422.     return (_nb_dns_mkquery(nd, name, af, T_PTR, cookie, errstr));
  423. }
  424.  
  425. int
  426. nb_dns_abort_request(struct nb_dns_info *nd, void *cookie)
  427. {
  428.     struct nb_dns_entry *ne, *lastne;
  429.  
  430.     /* Try to find this request on the outstanding request list */
  431.     lastne = NULL;
  432.     for (ne = nd->list; ne != NULL; ne = ne->next) {
  433.         if (ne->cookie == cookie)
  434.             break;
  435.         lastne = ne;
  436.     }
  437.  
  438.     /* Not a currently pending request */
  439.     if (ne == NULL)
  440.         return (-1);
  441.  
  442.     /* Unlink this entry */
  443.     if (lastne == NULL)
  444.         nd->list = ne->next;
  445.     else
  446.         lastne->next = ne->next;
  447.     ne->next = NULL;
  448.  
  449.     return (0);
  450. }
  451.  
  452. /* Returns 1 with an answer, 0 when reply was old, -1 on fatal errors */
  453. int
  454. nb_dns_activity(struct nb_dns_info *nd, struct nb_dns_result *nr, char *errstr)
  455. {
  456.     int msglen, qtype, atype, n, i;
  457.     struct nb_dns_entry *ne, *lastne;
  458.     socklen_t fromlen;
  459.     struct sockaddr from;
  460.     u_long msg[MAXPACKET / sizeof(u_long)];
  461.     char *bp, *ep;
  462.     char **ap, **hap;
  463.     u_int16_t id;
  464.     const u_char *rdata;
  465.     struct hostent *he;
  466.     size_t rdlen;
  467.     ns_msg handle;
  468.     ns_rr rr;
  469.  
  470.     /* This comes from the second half of do_query() */
  471.     fromlen = sizeof(from);
  472.     msglen = recvfrom(nd->s, (char *)msg, sizeof(msg), 0, &from, &fromlen);
  473.     if (msglen <= 0) {
  474.         snprintf(errstr, NB_DNS_ERRSIZE, "recvfrom(): %s",
  475.             my_strerror(errno));
  476.         return (-1);
  477.     }
  478.     if (msglen < HFIXEDSZ) {
  479.         snprintf(errstr, NB_DNS_ERRSIZE, "recvfrom(): undersized: %d",
  480.             msglen);
  481.         return (-1);
  482.     }
  483.     if (ns_initparse((u_char *)msg, msglen, &handle) < 0) {
  484.         snprintf(errstr, NB_DNS_ERRSIZE, "ns_initparse(): %s",
  485.             my_strerror(errno));
  486.         nr->host_errno = NO_RECOVERY;
  487.         return (-1);
  488.     }
  489.  
  490.     /* RES_INSECURE1 style check */
  491.     if (_nb_dns_cmpsockaddr((struct sockaddr *)&nd->server, &from,
  492.         errstr) < 0) {
  493.         nr->host_errno = NO_RECOVERY;
  494.         return (-1);
  495.     }
  496.  
  497.     /* Search for this request */
  498.     lastne = NULL;
  499.     id = ns_msg_id(handle);
  500.     for (ne = nd->list; ne != NULL; ne = ne->next) {
  501.         if (ne->id == id)
  502.             break;
  503.         lastne = ne;
  504.     }
  505.  
  506.     /* Not an answer to a question we care about anymore */
  507.     if (ne == NULL)
  508.         return (0);
  509.  
  510.     /* Unlink this entry */
  511.     if (lastne == NULL)
  512.         nd->list = ne->next;
  513.     else
  514.         lastne->next = ne->next;
  515.     ne->next = NULL;
  516.  
  517.     /* RES_INSECURE2 style check */
  518.     /* XXX not implemented */
  519.  
  520.     /* Initialize result struct */
  521.     memset(nr, 0, sizeof(*nr));
  522.     nr->cookie = ne->cookie;
  523.     qtype = ne->qtype;
  524.  
  525.     /* Deal with various errors */
  526.     switch (ns_msg_getflag(handle, ns_f_rcode)) {
  527.  
  528.     case ns_r_nxdomain:
  529.         nr->host_errno = HOST_NOT_FOUND;
  530.         free(ne);
  531.         return (1);
  532.  
  533.     case ns_r_servfail:
  534.         nr->host_errno = TRY_AGAIN;
  535.         free(ne);
  536.         return (1);
  537.  
  538.     case ns_r_noerror:
  539.         break;
  540.  
  541.     case ns_r_formerr:
  542.     case ns_r_notimpl:
  543.     case ns_r_refused:
  544.     default:
  545.         nr->host_errno = NO_RECOVERY;
  546.         free(ne);
  547.         return (1);
  548.     }
  549.  
  550.     /* Loop through records in packet */
  551.     memset(&rr, 0, sizeof(rr));
  552.     memset(&nd->dns_hostent, 0, sizeof(nd->dns_hostent));
  553.     he = &nd->dns_hostent.hostent;
  554.     /* XXX no support for aliases */
  555.     he->h_aliases = nd->dns_hostent.host_aliases;
  556.     he->h_addr_list = nd->dns_hostent.h_addr_ptrs;
  557.     he->h_addrtype = ne->atype;
  558.     he->h_length = ne->asize;
  559.     free(ne);
  560.  
  561.     bp = nd->dns_hostent.hostbuf;
  562.     ep = bp + sizeof(nd->dns_hostent.hostbuf);
  563.     hap = he->h_addr_list;
  564.     ap = he->h_aliases;
  565.  
  566.     for (i = 0; i < ns_msg_count(handle, ns_s_an); i++) {
  567.         /* Parse next record */
  568.         if (ns_parserr(&handle, ns_s_an, i, &rr) < 0) {
  569.             if (errno != ENODEV) {
  570.                 nr->host_errno = NO_RECOVERY;
  571.                 return (1);
  572.             }
  573.             /* All done */
  574.             break;
  575.         }
  576.  
  577.         /* Ignore records that don't answer our query (e.g. CNAMEs) */
  578.         atype = ns_rr_type(rr);
  579.         if (atype != qtype)
  580.             continue;
  581.  
  582.         rdata = ns_rr_rdata(rr);
  583.         rdlen = ns_rr_rdlen(rr);
  584.         switch (atype) {
  585.  
  586.         case T_A:
  587.         case T_AAAA:
  588.             if (rdlen != he->h_length) {
  589.                 snprintf(errstr, NB_DNS_ERRSIZE,
  590.                     "nb_dns_activity(): bad rdlen %d", rdlen);
  591.                 nr->host_errno = NO_RECOVERY;
  592.                 return (-1);
  593.             }
  594.  
  595.             if (bp + rdlen >= ep) {
  596.                 snprintf(errstr, NB_DNS_ERRSIZE,
  597.                     "nb_dns_activity(): overflow 1");
  598.                 nr->host_errno = NO_RECOVERY;
  599.                 return (-1);
  600.             }
  601.             if (nd->dns_hostent.numaddrs + 1 >= MAXADDRS) {
  602.                 snprintf(errstr, NB_DNS_ERRSIZE,
  603.                     "nb_dns_activity(): overflow 2");
  604.                 nr->host_errno = NO_RECOVERY;
  605.                 return (-1);
  606.             }
  607.             memcpy(bp, rdata, rdlen);
  608.             *hap++ = bp;
  609.             bp += rdlen;
  610.             ++nd->dns_hostent.numaddrs;
  611.  
  612.             /* Keep looking for more A records */
  613.             break;
  614.  
  615.         case T_PTR:
  616.             n = dn_expand((const u_char *)msg,
  617.                 (const u_char *)msg + msglen, rdata, bp, ep - bp);
  618.             if (n < 0) {
  619.                 /* XXX return -1 here ??? */
  620.                 nr->host_errno = NO_RECOVERY;
  621.                 return (1);
  622.             }
  623.             he->h_name = bp;
  624.             /* XXX check for overflow */
  625.             bp += n;        /* returned len includes EOS */
  626.  
  627.             /* "Find first satisfactory answer" */
  628.             nr->hostent = he;
  629.             return (1);
  630.         }
  631.     }
  632.  
  633.     nr->hostent = he;
  634.     return (1);
  635. }
  636.