Mercurial > dnsbl
diff 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 |
line wrap: on
line diff
--- a/src/dnsbl.cpp Mon Feb 20 08:43:41 2017 -0800 +++ b/src/dnsbl.cpp Tue Feb 28 17:02:07 2017 -0800 @@ -302,13 +302,15 @@ //////////////////////////////////////////////// -// ask a dns question and get an A record answer in network byte order -// we don't try very hard, just using the default resolver retry settings. +// Ask a dns question and get an A record answer in network byte order. +// We don't try very hard, just using the default resolver retry settings. // If we cannot get an answer, we just accept the mail. +// If the qtype is ns_t_txt, the answer is placed in txt_answer which +// must be non-null, and the return value can be ignored. +// If the qtype is ns_t_a, the ip address is returned in network byte order. // -// -uint32_t dns_interface(mlfiPriv &priv, const char *question, bool maybe_ip, ns_map *nameservers); -uint32_t dns_interface(mlfiPriv &priv, const char *question, bool maybe_ip, ns_map *nameservers) { +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); +uint32_t dns_interface(mlfiPriv &priv, const char *question, int qtype, bool maybe_ip, ns_map *nameservers, char *txt_answer, size_t txt_size) { // tell sendmail we are still working #if _FFR_SMFI_PROGRESS if (priv.eom) smfi_progress(priv.ctx); @@ -318,13 +320,15 @@ // milter thread is talking over its own socket to a separate resolver // process, which does the actual dns resolution. if (priv.err) return 0; // cannot ask more questions on this socket. - if (maybe_ip) { + if (maybe_ip && (qtype == ns_t_a)) { // might be a bare ip address, try this first to avoid dns lookups that may not be needed in_addr ip; if (inet_aton(question, &ip)) { return ip.s_addr; } } + int8_t qt = qtype; + priv.my_write((const char *)&qt, 1);// write the query type size_t n = strlen(question); if (question[n-1] == '.') { priv.my_write(question, n+1); // write the question including the null terminator @@ -405,14 +409,39 @@ } } int rrnum = 0; + if (qtype == ns_t_a) { while (ns_parserr(&handle, ns_s_an, rrnum++, &rr) == 0) { - if (ns_rr_type(rr) == ns_t_a) { + if (ns_rr_type(rr) == qtype) { uint32_t address; memcpy(&address, ns_rr_rdata(rr), sizeof(address)); ret_address = address; } } } + if ((qtype == ns_t_txt) && (txt_answer) && (txt_size > 5)) { + txt_size--; // allow room for terminating null; + txt_answer[0] = '\0'; // return null string if there are no answers + while (ns_parserr(&handle, ns_s_an, rrnum++, &rr) == 0) { + size_t offset = 0; + if (ns_rr_type(rr) == qtype) { + size_t rdlen = ns_rr_rdlen(rr); + const unsigned char *rdata = ns_rr_rdata(rr); + while ((offset < txt_size) && rdlen) { + size_t slen = size_t(*(rdata++)); + rdlen--; + size_t m = min(slen, rdlen); + m = min(m, txt_size-offset); + memcpy(txt_answer+offset, rdata, m); + offset += m; + rdata += m; + rdlen -= m; + } + } + txt_answer[offset] = '\0'; // trailing null + if (strcasecmp(txt_answer, "v=spf1 ") == 0) break; + } + } + } pthread_mutex_unlock(&resolve_mutex); #ifdef RESOLVER_DEBUG snprintf(text, sizeof(text), "dns_interface() found ip %d", ret_address); @@ -436,7 +465,7 @@ bool uriblookup(mlfiPriv &priv, string_set &hosts, const char *hostname, const char *&found) { char buf[maxlen]; snprintf(buf, sizeof(buf), "%s.%s.", hostname, priv.uribl_suffix); - uint32_t ip = ntohl(dns_interface(priv, buf, false, NULL)); + uint32_t ip = ntohl(dns_interface(priv, buf, ns_t_a)); if (ip and (ip != 0x7f000000)) { if (debug_syslog > 2) { char tmp[maxlen]; @@ -721,7 +750,6 @@ } const char *mlfiPriv::check_uribl_signers() { - const char *st; if (uribl_suffix) { for (string_set::iterator s=dkim_signers.begin(); s!=dkim_signers.end(); s++) { if (check_uribl(*this, hosts_uribl, *s, host_uribl)) return host_uribl; @@ -853,16 +881,16 @@ #ifdef NS_PACKETSZ #ifdef RESOLVER_DEBUG char text[1000]; - snprintf(text, sizeof(text), "process_resolver_requests() has a question %s", question); + snprintf(text, sizeof(text), "process_resolver_requests() has a question %s qtype %d", question+1, int8_t(question[0])); my_syslog(text); #endif - int res_result = res_search(question, ns_c_in, ns_t_a, glom.answer, sizeof(glom.answer)); + int res_result = res_search(question+1, ns_c_in, int8_t(question[0]), glom.answer, sizeof(glom.answer)); if (res_result < 0) glom.length = 0; // represent all errors as zero length answers else glom.length = (size_t)res_result; #else glom.length = sizeof(glom.answer); glom.answer = 0; - struct hostent *host = gethostbyname(question); + struct hostent *host = gethostbyname(question+1); if (host && (host->h_addrtype == AF_INET)) { memcpy(&glom.answer, host->h_addr, sizeof(glom.answer)); } @@ -913,7 +941,7 @@ #endif snprintf(question, sizeof(question), "%u.%u.%u.%u.%s.", src[3], src[2], src[1], src[0], suffix); // ask the question, if we get an A record it implies a blacklisted ip address - return dns_interface(priv, question, false, NULL); + return dns_interface(priv, question, ns_t_a); } @@ -1028,7 +1056,7 @@ } } count++; - ip = dns_interface(priv, host, true, &nameservers); + ip = dns_interface(priv, host, ns_t_a, true, &nameservers); if (debug_syslog > 2) { char buf[maxlen]; if (ip) { @@ -1066,7 +1094,7 @@ if ((count > limit) && (limit > 0)) return false; // too many name servers to check them all host = (*i).first; // a transient reference that needs to be replaced before we return it ip = (*i).second; - if (!ip) ip = dns_interface(priv, host, false, NULL); + if (!ip) ip = dns_interface(priv, host, ns_t_a); if (debug_syslog > 2) { char buf[maxlen]; if (ip) { @@ -1655,7 +1683,7 @@ for (context_map::iterator i=priv.env_to.begin(); i!=priv.env_to.end(); i++) { const char *rcpt = (*i).first; CONTEXT &con = *((*i).second); - const char *st = con.acceptable_content(*priv.memory, score, bulk, priv.queueid, priv.dkim_signers, priv.fromaddr, msg); + const char *st = con.acceptable_content(*priv.memory, score, bulk, priv.queueid, priv.dkim_signers, priv.fromaddr, &priv, msg); if (st == token_black) { // bad html tags or excessive hosts or // high spam assassin score or dcc bulk threshold exceedeed