summaryrefslogtreecommitdiff
path: root/source4/nbt_server
diff options
context:
space:
mode:
Diffstat (limited to 'source4/nbt_server')
-rw-r--r--source4/nbt_server/wins/winsdb.c133
-rw-r--r--source4/nbt_server/wins/winsserver.c48
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));
}