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                 /* XXX Do we really want to return success with no data
00367                  * on parse failure? */
00368                 spfrr->herrno = NO_RECOVERY;
00369                 return spfrr;
00370         }
00371 
00372 
00373         if (spf_dns_server->debug > 1) {
00374                 SPF_debugf("msg id:             %d", ns_msg_id(ns_handle));
00375                 SPF_debugf("ns_f_qr quest/resp: %d", ns_msg_getflag(ns_handle, ns_f_qr));
00376                 SPF_debugf("ns_f_opcode:        %d", ns_msg_getflag(ns_handle, ns_f_opcode));
00377                 SPF_debugf("ns_f_aa auth ans:   %d", ns_msg_getflag(ns_handle, ns_f_aa));
00378                 SPF_debugf("ns_f_tc truncated:  %d", ns_msg_getflag(ns_handle, ns_f_tc));
00379                 SPF_debugf("ns_f_rd rec desire: %d", ns_msg_getflag(ns_handle, ns_f_rd));
00380                 SPF_debugf("ns_f_ra rec avail:  %d", ns_msg_getflag(ns_handle, ns_f_ra));
00381                 SPF_debugf("ns_f_rcode:         %d", ns_msg_getflag(ns_handle, ns_f_rcode));
00382         }
00383 
00384 
00385         /* FIXME  the error handling from here on is suspect at best */
00386         for (ns_sect = 0; ns_sect < num_ns_sect; ns_sect++) {
00387                 /* We pass this point if:
00388                  * - We are the 'answer' section.
00389                  * - We are debugging.
00390                  * Otherwise, we continue to the next section.
00391                  */
00392                 if (ns_sects[ns_sect].number != ns_s_an && spf_dns_server->debug <= 1)
00393                         continue;
00394 
00395                 nrec = ns_msg_count(ns_handle, ns_sects[ns_sect].number);
00396 
00397                 if (spf_dns_server->debug > 1)
00398                         SPF_debugf("%s:  %d", ns_sects[ns_sect].name, nrec);
00399 
00400                 spfrr->num_rr = 0;
00401                 cnt = 0;
00402                 for (i = 0; i < nrec; i++) {
00403                         err = ns_parserr(&ns_handle, ns_sects[ns_sect].number, i, &rr);
00404                         if (err < 0) {          /* 0 or -1 */
00405                                 if (spf_dns_server->debug > 1)
00406                                         SPF_debugf("ns_parserr failed: err = %d  %s (%d)",
00407                                                         err, strerror(errno), errno);
00408                                 free(responsebuf);
00409                                 /* XXX Do we really want to return partial data
00410                                  * on parse failures? */
00411                                 spfrr->herrno = NO_RECOVERY;
00412                                 return spfrr;
00413                         }
00414 
00415                         rdlen = ns_rr_rdlen(rr);
00416                         if (spf_dns_server->debug > 1)
00417                                 SPF_debugf("name: %s  type: %d  class: %d  ttl: %d  rdlen: %lu",
00418                                                 ns_rr_name(rr), ns_rr_type(rr), ns_rr_class(rr),
00419                                                 ns_rr_ttl(rr), (unsigned long)rdlen);
00420 
00421                         if (rdlen <= 0)
00422                                 continue;
00423 
00424                         rdata = ns_rr_rdata(rr);
00425 
00426                         if (spf_dns_server->debug > 1)
00427                                 SPF_dns_resolv_debug(spf_dns_server, rr,
00428                                                 responsebuf, responselen, rdata, rdlen);
00429 
00430                         /* And now, if we aren't the answer section, we skip the section. */
00431                         if (ns_sects[ns_sect].number != ns_s_an)
00432                                 continue;
00433 
00434                         /* Now, we are in the answer section. */
00435                         if (ns_rr_type(rr) != spfrr->rr_type && ns_rr_type(rr) != ns_t_cname) {
00436                                 SPF_debugf("unexpected rr type: %d   expected: %d",
00437                                                 ns_rr_type(rr), rr_type);
00438                                 continue;
00439                         }
00440 
00441                         switch (ns_rr_type(rr)) {
00442                                 case ns_t_a:
00443                                         if (rdlen != 4) {
00444                                                 /* XXX Error handling. */
00445                                                 free(responsebuf);
00446                                                 return spfrr;
00447                                         }
00448                                         if (SPF_dns_rr_buf_realloc(spfrr, cnt,
00449                                                                 sizeof(spfrr->rr[cnt]->a)) != SPF_E_SUCCESS) {
00450                                                 free(responsebuf);
00451                                                 /* XXX Do we really want to return partial data
00452                                                  * on out of memory conditions? */
00453                                                 return spfrr;
00454                                         }
00455                                         memcpy(&spfrr->rr[cnt]->a, rdata, sizeof(spfrr->rr[cnt]->a));
00456                                         cnt++;
00457                                         break;
00458 
00459                                 case ns_t_aaaa:
00460                                         if (rdlen != 16) {
00461                                                 /* XXX Error handling. */
00462                                                 free(responsebuf);
00463                                                 return spfrr;
00464                                         }
00465                                         if (SPF_dns_rr_buf_realloc(spfrr, cnt,
00466                                                                 sizeof(spfrr->rr[cnt]->aaaa)) != SPF_E_SUCCESS) {
00467                                                 free(responsebuf);
00468                                                 /* XXX Do we really want to return partial data
00469                                                  * on out of memory conditions? */
00470                                                 return spfrr;
00471                                         }
00472                                         memcpy(&spfrr->rr[cnt]->aaaa, rdata, sizeof(spfrr->rr[cnt]->aaaa));
00473                                         cnt++;
00474                                         break;
00475 
00476                                 case ns_t_ns:
00477                                         break;
00478 
00479                                 case ns_t_cname:
00480                                         /* FIXME:  are CNAMEs always sent with the real RR? */
00481                                         break;
00482 
00483                                 case ns_t_mx:
00484                                         if (rdlen < NS_INT16SZ) {
00485                                                 /* XXX Error handling. */
00486                                                 free(responsebuf);
00487                                                 return spfrr;
00488                                         }
00489                                         err = ns_name_uncompress(responsebuf,
00490                                                                         responsebuf + responselen,
00491                                                                         rdata + NS_INT16SZ,
00492                                                                         name_buf, sizeof(name_buf));
00493                                         if (err < 0) {          /* 0 or -1 */
00494                                                 if (spf_dns_server->debug > 1)
00495                                                         SPF_debugf("ns_name_uncompress failed: err = %d  %s (%d)",
00496                                                                         err, strerror(errno), errno);
00497                                                 free(responsebuf);
00498                                                 /* XXX Do we really want to return partial data
00499                                                  * on parse error? */
00500                                                 return spfrr;
00501                                         }
00502 
00503                                         if (SPF_dns_rr_buf_realloc(spfrr, cnt,
00504                                                                         strlen(name_buf) + 1 ) != SPF_E_SUCCESS) {
00505                                                 free(responsebuf);
00506                                                 /* XXX Do we really want to return partial data
00507                                                  * on out of memory conditions? */
00508                                                 return spfrr;
00509                                         }
00510                                         strcpy(spfrr->rr[cnt]->mx, name_buf);
00511                                         cnt++;
00512                                         break;
00513 
00514                                 case ns_t_spf:
00515                                 case ns_t_txt:
00516                                         if (rdlen > 1) {
00517                                                 u_char *src, *dst;
00518                                                 size_t len;
00519 
00520                                                 /* Just rdlen is enough because there is at least one
00521                                                  * length byte, which we do not copy. */
00522                                                 if (SPF_dns_rr_buf_realloc(spfrr, cnt, rdlen) != SPF_E_SUCCESS) {
00523                                                         free(responsebuf);
00524                                                         /* XXX Do we really want to return partial data
00525                                                          * on out of memory conditions? */
00526                                                         return spfrr;
00527                                                 }
00528 
00529                                                 dst = (u_char *)spfrr->rr[cnt]->txt;
00530                                                 src = (u_char *)rdata;
00531                                                 len = 0;
00532                                                 while (rdlen > 0) {
00533                                                         /* Consume one byte into a length. */
00534                                                         len = *src;
00535                                                         src++;
00536                                                         rdlen--;
00537 
00538                                                         /* Avoid buffer overrun if len is junk. */
00539                                                         /* XXX don't we rather want to flag this as error? */
00540                                                         if (len > rdlen)
00541                                                                 len = rdlen;
00542                                                         memcpy(dst, src, len);
00543 
00544                                                         /* Consume the data. */
00545                                                         src += len;
00546                                                         dst += len;
00547                                                         rdlen -= len;
00548                                                 }
00549                                                 *dst = '\0';
00550                                         }
00551                                         else {
00552                                                 if (SPF_dns_rr_buf_realloc(spfrr, cnt, 1) != SPF_E_SUCCESS) {
00553                                                         free(responsebuf);
00554                                                         /* XXX Do we really want to return partial data
00555                                                          * on out of memory conditions? */
00556                                                         return spfrr;
00557                                                 }
00558                                                 spfrr->rr[cnt]->txt[0] = '\0';
00559                                         }
00560 
00561                                         cnt++;
00562                                         break;
00563 
00564                                 case ns_t_ptr:
00565                                         err = ns_name_uncompress(responsebuf,
00566                                                                         responsebuf + responselen,
00567                                                                         rdata,
00568                                                                         name_buf, sizeof(name_buf));
00569                                         if (err < 0) {          /* 0 or -1 */
00570                                                 if (spf_dns_server->debug > 1)
00571                                                         SPF_debugf("ns_name_uncompress failed: err = %d  %s (%d)",
00572                                                                         err, strerror(errno), errno);
00573                                                 free(responsebuf);
00574                                                 /* XXX Do we really want to return partial data
00575                                                  * on parse error? */
00576                                                 return spfrr;
00577                                         }
00578 
00579                                         if (SPF_dns_rr_buf_realloc(spfrr, cnt,
00580                                                                         strlen(name_buf) + 1) != SPF_E_SUCCESS) {
00581                                                 free(responsebuf);
00582                                                 /* XXX Do we really want to return partial data
00583                                                  * on out of memory conditions? */
00584                                                 return spfrr;
00585                                         }
00586                                         strcpy(spfrr->rr[cnt]->ptr, name_buf);
00587                                         cnt++;
00588                                         break;
00589 
00590                                 default:
00591                                         break;
00592                         }
00593                 }
00594 
00595                 spfrr->num_rr = cnt;
00596         }
00597 
00598         if (spfrr->num_rr == 0)
00599                 spfrr->herrno = NO_DATA;
00600 
00601         free(responsebuf);
00602         return spfrr;
00603 }
00604 
00605 
00606 static void
00607 SPF_dns_resolv_free(SPF_dns_server_t *spf_dns_server)
00608 {
00609         SPF_ASSERT_NOTNULL(spf_dns_server);
00610 
00611 #if ! HAVE_DECL_RES_NINIT
00612         res_close();
00613 #endif
00614 
00615         free(spf_dns_server);
00616 }
00617 
00618 SPF_dns_server_t *
00619 SPF_dns_resolv_new(SPF_dns_server_t *layer_below,
00620                                 const char *name, int debug)
00621 {
00622         SPF_dns_server_t                *spf_dns_server;
00623 
00624 #if HAVE_DECL_RES_NINIT
00625         pthread_once(&res_state_control, SPF_dns_resolv_init_key);
00626 #else
00627         if (res_init() != 0) {
00628                 SPF_warning("Failed to call res_init()");
00629                 return NULL;
00630         }
00631 #endif
00632 
00633         spf_dns_server = malloc(sizeof(SPF_dns_server_t));
00634         if (spf_dns_server == NULL)
00635                 return NULL;
00636         memset(spf_dns_server, 0, sizeof(SPF_dns_server_t));
00637 
00638         if (name ==  NULL)
00639                 name = "resolv";
00640 
00641         spf_dns_server->destroy     = SPF_dns_resolv_free;
00642         spf_dns_server->lookup      = SPF_dns_resolv_lookup;
00643         spf_dns_server->get_spf     = NULL;
00644         spf_dns_server->get_exp     = NULL;
00645         spf_dns_server->add_cache   = NULL;
00646         spf_dns_server->layer_below = layer_below;
00647         spf_dns_server->name        = name;
00648         spf_dns_server->debug       = debug;
00649 
00650         return spf_dns_server;
00651 }
00652 
00653 #endif  /* _WIN32 */

Generated on 1 Sep 2020 for libspf2 by  doxygen 1.6.1