r26309: Move specification of port higher up the all stack.
[kai/samba-autobuild/.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 = nbt_name_socket_init(tctx, NULL);
57         const char *myaddress = talloc_strdup(tctx, iface_best_ip(address));
58         struct socket_address *socket_address;
59
60         socket_address = socket_address_from_strings(tctx, 
61                                                      nbtsock->sock->backend_name,
62                                                      myaddress, 0);
63         torture_assert(tctx, socket_address != NULL, 
64                                    "Error getting address");
65
66         /* we do the listen here to ensure the WINS server receives the packets from
67            the right IP */
68         status = socket_listen(nbtsock->sock, socket_address, 0, 0);
69         torture_assert_ntstatus_ok(tctx, status, 
70                                                            "socket_listen for WINS failed");
71         talloc_free(socket_address);
72
73         torture_comment(tctx, "Testing name registration to WINS with name %s at %s nb_flags=0x%x\n", 
74                nbt_name_string(tctx, name), myaddress, nb_flags);
75
76         torture_comment(tctx, "release the name\n");
77         release.in.name = *name;
78         release.in.dest_addr = address;
79         release.in.address = myaddress;
80         release.in.nb_flags = nb_flags;
81         release.in.broadcast = false;
82         release.in.timeout = 3;
83         release.in.retries = 0;
84
85         status = nbt_name_release(nbtsock, tctx, &release);
86         torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name query", address));
87         CHECK_VALUE(tctx, release.out.rcode, 0);
88
89         torture_comment(tctx, "register the name\n");
90         io.in.name = *name;
91         io.in.wins_servers = str_list_make(tctx, address, NULL);
92         io.in.addresses = str_list_make(tctx, myaddress, NULL);
93         io.in.nb_flags = nb_flags;
94         io.in.ttl = 300000;
95         
96         status = nbt_name_register_wins(nbtsock, tctx, &io);
97         torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name register", address));
98         
99         CHECK_STRING(tctx, io.out.wins_server, address);
100         CHECK_VALUE(tctx, io.out.rcode, 0);
101
102         if (name->type != NBT_NAME_MASTER &&
103             name->type != NBT_NAME_LOGON && 
104             name->type != NBT_NAME_BROWSER && 
105             (nb_flags & NBT_NM_GROUP)) {
106                 torture_comment(tctx, "Try to register as non-group\n");
107                 io.in.nb_flags &= ~NBT_NM_GROUP;
108                 status = nbt_name_register_wins(nbtsock, tctx, &io);
109                 torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name register\n",
110                         address));
111                 CHECK_VALUE(tctx, io.out.rcode, NBT_RCODE_ACT);
112         }
113
114         torture_comment(tctx, "query the name to make sure its there\n");
115         query.in.name = *name;
116         query.in.dest_addr = address;
117         query.in.dest_port = lp_nbt_port(tctx->lp_ctx);
118         query.in.broadcast = false;
119         query.in.wins_lookup = true;
120         query.in.timeout = 3;
121         query.in.retries = 0;
122
123         status = nbt_name_query(nbtsock, tctx, &query);
124         if (name->type == NBT_NAME_MASTER) {
125                 torture_assert_ntstatus_equal(
126                           tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, 
127                           talloc_asprintf(tctx, "Bad response from %s for name query", address));
128                 return true;
129         }
130         torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name query", address));
131         
132         CHECK_NAME(tctx, query.out.name, *name);
133         CHECK_VALUE(tctx, query.out.num_addrs, 1);
134         if (name->type != NBT_NAME_LOGON &&
135             (nb_flags & NBT_NM_GROUP)) {
136                 CHECK_STRING(tctx, query.out.reply_addrs[0], "255.255.255.255");
137         } else {
138                 CHECK_STRING(tctx, query.out.reply_addrs[0], myaddress);
139         }
140
141
142         query.in.name.name = strupper_talloc(tctx, name->name);
143         if (query.in.name.name &&
144             strcmp(query.in.name.name, name->name) != 0) {
145                 torture_comment(tctx, "check case sensitivity\n");
146                 status = nbt_name_query(nbtsock, tctx, &query);
147                 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, talloc_asprintf(tctx, "Bad response from %s for name query", address));
148         }
149
150         query.in.name = *name;
151         if (name->scope) {
152                 query.in.name.scope = strupper_talloc(tctx, name->scope);
153         }
154         if (query.in.name.scope &&
155             strcmp(query.in.name.scope, name->scope) != 0) {
156                 torture_comment(tctx, "check case sensitivity on scope\n");
157                 status = nbt_name_query(nbtsock, tctx, &query);
158                 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, talloc_asprintf(tctx, "Bad response from %s for name query", address));
159         }
160
161         torture_comment(tctx, "refresh the name\n");
162         refresh.in.name = *name;
163         refresh.in.wins_servers = str_list_make(tctx, address, NULL);
164         refresh.in.addresses = str_list_make(tctx, myaddress, NULL);
165         refresh.in.nb_flags = nb_flags;
166         refresh.in.ttl = 12345;
167         
168         status = nbt_name_refresh_wins(nbtsock, tctx, &refresh);
169         torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name refresh", address));
170         
171         CHECK_STRING(tctx, refresh.out.wins_server, address);
172         CHECK_VALUE(tctx, refresh.out.rcode, 0);
173
174         torture_comment(tctx, "release the name\n");
175         release.in.name = *name;
176         release.in.dest_addr = address;
177         release.in.address = myaddress;
178         release.in.nb_flags = nb_flags;
179         release.in.broadcast = false;
180         release.in.timeout = 3;
181         release.in.retries = 0;
182
183         status = nbt_name_release(nbtsock, tctx, &release);
184         torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name query", address));
185         
186         CHECK_NAME(tctx, release.out.name, *name);
187         CHECK_VALUE(tctx, release.out.rcode, 0);
188
189         torture_comment(tctx, "release again\n");
190         status = nbt_name_release(nbtsock, tctx, &release);
191         torture_assert_ntstatus_ok(tctx, status, 
192                                 talloc_asprintf(tctx, "Bad response from %s for name query",
193                        address));
194         
195         CHECK_NAME(tctx, release.out.name, *name);
196         CHECK_VALUE(tctx, release.out.rcode, 0);
197
198
199         torture_comment(tctx, "query the name to make sure its gone\n");
200         query.in.name = *name;
201         status = nbt_name_query(nbtsock, tctx, &query);
202         if (name->type != NBT_NAME_LOGON &&
203             (nb_flags & NBT_NM_GROUP)) {
204                 torture_assert_ntstatus_ok(tctx, status, 
205                                 "ERROR: Name query failed after group release");
206         } else {
207                 torture_assert_ntstatus_equal(tctx, status, 
208                                                                           NT_STATUS_OBJECT_NAME_NOT_FOUND,
209                                 "Incorrect response to name query");
210         }
211         
212         return true;
213 }
214
215
216
217 /*
218   test operations against a WINS server
219 */
220 static bool nbt_test_wins(struct torture_context *tctx)
221 {
222         struct nbt_name name;
223         uint32_t r = (uint32_t)(random() % (100000));
224         const char *address;
225         bool ret = true;
226
227         if (!torture_nbt_get_name(tctx, &name, &address))
228                 return false;
229
230         name.name = talloc_asprintf(tctx, "_TORTURE-%5u", r);
231
232         name.type = NBT_NAME_CLIENT;
233         name.scope = NULL;
234         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
235
236         name.type = NBT_NAME_MASTER;
237         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
238
239         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H | NBT_NM_GROUP);
240
241         name.type = NBT_NAME_SERVER;
242         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
243
244         name.type = NBT_NAME_LOGON;
245         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H | NBT_NM_GROUP);
246
247         name.type = NBT_NAME_BROWSER;
248         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H | NBT_NM_GROUP);
249
250         name.type = NBT_NAME_PDC;
251         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
252
253         name.type = 0xBF;
254         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
255
256         name.type = 0xBE;
257         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
258
259         name.scope = "example";
260         name.type = 0x72;
261         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
262
263         name.scope = "example";
264         name.type = 0x71;
265         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H | NBT_NM_GROUP);
266
267         name.scope = "foo.example.com";
268         name.type = 0x72;
269         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
270
271         name.name = talloc_asprintf(tctx, "_T\01-%5u.foo", r);
272         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
273
274         name.name = "";
275         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
276
277         name.name = talloc_asprintf(tctx, ".");
278         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
279
280         name.name = talloc_asprintf(tctx, "%5u-\377\200\300FOO", r);
281         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
282
283         return ret;
284 }
285
286 /*
287   test WINS operations
288 */
289 struct torture_suite *torture_nbt_wins(TALLOC_CTX *mem_ctx)
290 {
291         struct torture_suite *suite = torture_suite_create(mem_ctx, "WINS");
292
293         torture_suite_add_simple_test(suite, "wins", nbt_test_wins);
294
295         return suite;
296 }