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_txt:
00183 if (rdlen < 1) {
00184 SPF_debugf("TXT: rdlen too short: %lu", (unsigned long)rdlen);
00185 break;
00186 }
00187
00188
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)
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
00256
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;
00274 memset(responsebuf, 0, responselen);
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292 for (;;) {
00293 int dns_len;
00294
00295 #if HAVE_DECL_RES_NINIT
00296
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
00306
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
00323 responselen = dns_len + (dns_len >> 1);
00324 #if 0
00325
00326 if (responselen > 1048576) {
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
00341 responselen = dns_len;
00342 break;
00343 }
00344 }
00345
00346
00347
00348
00349
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) {
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
00366
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
00385 for (ns_sect = 0; ns_sect < num_ns_sect; ns_sect++) {
00386
00387
00388
00389
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) {
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
00409
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
00430 if (ns_sects[ns_sect].number != ns_s_an)
00431 continue;
00432
00433
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
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
00451
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
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
00468
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
00480 break;
00481
00482 case ns_t_mx:
00483 if (rdlen < NS_INT16SZ) {
00484
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) {
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
00498
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
00506
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
00519
00520 if (SPF_dns_rr_buf_realloc(spfrr, cnt, rdlen) != SPF_E_SUCCESS) {
00521 free(responsebuf);
00522
00523
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
00532 len = *src;
00533 src++;
00534 rdlen--;
00535
00536
00537
00538 if (len > rdlen)
00539 len = rdlen;
00540 memcpy(dst, src, len);
00541
00542
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
00553
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) {
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
00573
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
00581
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