comparison src/dnsbl.cpp @ 27:43a4f6b3e668 stable-2-3

add configurable host name limit and bad html tag limits.
author carl
date Sat, 22 May 2004 22:30:45 -0700
parents fdae7ab30cfc
children 33e1e3910506
comparison
equal deleted inserted replaced
26:fdae7ab30cfc 27:43a4f6b3e668
66 #define WHITE "white" 66 #define WHITE "white"
67 #define BLACK "black" 67 #define BLACK "black"
68 #define OK "ok" 68 #define OK "ok"
69 #define MANY "many" 69 #define MANY "many"
70 70
71 enum status {oksofar, // not rejected yet 71 enum status {oksofar, // not rejected yet
72 white, // whitelisted by envelope from 72 white, // whitelisted by envelope from
73 black, // blacklisted by envelope from or to 73 black, // blacklisted by envelope from or to
74 reject}; // rejected by a dns list 74 reject, // rejected by a dns list
75 reject_tag, // too many bad html tags
76 reject_host}; // too many hosts/urls in body
75 77
76 using namespace std; 78 using namespace std;
77 79
78 extern "C" { 80 extern "C" {
79 #include "libmilter/mfapi.h" 81 #include "libmilter/mfapi.h"
123 from_map env_from; 125 from_map env_from;
124 string_map env_to_dnsbll; // map recipient to a named dnsbll 126 string_map env_to_dnsbll; // map recipient to a named dnsbll
125 string_map env_to_chkfrom; // map recipient to a named from map 127 string_map env_to_chkfrom; // map recipient to a named from map
126 char * content_suffix; // for sbl url body filtering 128 char * content_suffix; // for sbl url body filtering
127 char * content_message; // "" 129 char * content_message; // ""
128 char * limit_message; // error message for excessive bad html tags 130 char * host_limit_message; // error message for excessive host names
129 int bad_tag_limit; // limit on bad html tags 131 int host_limit; // limit on host names
132 char * tag_limit_message; // error message for excessive bad html tags
133 int tag_limit; // limit on bad html tags
130 string_set html_tags; // set of valid html tags 134 string_set html_tags; // set of valid html tags
131 CONFIG(); 135 CONFIG();
132 ~CONFIG(); 136 ~CONFIG();
133 }; 137 };
134 CONFIG::CONFIG() { 138 CONFIG::CONFIG() {
135 reference_count = 0; 139 reference_count = 0;
136 load_time = 0; 140 load_time = 0;
137 content_suffix = NULL; 141 content_suffix = NULL;
138 content_message = NULL; 142 content_message = NULL;
139 limit_message = NULL; 143 host_limit_message = NULL;
140 bad_tag_limit = 0; 144 host_limit = 0;
145 tag_limit_message = NULL;
146 tag_limit = 0;
141 } 147 }
142 CONFIG::~CONFIG() { 148 CONFIG::~CONFIG() {
143 for (dnsblp_map::iterator i=dnsbls.begin(); i!=dnsbls.end(); i++) { 149 for (dnsblp_map::iterator i=dnsbls.begin(); i!=dnsbls.end(); i++) {
144 DNSBLP d = (*i).second; 150 DNSBLP d = (*i).second;
145 // delete the underlying DNSBL objects. 151 // delete the underlying DNSBL objects.
481 CONFIG &dc = *priv.pc; 487 CONFIG &dc = *priv.pc;
482 if (!dc.content_suffix) return oksofar; 488 if (!dc.content_suffix) return oksofar;
483 int count = 0; 489 int count = 0;
484 for (string_set::iterator i=priv.memory->hosts.begin(); i!=priv.memory->hosts.end(); i++) { 490 for (string_set::iterator i=priv.memory->hosts.begin(); i!=priv.memory->hosts.end(); i++) {
485 count++; 491 count++;
486 if (count > 20) return oksofar; // silly to check too many hosts 492 int lim = priv.pc->host_limit;
493 if ((count > lim) && (lim > 0)) return reject_host;
487 host = *i; 494 host = *i;
488 if (debug_syslog) { 495 if (debug_syslog) {
489 char buf[200]; 496 char buf[200];
490 snprintf(buf, sizeof(buf), "looking for host %s", host); 497 snprintf(buf, sizeof(buf), "looking for host %s", host);
491 my_syslog(buf); 498 my_syslog(buf);
492 } 499 }
493 ip = protected_dns_interface(host, true); 500 ip = protected_dns_interface(host, true);
494 if (ip) { 501 if (ip) {
495 if (debug_syslog) { 502 // if (debug_syslog) {
496 char adr[sizeof "255.255.255.255"]; 503 // char adr[sizeof "255.255.255.255"];
497 adr[0] = '\0'; 504 // adr[0] = '\0';
498 inet_ntop(AF_INET, (const u_char *)&ip, adr, sizeof(adr)); 505 // inet_ntop(AF_INET, (const u_char *)&ip, adr, sizeof(adr));
499 char buf[200]; 506 // char buf[200];
500 snprintf(buf, sizeof(buf), "found host %s at %s", host, adr); 507 // snprintf(buf, sizeof(buf), "found host %s at %s", host, adr);
501 my_syslog(buf); 508 // my_syslog(buf);
502 } 509 // }
503 status st = check_single(ip, dc.content_suffix); 510 status st = check_single(ip, dc.content_suffix);
504 if (st == reject) return st; 511 if (st == reject) return st;
505 } 512 }
506 } 513 }
507 host = NULL; 514 host = NULL;
508 int bin = priv.memory->binary_tags; 515 int bin = priv.memory->binary_tags;
509 int bad = priv.memory->bad_html_tags; 516 int bad = priv.memory->bad_html_tags;
510 int lim = priv.pc->bad_tag_limit; 517 int lim = priv.pc->tag_limit;
511 if (bin > bad) return oksofar; // probably .zip or .tar.gz with random content 518 if (bin > bad) return oksofar; // probably .zip or .tar.gz with random content
512 if ((bad > lim) && (lim > 0)) return reject; 519 if ((bad > lim) && (lim > 0)) return reject_tag;
513 return oksofar; 520 return oksofar;
514 } 521 }
515 522
516 523
517 //////////////////////////////////////////////// 524 ////////////////////////////////////////////////
612 return SMFIS_CONTINUE; 619 return SMFIS_CONTINUE;
613 } 620 }
614 621
615 sfsistat mlfi_eom(SMFICTX *ctx) 622 sfsistat mlfi_eom(SMFICTX *ctx)
616 { 623 {
617 sfsistat rc; 624 sfsistat rc;
618 mlfiPriv &priv = *MLFIPRIV; 625 mlfiPriv &priv = *MLFIPRIV;
619 char *host = NULL; 626 char *host = NULL;
620 int ip; 627 int ip;
628 status st;
621 // process end of message 629 // process end of message
622 if (priv.authenticated || 630 if (priv.authenticated ||
623 priv.only_whites || 631 priv.only_whites ||
624 (check_hosts(priv, host, ip) == oksofar)) rc = SMFIS_CONTINUE; 632 ((st=check_hosts(priv, host, ip)) == oksofar)) rc = SMFIS_CONTINUE;
625 else { 633 else {
626 if (!priv.have_whites) { 634 if (!priv.have_whites) {
627 // can reject the entire message 635 // can reject the entire message
628 char buf[2000]; 636 char buf[2000];
629 if (!host) { 637 if (st == reject_tag) {
630 // must be rejected due to excessive bad html tags 638 // rejected due to excessive bad html tags
631 snprintf(buf, sizeof(buf), priv.pc->limit_message); 639 snprintf(buf, sizeof(buf), priv.pc->tag_limit_message);
640 }
641 else if (st == reject_host) {
642 // rejected due to excessive unique host/urls
643 snprintf(buf, sizeof(buf), priv.pc->host_limit_message);
632 } 644 }
633 else { 645 else {
634 char adr[sizeof "255.255.255.255"]; 646 char adr[sizeof "255.255.255.255"];
635 adr[0] = '\0'; 647 adr[0] = '\0';
636 inet_ntop(AF_INET, (const u_char *)&ip, adr, sizeof(adr)); 648 inet_ntop(AF_INET, (const u_char *)&ip, adr, sizeof(adr));
728 fprintf(stdout, "\n"); 740 fprintf(stdout, "\n");
729 } 741 }
730 if (dc.content_suffix) { 742 if (dc.content_suffix) {
731 fprintf(stdout, "\ncontent filtering enabled with %s %s\n", dc.content_suffix, dc.content_message); 743 fprintf(stdout, "\ncontent filtering enabled with %s %s\n", dc.content_suffix, dc.content_message);
732 } 744 }
733 if (dc.bad_tag_limit) { 745 if (dc.host_limit) {
734 fprintf(stdout, "\ncontent filtering for excessive html tags enabled with limit %d %s\n", dc.bad_tag_limit, dc.limit_message); 746 fprintf(stdout, "\ncontent filtering for host names enabled with limit %d %s\n", dc.host_limit, dc.host_limit_message);
747 }
748 if (dc.tag_limit) {
749 fprintf(stdout, "\ncontent filtering for excessive html tags enabled with limit %d %s\n", dc.tag_limit, dc.tag_limit_message);
735 } 750 }
736 fprintf(stdout, "\nfiles\n"); 751 fprintf(stdout, "\nfiles\n");
737 for (string_list::iterator i=dc.config_files.begin(); i!=dc.config_files.end(); i++) { 752 for (string_list::iterator i=dc.config_files.begin(); i!=dc.config_files.end(); i++) {
738 char *f = *i; 753 char *f = *i;
739 fprintf(stdout, "config includes %s\n", f); 754 fprintf(stdout, "config includes %s\n", f);
828 843
829 static void load_conf(CONFIG &dc, char *fn); 844 static void load_conf(CONFIG &dc, char *fn);
830 static void load_conf(CONFIG &dc, char *fn) { 845 static void load_conf(CONFIG &dc, char *fn) {
831 dc.config_files.push_back(fn); 846 dc.config_files.push_back(fn);
832 map<char*, int, ltstr> commands; 847 map<char*, int, ltstr> commands;
833 enum {dummy, content, htmllimit, htmltag, dnsbl, dnsbll, envfrom, envto, include, includedcc}; 848 enum {dummy, content, hostlimit, htmllimit, htmltag, dnsbl, dnsbll, envfrom, envto, include, includedcc};
834 commands["content" ] = content; 849 commands["content" ] = content;
850 commands["host_limit" ] = hostlimit;
835 commands["html_limit" ] = htmllimit; 851 commands["html_limit" ] = htmllimit;
836 commands["html_tag" ] = htmltag; 852 commands["html_tag" ] = htmltag;
837 commands["dnsbl" ] = dnsbl; 853 commands["dnsbl" ] = dnsbl;
838 commands["dnsbl_list" ] = dnsbll; 854 commands["dnsbl_list" ] = dnsbll;
839 commands["env_from" ] = envfrom; 855 commands["env_from" ] = envfrom;
873 dc.content_suffix = register_string(suff); 889 dc.content_suffix = register_string(suff);
874 dc.content_message = register_string(msg); 890 dc.content_message = register_string(msg);
875 processed = true; 891 processed = true;
876 } break; 892 } break;
877 893
894 case hostlimit: {
895 char *limit = strtok(NULL, delim);
896 if (!limit) break; // no integer limit
897 char *msg = limit + strlen(limit);
898 if ((msg - line) >= strlen(orig)) break; // line ended with the limit
899 msg = strchr(msg+1, '\'');
900 if (!msg) break; // no reply message template
901 msg++; // move over the leading '
902 if ((msg - line) >= strlen(orig)) break; // line ended with the leading quote
903 char *last = strchr(msg, '\'');
904 if (!last) break; // no trailing quote
905 *last = '\0'; // make it a null terminator
906 dc.host_limit = atoi(limit);
907 dc.host_limit_message = register_string(msg);
908 processed = true;
909 } break;
910
878 case htmllimit: { 911 case htmllimit: {
879 char *limit = strtok(NULL, delim); 912 char *limit = strtok(NULL, delim);
880 if (!limit) break; // no integer limit 913 if (!limit) break; // no integer limit
881 char *msg = limit + strlen(limit); 914 char *msg = limit + strlen(limit);
882 if ((msg - line) >= strlen(orig)) break; // line ended with the limit 915 if ((msg - line) >= strlen(orig)) break; // line ended with the limit
885 msg++; // move over the leading ' 918 msg++; // move over the leading '
886 if ((msg - line) >= strlen(orig)) break; // line ended with the leading quote 919 if ((msg - line) >= strlen(orig)) break; // line ended with the leading quote
887 char *last = strchr(msg, '\''); 920 char *last = strchr(msg, '\'');
888 if (!last) break; // no trailing quote 921 if (!last) break; // no trailing quote
889 *last = '\0'; // make it a null terminator 922 *last = '\0'; // make it a null terminator
890 dc.bad_tag_limit = atoi(limit); 923 dc.tag_limit = atoi(limit);
891 dc.limit_message = register_string(msg); 924 dc.tag_limit_message = register_string(msg);
892 processed = true; 925 processed = true;
893 } break; 926 } break;
894 927
895 case htmltag: { 928 case htmltag: {
896 char *tag = next_token(delim); 929 char *tag = next_token(delim);
897 if (!tag) break; // no html tag value 930 if (!tag) break; // no html tag value
931 dc.html_tags.insert(tag); // base version
898 char buf[200]; 932 char buf[200];
899 snprintf(buf, sizeof(buf), "/%s", tag); 933 snprintf(buf, sizeof(buf), "/%s", tag);
900 dc.html_tags.insert(tag); 934 dc.html_tags.insert(register_string(buf)); // leading /
901 dc.html_tags.insert(register_string(buf)); 935 snprintf(buf, sizeof(buf), "%s/", tag);
936 dc.html_tags.insert(register_string(buf)); // trailing /
902 processed = true; 937 processed = true;
903 } break; 938 } break;
904 939
905 case dnsbl: { 940 case dnsbl: {
906 // have a new dnsbl to use 941 // have a new dnsbl to use