"Fossies" - the Fresh Open Source Software Archive

Member "libspf2-1.2.10/src/libspf2/spf_dns_resolv.c" (28 Jan 2012, 17154 Bytes) of package /linux/privat/libspf2-1.2.10.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "spf_dns_resolv.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * This program is free software; you can redistribute it and/or modify
    3  * it under the terms of either:
    4  *
    5  *   a) The GNU Lesser General Public License as published by the Free
    6  *      Software Foundation; either version 2.1, or (at your option) any
    7  *      later version,
    8  *
    9  *   OR
   10  *
   11  *   b) The two-clause BSD license.
   12  *
   13  * These licenses can be found with the distribution in the file LICENSES
   14  */
   15 
   16 /**
   17  * @file
   18  * @brief A DNS resolver which uses libresolv/libbind to query a DNS server.
   19  *
   20  * If we have a res_ninit then we make a thread-local resolver
   21  * state, which we use to perform all resolutions.
   22  *
   23  * If we do not have res_ninit, then we do a res_init() at
   24  * server-create time, and a res_close() at server-close time, and
   25  * we are NOT thread-safe. I think we don't actually have to call
   26  * res_init(), but we do anyway.
   27  */
   28 
   29 #ifndef _WIN32
   30 
   31 #include "spf_sys_config.h"
   32 
   33 #ifdef HAVE_ERRNO_H
   34 #include <errno.h>
   35 #endif
   36 
   37 #ifdef STDC_HEADERS
   38 # include <stdio.h>        /* stdin / stdout */
   39 # include <stdlib.h>       /* malloc / free */
   40 #endif
   41 
   42 #ifdef HAVE_STRING_H
   43 # include <string.h>       /* strstr / strdup */
   44 #else
   45 # ifdef HAVE_STRINGS_H
   46 #  include <strings.h>       /* strstr / strdup */
   47 # endif
   48 #endif
   49 
   50 #ifdef HAVE_RESOLV_H
   51 # include <resolv.h>       /* dn_skipname */
   52 #endif
   53 #ifdef HAVE_NETDB_H
   54 # include <netdb.h>
   55 #endif
   56 
   57 #ifdef HAVE_PTHREAD_H
   58 # include <pthread.h>
   59 #endif
   60 
   61 #include "spf.h"
   62 #include "spf_dns.h"
   63 #include "spf_internal.h"
   64 #include "spf_dns_internal.h"
   65 #include "spf_dns_resolv.h"
   66 
   67 /**
   68  * @file
   69  * Audited, 2008-09-15, Shevek.
   70  */
   71 
   72 static const struct res_sym ns_sects[] = {
   73     { ns_s_qd, "QUESTION",   "Question" },
   74     { ns_s_an, "ANSWER",     "Answer" },
   75     { ns_s_ns, "AUTHORITY",  "Authority" },
   76     { ns_s_ar, "ADDITIONAL", "Additional" },
   77 };
   78 
   79 static const int num_ns_sect = sizeof(ns_sects) / sizeof(*ns_sects);
   80 
   81 
   82 #if HAVE_DECL_RES_NINIT
   83 # define SPF_h_errno res_state->res_h_errno
   84 #else
   85 # define SPF_h_errno h_errno
   86 #endif
   87 
   88 #if HAVE_DECL_RES_NINIT
   89 static pthread_once_t   res_state_control = PTHREAD_ONCE_INIT;
   90 static pthread_key_t    res_state_key;
   91 
   92 static void
   93 SPF_dns_resolv_thread_term(void *arg)
   94 {
   95 #if HAVE_DECL_RES_NDESTROY
   96     res_ndestroy( (struct __res_state *)arg );
   97 #else
   98     res_nclose( (struct __res_state *)arg );
   99 #endif
  100     free(arg);
  101 }
  102 
  103 static void
  104 SPF_dns_resolv_init_key(void)
  105 {
  106     pthread_key_create(&res_state_key, SPF_dns_resolv_thread_term);
  107 }
  108 #endif
  109 
  110 /** XXX ns_rr is 1048 bytes, pass a pointer. */
  111 static void
  112 SPF_dns_resolv_debug(SPF_dns_server_t *spf_dns_server, ns_rr rr,
  113                 const u_char *responsebuf, size_t responselen,
  114                 const u_char *rdata, size_t rdlen)
  115 {
  116     char    ip4_buf[ INET_ADDRSTRLEN ];
  117     char    ip6_buf[ INET6_ADDRSTRLEN ];
  118     char    name_buf[ NS_MAXDNAME ];
  119     int     prio;
  120     int     err;
  121 
  122     switch (ns_rr_type(rr)) {
  123         case ns_t_a:
  124             if (rdlen != 4)
  125                 SPF_debugf("A: wrong rdlen %lu", (unsigned long)rdlen);
  126             else
  127                 SPF_debugf("A: %s",
  128                     inet_ntop(AF_INET, rdata,
  129                         ip4_buf, sizeof(ip4_buf)));
  130             break;
  131 
  132         case ns_t_aaaa:
  133             if (rdlen != 16)
  134                 SPF_debugf("AAAA: wrong rdlen %lu", (unsigned long)rdlen);
  135             else
  136                 SPF_debugf("AAAA: %s",
  137                     inet_ntop(AF_INET6, rdata,
  138                         ip6_buf, sizeof(ip6_buf)));
  139             break;
  140 
  141         case ns_t_ns:
  142             err = ns_name_uncompress(responsebuf,
  143                           responsebuf + responselen,
  144                           rdata,
  145                           name_buf, sizeof(name_buf));
  146             if (err < 0)        /* 0 or -1 */
  147                 SPF_debugf("ns_name_uncompress failed: err = %d  %s (%d)",
  148                         err, strerror(errno), errno);
  149             else
  150                 SPF_debugf("NS: %s", name_buf);
  151             break;
  152 
  153         case ns_t_cname:
  154             err = ns_name_uncompress(responsebuf,
  155                           responsebuf + responselen,
  156                           rdata,
  157                           name_buf, sizeof(name_buf));
  158             if ( err < 0 )      /* 0 or -1 */
  159                 SPF_debugf("ns_name_uncompress failed: err = %d  %s (%d)",
  160                         err, strerror(errno), errno );
  161             else
  162                 SPF_debugf("CNAME: %s", name_buf);
  163             break;
  164 
  165         case ns_t_mx:
  166             if (rdlen < NS_INT16SZ) {
  167                 SPF_debugf("MX: rdlen too short: %lu", (unsigned long)rdlen);
  168                 break;
  169             }
  170             prio = ns_get16(rdata);
  171             err = ns_name_uncompress(responsebuf,
  172                             responsebuf + responselen,
  173                             rdata + NS_INT16SZ,
  174                             name_buf, sizeof(name_buf));
  175             if (err < 0)        /* 0 or -1 */
  176                 SPF_debugf("ns_name_uncompress failed: err = %d  %s (%d)",
  177                         err, strerror(errno), errno);
  178             else
  179                 SPF_debugf("MX: %d %s", prio, name_buf);
  180             break;
  181 
  182         case ns_t_txt:
  183             if (rdlen < 1) {
  184                 SPF_debugf("TXT: rdlen too short: %lu", (unsigned long)rdlen);
  185                 break;
  186             }
  187             /* XXX I think this is wrong/unsafe. Shevek. */
  188             /* XXX doesn't parse the different TXT "sections" */
  189             SPF_debugf("TXT: (%lu) \"%.*s\"",
  190                     (unsigned long)rdlen, (int)rdlen - 1, rdata + 1);
  191             break;
  192 
  193         case ns_t_ptr:
  194             err = ns_name_uncompress(responsebuf,
  195                             responsebuf + responselen,
  196                             rdata,
  197                             name_buf, sizeof(name_buf));
  198             if (err < 0)        /* 0 or -1 */
  199                 SPF_debugf("ns_name_uncompress failed: err = %d  %s (%d)",
  200                         err, strerror(errno), errno);
  201             else
  202                 SPF_debugf("PTR: %s", name_buf);
  203             break;
  204 
  205         default:
  206             SPF_debugf("not parsed:  type: %d", ns_rr_type(rr));
  207             break;
  208     }
  209 
  210 }
  211 
  212 /**
  213  * Can return NULL on out-of-memory condition.
  214  * Should return a HOST_NOT_FOUND or appropriate rr in all other
  215  * error cases.
  216  */
  217 static SPF_dns_rr_t *
  218 SPF_dns_resolv_lookup(SPF_dns_server_t *spf_dns_server,
  219                 const char *domain, ns_type rr_type, int should_cache)
  220 {
  221     SPF_dns_rr_t            *spfrr;
  222 
  223     int     err;
  224     int     i;
  225     int     nrec;
  226     int     cnt;
  227 
  228     u_char  *responsebuf;
  229     size_t   responselen;
  230 
  231     ns_msg  ns_handle;
  232     ns_rr   rr;
  233 
  234     int     ns_sect;
  235     // int      num_ns_sect = sizeof( ns_sects ) / sizeof( *ns_sects );
  236 
  237     char    name_buf[ NS_MAXDNAME ];
  238 
  239     size_t  rdlen;
  240     const u_char    *rdata;
  241 
  242 #if HAVE_DECL_RES_NINIT
  243     void                *res_spec;
  244     struct __res_state  *res_state;
  245 #endif
  246 
  247     SPF_ASSERT_NOTNULL(spf_dns_server);
  248 
  249 #if HAVE_DECL_RES_NINIT
  250     /** Get the thread-local resolver state. */
  251     res_spec = pthread_getspecific(res_state_key);
  252     if (res_spec == NULL) {
  253         res_state = (struct __res_state *)
  254                         malloc(sizeof(struct __res_state));
  255         /* XXX The interface doesn't allow to communicate back failure
  256          * to allocate memory, but SPF_errorf aborts anyway. */
  257         if (! res_state)
  258             SPF_errorf("Failed to allocate %lu bytes for res_state",
  259                             (unsigned long)sizeof(struct __res_state));
  260         memset(res_state, 0, sizeof(struct __res_state));
  261         if (res_ninit(res_state) != 0)
  262             SPF_error("Failed to call res_ninit()");
  263         pthread_setspecific(res_state_key, (void *)res_state);
  264     }
  265     else {
  266         res_state = (struct __res_state *)res_spec;
  267     }
  268 #endif
  269 
  270     responselen = 2048;
  271     responsebuf = (u_char *)malloc(responselen);
  272     if (! responsebuf)
  273         return NULL;    /* NULL always means OOM from DNS lookup. */
  274     memset(responsebuf, 0, responselen);
  275 
  276     /*
  277      * Retry the lookup until our response buffer is big enough.
  278      *
  279      * This loop repeats until either we fail a lookup or we succeed.
  280      * The size of the response buffer is monotonic increasing, so eventually we
  281      * must either succeed, or we try to malloc more RAM than we can.
  282      *
  283      * The Linux man pages do not describe res_nquery adequately. Solaris says:
  284      *
  285      * The res_nquery() and res_query() routines return a length that may be bigger
  286      * than anslen. In that case, retry the query with a larger buf. The answer to the
  287      * second query may be larger still], so it is recommended that you supply a buf
  288      * larger than the answer returned by the previous query. answer must be large
  289      * enough to receive a maximum UDP response from the server or parts of the answer
  290      * will be silently discarded. The default maximum UDP response size is 512 bytes.
  291      */
  292     for (;;) {
  293         int dns_len;
  294 
  295 #if HAVE_DECL_RES_NINIT
  296         /* Resolve the name. */
  297         dns_len = res_nquery(res_state, domain, ns_c_in, rr_type,
  298                  responsebuf, responselen);
  299 #else
  300         dns_len = res_query(domain, ns_c_in, rr_type,
  301                  responsebuf, responselen);
  302 #endif
  303 
  304         if (dns_len < 0) {
  305             /* We failed to perform a lookup. */
  306             /* This block returns unconditionally. */
  307             free(responsebuf);
  308             if (spf_dns_server->debug)
  309                 SPF_debugf("query failed: err = %d  %s (%d): %s",
  310                     dns_len, hstrerror(SPF_h_errno), SPF_h_errno,
  311                     domain);
  312             if ((SPF_h_errno == HOST_NOT_FOUND) &&
  313                     (spf_dns_server->layer_below != NULL)) {
  314                 return SPF_dns_lookup(spf_dns_server->layer_below,
  315                                 domain, rr_type, should_cache);
  316             }
  317             return SPF_dns_rr_new_init(spf_dns_server,
  318                             domain, rr_type, 0, SPF_h_errno);
  319         }
  320         else if (dns_len > responselen) {
  321             void    *tmp;
  322             /* We managed a lookup but our buffer was too small. */
  323             responselen = dns_len + (dns_len >> 1);
  324 #if 0
  325             /* Sanity-trap - we should never hit this. */
  326             if (responselen > 1048576) {    /* One megabyte. */
  327                 free(responsebuf);
  328                 return SPF_dns_rr_new_init(spf_dns_server,
  329                                 domain, rr_type, 0, SPF_h_errno);
  330             }
  331 #endif
  332             tmp = realloc(responsebuf, responselen);
  333             if (!tmp) {
  334                 free(responsebuf);
  335                 return NULL;
  336             }
  337             responsebuf = tmp;
  338         }
  339         else {
  340             /* We managed a lookup, and our buffer was large enough. */
  341             responselen = dns_len;
  342             break;
  343         }
  344     }
  345 
  346 
  347 
  348     /*
  349      * initialize stuff
  350      */
  351     spfrr = SPF_dns_rr_new_init(spf_dns_server,
  352                     domain, rr_type, 0, NETDB_SUCCESS);
  353     if (!spfrr) {
  354         free(responsebuf);
  355         return NULL;
  356     }
  357 
  358     err = ns_initparse(responsebuf, responselen, &ns_handle);
  359 
  360     if (err < 0) {  /* 0 or -1 */
  361         if (spf_dns_server->debug)
  362             SPF_debugf("ns_initparse failed: err = %d  %s (%d)",
  363                 err, strerror(errno), errno);
  364         free(responsebuf);
  365         /* XXX Do we really want to return success with no data
  366          * on parse failure? */
  367         spfrr->herrno = NO_RECOVERY;
  368         return spfrr;
  369     }
  370 
  371 
  372     if (spf_dns_server->debug > 1) {
  373         SPF_debugf("msg id:             %d", ns_msg_id(ns_handle));
  374         SPF_debugf("ns_f_qr quest/resp: %d", ns_msg_getflag(ns_handle, ns_f_qr));
  375         SPF_debugf("ns_f_opcode:        %d", ns_msg_getflag(ns_handle, ns_f_opcode));
  376         SPF_debugf("ns_f_aa auth ans:   %d", ns_msg_getflag(ns_handle, ns_f_aa));
  377         SPF_debugf("ns_f_tc truncated:  %d", ns_msg_getflag(ns_handle, ns_f_tc));
  378         SPF_debugf("ns_f_rd rec desire: %d", ns_msg_getflag(ns_handle, ns_f_rd));
  379         SPF_debugf("ns_f_ra rec avail:  %d", ns_msg_getflag(ns_handle, ns_f_ra));
  380         SPF_debugf("ns_f_rcode:         %d", ns_msg_getflag(ns_handle, ns_f_rcode));
  381     }
  382 
  383 
  384     /* FIXME  the error handling from here on is suspect at best */
  385     for (ns_sect = 0; ns_sect < num_ns_sect; ns_sect++) {
  386         /* We pass this point if:
  387          * - We are the 'answer' section.
  388          * - We are debugging.
  389          * Otherwise, we continue to the next section.
  390          */
  391         if (ns_sects[ns_sect].number != ns_s_an && spf_dns_server->debug <= 1)
  392             continue;
  393 
  394         nrec = ns_msg_count(ns_handle, ns_sects[ns_sect].number);
  395 
  396         if (spf_dns_server->debug > 1)
  397             SPF_debugf("%s:  %d", ns_sects[ns_sect].name, nrec);
  398 
  399         spfrr->num_rr = 0;
  400         cnt = 0;
  401         for (i = 0; i < nrec; i++) {
  402             err = ns_parserr(&ns_handle, ns_sects[ns_sect].number, i, &rr);
  403             if (err < 0) {      /* 0 or -1 */
  404                 if (spf_dns_server->debug > 1)
  405                     SPF_debugf("ns_parserr failed: err = %d  %s (%d)",
  406                             err, strerror(errno), errno);
  407                 free(responsebuf);
  408                 /* XXX Do we really want to return partial data
  409                  * on parse failures? */
  410                 spfrr->herrno = NO_RECOVERY;
  411                 return spfrr;
  412             }
  413 
  414             rdlen = ns_rr_rdlen(rr);
  415             if (spf_dns_server->debug > 1)
  416                 SPF_debugf("name: %s  type: %d  class: %d  ttl: %d  rdlen: %lu",
  417                         ns_rr_name(rr), ns_rr_type(rr), ns_rr_class(rr),
  418                         ns_rr_ttl(rr), (unsigned long)rdlen);
  419 
  420             if (rdlen <= 0)
  421                 continue;
  422 
  423             rdata = ns_rr_rdata(rr);
  424 
  425             if (spf_dns_server->debug > 1)
  426                 SPF_dns_resolv_debug(spf_dns_server, rr,
  427                         responsebuf, responselen, rdata, rdlen);
  428 
  429             /* And now, if we aren't the answer section, we skip the section. */
  430             if (ns_sects[ns_sect].number != ns_s_an)
  431                 continue;
  432 
  433             /* Now, we are in the answer section. */
  434             if (ns_rr_type(rr) != spfrr->rr_type && ns_rr_type(rr) != ns_t_cname) {
  435                 SPF_debugf("unexpected rr type: %d   expected: %d",
  436                         ns_rr_type(rr), rr_type);
  437                 continue;
  438             }
  439 
  440             switch (ns_rr_type(rr)) {
  441                 case ns_t_a:
  442                     if (rdlen != 4) {
  443                         /* XXX Error handling. */
  444                         free(responsebuf);
  445                         return spfrr;
  446                     }
  447                     if (SPF_dns_rr_buf_realloc(spfrr, cnt,
  448                                 sizeof(spfrr->rr[cnt]->a)) != SPF_E_SUCCESS) {
  449                         free(responsebuf);
  450                         /* XXX Do we really want to return partial data
  451                          * on out of memory conditions? */
  452                         return spfrr;
  453                     }
  454                     memcpy(&spfrr->rr[cnt]->a, rdata, sizeof(spfrr->rr[cnt]->a));
  455                     cnt++;
  456                     break;
  457 
  458                 case ns_t_aaaa:
  459                     if (rdlen != 16) {
  460                         /* XXX Error handling. */
  461                         free(responsebuf);
  462                         return spfrr;
  463                     }
  464                     if (SPF_dns_rr_buf_realloc(spfrr, cnt,
  465                                 sizeof(spfrr->rr[cnt]->aaaa)) != SPF_E_SUCCESS) {
  466                         free(responsebuf);
  467                         /* XXX Do we really want to return partial data
  468                          * on out of memory conditions? */
  469                         return spfrr;
  470                     }
  471                     memcpy(&spfrr->rr[cnt]->aaaa, rdata, sizeof(spfrr->rr[cnt]->aaaa));
  472                     cnt++;
  473                     break;
  474 
  475                 case ns_t_ns:
  476                     break;
  477 
  478                 case ns_t_cname:
  479                     /* FIXME:  are CNAMEs always sent with the real RR? */
  480                     break;
  481 
  482                 case ns_t_mx:
  483                     if (rdlen < NS_INT16SZ) {
  484                         /* XXX Error handling. */
  485                         free(responsebuf);
  486                         return spfrr;
  487                     }
  488                     err = ns_name_uncompress(responsebuf,
  489                                     responsebuf + responselen,
  490                                     rdata + NS_INT16SZ,
  491                                     name_buf, sizeof(name_buf));
  492                     if (err < 0) {      /* 0 or -1 */
  493                         if (spf_dns_server->debug > 1)
  494                             SPF_debugf("ns_name_uncompress failed: err = %d  %s (%d)",
  495                                     err, strerror(errno), errno);
  496                         free(responsebuf);
  497                         /* XXX Do we really want to return partial data
  498                          * on parse error? */
  499                         return spfrr;
  500                     }
  501 
  502                     if (SPF_dns_rr_buf_realloc(spfrr, cnt,
  503                                     strlen(name_buf) + 1 ) != SPF_E_SUCCESS) {
  504                         free(responsebuf);
  505                         /* XXX Do we really want to return partial data
  506                          * on out of memory conditions? */
  507                         return spfrr;
  508                     }
  509                     strcpy(spfrr->rr[cnt]->mx, name_buf);
  510                     cnt++;
  511                     break;
  512 
  513                 case ns_t_txt:
  514                     if (rdlen > 1) {
  515                         u_char *src, *dst;
  516                         size_t len;
  517 
  518                         /* Just rdlen is enough because there is at least one
  519                          * length byte, which we do not copy. */
  520                         if (SPF_dns_rr_buf_realloc(spfrr, cnt, rdlen) != SPF_E_SUCCESS) {
  521                             free(responsebuf);
  522                             /* XXX Do we really want to return partial data
  523                              * on out of memory conditions? */
  524                             return spfrr;
  525                         }
  526 
  527                         dst = (u_char *)spfrr->rr[cnt]->txt;
  528                         src = (u_char *)rdata;
  529                         len = 0;
  530                         while (rdlen > 0) {
  531                             /* Consume one byte into a length. */
  532                             len = *src;
  533                             src++;
  534                             rdlen--;
  535 
  536                             /* Avoid buffer overrun if len is junk. */
  537                             /* XXX don't we rather want to flag this as error? */
  538                             if (len > rdlen)
  539                                 len = rdlen;
  540                             memcpy(dst, src, len);
  541 
  542                             /* Consume the data. */
  543                             src += len;
  544                             dst += len;
  545                             rdlen -= len;
  546                         }
  547                         *dst = '\0';
  548                     }
  549                     else {
  550                         if (SPF_dns_rr_buf_realloc(spfrr, cnt, 1) != SPF_E_SUCCESS) {
  551                             free(responsebuf);
  552                             /* XXX Do we really want to return partial data
  553                              * on out of memory conditions? */
  554                             return spfrr;
  555                         }
  556                         spfrr->rr[cnt]->txt[0] = '\0';
  557                     }
  558 
  559                     cnt++;
  560                     break;
  561 
  562                 case ns_t_ptr:
  563                     err = ns_name_uncompress(responsebuf,
  564                                     responsebuf + responselen,
  565                                     rdata,
  566                                     name_buf, sizeof(name_buf));
  567                     if (err < 0) {      /* 0 or -1 */
  568                         if (spf_dns_server->debug > 1)
  569                             SPF_debugf("ns_name_uncompress failed: err = %d  %s (%d)",
  570                                     err, strerror(errno), errno);
  571                         free(responsebuf);
  572                         /* XXX Do we really want to return partial data
  573                          * on parse error? */
  574                         return spfrr;
  575                     }
  576 
  577                     if (SPF_dns_rr_buf_realloc(spfrr, cnt,
  578                                     strlen(name_buf) + 1) != SPF_E_SUCCESS) {
  579                         free(responsebuf);
  580                         /* XXX Do we really want to return partial data
  581                          * on out of memory conditions? */
  582                         return spfrr;
  583                     }
  584                     strcpy(spfrr->rr[cnt]->ptr, name_buf);
  585                     cnt++;
  586                     break;
  587 
  588                 default:
  589                     break;
  590             }
  591         }
  592 
  593         spfrr->num_rr = cnt;
  594     }
  595 
  596     if (spfrr->num_rr == 0)
  597         spfrr->herrno = NO_DATA;
  598 
  599     free(responsebuf);
  600     return spfrr;
  601 }
  602 
  603 
  604 static void
  605 SPF_dns_resolv_free(SPF_dns_server_t *spf_dns_server)
  606 {
  607     SPF_ASSERT_NOTNULL(spf_dns_server);
  608 
  609 #if ! HAVE_DECL_RES_NINIT
  610     res_close();
  611 #endif
  612 
  613     free(spf_dns_server);
  614 }
  615 
  616 SPF_dns_server_t *
  617 SPF_dns_resolv_new(SPF_dns_server_t *layer_below,
  618                 const char *name, int debug)
  619 {
  620     SPF_dns_server_t        *spf_dns_server;
  621 
  622 #if HAVE_DECL_RES_NINIT
  623     pthread_once(&res_state_control, SPF_dns_resolv_init_key);
  624 #else
  625     if (res_init() != 0) {
  626         SPF_warning("Failed to call res_init()");
  627         return NULL;
  628     }
  629 #endif
  630 
  631     spf_dns_server = malloc(sizeof(SPF_dns_server_t));
  632     if (spf_dns_server == NULL)
  633         return NULL;
  634     memset(spf_dns_server, 0, sizeof(SPF_dns_server_t));
  635 
  636     if (name ==  NULL)
  637         name = "resolv";
  638 
  639     spf_dns_server->destroy     = SPF_dns_resolv_free;
  640     spf_dns_server->lookup      = SPF_dns_resolv_lookup;
  641     spf_dns_server->get_spf     = NULL;
  642     spf_dns_server->get_exp     = NULL;
  643     spf_dns_server->add_cache   = NULL;
  644     spf_dns_server->layer_below = layer_below;
  645     spf_dns_server->name        = name;
  646     spf_dns_server->debug       = debug;
  647 
  648     return spf_dns_server;
  649 }
  650 
  651 #endif  /* _WIN32 */