Mercurial > dnsbl
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(); |