NBT-WINS: test if the server ignores resent packets
[kai/samba-autobuild/.git] / source4 / torture / nbt / wins.c
index 313a46b02af8ac0a416efb2e5a930c0be050f414..c581a69ca728989371ee935bdd6a3c874d496502 100644 (file)
@@ -7,7 +7,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
-#include "libcli/nbt/libnbt.h"
-#include "librpc/gen_ndr/ndr_nbt.h"
+#include "dlinklist.h"
+#include "lib/events/events.h"
 #include "lib/socket/socket.h"
+#include "libcli/resolve/resolve.h"
+#include "system/network.h"
+#include "lib/socket/netif.h"
+#include "librpc/gen_ndr/ndr_nbt.h"
+#include "torture/torture.h"
+#include "torture/nbt/proto.h"
+#include "param/param.h"
 
-#define CHECK_VALUE(v, correct) do { \
-       if ((v) != (correct)) { \
-               printf("(%s) Incorrect value %s=%d - should be %d\n", \
-                      __location__, #v, v, correct); \
-               ret = False; \
-       }} while (0)
+#define CHECK_VALUE(tctx, v, correct) \
+       torture_assert_int_equal(tctx, v, correct, "Incorrect value")
 
-#define CHECK_STRING(v, correct) do { \
-       if (StrCaseCmp(v, correct) != 0) { \
-               printf("(%s) Incorrect value %s='%s' - should be '%s'\n", \
-                      __location__, #v, v, correct); \
-               ret = False; \
-       }} while (0)
+#define CHECK_STRING(tctx, v, correct) \
+       torture_assert_casestr_equal(tctx, v, correct, "Incorrect value")
+
+#define CHECK_NAME(tctx, _name, correct) do { \
+       CHECK_STRING(tctx, (_name).name, (correct).name); \
+       CHECK_VALUE(tctx, (uint8_t)(_name).type, (uint8_t)(correct).type); \
+       CHECK_STRING(tctx, (_name).scope, (correct).scope); \
+} while (0)
 
 
 /*
   test operations against a WINS server
 */
