summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/torture/nbt/winsreplication.c289
1 files changed, 288 insertions, 1 deletions
diff --git a/source4/torture/nbt/winsreplication.c b/source4/torture/nbt/winsreplication.c
index e72ba9c8d6..e822624f7f 100644
--- a/source4/torture/nbt/winsreplication.c
+++ b/source4/torture/nbt/winsreplication.c
@@ -57,6 +57,11 @@ static BOOL test_assoc_ctx1(TALLOC_CTX *mem_ctx, const char *address)
struct wrepl_associate_stop assoc_stop;
NTSTATUS status;
+ if (!lp_parm_bool(-1, "torture", "dangerous", False)) {
+ printf("winsrepl: cross connection assoc_ctx usage disabled - enable dangerous tests to use\n");
+ return True;
+ }
+
printf("Test if assoc_ctx is only valid on the conection it was created on\n");
wrepl_socket1 = wrepl_socket_init(mem_ctx, NULL);
@@ -165,6 +170,283 @@ done:
return ret;
}
+struct test_wrepl_conflict_conn {
+ const char *address;
+ struct wrepl_socket *pull;
+ uint32_t pull_assoc;
+
+#define TEST_OWNER_A_ADDRESS "127.65.65.1"
+#define TEST_ADDRESS_A_PREFIX "127.0.65"
+#define TEST_OWNER_B_ADDRESS "127.66.66.1"
+#define TEST_ADDRESS_B_PREFIX "127.0.66"
+
+ struct wrepl_wins_owner a, b;
+};
+
+static const struct wrepl_ip addresses_A_1[] = {
+ {
+ .owner = TEST_OWNER_A_ADDRESS,
+ .ip = TEST_ADDRESS_A_PREFIX".1"
+ }
+};
+static const struct wrepl_ip addresses_A_2[] = {
+ {
+ .owner = TEST_OWNER_A_ADDRESS,
+ .ip = TEST_ADDRESS_A_PREFIX".2"
+ }
+};
+
+static struct test_wrepl_conflict_conn *test_create_conflict_ctx(TALLOC_CTX *mem_ctx,
+ const char *address)
+{
+ struct test_wrepl_conflict_conn *ctx;
+ struct wrepl_associate associate;
+ struct wrepl_pull_table pull_table;
+ NTSTATUS status;
+ uint32_t i;
+
+ ctx = talloc_zero(mem_ctx, struct test_wrepl_conflict_conn);
+ if (!ctx) return NULL;
+
+ ctx->address = address;
+ ctx->pull = wrepl_socket_init(ctx, NULL);
+ if (!ctx->pull) return NULL;
+
+ printf("Setup wrepl conflict pull connection\n");
+ status = wrepl_connect(ctx->pull, NULL, ctx->address);
+ if (!NT_STATUS_IS_OK(status)) return NULL;
+
+ status = wrepl_associate(ctx->pull, &associate);
+ if (!NT_STATUS_IS_OK(status)) return NULL;
+
+ ctx->pull_assoc = associate.out.assoc_ctx;
+
+ ctx->a.address = TEST_OWNER_A_ADDRESS;
+ ctx->a.max_version = 0;
+ ctx->a.min_version = 0;
+ ctx->a.type = 1;
+
+ ctx->b.address = TEST_OWNER_B_ADDRESS;
+ ctx->b.max_version = 0;
+ ctx->b.min_version = 0;
+ ctx->b.type = 1;
+
+ pull_table.in.assoc_ctx = ctx->pull_assoc;
+ status = wrepl_pull_table(ctx->pull, ctx->pull, &pull_table);
+ if (!NT_STATUS_IS_OK(status)) return NULL;
+
+ for (i=0; i < pull_table.out.num_partners; i++) {
+ if (strcmp(TEST_OWNER_A_ADDRESS,pull_table.out.partners[i].address)==0) {
+ ctx->a.max_version = pull_table.out.partners[i].max_version;
+ ctx->a.min_version = pull_table.out.partners[i].min_version;
+ }
+ if (strcmp(TEST_OWNER_B_ADDRESS,pull_table.out.partners[i].address)==0) {
+ ctx->b.max_version = pull_table.out.partners[i].max_version;
+ ctx->b.min_version = pull_table.out.partners[i].min_version;
+ }
+ }
+
+ talloc_free(pull_table.out.partners);
+
+ return ctx;
+}
+
+static BOOL test_wrepl_update_one_A(struct test_wrepl_conflict_conn *ctx,
+ const struct wrepl_wins_name *name)
+{
+ BOOL ret = True;
+ struct wrepl_socket *wrepl_socket;
+ struct wrepl_associate associate;
+ struct wrepl_packet update_packet, repl_send;
+ struct wrepl_table *update;
+ struct wrepl_wins_owner wrepl_wins_owners[1];
+ struct wrepl_packet *repl_recv;
+ struct wrepl_wins_owner *send_request;
+ struct wrepl_send_reply *send_reply;
+ struct wrepl_wins_name wrepl_wins_names[1];
+ uint32_t assoc_ctx;
+ NTSTATUS status;
+
+ wrepl_socket = wrepl_socket_init(ctx, NULL);
+
+ status = wrepl_connect(wrepl_socket, NULL, ctx->address);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = wrepl_associate(wrepl_socket, &associate);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ assoc_ctx = associate.out.assoc_ctx;
+
+ /* now send a WREPL_REPL_UPDATE message */
+ ZERO_STRUCT(update_packet);
+ update_packet.opcode = WREPL_OPCODE_BITS;
+ update_packet.assoc_ctx = assoc_ctx;
+ update_packet.mess_type = WREPL_REPLICATION;
+ update_packet.message.replication.command = WREPL_REPL_UPDATE;
+ update = &update_packet.message.replication.info.table;
+
+ update->partner_count = ARRAY_SIZE(wrepl_wins_owners);
+ update->partners = wrepl_wins_owners;
+ update->initiator = "0.0.0.0";
+
+ wrepl_wins_owners[0] = ctx->a;
+
+ status = wrepl_request(wrepl_socket, wrepl_socket,
+ &update_packet, &repl_recv);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(repl_recv->mess_type, WREPL_REPLICATION);
+ CHECK_VALUE(repl_recv->message.replication.command, WREPL_REPL_SEND_REQUEST);
+ send_request = &repl_recv->message.replication.info.owner;
+
+ ZERO_STRUCT(repl_send);
+ repl_send.opcode = WREPL_OPCODE_BITS;
+ repl_send.assoc_ctx = assoc_ctx;
+ repl_send.mess_type = WREPL_REPLICATION;
+ repl_send.message.replication.command = WREPL_REPL_SEND_REPLY;
+ send_reply = &repl_send.message.replication.info.reply;
+
+ send_reply->num_names = ARRAY_SIZE(wrepl_wins_names);
+ send_reply->names = wrepl_wins_names;
+
+ wrepl_wins_names[0] = *name;
+
+ status = wrepl_request(wrepl_socket, wrepl_socket,
+ &repl_send, &repl_recv);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(repl_recv->mess_type, WREPL_STOP_ASSOCIATION);
+ CHECK_VALUE(repl_recv->message.stop.reason, 0);
+
+done:
+ talloc_free(wrepl_socket);
+ return ret;
+}
+
+static BOOL test_wrepl_is_applied_A(struct test_wrepl_conflict_conn *ctx,
+ const struct wrepl_wins_name *name)
+{
+ BOOL ret = True;
+ NTSTATUS status;
+ struct wrepl_pull_names pull_names;
+
+ ctx->a.min_version = ctx->a.max_version;
+
+ pull_names.in.assoc_ctx = ctx->pull_assoc;
+ pull_names.in.partner = ctx->a;
+
+ status = wrepl_pull_names(ctx->pull, ctx->pull, &pull_names);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(pull_names.out.num_names, 1);
+
+done:
+ talloc_free(pull_names.out.names);
+ return ret;
+}
+
+static BOOL test_conflict_same_owner(struct test_wrepl_conflict_conn *ctx)
+{
+ BOOL ret = True;
+ struct nbt_name name;
+ struct wrepl_wins_name wins_name1;
+ struct wrepl_wins_name wins_name2;
+ struct wrepl_wins_name *wins_name_tmp;
+ struct wrepl_wins_name *wins_name_last;
+ struct wrepl_wins_name *wins_name_cur;
+ uint32_t i,j;
+ uint8_t types[] = { 0x00, 0x1C };
+ struct {
+ enum wrepl_name_type type;
+ enum wrepl_name_state state;
+ enum wrepl_name_node node;
+ BOOL is_static;
+ uint32_t num_ips;
+ const struct wrepl_ip *ips;
+ } records[] = {
+ {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = False,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ },{
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = False,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ },{
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = False,
+ .num_ips = ARRAY_SIZE(addresses_A_2),
+ .ips = addresses_A_2,
+ },{
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = False,
+ .num_ips = ARRAY_SIZE(addresses_A_2),
+ .ips = addresses_A_2,
+ },{
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = False,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ },{
+ /* the last one should always be a tomstone record! */
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = False,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ }
+ };
+
+ if (!ctx) return False;
+
+ name.name = "_SAME_OWNER_A";
+ name.type = 0;
+ name.scope = NULL;
+
+ wins_name_tmp = NULL;
+ wins_name_last = &wins_name2;
+ wins_name_cur = &wins_name1;
+
+ for (j=0; ret && j < ARRAY_SIZE(types); j++) {
+ name.type = types[j];
+ printf("Test Replica Conflicts with same owner[%s] for %s\n",
+ nbt_name_string(ctx, &name), ctx->a.address);
+
+ for(i=0; ret && i < ARRAY_SIZE(records); i++) {
+ wins_name_tmp = wins_name_last;
+ wins_name_last = wins_name_cur;
+ wins_name_cur = wins_name_tmp;
+
+ wins_name_cur->name = &name;
+ wins_name_cur->flags = WREPL_NAME_FLAGS(records[i].type,
+ records[i].state,
+ records[i].node,
+ records[i].is_static);
+ wins_name_cur->id = ++ctx->a.max_version;
+ if (wins_name_cur->flags & 2) {
+ wins_name_cur->addresses.addresses.num_ips = records[i].num_ips;
+ wins_name_cur->addresses.addresses.ips = discard_const(records[i].ips);
+ } else {
+ wins_name_cur->addresses.ip = records[i].ips[0].ip;
+ }
+ wins_name_cur->unknown = "255.255.255.255";
+
+ ret &= test_wrepl_update_one_A(ctx, wins_name_cur);
+ ret &= test_wrepl_is_applied_A(ctx, wins_name_cur);
+ }
+ }
+ return ret;
+}
+
/*
display a replication entry
*/
@@ -273,7 +555,8 @@ BOOL torture_nbt_winsreplication(void)
TALLOC_CTX *mem_ctx = talloc_new(NULL);
NTSTATUS status;
BOOL ret = True;
-
+ struct test_wrepl_conflict_conn *ctx;
+
make_nbt_name_server(&name, lp_parm_string(-1, "torture", "host"));
/* do an initial name resolution to find its IP */
@@ -290,6 +573,10 @@ BOOL torture_nbt_winsreplication(void)
ret &= test_wins_replication(mem_ctx, address);
+ ctx = test_create_conflict_ctx(mem_ctx, address);
+
+ ret &= test_conflict_same_owner(ctx);
+
talloc_free(mem_ctx);
return ret;