[SCM] Samba Shared Repository - branch master updated

Jeremy Allison jra at samba.org
Mon Mar 15 17:22:03 MDT 2010


The branch, master has been updated
       via  f2cbc9f... Fix bug #7191 - WINS doesn't respond after > 86 #1c registrations.
      from  9a825dc... s3:registry-legacy: use talloc_stackframe() instead of NULL in regkey_open_internal()

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit f2cbc9fbb12d36f6ce86111848ab0ee05469cdba
Author: Craig Miskell <craig.miskell at opus.co.nz>
Date:   Mon Mar 15 16:20:44 2010 -0700

    Fix bug #7191 - WINS doesn't respond after > 86 #1c registrations.

-----------------------------------------------------------------------

Summary of changes:
 source3/nmbd/nmbd_winsserver.c |  119 ++++++++++++++++++++++++++++++++++++++-
 1 files changed, 115 insertions(+), 4 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source3/nmbd/nmbd_winsserver.c b/source3/nmbd/nmbd_winsserver.c
index 0a5b1c8..be2c6a2 100644
--- a/source3/nmbd/nmbd_winsserver.c
+++ b/source3/nmbd/nmbd_winsserver.c
@@ -52,6 +52,26 @@ static void wins_delete_all_tmp_in_memory_records(void)
 }
 
 /****************************************************************************
+ Delete all the temporary 1b name records on the in-memory linked list.
+*****************************************************************************/
+
+static void wins_delete_all_1b_in_memory_records(void)
+{
+	struct name_record *nr = NULL;
+	struct name_record *nrnext = NULL;
+
+	/* Delete all temporary 1b name records on the wins subnet linked list. */
+	for( nr = wins_server_subnet->namelist; nr; nr = nrnext) {
+		nrnext = nr->next;
+		if (nr->name.name_type == 0x1b) {
+			DLIST_REMOVE(wins_server_subnet->namelist, nr);
+			SAFE_FREE(nr->data.ip);
+			SAFE_FREE(nr);
+		}
+	}
+}
+
+/****************************************************************************
  Convert a wins.tdb record to a struct name_record. Add in our global_scope().
 *****************************************************************************/
 
@@ -1250,6 +1270,84 @@ to register name %s from IP %s.\n", nmb_namestr(question), inet_ntoa(p->ip) ));
 			 */
 
 			if(!find_ip_in_name_record(namerec, from_ip)) {
+				/*
+				 * Need to emulate the behaviour of Windows, as
+				 * described in:
+				 * http://lists.samba.org/archive/samba-technical/2001-October/016236.html
+				 * (is there an MS reference for this
+				 * somewhere?) because if the 1c list gets over
+				 * 86 entries, the reply packet is too big
+				 * (rdata>576 bytes) so no reply is sent.
+				 *
+				 * Keep only the "latest" 25 records, while
+				 * ensuring that the PDC (0x1b) is never removed
+				 * We do this by removing the first entry that
+				 * isn't the 1b entry for the same name,
+				 * on the grounds that insertion is at the end
+				 * of the list, so the oldest entries are at
+				 * the start.
+				 *
+				 */
+				while(namerec->data.num_ips>=25) {
+					struct name_record *name1brec = NULL;
+
+					/* We only do this for 1c types. */
+					if (namerec->name.name_type != 0x1c) {
+						break;
+					}
+					DEBUG(3,("wins_process_name_registration_request: "
+						"More than 25 IPs already in "
+						"the list. Looking for a 1b "
+						"record\n"));
+
+					/* Ensure we have all the active 1b
+					 * names on the list. */
+					wins_delete_all_1b_in_memory_records();
+					fetch_all_active_wins_1b_names();
+
+					/* Per the above, find the 1b record,
+					   and then remove the first IP that isn't the same */
+					for(name1brec = subrec->namelist;
+							name1brec;
+							name1brec = name1brec->next ) {
+						if( WINS_STATE_ACTIVE(name1brec) &&
+								name1brec->name.name_type == 0x1b) {
+							DEBUG(3,("wins_process_name_registration_request: "
+								"Found the #1b record "
+								"with ip %s\n",
+								inet_ntoa(name1brec->data.ip[0])));
+							break;
+						}
+					}
+					if(!name1brec) {
+						DEBUG(3,("wins_process_name_registration_request: "
+							"Didn't find a #1b name record. "
+							"Removing the first available "
+							"entry %s\n",
+							inet_ntoa(namerec->data.ip[0])));
+						remove_ip_from_name_record(namerec, namerec->data.ip[0]);
+						wins_hook("delete", namerec, 0);
+					} else {
+						int i;
+						for(i=0; i<namerec->data.num_ips; i++) {
+							/* The name1brec should only have
+							 * the single IP address in it,
+							 * so we only check against the first one*/
+							if(!ip_equal_v4( namerec->data.ip[i], name1brec->data.ip[0])) {
+								/* The i'th entry isn't the 1b address; delete it  */
+								DEBUG(3,("wins_process_name_registration_request: "
+									"Entry at %d is not the #1b address. "
+									"About to remove it\n",
+									i));
+								remove_ip_from_name_record(namerec, namerec->data.ip[i]);
+								wins_hook("delete", namerec, 0);
+								break;
+							}
+						}
+					}
+				}
+				/* The list is guaranteed to be < 25 entries now
+				 * - safe to add a new one  */
 				add_ip_to_name_record(namerec, from_ip);
 				/* we need to update the record for replication */
 				get_global_id_and_update(&namerec->data.id, True);
@@ -1866,27 +1964,40 @@ void send_wins_name_query_response(int rcode, struct packet_struct *p,
 	memset(rdata,'\0',6);
 
 	if(rcode == 0) {
+
+		int ip_count;
+
 		ttl = (namerec->data.death_time != PERMANENT_TTL) ?  namerec->data.death_time - p->timestamp : lp_max_wins_ttl();
 
+		/* The netbios reply packet data section is limited to 576 bytes.  In theory 
+		 * this should give us space for 96 addresses, but in practice, 86 appears 
+		 * to be the max (don't know why).  If we send any more than that, 
+		 * reply_netbios_packet will fail to send a reply to avoid a memcpy buffer 
+		 * overflow.  Keep the count to 85 and it will be ok */
+		ip_count=namerec->data.num_ips;
+		if(ip_count>85) {
+			ip_count=85;	
+		}
+
 		/* Copy all known ip addresses into the return data. */
 		/* Optimise for the common case of one IP address so we don't need a malloc. */
 
-		if( namerec->data.num_ips == 1 ) {
+		if( ip_count == 1 ) {
 			prdata = rdata;
 		} else {
-			if((prdata = (char *)SMB_MALLOC( namerec->data.num_ips * 6 )) == NULL) {
+			if((prdata = (char *)SMB_MALLOC( ip_count * 6 )) == NULL) {
 				DEBUG(0,("send_wins_name_query_response: malloc fail !\n"));
 				return;
 			}
 		}
 
-		for(i = 0; i < namerec->data.num_ips; i++) {
+		for(i = 0; i < ip_count; i++) {
 			set_nb_flags(&prdata[i*6],namerec->data.nb_flags);
 			putip((char *)&prdata[2+(i*6)], &namerec->data.ip[i]);
 		}
 
 		sort_query_replies(prdata, i, p->ip);
-		reply_data_len = namerec->data.num_ips * 6;
+		reply_data_len = ip_count * 6;
 	}
 
 	reply_netbios_packet(p,                                /* Packet to reply to. */


-- 
Samba Shared Repository


More information about the samba-cvs mailing list