From 2ea8857effb833615b16d10fc7a19a7104c19e13 Mon Sep 17 00:00:00 2001 From: Patrik Flykt Date: Thu, 19 Jun 2014 15:39:30 +0300 Subject: [PATCH] sd-dhcp6-client: Add DHCPv6 Solicit test case Verify the Solicit message created by the DHCPv6 client code. Provide local variants for detect_vm(), detect_container() and detect_virtualization() defined in virt.h. This makes the DHCPv6 library believe it is run in a container and does not try to request interface information from udev for the non-existing interface index used by the test case code. --- Makefile.am | 1 + src/libsystemd-network/test-dhcp6-client.c | 151 +++++++++++++++++++++ 2 files changed, 152 insertions(+) diff --git a/Makefile.am b/Makefile.am index 82f187d5b..f1f5873f2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2665,6 +2665,7 @@ test_icmp6_rs_LDADD = \ test_dhcp6_client_SOURCES = \ src/systemd/sd-dhcp6-client.h \ + src/libsystemd-network/dhcp6-icmp6.h \ src/libsystemd-network/dhcp6-internal.h \ src/libsystemd-network/test-dhcp6-client.c diff --git a/src/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c index b52f40792..43b127582 100644 --- a/src/libsystemd-network/test-dhcp6-client.c +++ b/src/libsystemd-network/test-dhcp6-client.c @@ -21,10 +21,16 @@ #include #include +#include +#include +#include +#include +#include "socket-util.h" #include "macro.h" #include "sd-event.h" #include "event-util.h" +#include "virt.h" #include "sd-dhcp6-client.h" #include "dhcp6-protocol.h" @@ -36,6 +42,11 @@ static struct ether_addr mac_addr = { static bool verbose = false; +static sd_event_source *hangcheck; +static int test_dhcp_fd[2]; +static int test_index = 42; +static sd_event *e_solicit; + static int test_client_basic(sd_event *e) { sd_dhcp6_client *client; @@ -128,6 +139,145 @@ static int test_option(sd_event *e) { return 0; } +static int test_hangcheck(sd_event_source *s, uint64_t usec, void *userdata) { + assert_not_reached("Test case should have completed in 2 seconds"); + + return 0; +} + +int detect_vm(const char **id) { + return 1; +} + +int detect_container(const char **id) { + return 1; +} + +int detect_virtualization(const char **id) { + return 1; +} + +int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) { + assert_se(index == test_index); + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_dhcp_fd) < 0) + return -errno; + + return test_dhcp_fd[0]; +} + +static int verify_solicit(DHCP6Message *solicit, uint8_t *option, size_t len) { + uint8_t *optval; + uint16_t optcode; + size_t optlen; + bool found_clientid = false, found_iana = false; + int r; + + assert_se(solicit->type == DHCP6_SOLICIT); + + while ((r = dhcp6_option_parse(&option, &len, + &optcode, &optlen, &optval)) >= 0) { + switch(optcode) { + case DHCP6_OPTION_CLIENTID: + assert_se(!found_clientid); + found_clientid = true; + + assert_se(optlen == 14); + + break; + + case DHCP6_OPTION_IA_NA: + assert_se(!found_iana); + found_iana = true; + + assert_se(optlen == 12); + + break; + } + } + + assert_se(r == -ENOMSG); + assert_se(found_clientid && found_iana); + + sd_event_exit(e_solicit, 0); + + return 0; +} + +int dhcp6_network_send_udp_socket(int s, struct in6_addr *server_address, + const void *packet, size_t len) { + struct in6_addr mcast = + IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT; + DHCP6Message *message; + uint8_t *option; + + assert_se(s == test_dhcp_fd[0]); + assert_se(server_address); + assert_se(packet); + assert_se(len > sizeof(DHCP6Message) + 4); + + assert_se(IN6_ARE_ADDR_EQUAL(server_address, &mcast)); + + message = (DHCP6Message *)packet; + option = (uint8_t *)(message + 1); + len -= sizeof(DHCP6Message); + + assert_se(message->transaction_id & 0x00ffffff); + + verify_solicit(message, option, len); + + return len; +} + +static void test_client_solicit_cb(sd_dhcp6_client *client, int event, + void *userdata) { + sd_event *e = userdata; + + assert_se(e); + + if (verbose) + printf(" got DHCPv6 event %d\n", event); + + sd_event_exit(e, 0); +} + +static int test_client_solicit(sd_event *e) { + sd_dhcp6_client *client; + usec_t time_now = now(CLOCK_MONOTONIC); + + if (verbose) + printf("* %s\n", __FUNCTION__); + + assert_se(sd_dhcp6_client_new(&client) >= 0); + assert_se(client); + + assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0); + + assert_se(sd_dhcp6_client_set_index(client, test_index) == 0); + assert_se(sd_dhcp6_client_set_mac(client, &mac_addr) >= 0); + + assert_se(sd_dhcp6_client_set_callback(client, + test_client_solicit_cb, e) >= 0); + + assert_se(sd_event_add_time(e, &hangcheck, CLOCK_MONOTONIC, + time_now + 2 * USEC_PER_SEC, 0, + test_hangcheck, NULL) >= 0); + + e_solicit = e; + + assert_se(sd_dhcp6_client_start(client) >= 0); + + sd_event_loop(e); + + hangcheck = sd_event_source_unref(hangcheck); + + assert_se(!sd_dhcp6_client_unref(client)); + + test_dhcp_fd[1] = safe_close(test_dhcp_fd[1]); + + return 0; +} + int main(int argc, char *argv[]) { _cleanup_event_unref_ sd_event *e; @@ -139,6 +289,7 @@ int main(int argc, char *argv[]) { test_client_basic(e); test_option(e); + test_client_solicit(e); assert_se(!sd_event_unref(e)); -- 2.30.2