summaryrefslogtreecommitdiff
path: root/source3/nameresp.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/nameresp.c')
-rw-r--r--source3/nameresp.c384
1 files changed, 272 insertions, 112 deletions
diff --git a/source3/nameresp.c b/source3/nameresp.c
index b244d81159..31df799691 100644
--- a/source3/nameresp.c
+++ b/source3/nameresp.c
@@ -25,8 +25,7 @@
extern int ClientNMB;
extern int ClientDGRAM;
-/* this is our initiated name query response database */
-struct name_response_record *nameresponselist = NULL;
+extern struct subnet_record *subnetlist;
extern int DEBUGLEVEL;
@@ -35,24 +34,29 @@ BOOL CanRecurse = True;
extern pstring scope;
extern pstring myname;
extern struct in_addr ipzero;
+extern struct in_addr ipgrp;
+int num_response_packets = 0;
/***************************************************************************
add an initated name query into the list
**************************************************************************/
-extern void add_response_record(struct name_response_record *n)
+static void add_response_record(struct subnet_record *d,
+ struct response_record *n)
{
- struct name_response_record *n2;
+ struct response_record *n2;
- if (!nameresponselist)
+ if (!d) return;
+
+ if (!d->responselist)
{
- nameresponselist = n;
+ d->responselist = n;
n->prev = NULL;
n->next = NULL;
return;
}
- for (n2 = nameresponselist; n2->next; n2 = n2->next) ;
+ for (n2 = d->responselist; n2->next; n2 = n2->next) ;
n2->next = n;
n->next = NULL;
@@ -60,110 +64,123 @@ extern void add_response_record(struct name_response_record *n)
}
-/*******************************************************************
- remove old name response entries
- ******************************************************************/
-void expire_netbios_response_entries(time_t t)
+/***************************************************************************
+ deals with an entry before it dies
+ **************************************************************************/
+static void dead_netbios_entry(struct subnet_record *d,
+ struct response_record *n)
{
- struct name_response_record *n;
- struct name_response_record *nextn;
+ DEBUG(3,("Removing dead netbios entry for %s %s (num_msgs=%d)\n",
+ inet_ntoa(n->to_ip), namestr(&n->name), n->num_msgs));
- for (n = nameresponselist; n; n = nextn)
+ switch (n->cmd_type)
{
- if (n->start_time < t)
+ case NAME_QUERY_CONFIRM:
{
- DEBUG(3,("Removing dead name query for %s %s (num_msgs=%d)\n",
- inet_ntoa(n->to_ip), namestr(&n->name), n->num_msgs));
+ if (!lp_wins_support()) return; /* only if we're a WINS server */
- if (n->cmd_type == CHECK_MASTER)
- {
- /* if no response received, the master browser must have gone */
if (n->num_msgs == 0)
- browser_gone(n->name.name, n->to_ip);
- }
-
- nextn = n->next;
+ {
+ /* oops. name query had no response. check that the name is
+ unique and then remove it from our WINS database */
- if (n->prev) n->prev->next = n->next;
- if (n->next) n->next->prev = n->prev;
+ /* IMPORTANT: see query_refresh_names() */
- if (nameresponselist == n) nameresponselist = n->next;
-
- free(n);
- }
- else
+ if ((!NAME_GROUP(n->nb_flags)))
{
- nextn = n->next;
+ struct subnet_record *d = find_subnet(ipgrp);
+ if (d)
+ {
+ /* remove the name that had been registered with us,
+ and we're now getting no response when challenging.
+ see rfc1001.txt 15.5.2
+ */
+ remove_netbios_name(d, n->name.name, n->name.name_type,
+ REGISTER, n->to_ip);
}
}
}
+ break;
+ }
-
-/****************************************************************************
- reply to a netbios name packet
- ****************************************************************************/
-void reply_netbios_packet(struct packet_struct *p1,int trn_id,int rcode,
- int opcode,BOOL recurse,struct nmb_name *rr_name,
- int rr_type,int rr_class,int ttl,char *data,int len)
+ case NAME_QUERY_MST_CHK:
{
- struct packet_struct p;
- struct nmb_packet *nmb = &p.packet.nmb;
- struct res_rec answers;
- char *packet_type = "unknown";
+ /* if no response received, the master browser must have gone
+ down on that subnet, without telling anyone. */
- p = *p1;
+ /* IMPORTANT: see response_netbios_packet() */
- if (rr_type == NMB_STATUS) packet_type = "nmb_status";
- if (rr_type == NMB_QUERY ) packet_type = "nmb_query";
- if (rr_type == NMB_REG ) packet_type = "nmb_reg";
- if (rr_type == NMB_REL ) packet_type = "nmb_rel";
+ if (n->num_msgs == 0)
+ browser_gone(n->name.name, n->to_ip);
+ break;
+ }
- DEBUG(4,("replying netbios packet: %s %s\n",
- packet_type, namestr(rr_name), inet_ntoa(p.ip)));
+ case NAME_RELEASE:
+ {
+ /* if no response received, it must be OK for us to release the
+ name. nobody objected (including a potentially dead or deaf
+ WINS server) */
- nmb->header.name_trn_id = trn_id;
- nmb->header.opcode = opcode;
- nmb->header.response = True;
- nmb->header.nm_flags.bcast = False;
- nmb->header.nm_flags.recursion_available = recurse;
- nmb->header.nm_flags.recursion_desired = True;
- nmb->header.nm_flags.trunc = False;
- nmb->header.nm_flags.authoritative = True;
+ /* IMPORTANT: see response_name_release() */
- nmb->header.qdcount = 0;
- nmb->header.ancount = 1;
- nmb->header.nscount = 0;
- nmb->header.arcount = 0;
- nmb->header.rcode = 0;
+ if (ismyip(n->to_ip))
+ {
+ remove_netbios_name(d,n->name.name,n->name.name_type,SELF,n->to_ip);
+ }
+ if (!n->bcast)
+ {
+ DEBUG(1,("WINS server did not respond to name release!\n"));
+ }
+ break;
+ }
- bzero((char*)&nmb->question,sizeof(nmb->question));
+ case NAME_REGISTER:
+ {
+ /* if no response received, and we are using a broadcast registration
+ method, it must be OK for us to register the name: nobody objected
+ on that subnet. if we are using a WINS server, then the WINS
+ server must be dead or deaf.
+ */
+ if (n->bcast)
+ {
+ /* broadcast method: implicit acceptance of the name registration
+ by not receiving any objections. */
- nmb->answers = &answers;
- bzero((char*)nmb->answers,sizeof(*nmb->answers));
+ /* IMPORTANT: see response_name_reg() */
- nmb->answers->rr_name = *rr_name;
- nmb->answers->rr_type = rr_type;
- nmb->answers->rr_class = rr_class;
- nmb->answers->ttl = ttl;
+ enum name_source source = ismyip(n->to_ip) ? SELF : REGISTER;
- if (data && len)
- {
- nmb->answers->rdlength = len;
- memcpy(nmb->answers->rdata, data, len);
+ add_netbios_entry(d,n->name.name,n->name.name_type,
+ n->nb_flags, n->ttl, source,n->to_ip, True,!n->bcast);
}
+ else
+ {
+ /* XXXX oops. this is where i wish this code could retry DGRAM
+ packets. we directed a name registration at a WINS server, and
+ received no response. rfc1001.txt states that after retrying,
+ we should assume the WINS server is dead, and fall back to
+ broadcasting. */
- p.packet_type = NMB_PACKET;
-
- debug_nmb_packet(&p);
+ DEBUG(1,("WINS server did not respond to name registration!\n"));
+ }
+ break;
+ }
- send_packet(&p);
+ default:
+ {
+ /* nothing to do but delete the dead expected-response structure */
+ /* this is normal. */
+ break;
+ }
+ }
}
/****************************************************************************
initiate a netbios packet
****************************************************************************/
-uint16 initiate_netbios_packet(int fd,int quest_type,char *name,int name_type,
+static void initiate_netbios_packet(uint16 *id,
+ int fd,int quest_type,char *name,int name_type,
int nb_flags,BOOL bcast,BOOL recurse,
struct in_addr to_ip)
{
@@ -173,6 +190,8 @@ uint16 initiate_netbios_packet(int fd,int quest_type,char *name,int name_type,
char *packet_type = "unknown";
int opcode = -1;
+ if (!id) return;
+
if (quest_type == NMB_STATUS) { packet_type = "nmb_status"; opcode = 0; }
if (quest_type == NMB_QUERY ) { packet_type = "nmb_query"; opcode = 0; }
if (quest_type == NMB_REG ) { packet_type = "nmb_reg"; opcode = 5; }
@@ -181,7 +200,7 @@ uint16 initiate_netbios_packet(int fd,int quest_type,char *name,int name_type,
DEBUG(4,("initiating netbios packet: %s %s(%x) (bcast=%s) %s\n",
packet_type, name, name_type, BOOLSTR(bcast), inet_ntoa(to_ip)));
- if (opcode == -1) return False;
+ if (opcode == -1) return;
bzero((char *)&p,sizeof(p));
@@ -189,7 +208,9 @@ uint16 initiate_netbios_packet(int fd,int quest_type,char *name,int name_type,
(getpid()%(unsigned)100);
name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
- nmb->header.name_trn_id = name_trn_id;
+ if (*id == 0xffff) *id = name_trn_id; /* allow resending with same id */
+
+ nmb->header.name_trn_id = *id;
nmb->header.opcode = opcode;
nmb->header.response = False;
nmb->header.nm_flags.bcast = bcast;
@@ -229,10 +250,120 @@ uint16 initiate_netbios_packet(int fd,int quest_type,char *name,int name_type,
p.timestamp = time(NULL);
p.packet_type = NMB_PACKET;
- if (!send_packet(&p))
- return(0);
+ if (!send_packet(&p)) *id = 0xffff;
- return(name_trn_id);
+ return;
+}
+
+
+/*******************************************************************
+ remove old name response entries
+ XXXX retry code needs to be added, including a retry wait period and a count
+ see name_query() and name_status() for suggested implementation.
+ ******************************************************************/
+void expire_netbios_response_entries()
+{
+ struct response_record *n;
+ struct response_record *nextn;
+ struct subnet_record *d;
+
+ for (d = subnetlist; d; d = d->next)
+ for (n = d->responselist; n; n = nextn)
+ {
+ if (n->repeat_time < time(NULL))
+ {
+ if (n->repeat_count > 0)
+ {
+ /* resend the entry */
+ initiate_netbios_packet(&n->response_id, n->fd, n->quest_type,
+ n->name.name, n->name.name_type,
+ n->nb_flags, n->bcast, n->recurse, n->to_ip);
+
+ n->repeat_time += n->repeat_interval; /* XXXX ms needed */
+ n->repeat_count--;
+ }
+ else
+ {
+ dead_netbios_entry(d,n);
+
+ nextn = n->next;
+
+ if (n->prev) n->prev->next = n->next;
+ if (n->next) n->next->prev = n->prev;
+
+ if (d->responselist == n) d->responselist = n->next;
+
+ free(n);
+
+ num_response_packets--;
+
+ continue;
+ }
+ }
+ nextn = n->next;
+ }
+}
+
+
+/****************************************************************************
+ reply to a netbios name packet
+ ****************************************************************************/
+void reply_netbios_packet(struct packet_struct *p1,int trn_id,
+ int rcode,int opcode, BOOL recurse,
+ struct nmb_name *rr_name,int rr_type,int rr_class,int ttl,
+ char *data,int len)
+{
+ struct packet_struct p;
+ struct nmb_packet *nmb = &p.packet.nmb;
+ struct res_rec answers;
+ char *packet_type = "unknown";
+
+ p = *p1;
+
+ if (rr_type == NMB_STATUS) packet_type = "nmb_status";
+ if (rr_type == NMB_QUERY ) packet_type = "nmb_query";
+ if (rr_type == NMB_REG ) packet_type = "nmb_reg";
+ if (rr_type == NMB_REL ) packet_type = "nmb_rel";
+
+ DEBUG(4,("replying netbios packet: %s %s\n",
+ packet_type, namestr(rr_name), inet_ntoa(p.ip)));
+
+ nmb->header.name_trn_id = trn_id;
+ nmb->header.opcode = opcode;
+ nmb->header.response = True;
+ nmb->header.nm_flags.bcast = False;
+ nmb->header.nm_flags.recursion_available = recurse;
+ nmb->header.nm_flags.recursion_desired = True;
+ nmb->header.nm_flags.trunc = False;
+ nmb->header.nm_flags.authoritative = True;
+
+ nmb->header.qdcount = 0;
+ nmb->header.ancount = 1;
+ nmb->header.nscount = 0;
+ nmb->header.arcount = 0;
+ nmb->header.rcode = 0;
+
+ bzero((char*)&nmb->question,sizeof(nmb->question));
+
+ nmb->answers = &answers;
+ bzero((char*)nmb->answers,sizeof(*nmb->answers));
+
+ nmb->answers->rr_name = *rr_name;
+ nmb->answers->rr_type = rr_type;
+ nmb->answers->rr_class = rr_class;
+ nmb->answers->ttl = ttl;
+
+ if (data && len)
+ {
+ nmb->answers->rdlength = len;
+ memcpy(nmb->answers->rdata, data, len);
+ }
+
+ p.packet_type = NMB_PACKET;
+
+ debug_nmb_packet(&p);
+
+ send_packet(&p);
}
@@ -241,8 +372,9 @@ uint16 initiate_netbios_packet(int fd,int quest_type,char *name,int name_type,
name server instead, if it exists. if wins is false, and there has been no
WINS server specified, the packet will NOT be sent.
****************************************************************************/
-void queue_netbios_pkt_wins(int fd,int quest_type,enum cmd_type cmd,
- char *name,int name_type,int nb_flags,
+void queue_netbios_pkt_wins(struct subnet_record *d,
+ int fd,int quest_type,enum cmd_type cmd,
+ char *name,int name_type,int nb_flags, time_t ttl,
BOOL bcast,BOOL recurse,struct in_addr to_ip)
{
if ((!lp_wins_support()) && (*lp_wins_server()))
@@ -266,35 +398,45 @@ void queue_netbios_pkt_wins(int fd,int quest_type,enum cmd_type cmd,
if (zero_ip(to_ip)) return;
- queue_netbios_packet(fd, quest_type, cmd,
- name, name_type, nb_flags,
+ queue_netbios_packet(d,fd, quest_type, cmd,
+ name, name_type, nb_flags, ttl,
bcast, recurse, to_ip);
}
/****************************************************************************
create a name query response record
**************************************************************************/
-static struct name_response_record *
-make_name_query_record(enum cmd_type cmd,int id,int fd,char *name,int type,
+static struct response_record *
+make_response_queue_record(enum cmd_type cmd,int id,int fd,
+ int quest_type, char *name,int type, int nb_flags, time_t ttl,
BOOL bcast,BOOL recurse,struct in_addr ip)
{
- struct name_response_record *n;
+ struct response_record *n;
if (!name || !name[0]) return NULL;
- if (!(n = (struct name_response_record *)malloc(sizeof(*n))))
+ if (!(n = (struct response_record *)malloc(sizeof(*n))))
return(NULL);
n->response_id = id;
n->cmd_type = cmd;
n->fd = fd;
+ n->quest_type = quest_type;
make_nmb_name(&n->name, name, type, scope);
+ n->nb_flags = nb_flags;
+ n->ttl = ttl;
n->bcast = bcast;
n->recurse = recurse;
n->to_ip = ip;
- n->start_time = time(NULL);
+
+ n->repeat_interval = 1; /* XXXX should be in ms */
+ n->repeat_count = 4;
+ n->repeat_time = time(NULL) + n->repeat_interval;
+
n->num_msgs = 0;
+ num_response_packets++; /* count of total number of packets still around */
+
return n;
}
@@ -305,32 +447,43 @@ make_name_query_record(enum cmd_type cmd,int id,int fd,char *name,int type,
master browsers (WORKGROUP(1d or 1b) or __MSBROWSE__(1)) to get
complete lists across a wide area network
****************************************************************************/
-void queue_netbios_packet(int fd,int quest_type,enum cmd_type cmd,char *name,
- int name_type,int nb_flags,BOOL bcast,BOOL recurse,
- struct in_addr to_ip)
+void queue_netbios_packet(struct subnet_record *d,
+ int fd,int quest_type,enum cmd_type cmd,char *name,
+ int name_type,int nb_flags, time_t ttl,
+ BOOL bcast,BOOL recurse, struct in_addr to_ip)
{
- uint16 id = initiate_netbios_packet(fd, quest_type, name, name_type,
+ struct in_addr wins_ip = ipgrp;
+ struct response_record *n;
+ uint16 id = 0xffff;
+
+ /* ha ha. no. do NOT broadcast to 255.255.255.255: it's a pseudo address */
+ if (ip_equal(wins_ip, to_ip)) return;
+
+ initiate_netbios_packet(&id, fd, quest_type, name, name_type,
nb_flags, bcast, recurse, to_ip);
- struct name_response_record *n;
- if (id == 0) return;
+ if (id == 0xffff) return;
- if ((n =
- make_name_query_record(cmd,id,fd,name,name_type,bcast,recurse,to_ip)))
+ if ((n = make_response_queue_record(cmd,id,fd,
+ quest_type,name,name_type,nb_flags,ttl,
+ bcast,recurse,to_ip)))
{
- add_response_record(n);
+ add_response_record(d,n);
}
}
/****************************************************************************
- find a response in the name query response list
+ find a response in a subnet's name query response list.
**************************************************************************/
-struct name_response_record *find_name_query(uint16 id)
+struct response_record *find_response_record(struct subnet_record *d,
+ uint16 id)
{
- struct name_response_record *n;
+ struct response_record *n;
- for (n = nameresponselist; n; n = n->next)
+ if (!d) return NULL;
+
+ for (n = d->responselist; n; n = n->next)
{
if (n->response_id == id) {
return n;
@@ -409,10 +562,12 @@ void listen_for_packets(BOOL run_election)
FD_SET(ClientNMB,&fds);
FD_SET(ClientDGRAM,&fds);
- /* during elections we need to send election packets at one
- second intervals */
+ /* during elections and when expecting a netbios response packet we need
+ to send election packets at one second intervals.
+ XXXX actually, it needs to be the interval (in ms) between time now and the
+ time we are expecting the next netbios packet */
- timeout.tv_sec = run_election ? 1 : NMBD_SELECT_LOOP;
+ timeout.tv_sec = (run_election||num_response_packets) ? 1 : NMBD_SELECT_LOOP;
timeout.tv_usec = 0;
selrtn = sys_select(&fds,&timeout);
@@ -461,8 +616,9 @@ interpret a node status response. this is pretty hacked: we need two bits of
info. a) the name of the workgroup b) the name of the server. it will also
add all the names it finds into the namelist.
****************************************************************************/
-BOOL interpret_node_status(char *p, struct nmb_name *name,int t,
- char *serv_name, struct in_addr ip)
+BOOL interpret_node_status(struct subnet_record *d,
+ char *p, struct nmb_name *name,int t,
+ char *serv_name, struct in_addr ip, BOOL bcast)
{
int level = t==0x20 ? 4 : 0;
int numnames = CVAL(p,0);
@@ -516,7 +672,7 @@ BOOL interpret_node_status(char *p, struct nmb_name *name,int t,
nameip = ip;
src = STATUS_QUERY;
}
- add_netbios_entry(qname,type,nb_flags,2*60*60,src,nameip,True);
+ add_netbios_entry(d,qname,type,nb_flags,2*60*60,src,nameip,True,bcast);
}
/* we want the server name */
@@ -559,9 +715,13 @@ BOOL send_mailslot_reply(char *mailslot,int fd,char *buf,int len,char *srcname,
{
struct packet_struct p;
struct dgram_packet *dgram = &p.packet.dgram;
+ struct in_addr wins_ip = ipgrp;
char *ptr,*p2;
char tmp[4];
+ /* ha ha. no. do NOT send packets to 255.255.255.255: it's a pseudo address */
+ if (ip_equal(wins_ip, dest_ip)) return False;
+
bzero((char *)&p,sizeof(p));
dgram->header.msg_type = 0x11; /* DIRECT GROUP DATAGRAM */