comparison src/dnsbl.cpp @ 59:510a511ad554

Add resolver processes to allow better performance on busy machines
author carl
date Mon, 03 Jan 2005 18:35:50 -0800
parents 7bb8bbf79285
children 390ed250c5d2
comparison
equal deleted inserted replaced
58:7bb8bbf79285 59:510a511ad554
1 /* 1 /*
2 2
3 Copyright (c) 2004 Carl Byington - 510 Software Group, released under 3 Copyright (c) 2004, 2005 Carl Byington - 510 Software Group, released
4 the GPL version 2 or any later version at your choice available at 4 under the GPL version 2 or any later version at your choice available at
5 http://www.fsf.org/licenses/gpl.txt 5 http://www.fsf.org/licenses/gpl.txt
6 6
7 Based on a sample milter Copyright (c) 2000-2003 Sendmail, Inc. and its 7 Based on a sample milter Copyright (c) 2000-2003 Sendmail, Inc. and its
8 suppliers. Inspired by the DCC by Rhyolite Software 8 suppliers. Inspired by the DCC by Rhyolite Software
9 9
10 -r port The port used to talk to our internal dns resolver processes
10 -p port The port through which the MTA will connect to this milter. 11 -p port The port through which the MTA will connect to this milter.
11 -t sec The timeout value. 12 -t sec The timeout value.
12 -c Check the config, and print a copy to stdout. Don't start the 13 -c Check the config, and print a copy to stdout. Don't start the
13 milter or do anything with the socket. 14 milter or do anything with the socket.
14 -d Add debug syslog entries 15 -d Add debug syslog entries
24 data is rejected if sent. 25 data is rejected if sent.
25 26
26 3) Add option to only allow one recipient if the return path is empty. 27 3) Add option to only allow one recipient if the return path is empty.
27 28
28 4) Check if the envelope from domain name primary MX points 127.0.0.0/8 29 4) Check if the envelope from domain name primary MX points 127.0.0.0/8
30
31 5) Add option for using smtp connections to verify addresses from backup
32 mx machines. This allows the backup mx to learn the valid addresses
33 on the primary machine.
29 34
30 */ 35 */
31 36
32 37
33 // from sendmail sample 38 // from sendmail sample
190 static int generation = 0; // protected by the config_mutex 195 static int generation = 0; // protected by the config_mutex
191 196
192 static pthread_mutex_t config_mutex; 197 static pthread_mutex_t config_mutex;
193 static pthread_mutex_t syslog_mutex; 198 static pthread_mutex_t syslog_mutex;
194 static pthread_mutex_t resolve_mutex; 199 static pthread_mutex_t resolve_mutex;
200 static pthread_mutex_t fd_pool_mutex;
201 static std::set<int> fd_pool;
202
203 static int NULL_SOCKET = -1;
204 static int resolver_port = 0; // global port number to talk to the dns resolver process
205 static int resolver_socket = NULL_SOCKET; // socket used to listen for resolver requests
206 static time_t ERROR_SOCKET_TIME = 60; // number of seconds between attempts to open the spam filter socket
207 static time_t last_error_time;
208
209 #ifdef NS_PACKETSZ
210 // packed structure to allow a single socket write to dump the
211 // length and the following answer. The packing attribute is gcc specific.
212 struct glommer {
213 int length;
214 u_char answer[NS_PACKETSZ];
215 } __attribute__ ((packed));
216 #endif
195 217
196 struct mlfiPriv; 218 struct mlfiPriv;
197 219
198 220
199 //////////////////////////////////////////////// 221 ////////////////////////////////////////////////
257 // include the content scanner 279 // include the content scanner
258 #include "scanner.cpp" 280 #include "scanner.cpp"
259 281
260 282
261 //////////////////////////////////////////////// 283 ////////////////////////////////////////////////
284 // disconnect the fd from the dns resolver process
285 //
286 void my_disconnect(int sock);
287 void my_disconnect(int sock)
288 {
289 if (sock != NULL_SOCKET) {
290 shutdown(sock, SHUT_RDWR);
291 close(sock);
292 }
293 }
294
295
296 ////////////////////////////////////////////////
297 // return fd connected to the dns resolver process
298 //
299 int my_connect();
300 int my_connect()
301 {
302 // if we have had recent errors, don't even try to open the socket
303 time_t now = time(NULL);
304 if ((now - last_error_time) < ERROR_SOCKET_TIME) return NULL_SOCKET;
305
306 // nothing recent, maybe this time it will work
307 int sock = NULL_SOCKET;
308 hostent *host = gethostbyname("localhost");
309 if (host) {
310 sockaddr_in server;
311 server.sin_family = host->h_addrtype;
312 server.sin_port = htons(resolver_port);
313 memcpy(&server.sin_addr, host->h_addr_list[0], host->h_length);
314 sock = socket(PF_INET, SOCK_STREAM, 0);
315 if (sock != NULL_SOCKET) {
316 bool rc = (connect(sock, (sockaddr *)&server, sizeof(server)) == 0);
317 if (!rc) {
318 int er = errno;
319 my_disconnect(sock);
320 sock = NULL_SOCKET;
321 last_error_time = now;
322 }
323 }
324 else last_error_time = now;
325 }
326 return sock;
327 }
328
329
330 ////////////////////////////////////////////////
262 // mail filter private data, held for us by sendmail 331 // mail filter private data, held for us by sendmail
263 // 332 //
264 struct mlfiPriv 333 struct mlfiPriv
265 { 334 {
266 // connection specific data 335 // connection specific data
267 CONFIG *pc; // global context with our maps 336 CONFIG *pc; // global context with our maps
337 int fd; // to talk to dns resolvers process
338 bool err; // did we get any errors on the resolver socket?
268 int ip; // ip4 address of the smtp client 339 int ip; // ip4 address of the smtp client
269 map<DNSBLP, status> checked; // status from those lists 340 map<DNSBLP, status> checked; // status from those lists
270 // message specific data 341 // message specific data
271 char *mailaddr; // envelope from value 342 char *mailaddr; // envelope from value
272 char *queueid; // sendmail queue id 343 char *queueid; // sendmail queue id
277 recorder *memory; // memory for the content scanner 348 recorder *memory; // memory for the content scanner
278 url_scanner *scanner; // object to handle body scanning 349 url_scanner *scanner; // object to handle body scanning
279 mlfiPriv(); 350 mlfiPriv();
280 ~mlfiPriv(); 351 ~mlfiPriv();
281 void reset(bool final = false); // for a new message 352 void reset(bool final = false); // for a new message
353 void get_fd();
354 void return_fd();
355 int my_read(char *buf, int len);
356 int my_write(char *buf, int len);
282 }; 357 };
358
283 mlfiPriv::mlfiPriv() { 359 mlfiPriv::mlfiPriv() {
284 pthread_mutex_lock(&config_mutex); 360 pthread_mutex_lock(&config_mutex);
285 pc = config; 361 pc = config;
286 pc->reference_count++; 362 pc->reference_count++;
287 pthread_mutex_unlock(&config_mutex); 363 pthread_mutex_unlock(&config_mutex);
364 get_fd();
288 ip = 0; 365 ip = 0;
289 mailaddr = NULL; 366 mailaddr = NULL;
290 queueid = NULL; 367 queueid = NULL;
291 authenticated = false; 368 authenticated = false;
292 have_whites = false; 369 have_whites = false;
293 only_whites = true; 370 only_whites = true;
294 memory = new recorder(this, &pc->html_tags, &pc->tlds); 371 memory = new recorder(this, &pc->html_tags, &pc->tlds);
295 scanner = new url_scanner(memory); 372 scanner = new url_scanner(memory);
296 } 373 }
374
297 mlfiPriv::~mlfiPriv() { 375 mlfiPriv::~mlfiPriv() {
376 return_fd();
298 pthread_mutex_lock(&config_mutex); 377 pthread_mutex_lock(&config_mutex);
299 pc->reference_count--; 378 pc->reference_count--;
300 pthread_mutex_unlock(&config_mutex); 379 pthread_mutex_unlock(&config_mutex);
301 reset(true); 380 reset(true);
302 } 381 }
382
303 void mlfiPriv::reset(bool final) { 383 void mlfiPriv::reset(bool final) {
304 if (mailaddr) free(mailaddr); 384 if (mailaddr) free(mailaddr);
305 if (queueid) free(queueid); 385 if (queueid) free(queueid);
306 discard(non_whites); 386 discard(non_whites);
307 delete memory; 387 delete memory;
315 memory = new recorder(this, &pc->html_tags, &pc->tlds); 395 memory = new recorder(this, &pc->html_tags, &pc->tlds);
316 scanner = new url_scanner(memory); 396 scanner = new url_scanner(memory);
317 } 397 }
318 } 398 }
319 399
400 void mlfiPriv::get_fd()
401 {
402 err = true;
403 fd = NULL_SOCKET;
404 int result = pthread_mutex_lock(&fd_pool_mutex);
405 if (!result) {
406 std::set<int>::iterator i;
407 i = fd_pool.begin();
408 if (i != fd_pool.end()) {
409 // have at least one fd in the pool
410 err = false;
411 fd = *i;
412 fd_pool.erase(fd);
413 }
414 else {
415 // pool is empty, get a new fd
416 fd = my_connect();
417 err = (fd == NULL_SOCKET);
418 }
419 pthread_mutex_unlock(&fd_pool_mutex);
420 }
421 else {
422 // cannot lock the pool, just get a new fd
423 fd = my_connect();
424 err = (fd == NULL_SOCKET);
425 }
426 }
427
428 void mlfiPriv::return_fd()
429 {
430 if (err) {
431 // this fd got a socket error, so close it, rather than returning it to the pool
432 my_disconnect(fd);
433 }
434 else {
435 int result = pthread_mutex_lock(&fd_pool_mutex);
436 if (!result) {
437 // return the fd to the pool
438 fd_pool.insert(fd);
439 pthread_mutex_unlock(&fd_pool_mutex);
440 }
441 else {
442 // could not lock the pool, so just close the fd
443 my_disconnect(fd);
444 }
445 }
446 }
447
448 int mlfiPriv::my_write(char *buf, int len)
449 {
450 if (err) return 0;
451 int rs = 0;
452 while (len) {
453 int ws = write(fd, buf, len);
454 if (ws > 0) {
455 rs += ws;
456 len -= ws;
457 buf += ws;
458 }
459 else {
460 // peer closed the socket!
461 rs = 0;
462 err = true;
463 break;
464 }
465 }
466 return rs;
467 }
468
469 int mlfiPriv::my_read(char *buf, int len)
470 {
471 if (err) return 0;
472 int rs = 0;
473 while (len > 1) {
474 int ws = read(fd, buf, len);
475 if (ws > 0) {
476 rs += ws;
477 len -= ws;
478 buf += ws;
479 }
480 else {
481 // peer closed the socket!
482 rs = 0;
483 err = true;
484 break;
485 }
486 }
487 return rs;
488 }
489
320 #define MLFIPRIV ((struct mlfiPriv *) smfi_getpriv(ctx)) 490 #define MLFIPRIV ((struct mlfiPriv *) smfi_getpriv(ctx))
321 491
322 492
323 //////////////////////////////////////////////// 493 ////////////////////////////////////////////////
324 // syslog a message 494 // syslog a message
435 } 605 }
436 return *sm; 606 return *sm;
437 } 607 }
438 608
439 609
440 //////////////////////////////////////////////// 610
441 // 611 ////////////////////////////////////////////////
612 // read a resolver request from the socket, process it, and
613 // write the result back to the socket.
614
615 #ifdef NS_PACKETSZ
616 static void process_resolver_requests(int socket);
617 static void process_resolver_requests(int socket) {
618 #ifdef NS_MAXDNAME
619 char question[NS_MAXDNAME];
620 #else
621 char question[1000];
622 #endif
623 glommer glom;
624
625 int maxq = sizeof(question);
626 while (true) {
627 // read a question
628 int rs = 0;
629 while (true) {
630 int ns = read(socket, question+rs, maxq-rs);
631 if (ns > 0) {
632 rs += ns;
633 if (question[rs-1] == '\0') {
634 // last byte read was the null terminator, we are done
635 break;
636 }
637 }
638 else {
639 // peer closed the socket
640 //my_syslog("child worker process, peer closed socket while reading question");
641 shutdown(socket, SHUT_RDWR);
642 close(socket);
643 return;
644 }
645 }
646
647 // find the answer
648 //char text[1000];
649 //snprintf(text, sizeof(text), "child worker process has a question %s", question);
650 //my_syslog(text);
651 glom.length = res_search(question, ns_c_in, ns_t_a, glom.answer, sizeof(glom.answer));
652 if (glom.length < 0) glom.length = 0; // represent all errors as zero length answers
653
654 // write the answer
655 char *buf = (char *)&glom;
656 int len = glom.length + sizeof(glom.length);
657 //snprintf(text, sizeof(text), "child worker process writing answer length %d for total %d", glom.length, len);
658 //my_syslog(text);
659 int ws = 0;
660 while (len > ws) {
661 int ns = write(socket, buf+ws, len-ws);
662 if (ns > 0) {
663 ws += ns;
664 }
665 else {
666 // peer closed the socket!
667 //my_syslog("child worker process, peer closed socket while writing answer");
668 shutdown(socket, SHUT_RDWR);
669 close(socket);
670 return;
671 }
672 }
673 }
674 }
675 #endif
676
677
678 ////////////////////////////////////////////////
442 // ask a dns question and get an A record answer - we don't try 679 // ask a dns question and get an A record answer - we don't try
443 // very hard, just using the default resolver retry settings. 680 // very hard, just using the default resolver retry settings.
444 // If we cannot get an answer, we just accept the mail. The 681 // If we cannot get an answer, we just accept the mail.
445 // caller must ensure thread safety. 682 //
446 // 683 //
447 // 684 static int dns_interface(mlfiPriv &priv, char *question, bool maybe_ip, ns_map *nameservers);
448 static int dns_interface(char *question, bool maybe_ip, ns_map *nameservers); 685 static int dns_interface(mlfiPriv &priv, char *question, bool maybe_ip, ns_map *nameservers) {
449 static int dns_interface(char *question, bool maybe_ip, ns_map *nameservers) { 686 int ret_address = 0;
450 #ifdef NS_PACKETSZ 687 #ifdef NS_PACKETSZ
451 u_char answer[NS_PACKETSZ]; 688
452 int length = res_search(question, ns_c_in, ns_t_a, answer, sizeof(answer)); 689 // this part can be done without locking the resolver mutex. Each
453 if (length >= 0) { // no error yet 690 // milter thread is talking over its own socket to a separate resolver
454 // parse the answer 691 // process, which does the actual dns resolution.
455 ns_msg handle; 692 if (priv.err) return 0; // cannot ask more questions on this socket.
456 ns_rr rr; 693 priv.my_write(question, strlen(question)+1); // write the question including the null terminator
457 if (ns_initparse(answer, length, &handle) == 0) { 694 glommer glom;
458 // look for ns names 695 char *buf = (char *)&glom;
459 if (nameservers) { 696 priv.my_read(buf, sizeof(glom.length));
460 ns_map &ns = *nameservers; 697 buf += sizeof(glom.length);
461 int rrnum = 0; 698 //char text[1000];
462 while (ns_parserr(&handle, ns_s_ns, rrnum++, &rr) == 0) { 699 //snprintf(text, sizeof(text), "milter thread wrote question %s and has answer length %d", question, glom.length);
463 if (ns_rr_type(rr) == ns_t_ns) { 700 //my_syslog(text);
464 char nam[NS_MAXDNAME+1]; 701 if ((glom.length < 0) || (glom.length > sizeof(glom.answer))) {
465 char *n = nam; 702 priv.err = true;
466 const u_char *p = ns_rr_rdata(rr); 703 return 0; // cannot process overlarge answers
467 while (((n-nam) < NS_MAXDNAME) && ((p-answer) < length) && *p) { 704 }
468 size_t s = *(p++); 705 priv.my_read(buf, glom.length);
469 if (s > 191) { 706
470 // compression pointer 707 // now we need to lock the resolver mutex to keep the milter threads from
471 s = (s-192)*256 + *(p++); 708 // stepping on each other while parsing the dns answer.
472 if (s >= length) break; // pointer outside bounds of answer 709 pthread_mutex_lock(&resolve_mutex);
473 p = answer + s; 710 if (glom.length > 0) {
474 s = *(p++); 711 // parse the answer
712 ns_msg handle;
713 ns_rr rr;
714 if (ns_initparse(glom.answer, glom.length, &handle) == 0) {
715 // look for ns names
716 if (nameservers) {
717 ns_map &ns = *nameservers;
718 int rrnum = 0;
719 while (ns_parserr(&handle, ns_s_ns, rrnum++, &rr) == 0) {
720 if (ns_rr_type(rr) == ns_t_ns) {
721 char nam[NS_MAXDNAME+1];
722 char *n = nam;
723 const u_char *p = ns_rr_rdata(rr);
724 while (((n-nam) < NS_MAXDNAME) && ((p-glom.answer) < glom.length) && *p) {
725 size_t s = *(p++);
726 if (s > 191) {
727 // compression pointer
728 s = (s-192)*256 + *(p++);
729 if (s >= glom.length) break; // pointer outside bounds of answer
730 p = glom.answer + s;
731 s = *(p++);
732 }
733 if (s > 0) {
734 if ((n-nam) >= (NS_MAXDNAME-s)) break; // destination would overflow name buffer
735 if ((p-glom.answer) >= (glom.length-s)) break; // source outside bounds of answer
736 memcpy(n, p, s);
737 n += s;
738 p += s;
739 *(n++) = '.';
740 }
475 } 741 }
476 if (s > 0) { 742 if (n-nam) n--; // remove trailing .
477 if ((n-nam) >= (NS_MAXDNAME-s)) break; // destination would overflow name buffer 743 *n = '\0'; // null terminate it
478 if ((p-answer) >= (length-s)) break; // source outside bounds of answer 744 register_string(ns, nam, question); // ns host to lookup later
479 memcpy(n, p, s); 745 }
480 n += s; 746 }
481 p += s; 747 rrnum = 0;
482 *(n++) = '.'; 748 while (ns_parserr(&handle, ns_s_ar, rrnum++, &rr) == 0) {
749 if (ns_rr_type(rr) == ns_t_a) {
750 char* nam = (char*)ns_rr_name(rr);
751 ns_mapper::iterator i = ns.ns_ip.find(nam);
752 if (i != ns.ns_ip.end()) {
753 // we want this ip address
754 int address;
755 memcpy(&address, ns_rr_rdata(rr), sizeof(address));
756 ns.ns_ip[nam] = address;
483 } 757 }
484 }
485 if (n-nam) n--; // remove trailing .
486 *n = '\0'; // null terminate it
487 register_string(ns, nam, question); // ns host to lookup later
488 }
489 }
490 rrnum = 0;
491 while (ns_parserr(&handle, ns_s_ar, rrnum++, &rr) == 0) {
492 if (ns_rr_type(rr) == ns_t_a) {
493 char* nam = (char*)ns_rr_name(rr);
494 ns_mapper::iterator i = ns.ns_ip.find(nam);
495 if (i != ns.ns_ip.end()) {
496 // we want this ip address
497 int address;
498 memcpy(&address, ns_rr_rdata(rr), sizeof(address));
499 ns.ns_ip[nam] = address;
500 } 758 }
501 } 759 }
502 } 760 }
503 } 761 int rrnum = 0;
504 int rrnum = 0; 762 while (ns_parserr(&handle, ns_s_an, rrnum++, &rr) == 0) {
505 while (ns_parserr(&handle, ns_s_an, rrnum++, &rr) == 0) { 763 if (ns_rr_type(rr) == ns_t_a) {
506 if (ns_rr_type(rr) == ns_t_a) { 764 int address;
507 int address; 765 memcpy(&address, ns_rr_rdata(rr), sizeof(address));
508 memcpy(&address, ns_rr_rdata(rr), sizeof(address)); 766 ret_address = address;
509 return address; 767 }
510 } 768 }
511 } 769 }
512 } 770 }
513 } 771 if (maybe_ip && !ret_address) {
514 if (maybe_ip) { 772 // might be a bare ip address
515 // might be a bare ip address 773 in_addr ip;
516 in_addr ip; 774 if (inet_aton(question, &ip)) {
517 if (inet_aton(question, &ip)) { 775 ret_address = ip.s_addr;
518 return ip.s_addr; 776 }
519 } 777 }
520 } 778 pthread_mutex_unlock(&resolve_mutex);
521 return 0; 779 return ret_address;
780
522 #else 781 #else
523 struct hostent *host = gethostbyname(question); 782 // systems without the resolver interface
524 if (!host) return 0; 783 pthread_mutex_lock(&resolve_mutex);
525 if (host->h_addrtype != AF_INET) return 0; 784 struct hostent *host = gethostbyname(question);
526 int address; 785 if (host && (host->h_addrtype == AF_INET)) {
527 memcpy(&address, host->h_addr, sizeof(address)); 786 memcpy(&ret_address, host->h_addr, sizeof(ret_address));
528 return address; 787 }
788 pthread_mutex_unlock(&resolve_mutex);
789 return ret_address;
529 #endif 790 #endif
530 } 791 }
531 792
532 static int protected_dns_interface(char *question, bool maybe_ip, ns_map *nameservers);
533 static int protected_dns_interface(char *question, bool maybe_ip, ns_map *nameservers) {
534 int ans;
535 pthread_mutex_lock(&resolve_mutex);
536 ans = dns_interface(question, maybe_ip, nameservers);
537 pthread_mutex_unlock(&resolve_mutex);
538 return ans;
539
540 }
541 793
542 //////////////////////////////////////////////// 794 ////////////////////////////////////////////////
543 // check a single dnsbl 795 // check a single dnsbl
544 // 796 //
545 static status check_single(int ip, char *suffix); 797 static status check_single(mlfiPriv &priv, int ip, char *suffix);
546 static status check_single(int ip, char *suffix) { 798 static status check_single(mlfiPriv &priv, int ip, char *suffix) {
547 // make a dns question 799 // make a dns question
548 const u_char *src = (const u_char *)&ip; 800 const u_char *src = (const u_char *)&ip;
549 if (src[0] == 127) return oksofar; // don't do dns lookups on localhost 801 if (src[0] == 127) return oksofar; // don't do dns lookups on localhost
550 #ifdef NS_MAXDNAME 802 #ifdef NS_MAXDNAME
551 char question[NS_MAXDNAME]; 803 char question[NS_MAXDNAME];
552 #else 804 #else
553 char question[1000]; 805 char question[1000];
554 #endif 806 #endif
555 snprintf(question, sizeof(question), "%u.%u.%u.%u.%s.", src[3], src[2], src[1], src[0], suffix); 807 snprintf(question, sizeof(question), "%u.%u.%u.%u.%s.", src[3], src[2], src[1], src[0], suffix);
556 // ask the question, if we get an A record it implies a blacklisted ip address 808 // ask the question, if we get an A record it implies a blacklisted ip address
557 return (protected_dns_interface(question, false, NULL)) ? reject : oksofar; 809 return (dns_interface(priv, question, false, NULL)) ? reject : oksofar;
558 } 810 }
559 811
560 812
561 //////////////////////////////////////////////// 813 ////////////////////////////////////////////////
562 // check a single dnsbl 814 // check a single dnsbl
563 // 815 //
564 static status check_single(int ip, DNSBL &bl); 816 static status check_single(mlfiPriv &priv, int ip, DNSBL &bl);
565 static status check_single(int ip, DNSBL &bl) { 817 static status check_single(mlfiPriv &priv, int ip, DNSBL &bl) {
566 return check_single(ip, bl.suffix); 818 return check_single(priv, ip, bl.suffix);
567 } 819 }
568 820
569 821
570 //////////////////////////////////////////////// 822 ////////////////////////////////////////////////
571 // check the dnsbls specified for this recipient 823 // check the dnsbls specified for this recipient
579 DNSBLP dp = *i; // non null by construction 831 DNSBLP dp = *i; // non null by construction
580 status st; 832 status st;
581 map<DNSBLP, status>::iterator f = priv.checked.find(dp); 833 map<DNSBLP, status>::iterator f = priv.checked.find(dp);
582 if (f == priv.checked.end()) { 834 if (f == priv.checked.end()) {
583 // have not checked this list yet 835 // have not checked this list yet
584 st = check_single(priv.ip, *dp); 836 st = check_single(priv, priv.ip, *dp);
585 rejectlist = dp; 837 rejectlist = dp;
586 priv.checked[dp] = st; 838 priv.checked[dp] = st;
587 } 839 }
588 else { 840 else {
589 st = (*f).second; 841 st = (*f).second;
627 count++; 879 count++;
628 if ((count > lim) && (lim > 0) && (!ran)) { 880 if ((count > lim) && (lim > 0) && (!ran)) {
629 discard(nameservers); 881 discard(nameservers);
630 return reject_host; 882 return reject_host;
631 } 883 }
632 ip = protected_dns_interface(host, true, &nameservers); 884 ip = dns_interface(priv, host, true, &nameservers);
633 if (debug_syslog) { 885 if (debug_syslog) {
634 char buf[1000]; 886 char buf[1000];
635 if (ip) { 887 if (ip) {
636 char adr[sizeof "255.255.255.255"]; 888 char adr[sizeof "255.255.255.255"];
637 adr[0] = '\0'; 889 adr[0] = '\0';
645 } 897 }
646 if (ip) { 898 if (ip) {
647 int_set::iterator i = ips.find(ip); 899 int_set::iterator i = ips.find(ip);
648 if (i == ips.end()) { 900 if (i == ips.end()) {
649 ips.insert(ip); 901 ips.insert(ip);
650 status st = check_single(ip, dc.content_suffix); 902 status st = check_single(priv, ip, dc.content_suffix);
651 if (st == reject) { 903 if (st == reject) {
652 discard(nameservers); 904 discard(nameservers);
653 return st; 905 return st;
654 } 906 }
655 } 907 }
663 discard(nameservers); 915 discard(nameservers);
664 return reject_host; 916 return reject_host;
665 } 917 }
666 host = (*i).first; // a transient reference that needs to be replaced before we return it 918 host = (*i).first; // a transient reference that needs to be replaced before we return it
667 ip = (*i).second; 919 ip = (*i).second;
668 if (!ip) ip = protected_dns_interface(host, false, NULL); 920 if (!ip) ip = dns_interface(priv, host, false, NULL);
669 if (debug_syslog) { 921 if (debug_syslog) {
670 char buf[200]; 922 char buf[200];
671 if (ip) { 923 if (ip) {
672 char adr[sizeof "255.255.255.255"]; 924 char adr[sizeof "255.255.255.255"];
673 adr[0] = '\0'; 925 adr[0] = '\0';
681 } 933 }
682 if (ip) { 934 if (ip) {
683 int_set::iterator i = ips.find(ip); 935 int_set::iterator i = ips.find(ip);
684 if (i == ips.end()) { 936 if (i == ips.end()) {
685 ips.insert(ip); 937 ips.insert(ip);
686 status st = check_single(ip, dc.content_suffix); 938 status st = check_single(priv, ip, dc.content_suffix);
687 if (st == reject) { 939 if (st == reject) {
688 string_map::iterator j = nameservers.ns_host.find(host); 940 string_map::iterator j = nameservers.ns_host.find(host);
689 if (j != nameservers.ns_host.end()) { 941 if (j != nameservers.ns_host.end()) {
690 char *refer = (*j).second; 942 char *refer = (*j).second;
691 char buf[1000]; 943 char buf[1000];
1353 1605
1354 1606
1355 static void usage(char *prog); 1607 static void usage(char *prog);
1356 static void usage(char *prog) 1608 static void usage(char *prog)
1357 { 1609 {
1358 fprintf(stderr, "Usage: %s [-d] [-c] -p socket-addr [-t timeout]\n", prog); 1610 fprintf(stderr, "Usage: %s [-d] [-c] -r port -p sm-sock-addr [-t timeout]\n", prog);
1359 fprintf(stderr, "where socket-addr is for the connection to sendmail and should be one of\n"); 1611 fprintf(stderr, "where port is for the connection to our own dns resolver processes\n");
1360 fprintf(stderr, " inet:port@local-ip-address\n"); 1612 fprintf(stderr, "where sm-sock-addr is for the connection to sendmail\n");
1361 fprintf(stderr, " local:local-domain-socket-file-name\n"); 1613 fprintf(stderr, " and should be one of\n");
1614 fprintf(stderr, " inet:port@ip-address\n");
1615 fprintf(stderr, " local:local-domain-socket-file-name\n");
1362 fprintf(stderr, "-c will load and dump the config to stdout\n"); 1616 fprintf(stderr, "-c will load and dump the config to stdout\n");
1363 fprintf(stderr, "-d will add some syslog debug messages\n"); 1617 fprintf(stderr, "-d will add some syslog debug messages\n");
1364 } 1618 }
1365 1619
1366 1620
1380 1634
1381 int main(int argc, char**argv) 1635 int main(int argc, char**argv)
1382 { 1636 {
1383 bool check = false; 1637 bool check = false;
1384 bool setconn = false; 1638 bool setconn = false;
1639 bool setreso = false;
1385 int c; 1640 int c;
1386 const char *args = "p:t:hcd"; 1641 const char *args = "r:p:t:hcd";
1387 extern char *optarg; 1642 extern char *optarg;
1388 1643
1389 // Process command line options 1644 // Process command line options
1390 while ((c = getopt(argc, argv, args)) != -1) { 1645 while ((c = getopt(argc, argv, args)) != -1) {
1391 switch (c) { 1646 switch (c) {
1647 case 'r':
1648 if (optarg == NULL || *optarg == '\0') {
1649 fprintf(stderr, "Illegal resolver socket: %s\n", optarg);
1650 exit(EX_USAGE);
1651 }
1652 resolver_port = atoi(optarg);
1653 setreso = true;
1654 break;
1655
1392 case 'p': 1656 case 'p':
1393 if (optarg == NULL || *optarg == '\0') { 1657 if (optarg == NULL || *optarg == '\0') {
1394 fprintf(stderr, "Illegal conn: %s\n", optarg); 1658 fprintf(stderr, "Illegal sendmail socket: %s\n", optarg);
1395 exit(EX_USAGE); 1659 exit(EX_USAGE);
1396 } 1660 }
1397 if (smfi_setconn(optarg) == MI_FAILURE) { 1661 if (smfi_setconn(optarg) == MI_FAILURE) {
1398 fprintf(stderr, "smfi_setconn failed\n"); 1662 fprintf(stderr, "smfi_setconn failed\n");
1399 exit(EX_SOFTWARE); 1663 exit(EX_SOFTWARE);
1400 } 1664 }
1401
1402 if (strncasecmp(optarg, "unix:", 5) == 0) setup_socket(optarg + 5); 1665 if (strncasecmp(optarg, "unix:", 5) == 0) setup_socket(optarg + 5);
1403 else if (strncasecmp(optarg, "local:", 6) == 0) setup_socket(optarg + 6); 1666 else if (strncasecmp(optarg, "local:", 6) == 0) setup_socket(optarg + 6);
1404 setconn = true; 1667 setconn = true;
1405 break; 1668 break;
1406 1669
1436 return 0; 1699 return 0;
1437 } 1700 }
1438 1701
1439 if (!setconn) { 1702 if (!setconn) {
1440 fprintf(stderr, "%s: Missing required -p argument\n", argv[0]); 1703 fprintf(stderr, "%s: Missing required -p argument\n", argv[0]);
1704 usage(argv[0]);
1705 exit(EX_USAGE);
1706 }
1707
1708 if (!setreso) {
1709 fprintf(stderr, "%s: Missing required -r argument\n", argv[0]);
1441 usage(argv[0]); 1710 usage(argv[0]);
1442 exit(EX_USAGE); 1711 exit(EX_USAGE);
1443 } 1712 }
1444 1713
1445 if (smfi_register(smfilter) == MI_FAILURE) { 1714 if (smfi_register(smfilter) == MI_FAILURE) {
1472 fprintf(f, "%d\n", (u_int)getpid()); 1741 fprintf(f, "%d\n", (u_int)getpid());
1473 #endif 1742 #endif
1474 fclose(f); 1743 fclose(f);
1475 } 1744 }
1476 1745
1746 // initialize the thread sync objects
1747 pthread_mutex_init(&config_mutex, 0);
1748 pthread_mutex_init(&syslog_mutex, 0);
1749 pthread_mutex_init(&resolve_mutex, 0);
1750 pthread_mutex_init(&fd_pool_mutex, 0);
1751
1752 #ifdef NS_PACKETSZ
1753 // fork off the resolver listener process
1754 pid_t child = fork();
1755 if (child < 0) {
1756 my_syslog("failed to create resolver listener process");
1757 exit(0);
1758 }
1759 if (child == 0) {
1760 // we are the child - dns resolver listener process
1761 resolver_socket = socket(PF_INET, SOCK_STREAM, 0);
1762 if (resolver_socket < 0) {
1763 my_syslog("child failed to create resolver socket");
1764 exit(0); // failed
1765 }
1766 sockaddr_in server;
1767 server.sin_family = AF_INET;
1768 server.sin_port = htons(resolver_port);
1769 server.sin_addr.s_addr = 0;
1770 // set the socket options
1771 int reuse_addr = 1;
1772 linger linger_opt;
1773 linger_opt.l_onoff = 0; // off
1774 linger_opt.l_linger = 0;
1775 setsockopt(resolver_socket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&reuse_addr), sizeof(reuse_addr));
1776 setsockopt(resolver_socket, SOL_SOCKET, SO_LINGER, reinterpret_cast<char*>(&linger_opt), sizeof(linger_opt));
1777 ///// set nonblocking mode
1778 ///int dummy = 0;
1779 ///int flags = fcntl(resolver_socket, F_GETFL, dummy);
1780 ///if (flags >= 0) fcntl(resolver_socket, F_SETFL, flags | O_NONBLOCK);
1781 //try to bind the address to the socket.
1782 if (bind(resolver_socket, (sockaddr *)&server, sizeof(server)) < 0) {
1783 // bind failed
1784 shutdown(resolver_socket, SHUT_RDWR);
1785 close(resolver_socket);
1786 my_syslog("child failed to bind resolver socket");
1787 exit(0); // failed
1788 }
1789
1790 //listen on the socket.
1791 if (listen(resolver_socket, 10) < 0) {
1792 // listen failed
1793 shutdown(resolver_socket, SHUT_RDWR);
1794 close(resolver_socket);
1795 my_syslog("child failed to listen to the resolver socket");
1796 return -1;
1797 }
1798 }
1799 else {
1800 sleep(2); // allow child to get started
1801 }
1802 #endif
1803
1477 // drop root privs 1804 // drop root privs
1478 struct passwd *pw = getpwnam("dnsbl"); 1805 struct passwd *pw = getpwnam("dnsbl");
1479 if (pw) { 1806 if (pw) {
1480 if (setgid(pw->pw_gid) == -1) { 1807 if (setgid(pw->pw_gid) == -1) {
1481 my_syslog("failed to switch to group dnsbl"); 1808 my_syslog("failed to switch to group dnsbl");
1483 if (setuid(pw->pw_uid) == -1) { 1810 if (setuid(pw->pw_uid) == -1) {
1484 my_syslog("failed to switch to user dnsbl"); 1811 my_syslog("failed to switch to user dnsbl");
1485 } 1812 }
1486 } 1813 }
1487 1814
1488 // initialize the thread sync objects 1815 #ifdef NS_PACKETSZ
1489 pthread_mutex_init(&config_mutex, 0); 1816 if (child == 0) {
1490 pthread_mutex_init(&syslog_mutex, 0); 1817 while (true) {
1491 pthread_mutex_init(&resolve_mutex, 0); 1818 sockaddr_in client;
1819 socklen_t clientlen = sizeof(client);
1820 int s = accept(resolver_socket, (sockaddr *)&client, &clientlen);
1821 if (s > 0) {
1822 // accept worked, it did not get cancelled before we could accept it
1823 // fork off a process to handle this connection
1824 int newchild = fork();
1825 if (newchild == 0) {
1826 // this is the worker process
1827 my_syslog("child forked a worker process");
1828 process_resolver_requests(s);
1829 my_syslog("child terminated a worker process");
1830 exit(0);
1831 }
1832 }
1833 }
1834 exit(0); // make sure we don't fall thru.
1835 }
1836 #endif
1492 1837
1493 // load the initial config 1838 // load the initial config
1494 config = new_conf(); 1839 config = new_conf();
1495 1840
1496 // only create threads after the fork() in daemon 1841 // only create threads after the fork() in daemon