# HG changeset patch # User Carl Byington # Date 1528154706 25200 # Node ID f2bc221240e839c35be2370868879520ad8f7559 # Parent a0293ef794a7e0157c62997b28c71b75589943e2 add unsigned_black for enforcement of dmarc policy diff -r a0293ef794a7 -r f2bc221240e8 ChangeLog --- a/ChangeLog Tue Apr 10 13:00:55 2018 -0700 +++ b/ChangeLog Mon Jun 04 16:25:06 2018 -0700 @@ -1,3 +1,6 @@ +6.70 2018-06-04 + add unsigned_black for enforcement of dmarc policy. + 6.69 2018-04-10 fix spf mx:domain.tld token parsing. diff -r a0293ef794a7 -r f2bc221240e8 NEWS --- a/NEWS Tue Apr 10 13:00:55 2018 -0700 +++ b/NEWS Mon Jun 04 16:25:06 2018 -0700 @@ -1,3 +1,4 @@ +6.70 2018-06-04 add unsigned_black for enforcement of dmarc policy 6.69 2018-04-10 fix spf mx:domain.tld token parsing 6.68 2018-02-19 round spamassassin scores; check >= rather than > 6.67 2018-01-05 always call dcc code so we get log entries diff -r a0293ef794a7 -r f2bc221240e8 configure.in --- a/configure.in Tue Apr 10 13:00:55 2018 -0700 +++ b/configure.in Mon Jun 04 16:25:06 2018 -0700 @@ -1,6 +1,6 @@ AC_PREREQ(2.59) -AC_INIT(dnsbl,6.69,carl@five-ten-sg.com) +AC_INIT(dnsbl,6.70,carl@five-ten-sg.com) AC_CONFIG_SRCDIR([config.h.in]) AC_CONFIG_HEADER([config.h]) AC_CONFIG_MACRO_DIR([m4]) diff -r a0293ef794a7 -r f2bc221240e8 dnsbl.spec.in --- a/dnsbl.spec.in Tue Apr 10 13:00:55 2018 -0700 +++ b/dnsbl.spec.in Mon Jun 04 16:25:06 2018 -0700 @@ -155,6 +155,9 @@ %changelog +* Mon Jun 04 2018 Carl Byington - 6.70-1 +- add unsigned_black for enforcement of dmarc policy + * Tue Apr 10 2018 Carl Byington - 6.69-1 - fix spf mx:domain.tld token parsing diff -r a0293ef794a7 -r f2bc221240e8 src/context.cpp --- a/src/context.cpp Tue Apr 10 13:00:55 2018 -0700 +++ b/src/context.cpp Mon Jun 04 16:25:06 2018 -0700 @@ -73,6 +73,7 @@ const char *token_dkim_from; const char *token_signed_white; const char *token_signed_black; +const char *token_unsigned_black; const char *token_require_signed; const char *token_myhostname; @@ -1319,6 +1320,7 @@ DKIMP dk = find_dkim_from(from); if (dk) { const char *st = dk->action; + bool dmarc = false; for (string_set::iterator s=signers.begin(); s!=signers.end(); s++) { // signed by a white listed signer if ((st == token_signed_white) && in_signing_set(*s,dk->signer)) { @@ -1337,6 +1339,22 @@ msg = string(buf); return token_black; } + if ((st == token_unsigned_black) && in_signing_set(*s,dk->signer)) { + dmarc = true; + } + } + if (st == token_unsigned_black) { + // enforce dmarc + if (!dmarc) { + dmarc = resolve_spf(from, ntohl(priv->ip), priv); + } + if (!dmarc) { + // not signed and does not pass spf, reject it + char buf[maxlen]; + snprintf(buf, sizeof(buf), "Mail rejected - not dkim signed by %s", dk->signer); + msg = string(buf); + return token_black; + } } if (st == token_signed_white) { // not signed by a white listed signer, but maybe passes strong spf check @@ -2349,6 +2367,7 @@ token_dkim_from = register_string("dkim_from"); token_signed_white = register_string("signed_white"); token_signed_black = register_string("signed_black"); + token_unsigned_black = register_string("unsigned_black"); token_require_signed = register_string("require_signed"); if (gethostname(myhostname, HOST_NAME_MAX+1) != 0) { diff -r a0293ef794a7 -r f2bc221240e8 src/context.h --- a/src/context.h Tue Apr 10 13:00:55 2018 -0700 +++ b/src/context.h Mon Jun 04 16:25:06 2018 -0700 @@ -16,6 +16,7 @@ #endif enum status {oksofar, // not rejected yet + whitesofar, // probably whitelisted but require_signed or unsigned_black dkim requirements might change that white, // whitelisted black, // blacklisted reject}; // rejected by a dns list @@ -407,6 +408,7 @@ extern const char *token_dkim_from; extern const char *token_signed_white; extern const char *token_signed_black; +extern const char *token_unsigned_black; extern const char *token_require_signed; extern const char *token_myhostname; diff -r a0293ef794a7 -r f2bc221240e8 src/dnsbl.cpp --- a/src/dnsbl.cpp Tue Apr 10 13:00:55 2018 -0700 +++ b/src/dnsbl.cpp Mon Jun 04 16:25:06 2018 -0700 @@ -518,7 +518,7 @@ if (debug_syslog > 2) { char tmp[maxlen]; snprintf(tmp, sizeof(tmp), "found %s on %s", hostname, priv.uribl_suffix); - my_syslog(tmp); + my_syslog(&priv, tmp); } found = register_string(hosts, hostname); return true; @@ -1424,15 +1424,19 @@ DKIMP dk = con.find_dkim_from(domain+1); if (dk && (dk->action == token_require_signed)) { my_syslog(&priv, "dkim require_signed overrides envelope from whitelist"); - st = oksofar; + st = whitesofar; + } + else if (dk && (dk->action == token_unsigned_black)) { + my_syslog(&priv, "dkim unsigned_black overrides envelope from whitelist"); + st = whitesofar; } else st = white; } else st = white; // might be <>, envelope from has no @ } - if (st == oksofar) { - // check the dns based lists, whitelist first + if ((st == oksofar) || (st == whitesofar)) { + // check the dns based whitelists DNSWLP acceptlist = NULL; // list that caused the whitelisting if (check_dnswl(priv, con.get_dnswl_list(), acceptlist)) { st = white; @@ -1442,7 +1446,11 @@ my_syslog(&priv, msg); } } - else if (check_dnsbl(priv, con.get_dnsbl_list(), rejectlist)) { + } + + if (st == oksofar) { + // check the dns based blacklists + if (check_dnsbl(priv, con.get_dnsbl_list(), rejectlist)) { // reject the recipient based on some dnsbl char adr[sizeof "255.255.255.255 "]; adr[0] = '\0'; @@ -1452,9 +1460,6 @@ smfi_setreply(ctx, (char*)"550", (char*)"5.7.1", buf); return SMFIS_REJECT; } - } - - if (st == oksofar) { // check forged rdns if (con.get_requirerdns() && (!priv.client_dns_name || priv.client_dns_forged)) { // reject the recipient based on forged reverse dns @@ -1535,7 +1540,7 @@ // accept the recipient if (!con.get_content_filtering()) st = white; - if (st == oksofar) { + if ((st == oksofar) || (st == whitesofar)) { // remember first content filtering context if (con.get_content_filtering()) { if (!priv.content_context) priv.content_context = &con; @@ -1544,6 +1549,7 @@ return SMFIS_TEMPFAIL; } priv.need_content_filter(con); + if (st == oksofar) { char bu[maxlen]; bool uri = false; // content filtering implies also checking helo name on uribl (if enabled) @@ -1568,6 +1574,7 @@ return SMFIS_REJECT; } } + } // remember the non-whites register_string(priv.env_to, rcptaddr, &con); priv.only_whites = false; diff -r a0293ef794a7 -r f2bc221240e8 xml/dnsbl.in --- a/xml/dnsbl.in Tue Apr 10 13:00:55 2018 -0700 +++ b/xml/dnsbl.in Mon Jun 04 16:25:06 2018 -0700 @@ -25,7 +25,7 @@ - 2017-11-03 + 2018-06-04 Carl Byington @@ -393,7 +393,7 @@ If the answer is white, the mail is not from localhost, and the envelope from domain name is listed in the current (or parents) filtering contexts dkim_from with - "required_signed", we downgrade this white answer to unknown. + "required_signed" or "unsigned_black", we downgrade this white answer to unknown. If the answer is still white, mail to this recipient is accepted and the dns lists are not checked. @@ -474,14 +474,14 @@ If the header from domain maps to required_signed then: - If any of the message signers are in that list, the message is accepted. - If the source ip address passes a strong spf check for the header from + If any of the message signers are in that list, or if + the source ip address passes a strong spf check for the header from domain, the message is accepted. Otherwise, the message is rejected. If the header from domain maps to signed_white then: - If any of the message signers are in that list, the message is accepted. - If the source ip address passes a strong spf check for the header from + If any of the message signers are in that list, or if + the source ip address passes a strong spf check for the header from domain, the message is accepted. Otherwise, processing continues. @@ -490,6 +490,12 @@ Otherwise, processing continues. + If the header from domain maps to unsigned_black then: + If any of the message signers are in that list, or if + the source ip address passes a strong spf check for the header from + domain, processing continues. Otherwise, the message is rejected. + + If any of the message signers are blacklisted, the message is rejected. @@ -779,7 +785,7 @@ - 2017-11-03 + 2018-06-04 Carl Byington @@ -859,7 +865,7 @@ DKIMSIGNER = "dkim_signer" "{" {SIGNING_DOMAIN DEF [";"]}+ "}" DKIMFROM = "dkim_from" "{" {HEADER_FROM_DOMAIN DKIMVALUE SIGNERS [";"]}+ "}" -DKIMVALUE = "signed_white" | "signed_black" | "require_signed" +DKIMVALUE = "signed_white" | "signed_black" | "require_signed" | "unsigned_black" SIGNERS = quoted comma separated SIGNING_DOMAINs no whitespace ENV-TO = "env_to" "{" {(TO-ADDR | DCC-TO)}+ "}"