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
00367
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
00386 for (ns_sect = 0; ns_sect < num_ns_sect; ns_sect++) {
00387
00388
00389
00390
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) {
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
00410
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
00431 if (ns_sects[ns_sect].number != ns_s_an)
00432 continue;
00433
00434
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
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
00452
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
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
00469
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
00481 break;
00482
00483 case ns_t_mx:
00484 if (rdlen < NS_INT16SZ) {
00485
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) {
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
00499
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
00507
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
00521
00522 if (SPF_dns_rr_buf_realloc(spfrr, cnt, rdlen) != SPF_E_SUCCESS) {
00523 free(responsebuf);
00524
00525
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
00534 len = *src;
00535 src++;
00536 rdlen--;
00537
00538
00539
00540 if (len > rdlen)
00541 len = rdlen;
00542 memcpy(dst, src, len);
00543
00544
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
00555
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) {
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
00575
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
00583
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