1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-23 17:34:34 +03:00

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

This commit is contained in:
Craig Miskell 2010-03-15 16:20:44 -07:00 committed by Jeremy Allison
parent 9a825dc770
commit f2cbc9fbb1

View File

@ -51,6 +51,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. */