1 1.1 christos /* test-packet.c 2 1.1 christos * 3 1.1 christos * Copyright (c) 2023 Apple Inc. All rights reserved. 4 1.1 christos * 5 1.1 christos * Licensed under the Apache License, Version 2.0 (the "License"); 6 1.1 christos * you may not use this file except in compliance with the License. 7 1.1 christos * You may obtain a copy of the License at 8 1.1 christos * 9 1.1 christos * https://www.apache.org/licenses/LICENSE-2.0 10 1.1 christos * 11 1.1 christos * Unless required by applicable law or agreed to in writing, software 12 1.1 christos * distributed under the License is distributed on an "AS IS" BASIS, 13 1.1 christos * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 1.1 christos * See the License for the specific language governing permissions and 15 1.1 christos * limitations under the License. 16 1.1 christos * 17 1.1 christos * This file contains tools for generating SRP update packets that can be fed directly into the 18 1.1 christos * parser (srp-parse.c) rather than involving connections, using the pathway that's used by SRP 19 1.1 christos * replication. This is useful for unit tests generally, and particularly for testing the multi-packet 20 1.1 christos * functionality used by SRP replication. 21 1.1 christos */ 22 1.1 christos 23 1.1 christos #include <dns_sd.h> 24 1.1 christos #include "srp.h" 25 1.1 christos #include "srp-test-runner.h" 26 1.1 christos #include "srp-api.h" 27 1.1 christos #include "dns-msg.h" 28 1.1 christos #include "ioloop.h" 29 1.1 christos #include "srp-proxy.h" 30 1.1 christos #include "srp-dnssd.h" 31 1.1 christos #include "srp-mdns-proxy.h" 32 1.1 christos #include "test-api.h" 33 1.1 christos #include "srp-replication.h" 34 1.1 christos #include "test-packet.h" 35 1.1 christos #include "test-dnssd.h" 36 1.1 christos #include "dnssd-proxy.h" 37 1.1 christos #include "srp-tls.h" 38 1.1 christos #include <arpa/inet.h> 39 1.1 christos 40 1.1 christos #define MAX_PACKETS 10 41 1.1 christos typedef struct test_packet_state test_packet_state_t; 42 1.1 christos struct test_packet_state { 43 1.1 christos test_state_t *test_state; 44 1.1 christos client_state_t *current_client; 45 1.1 christos srpl_connection_t *srpl_connection; 46 1.1 christos message_t *packets[MAX_PACKETS]; 47 1.1 christos int num_packets; 48 1.1 christos }; 49 1.1 christos 50 1.1 christos test_packet_state_t * 51 1.1 christos test_packet_state_create(test_state_t *state, void (*advertise_finished_callback)(test_state_t *state)) 52 1.1 christos { 53 1.1 christos test_packet_state_t *packet_state = calloc(1, sizeof(*packet_state)); 54 1.1 christos TEST_FAIL_CHECK(state, state != NULL, "unable to allocate test packet state"); 55 1.1 christos packet_state->test_state = state; 56 1.1 christos srp_host_init(state); 57 1.1 christos packet_state->current_client = srp_client_get_current(); 58 1.1 christos 59 1.1 christos // We need to add at least one address record. 60 1.1 christos srp_test_set_local_example_address(state); 61 1.1 christos 62 1.1 christos // We need an SRPL connection to capture the advertise_finished event. It needs to look real enough that 63 1.1 christos // the event gets delivered, so we have to create a domain and an instance and tie them together, and then 64 1.1 christos // hang the connection off of the instance. 65 1.1 christos srpl_instance_t *instance = calloc(1, sizeof (*instance)); 66 1.1 christos TEST_FAIL_CHECK(state, instance != NULL, "no memory for instance"); 67 1.1 christos instance->instance_name = strdup("single-srpl-instance"); 68 1.1 christos TEST_FAIL_CHECK(state, instance->instance_name != NULL, "no memory for instance name"); 69 1.1 christos instance->domain = srpl_domain_create_or_copy(state->primary, "openthread.thread.home.arpa"); 70 1.1 christos instance->domain->srpl_opstate = SRPL_OPSTATE_ROUTINE; 71 1.1 christos TEST_FAIL_CHECK(state, instance->domain != NULL, "no domain created"); 72 1.1 christos instance->domain->instances = instance; 73 1.1 christos RETAIN_HERE(instance->domain, srpl_domain); 74 1.1 christos RETAIN_HERE(instance->domain->instances, srpl_instance); 75 1.1 christos 76 1.1 christos srpl_connection_t *srpl_connection = srpl_connection_create(instance, false); 77 1.1 christos TEST_FAIL_CHECK(state, srpl_connection != NULL, "srpl_connection_create failed"); 78 1.1 christos srpl_connection->state = srpl_state_test_event_intercept; 79 1.1 christos instance->connection = srpl_connection; 80 1.1 christos RETAIN_HERE(instance->connection, srpl_connection); 81 1.1 christos 82 1.1 christos srpl_connection->test_state = state; 83 1.1 christos srpl_connection->advertise_finished_callback = advertise_finished_callback; 84 1.1 christos packet_state->srpl_connection = srpl_connection; 85 1.1 christos RETAIN_HERE(packet_state->srpl_connection, srpl_connection); 86 1.1 christos 87 1.1 christos return packet_state; 88 1.1 christos } 89 1.1 christos 90 1.1 christos void 91 1.1 christos test_packet_generate(test_state_t *state, uint32_t host_lease, uint32_t key_lease, bool removing, bool prepend) 92 1.1 christos { 93 1.1 christos test_packet_state_t *packet_state = state->test_packet_state; 94 1.1 christos message_t *message = ioloop_message_create(sizeof(dns_wire_t)); 95 1.1 christos size_t length = message->length; 96 1.1 christos message->received_time = srp_time(); 97 1.1 christos message->lease = host_lease; 98 1.1 christos message->key_lease = key_lease; 99 1.1 christos dns_wire_t *ret = srp_client_generate_update(packet_state->current_client, host_lease, key_lease, 100 1.1 christos &length, &message->wire, 9999, removing); 101 1.1 christos TEST_FAIL_CHECK(state, length <= message->length, "srp_client_generate overflowed message length"); 102 1.1 christos TEST_FAIL_CHECK(state, ret != NULL, "srp_client_generate returned NULL"); 103 1.1 christos TEST_FAIL_CHECK(state, packet_state->num_packets < MAX_PACKETS, "more than maximum number of packets"); 104 1.1 christos if (prepend) { 105 1.1 christos for (int i = packet_state->num_packets; i > 0; i--) { 106 1.1 christos packet_state->packets[i] = packet_state->packets[i - 1]; 107 1.1 christos } 108 1.1 christos packet_state->packets[0] = message; 109 1.1 christos } else { 110 1.1 christos packet_state->packets[packet_state->num_packets] = message; 111 1.1 christos } 112 1.1 christos packet_state->num_packets++; 113 1.1 christos } 114 1.1 christos 115 1.1 christos void 116 1.1 christos test_packet_reset_key(test_state_t *state) 117 1.1 christos { 118 1.1 christos test_packet_state_t *packet_state = state->test_packet_state; 119 1.1 christos srp_host_key_reset_for_client(packet_state->current_client); 120 1.1 christos } 121 1.1 christos 122 1.1 christos void 123 1.1 christos test_packet_start(test_state_t *state, bool expect_fail) 124 1.1 christos { 125 1.1 christos test_packet_state_t *packet_state = state->test_packet_state; 126 1.1 christos bool success = srp_parse_host_messages_evaluate(state->primary, packet_state->srpl_connection, 127 1.1 christos packet_state->packets, packet_state->num_packets); 128 1.1 christos TEST_FAIL_CHECK_STATUS(state, expect_fail != success, "srp_parse_host_messages_evaluate returned " PUB_S_SRP, 129 1.1 christos success ? "true" : "false"); 130 1.1 christos if (expect_fail) { 131 1.1 christos TEST_PASSED(state); 132 1.1 christos } 133 1.1 christos } 134 1.1 christos 135 1.1 christos bool 136 1.1 christos test_packet_srpl_intercept(srpl_connection_t *srpl_connection, srpl_event_t *event) 137 1.1 christos { 138 1.1 christos if (event->event_type == srpl_event_advertise_finished) { 139 1.1 christos test_state_t *state = srpl_connection->test_state; 140 1.1 christos srpl_connection->advertise_finished_callback(state); 141 1.1 christos } 142 1.1 christos return false; 143 1.1 christos } 144 1.1 christos 145 1.1 christos void 146 1.1 christos test_packet_message_delete(test_state_t *test_state, int index) 147 1.1 christos { 148 1.1 christos test_packet_state_t *state = test_state->test_packet_state; 149 1.1 christos if (index < state->num_packets) { 150 1.1 christos ioloop_message_release(state->packets[index]); 151 1.1 christos int j = index; 152 1.1 christos for (int i = index + 1; i < state->num_packets; i++) { 153 1.1 christos state->packets[j++] = state->packets[i]; 154 1.1 christos } 155 1.1 christos state->num_packets--; 156 1.1 christos } 157 1.1 christos } 158 1.1 christos 159 1.1 christos // Local Variables: 160 1.1 christos // mode: C 161 1.1 christos // tab-width: 4 162 1.1 christos // c-file-style: "bsd" 163 1.1 christos // c-basic-offset: 4 164 1.1 christos // fill-column: 108 165 1.1 christos // indent-tabs-mode: nil 166 1.1 christos // End: 167