r5387: - added automatic WINS server record expiry
authorAndrew Tridgell <tridge@samba.org>
Mon, 14 Feb 2005 05:00:22 +0000 (05:00 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:09:50 +0000 (13:09 -0500)
- added support for group names in registration and query

source/nbt_server/winsdb.c
source/nbt_server/winsdb.h
source/nbt_server/winsserver.c

index 53fceedf37b06c0d80d4e27b05415a52eb2701c6..f452e58e70cfd5671e140ec6493d7fd0ea9ce91d 100644 (file)
@@ -25,6 +25,7 @@
 #include "nbt_server/winsdb.h"
 #include "lib/ldb/include/ldb.h"
 #include "db_wrap.h"
+#include "system/time.h"
 
 /*
   load a WINS entry from the database
@@ -72,6 +73,14 @@ struct winsdb_record *winsdb_load(struct wins_server *winssrv,
        }
        rec->addresses[i] = NULL;
 
+       /* see if it has already expired */
+       if (rec->state == WINS_REC_ACTIVE &&
+           rec->expire_time <= time(NULL)) {
+               DEBUG(5,("WINS: expiring name %s (expired at %s)\n", 
+                        nbt_name_string(tmp_ctx, rec->name), timestring(tmp_ctx, rec->expire_time)));
+               rec->state = WINS_REC_EXPIRED;
+       }
+
        talloc_steal(mem_ctx, rec);
        talloc_free(tmp_ctx);
        return rec;
@@ -164,6 +173,32 @@ failed:
        return NBT_RCODE_SVR;
 }
 
+
+/*
+  delete a WINS record from the database
+*/
+uint8_t winsdb_delete(struct wins_server *winssrv, struct nbt_name *name)
+{
+       struct ldb_context *ldb = winssrv->wins_db->ldb;
+       TALLOC_CTX *tmp_ctx = talloc_new(winssrv);
+       int ret;
+       const char *dn;
+
+       dn = talloc_asprintf(tmp_ctx, "NAME=%s", nbt_name_string(tmp_ctx, name));
+       if (dn == NULL) goto failed;
+
+       ret = ldb_delete(ldb, dn);
+       if (ret != 0) goto failed;
+
+       talloc_free(tmp_ctx);
+       return NBT_RCODE_OK;
+
+failed:
+       talloc_free(tmp_ctx);
+       return NBT_RCODE_SVR;
+}
+
+
 /*
   connect to the WINS database
 */
index 72aeb8ef78c7b39ffd3dbe0ac7a2152e15b0cf0d..fd0fe4af70a72d4046d1fa31eb7e61bf5681867b 100644 (file)
@@ -21,8 +21,9 @@
 */
 
 enum wins_record_state {
-       WINS_REC_RELEASED=0,
-       WINS_REC_ACTIVE=1
+       WINS_REC_RELEASED =0,
+       WINS_REC_ACTIVE   =1,
+       WINS_REC_EXPIRED  =2
 };
 
 /*
index b59a1c9fa355ed656e57054c759fb95e6c3e90b3..ad5ccdc16ec6aa9c33c7455f939a39b64d769925 100644 (file)
@@ -37,24 +37,83 @@ static uint8_t wins_register_new(struct nbt_name_socket *nbtsock,
        struct wins_server *winssrv = iface->nbtsrv->winssrv;
        struct nbt_name *name = &packet->questions[0].name;
        uint32_t ttl = packet->additional[0].ttl;
+       uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
+       const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
        struct winsdb_record rec;
 
        ttl = MIN(ttl, winssrv->max_ttl);
        ttl = MAX(ttl, winssrv->min_ttl);
 
        rec.name          = name;
-       rec.nb_flags      = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
+       rec.nb_flags      = nb_flags;
        rec.state         = WINS_REC_ACTIVE;
        rec.expire_time   = time(NULL) + ttl;
        rec.registered_by = src_address;
-       rec.addresses     = str_list_make(packet, 
-                                         packet->additional[0].rdata.netbios.addresses[0].ipaddr,
-                                         NULL);
+       if (nb_flags & NBT_NM_GROUP) {
+               rec.addresses     = str_list_make(packet, "255.255.255.255", NULL);
+       } else {
+               rec.addresses     = str_list_make(packet, address, NULL);
+       }
+       if (rec.addresses == NULL) return NBT_RCODE_SVR;
+
+       DEBUG(4,("WINS: accepted registration of %s with address %s\n",
+                nbt_name_string(packet, name), rec.addresses[0]));
        
        return winsdb_add(winssrv, &rec);
 }
 
 
+/*
+  update the ttl on an existing record
+*/
+static uint8_t wins_update_ttl(struct nbt_name_socket *nbtsock, 
+                              struct nbt_name_packet *packet, 
+                              struct winsdb_record *rec,
+                              const char *src_address, int src_port)
+{
+       struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, 
+                                                      struct nbtd_interface);
+       struct wins_server *winssrv = iface->nbtsrv->winssrv;
+       uint32_t ttl = packet->additional[0].ttl;
+       const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
+       time_t now = time(NULL);
+
+       ttl = MIN(ttl, winssrv->max_ttl);
+       ttl = MAX(ttl, winssrv->min_ttl);
+
+       if (now + ttl > rec->expire_time) {
+               rec->expire_time   = now + ttl;
+       }
+       rec->registered_by = src_address;
+
+       DEBUG(5,("WINS: refreshed registration of %s at %s\n",
+                nbt_name_string(packet, rec->name), address));
+       
+       return winsdb_modify(winssrv, rec);
+}
+
+
+/*
+  send a WACK reply, then check if the current owners want to keep the name
+*/
+static uint8_t wins_register_wack(struct nbt_name_socket *nbtsock, 
+                                 struct nbt_name_packet *packet, 
+                                 struct winsdb_record *rec,
+                                 const char *src_address, int src_port)
+{
+       struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, 
+                                                      struct nbtd_interface);
+       struct wins_server *winssrv = iface->nbtsrv->winssrv;
+       uint32_t ttl = packet->additional[0].ttl;
+       const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
+       time_t now = time(NULL);
+
+       DEBUG(0,("TODO: WACK\n"));
+
+       return NBT_RCODE_SVR;
+}
+
+
 /*
   register a name
 */