-static BOOL nbt_test_wins(TALLOC_CTX *mem_ctx, struct nbt_name *name, 
-                             const char *address)
+static bool nbt_test_wins_name(struct torture_context *tctx, const char *address,
+                              struct nbt_name *name, uint16_t nb_flags,
+                              bool try_low_port)
 {
        struct nbt_name_register_wins io;
+       struct nbt_name_register name_register;
        struct nbt_name_query query;
        struct nbt_name_refresh_wins refresh;
        struct nbt_name_release release;
+       struct nbt_name_request *req;
        NTSTATUS status;
-       struct nbt_name_socket *nbtsock = nbt_name_socket_init(mem_ctx, NULL);
-       BOOL ret = True;
-       const char *myaddress = talloc_strdup(mem_ctx, iface_n_ip(0));
-       const char *tname = talloc_asprintf(mem_ctx, "_TORTURE-%5u", 
-                                         (unsigned)(random() % (100000)));
+       struct nbt_name_socket *nbtsock = torture_init_nbt_socket(tctx);
+       const char *myaddress;
+       struct socket_address *socket_address;
+       struct interface *ifaces;
+       bool low_port = try_low_port;
+
+       load_interfaces(tctx, lp_interfaces(tctx->lp_ctx), &ifaces);
+
+       myaddress = talloc_strdup(tctx, iface_best_ip(ifaces, address));
+
+       socket_address = socket_address_from_strings(tctx, 
+                                                    nbtsock->sock->backend_name,
+                                                    myaddress, lp_nbt_port(tctx->lp_ctx));
+       torture_assert(tctx, socket_address != NULL, 
+                                  "Error getting address");
 
        /* we do the listen here to ensure the WINS server receives the packets from
           the right IP */
-       socket_listen(nbtsock->sock, myaddress, 0, 0, 0);
+       status = socket_listen(nbtsock->sock, socket_address, 0, 0);
+       talloc_free(socket_address);
+       if (!NT_STATUS_IS_OK(status)) {
+               low_port = false;
+               socket_address = socket_address_from_strings(tctx,
+                                                            nbtsock->sock->backend_name,
+                                                            myaddress, 0);
+               torture_assert(tctx, socket_address != NULL,
+                              "Error getting address");
 
-       printf("Testing name registration to WINS with name '%s' at %s\n", tname, myaddress);
+               status = socket_listen(nbtsock->sock, socket_address, 0, 0);
+               talloc_free(socket_address);
+               torture_assert_ntstatus_ok(tctx, status,
+                                          "socket_listen for WINS failed");
+       }
+
+       torture_comment(tctx, "Testing name registration to WINS with name %s at %s nb_flags=0x%x\n", 
+              nbt_name_string(tctx, name), myaddress, nb_flags);
 
-       io.in.name.name = tname;
-       io.in.name.type = NBT_NAME_CLIENT;
-       io.in.name.scope = NULL;
-       io.in.wins_servers = str_list_make(mem_ctx, address, NULL);
-       io.in.addresses = str_list_make(mem_ctx, myaddress, NULL);
-       io.in.nb_flags = NBT_NODE_H;
+       torture_comment(tctx, "release the name\n");
+       release.in.name = *name;
+       release.in.dest_port = lp_nbt_port(tctx->lp_ctx);
+       release.in.dest_addr = address;
+       release.in.address = myaddress;
+       release.in.nb_flags = nb_flags;
+       release.in.broadcast = false;
+       release.in.timeout = 3;
+       release.in.retries = 0;
+
+       status = nbt_name_release(nbtsock, tctx, &release);
+       torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name query", address));
+       CHECK_VALUE(tctx, release.out.rcode, 0);
+
+       if (nb_flags & NBT_NM_GROUP) {
+               /* ignore this for group names */
+       } else if (!low_port) {
+               torture_comment(tctx, "no low port - skip: register the name with a wrong address\n");
+       } else {
+               torture_comment(tctx, "register the name with a wrong address (makes the next request slow!)\n");
+               io.in.name = *name;
+               io.in.wins_port = lp_nbt_port(tctx->lp_ctx);
+               io.in.wins_servers = str_list_make(tctx, address, NULL);
+               io.in.addresses = str_list_make(tctx, "127.64.64.1", NULL);
+               io.in.nb_flags = nb_flags;
+               io.in.ttl = 300000;
+
+               status = nbt_name_register_wins(nbtsock, tctx, &io);
+               if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+                       torture_assert_ntstatus_ok(tctx, status,
+                               talloc_asprintf(tctx, "No response from %s for name register\n",
+                                               address));
+               }
+               torture_assert_ntstatus_ok(tctx, status,
+                       talloc_asprintf(tctx, "Bad response from %s for name register\n",
+                                       address));
+
+               CHECK_STRING(tctx, io.out.wins_server, address);
+               CHECK_VALUE(tctx, io.out.rcode, 0);
+
+               torture_comment(tctx, "register the name correct address\n");
+               name_register.in.name           = *name;
+               name_register.in.dest_port      = lp_nbt_port(tctx->lp_ctx);
+               name_register.in.dest_addr      = address;
+               name_register.in.address        = myaddress;
+               name_register.in.nb_flags       = nb_flags;
+               name_register.in.register_demand= false;
+               name_register.in.broadcast      = false;
+               name_register.in.multi_homed    = true;
+               name_register.in.ttl            = 300000;
+               name_register.in.timeout        = 3;
+               name_register.in.retries        = 2;
+
+               /*
+                * test if the server ignores resent requests
+                */
+               req = nbt_name_register_send(nbtsock, &name_register);
+               while (true) {
+                       event_loop_once(nbtsock->event_ctx);
+                       if (req->state != NBT_REQUEST_WAIT) {
+                               break;
+                       }
+                       if (req->received_wack) {
+                               /*
+                                * if we received the wack response
+                                * we resend the request and the
+                                * server should ignore that
+                                * and not handle it as new request
+                                */
+                               req->state = NBT_REQUEST_SEND;
+                               DLIST_ADD_END(nbtsock->send_queue, req,
+                                             struct nbt_name_request *);
+                               EVENT_FD_WRITEABLE(nbtsock->fde);
+                               break;
+                       }
+               }
+
+               status = nbt_name_register_recv(req, tctx, &name_register);
+               if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+                       torture_assert_ntstatus_ok(tctx, status,
+                               talloc_asprintf(tctx, "No response from %s for name register\n",
+                                               address));
+               }
+               torture_assert_ntstatus_ok(tctx, status,
+                       talloc_asprintf(tctx, "Bad response from %s for name register\n",
+                                       address));
+
+               CHECK_VALUE(tctx, name_register.out.rcode, 0);
+               CHECK_STRING(tctx, name_register.out.reply_addr, myaddress);
+       }
+
+       torture_comment(tctx, "register the name correct address\n");
+       io.in.name = *name;
+       io.in.wins_port = lp_nbt_port(tctx->lp_ctx);
+       io.in.wins_servers = (const char **)str_list_make(tctx, address, NULL);
+       io.in.addresses = (const char **)str_list_make(tctx, myaddress, NULL);
+       io.in.nb_flags = nb_flags;
        io.in.ttl = 300000;
        
