summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/nameserv.h23
-rw-r--r--source3/libsmb/nmblib.c9
-rw-r--r--source3/namedbname.c49
-rw-r--r--source3/namepacket.c55
-rw-r--r--source3/nameservreply.c32
-rw-r--r--source3/nmbd/asyncdns.c257
-rw-r--r--source3/nmbd/nmbd.c13
-rw-r--r--source3/utils/nmblookup.c9
8 files changed, 340 insertions, 107 deletions
diff --git a/source3/include/nameserv.h b/source3/include/nameserv.h
index ecd19b9563..5c8ec1e4eb 100644
--- a/source3/include/nameserv.h
+++ b/source3/include/nameserv.h
@@ -363,17 +363,18 @@ struct dgram_packet {
list of nmb packets */
struct packet_struct
{
- struct packet_struct *next;
- struct packet_struct *prev;
- struct in_addr ip;
- int port;
- int fd;
- time_t timestamp;
- enum packet_type packet_type;
- union {
- struct nmb_packet nmb;
- struct dgram_packet dgram;
- } packet;
+ struct packet_struct *next;
+ struct packet_struct *prev;
+ BOOL locked;
+ struct in_addr ip;
+ int port;
+ int fd;
+ time_t timestamp;
+ enum packet_type packet_type;
+ union {
+ struct nmb_packet nmb;
+ struct dgram_packet dgram;
+ } packet;
};
/* NETLOGON opcodes */
diff --git a/source3/libsmb/nmblib.c b/source3/libsmb/nmblib.c
index e8f281bc25..121008685b 100644
--- a/source3/libsmb/nmblib.c
+++ b/source3/libsmb/nmblib.c
@@ -482,9 +482,11 @@ void free_nmb_packet(struct nmb_packet *nmb)
******************************************************************/
void free_packet(struct packet_struct *packet)
{
- if (packet->packet_type == NMB_PACKET)
- free_nmb_packet(&packet->packet.nmb);
- free(packet);
+ if (packet->locked)
+ return;
+ if (packet->packet_type == NMB_PACKET)
+ free_nmb_packet(&packet->packet.nmb);
+ free(packet);
}
/*******************************************************************
@@ -511,6 +513,7 @@ struct packet_struct *read_packet(int fd,enum packet_type packet_type)
packet->ip = lastip;
packet->port = lastport;
packet->fd = fd;
+ packet->locked = False;
packet->timestamp = time(NULL);
packet->packet_type = packet_type;
switch (packet_type)
diff --git a/source3/namedbname.c b/source3/namedbname.c
index 51571d786a..f126b4651c 100644
--- a/source3/namedbname.c
+++ b/source3/namedbname.c
@@ -166,8 +166,8 @@ struct name_record *find_name(struct name_record *n,
{
continue;
}
- DEBUG(9,("find_name: found name %s(%02x)\n",
- name->name, name->name_type));
+ DEBUG(9,("find_name: found name %s(%02x) source=%d\n",
+ name->name, name->name_type, ret->source));
return ret;
}
}
@@ -185,8 +185,8 @@ struct name_record *find_name(struct name_record *n,
FIND_WINS - look for names in the WINS record
**************************************************************************/
struct name_record *find_name_search(struct subnet_record **d,
- struct nmb_name *name,
- int search, struct in_addr ip)
+ struct nmb_name *name,
+ int search, struct in_addr ip)
{
if (d == NULL) return NULL; /* bad error! */
@@ -558,44 +558,3 @@ void expire_names(time_t t)
}
-/***************************************************************************
- assume a WINS name is a dns name, and do a gethostbyname() on it.
- ****************************************************************************/
-struct name_record *dns_name_search(struct nmb_name *question, int Time)
-{
- int name_type = question->name_type;
- char *qname = question->name;
- BOOL dns_type = (name_type == 0x20 || name_type == 0);
- struct in_addr dns_ip;
-
- if (wins_subnet == NULL)
- return NULL;
-
- DEBUG(3,("Search for %s - ", namestr(question)));
-
- /* only do DNS lookups if the query is for type 0x20 or type 0x0 */
- if (!dns_type)
- {
- DEBUG(3,("types 0x20 0x0 only: name not found\n"));
- return NULL;
- }
-
- /* look it up with DNS */
- dns_ip.s_addr = interpret_addr(qname);
-
- if (!dns_ip.s_addr)
- {
- /* no luck with DNS. We could possibly recurse here XXXX */
- DEBUG(3,("not found. no recursion.\n"));
- /* add the fail to WINS cache of names. give it 1 hour in the cache */
- add_netbios_entry(wins_subnet,qname,name_type,NB_ACTIVE,60*60,DNSFAIL,dns_ip,
- True, True);
- return NULL;
- }
-
- DEBUG(3,("found with DNS: %s\n", inet_ntoa(dns_ip)));
-
- /* add it to our WINS cache of names. give it 2 hours in the cache */
- return add_netbios_entry(wins_subnet,qname,name_type,NB_ACTIVE,2*60*60,DNS,dns_ip,
- True,True);
-}
diff --git a/source3/namepacket.c b/source3/namepacket.c
index 3a23806a9c..c510c21169 100644
--- a/source3/namepacket.c
+++ b/source3/namepacket.c
@@ -171,6 +171,7 @@ void initiate_netbios_packet(uint16 *id,
p.fd = fd;
p.timestamp = time(NULL);
p.packet_type = NMB_PACKET;
+ p.locked = False;
debug_nmb_packet(&p);
@@ -482,32 +483,31 @@ static void process_nmb(struct packet_struct *p)
******************************************************************/
void run_packet_queue()
{
- struct packet_struct *p;
-
- while ((p=packet_queue))
- {
- switch (p->packet_type)
- {
- case NMB_PACKET:
- process_nmb(p);
- break;
-
- case DGRAM_PACKET:
- process_dgram(p);
- break;
+ struct packet_struct *p, *nextp;
+
+ while ((p=packet_queue)) {
+ packet_queue = p->next;
+ if (packet_queue) packet_queue->prev = NULL;
+ p->next = p->prev = NULL;
+
+ switch (p->packet_type) {
+ case NMB_PACKET:
+ process_nmb(p);
+ break;
+
+ case DGRAM_PACKET:
+ process_dgram(p);
+ break;
+ }
+ free_packet(p);
}
-
- packet_queue = packet_queue->next;
- if (packet_queue) packet_queue->prev = NULL;
- free_packet(p);
- }
}
+
/****************************************************************************
Create an fd_set containing all the sockets in the subnet structures,
plus the broadcast sockets.
***************************************************************************/
-
static BOOL create_listen_fdset(fd_set **ppset, int **psock_array, int *listen_number)
{
int *sock_array = NULL;
@@ -582,6 +582,9 @@ BOOL listen_for_packets(BOOL run_election)
fd_set fds;
int selrtn;
struct timeval timeout;
+#ifndef SYNC_DNS
+ int dns_fd;
+#endif
if(listen_set == NULL)
{
@@ -594,6 +597,14 @@ BOOL listen_for_packets(BOOL run_election)
memcpy((char *)&fds, (char *)listen_set, sizeof(fd_set));
+#ifndef SYNC_DNS
+ dns_fd = asyncdns_fd();
+ if (dns_fd != -1) {
+ FD_SET(dns_fd, &fds);
+ }
+#endif
+
+
/* during elections and when expecting a netbios response packet we
need to send election packets at tighter intervals
@@ -612,6 +623,12 @@ BOOL listen_for_packets(BOOL run_election)
{
int i;
+#ifndef SYNC_DNS
+ if (dns_fd != -1 && FD_ISSET(dns_fd,&fds)) {
+ run_dns_queue();
+ }
+#endif
+
for(i = 0; i < listen_number; i++)
{
if(i < (listen_number/2))
diff --git a/source3/nameservreply.c b/source3/nameservreply.c
index c901059f9b..6585a02261 100644
--- a/source3/nameservreply.c
+++ b/source3/nameservreply.c
@@ -569,23 +569,31 @@ void reply_name_query(struct packet_struct *p)
/* look up the name in the cache */
n = find_name_search(&d, question, FIND_LOCAL, p->ip);
+ /* check for a previous DNS lookup */
+ if (!n && (n = find_name_search(&d, question, FIND_WINS, p->ip))) {
+ if (n->source != DNS && n->source != DNSFAIL) {
+ n = NULL;
+ } else {
+ DEBUG(5,("Found DNS cache entry %s\n", namestr(&n->name)));
+ }
+ }
+
/* it is a name that already failed DNS lookup or it's expired */
if (n && (n->source == DNSFAIL ||
- (n->death_time && n->death_time < p->timestamp)))
- {
- success = False;
+ (n->death_time && n->death_time < p->timestamp))) {
+ DEBUG(5,("expired name %s\n", namestr(&n->name)));
+ success = False;
}
+
/* do we want to do dns lookups? */
- /* XXXX this DELAYS nmbd while it does a search. lp_dns_proxy()
- can be switched off, to ensure that the blocking doesn't occur.
- a better solution would be to fork, but this will require a
- mechanism to carry on processing after the query is resolved
- (similar to the netbios queue).
- */
- if (success && !n && (lp_dns_proxy() || !bcast))
- {
- n = dns_name_search(question, p->timestamp);
+ if (success && !n && (lp_dns_proxy() || !bcast)) {
+ BOOL dns_type = (name_type == 0x20 || name_type == 0);
+ if (dns_type && wins_subnet) {
+ /* add it to the dns name query queue */
+ if (queue_dns_query(p, question, &n))
+ return;
+ }
}
}
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
diff --git a/source3/nmbd/nmbd.c b/source3/nmbd/nmbd.c
index 047284832f..5feeb07c90 100644
--- a/source3/nmbd/nmbd.c
+++ b/source3/nmbd/nmbd.c
@@ -332,14 +332,6 @@ static void process(void)
****************************************************************************/
static BOOL open_sockets(BOOL isdaemon, int port)
{
- struct hostent *hp;
-
- /* get host info */
- if ((hp = Get_Hostbyname(myhostname)) == 0) {
- DEBUG(0,( "Get_Hostbyname: Unknown host. %s\n",myhostname));
- return False;
- }
-
/* The sockets opened here will be used to receive broadcast
packets *only*. Interface specific sockets are opened in
make_subnet() in namedbsubnet.c. Thus we bind to the
@@ -598,6 +590,10 @@ static void usage(char *pname)
become_daemon();
}
+#ifndef SYNC_DNS
+ start_async_dns();
+#endif
+
if (*pidFile)
{
int fd;
@@ -653,6 +649,7 @@ static void usage(char *pname)
/* We can only take sigterm signals in the select. */
BlockSignals(True,SIGTERM);
+
process();
close_sockets();
diff --git a/source3/utils/nmblookup.c b/source3/utils/nmblookup.c
index 63ca156449..d26d199695 100644
--- a/source3/utils/nmblookup.c
+++ b/source3/utils/nmblookup.c
@@ -42,15 +42,6 @@ int RootPort = 0;
**************************************************************************/
static BOOL open_sockets(void)
{
- struct hostent *hp;
-
- /* get host info */
- if ((hp = Get_Hostbyname(myhostname)) == 0)
- {
- DEBUG(0,( "Get_Hostbyname: Unknown host. %s\n",myhostname));
- return False;
- }
-
ServerFD = open_socket_in( SOCK_DGRAM,
(RootPort ? 137 :0),
3,