@@ -67,27 +126,58 @@ static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock,
        struct wins_server *winssrv = iface->nbtsrv->winssrv;
        struct nbt_name *name = &packet->questions[0].name;
        struct winsdb_record *rec;
-       uint8_t rcode = 0;
+       uint8_t rcode = NBT_RCODE_OK;
+       uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
+       const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
+       int i;
 
        rec = winsdb_load(winssrv, name, packet);
        if (rec == NULL) {
                rcode = wins_register_new(nbtsock, packet, src_address, src_port);
+               goto done;
        } else if (rec->state != WINS_REC_ACTIVE) {
-               uint32_t ttl = packet->additional[0].ttl;
-               ttl = MIN(ttl, winssrv->max_ttl);
-               ttl = MAX(ttl, winssrv->min_ttl);
-               rec->nb_flags      = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
-               rec->state         = WINS_REC_ACTIVE;
-               rec->expire_time   = time(NULL) + ttl;
-               rec->registered_by = src_address;
-               rec->addresses     = str_list_make(packet, 
-                                                  packet->additional[0].rdata.netbios.addresses[0].ipaddr,
-                                                  NULL);
-               winsdb_modify(winssrv, rec);
-       } else {
+               winsdb_delete(winssrv, rec->name);
+               rcode = wins_register_new(nbtsock, packet, src_address, src_port);
+               goto done;
+       }
+
+       /* its an active name - first see if the registration is of the right type */
+       if ((rec->nb_flags & NBT_NM_GROUP) && !(nb_flags & NBT_NM_GROUP)) {
+               DEBUG(2,("WINS: Attempt to register unique name %s when group name is active\n",
+                        nbt_name_string(packet, name)));
                rcode = NBT_RCODE_ACT;
+               goto done;
+       }
+
+       /* if its an active unique name, and the registration is for a group, then
+          see if the unique name owner still wants the name */
+       if (!(rec->nb_flags & NBT_NM_GROUP) && (nb_flags & NBT_NM_GROUP)) {
+               wins_register_wack(nbtsock, packet, rec, src_address, src_port);
+               return;
        }
 
+       /* if the registration is for a group, then just update the expiry time 
+          and we are done */
+       if (nb_flags & NBT_NM_GROUP) {
+               wins_update_ttl(nbtsock, packet, rec, src_address, src_port);
+               goto done;
+       }
+
+       /* if the registration is for an address that is currently active, then 
+          just update the expiry time */
+       for (i=0;rec->addresses[i];i++) {
+               if (strcmp(address, rec->addresses[i]) == 0) {
+                       wins_update_ttl(nbtsock, packet, rec, src_address, src_port);
+                       goto done;
+               }
+       }
+
+       /* we have to do a WACK to see if the current owners are willing to give
+          up their claim */    
+       wins_register_wack(nbtsock, packet, rec, src_address, src_port);
+       return;
+
+done:
        nbtd_name_registration_reply(nbtsock, packet, src_address, src_port, rcode);
 }
 
@@ -130,7 +220,10 @@ static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock,
        struct winsdb_record *rec;
 
        rec = winsdb_load(winssrv, name, packet);
-       if (rec != NULL && rec->state == WINS_REC_ACTIVE) {
+       if (rec != NULL && 
+           rec->state == WINS_REC_ACTIVE &&
+           !(rec->nb_flags & NBT_NM_GROUP)) {
+               /* should we release all, or only some of the addresses? */
                rec->state = WINS_REC_RELEASED;
                winsdb_modify(winssrv, rec);
        }