diff options
author | Samba Release Account <samba-bugs@samba.org> | 1996-06-29 18:49:20 +0000 |
---|---|---|
committer | Samba Release Account <samba-bugs@samba.org> | 1996-06-29 18:49:20 +0000 |
commit | ed2639ebe21dde49af816a96ec6ea1e40f76e768 (patch) | |
tree | 969aa897016d8e4f29d846cf23c5fa832ae6cf58 /source3/nameresp.c | |
parent | 851ee418b499df481b765286405cd761e91dcaaf (diff) | |
download | samba-ed2639ebe21dde49af816a96ec6ea1e40f76e768.tar.gz samba-ed2639ebe21dde49af816a96ec6ea1e40f76e768.tar.bz2 samba-ed2639ebe21dde49af816a96ec6ea1e40f76e768.zip |
luke's first attempt at using cvs
accidentally updated the Makefile
updated the name database structure (again!). this time, there is one
name database per local interface. there is also a pseudo-interface on
ip 255.255.255.255. its purpose is to store WINS name entries. all the
local interface name databases store SELF names only. the WINS name
database stores non-special browser names.
added wins.dat file: records WINS entries in ascii format. this is reloaded
when nmbd restarts.
added repeating code for response packets. timer is in seconds only at the
moment.
updated the response queue code to deal with samba registering with a
WINS server a bit better (added more cases when a response isn't received).
tidied up the response packet processing code and expire_response_queue()
code. added cross references between response received and await-response
expired code.
added over-zealous code that checks all machines that register with samba
as a WINS server (every 10 minutes i think): to see whether they are still
alive or not (see rfc1001.txt)
bug reported by terry@ren.pc.athabascau.ca: DNSFAILed names _stay_ as
DNSFAIL, even though the machine may come back up and REGISTER.
removed update_from_reg() function. it's not necessary, and it does too much.
added code that announces on each local interface samba's ttl as zero and
servertype as zero when nmbd is kill -TERMed
first attempt at putting the first functionality of samba browsing back in
(remote subnets should have samba appear in a workgroup specified through
the lmhosts file)
lots of other miscellaneous tidying up / chopping about.
(This used to be commit 7e8c60cfe54060860e5ce20b1c3b8ec6aa5c54da)
Diffstat (limited to 'source3/nameresp.c')
-rw-r--r-- | source3/nameresp.c | 384 |
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 */ |