Mercurial > dnsbl
comparison src/context.cpp @ 153:8d7c439bb6fa
add auto whitelisting
author | carl |
---|---|
date | Sat, 07 Jul 2007 16:10:39 -0700 |
parents | c7fc218686f5 |
children | 89ce226e5383 |
comparison
equal
deleted
inserted
replaced
152:c7fc218686f5 | 153:8d7c439bb6fa |
---|---|
19 #include <sys/socket.h> | 19 #include <sys/socket.h> |
20 #include <sys/un.h> | 20 #include <sys/un.h> |
21 | 21 |
22 static char* context_version="$Id$"; | 22 static char* context_version="$Id$"; |
23 | 23 |
24 char *token_autowhite; | |
24 char *token_black; | 25 char *token_black; |
25 char *token_content; | 26 char *token_content; |
26 char *token_context; | 27 char *token_context; |
27 char *token_dccfrom; | 28 char *token_dccfrom; |
28 char *token_dccto; | 29 char *token_dccto; |
61 #ifndef HOST_NAME_MAX | 62 #ifndef HOST_NAME_MAX |
62 #define HOST_NAME_MAX 255 | 63 #define HOST_NAME_MAX 255 |
63 #endif | 64 #endif |
64 char myhostname[HOST_NAME_MAX+1]; | 65 char myhostname[HOST_NAME_MAX+1]; |
65 | 66 |
67 pthread_mutex_t verifier_mutex; // protect the verifier map | |
66 verify_map verifiers; | 68 verify_map verifiers; |
69 | |
70 pthread_mutex_t whitelister_mutex; // protect the | |
71 whitelister_map whitelisters; | |
72 | |
67 string_set all_strings; // owns all the strings, only modified by the config loader thread | 73 string_set all_strings; // owns all the strings, only modified by the config loader thread |
68 const int maxlen = 1000; // used for snprintf buffers | 74 const int maxlen = 1000; // used for snprintf buffers |
69 const int maxage = 120; // smtp verify sockets older than this are ancient | 75 const int maxsmtp_age = 120;// smtp verify sockets older than this are ancient |
76 const int maxauto_age = 600;// auto whitelister delay before flushing to file | |
70 extern int NULL_SOCKET; | 77 extern int NULL_SOCKET; |
71 const time_t ERROR_SMTP_SOCKET_TIME = 600; // number of seconds between attempts to open a socket to an smtp server | 78 const time_t ERROR_SMTP_SOCKET_TIME = 600; // number of seconds between attempts to open a socket to an smtp server |
72 | 79 |
73 | 80 |
74 int SMTP::writer() { | 81 int SMTP::writer() { |
241 my_syslog(buf); | 248 my_syslog(buf); |
242 } | 249 } |
243 #endif | 250 #endif |
244 | 251 |
245 | 252 |
253 //////////////////////////////////////////////// | |
254 // smtp verifier so backup mx machines can see the valid users | |
255 // | |
246 VERIFY::VERIFY(char *h) { | 256 VERIFY::VERIFY(char *h) { |
247 host = h; | 257 host = h; |
248 last_err = 0; | 258 last_err = 0; |
249 pthread_mutex_init(&mutex, 0); | 259 pthread_mutex_init(&mutex, 0); |
250 } | 260 } |
259 ok = false; | 269 ok = false; |
260 } | 270 } |
261 else { | 271 else { |
262 conn = connections.front(); | 272 conn = connections.front(); |
263 time_t now = time(NULL); | 273 time_t now = time(NULL); |
264 if ((now - conn->get_stamp()) > maxage) { | 274 if ((now - conn->get_stamp()) > maxsmtp_age) { |
265 // this connection is ancient, remove it | 275 // this connection is ancient, remove it |
266 connections.pop_front(); | 276 connections.pop_front(); |
267 } | 277 } |
268 else { | 278 else { |
269 ok = false; | 279 ok = false; |
370 put_connection(conn); | 380 put_connection(conn); |
371 return (rc >= 500) ? false : true; | 381 return (rc >= 500) ? false : true; |
372 } | 382 } |
373 | 383 |
374 | 384 |
385 //////////////////////////////////////////////// | |
386 // setup a new smtp verify host | |
387 // | |
388 VERIFYP add_verify_host(char *host); | |
389 VERIFYP add_verify_host(char *host) { | |
390 VERIFYP rc = NULL; | |
391 pthread_mutex_lock(&verifier_mutex); | |
392 verify_map::iterator i = verifiers.find(host); | |
393 if (i == verifiers.end()) { | |
394 rc = new VERIFY(host); | |
395 verifiers[host] = rc; | |
396 } | |
397 else rc = (*i).second; | |
398 pthread_mutex_unlock(&verifier_mutex); | |
399 return rc; | |
400 } | |
401 | |
402 | |
403 //////////////////////////////////////////////// | |
404 // thread to check for verify hosts with old sockets that we can close | |
405 // | |
406 void* verify_closer(void *arg) { | |
407 while (true) { | |
408 sleep(maxsmtp_age); | |
409 pthread_mutex_lock(&verifier_mutex); | |
410 for (verify_map::iterator i=verifiers.begin(); i!=verifiers.end(); i++) { | |
411 VERIFYP v = (*i).second; | |
412 v->closer(); | |
413 } | |
414 pthread_mutex_unlock(&verifier_mutex); | |
415 } | |
416 return NULL; | |
417 } | |
418 | |
419 | |
420 //////////////////////////////////////////////// | |
421 // automatic whitelister | |
422 // | |
423 WHITELISTER::WHITELISTER(char *f, int d) { | |
424 fn = f; | |
425 days = d; | |
426 pthread_mutex_init(&mutex, 0); | |
427 need = false; | |
428 } | |
429 | |
430 | |
431 void WHITELISTER::writer() { | |
432 pthread_mutex_lock(&mutex); | |
433 time_t limit = time(NULL) - days*86400; | |
434 for (autowhite_sent::iterator i=rcpts.begin(); i!=rcpts.end();) { | |
435 time_t when = (*i).second; | |
436 if (when < limit) { | |
437 autowhite_sent::iterator j = i; | |
438 j++; | |
439 rcpts.erase(i); | |
440 i = j; | |
441 need = true; | |
442 } | |
443 else i++; | |
444 } | |
445 if (need) { | |
446 // dump the file | |
447 ofstream os; | |
448 os.open(fn); | |
449 if (!os.fail()) { | |
450 for (autowhite_sent::iterator i=rcpts.begin(); i!=rcpts.end(); i++) { | |
451 char *who = (*i).first; | |
452 int when = (*i).second; | |
453 os << who << " " << when << endl; | |
454 } | |
455 } | |
456 os.close(); | |
457 } | |
458 pthread_mutex_unlock(&mutex); | |
459 } | |
460 | |
461 | |
462 void WHITELISTER::sent(char *to) { | |
463 pthread_mutex_lock(&mutex); | |
464 need = true; | |
465 rcpts[to] = time(NULL); | |
466 pthread_mutex_unlock(&mutex); | |
467 } | |
468 | |
469 | |
470 bool WHITELISTER::is_white(char *from) { | |
471 bool rc = false; | |
472 pthread_mutex_lock(&mutex); | |
473 autowhite_sent::iterator i = rcpts.find(from); | |
474 if (i != rcpts.end()) { | |
475 time_t when = (*i).second; | |
476 time_t now = time(NULL); | |
477 rc = (when+(days*8640) > now); | |
478 } | |
479 pthread_mutex_unlock(&mutex); | |
480 return rc; | |
481 } | |
482 | |
483 | |
484 //////////////////////////////////////////////// | |
485 // setup a new auto whitelister file | |
486 // | |
487 WHITELISTERP add_whitelister_file(char *fn, int days); | |
488 WHITELISTERP add_whitelister_file(char *fn, int days) { | |
489 WHITELISTERP rc = NULL; | |
490 pthread_mutex_lock(&whitelister_mutex); | |
491 whitelister_map::iterator i = whitelisters.find(fn); | |
492 if (i == whitelisters.end()) { | |
493 rc = new WHITELISTER(fn, days); | |
494 whitelisters[fn] = rc; | |
495 } | |
496 else rc = (*i).second; | |
497 pthread_mutex_unlock(&whitelister_mutex); | |
498 return rc; | |
499 } | |
500 | |
501 | |
502 //////////////////////////////////////////////// | |
503 // thread to check for whitelister hosts with old sockets that we can close | |
504 // | |
505 void* whitelister_writer(void *arg) { | |
506 while (true) { | |
507 sleep(maxauto_age); | |
508 pthread_mutex_lock(&whitelister_mutex); | |
509 for (whitelister_map::iterator i=whitelisters.begin(); i!=whitelisters.end(); i++) { | |
510 WHITELISTERP v = (*i).second; | |
511 v->writer(); | |
512 } | |
513 pthread_mutex_unlock(&whitelister_mutex); | |
514 } | |
515 return NULL; | |
516 } | |
517 | |
518 | |
375 DNSBL::DNSBL(char *n, char *s, char *m) { | 519 DNSBL::DNSBL(char *n, char *s, char *m) { |
376 name = n; | 520 name = n; |
377 suffix = s; | 521 suffix = s; |
378 message = m; | 522 message = m; |
379 } | 523 } |
472 | 616 |
473 CONTEXT::CONTEXT(CONTEXTP parent_, char *name_) { | 617 CONTEXT::CONTEXT(CONTEXTP parent_, char *name_) { |
474 parent = parent_; | 618 parent = parent_; |
475 name = name_; | 619 name = name_; |
476 verify_host = NULL; | 620 verify_host = NULL; |
621 verifier = NULL; | |
622 autowhite_file = NULL; | |
623 whitelister = NULL; | |
477 env_from_default = (parent) ? token_inherit : token_unknown; | 624 env_from_default = (parent) ? token_inherit : token_unknown; |
478 content_filtering = (parent) ? parent->content_filtering : false; | 625 content_filtering = (parent) ? parent->content_filtering : false; |
479 content_suffix = NULL; | 626 content_suffix = NULL; |
480 content_message = NULL; | 627 content_message = NULL; |
481 uribl_suffix = NULL; | 628 uribl_suffix = NULL; |
529 return false; | 676 return false; |
530 } | 677 } |
531 | 678 |
532 | 679 |
533 VERIFYP CONTEXT::find_verify(char *to) { | 680 VERIFYP CONTEXT::find_verify(char *to) { |
534 if (verify_host && (verify_host != token_myhostname) && cover_env_to(to)) { | 681 if (verifier && (verify_host != token_myhostname) && cover_env_to(to)) |
535 verify_map::iterator i = verifiers.find(verify_host); | 682 return verifier; |
536 if (i == verifiers.end()) { | 683 else if (parent) |
537 if (debug_syslog) { | 684 return parent->find_verify(to); |
538 char buf[maxlen]; | 685 else |
539 snprintf(buf, maxlen, "cannot find struc for %s", verify_host); | 686 return NULL; |
540 my_syslog(buf); | 687 } |
541 } | 688 |
542 return NULL; | 689 |
543 } | 690 WHITELISTERP CONTEXT::find_autowhite(char *to) { |
544 VERIFYP v = (*i).second; | 691 if (whitelister && cover_env_to(to)) |
545 | 692 return whitelister; |
546 return v; | 693 else if (parent) |
547 } | 694 return parent->find_autowhite(to); |
548 else if (parent) return parent->find_verify(to); | 695 else |
549 else return NULL; | 696 return NULL; |
550 } | 697 } |
551 | 698 |
552 | 699 |
553 int CONTEXT::find_rate(char *user) { | 700 int CONTEXT::find_rate(char *user) { |
554 if (rcpt_per_hour.empty()) return default_rcpt_rate; | 701 if (rcpt_per_hour.empty()) return default_rcpt_rate; |
556 return (i == rcpt_per_hour.end()) ? default_rcpt_rate : (*i).second; | 703 return (i == rcpt_per_hour.end()) ? default_rcpt_rate : (*i).second; |
557 } | 704 } |
558 | 705 |
559 | 706 |
560 char *CONTEXT::find_from(char *from) { | 707 char *CONTEXT::find_from(char *from) { |
708 if (whitelister && whitelister->is_white(from)) return token_white; | |
561 char *rc = env_from_default; | 709 char *rc = env_from_default; |
562 string_map::iterator i = env_from.find(from); | 710 string_map::iterator i = env_from.find(from); |
563 if (i != env_from.end()) rc = (*i).second; // found user@domain key | 711 if (i != env_from.end()) rc = (*i).second; // found user@domain key |
564 else { | 712 else { |
565 char *x = strchr(from, '@'); | 713 char *x = strchr(from, '@'); |
771 } | 919 } |
772 printf("%s }; \n", indent); | 920 printf("%s }; \n", indent); |
773 | 921 |
774 if (verify_host) { | 922 if (verify_host) { |
775 printf("%s verify %s; \n", indent, verify_host); | 923 printf("%s verify %s; \n", indent, verify_host); |
924 } | |
925 | |
926 if (autowhite_file && whitelister) { | |
927 printf("%s autowhite %d %s; \n", indent, whitelister->get_days(), autowhite_file); | |
776 } | 928 } |
777 | 929 |
778 for (context_map::iterator i=children.begin(); i!=children.end(); i++) { | 930 for (context_map::iterator i=children.begin(); i!=children.end(); i++) { |
779 CONTEXTP c = (*i).second; | 931 CONTEXTP c = (*i).second; |
780 c->dump(false, level+1); | 932 c->dump(false, level+1); |
1098 bool parse_verify(TOKEN &tok, CONFIG &dc, CONTEXT &me); | 1250 bool parse_verify(TOKEN &tok, CONFIG &dc, CONTEXT &me); |
1099 bool parse_verify(TOKEN &tok, CONFIG &dc, CONTEXT &me) { | 1251 bool parse_verify(TOKEN &tok, CONFIG &dc, CONTEXT &me) { |
1100 char *host = tok.next(); | 1252 char *host = tok.next(); |
1101 if (!tsa(tok, token_semi)) return false; | 1253 if (!tsa(tok, token_semi)) return false; |
1102 me.set_verify(host); | 1254 me.set_verify(host); |
1103 add_verify_host(host); | 1255 me.set_verifier(add_verify_host(host)); |
1256 return true; | |
1257 } | |
1258 | |
1259 | |
1260 //////////////////////////////////////////////// | |
1261 // | |
1262 bool parse_autowhite(TOKEN &tok, CONFIG &dc, CONTEXT &me); | |
1263 bool parse_autowhite(TOKEN &tok, CONFIG &dc, CONTEXT &me) { | |
1264 int days = tok.nextint(); | |
1265 char *fn = tok.next(); | |
1266 if (!tsa(tok, token_semi)) return false; | |
1267 me.set_autowhite(fn); | |
1268 me.set_whitelister(add_whitelister_file(fn, days)); | |
1104 return true; | 1269 return true; |
1105 } | 1270 } |
1106 | 1271 |
1107 | 1272 |
1108 //////////////////////////////////////////////// | 1273 //////////////////////////////////////////////// |
1231 if (!parse_envto(tok, dc, *con)) return false; | 1396 if (!parse_envto(tok, dc, *con)) return false; |
1232 } | 1397 } |
1233 else if (have == token_verify) { | 1398 else if (have == token_verify) { |
1234 if (!parse_verify(tok, dc, *con)) return false; | 1399 if (!parse_verify(tok, dc, *con)) return false; |
1235 } | 1400 } |
1401 else if (have == token_autowhite) { | |
1402 if (!parse_autowhite(tok, dc, *con)) return false; | |
1403 } | |
1236 else if (have == token_envfrom) { | 1404 else if (have == token_envfrom) { |
1237 if (!parse_envfrom(tok, dc, *con)) return false; | 1405 if (!parse_envfrom(tok, dc, *con)) return false; |
1238 } | 1406 } |
1239 else if (have == token_rate) { | 1407 else if (have == token_rate) { |
1240 if (parent || dc.default_context) tok.token_error("rate limit ignored in non default context"); | 1408 if (parent || dc.default_context) tok.token_error("rate limit ignored in non default context"); |
1284 return (dc.default_context) ? true : false; | 1452 return (dc.default_context) ? true : false; |
1285 } | 1453 } |
1286 | 1454 |
1287 | 1455 |
1288 //////////////////////////////////////////////// | 1456 //////////////////////////////////////////////// |
1289 // setup a new smtp verify host | |
1290 // | |
1291 void add_verify_host(char *host) { | |
1292 verify_map::iterator i = verifiers.find(host); | |
1293 if (i == verifiers.end()) { | |
1294 VERIFYP v = new VERIFY(host); | |
1295 verifiers[host] = v; | |
1296 } | |
1297 } | |
1298 | |
1299 | |
1300 //////////////////////////////////////////////// | |
1301 // thread to check for verify hosts with old sockets that we can close | |
1302 // | |
1303 void* verify_closer(void *arg) { | |
1304 while (true) { | |
1305 sleep(maxage); | |
1306 for (verify_map::iterator i=verifiers.begin(); i!=verifiers.end(); i++) { | |
1307 VERIFYP v = (*i).second; | |
1308 v->closer(); | |
1309 } | |
1310 } | |
1311 return NULL; | |
1312 } | |
1313 | |
1314 | |
1315 //////////////////////////////////////////////// | |
1316 // init the tokens | 1457 // init the tokens |
1317 // | 1458 // |
1318 void token_init() { | 1459 void token_init() { |
1460 token_autowhite = register_string("autowhite"); | |
1319 token_black = register_string("black"); | 1461 token_black = register_string("black"); |
1320 token_cctld = register_string("cctld"); | 1462 token_cctld = register_string("cctld"); |
1321 token_content = register_string("content"); | 1463 token_content = register_string("content"); |
1322 token_context = register_string("context"); | 1464 token_context = register_string("context"); |
1323 token_dccfrom = register_string("dcc_from"); | 1465 token_dccfrom = register_string("dcc_from"); |