Mercurial > dnsbl
comparison src/dnsbl.cpp @ 350:f4ca91f49cb6
send the original mail from address to the verify server, not the srs/pvrs unwrapped version; recognize our own dkim signatures
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Mon, 26 Dec 2016 09:31:57 -0800 |
parents | 8fe6d5120771 |
children | f5a6740cabee |
comparison
equal
deleted
inserted
replaced
349:3c39051699bd | 350:f4ca91f49cb6 |
---|---|
96 CONFIG *config = NULL; // protected by the config_mutex | 96 CONFIG *config = NULL; // protected by the config_mutex |
97 int generation = 0; // protected by the config_mutex | 97 int generation = 0; // protected by the config_mutex |
98 const int maxlen = 1000; // used for snprintf buffers | 98 const int maxlen = 1000; // used for snprintf buffers |
99 regex_t srs_pattern; // used to detect srs coding in mail addresses | 99 regex_t srs_pattern; // used to detect srs coding in mail addresses |
100 regex_t prvs_pattern; // used to detect prvs coding in mail addresses | 100 regex_t prvs_pattern; // used to detect prvs coding in mail addresses |
101 regex_t dkim_pattern; // used to detect dkim signatures in authentication header generated by the upstream opendkim milter | 101 regex_t dkim_r_pattern; // used to detect dkim signatures authenticated by the upstream opendkim milter |
102 regex_t dkim_s_pattern; // used to detect dkim signatures generated by the upstream opendkim milter | |
102 regex_t from_pattern; // used to extract the senders mail domain from the body from: header | 103 regex_t from_pattern; // used to extract the senders mail domain from the body from: header |
103 | 104 |
104 pthread_mutex_t config_mutex; | 105 pthread_mutex_t config_mutex; |
105 pthread_mutex_t syslog_mutex; | 106 pthread_mutex_t syslog_mutex; |
106 pthread_mutex_t resolve_mutex; | 107 pthread_mutex_t resolve_mutex; |
520 ctx = NULL; | 521 ctx = NULL; |
521 eom = false; | 522 eom = false; |
522 ip = 0; | 523 ip = 0; |
523 helo = NULL; | 524 helo = NULL; |
524 mailaddr = NULL; | 525 mailaddr = NULL; |
526 origaddr = NULL; | |
525 fromaddr = NULL; | 527 fromaddr = NULL; |
526 header_count = 0; | 528 header_count = 0; |
527 dkim_ok = true; | 529 dkim_ok = true; |
528 queueid = NULL; | 530 queueid = NULL; |
529 authenticated = NULL; | 531 authenticated = NULL; |
570 if (loto) free((void*)loto); | 572 if (loto) free((void*)loto); |
571 delete dwp; | 573 delete dwp; |
572 delayer.pop_front(); | 574 delayer.pop_front(); |
573 } | 575 } |
574 if (mailaddr) free((void*)mailaddr); | 576 if (mailaddr) free((void*)mailaddr); |
577 if (origaddr) free((void*)origaddr); | |
575 if (fromaddr) free((void*)fromaddr); | 578 if (fromaddr) free((void*)fromaddr); |
576 if (queueid) free((void*)queueid); | 579 if (queueid) free((void*)queueid); |
577 if (authenticated) free((void*)authenticated); | 580 if (authenticated) free((void*)authenticated); |
578 if (client_name) free((void*)client_name); | 581 if (client_name) free((void*)client_name); |
579 if (client_dns_name) free((void*)client_dns_name); | 582 if (client_dns_name) free((void*)client_dns_name); |
587 if (dccifd) delete dccifd; | 590 if (dccifd) delete dccifd; |
588 if (!final) { | 591 if (!final) { |
589 ctx = NULL; | 592 ctx = NULL; |
590 eom = false; | 593 eom = false; |
591 mailaddr = NULL; | 594 mailaddr = NULL; |
595 origaddr = NULL; | |
592 fromaddr = NULL; | 596 fromaddr = NULL; |
593 header_count = 0; | 597 header_count = 0; |
594 dkim_ok = true; | 598 dkim_ok = true; |
595 queueid = NULL; | 599 queueid = NULL; |
596 authenticated = NULL; | 600 authenticated = NULL; |
714 } | 718 } |
715 } | 719 } |
716 return rs; | 720 return rs; |
717 } | 721 } |
718 | 722 |
719 void mlfiPriv::need_content_filter(const char *rcpt, CONTEXT &con) { | 723 void mlfiPriv::need_content_filter(CONTEXT &con) { |
720 if (!memory) { | 724 if (!memory) { |
721 // first recipient that needs content filtering sets | 725 // first recipient that needs content filtering sets |
722 // some of the content filtering parameters | 726 // some of the content filtering parameters |
723 memory = new recorder(this, con.get_html_tags(), con.get_content_tlds(), con.get_content_tldwilds(), con.get_content_tldnots()); | 727 memory = new recorder(this, con.get_html_tags(), con.get_content_tlds(), con.get_content_tldwilds(), con.get_content_tldnots()); |
724 scanner = new url_scanner(memory); | 728 scanner = new url_scanner(memory); |
1184 | 1188 |
1185 sfsistat mlfi_envfrom(SMFICTX *ctx, char **from) | 1189 sfsistat mlfi_envfrom(SMFICTX *ctx, char **from) |
1186 { | 1190 { |
1187 mlfiPriv &priv = *MLFIPRIV; | 1191 mlfiPriv &priv = *MLFIPRIV; |
1188 CONFIG &dc = *priv.pc; | 1192 CONFIG &dc = *priv.pc; |
1193 priv.origaddr = to_lower_string(from[0], false); | |
1189 priv.mailaddr = to_lower_string(from[0]); | 1194 priv.mailaddr = to_lower_string(from[0]); |
1190 priv.queueid = strdup(smfi_getsymval(ctx, (char*)"i")); | 1195 priv.queueid = strdup(smfi_getsymval(ctx, (char*)"i")); |
1191 priv.authenticated = smfi_getsymval(ctx, (char*)"{auth_authen}"); | 1196 priv.authenticated = smfi_getsymval(ctx, (char*)"{auth_authen}"); |
1192 priv.client_name = smfi_getsymval(ctx, (char*)"_"); | 1197 priv.client_name = smfi_getsymval(ctx, (char*)"_"); |
1193 if (!priv.helo) priv.helo = strdup("unknown"); | 1198 if (!priv.helo) priv.helo = strdup("unknown"); |
1300 else if ((fromvalue == token_white) && (local_source || from_root)) { | 1305 else if ((fromvalue == token_white) && (local_source || from_root)) { |
1301 st = white; | 1306 st = white; |
1302 } | 1307 } |
1303 else if ((fromvalue == token_white) && !self) { | 1308 else if ((fromvalue == token_white) && !self) { |
1304 // whitelisting based on envelope from value, but ignore it if | 1309 // whitelisting based on envelope from value, but ignore it if |
1305 // we have a dkim requirement for that domain | 1310 // we have a dkim requirement for the original domain |
1306 const char *domain = strchr(priv.mailaddr, '@'); | 1311 const char *domain = strchr(priv.origaddr, '@'); |
1307 if (domain) { | 1312 if (domain) { |
1308 DKIMP dk = con.find_dkim_from(domain+1); | 1313 DKIMP dk = con.find_dkim_from(domain+1); |
1309 if (dk && (dk->action == token_require_signed)) { | 1314 if (dk && (dk->action == token_require_signed)) { |
1310 my_syslog(&priv, "dkim require_signed overrides envelope from whitelist"); | 1315 my_syslog(&priv, "dkim require_signed overrides envelope from whitelist"); |
1311 st = oksofar; | 1316 st = oksofar; |
1365 smfi_setreply(ctx, (char*)"550", (char*)"5.7.1", (char*)"no such user"); | 1370 smfi_setreply(ctx, (char*)"550", (char*)"5.7.1", (char*)"no such user"); |
1366 return SMFIS_REJECT; | 1371 return SMFIS_REJECT; |
1367 } | 1372 } |
1368 | 1373 |
1369 if (ver) { | 1374 if (ver) { |
1370 // try to verify this from/to pair of addresses even if it might be explicitly whitelisted | 1375 // try to verify the original from/to pair of addresses even if it might be explicitly whitelisted |
1371 const char *loto = to_lower_string(rcptaddr, false); | 1376 const char *loto = to_lower_string(rcptaddr, false); |
1372 bool rc = ver->ok(priv.queueid, priv.mailaddr, loto); | 1377 bool rc = ver->ok(priv.queueid, priv.origaddr, loto); |
1373 free((void*)loto); | 1378 free((void*)loto); |
1374 if (!rc) { | 1379 if (!rc) { |
1375 smfi_setreply(ctx, (char*)"550", (char*)"5.7.1", (char*)"no such user"); | 1380 smfi_setreply(ctx, (char*)"550", (char*)"5.7.1", (char*)"no such user"); |
1376 return SMFIS_REJECT; | 1381 return SMFIS_REJECT; |
1377 } | 1382 } |
1425 if (!priv.content_context) priv.content_context = &con; | 1430 if (!priv.content_context) priv.content_context = &con; |
1426 else if (con.get_require() && (priv.content_context != &con)) { | 1431 else if (con.get_require() && (priv.content_context != &con)) { |
1427 smfi_setreply(ctx, (char*)"452", (char*)"4.2.1", (char*)"incompatible filtering contexts"); | 1432 smfi_setreply(ctx, (char*)"452", (char*)"4.2.1", (char*)"incompatible filtering contexts"); |
1428 return SMFIS_TEMPFAIL; | 1433 return SMFIS_TEMPFAIL; |
1429 } | 1434 } |
1430 priv.need_content_filter(rcptaddr, con); | 1435 priv.need_content_filter(con); |
1431 char bu[maxlen]; | 1436 char bu[maxlen]; |
1432 bool uri = false; | 1437 bool uri = false; |
1433 // content filtering implies also checking helo name on uribl (if enabled) | 1438 // content filtering implies also checking helo name on uribl (if enabled) |
1434 if (priv.helo_uribl) { | 1439 if (priv.helo_uribl) { |
1435 snprintf(bu, sizeof(bu), "(helo %s)", priv.host_uribl); | 1440 snprintf(bu, sizeof(bu), "(helo %s)", priv.host_uribl); |
1480 } | 1485 } |
1481 | 1486 |
1482 if (priv.dkim_ok) { | 1487 if (priv.dkim_ok) { |
1483 if ((priv.header_count == 1) && (strcasecmp(headerf, "DKIM-Filter") != 0)) priv.dkim_ok = false; | 1488 if ((priv.header_count == 1) && (strcasecmp(headerf, "DKIM-Filter") != 0)) priv.dkim_ok = false; |
1484 if (priv.header_count == 2) { | 1489 if (priv.header_count == 2) { |
1485 if (strcasecmp(headerf, "Authentication-Results") != 0) priv.dkim_ok = false; | 1490 if ((strcasecmp(headerf, "Authentication-Results") == 0) && |
1486 if (strncasecmp(headerv, token_myhostname, strlen(token_myhostname)) != 0) priv.dkim_ok = false; | 1491 (strncasecmp(headerv, token_myhostname, strlen(token_myhostname)) == 0)) { |
1487 if (priv.dkim_ok) { | |
1488 const int nmatch = 2; | 1492 const int nmatch = 2; |
1489 regmatch_t match[nmatch]; | 1493 regmatch_t match[nmatch]; |
1490 while (true) { | 1494 while (true) { |
1491 if (0 == regexec(&dkim_pattern, value, nmatch, match, 0)) { | 1495 if (0 == regexec(&dkim_r_pattern, value, nmatch, match, 0)) { |
1492 int s1 = match[1].rm_so; // domain | 1496 int s1 = match[1].rm_so; // domain |
1493 int e1 = match[1].rm_eo; | 1497 int e1 = match[1].rm_eo; |
1494 if (s1 != -1) { | 1498 if (s1 != -1) { |
1495 char save = value[e1]; | 1499 char save = value[e1]; |
1496 value[e1] = '\0'; | 1500 value[e1] = '\0'; |
1501 else break; | 1505 else break; |
1502 } | 1506 } |
1503 else break; | 1507 else break; |
1504 } | 1508 } |
1505 } | 1509 } |
1510 else if (strcasecmp(headerf, "DKIM-Signature") == 0) { | |
1511 const int nmatch = 2; | |
1512 regmatch_t match[nmatch]; | |
1513 if (0 == regexec(&dkim_s_pattern, value, nmatch, match, 0)) { | |
1514 int s1 = match[1].rm_so; // domain | |
1515 int e1 = match[1].rm_eo; | |
1516 if (s1 != -1) { | |
1517 value[e1] = '\0'; | |
1518 priv.dkim_signers.insert(strdup(value+s1)); | |
1519 } | |
1520 } | |
1521 } | |
1522 else priv.dkim_ok = false; | |
1506 } | 1523 } |
1507 } | 1524 } |
1508 | 1525 |
1509 // only look at the first from header | 1526 // only look at the first from header |
1510 if ((!priv.fromaddr) && (strcasecmp(headerf, "from") == 0)) { | 1527 if ((!priv.fromaddr) && (strcasecmp(headerf, "from") == 0)) { |
1511 const int nmatch = 2; | 1528 const int nmatch = 2; |
1512 regmatch_t match[nmatch]; | 1529 regmatch_t match[nmatch]; |
1513 int err = regexec(&from_pattern, value, nmatch, match, 0); | 1530 if (0 == regexec(&from_pattern, value, nmatch, match, 0)) { |
1514 if (err == 0) { | |
1515 int s1 = match[1].rm_so; // domain | 1531 int s1 = match[1].rm_so; // domain |
1516 int e1 = match[1].rm_eo; | 1532 int e1 = match[1].rm_eo; |
1517 if (s1 != -1) { | 1533 if (s1 != -1) { |
1518 value[e1] = '\0'; | 1534 value[e1] = '\0'; |
1519 priv.fromaddr = strdup(value+s1); | 1535 priv.fromaddr = strdup(value+s1); |
1885 if (regcomp(&prvs_pattern, "^prvs=([^=]+)=(.+)$", REG_ICASE | REG_EXTENDED)) { | 1901 if (regcomp(&prvs_pattern, "^prvs=([^=]+)=(.+)$", REG_ICASE | REG_EXTENDED)) { |
1886 printf("cannot compile regex pattern to find prvs coding in mail addresses\n"); | 1902 printf("cannot compile regex pattern to find prvs coding in mail addresses\n"); |
1887 exit(3); | 1903 exit(3); |
1888 } | 1904 } |
1889 | 1905 |
1890 // setup dkim signature detection | 1906 // setup dkim results signature detection |
1891 if (regcomp(&dkim_pattern, " dkim=pass .[0-9]*-bit key. header.d=([^ ]+) ", REG_ICASE | REG_EXTENDED)) { | 1907 if (regcomp(&dkim_r_pattern, " dkim=pass .[0-9]*-bit key. header.d=([^ ]+) ", REG_ICASE | REG_EXTENDED)) { |
1908 printf("cannot compile regex pattern to find dkim results gnatures\n"); | |
1909 exit(3); | |
1910 } | |
1911 | |
1912 // setup dkim results signature detection | |
1913 if (regcomp(&dkim_s_pattern, " d=([^;]+);", REG_ICASE | REG_EXTENDED)) { | |
1892 printf("cannot compile regex pattern to find dkim signatures\n"); | 1914 printf("cannot compile regex pattern to find dkim signatures\n"); |
1893 exit(3); | 1915 exit(3); |
1894 } | 1916 } |
1895 | 1917 |
1896 // setup from domain extraction | 1918 // setup from domain extraction |