Add convenience function for creating nbt sockets in torture.
[ab/samba.git/.git] / source4 / torture / nbt / wins.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    NBT WINS server testing
5
6    Copyright (C) Andrew Tridgell 2005
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "lib/socket/socket.h"
24 #include "libcli/resolve/resolve.h"
25 #include "system/network.h"
26 #include "lib/socket/netif.h"
27 #include "librpc/gen_ndr/ndr_nbt.h"
28 #include "torture/torture.h"
29 #include "torture/nbt/proto.h"
30 #include "param/param.h"
31
32 #define CHECK_VALUE(tctx, v, correct) \
33         torture_assert_int_equal(tctx, v, correct, "Incorrect value")
34
35 #define CHECK_STRING(tctx, v, correct) \
36         torture_assert_casestr_equal(tctx, v, correct, "Incorrect value")
37
38 #define CHECK_NAME(tctx, _name, correct) do { \
39         CHECK_STRING(tctx, (_name).name, (correct).name); \
40         CHECK_VALUE(tctx, (uint8_t)(_name).type, (uint8_t)(correct).type); \
41         CHECK_STRING(tctx, (_name).scope, (correct).scope); \
42 } while (0)
43
44
45 /*
46   test operations against a WINS server
47 */
48 static bool nbt_test_wins_name(struct torture_context *tctx, const char *address,
49                                struct nbt_name *name, uint16_t nb_flags)
50 {
51         struct nbt_name_register_wins io;
52         struct nbt_name_query query;
53         struct nbt_name_refresh_wins refresh;
54         struct nbt_name_release release;
55         NTSTATUS status;
56         struct nbt_name_socket *nbtsock = torture_init_nbt_socket(tctx);
57         const char *myaddress;
58         struct socket_address *socket_address;
59         struct interface *ifaces;
60
61         load_interfaces(tctx, lp_interfaces(tctx->lp_ctx), &ifaces);
62
63         myaddress = talloc_strdup(tctx, iface_best_ip(ifaces, address));
64
65         socket_address = socket_address_from_strings(tctx, 
66                                                      nbtsock->sock->backend_name,
67                                                      myaddress, 0);
68         torture_assert(tctx, socket_address != NULL, 
69                                    "Error getting address");
70
71         /* we do the listen here to ensure the WINS server receives the packets from
72            the right IP */
73         status = socket_listen(nbtsock->sock, socket_address, 0, 0);
74         torture_assert_ntstatus_ok(tctx, status, 
75                                                            "socket_listen for WINS failed");
76         talloc_free(socket_address);
77
78         torture_comment(tctx, "Testing name registration to WINS with name %s at %s nb_flags=0x%x\n", 
79                nbt_name_string(tctx, name), myaddress, nb_flags);
80
81         torture_comment(tctx, "release the name\n");
82         release.in.name = *name;
83         release.in.dest_port = lp_nbt_port(tctx->lp_ctx);
84         release.in.dest_addr = address;
85         release.in.address = myaddress;
86         release.in.nb_flags = nb_flags;
87         release.in.broadcast = false;
88         release.in.timeout = 3;
89         release.in.retries = 0;
90
91         status = nbt_name_release(nbtsock, tctx, &release);
92         torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name query", address));
93         CHECK_VALUE(tctx, release.out.rcode, 0);
94
95         torture_comment(tctx, "register the name\n");
96         io.in.name = *name;
97         io.in.wins_port = lp_nbt_port(tctx->lp_ctx);
98         io.in.wins_servers = str_list_make(tctx, address, NULL);
99         io.in.addresses = str_list_make(tctx, myaddress, NULL);
100         io.in.nb_flags = nb_flags;
101         io.in.ttl = 300000;
102         
103         status = nbt_name_register_wins(nbtsock, tctx, &io);
104         torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name register", address));
105         
106         CHECK_STRING(tctx, io.out.wins_server, address);
107         CHECK_VALUE(tctx, io.out.rcode, 0);
108
109         if (name->type != NBT_NAME_MASTER &&
110             name->type != NBT_NAME_LOGON && 
111             name->type != NBT_NAME_BROWSER && 
112             (nb_flags & NBT_NM_GROUP)) {
113                 torture_comment(tctx, "Try to register as non-group\n");
114                 io.in.nb_flags &= ~NBT_NM_GROUP;
115                 status = nbt_name_register_wins(nbtsock, tctx, &io);
116                 torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name register\n",
117                         address));
118                 CHECK_VALUE(tctx, io.out.rcode, NBT_RCODE_ACT);
119         }
120
121         torture_comment(tctx, "query the name to make sure its there\n");
122         query.in.name = *name;
123         query.in.dest_addr = address;
124         query.in.dest_port = lp_nbt_port(tctx->lp_ctx);
125         query.in.broadcast = false;
126         query.in.wins_lookup = true;
127         query.in.timeout = 3;
128         query.in.retries = 0;
129
130         status = nbt_name_query(nbtsock, tctx, &query);
131         if (name->type == NBT_NAME_MASTER) {
132                 torture_assert_ntstatus_equal(
133                           tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, 
134                           talloc_asprintf(tctx, "Bad response from %s for name query", address));
135                 return true;
136         }
137         torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name query", address));
138         
139         CHECK_NAME(tctx, query.out.name, *name);
140         CHECK_VALUE(tctx, query.out.num_addrs, 1);
141         if (name->type != NBT_NAME_LOGON &&
142             (nb_flags & NBT_NM_GROUP)) {
143                 CHECK_STRING(tctx, query.out.reply_addrs[0], "255.255.255.255");
144         } else {
145                 CHECK_STRING(tctx, query.out.reply_addrs[0], myaddress);
146         }
147
148
149         query.in.name.name = strupper_talloc(tctx, name->name);
150         if (query.in.name.name &&
151             strcmp(query.in.name.name, name->name) != 0) {
152                 torture_comment(tctx, "check case sensitivity\n");
153                 status = nbt_name_query(nbtsock, tctx, &query);
154                 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, talloc_asprintf(tctx, "Bad response from %s for name query", address));
155         }
156
157         query.in.name = *name;
158         if (name->scope) {
159                 query.in.name.scope = strupper_talloc(tctx, name->scope);
160         }
161         if (query.in.name.scope &&
162             strcmp(query.in.name.scope, name->scope) != 0) {
163                 torture_comment(tctx, "check case sensitivity on scope\n");
164                 status = nbt_name_query(nbtsock, tctx, &query);
165                 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, talloc_asprintf(tctx, "Bad response from %s for name query", address));
166         }
167
168         torture_comment(tctx, "refresh the name\n");
169         refresh.in.name = *name;
170         refresh.in.wins_port = lp_nbt_port(tctx->lp_ctx);
171         refresh.in.wins_servers = str_list_make(tctx, address, NULL);
172         refresh.in.addresses = str_list_make(tctx, myaddress, NULL);
173         refresh.in.nb_flags = nb_flags;
174         refresh.in.ttl = 12345;
175         
176         status = nbt_name_refresh_wins(nbtsock, tctx, &refresh);
177         torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name refresh", address));
178         
179         CHECK_STRING(tctx, refresh.out.wins_server, address);
180         CHECK_VALUE(tctx, refresh.out.rcode, 0);
181
182         torture_comment(tctx, "release the name\n");
183         release.in.name = *name;
184         release.in.dest_addr = address;
185         release.in.address = myaddress;
186         release.in.nb_flags = nb_flags;
187         release.in.broadcast = false;
188         release.in.timeout = 3;
189         release.in.retries = 0;
190
191         status = nbt_name_release(nbtsock, tctx, &release);
192         torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name query", address));
193         
194         CHECK_NAME(tctx, release.out.name, *name);
195         CHECK_VALUE(tctx, release.out.rcode, 0);
196
197         torture_comment(tctx, "release again\n");
198         status = nbt_name_release(nbtsock, tctx, &release);
199         torture_assert_ntstatus_ok(tctx, status, 
200                                 talloc_asprintf(tctx, "Bad response from %s for name query",
201                        address));
202         
203         CHECK_NAME(tctx, release.out.name, *name);
204         CHECK_VALUE(tctx, release.out.rcode, 0);
205
206
207         torture_comment(tctx, "query the name to make sure its gone\n");
208         query.in.name = *name;
209         status = nbt_name_query(nbtsock, tctx, &query);
210         if (name->type != NBT_NAME_LOGON &&
211             (nb_flags & NBT_NM_GROUP)) {
212                 torture_assert_ntstatus_ok(tctx, status, 
213                                 "ERROR: Name query failed after group release");
214         } else {
215                 torture_assert_ntstatus_equal(tctx, status, 
216                                                                           NT_STATUS_OBJECT_NAME_NOT_FOUND,
217                                 "Incorrect response to name query");
218         }
219         
220         return true;
221 }
222
223
224
225 /*
226   test operations against a WINS server
227 */
228 static bool nbt_test_wins(struct torture_context *tctx)
229 {
230         struct nbt_name name;
231         uint32_t r = (uint32_t)(random() % (100000));
232         const char *address;
233         bool ret = true;
234
235         if (!torture_nbt_get_name(tctx, &name, &address))
236                 return false;
237
238         name.name = talloc_asprintf(tctx, "_TORTURE-%5u", r);
239
240         name.type = NBT_NAME_CLIENT;
241         name.scope = NULL;
242         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
243
244         name.type = NBT_NAME_MASTER;
245         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
246
247         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H | NBT_NM_GROUP);
248
249         name.type = NBT_NAME_SERVER;
250         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
251
252         name.type = NBT_NAME_LOGON;
253         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H | NBT_NM_GROUP);
254
255         name.type = NBT_NAME_BROWSER;
256         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H | NBT_NM_GROUP);
257
258         name.type = NBT_NAME_PDC;
259         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
260
261         name.type = 0xBF;
262         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
263
264         name.type = 0xBE;
265         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
266
267         name.scope = "example";
268         name.type = 0x72;
269         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
270
271         name.scope = "example";
272         name.type = 0x71;
273         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H | NBT_NM_GROUP);
274
275         name.scope = "foo.example.com";
276         name.type = 0x72;
277         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
278
279         name.name = talloc_asprintf(tctx, "_T\01-%5u.foo", r);
280         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
281
282         name.name = "";
283         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
284
285         name.name = talloc_asprintf(tctx, ".");
286         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
287
288         name.name = talloc_asprintf(tctx, "%5u-\377\200\300FOO", r);
289         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
290
291         return ret;
292 }
293
294 /*
295   test WINS operations
296 */
297 struct torture_suite *torture_nbt_wins(TALLOC_CTX *mem_ctx)
298 {
299         struct torture_suite *suite = torture_suite_create(mem_ctx, "WINS");
300
301         torture_suite_add_simple_test(suite, "wins", nbt_test_wins);
302
303         return suite;
304 }