libspf2 1.2.10
|
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 */