diff options
-rw-r--r-- | source3/include/nameserv.h | 23 | ||||
-rw-r--r-- | source3/libsmb/nmblib.c | 9 | ||||
-rw-r--r-- | source3/namedbname.c | 49 | ||||
-rw-r--r-- | source3/namepacket.c | 55 | ||||
-rw-r--r-- | source3/nameservreply.c | 32 | ||||
-rw-r--r-- | source3/nmbd/asyncdns.c | 257 | ||||
-rw-r--r-- | source3/nmbd/nmbd.c | 13 | ||||
-rw-r--r-- | source3/utils/nmblookup.c | 9 |
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, |