comparison src/dnsbl.cpp @ 236:c0d2e99c0a1d

Add surbl checks on the smtp helo value, client reverse dns name, and mail from domain name
author Carl Byington <carl@five-ten-sg.com>
date Tue, 29 Sep 2009 11:36:15 -0700
parents e6c66640f6f9
children 7b818a4e21a4
comparison
equal deleted inserted replaced
235:e6c66640f6f9 236:c0d2e99c0a1d
248 pthread_mutex_lock(&fd_pool_mutex); 248 pthread_mutex_lock(&fd_pool_mutex);
249 resolver_sock_count++; 249 resolver_sock_count++;
250 pthread_mutex_unlock(&fd_pool_mutex); 250 pthread_mutex_unlock(&fd_pool_mutex);
251 } 251 }
252 return sock; 252 return sock;
253 }
254
255
256 mlfiPriv::mlfiPriv() {
257 pthread_mutex_lock(&config_mutex);
258 pc = config;
259 pc->reference_count++;
260 pthread_mutex_unlock(&config_mutex);
261 get_fd();
262 ctx = NULL;
263 eom = false;
264 ip = 0;
265 helo = NULL;
266 mailaddr = NULL;
267 queueid = NULL;
268 authenticated = NULL;
269 client_name = NULL;
270 have_whites = false;
271 only_whites = true;
272 want_spamassassin = false;
273 want_dccgrey = false;
274 want_dccbulk = false;
275 allow_autowhitelisting = true;
276 content_context = NULL;
277 memory = NULL;
278 scanner = NULL;
279 content_suffix = NULL;
280 content_message = NULL;
281 uribl_suffix = NULL;
282 uribl_message = NULL;
283 content_host_ignore = NULL;
284 assassin = NULL;
285 dccifd = NULL;
286 }
287
288 mlfiPriv::~mlfiPriv() {
289 return_fd();
290 pthread_mutex_lock(&config_mutex);
291 pc->reference_count--;
292 bool last = (!pc->reference_count) && (pc != config);
293 pthread_mutex_unlock(&config_mutex);
294 if (last) delete pc; // free this config, since we were the last reference to it
295 if (helo) free((void*)helo);
296 reset(true);
297 }
298
299 void mlfiPriv::reset(bool final) {
300 while (!delayer.empty()) {
301 DELAYWHITEP dwp = delayer.front();
302 const char *loto = dwp->get_loto();
303 if (loto) free((void*)loto);
304 delete dwp;
305 delayer.pop_front();
306 }
307 if (mailaddr) free((void*)mailaddr);
308 if (queueid) free((void*)queueid);
309 if (authenticated) free((void*)authenticated);
310 if (client_name) free((void*)client_name);
311 delayer.clear();
312 discard(env_to);
313 if (memory) delete memory;
314 if (scanner) delete scanner;
315 if (assassin) delete assassin;
316 if (dccifd) delete dccifd;
317 if (!final) {
318 ctx = NULL;
319 eom = false;
320 mailaddr = NULL;
321 queueid = NULL;
322 authenticated = NULL;
323 client_name = NULL;
324 have_whites = false;
325 only_whites = true;
326 want_spamassassin = false;
327 want_dccgrey = false;
328 want_dccbulk = false;
329 allow_autowhitelisting = true;
330 content_context = NULL;
331 memory = NULL;
332 scanner = NULL;
333 content_suffix = NULL;
334 content_message = NULL;
335 uribl_suffix = NULL;
336 uribl_message = NULL;
337 content_host_ignore = NULL;
338 assassin = NULL;
339 dccifd = NULL;
340 }
341 }
342
343 void mlfiPriv::get_fd() {
344 err = true;
345 fd = NULL_SOCKET;
346 int result = pthread_mutex_lock(&fd_pool_mutex);
347 if (!result) {
348 std::set<int>::iterator i;
349 i = fd_pool.begin();
350 if (i != fd_pool.end()) {
351 // have at least one fd in the pool
352 err = false;
353 fd = *i;
354 fd_pool.erase(fd);
355 resolver_pool_size--;
356 pthread_mutex_unlock(&fd_pool_mutex);
357 }
358 else {
359 // pool is empty, get a new fd
360 pthread_mutex_unlock(&fd_pool_mutex);
361 fd = my_connect();
362 err = (fd == NULL_SOCKET);
363 }
364 }
365 else {
366 // cannot lock the pool, just get a new fd
367 fd = my_connect();
368 err = (fd == NULL_SOCKET);
369 }
370 }
371
372 void mlfiPriv::return_fd() {
373 if (err) {
374 // this fd got a socket error, so close it, rather than returning it to the pool
375 my_disconnect(fd);
376 }
377 else {
378 int result = pthread_mutex_lock(&fd_pool_mutex);
379 if (!result) {
380 if ((resolver_sock_count > resolver_pool_size*5) || (resolver_pool_size < 5)) {
381 // return the fd to the pool
382 fd_pool.insert(fd);
383 resolver_pool_size++;
384 pthread_mutex_unlock(&fd_pool_mutex);
385 }
386 else {
387 // more than 20% of the open resolver sockets are in the pool, and the
388 // pool as at least 5 sockets. that is enough, so just close this one.
389 pthread_mutex_unlock(&fd_pool_mutex);
390 my_disconnect(fd);
391 }
392 }
393 else {
394 // could not lock the pool, so just close the fd
395 my_disconnect(fd);
396 }
397 }
398 }
399
400 size_t mlfiPriv::my_write(const char *buf, size_t len) {
401 if (err) return 0;
402 size_t rs = 0;
403 while (len) {
404 size_t ws = write(fd, buf, len);
405 if (ws > 0) {
406 rs += ws;
407 len -= ws;
408 buf += ws;
409 }
410 else {
411 // peer closed the socket!
412 rs = 0;
413 err = true;
414 break;
415 }
416 }
417 return rs;
418 }
419
420 size_t mlfiPriv::my_read(char *buf, size_t len) {
421 if (err) return 0;
422 size_t rs = 0;
423 while (len) {
424 size_t ws = read(fd, buf, len);
425 if (ws > 0) {
426 rs += ws;
427 len -= ws;
428 buf += ws;
429 }
430 else {
431 // peer closed the socket!
432 rs = 0;
433 err = true;
434 break;
435 }
436 }
437 return rs;
438 }
439
440 void mlfiPriv::need_content_filter(const char *rcpt, CONTEXT &con) {
441 register_string(env_to, rcpt, &con);
442 if (!memory) {
443 // first recipient that needs content filtering sets
444 // some of the content filtering parameters
445 memory = new recorder(this, con.get_html_tags(), con.get_content_tlds(), con.get_content_cctlds());
446 scanner = new url_scanner(memory);
447 content_suffix = con.get_content_suffix();
448 content_message = con.get_content_message();
449 uribl_suffix = con.get_uribl_suffix();
450 uribl_message = con.get_uribl_message();
451 content_host_ignore = &con.get_content_host_ignore();
452 }
453 }
454
455
456 mlfiPriv* fetch_priv_from_ctx(SMFICTX *ctx);
457 mlfiPriv* fetch_priv_from_ctx(SMFICTX *ctx)
458 {
459 mlfiPriv *priv = (struct mlfiPriv *)smfi_getpriv(ctx);
460 priv->ctx = ctx;
461 return priv;
462 }
463 #define MLFIPRIV fetch_priv_from_ctx(ctx)
464
465
466
467 ////////////////////////////////////////////////
468 // syslog a message
469 //
470 void my_syslog(mlfiPriv *priv, const char *text) {
471 char buf[maxlen];
472 if (priv) {
473 snprintf(buf, sizeof(buf), "%s: %s", priv->queueid, text);
474 text = buf;
475 }
476 if (use_syslog) {
477 pthread_mutex_lock(&syslog_mutex);
478 if (!syslog_opened) {
479 openlog("dnsbl", LOG_PID, LOG_MAIL);
480 syslog_opened = true;
481 }
482 syslog(LOG_NOTICE, "%s", text);
483 pthread_mutex_unlock(&syslog_mutex);
484 }
485 else {
486 printf("%s \n", text);
487 }
488 }
489
490 void my_syslog(mlfiPriv *priv, const string text) {
491 if (debug_syslog > 3) {
492 char buf[maxlen];
493 strncpy(buf, text.c_str(), sizeof(buf));
494 buf[maxlen-1] = '\0'; // ensure null termination
495 my_syslog(priv, buf);
496 }
497 }
498
499 void my_syslog(const char *text) {
500 my_syslog(NULL, text);
501 }
502
503
504 ////////////////////////////////////////////////
505 // read a resolver request from the socket, process it, and
506 // write the result back to the socket.
507
508 void process_resolver_requests(int socket);
509 void process_resolver_requests(int socket) {
510 #ifdef NS_MAXDNAME
511 char question[NS_MAXDNAME];
512 #else
513 char question[1000];
514 #endif
515 glommer glom;
516
517 int maxq = sizeof(question);
518 while (true) {
519 // read a question
520 int rs = 0;
521 while (rs < maxq) {
522 int ns = read(socket, question+rs, maxq-rs);
523 if (ns > 0) {
524 rs += ns;
525 if (question[rs-1] == '\0') {
526 // last byte read was the null terminator, we are done
527 break;
528 }
529 }
530 else {
531 // peer closed the socket
532 #ifdef RESOLVER_DEBUG
533 my_syslog("process_resolver_requests() peer closed socket while reading question");
534 #endif
535 shutdown(socket, SHUT_RDWR);
536 close(socket);
537 return;
538 }
539 }
540 question[rs-1] = '\0'; // ensure null termination
541
542 // find the answer
543 #ifdef NS_PACKETSZ
544 #ifdef RESOLVER_DEBUG
545 char text[1000];
546 snprintf(text, sizeof(text), "process_resolver_requests() has a question %s", question);
547 my_syslog(text);
548 #endif
549 int res_result = res_search(question, ns_c_in, ns_t_a, glom.answer, sizeof(glom.answer));
550 if (res_result < 0) glom.length = 0; // represent all errors as zero length answers
551 else glom.length = (size_t)res_result;
552 #else
553 glom.length = sizeof(glom.answer);
554 glom.answer = 0;
555 struct hostent *host = gethostbyname(question);
556 if (host && (host->h_addrtype == AF_INET)) {
557 memcpy(&glom.answer, host->h_addr, sizeof(glom.answer));
558 }
559 #endif
560
561 // write the answer
562 char *buf = (char *)&glom;
563 int len = glom.length + sizeof(glom.length);
564 #ifdef RESOLVER_DEBUG
565 snprintf(text, sizeof(text), "process_resolver_requests() writing answer length %d for total %d", glom.length, len);
566 my_syslog(text);
567 #endif
568 int ws = 0;
569 while (len > ws) {
570 int ns = write(socket, buf+ws, len-ws);
571 if (ns > 0) {
572 ws += ns;
573 }
574 else {
575 // peer closed the socket!
576 #ifdef RESOLVER_DEBUG
577 my_syslog("process_resolver_requests() peer closed socket while writing answer");
578 #endif
579 shutdown(socket, SHUT_RDWR);
580 close(socket);
581 return;
582 }
583 }
584 }
585 } 253 }
586 254
587 255
588 //////////////////////////////////////////////// 256 ////////////////////////////////////////////////
589 // ask a dns question and get an A record answer - we don't try 257 // ask a dns question and get an A record answer - we don't try
708 #endif 376 #endif
709 } 377 }
710 378
711 379
712 //////////////////////////////////////////////// 380 ////////////////////////////////////////////////
381 // lookup the domain name part of a hostname on the uribl
382 //
383 // if we find part of the hostname on the uribl, return
384 // true and point found to the part of the hostname that we found
385 // as a string registered in hosts.
386 // otherwise, return false and preserve the value of found.
387 //
388 bool uriblookup(mlfiPriv &priv, string_set &hosts, const char *hostname, const char *top, const char *&found) ;
389 bool uriblookup(mlfiPriv &priv, string_set &hosts, const char *hostname, const char *top, const char *&found) {
390 // top is pointer to '.' char at end of base domain, or null for ip address form
391 // so for hostname of www.fred.mydomain.co.uk
392 // top points to-----------------------^
393 // and we end up looking at only mydomain.co.uk, ignoring the www.fred stuff
394 char buf[maxlen];
395 if (top) {
396 // add one more component
397 const char *x = (const char *)memrchr(hostname, '.', top-hostname);
398 if (x) hostname = x+1;
399 }
400 snprintf(buf, sizeof(buf), "%s.%s.", hostname, priv.uribl_suffix);
401 if (dns_interface(priv, buf, false, NULL)) {
402 if (debug_syslog > 2) {
403 char tmp[maxlen];
404 snprintf(tmp, sizeof(tmp), "found %s on %s", hostname, priv.uribl_suffix);
405 my_syslog(tmp);
406 }
407 found = register_string(hosts, hostname);
408 return true;
409 }
410 return false;
411 }
412
413
414 ////////////////////////////////////////////////
415 // uribl checker
416 // -------------
417 // hostname MUST not have a trailing dot
418 // If tld, two level lookup.
419 // Else, look up three level domain.
420 //
421 // if we find part of the hostname on the uribl, return
422 // true and point found to the part of the hostname that we found
423 // as a string registered in hosts.
424 // otherwise, return false and preserve the value of found.
425 //
426 bool check_uribl(mlfiPriv &priv, string_set &hosts, const char *hostname, const char *&found) ;
427 bool check_uribl(mlfiPriv &priv, string_set &hosts, const char *hostname, const char *&found) {
428 in_addr ip;
429 if (inet_aton(hostname, &ip)) {
430 const u_char *src = (const u_char *)&ip.s_addr;
431 if (src[0] == 127) return false; // don't do dns lookups on localhost
432 if (src[0] == 10) return false; // don't do dns lookups on rfc1918 space
433 if ((src[0] == 192) && (src[1] == 168)) return false;
434 if ((src[0] == 172) && (16 <= src[1]) && (src[1] <= 31)) return false;
435 char adr[sizeof "255.255.255.255 "];
436 snprintf(adr, sizeof(adr), "%u.%u.%u.%u", src[3], src[2], src[1], src[0]);
437 // cannot use inet_ntop here since we want the octets reversed.
438 return (uriblookup(priv, hosts, adr, NULL, found));
439 }
440
441 const char *top, *top2, *top3;
442 top = strrchr(hostname, '.');
443 if (top) {
444 top2 = (const char *)memrchr(hostname, '.', top-hostname);
445
446 if (top2) {
447 string_set::iterator i = priv.memory->get_cctlds()->find(top2+1);
448 string_set::iterator x = priv.memory->get_cctlds()->end();
449 // if we have a 2-level-cctld, just look at top three levels of the name
450 if (i != x) return uriblookup(priv, hosts, hostname, top2, found);
451
452 // if we have more than 3 levels in the name, look at the top three levels of the name
453 top3 = (const char *)memrchr(hostname, '.', top2-hostname);
454 if (top3 && uriblookup(priv, hosts, hostname, top2, found)) return true;
455
456 // if that was not found, fall thru to looking at the top two levels
457 }
458 // look at the top two levels of the name
459 return uriblookup(priv, hosts, hostname, top, found);
460 }
461 return false;
462 }
463
464
465 mlfiPriv::mlfiPriv() {
466 pthread_mutex_lock(&config_mutex);
467 pc = config;
468 pc->reference_count++;
469 pthread_mutex_unlock(&config_mutex);
470 get_fd();
471 ctx = NULL;
472 eom = false;
473 ip = 0;
474 helo = NULL;
475 mailaddr = NULL;
476 queueid = NULL;
477 authenticated = NULL;
478 client_name = NULL;
479 helo_uribl = false;
480 client_uribl = false;
481 from_uribl = false;
482 have_whites = false;
483 only_whites = true;
484 want_spamassassin = false;
485 want_dccgrey = false;
486 want_dccbulk = false;
487 allow_autowhitelisting = true;
488 content_context = NULL;
489 memory = NULL;
490 scanner = NULL;
491 content_suffix = NULL;
492 content_message = NULL;
493 uribl_suffix = NULL;
494 uribl_message = NULL;
495 content_host_ignore = NULL;
496 assassin = NULL;
497 dccifd = NULL;
498 }
499
500 mlfiPriv::~mlfiPriv() {
501 return_fd();
502 pthread_mutex_lock(&config_mutex);
503 pc->reference_count--;
504 bool last = (!pc->reference_count) && (pc != config);
505 pthread_mutex_unlock(&config_mutex);
506 if (last) delete pc; // free this config, since we were the last reference to it
507 if (helo) free((void*)helo);
508 reset(true);
509 }
510
511 void mlfiPriv::reset(bool final) {
512 while (!delayer.empty()) {
513 DELAYWHITEP dwp = delayer.front();
514 const char *loto = dwp->get_loto();
515 if (loto) free((void*)loto);
516 delete dwp;
517 delayer.pop_front();
518 }
519 if (mailaddr) free((void*)mailaddr);
520 if (queueid) free((void*)queueid);
521 if (authenticated) free((void*)authenticated);
522 if (client_name) free((void*)client_name);
523 delayer.clear();
524 discard(env_to);
525 if (memory) delete memory;
526 if (scanner) delete scanner;
527 if (assassin) delete assassin;
528 if (dccifd) delete dccifd;
529 if (!final) {
530 ctx = NULL;
531 eom = false;
532 mailaddr = NULL;
533 queueid = NULL;
534 authenticated = NULL;
535 client_name = NULL;
536 helo_uribl = false;
537 client_uribl = false;
538 from_uribl = false;
539 have_whites = false;
540 only_whites = true;
541 want_spamassassin = false;
542 want_dccgrey = false;
543 want_dccbulk = false;
544 allow_autowhitelisting = true;
545 content_context = NULL;
546 memory = NULL;
547 scanner = NULL;
548 content_suffix = NULL;
549 content_message = NULL;
550 uribl_suffix = NULL;
551 uribl_message = NULL;
552 content_host_ignore = NULL;
553 assassin = NULL;
554 dccifd = NULL;
555 }
556 }
557
558 void mlfiPriv::get_fd() {
559 err = true;
560 fd = NULL_SOCKET;
561 int result = pthread_mutex_lock(&fd_pool_mutex);
562 if (!result) {
563 std::set<int>::iterator i;
564 i = fd_pool.begin();
565 if (i != fd_pool.end()) {
566 // have at least one fd in the pool
567 err = false;
568 fd = *i;
569 fd_pool.erase(fd);
570 resolver_pool_size--;
571 pthread_mutex_unlock(&fd_pool_mutex);
572 }
573 else {
574 // pool is empty, get a new fd
575 pthread_mutex_unlock(&fd_pool_mutex);
576 fd = my_connect();
577 err = (fd == NULL_SOCKET);
578 }
579 }
580 else {
581 // cannot lock the pool, just get a new fd
582 fd = my_connect();
583 err = (fd == NULL_SOCKET);
584 }
585 }
586
587 void mlfiPriv::return_fd() {
588 if (err) {
589 // this fd got a socket error, so close it, rather than returning it to the pool
590 my_disconnect(fd);
591 }
592 else {
593 int result = pthread_mutex_lock(&fd_pool_mutex);
594 if (!result) {
595 if ((resolver_sock_count > resolver_pool_size*5) || (resolver_pool_size < 5)) {
596 // return the fd to the pool
597 fd_pool.insert(fd);
598 resolver_pool_size++;
599 pthread_mutex_unlock(&fd_pool_mutex);
600 }
601 else {
602 // more than 20% of the open resolver sockets are in the pool, and the
603 // pool as at least 5 sockets. that is enough, so just close this one.
604 pthread_mutex_unlock(&fd_pool_mutex);
605 my_disconnect(fd);
606 }
607 }
608 else {
609 // could not lock the pool, so just close the fd
610 my_disconnect(fd);
611 }
612 }
613 }
614
615 size_t mlfiPriv::my_write(const char *buf, size_t len) {
616 if (err) return 0;
617 size_t rs = 0;
618 while (len) {
619 size_t ws = write(fd, buf, len);
620 if (ws > 0) {
621 rs += ws;
622 len -= ws;
623 buf += ws;
624 }
625 else {
626 // peer closed the socket!
627 rs = 0;
628 err = true;
629 break;
630 }
631 }
632 return rs;
633 }
634
635 size_t mlfiPriv::my_read(char *buf, size_t len) {
636 if (err) return 0;
637 size_t rs = 0;
638 while (len) {
639 size_t ws = read(fd, buf, len);
640 if (ws > 0) {
641 rs += ws;
642 len -= ws;
643 buf += ws;
644 }
645 else {
646 // peer closed the socket!
647 rs = 0;
648 err = true;
649 break;
650 }
651 }
652 return rs;
653 }
654
655 void mlfiPriv::need_content_filter(const char *rcpt, CONTEXT &con) {
656 if (!memory) {
657 // first recipient that needs content filtering sets
658 // some of the content filtering parameters
659 memory = new recorder(this, con.get_html_tags(), con.get_content_tlds(), con.get_content_cctlds());
660 scanner = new url_scanner(memory);
661 content_suffix = con.get_content_suffix();
662 content_message = con.get_content_message();
663 uribl_suffix = con.get_uribl_suffix();
664 uribl_message = con.get_uribl_message();
665 content_host_ignore = &con.get_content_host_ignore();
666 // if we are using uribl, test helo and client names here
667 if (uribl_suffix) {
668 const char *found = NULL;
669 string_set hosts;
670 if (helo) {
671 helo_uribl = check_uribl(*this, hosts, helo, found);
672 }
673 if (client_name && !helo_uribl) {
674 client_uribl = check_uribl(*this, hosts, client_name, found);
675 }
676 if (mailaddr && !client_uribl) {
677 char *f = strchr(mailaddr, '@');
678 if (f) from_uribl = check_uribl(*this, hosts, f+1, found);
679 }
680 discard(hosts);
681 }
682 }
683 }
684
685
686 mlfiPriv* fetch_priv_from_ctx(SMFICTX *ctx);
687 mlfiPriv* fetch_priv_from_ctx(SMFICTX *ctx)
688 {
689 mlfiPriv *priv = (struct mlfiPriv *)smfi_getpriv(ctx);
690 priv->ctx = ctx;
691 return priv;
692 }
693 #define MLFIPRIV fetch_priv_from_ctx(ctx)
694
695
696
697 ////////////////////////////////////////////////
698 // syslog a message
699 //
700 void my_syslog(mlfiPriv *priv, const char *text) {
701 char buf[maxlen];
702 if (priv) {
703 snprintf(buf, sizeof(buf), "%s: %s", priv->queueid, text);
704 text = buf;
705 }
706 if (use_syslog) {
707 pthread_mutex_lock(&syslog_mutex);
708 if (!syslog_opened) {
709 openlog("dnsbl", LOG_PID, LOG_MAIL);
710 syslog_opened = true;
711 }
712 syslog(LOG_NOTICE, "%s", text);
713 pthread_mutex_unlock(&syslog_mutex);
714 }
715 else {
716 printf("%s \n", text);
717 }
718 }
719
720 void my_syslog(mlfiPriv *priv, const string text) {
721 if (debug_syslog > 3) {
722 char buf[maxlen];
723 strncpy(buf, text.c_str(), sizeof(buf));
724 buf[maxlen-1] = '\0'; // ensure null termination
725 my_syslog(priv, buf);
726 }
727 }
728
729 void my_syslog(const char *text) {
730 my_syslog(NULL, text);
731 }
732
733
734 ////////////////////////////////////////////////
735 // read a resolver request from the socket, process it, and
736 // write the result back to the socket.
737
738 void process_resolver_requests(int socket);
739 void process_resolver_requests(int socket) {
740 #ifdef NS_MAXDNAME
741 char question[NS_MAXDNAME];
742 #else
743 char question[1000];
744 #endif
745 glommer glom;
746
747 int maxq = sizeof(question);
748 while (true) {
749 // read a question
750 int rs = 0;
751 while (rs < maxq) {
752 int ns = read(socket, question+rs, maxq-rs);
753 if (ns > 0) {
754 rs += ns;
755 if (question[rs-1] == '\0') {
756 // last byte read was the null terminator, we are done
757 break;
758 }
759 }
760 else {
761 // peer closed the socket
762 #ifdef RESOLVER_DEBUG
763 my_syslog("process_resolver_requests() peer closed socket while reading question");
764 #endif
765 shutdown(socket, SHUT_RDWR);
766 close(socket);
767 return;
768 }
769 }
770 question[rs-1] = '\0'; // ensure null termination
771
772 // find the answer
773 #ifdef NS_PACKETSZ
774 #ifdef RESOLVER_DEBUG
775 char text[1000];
776 snprintf(text, sizeof(text), "process_resolver_requests() has a question %s", question);
777 my_syslog(text);
778 #endif
779 int res_result = res_search(question, ns_c_in, ns_t_a, glom.answer, sizeof(glom.answer));
780 if (res_result < 0) glom.length = 0; // represent all errors as zero length answers
781 else glom.length = (size_t)res_result;
782 #else
783 glom.length = sizeof(glom.answer);
784 glom.answer = 0;
785 struct hostent *host = gethostbyname(question);
786 if (host && (host->h_addrtype == AF_INET)) {
787 memcpy(&glom.answer, host->h_addr, sizeof(glom.answer));
788 }
789 #endif
790
791 // write the answer
792 char *buf = (char *)&glom;
793 int len = glom.length + sizeof(glom.length);
794 #ifdef RESOLVER_DEBUG
795 snprintf(text, sizeof(text), "process_resolver_requests() writing answer length %d for total %d", glom.length, len);
796 my_syslog(text);
797 #endif
798 int ws = 0;
799 while (len > ws) {
800 int ns = write(socket, buf+ws, len-ws);
801 if (ns > 0) {
802 ws += ns;
803 }
804 else {
805 // peer closed the socket!
806 #ifdef RESOLVER_DEBUG
807 my_syslog("process_resolver_requests() peer closed socket while writing answer");
808 #endif
809 shutdown(socket, SHUT_RDWR);
810 close(socket);
811 return;
812 }
813 }
814 }
815 }
816
817
818 ////////////////////////////////////////////////
713 // check a single dnsbl 819 // check a single dnsbl
714 // 820 //
715 bool check_single(mlfiPriv &priv, int ip, const char *suffix); 821 bool check_single(mlfiPriv &priv, int ip, const char *suffix);
716 bool check_single(mlfiPriv &priv, int ip, const char *suffix) { 822 bool check_single(mlfiPriv &priv, int ip, const char *suffix) {
717 // make a dns question 823 // make a dns question
758 else { 864 else {
759 st = (*f).second; 865 st = (*f).second;
760 rejectlist = (*f).first; 866 rejectlist = (*f).first;
761 } 867 }
762 if (st) return st; 868 if (st) return st;
763 }
764 return false;
765 }
766
767
768 ////////////////////////////////////////////////
769 // lookup the domain name part of a hostname on the uribl
770 //
771 // if we find part of the hostname on the uribl, return
772 // true and point found to the part of the hostname that we found
773 // as a string registered in hosts.
774 // otherwise, return false and preserve the value of found.
775 //
776 bool uriblookup(mlfiPriv &priv, string_set &hosts, const char *hostname, const char *top, const char *&found) ;
777 bool uriblookup(mlfiPriv &priv, string_set &hosts, const char *hostname, const char *top, const char *&found) {
778 // top is pointer to '.' char at end of base domain, or null for ip address form
779 // so for hostname of www.fred.mydomain.co.uk
780 // top points to-----------------------^
781 // and we end up looking at only mydomain.co.uk, ignoring the www.fred stuff
782 char buf[maxlen];
783 if (top) {
784 // add one more component
785 const char *x = (const char *)memrchr(hostname, '.', top-hostname);
786 if (x) hostname = x+1;
787 }
788 snprintf(buf, sizeof(buf), "%s.%s.", hostname, priv.uribl_suffix);
789 if (dns_interface(priv, buf, false, NULL)) {
790 if (debug_syslog > 2) {
791 char tmp[maxlen];
792 snprintf(tmp, sizeof(tmp), "found %s on %s", hostname, priv.uribl_suffix);
793 my_syslog(tmp);
794 }
795 found = register_string(hosts, hostname);
796 return true;
797 }
798 return false;
799 }
800
801
802 ////////////////////////////////////////////////
803 // uribl checker
804 // -------------
805 // hostname MUST not have a trailing dot
806 // If tld, two level lookup.
807 // Else, look up three level domain.
808 //
809 // if we find part of the hostname on the uribl, return
810 // true and point found to the part of the hostname that we found
811 // as a string registered in hosts.
812 // otherwise, return false and preserve the value of found.
813 //
814 bool check_uribl(mlfiPriv &priv, string_set &hosts, const char *hostname, const char *&found) ;
815 bool check_uribl(mlfiPriv &priv, string_set &hosts, const char *hostname, const char *&found) {
816 in_addr ip;
817 if (inet_aton(hostname, &ip)) {
818 const u_char *src = (const u_char *)&ip.s_addr;
819 if (src[0] == 127) return false; // don't do dns lookups on localhost
820 if (src[0] == 10) return false; // don't do dns lookups on rfc1918 space
821 if ((src[0] == 192) && (src[1] == 168)) return false;
822 if ((src[0] == 172) && (16 <= src[1]) && (src[1] <= 31)) return false;
823 char adr[sizeof "255.255.255.255 "];
824 snprintf(adr, sizeof(adr), "%u.%u.%u.%u", src[3], src[2], src[1], src[0]);
825 // cannot use inet_ntop here since we want the octets reversed.
826 return (uriblookup(priv, hosts, adr, NULL, found));
827 }
828
829 const char *top, *top2, *top3;
830 top = strrchr(hostname, '.');
831 if (top) {
832 top2 = (const char *)memrchr(hostname, '.', top-hostname);
833
834 if (top2) {
835 string_set::iterator i = priv.memory->get_cctlds()->find(top2+1);
836 string_set::iterator x = priv.memory->get_cctlds()->end();
837 // if we have a 2-level-cctld, just look at top three levels of the name
838 if (i != x) return uriblookup(priv, hosts, hostname, top2, found);
839
840 // if we have more than 3 levels in the name, look at the top three levels of the name
841 top3 = (const char *)memrchr(hostname, '.', top2-hostname);
842 if (top3 && uriblookup(priv, hosts, hostname, top2, found)) return true;
843
844 // if that was not found, fall thru to looking at the top two levels
845 }
846 // look at the top two levels of the name
847 return uriblookup(priv, hosts, hostname, top, found);
848 } 869 }
849 return false; 870 return false;
850 } 871 }
851 872
852 873
1178 if (!priv.content_context) priv.content_context = &con; 1199 if (!priv.content_context) priv.content_context = &con;
1179 else if (con.get_require() && (priv.content_context != &con)) { 1200 else if (con.get_require() && (priv.content_context != &con)) {
1180 smfi_setreply(ctx, (char*)"452", (char*)"4.2.1", (char*)"incompatible filtering contexts"); 1201 smfi_setreply(ctx, (char*)"452", (char*)"4.2.1", (char*)"incompatible filtering contexts");
1181 return SMFIS_TEMPFAIL; 1202 return SMFIS_TEMPFAIL;
1182 } 1203 }
1204 priv.need_content_filter(rcptaddr, con);
1205 char bu[maxlen];
1206 bool uri = false;
1207 // content filtering implies also checking helo name on uribl (if enabled)
1208 if (priv.helo_uribl) {
1209 snprintf(bu, sizeof(bu), "(helo %s)", priv.helo);
1210 uri = true;
1211 }
1212 // content filterint implies also checking client reverse dns name on uribl (if enabled)
1213 if (priv.client_uribl) {
1214 snprintf(bu, sizeof(bu), "(rdns %s)", priv.client_name);
1215 uri = true;
1216 }
1217 // content filterint implies also checking mail from domain name on uribl (if enabled)
1218 if (priv.from_uribl) {
1219 snprintf(bu, sizeof(bu), "(from %s)", priv.mailaddr);
1220 uri = true;
1221 }
1222 if (uri) {
1223 char buf[maxlen];
1224 snprintf(buf, sizeof(buf), priv.uribl_message, bu);
1225 smfi_setreply(ctx, (char*)"550", (char*)"5.7.1", buf);
1226 return SMFIS_REJECT;
1227 }
1183 } 1228 }
1184 // remember the non-whites 1229 // remember the non-whites
1185 priv.need_content_filter(rcptaddr, con); 1230 register_string(priv.env_to, rcptaddr, &con);
1186 priv.only_whites = false; 1231 priv.only_whites = false;
1187 priv.want_spamassassin |= (priv.assassin) && // have spam assassin available and 1232 priv.want_spamassassin |= (priv.assassin) && // have spam assassin available and
1188 (con.get_spamassassin_limit() != 0); // want to use it with a non-zero score 1233 (con.get_spamassassin_limit() != 0); // want to use it with a non-zero score
1189 priv.want_dccgrey |= (priv.dccifd) && // have dcc interface and 1234 priv.want_dccgrey |= (priv.dccifd) && // have dcc interface and
1190 (con.get_grey()); // want to use it for greylisting 1235 (con.get_grey()); // want to use it for greylisting
1620 1665
1621 if (email) { 1666 if (email) {
1622 char *x = strchr(email, '|'); 1667 char *x = strchr(email, '|');
1623 if (x) { 1668 if (x) {
1624 *x = '\0'; 1669 *x = '\0';
1625 char *from = strdup(email); 1670 const char *from = to_lower_string(email);
1626 char *to = strdup(x+1); 1671 const char *to = to_lower_string(x+1);
1627 use_syslog = false; 1672 use_syslog = false;
1628 CONFIG *conf = new_conf(); 1673 CONFIG *conf = new_conf();
1629 if (conf) { 1674 if (conf) {
1630 CONTEXTP con = conf->find_context(to); 1675 CONTEXTP con = conf->find_context(to);
1631 char buf[maxlen]; 1676 char buf[maxlen];