Mercurial > dnsbl
comparison src/dnsbl.cpp @ 381:879a470c6ac3
fetch spf txt records for required dkim signers
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Tue, 28 Feb 2017 17:02:07 -0800 |
parents | e42923f8f3fd |
children | c378e9d03f37 |
comparison
equal
deleted
inserted
replaced
380:0495e767bfb7 | 381:879a470c6ac3 |
---|---|
300 return sock; | 300 return sock; |
301 } | 301 } |
302 | 302 |
303 | 303 |
304 //////////////////////////////////////////////// | 304 //////////////////////////////////////////////// |
305 // ask a dns question and get an A record answer in network byte order | 305 // Ask a dns question and get an A record answer in network byte order. |
306 // we don't try very hard, just using the default resolver retry settings. | 306 // We don't try very hard, just using the default resolver retry settings. |
307 // If we cannot get an answer, we just accept the mail. | 307 // If we cannot get an answer, we just accept the mail. |
308 // If the qtype is ns_t_txt, the answer is placed in txt_answer which | |
309 // must be non-null, and the return value can be ignored. | |
310 // If the qtype is ns_t_a, the ip address is returned in network byte order. | |
308 // | 311 // |
309 // | 312 uint32_t dns_interface(mlfiPriv &priv, const char *question, int qtype, bool maybe_ip = false, ns_map *nameservers = NULL, char *txt_answer = NULL, size_t txt_size = 0); |
310 uint32_t dns_interface(mlfiPriv &priv, const char *question, bool maybe_ip, ns_map *nameservers); | 313 uint32_t dns_interface(mlfiPriv &priv, const char *question, int qtype, bool maybe_ip, ns_map *nameservers, char *txt_answer, size_t txt_size) { |
311 uint32_t dns_interface(mlfiPriv &priv, const char *question, bool maybe_ip, ns_map *nameservers) { | |
312 // tell sendmail we are still working | 314 // tell sendmail we are still working |
313 #if _FFR_SMFI_PROGRESS | 315 #if _FFR_SMFI_PROGRESS |
314 if (priv.eom) smfi_progress(priv.ctx); | 316 if (priv.eom) smfi_progress(priv.ctx); |
315 #endif | 317 #endif |
316 | 318 |
317 // this part can be done without locking the resolver mutex. Each | 319 // this part can be done without locking the resolver mutex. Each |
318 // milter thread is talking over its own socket to a separate resolver | 320 // milter thread is talking over its own socket to a separate resolver |
319 // process, which does the actual dns resolution. | 321 // process, which does the actual dns resolution. |
320 if (priv.err) return 0; // cannot ask more questions on this socket. | 322 if (priv.err) return 0; // cannot ask more questions on this socket. |
321 if (maybe_ip) { | 323 if (maybe_ip && (qtype == ns_t_a)) { |
322 // might be a bare ip address, try this first to avoid dns lookups that may not be needed | 324 // might be a bare ip address, try this first to avoid dns lookups that may not be needed |
323 in_addr ip; | 325 in_addr ip; |
324 if (inet_aton(question, &ip)) { | 326 if (inet_aton(question, &ip)) { |
325 return ip.s_addr; | 327 return ip.s_addr; |
326 } | 328 } |
327 } | 329 } |
330 int8_t qt = qtype; | |
331 priv.my_write((const char *)&qt, 1);// write the query type | |
328 size_t n = strlen(question); | 332 size_t n = strlen(question); |
329 if (question[n-1] == '.') { | 333 if (question[n-1] == '.') { |
330 priv.my_write(question, n+1); // write the question including the null terminator | 334 priv.my_write(question, n+1); // write the question including the null terminator |
331 } | 335 } |
332 else { | 336 else { |
333 priv.my_write(question, n); // write the question | 337 priv.my_write(question, n); // write the question |
334 priv.my_write(".", 2); // and the fully qualified . terminator and null string terminator | 338 priv.my_write(".", 2); // and the fully qualified . terminator and null string terminator |
335 } | 339 } |
340 | |
336 glommer glom; | 341 glommer glom; |
337 char *buf = (char *)&glom; | 342 char *buf = (char *)&glom; |
338 priv.my_read(buf, sizeof(glom.length)); | 343 priv.my_read(buf, sizeof(glom.length)); |
339 buf += sizeof(glom.length); | 344 buf += sizeof(glom.length); |
340 #ifdef RESOLVER_DEBUG | 345 #ifdef RESOLVER_DEBUG |
403 } | 408 } |
404 } | 409 } |
405 } | 410 } |
406 } | 411 } |
407 int rrnum = 0; | 412 int rrnum = 0; |
408 while (ns_parserr(&handle, ns_s_an, rrnum++, &rr) == 0) { | 413 if (qtype == ns_t_a) { |
409 if (ns_rr_type(rr) == ns_t_a) { | 414 while (ns_parserr(&handle, ns_s_an, rrnum++, &rr) == 0) { |
410 uint32_t address; | 415 if (ns_rr_type(rr) == qtype) { |
411 memcpy(&address, ns_rr_rdata(rr), sizeof(address)); | 416 uint32_t address; |
412 ret_address = address; | 417 memcpy(&address, ns_rr_rdata(rr), sizeof(address)); |
418 ret_address = address; | |
419 } | |
420 } | |
421 } | |
422 if ((qtype == ns_t_txt) && (txt_answer) && (txt_size > 5)) { | |
423 txt_size--; // allow room for terminating null; | |
424 txt_answer[0] = '\0'; // return null string if there are no answers | |
425 while (ns_parserr(&handle, ns_s_an, rrnum++, &rr) == 0) { | |
426 size_t offset = 0; | |
427 if (ns_rr_type(rr) == qtype) { | |
428 size_t rdlen = ns_rr_rdlen(rr); | |
429 const unsigned char *rdata = ns_rr_rdata(rr); | |
430 while ((offset < txt_size) && rdlen) { | |
431 size_t slen = size_t(*(rdata++)); | |
432 rdlen--; | |
433 size_t m = min(slen, rdlen); | |
434 m = min(m, txt_size-offset); | |
435 memcpy(txt_answer+offset, rdata, m); | |
436 offset += m; | |
437 rdata += m; | |
438 rdlen -= m; | |
439 } | |
440 } | |
441 txt_answer[offset] = '\0'; // trailing null | |
442 if (strcasecmp(txt_answer, "v=spf1 ") == 0) break; | |
413 } | 443 } |
414 } | 444 } |
415 } | 445 } |
416 pthread_mutex_unlock(&resolve_mutex); | 446 pthread_mutex_unlock(&resolve_mutex); |
417 #ifdef RESOLVER_DEBUG | 447 #ifdef RESOLVER_DEBUG |
434 // | 464 // |
435 bool uriblookup(mlfiPriv &priv, string_set &hosts, const char *hostname, const char *&found) ; | 465 bool uriblookup(mlfiPriv &priv, string_set &hosts, const char *hostname, const char *&found) ; |
436 bool uriblookup(mlfiPriv &priv, string_set &hosts, const char *hostname, const char *&found) { | 466 bool uriblookup(mlfiPriv &priv, string_set &hosts, const char *hostname, const char *&found) { |
437 char buf[maxlen]; | 467 char buf[maxlen]; |
438 snprintf(buf, sizeof(buf), "%s.%s.", hostname, priv.uribl_suffix); | 468 snprintf(buf, sizeof(buf), "%s.%s.", hostname, priv.uribl_suffix); |
439 uint32_t ip = ntohl(dns_interface(priv, buf, false, NULL)); | 469 uint32_t ip = ntohl(dns_interface(priv, buf, ns_t_a)); |
440 if (ip and (ip != 0x7f000000)) { | 470 if (ip and (ip != 0x7f000000)) { |
441 if (debug_syslog > 2) { | 471 if (debug_syslog > 2) { |
442 char tmp[maxlen]; | 472 char tmp[maxlen]; |
443 snprintf(tmp, sizeof(tmp), "found %s on %s", hostname, priv.uribl_suffix); | 473 snprintf(tmp, sizeof(tmp), "found %s on %s", hostname, priv.uribl_suffix); |
444 my_syslog(tmp); | 474 my_syslog(tmp); |
719 } | 749 } |
720 return rs; | 750 return rs; |
721 } | 751 } |
722 | 752 |
723 const char *mlfiPriv::check_uribl_signers() { | 753 const char *mlfiPriv::check_uribl_signers() { |
724 const char *st; | |
725 if (uribl_suffix) { | 754 if (uribl_suffix) { |
726 for (string_set::iterator s=dkim_signers.begin(); s!=dkim_signers.end(); s++) { | 755 for (string_set::iterator s=dkim_signers.begin(); s!=dkim_signers.end(); s++) { |
727 if (check_uribl(*this, hosts_uribl, *s, host_uribl)) return host_uribl; | 756 if (check_uribl(*this, hosts_uribl, *s, host_uribl)) return host_uribl; |
728 } | 757 } |
729 } | 758 } |
851 | 880 |
852 // find the answer | 881 // find the answer |
853 #ifdef NS_PACKETSZ | 882 #ifdef NS_PACKETSZ |
854 #ifdef RESOLVER_DEBUG | 883 #ifdef RESOLVER_DEBUG |
855 char text[1000]; | 884 char text[1000]; |
856 snprintf(text, sizeof(text), "process_resolver_requests() has a question %s", question); | 885 snprintf(text, sizeof(text), "process_resolver_requests() has a question %s qtype %d", question+1, int8_t(question[0])); |
857 my_syslog(text); | 886 my_syslog(text); |
858 #endif | 887 #endif |
859 int res_result = res_search(question, ns_c_in, ns_t_a, glom.answer, sizeof(glom.answer)); | 888 int res_result = res_search(question+1, ns_c_in, int8_t(question[0]), glom.answer, sizeof(glom.answer)); |
860 if (res_result < 0) glom.length = 0; // represent all errors as zero length answers | 889 if (res_result < 0) glom.length = 0; // represent all errors as zero length answers |
861 else glom.length = (size_t)res_result; | 890 else glom.length = (size_t)res_result; |
862 #else | 891 #else |
863 glom.length = sizeof(glom.answer); | 892 glom.length = sizeof(glom.answer); |
864 glom.answer = 0; | 893 glom.answer = 0; |
865 struct hostent *host = gethostbyname(question); | 894 struct hostent *host = gethostbyname(question+1); |
866 if (host && (host->h_addrtype == AF_INET)) { | 895 if (host && (host->h_addrtype == AF_INET)) { |
867 memcpy(&glom.answer, host->h_addr, sizeof(glom.answer)); | 896 memcpy(&glom.answer, host->h_addr, sizeof(glom.answer)); |
868 } | 897 } |
869 #endif | 898 #endif |
870 | 899 |
911 #else | 940 #else |
912 char question[1000]; | 941 char question[1000]; |
913 #endif | 942 #endif |
914 snprintf(question, sizeof(question), "%u.%u.%u.%u.%s.", src[3], src[2], src[1], src[0], suffix); | 943 snprintf(question, sizeof(question), "%u.%u.%u.%u.%s.", src[3], src[2], src[1], src[0], suffix); |
915 // ask the question, if we get an A record it implies a blacklisted ip address | 944 // ask the question, if we get an A record it implies a blacklisted ip address |
916 return dns_interface(priv, question, false, NULL); | 945 return dns_interface(priv, question, ns_t_a); |
917 } | 946 } |
918 | 947 |
919 | 948 |
920 //////////////////////////////////////////////// | 949 //////////////////////////////////////////////// |
921 // check a single dnsbl | 950 // check a single dnsbl |
1026 } | 1055 } |
1027 continue; | 1056 continue; |
1028 } | 1057 } |
1029 } | 1058 } |
1030 count++; | 1059 count++; |
1031 ip = dns_interface(priv, host, true, &nameservers); | 1060 ip = dns_interface(priv, host, ns_t_a, true, &nameservers); |
1032 if (debug_syslog > 2) { | 1061 if (debug_syslog > 2) { |
1033 char buf[maxlen]; | 1062 char buf[maxlen]; |
1034 if (ip) { | 1063 if (ip) { |
1035 char adr[sizeof "255.255.255.255 "]; | 1064 char adr[sizeof "255.255.255.255 "]; |
1036 adr[0] = '\0'; | 1065 adr[0] = '\0'; |
1064 for (ns_mapper::iterator i=nameservers.ns_ip.begin(); i!=nameservers.ns_ip.end(); i++) { | 1093 for (ns_mapper::iterator i=nameservers.ns_ip.begin(); i!=nameservers.ns_ip.end(); i++) { |
1065 count++; | 1094 count++; |
1066 if ((count > limit) && (limit > 0)) return false; // too many name servers to check them all | 1095 if ((count > limit) && (limit > 0)) return false; // too many name servers to check them all |
1067 host = (*i).first; // a transient reference that needs to be replaced before we return it | 1096 host = (*i).first; // a transient reference that needs to be replaced before we return it |
1068 ip = (*i).second; | 1097 ip = (*i).second; |
1069 if (!ip) ip = dns_interface(priv, host, false, NULL); | 1098 if (!ip) ip = dns_interface(priv, host, ns_t_a); |
1070 if (debug_syslog > 2) { | 1099 if (debug_syslog > 2) { |
1071 char buf[maxlen]; | 1100 char buf[maxlen]; |
1072 if (ip) { | 1101 if (ip) { |
1073 char adr[sizeof "255.255.255.255 "]; | 1102 char adr[sizeof "255.255.255.255 "]; |
1074 adr[0] = '\0'; | 1103 adr[0] = '\0'; |
1653 } | 1682 } |
1654 | 1683 |
1655 for (context_map::iterator i=priv.env_to.begin(); i!=priv.env_to.end(); i++) { | 1684 for (context_map::iterator i=priv.env_to.begin(); i!=priv.env_to.end(); i++) { |
1656 const char *rcpt = (*i).first; | 1685 const char *rcpt = (*i).first; |
1657 CONTEXT &con = *((*i).second); | 1686 CONTEXT &con = *((*i).second); |
1658 const char *st = con.acceptable_content(*priv.memory, score, bulk, priv.queueid, priv.dkim_signers, priv.fromaddr, msg); | 1687 const char *st = con.acceptable_content(*priv.memory, score, bulk, priv.queueid, priv.dkim_signers, priv.fromaddr, &priv, msg); |
1659 if (st == token_black) { | 1688 if (st == token_black) { |
1660 // bad html tags or excessive hosts or | 1689 // bad html tags or excessive hosts or |
1661 // high spam assassin score or dcc bulk threshold exceedeed | 1690 // high spam assassin score or dcc bulk threshold exceedeed |
1662 // or signed by a dkim signer that we don't like | 1691 // or signed by a dkim signer that we don't like |
1663 // or header from requires dkim signer that is missing | 1692 // or header from requires dkim signer that is missing |