comparison src/dnsbl.cpp @ 322:9f8411f3919c

add dkim white/black listing
author Carl Byington <carl@five-ten-sg.com>
date Sat, 17 Dec 2016 17:04:52 -0800
parents e172dc10fe24
children a6de27b0a1e9
comparison
equal deleted inserted replaced
321:e172dc10fe24 322:9f8411f3919c
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
102 regex_t from_pattern; // used to extract the senders mail domain from the body from: header
101 103
102 pthread_mutex_t config_mutex; 104 pthread_mutex_t config_mutex;
103 pthread_mutex_t syslog_mutex; 105 pthread_mutex_t syslog_mutex;
104 pthread_mutex_t resolve_mutex; 106 pthread_mutex_t resolve_mutex;
105 pthread_mutex_t fd_pool_mutex; 107 pthread_mutex_t fd_pool_mutex;
520 ip = 0; 522 ip = 0;
521 helo = NULL; 523 helo = NULL;
522 mailaddr = NULL; 524 mailaddr = NULL;
523 fromaddr = NULL; 525 fromaddr = NULL;
524 header_count = 0; 526 header_count = 0;
527 dkim_ok = true;
528 dkim_signer = NULL;
525 queueid = NULL; 529 queueid = NULL;
526 authenticated = NULL; 530 authenticated = NULL;
527 client_name = NULL; 531 client_name = NULL;
528 client_dns_name = NULL; 532 client_dns_name = NULL;
529 client_dns_forged = false; 533 client_dns_forged = false;
568 delete dwp; 572 delete dwp;
569 delayer.pop_front(); 573 delayer.pop_front();
570 } 574 }
571 if (mailaddr) free((void*)mailaddr); 575 if (mailaddr) free((void*)mailaddr);
572 if (fromaddr) free((void*)fromaddr); 576 if (fromaddr) free((void*)fromaddr);
577 if (dkim_signer) free((void*)dkim_signer);
573 if (queueid) free((void*)queueid); 578 if (queueid) free((void*)queueid);
574 if (authenticated) free((void*)authenticated); 579 if (authenticated) free((void*)authenticated);
575 if (client_name) free((void*)client_name); 580 if (client_name) free((void*)client_name);
576 if (client_dns_name) free((void*)client_dns_name); 581 if (client_dns_name) free((void*)client_dns_name);
577 discard(hosts_uribl); 582 discard(hosts_uribl);
585 ctx = NULL; 590 ctx = NULL;
586 eom = false; 591 eom = false;
587 mailaddr = NULL; 592 mailaddr = NULL;
588 fromaddr = NULL; 593 fromaddr = NULL;
589 header_count = 0; 594 header_count = 0;
595 dkim_ok = true;
596 dkim_signer = NULL;
590 queueid = NULL; 597 queueid = NULL;
591 authenticated = NULL; 598 authenticated = NULL;
592 client_name = NULL; 599 client_name = NULL;
593 client_dns_name = NULL; 600 client_dns_name = NULL;
594 host_uribl = NULL; 601 host_uribl = NULL;
1448 1455
1449 sfsistat mlfi_header(SMFICTX* ctx, char* headerf, char* headerv) 1456 sfsistat mlfi_header(SMFICTX* ctx, char* headerf, char* headerv)
1450 { 1457 {
1451 mlfiPriv &priv = *MLFIPRIV; 1458 mlfiPriv &priv = *MLFIPRIV;
1452 priv.header_count++; 1459 priv.header_count++;
1460 char msg[maxlen];
1453 if ((priv.header_count < 4) || (strcasecmp(headerf, "from") == 0)) { 1461 if ((priv.header_count < 4) || (strcasecmp(headerf, "from") == 0)) {
1454 char msg[maxlen];
1455 snprintf(msg, sizeof(msg), "header %s: %s", headerf, headerv); 1462 snprintf(msg, sizeof(msg), "header %s: %s", headerf, headerv);
1456 for (int i=0; i<strlen(msg); i++) { 1463 for (int i=0; i<strlen(msg); i++) {
1457 if (msg[i] < 0x20) msg[i] = ' '; 1464 if (msg[i] < 0x20) msg[i] = ' ';
1458 } 1465 }
1459 my_syslog(&priv, msg); 1466 my_syslog(&priv, msg);
1467 }
1468
1469 if (priv.dkim_ok) {
1470 if ((priv.header_count == 1) && (strcasecmp(headerf, "DKIM-Filter") != 0)) priv.dkim_ok = false;
1471 if (priv.header_count == 2) {
1472 if (strcasecmp(headerf, "Authentication-Results") != 0) priv.dkim_ok = false;
1473 if (strncasecmp(headerv, token_myhostname, strlen(token_myhostname)) != 0) priv.dkim_ok = false;
1474 if (priv.dkim_ok) {
1475 const int nmatch = 2;
1476 regmatch_t match[nmatch];
1477 if (0 == regexec(&dkim_pattern, msg, nmatch, match, 0)) {
1478 int s1 = match[1].rm_so; // domain
1479 int e1 = match[1].rm_eo;
1480 if (s1 != -1) {
1481 msg[e1] = '\0';
1482 priv.dkim_signer = strdup(msg+s1);
1483 }
1484 }
1485 }
1486 }
1487 if ((priv.header_count > 2) && (strcasecmp(headerf, "from"))) {
1488 const int nmatch = 2;
1489 regmatch_t match[nmatch];
1490 if (0 == regexec(&from_pattern, msg, nmatch, match, 0)) {
1491 int s1 = match[1].rm_so; // domain
1492 int e1 = match[1].rm_eo;
1493 if (s1 != -1) {
1494 msg[e1] = '\0';
1495 priv.fromaddr = strdup(msg+s1);
1496 }
1497 }
1498 }
1460 } 1499 }
1461 1500
1462 // headers that avoid autowhitelisting 1501 // headers that avoid autowhitelisting
1463 if (((strcasecmp(headerf, "precedence") == 0) && (strcasecmp(headerv, "bulk") == 0)) || 1502 if (((strcasecmp(headerf, "precedence") == 0) && (strcasecmp(headerv, "bulk") == 0)) ||
1464 ((strcasecmp(headerf, "content-type") == 0) && (strncasecmp(headerv, "multipart/report", 16) == 0))) { 1503 ((strcasecmp(headerf, "content-type") == 0) && (strncasecmp(headerv, "multipart/report", 16) == 0))) {
1544 bool random = false; 1583 bool random = false;
1545 int limit = 0; 1584 int limit = 0;
1546 for (context_map::iterator i=priv.env_to.begin(); i!=priv.env_to.end(); i++) { 1585 for (context_map::iterator i=priv.env_to.begin(); i!=priv.env_to.end(); i++) {
1547 const char *rcpt = (*i).first; 1586 const char *rcpt = (*i).first;
1548 CONTEXT &con = *((*i).second); 1587 CONTEXT &con = *((*i).second);
1549 if (!con.acceptable_content(*priv.memory, score, bulk, msg)) { 1588 if (!con.acceptable_content(*priv.memory, score, bulk, priv.dkim_signer, priv.fromaddr, msg)) {
1550 // bad html tags or excessive hosts or 1589 // bad html tags or excessive hosts or
1551 // high spam assassin score or dcc bulk threshold exceedeed 1590 // high spam assassin score or dcc bulk threshold exceedeed
1591 // or signed by a dkim signer that we don't like
1592 // or header from requires dkim signer that is missing
1552 smfi_delrcpt(ctx, (char*)rcpt); 1593 smfi_delrcpt(ctx, (char*)rcpt);
1553 } 1594 }
1554 else { 1595 else {
1555 alive.insert(rcpt); 1596 alive.insert(rcpt);
1556 random |= con.get_host_random(); 1597 random |= con.get_host_random();
1802 if (regcomp(&prvs_pattern, "^prvs=([^=]+)=(.+)$", REG_ICASE | REG_EXTENDED)) { 1843 if (regcomp(&prvs_pattern, "^prvs=([^=]+)=(.+)$", REG_ICASE | REG_EXTENDED)) {
1803 printf("cannot compile regex pattern to find prvs coding in mail addresses\n"); 1844 printf("cannot compile regex pattern to find prvs coding in mail addresses\n");
1804 exit(3); 1845 exit(3);
1805 } 1846 }
1806 1847
1848 // setup dkim signature detection
1849 if (regcomp(&dkim_pattern, " dkim=pass .* header.d=([^ ]+) ", REG_ICASE | REG_EXTENDED)) {
1850 printf("cannot compile regex pattern to find dkim signatures\n");
1851 exit(3);
1852 }
1853
1854 // setup from domain extraction
1855 if (regcomp(&from_pattern, "@([a-zA-Z0-9.-]+)", REG_ICASE | REG_EXTENDED)) {
1856 printf("cannot compile regex pattern to find dkim signatures\n");
1857 exit(3);
1858 }
1859
1807 // Process command line options 1860 // Process command line options
1808 while ((c = getopt(argc, argv, args)) != -1) { 1861 while ((c = getopt(argc, argv, args)) != -1) {
1809 switch (c) { 1862 switch (c) {
1810 case 'b': 1863 case 'b':
1811 if (optarg == NULL || *optarg == '\0') { 1864 if (optarg == NULL || *optarg == '\0') {