From: Yu Watanabe Date: Thu, 10 Feb 2022 07:14:21 +0000 (+0900) Subject: test-dhcp6-client: cleanups X-Git-Tag: v251-rc1~291^2~1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=1f2801911367a6f7d6cbc576b963461a88fd5d6f;p=thirdparty%2Fsystemd.git test-dhcp6-client: cleanups This does many cleanups. Most prominently, - check the sents packet more strictly, - make the packets used in the test more readable, - unify callbacks. --- diff --git a/src/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c index 60bb7f0ca8c..5aa7ebb977a 100644 --- a/src/libsystemd-network/test-dhcp6-client.c +++ b/src/libsystemd-network/test-dhcp6-client.c @@ -26,19 +26,62 @@ #include "tests.h" #include "time-util.h" -static struct ether_addr mac_addr = { - .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'} +#define DHCP6_CLIENT_EVENT_TEST_ADVERTISED 77 +#define IA_ID_BYTES \ + 0x0e, 0xcf, 0xa3, 0x7d +#define IA_NA_ADDRESS1_BYTES \ + 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x78, 0xee, 0x1c, 0xf3, 0x09, 0x3c, 0x55, 0xad +#define IA_NA_ADDRESS2_BYTES \ + 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x78, 0xee, 0x1c, 0xf3, 0x09, 0x3c, 0x55, 0xae +#define IA_PD_PREFIX1_BYTES \ + 0x2a, 0x02, 0x81, 0x0d, 0x98, 0x80, 0x37, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +#define IA_PD_PREFIX2_BYTES \ + 0x2a, 0x02, 0x81, 0x0d, 0x98, 0x80, 0x37, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +#define DNS1_BYTES \ + 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 +#define DNS2_BYTES \ + 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 +#define SNTP1_BYTES \ + 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03 +#define SNTP2_BYTES \ + 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04 +#define NTP1_BYTES \ + 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05 +#define NTP2_BYTES \ + 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06 +#define CLIENT_ID_BYTES \ + 0x00, 0x02, 0x00, 0x00, 0xab, 0x11, 0x61, 0x77, 0x40, 0xde, 0x13, 0x42, 0xc3, 0xa2 +#define SERVER_ID_BYTES \ + 0x00, 0x01, 0x00, 0x01, 0x19, 0x40, 0x5c, 0x53, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53 + +static const struct in6_addr local_address = + { { { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, } } }; +static const struct in6_addr mcast_address = + IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT; +static const struct in6_addr ia_na_address1 = { { { IA_NA_ADDRESS1_BYTES } } }; +static const struct in6_addr ia_na_address2 = { { { IA_NA_ADDRESS2_BYTES } } }; +static const struct in6_addr ia_pd_prefix1 = { { { IA_PD_PREFIX1_BYTES } } }; +static const struct in6_addr ia_pd_prefix2 = { { { IA_PD_PREFIX2_BYTES } } }; +static const struct in6_addr dns1 = { { { DNS1_BYTES } } }; +static const struct in6_addr dns2 = { { { DNS2_BYTES } } }; +static const struct in6_addr sntp1 = { { { SNTP1_BYTES } } }; +static const struct in6_addr sntp2 = { { { SNTP2_BYTES } } }; +static const struct in6_addr ntp1 = { { { NTP1_BYTES } } }; +static const struct in6_addr ntp2 = { { { NTP2_BYTES } } }; +static const uint8_t client_id[] = { CLIENT_ID_BYTES }; +static const uint8_t server_id[] = { SERVER_ID_BYTES }; +static const struct ether_addr mac = { + .ether_addr_octet = { 'A', 'B', 'C', '1', '2', '3' }, }; - -static sd_event_source *hangcheck; -static int test_dhcp_fd[2]; +static int test_fd[2] = { -1, -1, }; static int test_ifindex = 42; -static int test_client_message_num; -static be32_t test_iaid = 0; -static uint8_t test_duid[14] = { }; +static unsigned test_client_sent_message_count = 0; +static sd_dhcp6_client *client_ref = NULL; + +STATIC_DESTRUCTOR_REGISTER(client_ref, sd_dhcp6_client_unrefp); -static void test_client_basic(sd_event *e) { - sd_dhcp6_client *client; +static void test_client_basic(void) { + _cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL; int v; log_debug("/* %s */", __func__); @@ -46,16 +89,10 @@ static void test_client_basic(sd_event *e) { 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_ifindex(client, 15) == 0); - assert_se(sd_dhcp6_client_set_ifindex(client, -42) == -EINVAL); - assert_se(sd_dhcp6_client_set_ifindex(client, -1) == -EINVAL); assert_se(sd_dhcp6_client_set_ifindex(client, 42) >= 0); - assert_se(sd_dhcp6_client_set_mac(client, (const uint8_t *) &mac_addr, - sizeof (mac_addr), - ARPHRD_ETHER) >= 0); + assert_se(sd_dhcp6_client_set_mac(client, mac.ether_addr_octet, sizeof(mac), ARPHRD_ETHER) >= 0); assert_se(sd_dhcp6_client_set_fqdn(client, "host") == 1); assert_se(sd_dhcp6_client_set_fqdn(client, "host.domain") == 1); @@ -107,51 +144,44 @@ static void test_client_basic(sd_event *e) { assert_se(sd_dhcp6_client_set_callback(client, NULL, NULL) >= 0); assert_se(sd_dhcp6_client_detach_event(client) >= 0); - assert_se(!sd_dhcp6_client_unref(client)); } static void test_parse_domain(void) { + _cleanup_free_ char *domain = NULL; + _cleanup_strv_free_ char **list = NULL; uint8_t *data; - char *domain; - char **list; - int r; log_debug("/* %s */", __func__); data = (uint8_t []) { 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'c', 'o', 'm', 0 }; - r = dhcp6_option_parse_domainname(data, 13, &domain); - assert_se(r == 0); + assert_se(dhcp6_option_parse_domainname(data, 13, &domain) >= 0); assert_se(domain); assert_se(streq(domain, "example.com")); - free(domain); + domain = mfree(domain); data = (uint8_t []) { 4, 't', 'e', 's', 't' }; - r = dhcp6_option_parse_domainname(data, 5, &domain); - assert_se(r == 0); + assert_se(dhcp6_option_parse_domainname(data, 5, &domain) >= 0); assert_se(domain); assert_se(streq(domain, "test")); - free(domain); + domain = mfree(domain); data = (uint8_t []) { 0 }; - r = dhcp6_option_parse_domainname(data, 1, &domain); - assert_se(r < 0); + assert_se(dhcp6_option_parse_domainname(data, 1, &domain) < 0); data = (uint8_t []) { 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'c', 'o', 'm', 0, 6, 'f', 'o', 'o', 'b', 'a', 'r', 0 }; - r = dhcp6_option_parse_domainname_list(data, 21, &list); - assert_se(r == 0); + assert_se(dhcp6_option_parse_domainname_list(data, 21, &list) >= 0); assert_se(list); assert_se(streq(list[0], "example.com")); assert_se(streq(list[1], "foobar")); - strv_free(list); + assert_se(!list[2]); + list = strv_free(list); data = (uint8_t []) { 1, 'a', 0, 20, 'b', 'c' }; - r = dhcp6_option_parse_domainname_list(data, 6, &list); - assert_se(r < 0); + assert_se(dhcp6_option_parse_domainname_list(data, 6, &list) < 0); data = (uint8_t []) { 0 , 0 }; - r = dhcp6_option_parse_domainname_list(data, 2, &list); - assert_se(r < 0); + assert_se(dhcp6_option_parse_domainname_list(data, 2, &list) < 0); } static void test_option(void) { @@ -358,36 +388,57 @@ static void test_option_status(void) { static void test_client_parse_message_issue_22099(void) { static const uint8_t msg[] = { - /* xid */ - 0x07, 0x7c, 0x4c, 0x16, - /* status code (zero length) */ - 0x00, 0x0e, 0x00, 0x00, - /* NTP servers (broken sub option and sub option length) */ - 0x00, 0x38, 0x00, 0x14, 0x01, 0x00, 0x10, 0x00, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xde, 0x15, 0xc8, 0xff, 0xfe, 0xef, 0x1e, 0x4e, - /* client ID */ - 0x00, 0x01, 0x00, 0x0e, 0x00, 0x02, 0x00, 0x00, 0xab, 0x11, 0x5c, 0x6b, 0x90, 0xec, 0xda, 0x95, - 0x15, 0x45, - /* server ID */ - 0x00, 0x02, 0x00, 0x0a, 0x00, 0x03, 0x00, 0x01, 0xdc, 0x15, 0xc8, 0xef, 0x1e, 0x4e, + /* Message type */ + DHCP6_MESSAGE_REPLY, + /* Transaction ID */ + 0x7c, 0x4c, 0x16, + /* Rapid commit */ + 0x00, SD_DHCP6_OPTION_RAPID_COMMIT, 0x00, 0x00, + /* NTP servers */ + 0x00, SD_DHCP6_OPTION_NTP_SERVER, 0x00, 0x14, + /* NTP server (broken sub option and sub option length) */ + 0x01, 0x00, 0x10, 0x00, + 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x15, 0xc8, 0xff, 0xfe, 0xef, 0x1e, 0x4e, + /* Client ID */ + 0x00, SD_DHCP6_OPTION_CLIENTID, 0x00, 0x0e, + 0x00, 0x02, /* DUID-EN */ + 0x00, 0x00, 0xab, 0x11, /* pen */ + 0x5c, 0x6b, 0x90, 0xec, 0xda, 0x95, 0x15, 0x45, /* id */ + /* Server ID */ + 0x00, SD_DHCP6_OPTION_SERVERID, 0x00, 0x0a, + 0x00, 0x03, /* DUID-LL */ + 0x00, 0x01, /* htype */ + 0xdc, 0x15, 0xc8, 0xef, 0x1e, 0x4e, /* haddr */ /* preference */ - 0x00, 0x07, 0x00, 0x01, 0x00, + 0x00, SD_DHCP6_OPTION_PREFERENCE, 0x00, 0x01, + 0x00, /* DNS servers */ - 0x00, 0x17, 0x00, 0x10, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x15, 0xc8, 0xff, - 0xfe, 0xef, 0x1e, 0x4e, + 0x00, SD_DHCP6_OPTION_DNS_SERVERS, 0x00, 0x10, + 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x15, 0xc8, 0xff, 0xfe, 0xef, 0x1e, 0x4e, /* v6 pcp server */ - 0x00, 0x56, 0x00, 0x10, 0x2a, 0x02, 0x81, 0x0d, 0x98, 0x80, 0x37, 0x00, 0xde, 0x15, 0xc8, 0xff, - 0xfe, 0xef, 0x1e, 0x4e, + 0x00, SD_DHCP6_OPTION_V6_PCP_SERVER, 0x00, 0x10, + 0x2a, 0x02, 0x81, 0x0d, 0x98, 0x80, 0x37, 0x00, 0xde, 0x15, 0xc8, 0xff, 0xfe, 0xef, 0x1e, 0x4e, /* IA_NA */ - 0x00, 0x03, 0x00, 0x28, 0xcc, 0x59, 0x11, 0x7b, 0x00, 0x00, 0x07, 0x08, 0x00, 0x00, 0x0b, 0x40, - /* IA_NA (iaaddr) */ - 0x00, 0x05, 0x00, 0x18, 0x2a, 0x02, 0x81, 0x0d, 0x98, 0x80, 0x37, 0x00, 0x6a, 0x05, 0xca, 0xff, - 0xfe, 0xf1, 0x51, 0x53, 0x00, 0x00, 0x0e, 0x10, 0x00, 0x00, 0x1c, 0x20, + 0x00, SD_DHCP6_OPTION_IA_NA, 0x00, 0x28, + 0xcc, 0x59, 0x11, 0x7b, /* iaid */ + 0x00, 0x00, 0x07, 0x08, /* lifetime T1 */ + 0x00, 0x00, 0x0b, 0x40, /* lifetime T2 */ + /* IA_NA (iaaddr suboption) */ + 0x00, SD_DHCP6_OPTION_IAADDR, 0x00, 0x18, + 0x2a, 0x02, 0x81, 0x0d, 0x98, 0x80, 0x37, 0x00, 0x6a, 0x05, 0xca, 0xff, 0xfe, 0xf1, 0x51, 0x53, /* address */ + 0x00, 0x00, 0x0e, 0x10, /* preferred lifetime */ + 0x00, 0x00, 0x1c, 0x20, /* valid lifetime */ /* IA_PD */ - 0x00, 0x19, 0x00, 0x29, 0xcc, 0x59, 0x11, 0x7b, 0x00, 0x00, 0x07, 0x08, 0x00, 0x00, 0x0b, 0x40, - /* IA_PD (iaprefix) */ - 0x00, 0x1a, 0x00, 0x19, 0x00, 0x00, 0x0e, 0x10, 0x00, 0x00, 0x1c, 0x20, 0x3a, 0x2a, 0x02, 0x81, - 0x0d, 0x98, 0x80, 0x37, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, SD_DHCP6_OPTION_IA_PD, 0x00, 0x29, + 0xcc, 0x59, 0x11, 0x7b, /* iaid */ + 0x00, 0x00, 0x07, 0x08, /* lifetime T1 */ + 0x00, 0x00, 0x0b, 0x40, /* lifetime T2 */ + /* IA_PD (iaprefix suboption) */ + 0x00, SD_DHCP6_OPTION_IA_PD_PREFIX, 0x00, 0x19, + 0x00, 0x00, 0x0e, 0x10, /* preferred lifetime */ + 0x00, 0x00, 0x1c, 0x20, /* valid lifetime */ + 0x3a, /* prefixlen */ + 0x2a, 0x02, 0x81, 0x0d, 0x98, 0x80, 0x37, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* prefix */ }; static const uint8_t duid[] = { 0x00, 0x00, 0xab, 0x11, 0x5c, 0x6b, 0x90, 0xec, 0xda, 0x95, 0x15, 0x45, @@ -404,614 +455,548 @@ static void test_client_parse_message_issue_22099(void) { assert_se(dhcp6_lease_new_from_message(client, (const DHCP6Message*) msg, sizeof(msg), NULL, NULL, &lease) >= 0); } -static uint8_t msg_advertise[198] = { - 0x02, 0x0f, 0xb4, 0xe5, 0x00, 0x01, 0x00, 0x0e, - 0x00, 0x01, 0x00, 0x01, 0x1a, 0x6b, 0xf3, 0x30, - 0x3c, 0x97, 0x0e, 0xcf, 0xa3, 0x7d, 0x00, 0x03, - 0x00, 0x5e, 0x0e, 0xcf, 0xa3, 0x7d, 0x00, 0x00, - 0x00, 0x50, 0x00, 0x00, 0x00, 0x78, 0x00, 0x05, - 0x00, 0x18, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, - 0xbe, 0xef, 0x78, 0xee, 0x1c, 0xf3, 0x09, 0x3c, - 0x55, 0xad, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, - 0x00, 0xb4, 0x00, 0x0d, 0x00, 0x32, 0x00, 0x00, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x28, - 0x65, 0x73, 0x29, 0x20, 0x72, 0x65, 0x6e, 0x65, - 0x77, 0x65, 0x64, 0x2e, 0x20, 0x47, 0x72, 0x65, - 0x65, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x66, - 0x72, 0x6f, 0x6d, 0x20, 0x70, 0x6c, 0x61, 0x6e, - 0x65, 0x74, 0x20, 0x45, 0x61, 0x72, 0x74, 0x68, - 0x00, 0x17, 0x00, 0x10, 0x20, 0x01, 0x0d, 0xb8, - 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x0b, - 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74, - 0x72, 0x61, 0x00, 0x00, 0x1f, 0x00, 0x10, 0x20, - 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x02, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x19, - 0x40, 0x5c, 0x53, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, - 0x53, 0x00, 0x07, 0x00, 0x01, 0x00 +static const uint8_t msg_information_request[] = { + /* Message type */ + DHCP6_MESSAGE_INFORMATION_REQUEST, + /* Transaction ID */ + 0x0f, 0xb4, 0xe5, + /* MUD URL */ + /* ORO */ + 0x00, SD_DHCP6_OPTION_ORO, 0x00, 0x08, + 0x00, SD_DHCP6_OPTION_DNS_SERVERS, + 0x00, SD_DHCP6_OPTION_DOMAIN_LIST, + 0x00, SD_DHCP6_OPTION_NTP_SERVER, + 0x00, SD_DHCP6_OPTION_SNTP_SERVERS, + /* Client ID */ + 0x00, SD_DHCP6_OPTION_CLIENTID, 0x00, 0x0e, + CLIENT_ID_BYTES, + /* Extra options */ + /* Elapsed time */ + 0x00, SD_DHCP6_OPTION_ELAPSED_TIME, 0x00, 0x02, + 0x00, 0x00, }; -static uint8_t msg_reply[191] = { - 0x07, 0xf7, 0x4e, 0x57, 0x00, 0x02, 0x00, 0x0e, - 0x00, 0x01, 0x00, 0x01, 0x19, 0x40, 0x5c, 0x53, - 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53, 0x00, 0x01, - 0x00, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x1a, 0x6b, - 0xf3, 0x30, 0x3c, 0x97, 0x0e, 0xcf, 0xa3, 0x7d, - 0x00, 0x03, 0x00, 0x4a, 0x0e, 0xcf, 0xa3, 0x7d, - 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x78, - 0x00, 0x05, 0x00, 0x18, 0x20, 0x01, 0x0d, 0xb8, - 0xde, 0xad, 0xbe, 0xef, 0x78, 0xee, 0x1c, 0xf3, - 0x09, 0x3c, 0x55, 0xad, 0x00, 0x00, 0x00, 0x96, - 0x00, 0x00, 0x00, 0xb4, 0x00, 0x0d, 0x00, 0x1e, - 0x00, 0x00, 0x41, 0x6c, 0x6c, 0x20, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x20, - 0x77, 0x65, 0x72, 0x65, 0x20, 0x61, 0x73, 0x73, - 0x69, 0x67, 0x6e, 0x65, 0x64, 0x2e, 0x00, 0x17, - 0x00, 0x10, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, - 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x18, 0x00, 0x0b, 0x03, 0x6c, - 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74, 0x72, 0x61, - 0x00, 0x00, 0x1f, 0x00, 0x10, 0x20, 0x01, 0x0d, - 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x27, 0x00, - 0x0e, 0x01, 0x06, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x05, 0x69, 0x6e, 0x74, 0x72, 0x61 +static const uint8_t msg_solicit[] = { + /* Message type */ + DHCP6_MESSAGE_SOLICIT, + /* Transaction ID */ + 0x0f, 0xb4, 0xe5, + /* Rapid commit */ + 0x00, SD_DHCP6_OPTION_RAPID_COMMIT, 0x00, 0x00, + /* IA_NA */ + 0x00, SD_DHCP6_OPTION_IA_NA, 0x00, 0x0c, + IA_ID_BYTES, + 0x00, 0x00, 0x00, 0x00, /* lifetime T1 */ + 0x00, 0x00, 0x00, 0x00, /* lifetime T2 */ + /* IA_PD */ + 0x00, SD_DHCP6_OPTION_IA_PD, 0x00, 0x0c, + IA_ID_BYTES, + 0x00, 0x00, 0x00, 0x00, /* lifetime T1 */ + 0x00, 0x00, 0x00, 0x00, /* lifetime T2 */ + /* Client FQDN */ + 0x00, SD_DHCP6_OPTION_CLIENT_FQDN, 0x00, 0x11, + DHCP6_FQDN_FLAG_S, + 0x04, 'h', 'o', 's', 't', 0x03, 'l', 'a', 'b', 0x05, 'i', 'n', 't', 'r', 'a', 0x00, + /* User Class */ + /* Vendor Class */ + /* Vendor Options */ + /* MUD URL */ + /* ORO */ + 0x00, SD_DHCP6_OPTION_ORO, 0x00, 0x08, + 0x00, SD_DHCP6_OPTION_DNS_SERVERS, + 0x00, SD_DHCP6_OPTION_DOMAIN_LIST, + 0x00, SD_DHCP6_OPTION_NTP_SERVER, + 0x00, SD_DHCP6_OPTION_SNTP_SERVERS, + /* Client ID */ + 0x00, SD_DHCP6_OPTION_CLIENTID, 0x00, 0x0e, + CLIENT_ID_BYTES, + /* Extra options */ + /* Elapsed time */ + 0x00, SD_DHCP6_OPTION_ELAPSED_TIME, 0x00, 0x02, + 0x00, 0x00, }; -static uint8_t fqdn_wire[16] = { - 0x04, 'h', 'o', 's', 't', 0x03, 'l', 'a', 'b', - 0x05, 'i', 'n', 't', 'r', 'a', 0x00 +static const uint8_t msg_request[] = { + /* Message type */ + DHCP6_MESSAGE_REQUEST, + /* Transaction ID */ + 0x00, 0x00, 0x00, + /* Server ID */ + 0x00, SD_DHCP6_OPTION_SERVERID, 0x00, 0x0e, + SERVER_ID_BYTES, + /* IA_NA */ + 0x00, SD_DHCP6_OPTION_IA_NA, 0x00, 0x44, + IA_ID_BYTES, + 0x00, 0x00, 0x00, 0x00, /* lifetime T1 */ + 0x00, 0x00, 0x00, 0x00, /* lifetime T2 */ + /* IA_NA (IAADDR suboption) */ + 0x00, SD_DHCP6_OPTION_IAADDR, 0x00, 0x18, + IA_NA_ADDRESS1_BYTES, + 0x00, 0x00, 0x00, 0x00, /* preferred lifetime */ + 0x00, 0x00, 0x00, 0x00, /* valid lifetime */ + /* IA_NA (IAADDR suboption) */ + 0x00, SD_DHCP6_OPTION_IAADDR, 0x00, 0x18, + IA_NA_ADDRESS2_BYTES, + 0x00, 0x00, 0x00, 0x00, /* preferred lifetime */ + 0x00, 0x00, 0x00, 0x00, /* valid lifetime */ + /* IA_PD */ + 0x00, SD_DHCP6_OPTION_IA_PD, 0x00, 0x46, + IA_ID_BYTES, + 0x00, 0x00, 0x00, 0x00, /* lifetime T1 */ + 0x00, 0x00, 0x00, 0x00, /* lifetime T2 */ + /* IA_PD (IA_PD_PREFIX suboption) */ + 0x00, SD_DHCP6_OPTION_IA_PD_PREFIX, 0x00, 0x19, + 0x00, 0x00, 0x00, 0x00, /* preferred lifetime */ + 0x00, 0x00, 0x00, 0x00, /* valid lifetime */ + 0x40, /* prefixlen */ + IA_PD_PREFIX1_BYTES, + /* IA_PD (IA_PD_PREFIX suboption) */ + 0x00, SD_DHCP6_OPTION_IA_PD_PREFIX, 0x00, 0x19, + 0x00, 0x00, 0x00, 0x00, /* preferred lifetime */ + 0x00, 0x00, 0x00, 0x00, /* valid lifetime */ + 0x40, /* prefixlen */ + IA_PD_PREFIX2_BYTES, + /* Client FQDN */ + 0x00, SD_DHCP6_OPTION_CLIENT_FQDN, 0x00, 0x11, + DHCP6_FQDN_FLAG_S, + 0x04, 'h', 'o', 's', 't', 0x03, 'l', 'a', 'b', 0x05, 'i', 'n', 't', 'r', 'a', 0x00, + /* User Class */ + /* Vendor Class */ + /* Vendor Options */ + /* MUD URL */ + /* ORO */ + 0x00, SD_DHCP6_OPTION_ORO, 0x00, 0x08, + 0x00, SD_DHCP6_OPTION_DNS_SERVERS, + 0x00, SD_DHCP6_OPTION_DOMAIN_LIST, + 0x00, SD_DHCP6_OPTION_NTP_SERVER, + 0x00, SD_DHCP6_OPTION_SNTP_SERVERS, + /* Client ID */ + 0x00, SD_DHCP6_OPTION_CLIENTID, 0x00, 0x0e, + CLIENT_ID_BYTES, + /* Extra options */ + /* Elapsed time */ + 0x00, SD_DHCP6_OPTION_ELAPSED_TIME, 0x00, 0x02, + 0x00, 0x00, }; -static void test_advertise_option(sd_event *e) { - _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL; - DHCP6Message *advertise = (DHCP6Message *)msg_advertise; - size_t len = sizeof(msg_advertise) - sizeof(DHCP6Message), pos = 0; - uint32_t lt_pref, lt_valid; - bool opt_clientid = false; - const struct in6_addr *addrs; - uint8_t preference = 255; - struct in6_addr addr; - char **domains; - uint8_t *opt; - int r; - be32_t val; - - log_debug("/* %s */", __func__); - - assert_se(len >= sizeof(DHCP6Message)); - - assert_se(dhcp6_lease_new(&lease) >= 0); - - assert_se(advertise->type == DHCP6_MESSAGE_ADVERTISE); - assert_se((be32toh(advertise->transaction_id) & 0x00ffffff) == 0x0fb4e5); - - while (pos < len) { - DHCP6Option *option = (DHCP6Option *)&advertise->options[pos]; - const uint16_t optcode = be16toh(option->code); - const uint16_t optlen = be16toh(option->len); - uint8_t *optval = option->data; - - switch(optcode) { - case SD_DHCP6_OPTION_CLIENTID: - assert_se(optlen == 14); +static const uint8_t msg_reply[] = { + /* Message type */ + DHCP6_MESSAGE_REPLY, + /* Transaction ID */ + 0x0f, 0xb4, 0xe5, + /* Client ID */ + 0x00, SD_DHCP6_OPTION_CLIENTID, 0x00, 0x0e, + CLIENT_ID_BYTES, + /* Server ID */ + 0x00, SD_DHCP6_OPTION_SERVERID, 0x00, 0x0e, + SERVER_ID_BYTES, + /* Rapid commit */ + 0x00, SD_DHCP6_OPTION_RAPID_COMMIT, 0x00, 0x01, + 0x00, + /* IA_NA */ + 0x00, SD_DHCP6_OPTION_IA_NA, 0x00, 0x66, + IA_ID_BYTES, + 0x00, 0x00, 0x00, 0x50, /* lifetime T1 */ + 0x00, 0x00, 0x00, 0x78, /* lifetime T2 */ + /* IA_NA (IAADDR suboption) */ + 0x00, SD_DHCP6_OPTION_IAADDR, 0x00, 0x18, + IA_NA_ADDRESS2_BYTES, + 0x00, 0x00, 0x00, 0x96, /* preferred lifetime */ + 0x00, 0x00, 0x00, 0xb4, /* valid lifetime */ + /* IA_NA (IAADDR suboption) */ + 0x00, SD_DHCP6_OPTION_IAADDR, 0x00, 0x18, + IA_NA_ADDRESS1_BYTES, + 0x00, 0x00, 0x00, 0x96, /* preferred lifetime */ + 0x00, 0x00, 0x00, 0xb4, /* valid lifetime */ + /* IA_NA (status code suboption) */ + 0x00, SD_DHCP6_OPTION_STATUS_CODE, 0x00, 0x1e, + 0x00, 0x00, /* status code */ + 0x41, 0x6c, 0x6c, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x20, 0x77, 0x65, + 0x72, 0x65, 0x20, 0x61, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x2e, /* status message */ + /* IA_PD */ + 0x00, SD_DHCP6_OPTION_IA_PD, 0x00, 0x46, + IA_ID_BYTES, + 0x00, 0x00, 0x00, 0x50, /* lifetime T1 */ + 0x00, 0x00, 0x00, 0x78, /* lifetime T2 */ + /* IA_PD (IA_PD_PREFIX suboption) */ + 0x00, SD_DHCP6_OPTION_IA_PD_PREFIX, 0x00, 0x19, + 0x00, 0x00, 0x00, 0x96, /* preferred lifetime */ + 0x00, 0x00, 0x00, 0xb4, /* valid lifetime */ + 0x40, /* prefixlen */ + IA_PD_PREFIX2_BYTES, + /* IA_PD (IA_PD_PREFIX suboption) */ + 0x00, SD_DHCP6_OPTION_IA_PD_PREFIX, 0x00, 0x19, + 0x00, 0x00, 0x00, 0x96, /* preferred lifetime */ + 0x00, 0x00, 0x00, 0xb4, /* valid lifetime */ + 0x40, /* prefixlen */ + IA_PD_PREFIX1_BYTES, + /* DNS servers */ + 0x00, SD_DHCP6_OPTION_DNS_SERVERS, 0x00, 0x20, + DNS1_BYTES, + DNS2_BYTES, + /* SNTP servers */ + 0x00, SD_DHCP6_OPTION_SNTP_SERVERS, 0x00, 0x20, + SNTP1_BYTES, + SNTP2_BYTES, + /* NTP servers */ + 0x00, SD_DHCP6_OPTION_NTP_SERVER, 0x00, 0x37, + /* NTP server (address suboption) */ + 0x00, DHCP6_NTP_SUBOPTION_SRV_ADDR, 0x00, 0x10, + NTP1_BYTES, + /* NTP server (address suboption) */ + 0x00, DHCP6_NTP_SUBOPTION_SRV_ADDR, 0x00, 0x10, + NTP2_BYTES, + /* NTP server (fqdn suboption) */ + 0x00, DHCP6_NTP_SUBOPTION_SRV_FQDN, 0x00, 0x0b, + 0x03, 'n', 't', 'p', 0x05, 'i', 'n', 't', 'r', 'a', 0x00, + /* Domain list */ + 0x00, SD_DHCP6_OPTION_DOMAIN_LIST, 0x00, 0x0b, + 0x03, 'l', 'a', 'b', 0x05, 'i', 'n', 't', 'r', 'a', 0x00, + /* Client FQDN */ + 0x00, SD_DHCP6_OPTION_CLIENT_FQDN, 0x00, 0x12, + 0x01, 0x06, 'c', 'l', 'i', 'e', 'n', 't', 0x03, 'l', 'a', 'b', 0x05, 'i', 'n', 't', 'r', 'a', +}; - opt_clientid = true; - break; +static const uint8_t msg_advertise[] = { + /* Message type */ + DHCP6_MESSAGE_ADVERTISE, + /* Transaction ID */ + 0x0f, 0xb4, 0xe5, + /* Client ID */ + 0x00, SD_DHCP6_OPTION_CLIENTID, 0x00, 0x0e, + CLIENT_ID_BYTES, + /* Server ID */ + 0x00, SD_DHCP6_OPTION_SERVERID, 0x00, 0x0e, + SERVER_ID_BYTES, + /* Preference */ + 0x00, SD_DHCP6_OPTION_PREFERENCE, 0x00, 0x01, + 0xff, + /* IA_NA */ + 0x00, SD_DHCP6_OPTION_IA_NA, 0x00, 0x7a, + IA_ID_BYTES, + 0x00, 0x00, 0x00, 0x50, /* lifetime T1 */ + 0x00, 0x00, 0x00, 0x78, /* lifetime T2 */ + /* IA_NA (IAADDR suboption) */ + 0x00, SD_DHCP6_OPTION_IAADDR, 0x00, 0x18, + IA_NA_ADDRESS2_BYTES, /* address */ + 0x00, 0x00, 0x00, 0x96, /* preferred lifetime */ + 0x00, 0x00, 0x00, 0xb4, /* valid lifetime */ + /* IA_NA (IAADDR suboption) */ + 0x00, SD_DHCP6_OPTION_IAADDR, 0x00, 0x18, + IA_NA_ADDRESS1_BYTES, /* address */ + 0x00, 0x00, 0x00, 0x96, /* preferred lifetime */ + 0x00, 0x00, 0x00, 0xb4, /* valid lifetime */ + /* IA_NA (status code suboption) */ + 0x00, SD_DHCP6_OPTION_STATUS_CODE, 0x00, 0x32, + 0x00, 0x00, /* status code */ + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x28, 0x65, 0x73, 0x29, 0x20, 0x72, 0x65, 0x6e, 0x65, + 0x77, 0x65, 0x64, 0x2e, 0x20, 0x47, 0x72, 0x65, 0x65, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x66, + 0x72, 0x6f, 0x6d, 0x20, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x74, 0x20, 0x45, 0x61, 0x72, 0x74, 0x68, /* status message */ + /* IA_PD */ + 0x00, SD_DHCP6_OPTION_IA_PD, 0x00, 0x46, + IA_ID_BYTES, + 0x00, 0x00, 0x00, 0x50, /* lifetime T1 */ + 0x00, 0x00, 0x00, 0x78, /* lifetime T2 */ + /* IA_PD (IA_PD_PREFIX suboption) */ + 0x00, SD_DHCP6_OPTION_IA_PD_PREFIX, 0x00, 0x19, + 0x00, 0x00, 0x00, 0x96, /* preferred lifetime */ + 0x00, 0x00, 0x00, 0xb4, /* valid lifetime */ + 0x40, /* prefixlen */ + IA_PD_PREFIX2_BYTES, + /* IA_PD (IA_PD_PREFIX suboption) */ + 0x00, SD_DHCP6_OPTION_IA_PD_PREFIX, 0x00, 0x19, + 0x00, 0x00, 0x00, 0x96, /* preferred lifetime */ + 0x00, 0x00, 0x00, 0xb4, /* valid lifetime */ + 0x40, /* prefixlen */ + IA_PD_PREFIX1_BYTES, + /* DNS servers */ + 0x00, SD_DHCP6_OPTION_DNS_SERVERS, 0x00, 0x20, + DNS1_BYTES, + DNS2_BYTES, + /* SNTP servers */ + 0x00, SD_DHCP6_OPTION_SNTP_SERVERS, 0x00, 0x20, + SNTP1_BYTES, + SNTP2_BYTES, + /* NTP servers */ + 0x00, SD_DHCP6_OPTION_NTP_SERVER, 0x00, 0x37, + /* NTP server (address suboption) */ + 0x00, DHCP6_NTP_SUBOPTION_SRV_ADDR, 0x00, 0x10, + NTP1_BYTES, + /* NTP server (address suboption) */ + 0x00, DHCP6_NTP_SUBOPTION_SRV_ADDR, 0x00, 0x10, + NTP2_BYTES, + /* NTP server (fqdn suboption) */ + 0x00, DHCP6_NTP_SUBOPTION_SRV_FQDN, 0x00, 0x0b, + 0x03, 'n', 't', 'p', 0x05, 'i', 'n', 't', 'r', 'a', 0x00, + /* Domain list */ + 0x00, SD_DHCP6_OPTION_DOMAIN_LIST, 0x00, 0x0b, + 0x03, 'l', 'a', 'b', 0x05, 'i', 'n', 't', 'r', 'a', 0x00, + /* Client FQDN */ + 0x00, SD_DHCP6_OPTION_CLIENT_FQDN, 0x00, 0x12, + 0x01, 0x06, 'c', 'l', 'i', 'e', 'n', 't', 0x03, 'l', 'a', 'b', 0x05, 'i', 'n', 't', 'r', 'a', +}; - case SD_DHCP6_OPTION_IA_NA: { - be32_t iaid = htobe32(0x0ecfa37d); +static void test_client_verify_information_request(const DHCP6Message *msg, size_t len) { + log_debug("/* %s */", __func__); - assert_se(optlen == 94); - assert_se(optval == &msg_advertise[26]); - assert_se(!memcmp(optval, &msg_advertise[26], optlen)); + assert_se(len == sizeof(msg_information_request)); + /* The elapsed time value is not deterministic. Skip it. */ + assert_se(memcmp(msg, msg_information_request, len - sizeof(be16_t)) == 0); +} - assert_se(!memcmp(optval, &iaid, sizeof(val))); +static void test_client_verify_solicit(const DHCP6Message *msg, size_t len) { + log_debug("/* %s */", __func__); - val = htobe32(80); - assert_se(!memcmp(optval + 4, &val, sizeof(val))); + assert_se(len == sizeof(msg_solicit)); + /* The elapsed time value is not deterministic. Skip it. */ + assert_se(memcmp(msg, msg_solicit, len - sizeof(be16_t)) == 0); +} - val = htobe32(120); - assert_se(!memcmp(optval + 8, &val, sizeof(val))); +static void test_client_verify_request(const DHCP6Message *msg, size_t len) { + log_debug("/* %s */", __func__); - assert_se(dhcp6_option_parse_ia(NULL, iaid, optcode, optlen, optval, &lease->ia_na) >= 0); + assert_se(len == sizeof(msg_request)); + assert_se(msg->type == DHCP6_MESSAGE_REQUEST); + /* The transaction ID and elapsed time value are not deterministic. Skip them. */ + assert_se(memcmp(msg->options, msg_request + offsetof(DHCP6Message, options), len - offsetof(DHCP6Message, options) - sizeof(be16_t)) == 0); +} - break; - } - case SD_DHCP6_OPTION_SERVERID: - assert_se(optlen == 14); - assert_se(optval == &msg_advertise[179]); - assert_se(!memcmp(optval, &msg_advertise[179], optlen)); +static void test_lease_common(sd_dhcp6_client *client) { + sd_dhcp6_lease *lease; + const struct in6_addr *addrs; + const char *str; + char **strv; + uint8_t *id; + size_t len; - assert_se(dhcp6_lease_set_serverid(lease, optval, optlen) >= 0); - break; + assert_se(sd_dhcp6_client_get_lease(client, &lease) >= 0); - case SD_DHCP6_OPTION_PREFERENCE: - assert_se(optlen == 1); - assert_se(!*optval); + assert_se(dhcp6_lease_get_clientid(lease, &id, &len) >= 0); + assert_se(memcmp_nn(id, len, client_id, sizeof(client_id)) == 0); - assert_se(dhcp6_lease_set_preference(lease, *optval) >= 0); - break; + assert_se(sd_dhcp6_lease_get_domains(lease, &strv) == 1); + assert_se(streq(strv[0], "lab.intra")); + assert_se(!strv[1]); - case SD_DHCP6_OPTION_ELAPSED_TIME: - assert_se(optlen == 2); + assert_se(sd_dhcp6_lease_get_fqdn(lease, &str) >= 0); + assert_se(streq(str, "client.lab.intra")); - break; + assert_se(sd_dhcp6_lease_get_dns(lease, &addrs) == 2); + assert_se(in6_addr_equal(&addrs[0], &dns1)); + assert_se(in6_addr_equal(&addrs[1], &dns2)); - case SD_DHCP6_OPTION_DNS_SERVERS: - assert_se(optlen == 16); - assert_se(dhcp6_lease_add_dns(lease, optval, optlen) >= 0); - break; + assert_se(sd_dhcp6_lease_get_ntp_addrs(lease, &addrs) == 2); + assert_se(in6_addr_equal(&addrs[0], &ntp1)); + assert_se(in6_addr_equal(&addrs[1], &ntp2)); - case SD_DHCP6_OPTION_DOMAIN_LIST: - assert_se(optlen == 11); - assert_se(dhcp6_lease_add_domains(lease, optval, optlen) >= 0); - break; + assert_se(sd_dhcp6_lease_get_ntp_fqdn(lease, &strv) == 1); + assert_se(streq(strv[0], "ntp.intra")); + assert_se(!strv[1]); - case SD_DHCP6_OPTION_SNTP_SERVERS: - assert_se(optlen == 16); - assert_se(dhcp6_lease_add_sntp(lease, optval, optlen) >= 0); - break; + assert_se(lease->sntp_count == 2); + assert_se(in6_addr_equal(&lease->sntp[0], &sntp1)); + assert_se(in6_addr_equal(&lease->sntp[1], &sntp2)); +} - default: - break; - } +static void test_lease_managed(sd_dhcp6_client *client) { + sd_dhcp6_lease *lease; + struct in6_addr addr; + uint32_t lt_pref, lt_valid; + uint8_t *id, prefixlen; + size_t len; - pos += sizeof(*option) + optlen; - } + assert_se(sd_dhcp6_client_get_lease(client, &lease) >= 0); - assert_se(pos == len); - assert_se(opt_clientid); + assert_se(dhcp6_lease_get_serverid(lease, &id, &len) >= 0); + assert_se(memcmp_nn(id, len, server_id, sizeof(server_id)) == 0); sd_dhcp6_lease_reset_address_iter(lease); assert_se(sd_dhcp6_lease_get_address(lease, &addr, <_pref, <_valid) >= 0); - assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr))); + assert_se(in6_addr_equal(&addr, &ia_na_address1)); + assert_se(lt_pref == 150); + assert_se(lt_valid == 180); + assert_se(sd_dhcp6_lease_get_address(lease, &addr, <_pref, <_valid) >= 0); + assert_se(in6_addr_equal(&addr, &ia_na_address2)); assert_se(lt_pref == 150); assert_se(lt_valid == 180); assert_se(sd_dhcp6_lease_get_address(lease, &addr, <_pref, <_valid) == -ENODATA); sd_dhcp6_lease_reset_address_iter(lease); assert_se(sd_dhcp6_lease_get_address(lease, &addr, <_pref, <_valid) >= 0); - assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr))); - assert_se(sd_dhcp6_lease_get_address(lease, &addr, <_pref, <_valid) == -ENODATA); - sd_dhcp6_lease_reset_address_iter(lease); + assert_se(in6_addr_equal(&addr, &ia_na_address1)); + assert_se(lt_pref == 150); + assert_se(lt_valid == 180); assert_se(sd_dhcp6_lease_get_address(lease, &addr, <_pref, <_valid) >= 0); - assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr))); + assert_se(in6_addr_equal(&addr, &ia_na_address2)); + assert_se(lt_pref == 150); + assert_se(lt_valid == 180); assert_se(sd_dhcp6_lease_get_address(lease, &addr, <_pref, <_valid) == -ENODATA); - assert_se(dhcp6_lease_get_serverid(lease, &opt, &len) >= 0); - assert_se(len == 14); - assert_se(!memcmp(opt, &msg_advertise[179], len)); - - assert_se(dhcp6_lease_get_preference(lease, &preference) >= 0); - assert_se(preference == 0); - - r = sd_dhcp6_lease_get_dns(lease, &addrs); - assert_se(r == 1); - assert_se(!memcmp(addrs, &msg_advertise[124], r * 16)); - - r = sd_dhcp6_lease_get_domains(lease, &domains); - assert_se(r == 1); - assert_se(!strcmp("lab.intra", domains[0])); - assert_se(domains[1] == NULL); - - r = sd_dhcp6_lease_get_ntp_addrs(lease, &addrs); - assert_se(r == 1); - assert_se(!memcmp(addrs, &msg_advertise[159], r * 16)); -} - -static int test_check_completed_in_2_seconds(sd_event_source *s, uint64_t usec, void *userdata) { - assert_not_reached(); -} - -static void test_client_solicit_cb(sd_dhcp6_client *client, int event, - void *userdata) { - sd_event *e = userdata; - sd_dhcp6_lease *lease; - const struct in6_addr *addrs; - char **domains; - - log_debug("/* %s */", __func__); - - assert_se(e); - assert_se(event == SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE); - - assert_se(sd_dhcp6_client_get_lease(client, &lease) >= 0); - - assert_se(sd_dhcp6_lease_get_domains(lease, &domains) == 1); - assert_se(!strcmp("lab.intra", domains[0])); - assert_se(domains[1] == NULL); - - assert_se(sd_dhcp6_lease_get_dns(lease, &addrs) == 1); - assert_se(!memcmp(addrs, &msg_advertise[124], 16)); - - assert_se(sd_dhcp6_lease_get_ntp_addrs(lease, &addrs) == 1); - assert_se(!memcmp(addrs, &msg_advertise[159], 16)); - - assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DNS_SERVERS) == -EBUSY); - - sd_event_exit(e, 0); -} - -static void test_client_send_reply(DHCP6Message *request) { - DHCP6Message reply; - - log_debug("/* %s */", __func__); - - reply.transaction_id = request->transaction_id; - reply.type = DHCP6_MESSAGE_REPLY; - - memcpy(msg_reply, &reply.transaction_id, 4); - - memcpy(&msg_reply[26], test_duid, sizeof(test_duid)); - - memcpy(&msg_reply[44], &test_iaid, sizeof(test_iaid)); - - assert_se(write(test_dhcp_fd[1], msg_reply, sizeof(msg_reply)) == sizeof(msg_reply)); -} - -static void test_client_verify_request(DHCP6Message *request, size_t len) { - _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL; - bool found_clientid = false, found_iana = false, found_serverid = false, - found_elapsed_time = false, found_fqdn = false; - uint32_t lt_pref, lt_valid; - struct in6_addr addr; - size_t pos = 0; - be32_t val; - - log_debug("/* %s */", __func__); - - assert_se(request->type == DHCP6_MESSAGE_REQUEST); - assert_se(dhcp6_lease_new(&lease) >= 0); - - len -= sizeof(DHCP6Message); - - while (pos < len) { - DHCP6Option *option = (DHCP6Option *)&request->options[pos]; - uint16_t optcode = be16toh(option->code); - uint16_t optlen = be16toh(option->len); - uint8_t *optval = option->data; - - switch(optcode) { - case SD_DHCP6_OPTION_CLIENTID: - assert_se(!found_clientid); - found_clientid = true; - - assert_se(!memcmp(optval, &test_duid, - sizeof(test_duid))); - - break; - - case SD_DHCP6_OPTION_IA_NA: - assert_se(!found_iana); - found_iana = true; - - assert_se(optlen == 40); - assert_se(!memcmp(optval, &test_iaid, sizeof(test_iaid))); - - /* T1 and T2 should not be set. */ - val = 0; - assert_se(!memcmp(optval + 4, &val, sizeof(val))); - assert_se(!memcmp(optval + 8, &val, sizeof(val))); - - /* Then, this should refuse all addresses. */ - assert_se(dhcp6_option_parse_ia(NULL, test_iaid, optcode, optlen, optval, &lease->ia_na) == -ENODATA); - - break; - - case SD_DHCP6_OPTION_SERVERID: - assert_se(!found_serverid); - found_serverid = true; - - assert_se(optlen == 14); - assert_se(!memcmp(&msg_advertise[179], optval, optlen)); - - break; - - case SD_DHCP6_OPTION_ELAPSED_TIME: - assert_se(!found_elapsed_time); - found_elapsed_time = true; - - assert_se(optlen == 2); - - break; - case SD_DHCP6_OPTION_CLIENT_FQDN: - assert_se(!found_fqdn); - found_fqdn = true; - - assert_se(optlen == 17); - - assert_se(optval[0] == 0x01); - assert_se(!memcmp(optval + 1, fqdn_wire, sizeof(fqdn_wire))); - break; - } - - pos += sizeof(*option) + optlen; - } - - assert_se(found_clientid && found_iana && found_serverid && found_elapsed_time); - - sd_dhcp6_lease_reset_address_iter(lease); + sd_dhcp6_lease_reset_pd_prefix_iter(lease); + assert_se(sd_dhcp6_lease_get_pd(lease, &addr, &prefixlen, <_pref, <_valid) >= 0); + assert_se(in6_addr_equal(&addr, &ia_pd_prefix1)); + assert_se(prefixlen == 64); + assert_se(lt_pref == 150); + assert_se(lt_valid == 180); + assert_se(sd_dhcp6_lease_get_pd(lease, &addr, &prefixlen, <_pref, <_valid) >= 0); + assert_se(in6_addr_equal(&addr, &ia_pd_prefix2)); + assert_se(prefixlen == 64); + assert_se(lt_pref == 150); + assert_se(lt_valid == 180); assert_se(sd_dhcp6_lease_get_address(lease, &addr, <_pref, <_valid) == -ENODATA); -} - -static void test_client_send_advertise(DHCP6Message *solicit) { - DHCP6Message advertise; - - log_debug("/* %s */", __func__); - - advertise.transaction_id = solicit->transaction_id; - advertise.type = DHCP6_MESSAGE_ADVERTISE; - - memcpy(msg_advertise, &advertise.transaction_id, 4); - memcpy(&msg_advertise[8], test_duid, sizeof(test_duid)); - - memcpy(&msg_advertise[26], &test_iaid, sizeof(test_iaid)); + sd_dhcp6_lease_reset_pd_prefix_iter(lease); + assert_se(sd_dhcp6_lease_get_pd(lease, &addr, &prefixlen, <_pref, <_valid) >= 0); + assert_se(in6_addr_equal(&addr, &ia_pd_prefix1)); + assert_se(prefixlen == 64); + assert_se(lt_pref == 150); + assert_se(lt_valid == 180); + assert_se(sd_dhcp6_lease_get_pd(lease, &addr, &prefixlen, <_pref, <_valid) >= 0); + assert_se(in6_addr_equal(&addr, &ia_pd_prefix2)); + assert_se(prefixlen == 64); + assert_se(lt_pref == 150); + assert_se(lt_valid == 180); + assert_se(sd_dhcp6_lease_get_address(lease, &addr, <_pref, <_valid) == -ENODATA); - assert_se(write(test_dhcp_fd[1], msg_advertise, sizeof(msg_advertise)) == sizeof(msg_advertise)); + test_lease_common(client); } -static void test_client_verify_solicit(DHCP6Message *solicit, size_t len) { - bool found_clientid = false, found_iana = false, - found_elapsed_time = false, found_fqdn = false; - size_t pos = 0; - - log_debug("/* %s */", __func__); - - assert_se(solicit->type == DHCP6_MESSAGE_SOLICIT); +static void test_client_callback(sd_dhcp6_client *client, int event, void *userdata) { + switch (event) { + case SD_DHCP6_CLIENT_EVENT_STOP: + log_debug("/* %s (event=stop) */", __func__); + return; - len -= sizeof(DHCP6Message); + case SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST: + log_debug("/* %s (event=information-request) */", __func__); - while (pos < len) { - DHCP6Option *option = (DHCP6Option *)&solicit->options[pos]; - uint16_t optcode = be16toh(option->code); - uint16_t optlen = be16toh(option->len); - uint8_t *optval = option->data; + assert_se(test_client_sent_message_count == 1); - switch(optcode) { - case SD_DHCP6_OPTION_CLIENTID: - assert_se(!found_clientid); - found_clientid = true; + test_lease_common(client); - assert_se(optlen == sizeof(test_duid)); - memcpy(&test_duid, optval, sizeof(test_duid)); + assert_se(sd_dhcp6_client_set_information_request(client, false) >= 0); + assert_se(sd_dhcp6_client_start(client) >= 0); + assert_se(dhcp6_client_set_transaction_id(client, ((const DHCP6Message*) msg_advertise)->transaction_id) >= 0); + break; - break; + case SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE: + log_debug("/* %s (event=ip-acquire) */", __func__); - case SD_DHCP6_OPTION_IA_NA: - assert_se(!found_iana); - found_iana = true; + assert_se(IN_SET(test_client_sent_message_count, 3, 4)); - assert_se(optlen == 12); + test_lease_managed(client); - memcpy(&test_iaid, optval, sizeof(test_iaid)); + assert_se(sd_event_exit(sd_dhcp6_client_get_event(client), 0) >= 0); + break; - break; + case DHCP6_CLIENT_EVENT_TEST_ADVERTISED: { + sd_dhcp6_lease *lease; + uint8_t preference; - case SD_DHCP6_OPTION_ELAPSED_TIME: - assert_se(!found_elapsed_time); - found_elapsed_time = true; + log_debug("/* %s (event=test-advertised) */", __func__); - assert_se(optlen == 2); + assert_se(test_client_sent_message_count == 2); - break; + test_lease_managed(client); - case SD_DHCP6_OPTION_CLIENT_FQDN: - assert_se(!found_fqdn); - found_fqdn = true; + assert_se(sd_dhcp6_client_get_lease(client, &lease) >= 0); + assert_se(dhcp6_lease_get_preference(lease, &preference) >= 0); + assert_se(preference == 0xff); - assert_se(optlen == 17); - - assert_se(optval[0] == 0x01); - assert_se(!memcmp(optval + 1, fqdn_wire, sizeof(fqdn_wire))); - - break; - } - - pos += sizeof(*option) + optlen; + assert_se(dhcp6_client_set_transaction_id(client, ((const DHCP6Message*) msg_reply)->transaction_id) >= 0); + break; } - - assert_se(pos == len); - assert_se(found_clientid && found_iana && found_elapsed_time); -} - -static void test_client_information_cb(sd_dhcp6_client *client, int event, void *userdata) { - sd_event *e = userdata; - sd_dhcp6_lease *lease; - const struct in6_addr *addrs; - struct in6_addr address = { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } }; - char **domains; - const char *fqdn; - - log_debug("/* %s */", __func__); - - assert_se(e); - assert_se(event == SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST); - - assert_se(sd_dhcp6_client_get_lease(client, &lease) >= 0); - - assert_se(sd_dhcp6_lease_get_domains(lease, &domains) == 1); - assert_se(!strcmp("lab.intra", domains[0])); - assert_se(domains[1] == NULL); - - assert_se(sd_dhcp6_lease_get_fqdn(lease, &fqdn) >= 0); - assert_se(streq(fqdn, "client.intra")); - - assert_se(sd_dhcp6_lease_get_dns(lease, &addrs) == 1); - assert_se(!memcmp(addrs, &msg_advertise[124], 16)); - - assert_se(sd_dhcp6_lease_get_ntp_addrs(lease, &addrs) == 1); - assert_se(!memcmp(addrs, &msg_advertise[159], 16)); - - assert_se(sd_dhcp6_client_set_callback(client, NULL, e) >= 0); - assert_se(sd_dhcp6_client_stop(client) >= 0); - assert_se(sd_dhcp6_client_set_information_request(client, false) >= 0); - - assert_se(sd_dhcp6_client_set_callback(client, test_client_solicit_cb, e) >= 0); - - assert_se(sd_dhcp6_client_set_local_address(client, &address) >= 0); - - assert_se(sd_dhcp6_client_start(client) >= 0); -} - -static void test_client_verify_information_request(DHCP6Message *information_request, size_t len) { - _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL; - size_t pos = 0; - bool found_clientid = false, found_elapsed_time = false; - struct in6_addr addr; - uint32_t lt_pref, lt_valid; - - log_debug("/* %s */", __func__); - - assert_se(information_request->type == DHCP6_MESSAGE_INFORMATION_REQUEST); - assert_se(dhcp6_lease_new(&lease) >= 0); - - len -= sizeof(DHCP6Message); - - while (pos < len) { - DHCP6Option *option = (DHCP6Option *)&information_request->options[pos]; - uint16_t optcode = be16toh(option->code); - uint16_t optlen = be16toh(option->len); - uint8_t *optval = option->data; - - switch(optcode) { - case SD_DHCP6_OPTION_CLIENTID: - assert_se(!found_clientid); - found_clientid = true; - - assert_se(optlen == sizeof(test_duid)); - memcpy(&test_duid, optval, sizeof(test_duid)); - - break; - - case SD_DHCP6_OPTION_IA_NA: - case SD_DHCP6_OPTION_SERVERID: - assert_not_reached(); - - case SD_DHCP6_OPTION_ELAPSED_TIME: - assert_se(!found_elapsed_time); - found_elapsed_time = true; - - assert_se(optlen == 2); - - break; - } - - pos += sizeof(*option) + optlen; + default: + assert_not_reached(); } - - assert_se(pos == len); - assert_se(found_clientid && found_elapsed_time); - - sd_dhcp6_lease_reset_address_iter(lease); - - assert_se(sd_dhcp6_lease_get_address(lease, &addr, <_pref, <_valid) == -ENODATA); } -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; +int dhcp6_network_send_udp_socket(int s, struct in6_addr *a, const void *packet, size_t len) { + log_debug("/* %s(count=%u) */", __func__, test_client_sent_message_count); - log_debug("/* %s */", __func__); - - assert_se(s == test_dhcp_fd[0]); - assert_se(server_address); + assert_se(a); + assert_se(in6_addr_equal(a, &mcast_address)); assert_se(packet); - assert_se(len > sizeof(DHCP6Message) + 4); - assert_se(IN6_ARE_ADDR_EQUAL(server_address, &mcast)); - - message = (DHCP6Message *)packet; - - assert_se(message->transaction_id & 0x00ffffff); - - if (test_client_message_num == 0) { - test_client_verify_information_request(message, len); - test_client_send_reply(message); - test_client_message_num++; - } else if (test_client_message_num == 1) { - test_client_verify_solicit(message, len); - test_client_send_advertise(message); - test_client_message_num++; - } else if (test_client_message_num == 2) { - test_client_verify_request(message, len); - test_client_send_reply(message); - test_client_message_num++; + assert_se(len >= sizeof(DHCP6Message)); + + switch (test_client_sent_message_count) { + case 0: + test_client_verify_information_request(packet, len); + assert_se(write(test_fd[1], msg_reply, sizeof(msg_reply)) == sizeof(msg_reply)); + break; + + case 1: + test_client_verify_solicit(packet, len); + assert_se(write(test_fd[1], msg_advertise, sizeof(msg_advertise)) == sizeof(msg_advertise)); + break; + + case 2: + test_client_callback(client_ref, DHCP6_CLIENT_EVENT_TEST_ADVERTISED, NULL); + test_client_verify_request(packet, len); + assert_se(write(test_fd[1], msg_reply, sizeof(msg_reply)) == sizeof(msg_reply)); + break; + + default: + assert_not_reached(); } + test_client_sent_message_count++; return len; } -int dhcp6_network_bind_udp_socket(int ifindex, struct in6_addr *local_address) { +int dhcp6_network_bind_udp_socket(int ifindex, struct in6_addr *a) { assert_se(ifindex == test_ifindex); + assert_se(a); + assert_se(in6_addr_equal(a, &local_address)); - if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_dhcp_fd) < 0) - return -errno; - - return test_dhcp_fd[0]; + assert_se(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) >= 0); + return TAKE_FD(test_fd[0]); } -static void test_client_solicit(sd_event *e) { - sd_dhcp6_client *client; - struct in6_addr address = { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } }; - int val; +static void test_dhcp6_client(void) { + _cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL; + _cleanup_(sd_event_unrefp) sd_event *e = NULL; log_debug("/* %s */", __func__); - assert_se(sd_dhcp6_client_new(&client) >= 0); - assert_se(client); + assert_se(sd_event_new(&e) >= 0); + assert_se(sd_event_add_time_relative(e, NULL, clock_boottime_or_monotonic(), + 2 * USEC_PER_SEC, 0, + NULL, INT_TO_PTR(ETIMEDOUT)) >= 0); + assert_se(sd_dhcp6_client_new(&client) >= 0); assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0); - assert_se(sd_dhcp6_client_set_ifindex(client, test_ifindex) == 0); - assert_se(sd_dhcp6_client_set_mac(client, (const uint8_t *) &mac_addr, - sizeof (mac_addr), - ARPHRD_ETHER) >= 0); - assert_se(sd_dhcp6_client_set_fqdn(client, "host.lab.intra") == 1); + assert_se(sd_dhcp6_client_set_local_address(client, &local_address) >= 0); + assert_se(sd_dhcp6_client_set_fqdn(client, "host.lab.intra") >= 0); + assert_se(sd_dhcp6_client_set_iaid(client, unaligned_read_be32((uint8_t[]) { IA_ID_BYTES })) >= 0); dhcp6_client_set_test_mode(client, true); - assert_se(sd_dhcp6_client_get_information_request(client, &val) >= 0); - assert_se(val == 0); - assert_se(sd_dhcp6_client_set_information_request(client, 42) >= 0); - assert_se(sd_dhcp6_client_get_information_request(client, &val) >= 0); - assert_se(val); - - assert_se(sd_dhcp6_client_set_callback(client, - test_client_information_cb, e) >= 0); - - assert_se(sd_event_add_time_relative(e, &hangcheck, clock_boottime_or_monotonic(), - 2 * USEC_PER_SEC, 0, - test_check_completed_in_2_seconds, NULL) >= 0); - - assert_se(sd_dhcp6_client_set_local_address(client, &address) >= 0); + assert_se(sd_dhcp6_client_set_information_request(client, true) >= 0); + assert_se(sd_dhcp6_client_set_callback(client, test_client_callback, NULL) >= 0); assert_se(sd_dhcp6_client_start(client) >= 0); - sd_event_loop(e); + assert_se(dhcp6_client_set_transaction_id(client, ((const DHCP6Message*) msg_reply)->transaction_id) >= 0); + + assert_se(client_ref = sd_dhcp6_client_ref(client)); - hangcheck = sd_event_source_unref(hangcheck); + assert_se(sd_event_loop(e) >= 0); - assert_se(!sd_dhcp6_client_unref(client)); + assert_se(test_client_sent_message_count == 3); - test_dhcp_fd[1] = safe_close(test_dhcp_fd[1]); + test_fd[1] = safe_close(test_fd[1]); } int main(int argc, char *argv[]) { - _cleanup_(sd_event_unrefp) sd_event *e; - - assert_se(sd_event_new(&e) >= 0); - test_setup_logging(LOG_DEBUG); - test_client_basic(e); + test_client_basic(); test_parse_domain(); test_option(); test_option_status(); test_client_parse_message_issue_22099(); - test_advertise_option(e); - test_client_solicit(e); + test_dhcp6_client(); return 0; }