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_txt:
00183                         if (rdlen < 1) {
00184                                 SPF_debugf("TXT: rdlen too short: %lu", (unsigned long)rdlen);
00185                                 break;
00186                         }
00187                         /* XXX I think this is wrong/unsafe. Shevek. */
00188                         /* XXX doesn't parse the different TXT "sections" */
00189                         SPF_debugf("TXT: (%lu) \"%.*s\"",
00190                                         (unsigned long)rdlen, (int)rdlen - 1, rdata + 1);
00191                         break;
00192 
00193                 case ns_t_ptr:
00194                         err = ns_name_uncompress(responsebuf,
00195                                                         responsebuf + responselen,
00196                                                         rdata,
00197                                                         name_buf, sizeof(name_buf));
00198                         if (err < 0)            /* 0 or -1 */
00199                                 SPF_debugf("ns_name_uncompress failed: err = %d  %s (%d)",
00200                                                 err, strerror(errno), errno);
00201                         else
00202                                 SPF_debugf("PTR: %s", name_buf);
00203                         break;
00204 
00205                 default:
00206                         SPF_debugf("not parsed:  type: %d", ns_rr_type(rr));
00207                         break;
00208         }
00209 
00210 }
00211 
00217 static SPF_dns_rr_t *
00218 SPF_dns_resolv_lookup(SPF_dns_server_t *spf_dns_server,
00219                                 const char *domain, ns_type rr_type, int should_cache)
00220 {
00221         SPF_dns_rr_t                    *spfrr;
00222 
00223         int             err;
00224         int             i;
00225         int             nrec;
00226         int             cnt;
00227 
00228         u_char  *responsebuf;
00229         size_t   responselen;
00230 
00231         ns_msg  ns_handle;
00232         ns_rr   rr;
00233 
00234         int             ns_sect;
00235         int             num_ns_sect = sizeof( ns_sects ) / sizeof( *ns_sects );
00236 
00237         char    name_buf[ NS_MAXDNAME ];
00238 
00239         size_t  rdlen;
00240         const u_char    *rdata;
00241 
00242 #if HAVE_DECL_RES_NINIT
00243         void                            *res_spec;
00244         struct __res_state      *res_state;
00245 #endif
00246 
00247         SPF_ASSERT_NOTNULL(spf_dns_server);
00248 
00249 #if HAVE_DECL_RES_NINIT
00250 
00251         res_spec = pthread_getspecific(res_state_key);
00252         if (res_spec == NULL) {
00253                 res_state = (struct __res_state *)
00254                                                 malloc(sizeof(struct __res_state));
00255                 /* XXX The interface doesn't allow to communicate back failure
00256                  * to allocate memory, but SPF_errorf aborts anyway. */
00257                 if (! res_state)
00258                         SPF_errorf("Failed to allocate %lu bytes for res_state",
00259                                                         (unsigned long)sizeof(struct __res_state));
00260                 memset(res_state, 0, sizeof(struct __res_state));
00261                 if (res_ninit(res_state) != 0)
00262                         SPF_error("Failed to call res_ninit()");
00263                 pthread_setspecific(res_state_key, (void *)res_state);
00264         }
00265         else {
00266                 res_state = (struct __res_state *)res_spec;
00267         }
00268 #endif
00269 
00270         responselen = 2048;
00271         responsebuf = (u_char *)malloc(responselen);
00272         if (! responsebuf)
00273                 return NULL;    /* NULL always means OOM from DNS lookup. */
00274         memset(responsebuf, 0, responselen);
00275 
00276         /*
00277          * Retry the lookup until our response buffer is big enough.
00278          *
00279          * This loop repeats until either we fail a lookup or we succeed.
00280          * The size of the response buffer is monotonic increasing, so eventually we
00281          * must either succeed, or we try to malloc more RAM than we can.
00282          *
00283          * The Linux man pages do not describe res_nquery adequately. Solaris says:
00284          *
00285          * The res_nquery() and res_query() routines return a length that may be bigger
00286          * than anslen. In that case, retry the query with a larger buf. The answer to the
00287          * second query may be larger still], so it is recommended that you supply a buf
00288          * larger than the answer returned by the previous query. answer must be large
00289          * enough to receive a maximum UDP response from the server or parts of the answer
00290          * will be silently discarded. The default maximum UDP response size is 512 bytes.
00291          */
00292         for (;;) {
00293                 int     dns_len;
00294 
00295 #if HAVE_DECL_RES_NINIT
00296                 /* Resolve the name. */
00297                 dns_len = res_nquery(res_state, domain, ns_c_in, rr_type,
00298                                  responsebuf, responselen);
00299 #else
00300                 dns_len = res_query(domain, ns_c_in, rr_type,
00301                                  responsebuf, responselen);
00302 #endif
00303 
00304                 if (dns_len < 0) {
00305                         /* We failed to perform a lookup. */
00306                         /* This block returns unconditionally. */
00307                         free(responsebuf);
00308                         if (spf_dns_server->debug)
00309                                 SPF_debugf("query failed: err = %d  %s (%d): %s",
00310                                         dns_len, hstrerror(SPF_h_errno), SPF_h_errno,
00311                                         domain);
00312                         if ((SPF_h_errno == HOST_NOT_FOUND) &&
00313                                         (spf_dns_server->layer_below != NULL)) {
00314                                 return SPF_dns_lookup(spf_dns_server->layer_below,
00315                                                                 domain, rr_type, should_cache);
00316                         }
00317                         return SPF_dns_rr_new_init(spf_dns_server,
00318                                                         domain, rr_type, 0, SPF_h_errno);
00319                 }
00320                 else if (dns_len > responselen) {
00321                         void    *tmp;
00322                         /* We managed a lookup but our buffer was too small. */
00323                         responselen = dns_len + (dns_len >> 1);
00324 #if 0
00325                         /* Sanity-trap - we should never hit this. */
00326                         if (responselen > 1048576) {    /* One megabyte. */
00327                                 free(responsebuf);
00328                                 return SPF_dns_rr_new_init(spf_dns_server,
00329                                                                 domain, rr_type, 0, SPF_h_errno);
00330                         }
00331 #endif
00332                         tmp = realloc(responsebuf, responselen);
00333                         if (!tmp) {
00334                                 free(responsebuf);
00335                                 return NULL;
00336                         }
00337                         responsebuf = tmp;
00338                 }
00339                 else {
00340                         /* We managed a lookup, and our buffer was large enough. */
00341                         responselen = dns_len;
00342                         break;
00343                 }
00344         }
00345 
00346 
00347 
00348         /*
00349          * initialize stuff
00350          */
00351         spfrr = SPF_dns_rr_new_init(spf_dns_server,
00352                                         domain, rr_type, 0, NETDB_SUCCESS);
00353         if (!spfrr) {
00354                 free(responsebuf);
00355                 return NULL;
00356         }
00357 
00358         err = ns_initparse(responsebuf, responselen, &ns_handle);
00359 
00360         if (err < 0) {  /* 0 or -1 */
00361                 if (spf_dns_server->debug)
00362                         SPF_debugf("ns_initparse failed: err = %d  %s (%d)",
00363                                 err, strerror(errno), errno);
00364                 free(responsebuf);
00365                 /* XXX Do we really want to return success with no data
00366                  * on parse failure? */
00367                 spfrr->herrno = NO_RECOVERY;
00368                 return spfrr;
00369         }
00370 
00371 
00372         if (spf_dns_server->debug > 1) {
00373                 SPF_debugf("msg id:             %d", ns_msg_id(ns_handle));
00374                 SPF_debugf("ns_f_qr quest/resp: %d", ns_msg_getflag(ns_handle, ns_f_qr));
00375                 SPF_debugf("ns_f_opcode:        %d", ns_msg_getflag(ns_handle, ns_f_opcode));
00376                 SPF_debugf("ns_f_aa auth ans:   %d", ns_msg_getflag(ns_handle, ns_f_aa));
00377                 SPF_debugf("ns_f_tc truncated:  %d", ns_msg_getflag(ns_handle, ns_f_tc));
00378                 SPF_debugf("ns_f_rd rec desire: %d", ns_msg_getflag(ns_handle, ns_f_rd));
00379                 SPF_debugf("ns_f_ra rec avail:  %d", ns_msg_getflag(ns_handle, ns_f_ra));
00380                 SPF_debugf("ns_f_rcode:         %d", ns_msg_getflag(ns_handle, ns_f_rcode));
00381         }
00382 
00383 
00384         /* FIXME  the error handling from here on is suspect at best */
00385         for (ns_sect = 0; ns_sect < num_ns_sect; ns_sect++) {
00386                 /* We pass this point if:
00387                  * - We are the 'answer' section.
00388                  * - We are debugging.
00389                  * Otherwise, we continue to the next section.
00390                  */
00391                 if (ns_sects[ns_sect].number != ns_s_an && spf_dns_server->debug <= 1)
00392                         continue;
00393 
00394                 nrec = ns_msg_count(ns_handle, ns_sects[ns_sect].number);
00395 
00396                 if (spf_dns_server->debug > 1)
00397                         SPF_debugf("%s:  %d", ns_sects[ns_sect].name, nrec);
00398 
00399                 spfrr->num_rr = 0;
00400                 cnt = 0;
00401                 for (i = 0; i < nrec; i++) {
00402                         err = ns_parserr(&ns_handle, ns_sects[ns_sect].number, i, &rr);
00403                         if (err < 0) {          /* 0 or -1 */
00404                                 if (spf_dns_server->debug > 1)
00405                                         SPF_debugf("ns_parserr failed: err = %d  %s (%d)",
00406                                                         err, strerror(errno), errno);
00407                                 free(responsebuf);
00408                                 /* XXX Do we really want to return partial data
00409                                  * on parse failures? */
00410                                 spfrr->herrno = NO_RECOVERY;
00411                                 return spfrr;
00412                         }
00413 
00414                         rdlen = ns_rr_rdlen(rr);
00415                         if (spf_dns_server->debug > 1)
00416                                 SPF_debugf("name: %s  type: %d  class: %d  ttl: %d  rdlen: %lu",
00417                                                 ns_rr_name(rr), ns_rr_type(rr), ns_rr_class(rr),
00418                                                 ns_rr_ttl(rr), (unsigned long)rdlen);
00419 
00420                         if (rdlen <= 0)
00421                                 continue;
00422 
00423                         rdata = ns_rr_rdata(rr);
00424 
00425                         if (spf_dns_server->debug > 1)
00426                                 SPF_dns_resolv_debug(spf_dns_server, rr,
00427                                                 responsebuf, responselen, rdata, rdlen);
00428 
00429                         /* And now, if we aren't the answer section, we skip the section. */
00430                         if (ns_sects[ns_sect].number != ns_s_an)
00431                                 continue;
00432 
00433                         /* Now, we are in the answer section. */
00434                         if (ns_rr_type(rr) != spfrr->rr_type && ns_rr_type(rr) != ns_t_cname) {
00435                                 SPF_debugf("unexpected rr type: %d   expected: %d",
00436                                                 ns_rr_type(rr), rr_type);
00437                                 continue;
00438                         }
00439 
00440                         switch (ns_rr_type(rr)) {
00441                                 case ns_t_a:
00442                                         if (rdlen != 4) {
00443                                                 /* XXX Error handling. */
00444                                                 free(responsebuf);
00445                                                 return spfrr;
00446                                         }
00447                                         if (SPF_dns_rr_buf_realloc(spfrr, cnt,
00448                                                                 sizeof(spfrr->rr[cnt]->a)) != SPF_E_SUCCESS) {
00449                                                 free(responsebuf);
00450                                                 /* XXX Do we really want to return partial data
00451                                                  * on out of memory conditions? */
00452                                                 return spfrr;
00453                                         }
00454                                         memcpy(&spfrr->rr[cnt]->a, rdata, sizeof(spfrr->rr[cnt]->a));
00455                                         cnt++;
00456                                         break;
00457 
00458                                 case ns_t_aaaa:
00459                                         if (rdlen != 16) {
00460                                                 /* XXX Error handling. */
00461                                                 free(responsebuf);
00462                                                 return spfrr;
00463                                         }
00464                                         if (SPF_dns_rr_buf_realloc(spfrr, cnt,
00465                                                                 sizeof(spfrr->rr[cnt]->aaaa)) != SPF_E_SUCCESS) {
00466                                                 free(responsebuf);
00467                                                 /* XXX Do we really want to return partial data
00468                                                  * on out of memory conditions? */
00469                                                 return spfrr;
00470                                         }
00471                                         memcpy(&spfrr->rr[cnt]->aaaa, rdata, sizeof(spfrr->rr[cnt]->aaaa));
00472                                         cnt++;
00473                                         break;
00474 
00475                                 case ns_t_ns:
00476                                         break;
00477 
00478                                 case ns_t_cname:
00479                                         /* FIXME:  are CNAMEs always sent with the real RR? */
00480                                         break;
00481 
00482                                 case ns_t_mx:
00483                                         if (rdlen < NS_INT16SZ) {
00484                                                 /* XXX Error handling. */
00485                                                 free(responsebuf);
00486                                                 return spfrr;
00487                                         }
00488                                         err = ns_name_uncompress(responsebuf,
00489                                                                         responsebuf + responselen,
00490                                                                         rdata + NS_INT16SZ,
00491                                                                         name_buf, sizeof(name_buf));
00492                                         if (err < 0) {          /* 0 or -1 */
00493                                                 if (spf_dns_server->debug > 1)
00494                                                         SPF_debugf("ns_name_uncompress failed: err = %d  %s (%d)",
00495                                                                         err, strerror(errno), errno);
00496                                                 free(responsebuf);
00497                                                 /* XXX Do we really want to return partial data
00498                                                  * on parse error? */
00499                                                 return spfrr;
00500                                         }
00501 
00502                                         if (SPF_dns_rr_buf_realloc(spfrr, cnt,
00503                                                                         strlen(name_buf) + 1 ) != SPF_E_SUCCESS) {
00504                                                 free(responsebuf);
00505                                                 /* XXX Do we really want to return partial data
00506                                                  * on out of memory conditions? */
00507                                                 return spfrr;
00508                                         }
00509                                         strcpy(spfrr->rr[cnt]->mx, name_buf);
00510                                         cnt++;
00511                                         break;
00512 
00513                                 case ns_t_txt:
00514                                         if (rdlen > 1) {
00515                                                 u_char *src, *dst;
00516                                                 size_t len;
00517 
00518                                                 /* Just rdlen is enough because there is at least one
00519                                                  * length byte, which we do not copy. */
00520                                                 if (SPF_dns_rr_buf_realloc(spfrr, cnt, rdlen) != SPF_E_SUCCESS) {
00521                                                         free(responsebuf);
00522                                                         /* XXX Do we really want to return partial data
00523                                                          * on out of memory conditions? */
00524                                                         return spfrr;
00525                                                 }
00526 
00527                                                 dst = (u_char *)spfrr->rr[cnt]->txt;
00528                                                 src = (u_char *)rdata;
00529                                                 len = 0;
00530                                                 while (rdlen > 0) {
00531                                                         /* Consume one byte into a length. */
00532                                                         len = *src;
00533                                                         src++;
00534                                                         rdlen--;
00535 
00536                                                         /* Avoid buffer overrun if len is junk. */
00537                                                         /* XXX don't we rather want to flag this as error? */
00538                                                         if (len > rdlen)
00539                                                                 len = rdlen;
00540                                                         memcpy(dst, src, len);
00541 
00542                                                         /* Consume the data. */
00543                                                         src += len;
00544                                                         dst += len;
00545                                                         rdlen -= len;
00546                                                 }
00547                                                 *dst = '\0';
00548                                         }
00549                                         else {
00550                                                 if (SPF_dns_rr_buf_realloc(spfrr, cnt, 1) != SPF_E_SUCCESS) {
00551                                                         free(responsebuf);
00552                                                         /* XXX Do we really want to return partial data
00553                                                          * on out of memory conditions? */
00554                                                         return spfrr;
00555                                                 }
00556                                                 spfrr->rr[cnt]->txt[0] = '\0';
00557                                         }
00558 
00559                                         cnt++;
00560                                         break;
00561 
00562                                 case ns_t_ptr:
00563                                         err = ns_name_uncompress(responsebuf,
00564                                                                         responsebuf + responselen,
00565                                                                         rdata,
00566                                                                         name_buf, sizeof(name_buf));
00567                                         if (err < 0) {          /* 0 or -1 */
00568                                                 if (spf_dns_server->debug > 1)
00569                                                         SPF_debugf("ns_name_uncompress failed: err = %d  %s (%d)",
00570                                                                         err, strerror(errno), errno);
00571                                                 free(responsebuf);
00572                                                 /* XXX Do we really want to return partial data
00573                                                  * on parse error? */
00574                                                 return spfrr;
00575                                         }
00576 
00577                                         if (SPF_dns_rr_buf_realloc(spfrr, cnt,
00578                                                                         strlen(name_buf) + 1) != SPF_E_SUCCESS) {
00579                                                 free(responsebuf);
00580                                                 /* XXX Do we really want to return partial data
00581                                                  * on out of memory conditions? */
00582                                                 return spfrr;
00583                                         }
00584                                         strcpy(spfrr->rr[cnt]->ptr, name_buf);
00585                                         cnt++;
00586                                         break;
00587 
00588                                 default:
00589                                         break;
00590                         }
00591                 }
00592 
00593                 spfrr->num_rr = cnt;
00594         }
00595 
00596         if (spfrr->num_rr == 0)
00597                 spfrr->herrno = NO_DATA;
00598 
00599         free(responsebuf);
00600         return spfrr;
00601 }
00602 
00603 
00604 static void
00605 SPF_dns_resolv_free(SPF_dns_server_t *spf_dns_server)
00606 {
00607         SPF_ASSERT_NOTNULL(spf_dns_server);
00608 
00609 #if ! HAVE_DECL_RES_NINIT
00610         res_close();
00611 #endif
00612 
00613         free(spf_dns_server);
00614 }
00615 
00616 SPF_dns_server_t *
00617 SPF_dns_resolv_new(SPF_dns_server_t *layer_below,
00618                                 const char *name, int debug)
00619 {
00620         SPF_dns_server_t                *spf_dns_server;
00621 
00622 #if HAVE_DECL_RES_NINIT
00623         pthread_once(&res_state_control, SPF_dns_resolv_init_key);
00624 #else
00625         if (res_init() != 0) {
00626                 SPF_warning("Failed to call res_init()");
00627                 return NULL;
00628         }
00629 #endif
00630 
00631         spf_dns_server = malloc(sizeof(SPF_dns_server_t));
00632         if (spf_dns_server == NULL)
00633                 return NULL;
00634         memset(spf_dns_server, 0, sizeof(SPF_dns_server_t));
00635 
00636         if (name ==  NULL)
00637                 name = "resolv";
00638 
00639         spf_dns_server->destroy     = SPF_dns_resolv_free;
00640         spf_dns_server->lookup      = SPF_dns_resolv_lookup;
00641         spf_dns_server->get_spf     = NULL;
00642         spf_dns_server->get_exp     = NULL;
00643         spf_dns_server->add_cache   = NULL;
00644         spf_dns_server->layer_below = layer_below;
00645         spf_dns_server->name        = name;
00646         spf_dns_server->debug       = debug;
00647 
00648         return spf_dns_server;
00649 }
00650 
00651 #endif  /* _WIN32 */

Generated on Tue Nov 4 13:27:39 2008 for libspf2 by  doxygen 1.5.4