📄 winsreplication.c
字号:
/* Unix SMB/CIFS implementation. WINS replication testing Copyright (C) Andrew Tridgell 2005 Copyright (C) Stefan Metzmacher 2005 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 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 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, see <http://www.gnu.org/licenses/>.*/#include "includes.h"#include "libcli/wrepl/winsrepl.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_STATUS(tctx, status, correct) \ torture_assert_ntstatus_equal(tctx, status, correct, \ "Incorrect status")#define CHECK_VALUE(tctx, v, correct) \ torture_assert(tctx, (v) == (correct), \ talloc_asprintf(tctx, "Incorrect value %s=%d - should be %d\n", \ #v, v, correct))#define CHECK_VALUE_UINT64(tctx, v, correct) \ torture_assert(tctx, (v) == (correct), \ talloc_asprintf(tctx, "Incorrect value %s=%llu - should be %llu\n", \ #v, (long long)v, (long long)correct))#define CHECK_VALUE_STRING(tctx, v, correct) \ torture_assert_str_equal(tctx, v, correct, "Invalid value")#define _NBT_NAME(n,t,s) {\ .name = n,\ .type = t,\ .scope = s\}static const char *wrepl_name_type_string(enum wrepl_name_type type){ switch (type) { case WREPL_TYPE_UNIQUE: return "UNIQUE"; case WREPL_TYPE_GROUP: return "GROUP"; case WREPL_TYPE_SGROUP: return "SGROUP"; case WREPL_TYPE_MHOMED: return "MHOMED"; } return "UNKNOWN_TYPE";}static const char *wrepl_name_state_string(enum wrepl_name_state state){ switch (state) { case WREPL_STATE_ACTIVE: return "ACTIVE"; case WREPL_STATE_RELEASED: return "RELEASED"; case WREPL_STATE_TOMBSTONE: return "TOMBSTONE"; case WREPL_STATE_RESERVED: return "RESERVED"; } return "UNKNOWN_STATE";}/* test how assoc_ctx's are only usable on the connection they are created on.*/static bool test_assoc_ctx1(struct torture_context *tctx){ bool ret = true; struct wrepl_request *req; struct wrepl_socket *wrepl_socket1; struct wrepl_associate associate1; struct wrepl_socket *wrepl_socket2; struct wrepl_associate associate2; struct wrepl_pull_table pull_table; struct wrepl_packet packet; struct wrepl_send_ctrl ctrl; struct wrepl_packet *rep_packet; struct wrepl_associate_stop assoc_stop; NTSTATUS status; struct nbt_name name; const char *address; if (!torture_nbt_get_name(tctx, &name, &address)) return false; torture_comment(tctx, "Test if assoc_ctx is only valid on the conection it was created on\n"); wrepl_socket1 = wrepl_socket_init(tctx, tctx->ev, lp_iconv_convenience(tctx->lp_ctx)); wrepl_socket2 = wrepl_socket_init(tctx, tctx->ev, lp_iconv_convenience(tctx->lp_ctx)); torture_comment(tctx, "Setup 2 wrepl connections\n"); status = wrepl_connect(wrepl_socket1, lp_resolve_context(tctx->lp_ctx), wrepl_best_ip(tctx->lp_ctx, address), address); CHECK_STATUS(tctx, status, NT_STATUS_OK); status = wrepl_connect(wrepl_socket2, lp_resolve_context(tctx->lp_ctx), wrepl_best_ip(tctx->lp_ctx, address), address); CHECK_STATUS(tctx, status, NT_STATUS_OK); torture_comment(tctx, "Send a start association request (conn1)\n"); status = wrepl_associate(wrepl_socket1, &associate1); CHECK_STATUS(tctx, status, NT_STATUS_OK); torture_comment(tctx, "association context (conn1): 0x%x\n", associate1.out.assoc_ctx); torture_comment(tctx, "Send a start association request (conn2)\n"); status = wrepl_associate(wrepl_socket2, &associate2); CHECK_STATUS(tctx, status, NT_STATUS_OK); torture_comment(tctx, "association context (conn2): 0x%x\n", associate2.out.assoc_ctx); torture_comment(tctx, "Send a replication table query, with assoc 1 (conn2), the anwser should be on conn1\n"); ZERO_STRUCT(packet); packet.opcode = WREPL_OPCODE_BITS; packet.assoc_ctx = associate1.out.assoc_ctx; packet.mess_type = WREPL_REPLICATION; packet.message.replication.command = WREPL_REPL_TABLE_QUERY; ZERO_STRUCT(ctrl); ctrl.send_only = true; req = wrepl_request_send(wrepl_socket2, &packet, &ctrl); status = wrepl_request_recv(req, tctx, &rep_packet); CHECK_STATUS(tctx, status, NT_STATUS_OK); torture_comment(tctx, "Send a association request (conn2), to make sure the last request was ignored\n"); status = wrepl_associate(wrepl_socket2, &associate2); CHECK_STATUS(tctx, status, NT_STATUS_OK); torture_comment(tctx, "Send a replication table query, with invalid assoc (conn1), receive answer from conn2\n"); pull_table.in.assoc_ctx = 0; req = wrepl_pull_table_send(wrepl_socket1, &pull_table); status = wrepl_request_recv(req, tctx, &rep_packet); CHECK_STATUS(tctx, status, NT_STATUS_OK); torture_comment(tctx, "Send a association request (conn1), to make sure the last request was handled correct\n"); status = wrepl_associate(wrepl_socket1, &associate2); CHECK_STATUS(tctx, status, NT_STATUS_OK); assoc_stop.in.assoc_ctx = associate1.out.assoc_ctx; assoc_stop.in.reason = 4; torture_comment(tctx, "Send a association stop request (conn1), reson: %u\n", assoc_stop.in.reason); status = wrepl_associate_stop(wrepl_socket1, &assoc_stop); CHECK_STATUS(tctx, status, NT_STATUS_END_OF_FILE); assoc_stop.in.assoc_ctx = associate2.out.assoc_ctx; assoc_stop.in.reason = 0; torture_comment(tctx, "Send a association stop request (conn2), reson: %u\n", assoc_stop.in.reason); status = wrepl_associate_stop(wrepl_socket2, &assoc_stop); CHECK_STATUS(tctx, status, NT_STATUS_OK); torture_comment(tctx, "Close 2 wrepl connections\n"); talloc_free(wrepl_socket1); talloc_free(wrepl_socket2); return ret;}/* test if we always get back the same assoc_ctx*/static bool test_assoc_ctx2(struct torture_context *tctx){ struct wrepl_socket *wrepl_socket; struct wrepl_associate associate; uint32_t assoc_ctx1; struct nbt_name name; NTSTATUS status; const char *address; if (!torture_nbt_get_name(tctx, &name, &address)) return false; torture_comment(tctx, "Test if we always get back the same assoc_ctx\n"); wrepl_socket = wrepl_socket_init(tctx, tctx->ev, lp_iconv_convenience(tctx->lp_ctx)); torture_comment(tctx, "Setup wrepl connections\n"); status = wrepl_connect(wrepl_socket, lp_resolve_context(tctx->lp_ctx), wrepl_best_ip(tctx->lp_ctx, address), address); CHECK_STATUS(tctx, status, NT_STATUS_OK); torture_comment(tctx, "Send 1st start association request\n"); status = wrepl_associate(wrepl_socket, &associate); CHECK_STATUS(tctx, status, NT_STATUS_OK); assoc_ctx1 = associate.out.assoc_ctx; torture_comment(tctx, "1st association context: 0x%x\n", associate.out.assoc_ctx); torture_comment(tctx, "Send 2nd start association request\n"); status = wrepl_associate(wrepl_socket, &associate); torture_assert_ntstatus_ok(tctx, status, "2nd start association failed"); torture_assert(tctx, associate.out.assoc_ctx == assoc_ctx1, "Different context returned"); torture_comment(tctx, "2nd association context: 0x%x\n", associate.out.assoc_ctx); torture_comment(tctx, "Send 3rd start association request\n"); status = wrepl_associate(wrepl_socket, &associate); torture_assert(tctx, associate.out.assoc_ctx == assoc_ctx1, "Different context returned"); CHECK_STATUS(tctx, status, NT_STATUS_OK); torture_comment(tctx, "3rd association context: 0x%x\n", associate.out.assoc_ctx); torture_comment(tctx, "Close wrepl connections\n"); talloc_free(wrepl_socket); return true;}/* display a replication entry*/static void display_entry(struct torture_context *tctx, struct wrepl_name *name){ int i; torture_comment(tctx, "%s\n", nbt_name_string(tctx, &name->name)); torture_comment(tctx, "\tTYPE:%u STATE:%u NODE:%u STATIC:%u VERSION_ID: %llu\n", name->type, name->state, name->node, name->is_static, (long long)name->version_id); torture_comment(tctx, "\tRAW_FLAGS: 0x%08X OWNER: %-15s\n", name->raw_flags, name->owner); for (i=0;i<name->num_addresses;i++) { torture_comment(tctx, "\tADDR: %-15s OWNER: %-15s\n", name->addresses[i].address, name->addresses[i].owner); }}/* test a full replication dump from a WINS server*/static bool test_wins_replication(struct torture_context *tctx){ struct wrepl_socket *wrepl_socket; NTSTATUS status; int i, j; struct wrepl_associate associate; struct wrepl_pull_table pull_table; struct wrepl_pull_names pull_names; struct nbt_name name; const char *address; if (!torture_nbt_get_name(tctx, &name, &address)) return false; torture_comment(tctx, "Test one pull replication cycle\n"); wrepl_socket = wrepl_socket_init(tctx, tctx->ev, lp_iconv_convenience(tctx->lp_ctx)); torture_comment(tctx, "Setup wrepl connections\n"); status = wrepl_connect(wrepl_socket, lp_resolve_context(tctx->lp_ctx), wrepl_best_ip(tctx->lp_ctx, address), address); CHECK_STATUS(tctx, status, NT_STATUS_OK); torture_comment(tctx, "Send a start association request\n"); status = wrepl_associate(wrepl_socket, &associate); CHECK_STATUS(tctx, status, NT_STATUS_OK); torture_comment(tctx, "association context: 0x%x\n", associate.out.assoc_ctx); torture_comment(tctx, "Send a replication table query\n"); pull_table.in.assoc_ctx = associate.out.assoc_ctx; status = wrepl_pull_table(wrepl_socket, tctx, &pull_table); if (NT_STATUS_EQUAL(NT_STATUS_NETWORK_ACCESS_DENIED,status)) { struct wrepl_packet packet; struct wrepl_request *req; ZERO_STRUCT(packet); packet.opcode = WREPL_OPCODE_BITS; packet.assoc_ctx = associate.out.assoc_ctx; packet.mess_type = WREPL_STOP_ASSOCIATION; packet.message.stop.reason = 0; req = wrepl_request_send(wrepl_socket, &packet, NULL); talloc_free(req); torture_fail(tctx, "We are not a valid pull partner for the server"); } CHECK_STATUS(tctx, status, NT_STATUS_OK); torture_comment(tctx, "Found %d replication partners\n", pull_table.out.num_partners); for (i=0;i<pull_table.out.num_partners;i++) { struct wrepl_wins_owner *partner = &pull_table.out.partners[i]; torture_comment(tctx, "%s max_version=%6llu min_version=%6llu type=%d\n", partner->address, (long long)partner->max_version, (long long)partner->min_version, partner->type); pull_names.in.assoc_ctx = associate.out.assoc_ctx; pull_names.in.partner = *partner; status = wrepl_pull_names(wrepl_socket, tctx, &pull_names); CHECK_STATUS(tctx, status, NT_STATUS_OK); torture_comment(tctx, "Received %d names\n", pull_names.out.num_names); for (j=0;j<pull_names.out.num_names;j++) { display_entry(tctx, &pull_names.out.names[j]); } } torture_comment(tctx, "Close wrepl connections\n"); talloc_free(wrepl_socket); return true;}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"#define TEST_OWNER_X_ADDRESS "127.88.88.1"#define TEST_ADDRESS_X_PREFIX "127.0.88" struct wrepl_wins_owner a, b, c, x; struct socket_address *myaddr; struct socket_address *myaddr2; struct nbt_name_socket *nbtsock; struct nbt_name_socket *nbtsock2; struct nbt_name_socket *nbtsock_srv; struct nbt_name_socket *nbtsock_srv2; uint32_t addresses_best_num; struct wrepl_ip *addresses_best; uint32_t addresses_best2_num; struct wrepl_ip *addresses_best2; uint32_t addresses_all_num; struct wrepl_ip *addresses_all; uint32_t addresses_mhomed_num; struct wrepl_ip *addresses_mhomed;};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 const struct wrepl_ip addresses_A_3_4[] = { { .owner = TEST_OWNER_A_ADDRESS, .ip = TEST_ADDRESS_A_PREFIX".3" }, { .owner = TEST_OWNER_A_ADDRESS, .ip = TEST_ADDRESS_A_PREFIX".4" }};static const struct wrepl_ip addresses_A_3_4_X_3_4[] = { { .owner = TEST_OWNER_A_ADDRESS, .ip = TEST_ADDRESS_A_PREFIX".3" }, { .owner = TEST_OWNER_A_ADDRESS, .ip = TEST_ADDRESS_A_PREFIX".4" }, { .owner = TEST_OWNER_X_ADDRESS, .ip = TEST_ADDRESS_X_PREFIX".3" }, { .owner = TEST_OWNER_X_ADDRESS, .ip = TEST_ADDRESS_X_PREFIX".4" }};static const struct wrepl_ip addresses_A_3_4_B_3_4[] = { { .owner = TEST_OWNER_A_ADDRESS, .ip = TEST_ADDRESS_A_PREFIX".3" }, { .owner = TEST_OWNER_A_ADDRESS, .ip = TEST_ADDRESS_A_PREFIX".4" }, { .owner = TEST_OWNER_B_ADDRESS, .ip = TEST_ADDRESS_B_PREFIX".3" }, { .owner = TEST_OWNER_B_ADDRESS, .ip = TEST_ADDRESS_B_PREFIX".4" }};static const struct wrepl_ip addresses_A_3_4_OWNER_B[] = { { .owner = TEST_OWNER_B_ADDRESS, .ip = TEST_ADDRESS_A_PREFIX".3" }, { .owner = TEST_OWNER_B_ADDRESS, .ip = TEST_ADDRESS_A_PREFIX".4" }};static const struct wrepl_ip addresses_A_3_4_X_3_4_OWNER_B[] = { { .owner = TEST_OWNER_B_ADDRESS, .ip = TEST_ADDRESS_A_PREFIX".3" }, { .owner = TEST_OWNER_B_ADDRESS, .ip = TEST_ADDRESS_A_PREFIX".4" }, { .owner = TEST_OWNER_B_ADDRESS, .ip = TEST_ADDRESS_X_PREFIX".3" }, { .owner = TEST_OWNER_B_ADDRESS, .ip = TEST_ADDRESS_X_PREFIX".4" }};static const struct wrepl_ip addresses_A_3_4_X_1_2[] = { { .owner = TEST_OWNER_A_ADDRESS, .ip = TEST_ADDRESS_A_PREFIX".3" }, { .owner = TEST_OWNER_A_ADDRESS, .ip = TEST_ADDRESS_A_PREFIX".4" }, { .owner = TEST_OWNER_X_ADDRESS, .ip = TEST_ADDRESS_X_PREFIX".1" }, { .owner = TEST_OWNER_X_ADDRESS, .ip = TEST_ADDRESS_X_PREFIX".2" }};static const struct wrepl_ip addresses_B_1[] = { { .owner = TEST_OWNER_B_ADDRESS, .ip = TEST_ADDRESS_B_PREFIX".1" }};static const struct wrepl_ip addresses_B_2[] = { { .owner = TEST_OWNER_B_ADDRESS, .ip = TEST_ADDRESS_B_PREFIX".2" }};static const struct wrepl_ip addresses_B_3_4[] = { { .owner = TEST_OWNER_B_ADDRESS, .ip = TEST_ADDRESS_B_PREFIX".3" }, { .owner = TEST_OWNER_B_ADDRESS, .ip = TEST_ADDRESS_B_PREFIX".4" }};static const struct wrepl_ip addresses_B_3_4_X_3_4[] = { { .owner = TEST_OWNER_B_ADDRESS, .ip = TEST_ADDRESS_B_PREFIX".3" }, { .owner = TEST_OWNER_B_ADDRESS, .ip = TEST_ADDRESS_B_PREFIX".4" }, { .owner = TEST_OWNER_X_ADDRESS, .ip = TEST_ADDRESS_X_PREFIX".3" }, { .owner = TEST_OWNER_X_ADDRESS, .ip = TEST_ADDRESS_X_PREFIX".4" }};static const struct wrepl_ip addresses_B_3_4_X_1_2[] = {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -