comparison src/dnsbl.cpp @ 16:2ae8d953f1d0

add scanning for bare hostnames
author carl
date Thu, 29 Apr 2004 21:56:22 -0700
parents 443aa0e8c6fa
children 041ea016b684
comparison
equal deleted inserted replaced
15:6a21f7a3b002 16:2ae8d953f1d0
9 9
10 -p port The port through which the MTA will connect to this milter. 10 -p port The port through which the MTA will connect to this milter.
11 -t sec The timeout value. 11 -t sec The timeout value.
12 -c Check the config, and print a copy to stdout. Don't start the 12 -c Check the config, and print a copy to stdout. Don't start the
13 milter or do anything with the socket. 13 milter or do anything with the socket.
14 -d Add debug syslog entries
15
14 16
15 TODO: 17 TODO:
16 1) Add config for max_recipients for each mail domain. Recipients in 18 1) Add config for max_recipients for each mail domain. Recipients in
17 excess of that limit will be rejected, and the entire data will be 19 excess of that limit will be rejected, and the entire data will be
18 rejected if it is sent. 20 rejected if it is sent.
145 string_map *d = (*i).second; 147 string_map *d = (*i).second;
146 delete d; 148 delete d;
147 } 149 }
148 } 150 }
149 151
152 static bool debug_syslog = false;
150 static string_set all_strings; // owns all the strings, only modified by the config loader thread 153 static string_set all_strings; // owns all the strings, only modified by the config loader thread
151 static CONFIG * config = NULL; // protected by the config_mutex 154 static CONFIG * config = NULL; // protected by the config_mutex
152 155
153 static pthread_mutex_t config_mutex; 156 static pthread_mutex_t config_mutex;
154 static pthread_mutex_t syslog_mutex; 157 static pthread_mutex_t syslog_mutex;
176 char *x = strdup(name); 179 char *x = strdup(name);
177 s.insert(x); 180 s.insert(x);
178 return x; 181 return x;
179 } 182 }
180 183
184 ////////////////////////////////////////////////
185 // syslog a message
186 //
187 static void my_syslog(char *text);
188 static void my_syslog(char *text) {
189 pthread_mutex_lock(&syslog_mutex);
190 openlog("dnsbl", LOG_PID, LOG_MAIL);
191 syslog(LOG_NOTICE, "%s", text);
192 closelog();
193 pthread_mutex_unlock(&syslog_mutex);
194 }
195
196
181 // include the content scanner 197 // include the content scanner
182 #include "scanner.cpp" 198 #include "scanner.cpp"
183
184 199
185 200
186 //////////////////////////////////////////////// 201 ////////////////////////////////////////////////
187 // mail filter private data, held for us by sendmail 202 // mail filter private data, held for us by sendmail
188 // 203 //
238 253
239 #define MLFIPRIV ((struct mlfiPriv *) smfi_getpriv(ctx)) 254 #define MLFIPRIV ((struct mlfiPriv *) smfi_getpriv(ctx))
240 255
241 256
242 //////////////////////////////////////////////// 257 ////////////////////////////////////////////////
243 // syslog a message
244 //
245 static void my_syslog(char *text);
246 static void my_syslog(char *text) {
247 pthread_mutex_lock(&syslog_mutex);
248 openlog("dnsbl", LOG_PID, LOG_MAIL);
249 syslog(LOG_NOTICE, "%s", text);
250 closelog();
251 pthread_mutex_unlock(&syslog_mutex);
252 }
253
254
255 ////////////////////////////////////////////////
256 // register a global string 258 // register a global string
257 // 259 //
258 static char* register_string(char *name); 260 static char* register_string(char *name);
259 static char* register_string(char *name) { 261 static char* register_string(char *name) {
260 return register_string(all_strings, name); 262 return register_string(all_strings, name);
356 // caller must ensure thread safety. 358 // caller must ensure thread safety.
357 // 359 //
358 // 360 //
359 static int dns_interface(char *question); 361 static int dns_interface(char *question);
360 static int dns_interface(char *question) { 362 static int dns_interface(char *question) {
363 #ifdef NS_PACKETSZ
361 u_char answer[NS_PACKETSZ]; 364 u_char answer[NS_PACKETSZ];
362 int length = res_search(question, ns_c_in, ns_t_a, answer, sizeof(answer)); 365 int length = res_search(question, ns_c_in, ns_t_a, answer, sizeof(answer));
363 if (length < 0) return 0; // error in getting answer 366 if (length < 0) return 0; // error in getting answer
364 // parse the answer 367 // parse the answer
365 ns_msg handle; 368 ns_msg handle;
372 memcpy(&address, ns_rr_rdata(rr), sizeof(address)); 375 memcpy(&address, ns_rr_rdata(rr), sizeof(address));
373 return address; 376 return address;
374 } 377 }
375 } 378 }
376 return 0; 379 return 0;
380 #else
381 struct hostent *host = gethostbyname(question);
382 if (!host) return 0;
383 if (host->h_addrtype != AF_INET) return 0;
384 int address;
385 memcpy(&address, host->h_addr, sizeof(address));
386 return address;
387 #endif
377 } 388 }
378 389
379 static int protected_dns_interface(char *question); 390 static int protected_dns_interface(char *question);
380 static int protected_dns_interface(char *question) { 391 static int protected_dns_interface(char *question) {
381 int ans; 392 int ans;
392 static status check_single(int ip, char *suffix); 403 static status check_single(int ip, char *suffix);
393 static status check_single(int ip, char *suffix) { 404 static status check_single(int ip, char *suffix) {
394 // make a dns question 405 // make a dns question
395 const u_char *src = (const u_char *)&ip; 406 const u_char *src = (const u_char *)&ip;
396 if (src[0] == 127) return oksofar; // don't do dns lookups on localhost 407 if (src[0] == 127) return oksofar; // don't do dns lookups on localhost
408 #ifdef NS_MAXDNAME
397 char question[NS_MAXDNAME]; 409 char question[NS_MAXDNAME];
410 #else
411 char question[1000];
412 #endif
398 snprintf(question, sizeof(question), "%u.%u.%u.%u.%s.", src[3], src[2], src[1], src[0], suffix); 413 snprintf(question, sizeof(question), "%u.%u.%u.%u.%s.", src[3], src[2], src[1], src[0], suffix);
399 // ask the question, if we get an A record it implies a blacklisted ip address 414 // ask the question, if we get an A record it implies a blacklisted ip address
400 return (protected_dns_interface(question)) ? reject : oksofar; 415 return (protected_dns_interface(question)) ? reject : oksofar;
401 } 416 }
402 417
439 454
440 455
441 //////////////////////////////////////////////// 456 ////////////////////////////////////////////////
442 // check the dnsbls specified for this recipient 457 // check the dnsbls specified for this recipient
443 // 458 //
444 static status check_hosts(mlfiPriv &priv, char *&url, int &ip); 459 static status check_hosts(mlfiPriv &priv, char *&host, int &ip);
445 static status check_hosts(mlfiPriv &priv, char *&url, int &ip) { 460 static status check_hosts(mlfiPriv &priv, char *&host, int &ip) {
446 CONFIG &dc = *priv.pc; 461 CONFIG &dc = *priv.pc;
447 if (!dc.content_suffix) return oksofar; 462 if (!dc.content_suffix) return oksofar;
448 int count = 0; 463 int count = 0;
449 for (string_set::iterator i=priv.hosts.begin(); i!=priv.hosts.end(); i++) { 464 for (string_set::iterator i=priv.hosts.begin(); i!=priv.hosts.end(); i++) {
450 count++; 465 count++;
451 if (count > 20) return oksofar; // silly to check too many hosts 466 if (count > 20) return oksofar; // silly to check too many hosts
452 url = *i; 467 host = *i;
453 // char buf[200]; 468 if (debug_syslog) {
454 // snprintf(buf, sizeof(buf), "looking for url %s", url); 469 char buf[200];
455 // my_syslog(buf); 470 snprintf(buf, sizeof(buf), "looking for host %s", host);
456 ip = protected_dns_interface(url); 471 my_syslog(buf);
472 }
473 ip = protected_dns_interface(host);
457 if (ip) { 474 if (ip) {
475 if (debug_syslog) {
476 char adr[sizeof "255.255.255.255"];
477 adr[0] = '\0';
478 inet_ntop(AF_INET, (const u_char *)&ip, adr, sizeof(adr));
479 char buf[200];
480 snprintf(buf, sizeof(buf), "found host %s at %s", host, adr);
481 my_syslog(buf);
482 }
458 status st = check_single(ip, dc.content_suffix); 483 status st = check_single(ip, dc.content_suffix);
459 if (st == reject) return st; 484 if (st == reject) return st;
460 } 485 }
461 } 486 }
462 return oksofar; 487 return oksofar;
563 588
564 sfsistat mlfi_eom(SMFICTX *ctx) 589 sfsistat mlfi_eom(SMFICTX *ctx)
565 { 590 {
566 sfsistat rc; 591 sfsistat rc;
567 mlfiPriv &priv = *MLFIPRIV; 592 mlfiPriv &priv = *MLFIPRIV;
568 char *url = NULL; 593 char *host = NULL;
569 int ip; 594 int ip;
570 // process end of message 595 // process end of message
571 if (priv.authenticated || 596 if (priv.authenticated ||
572 priv.only_whites || 597 priv.only_whites ||
573 (check_hosts(priv, url, ip) == oksofar)) rc = SMFIS_CONTINUE; 598 (check_hosts(priv, host, ip) == oksofar)) rc = SMFIS_CONTINUE;
574 else { 599 else {
575 if (!priv.have_whites) { 600 if (!priv.have_whites) {
576 // can reject the entire message 601 // can reject the entire message
577 char adr[sizeof "255.255.255.255"]; 602 char adr[sizeof "255.255.255.255"];
578 adr[0] = '\0'; 603 adr[0] = '\0';
579 inet_ntop(AF_INET, (const u_char *)&ip, adr, sizeof(adr)); 604 inet_ntop(AF_INET, (const u_char *)&ip, adr, sizeof(adr));
580 char buf[2000]; 605 char buf[2000];
581 snprintf(buf, sizeof(buf), priv.pc->content_message, url, adr); 606 snprintf(buf, sizeof(buf), priv.pc->content_message, host, adr);
582 smfi_setreply(ctx, "550", "5.7.1", buf); 607 smfi_setreply(ctx, "550", "5.7.1", buf);
583 rc = SMFIS_REJECT; 608 rc = SMFIS_REJECT;
584 } 609 }
585 else { 610 else {
586 // need to accept it but remove the recipients that don't want it 611 // need to accept it but remove the recipients that don't want it
983 1008
984 1009
985 static void usage(char *prog); 1010 static void usage(char *prog);
986 static void usage(char *prog) 1011 static void usage(char *prog)
987 { 1012 {
988 fprintf(stderr, "Usage: %s [-c] -p socket-addr [-t timeout]\n", prog); 1013 fprintf(stderr, "Usage: %s [-d] [-c] -p socket-addr [-t timeout]\n", prog);
989 fprintf(stderr, "where socket-addr is for the connection to sendmail and should be one of\n"); 1014 fprintf(stderr, "where socket-addr is for the connection to sendmail and should be one of\n");
990 fprintf(stderr, " inet:port@local-ip-address\n"); 1015 fprintf(stderr, " inet:port@local-ip-address\n");
991 fprintf(stderr, " local:local-domain-socket-file-name\n"); 1016 fprintf(stderr, " local:local-domain-socket-file-name\n");
992 fprintf(stderr, "-c will load and dump the config to stdout\n"); 1017 fprintf(stderr, "-c will load and dump the config to stdout\n");
1018 fprintf(stderr, "-d will add some syslog debug messages\n");
993 } 1019 }
994 1020
995 1021
996 int main(int argc, char**argv) 1022 int main(int argc, char**argv)
997 { 1023 {
998 bool check = false; 1024 bool check = false;
999 bool setconn = false; 1025 bool setconn = false;
1000 int c; 1026 int c;
1001 const char *args = "p:t:hc"; 1027 const char *args = "p:t:hcd";
1002 extern char *optarg; 1028 extern char *optarg;
1003 1029
1004 // Process command line options 1030 // Process command line options
1005 while ((c = getopt(argc, argv, args)) != -1) { 1031 while ((c = getopt(argc, argv, args)) != -1) {
1006 switch (c) { 1032 switch (c) {
1032 1058
1033 case 'c': 1059 case 'c':
1034 check = true; 1060 check = true;
1035 break; 1061 break;
1036 1062
1063 case 'd':
1064 debug_syslog = true;
1065 break;
1066
1037 case 'h': 1067 case 'h':
1038 default: 1068 default:
1039 usage(argv[0]); 1069 usage(argv[0]);
1040 exit(EX_USAGE); 1070 exit(EX_USAGE);
1041 } 1071 }