diff options
Diffstat (limited to 'source4/nbt_server')
-rw-r--r-- | source4/nbt_server/wins/winsdb.c | 133 | ||||
-rw-r--r-- | source4/nbt_server/wins/winsserver.c | 48 |
2 files changed, 165 insertions, 16 deletions
diff --git a/source4/nbt_server/wins/winsdb.c b/source4/nbt_server/wins/winsdb.c index 625d4e68dc..f294705e55 100644 --- a/source4/nbt_server/wins/winsdb.c +++ b/source4/nbt_server/wins/winsdb.c @@ -353,11 +353,134 @@ struct winsdb_addr **winsdb_addr_list_make(TALLOC_CTX *mem_ctx) return addresses; } -struct winsdb_addr **winsdb_addr_list_add(struct winsdb_addr **addresses, const char *address, - const char *wins_owner, time_t expire_time) +static int winsdb_addr_sort_list (struct winsdb_addr **p1, struct winsdb_addr **p2, void *opaque) { - size_t len = winsdb_addr_list_length(addresses); + struct winsdb_addr *a1 = talloc_get_type(*p1, struct winsdb_addr); + struct winsdb_addr *a2 = talloc_get_type(*p2, struct winsdb_addr); + struct winsdb_handle *h= talloc_get_type(opaque, struct winsdb_handle); + BOOL a1_owned = False; + BOOL a2_owned = False; + + /* + * first the owned addresses with the newest to the oldest address + * then the replica addresses with the newest to the oldest address + */ + if (a2->expire_time != a1->expire_time) { + return a2->expire_time - a1->expire_time; + } + + if (strcmp(a2->wins_owner, h->local_owner) == 0) { + a2_owned = True; + } + + if (strcmp(a1->wins_owner, h->local_owner) == 0) { + a1_owned = True; + } + return a2_owned - a1_owned; +} + +struct winsdb_addr **winsdb_addr_list_add(struct winsdb_handle *h, const struct winsdb_record *rec, + struct winsdb_addr **addresses, const char *address, + const char *wins_owner, time_t expire_time, + BOOL is_name_registration) +{ + struct winsdb_addr *old_addr = NULL; + size_t len = 0; + size_t i; + BOOL found_old_replica = False; + + /* + * count the addresses and maybe + * find an old entry for the new address + */ + for (i=0; addresses[i]; i++) { + if (old_addr) continue; + if (strcmp(addresses[i]->address, address) == 0) { + old_addr = addresses[i]; + } + } + len = i; + + /* + * the address is already there + * and we can replace it + */ + if (old_addr) { + goto remove_old_addr; + } + + /* + * if we don't have 25 addresses already, + * we can just add the new address + */ + if (len < 25) { + goto add_new_addr; + } + + /* + * if we haven't found the address, + * and we have already have 25 addresses + * if so then we need to do the following: + * - if it isn't a name registration, then just ignore the new address + * - if it is a name registration, then first search for + * the oldest replica and if there's no replica address + * search the oldest owned address + */ + if (!is_name_registration) { + return addresses; + } + + /* + * find the oldest replica address, if there's no replica + * record at all, find the oldest owned address + */ + for (i=0; addresses[i]; i++) { + BOOL cur_is_replica = False; + /* find out if the current address is a replica */ + if (strcmp(addresses[i]->wins_owner, h->local_owner) != 0) { + cur_is_replica = True; + } + + /* + * if we already found a replica address and the current address + * is not a replica, then skip it + */ + if (found_old_replica && !cur_is_replica) continue; + + /* + * if we found the first replica address, reset the address + * that would be replaced + */ + if (!found_old_replica && cur_is_replica) { + found_old_replica = True; + old_addr = addresses[i]; + continue; + } + + /* + * if the first address isn't a replica, just start with + * the first one + */ + if (!old_addr) { + old_addr = addresses[i]; + continue; + } + + /* + * see if we find an older address + */ + if (addresses[i]->expire_time < old_addr->expire_time) { + old_addr = addresses[i]; + continue; + } + } + +remove_old_addr: + winsdb_addr_list_remove(addresses, old_addr->address); + len --; + +add_new_addr: addresses = talloc_realloc(addresses, addresses, struct winsdb_addr *, len + 2); if (!addresses) return NULL; @@ -383,6 +506,8 @@ struct winsdb_addr **winsdb_addr_list_add(struct winsdb_addr **addresses, const addresses[len+1] = NULL; + ldb_qsort(addresses, len+1 , sizeof(addresses[0]), h, (ldb_qsort_cmp_fn_t)winsdb_addr_sort_list); + return addresses; } @@ -395,7 +520,7 @@ void winsdb_addr_list_remove(struct winsdb_addr **addresses, const char *address break; } } - if (!addresses[i]) return; + if (addresses[i]) talloc_free(addresses[i]); for (; addresses[i]; i++) { addresses[i] = addresses[i+1]; diff --git a/source4/nbt_server/wins/winsserver.c b/source4/nbt_server/wins/winsserver.c index 5cc3a51a00..7f67429996 100644 --- a/source4/nbt_server/wins/winsserver.c +++ b/source4/nbt_server/wins/winsserver.c @@ -90,10 +90,12 @@ static uint8_t wins_register_new(struct nbt_name_socket *nbtsock, rec.addresses = winsdb_addr_list_make(packet); if (rec.addresses == NULL) return NBT_RCODE_SVR; - rec.addresses = winsdb_addr_list_add(rec.addresses, + rec.addresses = winsdb_addr_list_add(winssrv->wins_db, + &rec, rec.addresses, address, winssrv->wins_db->local_owner, - rec.expire_time); + rec.expire_time, + True); if (rec.addresses == NULL) return NBT_RCODE_SVR; DEBUG(4,("WINS: accepted registration of %s with address %s\n", @@ -123,8 +125,13 @@ static uint8_t wins_update_ttl(struct nbt_name_socket *nbtsock, rec->registered_by = src->addr; if (winsdb_addr) { - winsdb_addr->wins_owner = winssrv->wins_db->local_owner; - winsdb_addr->expire_time = rec->expire_time; + rec->addresses = winsdb_addr_list_add(winssrv->wins_db, + rec, rec->addresses, + winsdb_addr->address, + winssrv->wins_db->local_owner, + rec->expire_time, + True); + if (rec->addresses == NULL) return NBT_RCODE_SVR; } if (strcmp(winssrv->wins_db->local_owner, rec->wins_owner) != 0) { @@ -154,10 +161,12 @@ static uint8_t wins_sgroup_merge(struct nbt_name_socket *nbtsock, rec->expire_time = time(NULL) + ttl; rec->registered_by = src->addr; - rec->addresses = winsdb_addr_list_add(rec->addresses, + rec->addresses = winsdb_addr_list_add(winssrv->wins_db, + rec, rec->addresses, address, winssrv->wins_db->local_owner, - rec->expire_time); + rec->expire_time, + True); if (rec->addresses == NULL) return NBT_RCODE_SVR; DEBUG(5,("WINS: sgroup merge of %s at %s\n", @@ -244,18 +253,25 @@ static void wins_wack_allow(struct wack_state *s) break; } if (found) { - rec->addresses[i]->wins_owner = s->winssrv->wins_db->local_owner; - rec->addresses[i]->expire_time = rec->expire_time; + rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db, + rec, rec->addresses, + s->reg_address, + s->winssrv->wins_db->local_owner, + rec->expire_time, + True); + if (rec->addresses == NULL) goto failed; continue; } winsdb_addr_list_remove(rec->addresses, rec->addresses[i]->address); } - rec->addresses = winsdb_addr_list_add(rec->addresses, + rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db, + rec, rec->addresses, s->reg_address, s->winssrv->wins_db->local_owner, - rec->expire_time); + rec->expire_time, + True); if (rec->addresses == NULL) goto failed; /* if we have more than one address, this becomes implicit a MHOMED record */ @@ -623,16 +639,24 @@ static void nbtd_winsserver_query(struct nbt_name_socket *nbtsock, if (addresses_1b && addresses_1b[0]) { const char **addresses_1c = addresses; uint32_t i; + uint32_t num_addrs; addresses = str_list_add(NULL, addresses_1b[0]); if (!addresses) { goto notfound; } talloc_steal(packet, addresses); + num_addrs = 1; for (i=0; addresses_1c[i]; i++) { if (strcmp(addresses_1b[0], addresses_1c[i]) == 0) continue; + /* + * stop when we already have 25 addresses + */ + if (num_addrs >= 25) break; + + num_addrs++; addresses = str_list_add(addresses, addresses_1c[i]); if (!addresses) { goto notfound; @@ -643,7 +667,7 @@ static void nbtd_winsserver_query(struct nbt_name_socket *nbtsock, if (rec->type == WREPL_TYPE_SGROUP) { nb_flags |= NBT_NM_GROUP; } else { - nb_flags |= (rec->node <<13); + nb_flags |= (rec->node <<13); } found: @@ -705,7 +729,7 @@ static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock, if (!winsdb_addr_list_check(rec->addresses, src->addr)) { int i; DEBUG(4,("WINS: silently ignoring attempted name release on %s from %s\n", nbt_name_string(rec, rec->name), src->addr)); - DEBUGADD(4, ("Registered Addressss: \n")); + DEBUGADD(4, ("Registered Addresses: \n")); for (i=0; rec->addresses && rec->addresses[i]; i++) { DEBUGADD(4, ("%s\n", rec->addresses[i]->address)); } |