-       status = nbt_name_register_wins(nbtsock, mem_ctx, &io);
-       if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
-               printf("No response from %s for name register\n", address);
-               return False;
-       }
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("Bad response from %s for name register - %s\n",
-                      address, nt_errstr(status));
-               return False;
-       }
+       status = nbt_name_register_wins(nbtsock, tctx, &io);
+       torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name register", address));
        
-       CHECK_STRING(io.out.wins_server, address);
-       CHECK_VALUE(io.out.rcode, 0);
+       CHECK_STRING(tctx, io.out.wins_server, address);
+       CHECK_VALUE(tctx, io.out.rcode, 0);
+
+       if (name->type != NBT_NAME_MASTER &&
+           name->type != NBT_NAME_LOGON && 
+           name->type != NBT_NAME_BROWSER && 
+           (nb_flags & NBT_NM_GROUP)) {
+               torture_comment(tctx, "Try to register as non-group\n");
+               io.in.nb_flags &= ~NBT_NM_GROUP;
+               status = nbt_name_register_wins(nbtsock, tctx, &io);
+               torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name register\n",
+                       address));
+               CHECK_VALUE(tctx, io.out.rcode, NBT_RCODE_ACT);
+       }
 
-       printf("query the name to make sure its there\n");
-       query.in.name = io.in.name;
+       torture_comment(tctx, "query the name to make sure its there\n");
+       query.in.name = *name;
        query.in.dest_addr = address;
-       query.in.broadcast = False;
-       query.in.wins_lookup = True;
+       query.in.dest_port = lp_nbt_port(tctx->lp_ctx);
+       query.in.broadcast = false;
+       query.in.wins_lookup = true;
        query.in.timeout = 3;
        query.in.retries = 0;
 
-       status = nbt_name_query(nbtsock, mem_ctx, &query);
-       if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
-               printf("No response from %s for name query\n", address);
-               return False;
-       }
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("Bad response from %s for name query - %s\n",
-                      address, nt_errstr(status));
-               return False;
+       status = nbt_name_query(nbtsock, tctx, &query);
+       if (name->type == NBT_NAME_MASTER) {
+               torture_assert_ntstatus_equal(
+                         tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, 
+                         talloc_asprintf(tctx, "Bad response from %s for name query", address));
+               return true;
        }
+       torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name query", address));
        
