Home | History | Annotate | Line # | Download | only in test
      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