00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
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>
00039 # include <stdlib.h>
00040 #endif
00041
00042 #ifdef HAVE_STRING_H
00043 # include <string.h>
00044 #else
00045 # ifdef HAVE_STRINGS_H
00046 # include <strings.h>
00047 # endif
00048 #endif
00049
00050 #ifdef HAVE_RESOLV_H
00051 # include <resolv.h>
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)
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 )
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)
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
00189
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)
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
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
00257
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;
00275 memset(responsebuf, 0, responselen);
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293 for (;;) {
00294 int dns_len;
00295
00296 #if HAVE_DECL_RES_NINIT
00297
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
00307
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
00324 responselen = dns_len + (dns_len >> 1);
00325 #if 0
00326
00327 if (responselen > 1048576) {
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
00342 responselen = dns_len;
00343 break;
00344 }
00345 }
00346
00347
00348
00349
00350
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) {
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
00386
00387
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) {
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
00425 if (ns_sects[ns_sect].number != ns_s_an)
00426 continue;
00427
00428
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
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) {
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
00511
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
00523 len = *src;
00524 src++;
00525 rdlen--;
00526
00527
00528
00529 if (len > rdlen)
00530 len = rdlen;
00531 memcpy(dst, src, len);
00532
00533
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) {
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