-       CHECK_STRING(query.out.name.name, tname);
-       CHECK_VALUE(query.out.name.type, NBT_NAME_CLIENT);
-       CHECK_VALUE(query.out.num_addrs, 1);
-       CHECK_STRING(query.out.reply_addrs[0], myaddress);
-
-       printf("refresh the name\n");
-       refresh.in.name.name = tname;
-       refresh.in.name.type = NBT_NAME_CLIENT;
-       refresh.in.name.scope = NULL;
-       refresh.in.wins_servers = str_list_make(mem_ctx, address, NULL);
-       refresh.in.addresses = str_list_make(mem_ctx, myaddress, NULL);
-       refresh.in.nb_flags = NBT_NODE_H;
+       CHECK_NAME(tctx, query.out.name, *name);
+       CHECK_VALUE(tctx, query.out.num_addrs, 1);
+       if (name->type != NBT_NAME_LOGON &&
+           (nb_flags & NBT_NM_GROUP)) {
+               CHECK_STRING(tctx, query.out.reply_addrs[0], "255.255.255.255");
+       } else {
+               CHECK_STRING(tctx, query.out.reply_addrs[0], myaddress);
+       }
+
+
+       query.in.name.name = strupper_talloc(tctx, name->name);
+       if (query.in.name.name &&
+           strcmp(query.in.name.name, name->name) != 0) {
+               torture_comment(tctx, "check case sensitivity\n");
+               status = nbt_name_query(nbtsock, tctx, &query);
+               torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, talloc_asprintf(tctx, "Bad response from %s for name query", address));
+       }
+
+       query.in.name = *name;
+       if (name->scope) {
+               query.in.name.scope = strupper_talloc(tctx, name->scope);
+       }
+       if (query.in.name.scope &&
+           strcmp(query.in.name.scope, name->scope) != 0) {
+               torture_comment(tctx, "check case sensitivity on scope\n");
+               status = nbt_name_query(nbtsock, tctx, &query);
+               torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, talloc_asprintf(tctx, "Bad response from %s for name query", address));
+       }
+
+       torture_comment(tctx, "refresh the name\n");
+       refresh.in.name = *name;
+       refresh.in.wins_port = lp_nbt_port(tctx->lp_ctx);
+       refresh.in.wins_servers = (const char **)str_list_make(tctx, address, NULL);
+       refresh.in.addresses = (const char **)str_list_make(tctx, myaddress, NULL);
+       refresh.in.nb_flags = nb_flags;
        refresh.in.ttl = 12345;
        
-       status = nbt_name_refresh_wins(nbtsock, mem_ctx, &refresh);
+       status = nbt_name_refresh_wins(nbtsock, tctx, &refresh);
        if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
-               printf("No response from %s for name refresh\n", address);
-               return False;
-       }
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("Bad response from %s for name refresh - %s\n",
-                      address, nt_errstr(status));
-               return False;
+               torture_assert_ntstatus_ok(tctx, status,
+                       talloc_asprintf(tctx, "No response from %s for name refresh",
+                                       address));
        }
-       
-       CHECK_STRING(io.out.wins_server, address);
-       CHECK_VALUE(io.out.rcode, 0);
+       torture_assert_ntstatus_ok(tctx, status,
+               talloc_asprintf(tctx, "Bad response from %s for name refresh",
+                               address));
+
+       CHECK_STRING(tctx, refresh.out.wins_server, address);
+       CHECK_VALUE(tctx, refresh.out.rcode, 0);
 
        printf("release the name\n");
-       release.in.name = io.in.name;
+       release.in.name = *name;
+       release.in.dest_port = lp_nbt_port(tctx->lp_ctx);
        release.in.dest_addr = address;
        release.in.address = myaddress;
-       release.in.nb_flags = NBT_NODE_H;
-       release.in.broadcast = False;
+       release.in.nb_flags = nb_flags;
+       release.in.broadcast = false;
        release.in.timeout = 3;
        release.in.retries = 0;
 
-       status = nbt_name_release(nbtsock, mem_ctx, &release);
+       status = nbt_name_release(nbtsock, tctx, &release);
        if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
-               printf("No response from %s for name release\n", address);
-               return False;
-       }
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("Bad response from %s for name query - %s\n",
-                      address, nt_errstr(status));
-               return False;
+               torture_assert_ntstatus_ok(tctx, status,
+                       talloc_asprintf(tctx, "No response from %s for name release",
+                                       address));
        }
