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:
parent
9a825dc770
commit
f2cbc9fbb1
@ -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. */
|
||||
|
Loading…
Reference in New Issue
Block a user