2 Unix SMB/CIFS implementation.
4 WINS replication testing
6 Copyright (C) Andrew Tridgell 2005
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 2 of the License, or
11 (at your option) any later version.
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.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "libcli/nbt/libnbt.h"
25 #include "libcli/wrepl/winsrepl.h"
27 #define CHECK_STATUS(status, correct) do { \
28 if (!NT_STATUS_EQUAL(status, correct)) { \
29 printf("(%s) Incorrect status %s - should be %s\n", \
30 __location__, nt_errstr(status), nt_errstr(correct)); \
35 #define CHECK_VALUE(v, correct) do { \
36 if ((v) != (correct)) { \
37 printf("(%s) Incorrect value %s=%d - should be %d\n", \
38 __location__, #v, v, correct); \
44 test how assoc_ctx's are only usable on the connection
47 static BOOL test_assoc_ctx1(TALLOC_CTX *mem_ctx, const char *address)
50 struct wrepl_request *req;
51 struct wrepl_socket *wrepl_socket1;
52 struct wrepl_associate associate1;
53 struct wrepl_socket *wrepl_socket2;
54 struct wrepl_associate associate2;
55 struct wrepl_pull_table pull_table;
56 struct wrepl_packet *rep_packet;
57 struct wrepl_associate_stop assoc_stop;
60 if (!lp_parm_bool(-1, "torture", "dangerous", False)) {
61 printf("winsrepl: cross connection assoc_ctx usage disabled - enable dangerous tests to use\n");
65 printf("Test if assoc_ctx is only valid on the conection it was created on\n");
67 wrepl_socket1 = wrepl_socket_init(mem_ctx, NULL);
68 wrepl_socket2 = wrepl_socket_init(mem_ctx, NULL);
70 printf("Setup 2 wrepl connections\n");
71 status = wrepl_connect(wrepl_socket1, NULL, address);
72 CHECK_STATUS(status, NT_STATUS_OK);
74 status = wrepl_connect(wrepl_socket2, NULL, address);
75 CHECK_STATUS(status, NT_STATUS_OK);
77 printf("Send a start association request (conn1)\n");
78 status = wrepl_associate(wrepl_socket1, &associate1);
79 CHECK_STATUS(status, NT_STATUS_OK);
81 printf("association context (conn1): 0x%x\n", associate1.out.assoc_ctx);
83 printf("Send a start association request (conn2)\n");
84 status = wrepl_associate(wrepl_socket2, &associate2);
85 CHECK_STATUS(status, NT_STATUS_OK);
87 printf("association context (conn2): 0x%x\n", associate2.out.assoc_ctx);
89 printf("Send a replication table query, with assoc 1 (conn2), the anwser should be on conn1\n");
90 pull_table.in.assoc_ctx = associate1.out.assoc_ctx;
91 req = wrepl_pull_table_send(wrepl_socket2, &pull_table);
92 req->send_only = True;
93 status = wrepl_request_recv(req, mem_ctx, &rep_packet);
94 CHECK_STATUS(status, NT_STATUS_OK);
96 printf("Send a association request (conn2), to make sure the last request was ignored\n");
97 status = wrepl_associate(wrepl_socket2, &associate2);
98 CHECK_STATUS(status, NT_STATUS_OK);
100 printf("Send a replication table query, with invalid assoc (conn1), receive answer from conn2\n");
101 pull_table.in.assoc_ctx = 0;
102 req = wrepl_pull_table_send(wrepl_socket1, &pull_table);
103 status = wrepl_request_recv(req, mem_ctx, &rep_packet);
104 CHECK_STATUS(status, NT_STATUS_OK);
106 printf("Send a association request (conn1), to make sure the last request was handled correct\n");
107 status = wrepl_associate(wrepl_socket1, &associate2);
108 CHECK_STATUS(status, NT_STATUS_OK);
110 assoc_stop.in.assoc_ctx = associate1.out.assoc_ctx;
111 assoc_stop.in.reason = 4;
112 printf("Send a association stop request (conn1), reson: %u\n", assoc_stop.in.reason);
113 status = wrepl_associate_stop(wrepl_socket1, &assoc_stop);
114 CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
116 assoc_stop.in.assoc_ctx = associate2.out.assoc_ctx;
117 assoc_stop.in.reason = 0;
118 printf("Send a association stop request (conn2), reson: %u\n", assoc_stop.in.reason);
119 status = wrepl_associate_stop(wrepl_socket2, &assoc_stop);
120 CHECK_STATUS(status, NT_STATUS_OK);
123 printf("Close 2 wrepl connections\n");
124 talloc_free(wrepl_socket1);
125 talloc_free(wrepl_socket2);
130 test if we always get back the same assoc_ctx
132 static BOOL test_assoc_ctx2(TALLOC_CTX *mem_ctx, const char *address)
135 struct wrepl_socket *wrepl_socket;
136 struct wrepl_associate associate;
140 printf("Test if we always get back the same assoc_ctx\n");
142 wrepl_socket = wrepl_socket_init(mem_ctx, NULL);
144 printf("Setup wrepl connections\n");
145 status = wrepl_connect(wrepl_socket, NULL, address);
146 CHECK_STATUS(status, NT_STATUS_OK);
149 printf("Send 1st start association request\n");
150 status = wrepl_associate(wrepl_socket, &associate);
151 CHECK_STATUS(status, NT_STATUS_OK);
152 assoc_ctx1 = associate.out.assoc_ctx;
153 printf("1st association context: 0x%x\n", associate.out.assoc_ctx);
155 printf("Send 2nd start association request\n");
156 status = wrepl_associate(wrepl_socket, &associate);
157 CHECK_VALUE(associate.out.assoc_ctx, assoc_ctx1);
158 CHECK_STATUS(status, NT_STATUS_OK);
159 printf("2nd association context: 0x%x\n", associate.out.assoc_ctx);
161 printf("Send 3rd start association request\n");
162 status = wrepl_associate(wrepl_socket, &associate);
163 CHECK_VALUE(associate.out.assoc_ctx, assoc_ctx1);
164 CHECK_STATUS(status, NT_STATUS_OK);
165 printf("3rd association context: 0x%x\n", associate.out.assoc_ctx);
168 printf("Close wrepl connections\n");
169 talloc_free(wrepl_socket);
175 display a replication entry
177 static void display_entry(TALLOC_CTX *mem_ctx, struct wrepl_name *name)
181 printf("%s\n", nbt_name_string(mem_ctx, &name->name));
182 printf("\tTYPE:%u STATE:%u NODE:%u STATIC:%u VERSION_ID: %llu\n",
183 name->type, name->state, name->node, name->is_static, name->version_id);
184 printf("\tRAW_FLAGS: 0x%08X OWNER: %-15s\n",
185 name->raw_flags, name->owner);
186 for (i=0;i<name->num_addresses;i++) {
187 printf("\tADDR: %-15s OWNER: %-15s\n",
188 name->addresses[i].address, name->addresses[i].owner);
193 test a full replication dump from a WINS server
195 static BOOL test_wins_replication(TALLOC_CTX *mem_ctx, const char *address)
198 struct wrepl_socket *wrepl_socket;
201 struct wrepl_associate associate;
202 struct wrepl_pull_table pull_table;
203 struct wrepl_pull_names pull_names;
205 printf("Test one pull replication cycle\n");
207 wrepl_socket = wrepl_socket_init(mem_ctx, NULL);
209 printf("Setup wrepl connections\n");
210 status = wrepl_connect(wrepl_socket, NULL, address);
211 CHECK_STATUS(status, NT_STATUS_OK);
213 printf("Send a start association request\n");
215 status = wrepl_associate(wrepl_socket, &associate);
216 CHECK_STATUS(status, NT_STATUS_OK);
218 printf("association context: 0x%x\n", associate.out.assoc_ctx);
220 printf("Send a replication table query\n");
221 pull_table.in.assoc_ctx = associate.out.assoc_ctx;
223 status = wrepl_pull_table(wrepl_socket, mem_ctx, &pull_table);
224 if (NT_STATUS_EQUAL(NT_STATUS_NETWORK_ACCESS_DENIED,status)) {
225 struct wrepl_packet packet;
226 struct wrepl_request *req;
229 packet.opcode = WREPL_OPCODE_BITS;
230 packet.assoc_ctx = associate.out.assoc_ctx;
231 packet.mess_type = WREPL_STOP_ASSOCIATION;
232 packet.message.stop.reason = 0;
234 req = wrepl_request_send(wrepl_socket, &packet);
237 printf("failed - We are not a valid pull partner for the server\n");
241 CHECK_STATUS(status, NT_STATUS_OK);
243 printf("Found %d replication partners\n", pull_table.out.num_partners);
245 for (i=0;i<pull_table.out.num_partners;i++) {
246 struct wrepl_wins_owner *partner = &pull_table.out.partners[i];
247 printf("%s max_version=%6llu min_version=%6llu type=%d\n",
249 partner->max_version,
250 partner->min_version,
253 pull_names.in.assoc_ctx = associate.out.assoc_ctx;
254 pull_names.in.partner = *partner;
256 status = wrepl_pull_names(wrepl_socket, mem_ctx, &pull_names);
257 CHECK_STATUS(status, NT_STATUS_OK);
259 printf("Received %d names\n", pull_names.out.num_names);
261 for (j=0;j<pull_names.out.num_names;j++) {
262 display_entry(mem_ctx, &pull_names.out.names[j]);
267 printf("Close wrepl connections\n");
268 talloc_free(wrepl_socket);
272 struct test_wrepl_conflict_conn {
274 struct wrepl_socket *pull;
277 #define TEST_OWNER_A_ADDRESS "127.65.65.1"
278 #define TEST_ADDRESS_A_PREFIX "127.0.65"
279 #define TEST_OWNER_B_ADDRESS "127.66.66.1"
280 #define TEST_ADDRESS_B_PREFIX "127.0.66"
282 struct wrepl_wins_owner a, b;
285 static const struct wrepl_ip addresses_A_1[] = {
287 .owner = TEST_OWNER_A_ADDRESS,
288 .ip = TEST_ADDRESS_A_PREFIX".1"
291 static const struct wrepl_ip addresses_A_2[] = {
293 .owner = TEST_OWNER_A_ADDRESS,
294 .ip = TEST_ADDRESS_A_PREFIX".2"
298 static struct test_wrepl_conflict_conn *test_create_conflict_ctx(TALLOC_CTX *mem_ctx,
301 struct test_wrepl_conflict_conn *ctx;
302 struct wrepl_associate associate;
303 struct wrepl_pull_table pull_table;
307 ctx = talloc_zero(mem_ctx, struct test_wrepl_conflict_conn);
308 if (!ctx) return NULL;
310 ctx->address = address;
311 ctx->pull = wrepl_socket_init(ctx, NULL);
312 if (!ctx->pull) return NULL;
314 printf("Setup wrepl conflict pull connection\n");
315 status = wrepl_connect(ctx->pull, NULL, ctx->address);
316 if (!NT_STATUS_IS_OK(status)) return NULL;
318 status = wrepl_associate(ctx->pull, &associate);
319 if (!NT_STATUS_IS_OK(status)) return NULL;
321 ctx->pull_assoc = associate.out.assoc_ctx;
323 ctx->a.address = TEST_OWNER_A_ADDRESS;
324 ctx->a.max_version = 0;
325 ctx->a.min_version = 0;
328 ctx->b.address = TEST_OWNER_B_ADDRESS;
329 ctx->b.max_version = 0;
330 ctx->b.min_version = 0;
333 pull_table.in.assoc_ctx = ctx->pull_assoc;
334 status = wrepl_pull_table(ctx->pull, ctx->pull, &pull_table);
335 if (!NT_STATUS_IS_OK(status)) return NULL;
337 for (i=0; i < pull_table.out.num_partners; i++) {
338 if (strcmp(TEST_OWNER_A_ADDRESS,pull_table.out.partners[i].address)==0) {
339 ctx->a.max_version = pull_table.out.partners[i].max_version;
340 ctx->a.min_version = pull_table.out.partners[i].min_version;
342 if (strcmp(TEST_OWNER_B_ADDRESS,pull_table.out.partners[i].address)==0) {
343 ctx->b.max_version = pull_table.out.partners[i].max_version;
344 ctx->b.min_version = pull_table.out.partners[i].min_version;
348 talloc_free(pull_table.out.partners);
353 static BOOL test_wrepl_update_one_A(struct test_wrepl_conflict_conn *ctx,
354 const struct wrepl_wins_name *name)
357 struct wrepl_socket *wrepl_socket;
358 struct wrepl_associate associate;
359 struct wrepl_packet update_packet, repl_send;
360 struct wrepl_table *update;
361 struct wrepl_wins_owner wrepl_wins_owners[1];
362 struct wrepl_packet *repl_recv;
363 struct wrepl_wins_owner *send_request;
364 struct wrepl_send_reply *send_reply;
365 struct wrepl_wins_name wrepl_wins_names[1];
369 wrepl_socket = wrepl_socket_init(ctx, NULL);
371 status = wrepl_connect(wrepl_socket, NULL, ctx->address);
372 CHECK_STATUS(status, NT_STATUS_OK);
374 status = wrepl_associate(wrepl_socket, &associate);
375 CHECK_STATUS(status, NT_STATUS_OK);
376 assoc_ctx = associate.out.assoc_ctx;
378 /* now send a WREPL_REPL_UPDATE message */
379 ZERO_STRUCT(update_packet);
380 update_packet.opcode = WREPL_OPCODE_BITS;
381 update_packet.assoc_ctx = assoc_ctx;
382 update_packet.mess_type = WREPL_REPLICATION;
383 update_packet.message.replication.command = WREPL_REPL_UPDATE;
384 update = &update_packet.message.replication.info.table;
386 update->partner_count = ARRAY_SIZE(wrepl_wins_owners);
387 update->partners = wrepl_wins_owners;
388 update->initiator = "0.0.0.0";
390 wrepl_wins_owners[0] = ctx->a;
392 status = wrepl_request(wrepl_socket, wrepl_socket,
393 &update_packet, &repl_recv);
394 CHECK_STATUS(status, NT_STATUS_OK);
395 CHECK_VALUE(repl_recv->mess_type, WREPL_REPLICATION);
396 CHECK_VALUE(repl_recv->message.replication.command, WREPL_REPL_SEND_REQUEST);
397 send_request = &repl_recv->message.replication.info.owner;
399 ZERO_STRUCT(repl_send);
400 repl_send.opcode = WREPL_OPCODE_BITS;
401 repl_send.assoc_ctx = assoc_ctx;
402 repl_send.mess_type = WREPL_REPLICATION;
403 repl_send.message.replication.command = WREPL_REPL_SEND_REPLY;
404 send_reply = &repl_send.message.replication.info.reply;
406 send_reply->num_names = ARRAY_SIZE(wrepl_wins_names);
407 send_reply->names = wrepl_wins_names;
409 wrepl_wins_names[0] = *name;
411 status = wrepl_request(wrepl_socket, wrepl_socket,
412 &repl_send, &repl_recv);
413 CHECK_STATUS(status, NT_STATUS_OK);
414 CHECK_VALUE(repl_recv->mess_type, WREPL_STOP_ASSOCIATION);
415 CHECK_VALUE(repl_recv->message.stop.reason, 0);
418 talloc_free(wrepl_socket);
422 static BOOL test_wrepl_is_applied_A(struct test_wrepl_conflict_conn *ctx,
423 const struct wrepl_wins_name *name)
427 struct wrepl_pull_names pull_names;
429 ctx->a.min_version = ctx->a.max_version;
431 pull_names.in.assoc_ctx = ctx->pull_assoc;
432 pull_names.in.partner = ctx->a;
434 status = wrepl_pull_names(ctx->pull, ctx->pull, &pull_names);
435 CHECK_STATUS(status, NT_STATUS_OK);
436 CHECK_VALUE(pull_names.out.num_names, 1);
439 talloc_free(pull_names.out.names);
443 static BOOL test_conflict_same_owner(struct test_wrepl_conflict_conn *ctx)
446 struct nbt_name name;
447 struct wrepl_wins_name wins_name1;
448 struct wrepl_wins_name wins_name2;
449 struct wrepl_wins_name *wins_name_tmp;
450 struct wrepl_wins_name *wins_name_last;
451 struct wrepl_wins_name *wins_name_cur;
453 uint8_t types[] = { 0x00, 0x1C };
455 enum wrepl_name_type type;
456 enum wrepl_name_state state;
457 enum wrepl_name_node node;
460 const struct wrepl_ip *ips;
463 .type = WREPL_TYPE_GROUP,
464 .state = WREPL_STATE_ACTIVE,
465 .node = WREPL_NODE_B,
467 .num_ips = ARRAY_SIZE(addresses_A_1),
468 .ips = addresses_A_1,
470 .type = WREPL_TYPE_UNIQUE,
471 .state = WREPL_STATE_ACTIVE,
472 .node = WREPL_NODE_B,
474 .num_ips = ARRAY_SIZE(addresses_A_1),
475 .ips = addresses_A_1,
477 .type = WREPL_TYPE_UNIQUE,
478 .state = WREPL_STATE_ACTIVE,
479 .node = WREPL_NODE_B,
481 .num_ips = ARRAY_SIZE(addresses_A_2),
482 .ips = addresses_A_2,
484 .type = WREPL_TYPE_SGROUP,
485 .state = WREPL_STATE_TOMBSTONE,
486 .node = WREPL_NODE_B,
488 .num_ips = ARRAY_SIZE(addresses_A_2),
489 .ips = addresses_A_2,
491 .type = WREPL_TYPE_MHOMED,
492 .state = WREPL_STATE_TOMBSTONE,
493 .node = WREPL_NODE_B,
495 .num_ips = ARRAY_SIZE(addresses_A_1),
496 .ips = addresses_A_1,
498 /* the last one should always be a tomstone record! */
499 .type = WREPL_TYPE_UNIQUE,
500 .state = WREPL_STATE_TOMBSTONE,
501 .node = WREPL_NODE_B,
503 .num_ips = ARRAY_SIZE(addresses_A_1),
504 .ips = addresses_A_1,
508 if (!ctx) return False;
510 name.name = "_SAME_OWNER_A";
514 wins_name_tmp = NULL;
515 wins_name_last = &wins_name2;
516 wins_name_cur = &wins_name1;
518 for (j=0; ret && j < ARRAY_SIZE(types); j++) {
519 name.type = types[j];
520 printf("Test Replica Conflicts with same owner[%s] for %s\n",
521 nbt_name_string(ctx, &name), ctx->a.address);
523 for(i=0; ret && i < ARRAY_SIZE(records); i++) {
524 wins_name_tmp = wins_name_last;
525 wins_name_last = wins_name_cur;
526 wins_name_cur = wins_name_tmp;
528 wins_name_cur->name = &name;
529 wins_name_cur->flags = WREPL_NAME_FLAGS(records[i].type,
532 records[i].is_static);
533 wins_name_cur->id = ++ctx->a.max_version;
534 if (wins_name_cur->flags & 2) {
535 wins_name_cur->addresses.addresses.num_ips = records[i].num_ips;
536 wins_name_cur->addresses.addresses.ips = discard_const(records[i].ips);
538 wins_name_cur->addresses.ip = records[i].ips[0].ip;
540 wins_name_cur->unknown = "255.255.255.255";
542 ret &= test_wrepl_update_one_A(ctx, wins_name_cur);
543 ret &= test_wrepl_is_applied_A(ctx, wins_name_cur);
550 test WINS replication operations
552 BOOL torture_nbt_winsreplication(void)
555 struct nbt_name name;
556 TALLOC_CTX *mem_ctx = talloc_new(NULL);
559 struct test_wrepl_conflict_conn *ctx;
561 make_nbt_name_server(&name, lp_parm_string(-1, "torture", "host"));
563 /* do an initial name resolution to find its IP */
564 status = resolve_name(&name, mem_ctx, &address, NULL);
565 if (!NT_STATUS_IS_OK(status)) {
566 printf("Failed to resolve %s - %s\n",
567 name.name, nt_errstr(status));
568 talloc_free(mem_ctx);
572 ret &= test_assoc_ctx1(mem_ctx, address);
573 ret &= test_assoc_ctx2(mem_ctx, address);
575 ret &= test_wins_replication(mem_ctx, address);
577 ctx = test_create_conflict_ctx(mem_ctx, address);
579 ret &= test_conflict_same_owner(ctx);
581 talloc_free(mem_ctx);