summaryrefslogtreecommitdiff
path: root/source3/nmbd/asyncdns.c
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>1997-10-22 11:02:00 +0000
committerAndrew Tridgell <tridge@samba.org>1997-10-22 11:02:00 +0000
commite5c319186d079eeef55a7ee62fac2a993e932938 (patch)
treec8f01f398f801ecfa5a3a97ff5ca45ece501f459 /source3/nmbd/asyncdns.c
parentbda8cac802414eb15122cc7ad2f0082bcca177d5 (diff)
downloadsamba-e5c319186d079eeef55a7ee62fac2a993e932938.tar.gz
samba-e5c319186d079eeef55a7ee62fac2a993e932938.tar.bz2
samba-e5c319186d079eeef55a7ee62fac2a993e932938.zip
Implemented asynchronous DNS lookups in nmbd.
I realised this afternoon just how easy it is to add this, so I thought I'd implement it while the idea was fresh. nmbd forks at startup and uses a pipe to talk to its child. The child does the DNS lookups and the file descriptor of the child is added to the main select loop. While I was doing this I discovered a bug in nmbd that explains why the dns proxy option has been so expensive. The DNS cache entries in the WINS list were never being checked, which means we always did a DNS lookup even if we have done it before and it is in cache. I'm sure this used to work (I tested the DNS cache when I added it) so someone broke it :-( Anyway, the async DNS gets rid of the problem completely. I'll commit just the fix to the DNS cache bug to the 1.9.17 tree. You can disable async DNS by adding -DSYNC_DNS to the compile flags. (This used to be commit 178e27de0791c1ff3268cb456ed5c5efc9ac2a01)
Diffstat (limited to 'source3/nmbd/asyncdns.c')
-rw-r--r--source3/nmbd/asyncdns.c257
1 files changed, 257 insertions, 0 deletions
diff --git a/source3/nmbd/asyncdns.c b/source3/nmbd/asyncdns.c
new file mode 100644
index 0000000000..548781edea
--- /dev/null
+++ b/source3/nmbd/asyncdns.c
@@ -0,0 +1,257 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ a async DNS handler
+ Copyright (C) Andrew Tridgell 1994-1997
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+
+/***************************************************************************
+ add a DNS result to the name cache
+ ****************************************************************************/
+static struct name_record *add_dns_result(struct nmb_name *question, struct in_addr addr)
+{
+ int name_type = question->name_type;
+ char *qname = question->name;
+
+ if (!addr.s_addr) {
+ /* add the fail to WINS cache of names. give it 1 hour in the cache */
+ DEBUG(3,("Negative DNS answer for %s\n", qname));
+ add_netbios_entry(wins_subnet,qname,name_type,NB_ACTIVE,60*60,DNSFAIL,addr,
+ True, True);
+ return NULL;
+ }
+
+ /* add it to our WINS cache of names. give it 2 hours in the cache */
+ DEBUG(3,("DNS gave answer for %s of %s\n", qname, inet_ntoa(addr)));
+
+ return add_netbios_entry(wins_subnet,qname,name_type,NB_ACTIVE,2*60*60,DNS,addr,
+ True,True);
+}
+
+
+
+#ifndef SYNC_DNS
+
+static int fd_in = -1, fd_out = -1;
+static int child_pid = -1;
+static int in_dns;
+
+/* this is the structure that is passed between the parent and child */
+struct query_record {
+ struct nmb_name name;
+ struct in_addr result;
+};
+
+/* a queue of pending requests waiting for DNS responses */
+static struct packet_struct *dns_queue;
+
+
+
+/***************************************************************************
+ return the fd used to gather async dns replies. This is added to the select
+ loop
+ ****************************************************************************/
+int asyncdns_fd(void)
+{
+ return fd_in;
+}
+
+/***************************************************************************
+ handle DNS queries arriving from the parent
+ ****************************************************************************/
+static void asyncdns_process(void)
+{
+ struct query_record r;
+ fstring qname;
+
+ DEBUGLEVEL = 0;
+
+ while (1) {
+ if (read_data(fd_in, (char *)&r, sizeof(r)) != sizeof(r))
+ break;
+
+ fstrcpy(qname, r.name.name);
+
+ r.result.s_addr = interpret_addr(qname);
+
+ if (write_data(fd_out, (char *)&r, sizeof(r)) != sizeof(r))
+ break;
+ }
+
+ exit(0);
+}
+
+
+/***************************************************************************
+ create a child process to handle DNS lookups
+ ****************************************************************************/
+void start_async_dns(void)
+{
+ int fd1[2], fd2[2];
+
+ signal(SIGCLD, SIG_IGN);
+
+ if (pipe(fd1) || pipe(fd2)) {
+ return;
+ }
+
+ child_pid = fork();
+
+ if (child_pid) {
+ fd_in = fd1[0];
+ fd_out = fd2[1];
+ close(fd1[1]);
+ close(fd2[0]);
+ DEBUG(3,("async DNS initialised\n"));
+ return;
+ }
+
+ fd_in = fd2[0];
+ fd_out = fd1[1];
+
+ asyncdns_process();
+}
+
+
+/***************************************************************************
+check if a particular name is already being queried
+ ****************************************************************************/
+static BOOL query_in_queue(struct query_record *r)
+{
+ struct packet_struct *p;
+ for (p = dns_queue; p; p = p->next) {
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
+
+ if (name_equal(question, &r->name))
+ return True;
+ }
+ return False;
+}
+
+
+/***************************************************************************
+ check the DNS queue
+ ****************************************************************************/
+void run_dns_queue(void)
+{
+ struct query_record r;
+ struct packet_struct *p, *p2;
+
+ if (fd_in == -1)
+ return;
+
+ if (read_data(fd_in, (char *)&r, sizeof(r)) != sizeof(r)) {
+ DEBUG(0,("Incomplete DNS answer from child!\n"));
+ fd_in = -1;
+ return;
+ }
+
+ add_dns_result(&r.name, r.result);
+
+ /* loop over the whole dns queue looking for entries that
+ match the result we just got */
+ for (p = dns_queue; p;) {
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
+
+ if (name_equal(question, &r.name)) {
+ DEBUG(3,("DNS calling reply_name_query\n"));
+ in_dns = 1;
+ reply_name_query(p);
+ in_dns = 0;
+ p->locked = False;
+
+ if (p->prev)
+ p->prev->next = p->next;
+ else
+ dns_queue = p->next;
+ if (p->next)
+ p->next->prev = p->prev;
+ p2 = p->next;
+ free_packet(p);
+ p = p2;
+ } else {
+ p = p->next;
+ }
+ }
+
+}
+
+/***************************************************************************
+queue a DNS query
+ ****************************************************************************/
+BOOL queue_dns_query(struct packet_struct *p,struct nmb_name *question,
+ struct name_record **n)
+{
+ struct query_record r;
+
+ if (in_dns || fd_in == -1)
+ return False;
+
+ r.name = *question;
+
+ if (!query_in_queue(&r) &&
+ !write_data(fd_out, (char *)&r, sizeof(r))) {
+ DEBUG(3,("failed to send DNS query to child!\n"));
+ return False;
+ }
+
+ p->locked = True;
+ p->next = dns_queue;
+ p->prev = NULL;
+ if (p->next)
+ p->next->prev = p;
+ dns_queue = p;
+
+
+ DEBUG(3,("added DNS query for %s\n", namestr(question)));
+ return True;
+}
+
+#else
+
+
+/***************************************************************************
+ we use this then we can't do async DNS lookups
+ ****************************************************************************/
+BOOL queue_dns_query(struct packet_struct *p,struct nmb_name *question,
+ struct name_record **n)
+{
+ int name_type = question->name_type;
+ char *qname = question->name;
+ struct in_addr dns_ip;
+
+ DEBUG(3,("DNS search for %s - ", namestr(question)));
+
+ dns_ip.s_addr = interpret_addr(qname);
+
+ *n = add_dns_result(question, dns_ip);
+ return False;
+}
+#endif