+       torture_assert_ntstatus_ok(tctx, status,
+               talloc_asprintf(tctx, "Bad response from %s for name release",
+                               address));
+
+       CHECK_NAME(tctx, release.out.name, *name);
+       CHECK_VALUE(tctx, release.out.rcode, 0);
+
+       if (nb_flags & NBT_NM_GROUP) {
+               /* ignore this for group names */
+       } else if (!low_port) {
+               torture_comment(tctx, "no low port - skip: register the name with a wrong address\n");
+       } else {
+               torture_comment(tctx, "register the name with a wrong address (makes the next request slow!)\n");
+               io.in.name = *name;
+               io.in.wins_port = lp_nbt_port(tctx->lp_ctx);
+               io.in.wins_servers = str_list_make(tctx, address, NULL);
+               io.in.addresses = str_list_make(tctx, "127.64.64.1", NULL);
+               io.in.nb_flags = nb_flags;
+               io.in.ttl = 300000;
        
-       CHECK_STRING(release.out.name.name, tname);
-       CHECK_VALUE(release.out.name.type, NBT_NAME_CLIENT);
-       CHECK_VALUE(release.out.rcode, 0);
+               status = nbt_name_register_wins(nbtsock, tctx, &io);
+               if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+                       torture_assert_ntstatus_ok(tctx, status,
+                               talloc_asprintf(tctx, "No response from %s for name register\n",
+                                               address));
+               }
+               torture_assert_ntstatus_ok(tctx, status,
+                       talloc_asprintf(tctx, "Bad response from %s for name register\n",
+                                       address));
 
-       printf("release again\n");
-       status = nbt_name_release(nbtsock, mem_ctx, &release);
-       if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
-               printf("No response from %s for name release\n", address);
-               return False;
+               CHECK_STRING(tctx, io.out.wins_server, address);
+               CHECK_VALUE(tctx, io.out.rcode, 0);
        }
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("Bad response from %s for name query - %s\n",
-                      address, nt_errstr(status));
-               return False;
+
+       torture_comment(tctx, "refresh the name with the correct address\n");
+       refresh.in.name = *name;
+       refresh.in.wins_port = lp_nbt_port(tctx->lp_ctx);
+       refresh.in.wins_servers = str_list_make(tctx, address, NULL);
+       refresh.in.addresses = str_list_make(tctx, myaddress, NULL);
+       refresh.in.nb_flags = nb_flags;
+       refresh.in.ttl = 12345;
+
+       status = nbt_name_refresh_wins(nbtsock, tctx, &refresh);
+       if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+               torture_assert_ntstatus_ok(tctx, status,
+                       talloc_asprintf(tctx, "No response from %s for name refresh",
+                                       address));
        }
+       torture_assert_ntstatus_ok(tctx, status,
+               talloc_asprintf(tctx, "Bad response from %s for name refresh",
+                               address));
+
+       CHECK_STRING(tctx, refresh.out.wins_server, address);
+       CHECK_VALUE(tctx, refresh.out.rcode, 0);
+
+       torture_comment(tctx, "release the name\n");
+       release.in.name = *name;
+       release.in.dest_port = lp_nbt_port(tctx->lp_ctx);
+       release.in.dest_addr = address;
+       release.in.address = myaddress;
+       release.in.nb_flags = nb_flags;
+       release.in.broadcast = false;
+       release.in.timeout = 3;
+       release.in.retries = 0;
+
+       status = nbt_name_release(nbtsock, tctx, &release);
+       torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name query", address));
        
-       CHECK_STRING(release.out.name.name, tname);
-       CHECK_VALUE(release.out.name.type, NBT_NAME_CLIENT);
-       CHECK_VALUE(release.out.rcode, 0);
+       CHECK_NAME(tctx, release.out.name, *name);
+       CHECK_VALUE(tctx, release.out.rcode, 0);
 
+       torture_comment(tctx, "release again\n");
+       status = nbt_name_release(nbtsock, tctx, &release);
+       torture_assert_ntstatus_ok(tctx, status, 
+                               talloc_asprintf(tctx, "Bad response from %s for name query",
+                      address));
+       
+       CHECK_NAME(tctx, release.out.name, *name);
+       CHECK_VALUE(tctx, release.out.rcode, 0);
 
