Mercurial > dnsbl
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 } |