comparison src/dnsbl.cpp @ 60:390ed250c5d2 stable-4-1

use local unix domain socket for resolver process communication
author carl
date Thu, 06 Jan 2005 11:35:38 -0800
parents 510a511ad554
children 7f44a4974bf6
comparison
equal deleted inserted replaced
59:510a511ad554 60:390ed250c5d2
199 static pthread_mutex_t resolve_mutex; 199 static pthread_mutex_t resolve_mutex;
200 static pthread_mutex_t fd_pool_mutex; 200 static pthread_mutex_t fd_pool_mutex;
201 static std::set<int> fd_pool; 201 static std::set<int> fd_pool;
202 202
203 static int NULL_SOCKET = -1; 203 static int NULL_SOCKET = -1;
204 static int resolver_port = 0; // global port number to talk to the dns resolver process 204 static char *resolver_port = NULL; // unix domain socket to talk to the dns resolver process
205 static int resolver_socket = NULL_SOCKET; // socket used to listen for resolver requests 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 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; 207 static time_t last_error_time;
208 208
209 #ifdef NS_PACKETSZ 209 #ifdef NS_PACKETSZ
303 time_t now = time(NULL); 303 time_t now = time(NULL);
304 if ((now - last_error_time) < ERROR_SOCKET_TIME) return NULL_SOCKET; 304 if ((now - last_error_time) < ERROR_SOCKET_TIME) return NULL_SOCKET;
305 305
306 // nothing recent, maybe this time it will work 306 // nothing recent, maybe this time it will work
307 int sock = NULL_SOCKET; 307 int sock = NULL_SOCKET;
308 hostent *host = gethostbyname("localhost"); 308 sockaddr_un server;
309 if (host) { 309 memset(&server, '\0', sizeof(server));
310 sockaddr_in server; 310 server.sun_family = AF_UNIX;
311 server.sin_family = host->h_addrtype; 311 strncpy(server.sun_path, resolver_port, sizeof(server.sun_path)-1);
312 server.sin_port = htons(resolver_port); 312 sock = socket(AF_UNIX, SOCK_STREAM, 0);
313 memcpy(&server.sin_addr, host->h_addr_list[0], host->h_length); 313 if (sock != NULL_SOCKET) {
314 sock = socket(PF_INET, SOCK_STREAM, 0); 314 bool rc = (connect(sock, (sockaddr *)&server, sizeof(server)) == 0);
315 if (sock != NULL_SOCKET) { 315 if (!rc) {
316 bool rc = (connect(sock, (sockaddr *)&server, sizeof(server)) == 0); 316 int er = errno;
317 if (!rc) { 317 my_disconnect(sock);
318 int er = errno; 318 sock = NULL_SOCKET;
319 my_disconnect(sock); 319 last_error_time = now;
320 sock = NULL_SOCKET; 320 }
321 last_error_time = now; 321 }
322 } 322 else last_error_time = now;
323 }
324 else last_error_time = now;
325 }
326 return sock; 323 return sock;
327 } 324 }
328 325
329 326
330 //////////////////////////////////////////////// 327 ////////////////////////////////////////////////
635 break; 632 break;
636 } 633 }
637 } 634 }
638 else { 635 else {
639 // peer closed the socket 636 // peer closed the socket
640 //my_syslog("child worker process, peer closed socket while reading question"); 637 //my_syslog("!!child worker process, peer closed socket while reading question");
641 shutdown(socket, SHUT_RDWR); 638 shutdown(socket, SHUT_RDWR);
642 close(socket); 639 close(socket);
643 return; 640 return;
644 } 641 }
645 } 642 }
646 643
647 // find the answer 644 // find the answer
648 //char text[1000]; 645 //char text[1000];
649 //snprintf(text, sizeof(text), "child worker process has a question %s", question); 646 //snprintf(text, sizeof(text), "!!child worker process has a question %s", question);
650 //my_syslog(text); 647 //my_syslog(text);
651 glom.length = res_search(question, ns_c_in, ns_t_a, glom.answer, sizeof(glom.answer)); 648 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 649 if (glom.length < 0) glom.length = 0; // represent all errors as zero length answers
653 650
654 // write the answer 651 // write the answer
655 char *buf = (char *)&glom; 652 char *buf = (char *)&glom;
656 int len = glom.length + sizeof(glom.length); 653 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); 654 //snprintf(text, sizeof(text), "!!child worker process writing answer length %d for total %d", glom.length, len);
658 //my_syslog(text); 655 //my_syslog(text);
659 int ws = 0; 656 int ws = 0;
660 while (len > ws) { 657 while (len > ws) {
661 int ns = write(socket, buf+ws, len-ws); 658 int ns = write(socket, buf+ws, len-ws);
662 if (ns > 0) { 659 if (ns > 0) {
663 ws += ns; 660 ws += ns;
664 } 661 }
665 else { 662 else {
666 // peer closed the socket! 663 // peer closed the socket!
667 //my_syslog("child worker process, peer closed socket while writing answer"); 664 //my_syslog("!!child worker process, peer closed socket while writing answer");
668 shutdown(socket, SHUT_RDWR); 665 shutdown(socket, SHUT_RDWR);
669 close(socket); 666 close(socket);
670 return; 667 return;
671 } 668 }
672 } 669 }
693 priv.my_write(question, strlen(question)+1); // write the question including the null terminator 690 priv.my_write(question, strlen(question)+1); // write the question including the null terminator
694 glommer glom; 691 glommer glom;
695 char *buf = (char *)&glom; 692 char *buf = (char *)&glom;
696 priv.my_read(buf, sizeof(glom.length)); 693 priv.my_read(buf, sizeof(glom.length));
697 buf += sizeof(glom.length); 694 buf += sizeof(glom.length);
698 //char text[1000]; 695 ///char text[1000];
699 //snprintf(text, sizeof(text), "milter thread wrote question %s and has answer length %d", question, glom.length); 696 ///snprintf(text, sizeof(text), "!!milter thread wrote question %s and has answer length %d", question, glom.length);
700 //my_syslog(text); 697 ///my_syslog(text);
701 if ((glom.length < 0) || (glom.length > sizeof(glom.answer))) { 698 if ((glom.length < 0) || (glom.length > sizeof(glom.answer))) {
702 priv.err = true; 699 priv.err = true;
703 return 0; // cannot process overlarge answers 700 return 0; // cannot process overlarge answers
704 } 701 }
705 priv.my_read(buf, glom.length); 702 priv.my_read(buf, glom.length);
1607 static void usage(char *prog); 1604 static void usage(char *prog);
1608 static void usage(char *prog) 1605 static void usage(char *prog)
1609 { 1606 {
1610 fprintf(stderr, "Usage: %s [-d] [-c] -r port -p sm-sock-addr [-t timeout]\n", prog); 1607 fprintf(stderr, "Usage: %s [-d] [-c] -r port -p sm-sock-addr [-t timeout]\n", prog);
1611 fprintf(stderr, "where port is for the connection to our own dns resolver processes\n"); 1608 fprintf(stderr, "where port is for the connection to our own dns resolver processes\n");
1609 fprintf(stderr, " and should be local-domain-socket-file-name\n");
1612 fprintf(stderr, "where sm-sock-addr is for the connection to sendmail\n"); 1610 fprintf(stderr, "where sm-sock-addr is for the connection to sendmail\n");
1613 fprintf(stderr, " and should be one of\n"); 1611 fprintf(stderr, " and should be one of\n");
1614 fprintf(stderr, " inet:port@ip-address\n"); 1612 fprintf(stderr, " inet:port@ip-address\n");
1615 fprintf(stderr, " local:local-domain-socket-file-name\n"); 1613 fprintf(stderr, " local:local-domain-socket-file-name\n");
1616 fprintf(stderr, "-c will load and dump the config to stdout\n"); 1614 fprintf(stderr, "-c will load and dump the config to stdout\n");
1620 1618
1621 1619
1622 static void setup_socket(char *sock); 1620 static void setup_socket(char *sock);
1623 static void setup_socket(char *sock) { 1621 static void setup_socket(char *sock) {
1624 unlink(sock); 1622 unlink(sock);
1625 // sockaddr_un addr; 1623 // sockaddr_un addr;
1626 // memset(&addr, '\0', sizeof addr); 1624 // memset(&addr, '\0', sizeof addr);
1627 // addr.sun_family = AF_UNIX; 1625 // addr.sun_family = AF_UNIX;
1628 // strncpy(addr.sun_path, sock, sizeof(addr.sun_path)-1); 1626 // strncpy(addr.sun_path, sock, sizeof(addr.sun_path)-1);
1629 // int s = socket(AF_UNIX, SOCK_STREAM, 0); 1627 // int s = socket(AF_UNIX, SOCK_STREAM, 0);
1630 // bind(s, (sockaddr*)&addr, sizeof(addr)); 1628 // bind(s, (sockaddr*)&addr, sizeof(addr));
1631 // close(s); 1629 // close(s);
1632 } 1630 }
1633 1631
1634 1632
1635 int main(int argc, char**argv) 1633 int main(int argc, char**argv)
1636 { 1634 {
1647 case 'r': 1645 case 'r':
1648 if (optarg == NULL || *optarg == '\0') { 1646 if (optarg == NULL || *optarg == '\0') {
1649 fprintf(stderr, "Illegal resolver socket: %s\n", optarg); 1647 fprintf(stderr, "Illegal resolver socket: %s\n", optarg);
1650 exit(EX_USAGE); 1648 exit(EX_USAGE);
1651 } 1649 }
1652 resolver_port = atoi(optarg); 1650 resolver_port = strdup(optarg);
1651 setup_socket(resolver_port);
1653 setreso = true; 1652 setreso = true;
1654 break; 1653 break;
1655 1654
1656 case 'p': 1655 case 'p':
1657 if (optarg == NULL || *optarg == '\0') { 1656 if (optarg == NULL || *optarg == '\0') {
1747 pthread_mutex_init(&config_mutex, 0); 1746 pthread_mutex_init(&config_mutex, 0);
1748 pthread_mutex_init(&syslog_mutex, 0); 1747 pthread_mutex_init(&syslog_mutex, 0);
1749 pthread_mutex_init(&resolve_mutex, 0); 1748 pthread_mutex_init(&resolve_mutex, 0);
1750 pthread_mutex_init(&fd_pool_mutex, 0); 1749 pthread_mutex_init(&fd_pool_mutex, 0);
1751 1750
1751 // drop root privs
1752 struct passwd *pw = getpwnam("dnsbl");
1753 if (pw) {
1754 if (setgid(pw->pw_gid) == -1) {
1755 my_syslog("failed to switch to group dnsbl");
1756 }
1757 if (setuid(pw->pw_uid) == -1) {
1758 my_syslog("failed to switch to user dnsbl");
1759 }
1760 }
1761
1752 #ifdef NS_PACKETSZ 1762 #ifdef NS_PACKETSZ
1753 // fork off the resolver listener process 1763 // fork off the resolver listener process
1754 pid_t child = fork(); 1764 pid_t child = fork();
1755 if (child < 0) { 1765 if (child < 0) {
1756 my_syslog("failed to create resolver listener process"); 1766 my_syslog("failed to create resolver listener process");
1757 exit(0); 1767 exit(0);
1758 } 1768 }
1759 if (child == 0) { 1769 if (child == 0) {
1760 // we are the child - dns resolver listener process 1770 // we are the child - dns resolver listener process
1761 resolver_socket = socket(PF_INET, SOCK_STREAM, 0); 1771 resolver_socket = socket(AF_UNIX, SOCK_STREAM, 0);
1762 if (resolver_socket < 0) { 1772 if (resolver_socket < 0) {
1763 my_syslog("child failed to create resolver socket"); 1773 my_syslog("child failed to create resolver socket");
1764 exit(0); // failed 1774 exit(0); // failed
1765 } 1775 }
1766 sockaddr_in server; 1776 sockaddr_un server;
1767 server.sin_family = AF_INET; 1777 memset(&server, '\0', sizeof(server));
1768 server.sin_port = htons(resolver_port); 1778 server.sun_family = AF_UNIX;
1769 server.sin_addr.s_addr = 0; 1779 strncpy(server.sun_path, resolver_port, sizeof(server.sun_path)-1);
1770 // set the socket options 1780 // set the socket options
1771 int reuse_addr = 1; 1781 ///int reuse_addr = 1;
1772 linger linger_opt; 1782 ///linger linger_opt;
1773 linger_opt.l_onoff = 0; // off 1783 ///linger_opt.l_onoff = 0; // off
1774 linger_opt.l_linger = 0; 1784 ///linger_opt.l_linger = 0;
1775 setsockopt(resolver_socket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&reuse_addr), sizeof(reuse_addr)); 1785 ///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)); 1786 ///setsockopt(resolver_socket, SOL_SOCKET, SO_LINGER, reinterpret_cast<char*>(&linger_opt), sizeof(linger_opt));
1777 ///// set nonblocking mode 1787 ///// set nonblocking mode
1778 ///int dummy = 0; 1788 ///int dummy = 0;
1779 ///int flags = fcntl(resolver_socket, F_GETFL, dummy); 1789 ///int flags = fcntl(resolver_socket, F_GETFL, dummy);
1780 ///if (flags >= 0) fcntl(resolver_socket, F_SETFL, flags | O_NONBLOCK); 1790 ///if (flags >= 0) fcntl(resolver_socket, F_SETFL, flags | O_NONBLOCK);
1781 //try to bind the address to the socket. 1791 //try to bind the address to the socket.
1791 if (listen(resolver_socket, 10) < 0) { 1801 if (listen(resolver_socket, 10) < 0) {
1792 // listen failed 1802 // listen failed
1793 shutdown(resolver_socket, SHUT_RDWR); 1803 shutdown(resolver_socket, SHUT_RDWR);
1794 close(resolver_socket); 1804 close(resolver_socket);
1795 my_syslog("child failed to listen to the resolver socket"); 1805 my_syslog("child failed to listen to the resolver socket");
1796 return -1; 1806 exit(0); // failed
1797 } 1807 }
1798 }
1799 else {
1800 sleep(2); // allow child to get started
1801 }
1802 #endif
1803
1804 // drop root privs
1805 struct passwd *pw = getpwnam("dnsbl");
1806 if (pw) {
1807 if (setgid(pw->pw_gid) == -1) {
1808 my_syslog("failed to switch to group dnsbl");
1809 }
1810 if (setuid(pw->pw_uid) == -1) {
1811 my_syslog("failed to switch to user dnsbl");
1812 }
1813 }
1814
1815 #ifdef NS_PACKETSZ
1816 if (child == 0) {
1817 while (true) { 1808 while (true) {
1818 sockaddr_in client; 1809 sockaddr_un client;
1819 socklen_t clientlen = sizeof(client); 1810 socklen_t clientlen = sizeof(client);
1820 int s = accept(resolver_socket, (sockaddr *)&client, &clientlen); 1811 int s = accept(resolver_socket, (sockaddr *)&client, &clientlen);
1821 if (s > 0) { 1812 if (s > 0) {
1822 // accept worked, it did not get cancelled before we could accept it 1813 // accept worked, it did not get cancelled before we could accept it
1823 // fork off a process to handle this connection 1814 // fork off a process to handle this connection
1824 int newchild = fork(); 1815 int newchild = fork();
1825 if (newchild == 0) { 1816 if (newchild == 0) {
1826 // this is the worker process 1817 // this is the worker process
1818 // child does not need the listening socket
1819 close(resolver_socket);
1827 my_syslog("child forked a worker process"); 1820 my_syslog("child forked a worker process");
1828 process_resolver_requests(s); 1821 process_resolver_requests(s);
1829 my_syslog("child terminated a worker process"); 1822 my_syslog("child terminated a worker process");
1830 exit(0); 1823 exit(0);
1831 } 1824 }
1825 else {
1826 // this is the parent
1827 // parent does not need the accepted socket
1828 close(s);
1829 }
1832 } 1830 }
1833 } 1831 }
1834 exit(0); // make sure we don't fall thru. 1832 exit(0); // make sure we don't fall thru.
1833 }
1834 else {
1835 sleep(2); // allow child to get started
1835 } 1836 }
1836 #endif 1837 #endif
1837 1838
1838 // load the initial config 1839 // load the initial config
1839 config = new_conf(); 1840 config = new_conf();