Mercurial > dnsbl
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') { |