spf_dns_resolv.c

Go to the documentation of this file.
00001 /*
00002  * This program is free software; you can redistribute it and/or modify
00003  * it under the terms of either:
00004  *
00005  *   a) The GNU Lesser General Public License as published by the Free
00006  *      Software Foundation; either version 2.1, or (at your option) any
00007  *      later version,
00008  *
00009  *   OR
00010  *
00011  *   b) The two-clause BSD license.
00012  *
00013  * These licenses can be found with the distribution in the file LICENSES
00014  */
00015 
00029 #ifndef _WIN32
00030 
00031 #include "spf_sys_config.h"
00032 
00033 #ifdef HAVE_ERRNO_H
00034 #include <errno.h>
00035 #endif
00036 
00037 #ifdef STDC_HEADERS
00038 # include <stdio.h>        /* stdin / stdout */
00039 # include <stdlib.h>       /* malloc / free */
00040 #endif
00041 
00042 #ifdef HAVE_STRING_H
00043 # include <string.h>       /* strstr / strdup */
00044 #else
00045 # ifdef HAVE_STRINGS_H
00046 #  include <strings.h>       /* strstr / strdup */
00047 # endif
00048 #endif
00049 
00050 #ifdef HAVE_RESOLV_H
00051 # include <resolv.h>       /* dn_skipname */
00052 #endif
00053 #ifdef HAVE_NETDB_H
00054 # include <netdb.h>
00055 #endif
00056 
00057 #ifdef HAVE_PTHREAD_H
00058 # include <pthread.h>
00059 #endif
00060 
00061 #include "spf.h"
00062 #include "spf_dns.h"
00063 #include "spf_internal.h"
00064 #include "spf_dns_internal.h"
00065 #include "spf_dns_resolv.h"
00066 
00072 static const struct res_sym ns_sects[] = {
00073         { ns_s_qd, "QUESTION",   "Question" },
00074         { ns_s_an, "ANSWER",     "Answer" },
00075         { ns_s_ns, "AUTHORITY",  "Authority" },
00076         { ns_s_ar, "ADDITIONAL", "Additional" },
00077 };
00078 
00079 static const int num_ns_sect = sizeof(ns_sects) / sizeof(*ns_sects);
00080 
00081 
00082 #if HAVE_DECL_RES_NINIT
00083 # define SPF_h_errno res_state->res_h_errno
00084 #else
00085 # define SPF_h_errno h_errno
00086 #endif
00087 
00088 #if HAVE_DECL_RES_NINIT
00089 static pthread_once_t   res_state_control = PTHREAD_ONCE_INIT;
00090 static pthread_key_t    res_state_key;
00091 
00092 static void
00093 SPF_dns_resolv_thread_term(void *arg)
00094 {
00095 #if HAVE_DECL_RES_NDESTROY
00096         res_ndestroy( (struct __res_state *)arg );
00097 #else
00098         res_nclose( (struct __res_state *)arg );
00099 #endif
00100         free(arg);
00101 }
00102 
00103 static void
00104 SPF_dns_resolv_init_key(void)
00105 {
00106         pthread_key_create(&res_state_key, SPF_dns_resolv_thread_term);
00107 }
00108 #endif
00109 
00111 static void
00112 SPF_dns_resolv_debug(SPF_dns_server_t *spf_dns_server, ns_rr rr,
00113                                 const u_char *responsebuf, size_t responselen,
00114                                 const u_char *rdata, size_t rdlen)
00115 {
00116         char    ip4_buf[ INET_ADDRSTRLEN ];
00117         char    ip6_buf[ INET6_ADDRSTRLEN ];
00118         char    name_buf[ NS_MAXDNAME ];
00119         int             prio;
00120         int             err;
00121 
00122         switch (ns_rr_type(rr)) {
00123                 case ns_t_a:
00124                         if (rdlen != 4)
00125                                 SPF_debugf("A: wrong rdlen %lu", (unsigned long)rdlen);
00126                         else
00127                                 SPF_debugf("A: %s",
00128                                         inet_ntop(AF_INET, rdata,
00129                                                 ip4_buf, sizeof(ip4_buf)));
00130                         break;
00131 
00132                 case ns_t_aaaa:
00133                         if (rdlen != 16)
00134                                 SPF_debugf("AAAA: wrong rdlen %lu", (unsigned long)rdlen);
00135                         else
00136                                 SPF_debugf("AAAA: %s",
00137                                         inet_ntop(AF_INET6, rdata,
00138                                                 ip6_buf, sizeof(ip6_buf)));
00139                         break;
00140 
00141                 case ns_t_ns:
00142                         err = ns_name_uncompress(responsebuf,
00143                                                   responsebuf + responselen,
00144                                                   rdata,
00145                                                   name_buf, sizeof(name_buf));
00146                         if (err < 0)            /* 0 or -1 */
00147                                 SPF_debugf("ns_name_uncompress failed: err = %d  %s (%d)",
00148                                                 err, strerror(errno), errno);
00149                         else
00150                                 SPF_debugf("NS: %s", name_buf);
00151                         break;
00152 
00153                 case ns_t_cname:
00154                         err = ns_name_uncompress(responsebuf,
00155                                                   responsebuf + responselen,
00156                                                   rdata,
00157                                                   name_buf, sizeof(name_buf));
00158                         if ( err < 0 )          /* 0 or -1 */
00159                                 SPF_debugf("ns_name_uncompress failed: err = %d  %s (%d)",
00160                                                 err, strerror(errno), errno );
00161                         else
00162                                 SPF_debugf("CNAME: %s", name_buf);
00163                         break;
00164 
00165                 case ns_t_mx:
00166                         if (rdlen < NS_INT16SZ) {
00167                                 SPF_debugf("MX: rdlen too short: %lu", (unsigned long)rdlen);
00168                                 break;
00169                         }
00170                         prio = ns_get16(rdata);
00171                         err = ns_name_uncompress(responsebuf,
00172                                                         responsebuf + responselen,
00173                                                         rdata + NS_INT16SZ,
00174                                                         name_buf, sizeof(name_buf));
00175                         if (err < 0)            /* 0 or -1 */
00176                                 SPF_debugf("ns_name_uncompress failed: err = %d  %s (%d)",
00177                                                 err, strerror(errno), errno);
00178                         else
00179                                 SPF_debugf("MX: %d %s", prio, name_buf);
00180                         break;
00181 
00182                 case ns_t_spf:
00183                 case ns_t_txt:
00184                         if (rdlen < 1) {
00185                                 SPF_debugf(ns_rr_type(rr) == ns_t_txt ? "TXT" : "SPF" ": rdlen too short: %lu", (unsigned long)rdlen);
00186                                 break;
00187                         }
00188                         /* XXX I think this is wrong/unsafe. Shevek. */
00189                         /* XXX doesn't parse the different TXT "sections" */
00190                         SPF_debugf(ns_rr_type(rr) == ns_t_txt ? "TXT" : "SPF" ": (%lu) \"%.*s\"",
00191                                         (unsigned long)rdlen, (int)rdlen - 1, rdata + 1);
00192                         break;
00193 
00194                 case ns_t_ptr:
00195                         err = ns_name_uncompress(responsebuf,
00196                                                         responsebuf + responselen,
00197                                                         rdata,
00198                                                         name_buf, sizeof(name_buf));
00199                         if (err < 0)            /* 0 or -1 */
00200                                 SPF_debugf("ns_name_uncompress failed: err = %d  %s (%d)",
00201                                                 err, strerror(errno), errno);
00202                         else
00203                                 SPF_debugf("PTR: %s", name_buf);
00204                         break;
00205 
00206                 default:
00207                         SPF_debugf("not parsed:  type: %d", ns_rr_type(rr));
00208                         break;
00209         }
00210 
00211 }
00212 
00218 static SPF_dns_rr_t *
00219 SPF_dns_resolv_lookup(SPF_dns_server_t *spf_dns_server,
00220                                 const char *domain, ns_type rr_type, int should_cache)
00221 {
00222         SPF_dns_rr_t                    *spfrr;
00223 
00224         int             err;
00225         int             i;
00226         int             nrec;
00227         int             cnt;
00228 
00229         u_char  *responsebuf;
00230         size_t   responselen;
00231 
00232         ns_msg  ns_handle;
00233         ns_rr   rr;
00234 
00235         int             ns_sect;
00236         // int          num_ns_sect = sizeof( ns_sects ) / sizeof( *ns_sects );
00237 
00238         char    name_buf[ NS_MAXDNAME ];
00239 
00240         size_t  rdlen;
00241         const u_char    *rdata;
00242 
00243 #if HAVE_DECL_RES_NINIT
00244         void                            *res_spec;
00245         struct __res_state      *res_state;
00246 #endif
00247 
00248         SPF_ASSERT_NOTNULL(spf_dns_server);
00249 
00250 #if HAVE_DECL_RES_NINIT
00251 
00252         res_spec = pthread_getspecific(res_state_key);
00253         if (res_spec == NULL) {
00254                 res_state = (struct __res_state *)
00255                                                 malloc(sizeof(struct __res_state));
00256                 /* XXX The interface doesn't allow to communicate back failure
00257                  * to allocate memory, but SPF_errorf aborts anyway. */
00258                 if (! res_state)
00259                         SPF_errorf("Failed to allocate %lu bytes for res_state",
00260                                                         (unsigned long)sizeof(struct __res_state));
00261                 memset(res_state, 0, sizeof(struct __res_state));
00262                 if (res_ninit(res_state) != 0)
00263                         SPF_error("Failed to call res_ninit()");
00264                 pthread_setspecific(res_state_key, (void *)res_state);
00265         }
00266         else {
00267                 res_state = (struct __res_state *)res_spec;
00268         }
00269 #endif
00270 
00271         responselen = 2048;
00272         responsebuf = (u_char *)malloc(responselen);
00273         if (! responsebuf)
00274                 return NULL;    /* NULL always means OOM from DNS lookup. */
00275         memset(responsebuf, 0, responselen);
00276 
00277         /*
00278          * Retry the lookup until our response buffer is big enough.
00279          *
00280          * This loop repeats until either we fail a lookup or we succeed.
00281          * The size of the response buffer is monotonic increasing, so eventually we
00282          * must either succeed, or we try to malloc more RAM than we can.
00283          *
00284          * The Linux man pages do not describe res_nquery adequately. Solaris says:
00285          *
00286          * The res_nquery() and res_query() routines return a length that may be bigger
00287          * than anslen. In that case, retry the query with a larger buf. The answer to the
00288          * second query may be larger still], so it is recommended that you supply a buf
00289          * larger than the answer returned by the previous query. answer must be large
00290          * enough to receive a maximum UDP response from the server or parts of the answer
00291          * will be silently discarded. The default maximum UDP response size is 512 bytes.
00292          */
00293         for (;;) {
00294                 int     dns_len;
00295 
00296 #if HAVE_DECL_RES_NINIT
00297                 /* Resolve the name. */
00298                 dns_len = res_nquery(res_state, domain, ns_c_in, rr_type,
00299                                  responsebuf, responselen);
00300 #else
00301                 dns_len = res_query(domain, ns_c_in, rr_type,
00302                                  responsebuf, responselen);
00303 #endif
00304 
00305                 if (dns_len < 0) {
00306                         /* We failed to perform a lookup. */
00307                         /* This block returns unconditionally. */
00308                         free(responsebuf);
00309                         if (spf_dns_server->debug)
00310                                 SPF_debugf("query failed: err = %d  %s (%d): %s",
00311                                         dns_len, hstrerror(SPF_h_errno), SPF_h_errno,
00312                                         domain);
00313                         if ((SPF_h_errno == HOST_NOT_FOUND) &&
00314                                         (spf_dns_server->layer_below != NULL)) {
00315                                 return SPF_dns_lookup(spf_dns_server->layer_below,
00316                                                                 domain, rr_type, should_cache);
00317                         }
00318                         return SPF_dns_rr_new_init(spf_dns_server,
00319                                                         domain, rr_type, 0, SPF_h_errno);
00320                 }
00321                 else if (dns_len > responselen) {
00322                         void    *tmp;
00323                         /* We managed a lookup but our buffer was too small. */
00324                         responselen = dns_len + (dns_len >> 1);
00325 #if 0
00326                         /* Sanity-trap - we should never hit this. */
00327                         if (responselen > 1048576) {    /* One megabyte. */
00328                                 free(responsebuf);
00329                                 return SPF_dns_rr_new_init(spf_dns_server,
00330                                                                 domain, rr_type, 0, SPF_h_errno);
00331                         }
00332 #endif
00333                         tmp = realloc(responsebuf, responselen);
00334                         if (!tmp) {
00335                                 free(responsebuf);
00336                                 return NULL;
00337                         }
00338                         responsebuf = tmp;
00339                 }
00340                 else {
00341                         /* We managed a lookup, and our buffer was large enough. */
00342                         responselen = dns_len;
00343                         break;
00344                 }
00345         }
00346 
00347 
00348 
00349         /*
00350          * initialize stuff
00351          */
00352         spfrr = SPF_dns_rr_new_init(spf_dns_server,
00353                                         domain, rr_type, 0, NETDB_SUCCESS);
00354         if (!spfrr) {
00355                 free(responsebuf);
00356                 return NULL;
00357         }
00358 
00359         err = ns_initparse(responsebuf, responselen, &ns_handle);
00360 
00361         if (err < 0) {  /* 0 or -1 */
00362                 if (spf_dns_server->debug)
00363                         SPF_debugf("ns_initparse failed: err = %d  %s (%d)",
00364                                 err, strerror(errno), errno);
00365                 free(responsebuf);
00366                 spfrr->herrno = NO_RECOVERY;
00367                 return spfrr;
00368         }
00369 
00370 
00371         if (spf_dns_server->debug > 1) {
00372                 SPF_debugf("msg id:             %d", ns_msg_id(ns_handle));
00373                 SPF_debugf("ns_f_qr quest/resp: %d", ns_msg_getflag(ns_handle, ns_f_qr));
00374                 SPF_debugf("ns_f_opcode:        %d", ns_msg_getflag(ns_handle, ns_f_opcode));
00375                 SPF_debugf("ns_f_aa auth ans:   %d", ns_msg_getflag(ns_handle, ns_f_aa));
00376                 SPF_debugf("ns_f_tc truncated:  %d", ns_msg_getflag(ns_handle, ns_f_tc));
00377                 SPF_debugf("ns_f_rd rec desire: %d", ns_msg_getflag(ns_handle, ns_f_rd));
00378                 SPF_debugf("ns_f_ra rec avail:  %d", ns_msg_getflag(ns_handle, ns_f_ra));
00379                 SPF_debugf("ns_f_rcode:         %d", ns_msg_getflag(ns_handle, ns_f_rcode));
00380         }
00381 
00382 
00383         spfrr->num_rr = 0;
00384         for (ns_sect = 0; ns_sect < num_ns_sect; ns_sect++) {
00385                 /* We pass this point if:
00386                  * - We are the 'answer' section.
00387                  * Otherwise, we continue to the next section.
00388                  */
00389                 if (ns_sects[ns_sect].number != ns_s_an)
00390                         continue;
00391 
00392                 nrec = ns_msg_count(ns_handle, ns_sects[ns_sect].number);
00393 
00394                 if (spf_dns_server->debug > 1)
00395                         SPF_debugf("%s:  %d", ns_sects[ns_sect].name, nrec);
00396 
00397                 cnt = 0;
00398                 for (i = 0; i < nrec; i++) {
00399                         err = ns_parserr(&ns_handle, ns_sects[ns_sect].number, i, &rr);
00400                         if (err < 0) {          /* 0 or -1 */
00401                                 if (spf_dns_server->debug > 1)
00402                                         SPF_debugf("ns_parserr failed: err = %d  %s (%d)",
00403                                                         err, strerror(errno), errno);
00404                                 free(responsebuf);
00405                                 spfrr->herrno = NO_RECOVERY;
00406                                 return spfrr;
00407                         }
00408 
00409                         rdlen = ns_rr_rdlen(rr);
00410                         if (spf_dns_server->debug > 1)
00411                                 SPF_debugf("name: %s  type: %d  class: %d  ttl: %d  rdlen: %lu",
00412                                                 ns_rr_name(rr), ns_rr_type(rr), ns_rr_class(rr),
00413                                                 ns_rr_ttl(rr), (unsigned long)rdlen);
00414 
00415                         if (rdlen <= 0)
00416                                 continue;
00417 
00418                         rdata = ns_rr_rdata(rr);
00419 
00420                         if (spf_dns_server->debug > 1)
00421                                 SPF_dns_resolv_debug(spf_dns_server, rr,
00422                                                 responsebuf, responselen, rdata, rdlen);
00423 
00424                         /* And now, if we aren't the answer section, we skip the section. */
00425                         if (ns_sects[ns_sect].number != ns_s_an)
00426                                 continue;
00427 
00428                         /* Now, we are in the answer section. */
00429                         if (ns_rr_type(rr) != spfrr->rr_type && ns_rr_type(rr) != ns_t_cname) {
00430                                 SPF_debugf("unexpected rr type: %d   expected: %d",
00431                                                 ns_rr_type(rr), rr_type);
00432                                 continue;
00433                         }
00434 
00435                         switch (ns_rr_type(rr)) {
00436                                 case ns_t_a:
00437                                         if (rdlen != 4) {
00438                                                 free(responsebuf);
00439                                                 spfrr->herrno = NO_RECOVERY;
00440                                                 return spfrr;
00441                                         }
00442                                         if (SPF_dns_rr_buf_realloc(spfrr, cnt,
00443                                                                 sizeof(spfrr->rr[cnt]->a)) != SPF_E_SUCCESS) {
00444                                                 free(responsebuf);
00445                                                 spfrr->herrno = TRY_AGAIN;
00446                                                 return spfrr;
00447                                         }
00448                                         memcpy(&spfrr->rr[cnt]->a, rdata, sizeof(spfrr->rr[cnt]->a));
00449                                         cnt++;
00450                                         break;
00451 
00452                                 case ns_t_aaaa:
00453                                         if (rdlen != 16) {
00454                                                 free(responsebuf);
00455                                                 spfrr->herrno = NO_RECOVERY;
00456                                                 return spfrr;
00457                                         }
00458                                         if (SPF_dns_rr_buf_realloc(spfrr, cnt,
00459                                                                 sizeof(spfrr->rr[cnt]->aaaa)) != SPF_E_SUCCESS) {
00460                                                 free(responsebuf);
00461                                                 spfrr->herrno = TRY_AGAIN;
00462                                                 return spfrr;
00463                                         }
00464                                         memcpy(&spfrr->rr[cnt]->aaaa, rdata, sizeof(spfrr->rr[cnt]->aaaa));
00465                                         cnt++;
00466                                         break;
00467 
00468                                 case ns_t_ns:
00469                                         break;
00470 
00471                                 case ns_t_cname:
00472                                         /* FIXME:  are CNAMEs always sent with the real RR? */
00473                                         break;
00474 
00475                                 case ns_t_mx:
00476                                         if (rdlen < NS_INT16SZ) {
00477                                                 free(responsebuf);
00478                                                 spfrr->herrno = NO_RECOVERY;
00479                                                 return spfrr;
00480                                         }
00481                                         err = ns_name_uncompress(responsebuf,
00482                                                                         responsebuf + responselen,
00483                                                                         rdata + NS_INT16SZ,
00484                                                                         name_buf, sizeof(name_buf));
00485                                         if (err < 0) {          /* 0 or -1 */
00486                                                 if (spf_dns_server->debug > 1)
00487                                                         SPF_debugf("ns_name_uncompress failed: err = %d  %s (%d)",
00488                                                                         err, strerror(errno), errno);
00489                                                 free(responsebuf);
00490                                                 spfrr->herrno = NO_RECOVERY;
00491                                                 return spfrr;
00492                                         }
00493 
00494                                         if (SPF_dns_rr_buf_realloc(spfrr, cnt,
00495                                                                         strlen(name_buf) + 1 ) != SPF_E_SUCCESS) {
00496                                                 free(responsebuf);
00497                                                 spfrr->herrno = TRY_AGAIN;
00498                                                 return spfrr;
00499                                         }
00500                                         strcpy(spfrr->rr[cnt]->mx, name_buf);
00501                                         cnt++;
00502                                         break;
00503 
00504                                 case ns_t_spf:
00505                                 case ns_t_txt:
00506                                         if (rdlen > 1) {
00507                                                 u_char *src, *dst;
00508                                                 size_t len;
00509 
00510                                                 /* Just rdlen is enough because there is at least one
00511                                                  * length byte, which we do not copy. */
00512                                                 if (SPF_dns_rr_buf_realloc(spfrr, cnt, rdlen) != SPF_E_SUCCESS) {
00513                                                         free(responsebuf);
00514                                                         spfrr->herrno = TRY_AGAIN;
00515                                                         return spfrr;
00516                                                 }
00517 
00518                                                 dst = (u_char *)spfrr->rr[cnt]->txt;
00519                                                 src = (u_char *)rdata;
00520                                                 len = 0;
00521                                                 while (rdlen > 0) {
00522                                                         /* Consume one byte into a length. */
00523                                                         len = *src;
00524                                                         src++;
00525                                                         rdlen--;
00526 
00527                                                         /* Avoid buffer overrun if len is junk. */
00528                                                         /* XXX don't we rather want to flag this as error? */
00529                                                         if (len > rdlen)
00530                                                                 len = rdlen;
00531                                                         memcpy(dst, src, len);
00532 
00533                                                         /* Consume the data. */
00534                                                         src += len;
00535                                                         dst += len;
00536                                                         rdlen -= len;
00537                                                 }
00538                                                 *dst = '\0';
00539                                         }
00540                                         else {
00541                                                 if (SPF_dns_rr_buf_realloc(spfrr, cnt, 1) != SPF_E_SUCCESS) {
00542                                                         free(responsebuf);
00543                                                         spfrr->herrno = TRY_AGAIN;
00544                                                         return spfrr;
00545                                                 }
00546                                                 spfrr->rr[cnt]->txt[0] = '\0';
00547                                         }
00548 
00549                                         cnt++;
00550                                         break;
00551 
00552                                 case ns_t_ptr:
00553                                         err = ns_name_uncompress(responsebuf,
00554                                                                         responsebuf + responselen,
00555                                                                         rdata,
00556                                                                         name_buf, sizeof(name_buf));
00557                                         if (err < 0) {          /* 0 or -1 */
00558                                                 if (spf_dns_server->debug > 1)
00559                                                         SPF_debugf("ns_name_uncompress failed: err = %d  %s (%d)",
00560                                                                         err, strerror(errno), errno);
00561                                                 free(responsebuf);
00562                                                 spfrr->herrno = NO_RECOVERY;
00563                                                 return spfrr;
00564                                         }
00565 
00566                                         if (SPF_dns_rr_buf_realloc(spfrr, cnt,
00567                                                                         strlen(name_buf) + 1) != SPF_E_SUCCESS) {
00568                                                 free(responsebuf);
00569                                                 spfrr->herrno = TRY_AGAIN;
00570                                                 return spfrr;
00571                                         }
00572                                         strcpy(spfrr->rr[cnt]->ptr, name_buf);
00573                                         cnt++;
00574                                         break;
00575 
00576                                 default:
00577                                         break;
00578                         }
00579                 }
00580 
00581                 spfrr->num_rr += cnt;
00582         }
00583 
00584         if (spfrr->num_rr == 0)
00585                 spfrr->herrno = NO_DATA;
00586 
00587         free(responsebuf);
00588         return spfrr;
00589 }
00590 
00591 
00592 static void
00593 SPF_dns_resolv_free(SPF_dns_server_t *spf_dns_server)
00594 {
00595         SPF_ASSERT_NOTNULL(spf_dns_server);
00596 
00597 #if ! HAVE_DECL_RES_NINIT
00598         res_close();
00599 #endif
00600 
00601         free(spf_dns_server);
00602 }
00603 
00604 SPF_dns_server_t *
00605 SPF_dns_resolv_new(SPF_dns_server_t *layer_below,
00606                                 const char *name, int debug)
00607 {
00608         SPF_dns_server_t                *spf_dns_server;
00609 
00610 #if HAVE_DECL_RES_NINIT
00611         pthread_once(&res_state_control, SPF_dns_resolv_init_key);
00612 #else
00613         if (res_init() != 0) {
00614                 SPF_warning("Failed to call res_init()");
00615                 return NULL;
00616         }
00617 #endif
00618 
00619         spf_dns_server = malloc(sizeof(SPF_dns_server_t));
00620         if (spf_dns_server == NULL)
00621                 return NULL;
00622         memset(spf_dns_server, 0, sizeof(SPF_dns_server_t));
00623 
00624         if (name ==  NULL)
00625                 name = "resolv";
00626 
00627         spf_dns_server->destroy     = SPF_dns_resolv_free;
00628         spf_dns_server->lookup      = SPF_dns_resolv_lookup;
00629         spf_dns_server->get_spf     = NULL;
00630         spf_dns_server->get_exp     = NULL;
00631         spf_dns_server->add_cache   = NULL;
00632         spf_dns_server->layer_below = layer_below;
00633         spf_dns_server->name        = name;
00634         spf_dns_server->debug       = debug;
00635 
00636         return spf_dns_server;
00637 }
00638 
00639 #endif  /* _WIN32 */

Generated on 20 May 2019 for libspf2 by  doxygen 1.6.1