-       printf("query the name to make sure its gone\n");
-       status = nbt_name_query(nbtsock, mem_ctx, &query);
-       if (NT_STATUS_IS_OK(status)) {
-               printf("ERROR: Name query success after release\n");
-               return False;
-       }
-       if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
-               printf("Incorrect response to name query - %s\n", nt_errstr(status));
-               return False;
+
+       torture_comment(tctx, "query the name to make sure its gone\n");
+       query.in.name = *name;
+       status = nbt_name_query(nbtsock, tctx, &query);
+       if (name->type != NBT_NAME_LOGON &&
+           (nb_flags & NBT_NM_GROUP)) {
+               torture_assert_ntstatus_ok(tctx, status, 
+                               "ERROR: Name query failed after group release");
+       } else {
+               torture_assert_ntstatus_equal(tctx, status, 
+                                                                         NT_STATUS_OBJECT_NAME_NOT_FOUND,
+                               "Incorrect response to name query");
        }
        
-       return ret;
+       return true;
 }
 
 
+
 /*
-  test WINS operations
+  test operations against a WINS server
 */
-BOOL torture_nbt_wins(void)
+static bool nbt_test_wins(struct torture_context *tctx)
 {
-       const char *address;
        struct nbt_name name;
-       TALLOC_CTX *mem_ctx = talloc_new(NULL);
-       NTSTATUS status;
-       BOOL ret = True;
-       
-       name.name = lp_parm_string(-1, "torture", "host");
-       name.type = NBT_NAME_SERVER;
+       uint32_t r = (uint32_t)(random() % (100000));
+       const char *address;
+       bool ret = true;
+
+       if (!torture_nbt_get_name(tctx, &name, &address))
+               return false;
+
+       name.name = talloc_asprintf(tctx, "_TORTURE-%5u", r);
+
+       name.type = NBT_NAME_CLIENT;
        name.scope = NULL;
+       ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H, true);
 
-       /* do an initial name resolution to find its IP */
-       status = resolve_name(&name, mem_ctx, &address);
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("Failed to resolve %s - %s\n",
-                      name.name, nt_errstr(status));
-               talloc_free(mem_ctx);
-               return False;
-       }
+       name.type = NBT_NAME_MASTER;
+       ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H, false);
+
+       ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H | NBT_NM_GROUP, false);
+
+       name.type = NBT_NAME_SERVER;
+       ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H, true);
+
+       name.type = NBT_NAME_LOGON;
+       ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H | NBT_NM_GROUP, false);
+
+       name.type = NBT_NAME_BROWSER;
+       ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H | NBT_NM_GROUP, false);
+
+       name.type = NBT_NAME_PDC;
+       ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H, true);
+
+       name.type = 0xBF;
+       ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H, true);
+
+       name.type = 0xBE;
+       ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H, false);
+
+       name.scope = "example";
+       name.type = 0x72;
+       ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H, true);
 
-       ret &= nbt_test_wins(mem_ctx, &name, address);
+       name.scope = "example";
+       name.type = 0x71;
+       ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H | NBT_NM_GROUP, false);
 
-       talloc_free(mem_ctx);
+       name.scope = "foo.example.com";
+       name.type = 0x72;
+       ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H, false);
+
+       name.name = talloc_asprintf(tctx, "_T\01-%5u.foo", r);
+       ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H, false);
+
+       name.name = "";
+       ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H, false);
+
+       name.name = talloc_asprintf(tctx, ".");
+       ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H, false);
+
+       name.name = talloc_asprintf(tctx, "%5u-\377\200\300FOO", r);
+       ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H, false);
 
        return ret;
 }
+
+/*
+  test WINS operations
+*/
+struct torture_suite *torture_nbt_wins(TALLOC_CTX *mem_ctx)
+{
+       struct torture_suite *suite = torture_suite_create(mem_ctx, "WINS");
+
+       torture_suite_add_simple_test(suite, "wins", nbt_test_wins);
+
+       return suite;
+}