dhcp-message: add SIP server option support
The DHCP option 120 (SIP server) option takes a list of addresses or domain names, and the first byte in the data classifies which type is stored. Let's extend _addresses() and _domains() to make them support the SIP server option.
This commit is contained in:
@@ -191,6 +191,24 @@ int dhcp_message_append_option_addresses(sd_dhcp_message *message, uint8_t code,
|
||||
if (size_multiply_overflow(sizeof(struct in_addr), n_addr))
|
||||
return -ENOBUFS;
|
||||
|
||||
if (code == SD_DHCP_OPTION_SIP_SERVER) {
|
||||
if (dhcp_message_has_option(message, SD_DHCP_OPTION_SIP_SERVER))
|
||||
return -EEXIST;
|
||||
|
||||
size_t len = size_add(1, sizeof(struct in_addr) * n_addr);
|
||||
if (len == SIZE_MAX)
|
||||
return -ENOBUFS;
|
||||
|
||||
_cleanup_free_ uint8_t *buf = new(uint8_t, len);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
buf[0] = 1; /* 'enc' field, 0: domains, 1: addresses */
|
||||
memcpy(buf + 1, addr, sizeof(struct in_addr) * n_addr);
|
||||
|
||||
return dhcp_message_append_option(message, code, len, buf);
|
||||
}
|
||||
|
||||
return dhcp_message_append_option(message, code, sizeof(struct in_addr) * n_addr, addr);
|
||||
}
|
||||
|
||||
@@ -423,11 +441,22 @@ int dhcp_message_get_option_addresses(sd_dhcp_message *message, uint8_t code, si
|
||||
assert(message);
|
||||
assert(ret_n_addr || !ret_addr);
|
||||
|
||||
_cleanup_(iovec_done) struct iovec iov = {};
|
||||
r = dhcp_message_get_option_alloc(message, code, &iov);
|
||||
_cleanup_(iovec_done) struct iovec iov_free = {};
|
||||
r = dhcp_message_get_option_alloc(message, code, &iov_free);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
struct iovec iov = iov_free;
|
||||
if (code == SD_DHCP_OPTION_SIP_SERVER) {
|
||||
if (!iovec_is_set(&iov))
|
||||
return -EBADMSG;
|
||||
|
||||
if (*(uint8_t*) iov.iov_base != 1) /* 'enc' field, 0: domains, 1: addresses */
|
||||
return -ENODATA;
|
||||
|
||||
iovec_inc(&iov, 1);
|
||||
}
|
||||
|
||||
if (iov.iov_len % sizeof(struct in_addr) != 0)
|
||||
return -EBADMSG;
|
||||
|
||||
@@ -435,8 +464,17 @@ int dhcp_message_get_option_addresses(sd_dhcp_message *message, uint8_t code, si
|
||||
if (n == 0)
|
||||
return -ENODATA;
|
||||
|
||||
if (ret_addr)
|
||||
*ret_addr = (struct in_addr*) TAKE_PTR(iov.iov_base);
|
||||
if (ret_addr) {
|
||||
if (code == SD_DHCP_OPTION_SIP_SERVER) {
|
||||
struct in_addr *addr = newdup(struct in_addr, iov.iov_base, n);
|
||||
if (!addr)
|
||||
return -ENOMEM;
|
||||
*ret_addr = addr;
|
||||
} else {
|
||||
*ret_addr = iov.iov_base;
|
||||
TAKE_STRUCT(iov_free);
|
||||
}
|
||||
}
|
||||
if (ret_n_addr)
|
||||
*ret_n_addr = n;
|
||||
return 0;
|
||||
@@ -625,7 +663,7 @@ int dhcp_message_get_option_domains(sd_dhcp_message *message, uint8_t code, char
|
||||
|
||||
assert(message);
|
||||
|
||||
/* This is mostly for SD_DHCP_OPTION_DOMAIN_SEARCH. */
|
||||
/* This is mostly for SD_DHCP_OPTION_DOMAIN_SEARCH and SD_DHCP_OPTION_SIP_SERVER. */
|
||||
|
||||
_cleanup_(iovec_done) struct iovec iov = {};
|
||||
r = dhcp_message_get_option_alloc(message, code, &iov);
|
||||
@@ -635,6 +673,17 @@ int dhcp_message_get_option_domains(sd_dhcp_message *message, uint8_t code, char
|
||||
const uint8_t *buf = iov.iov_base;
|
||||
size_t len = iov.iov_len;
|
||||
|
||||
if (code == SD_DHCP_OPTION_SIP_SERVER) {
|
||||
if (len == 0)
|
||||
return -EBADMSG;
|
||||
|
||||
if (buf[0] != 0) /* 'enc' field, 0: domains, 1: addresses */
|
||||
return -ENODATA;
|
||||
|
||||
len--;
|
||||
buf++;
|
||||
}
|
||||
|
||||
_cleanup_strv_free_ char **names = NULL;
|
||||
size_t n_names = 0;
|
||||
|
||||
|
||||
@@ -68,7 +68,8 @@ static void verify_address(sd_dhcp_message *m, const struct in_addr *expected) {
|
||||
|
||||
static void verify_addresses(
|
||||
sd_dhcp_message *m,
|
||||
size_t n_ntp, const struct in_addr *ntp) {
|
||||
size_t n_ntp, const struct in_addr *ntp,
|
||||
size_t n_sip, const struct in_addr *sip) {
|
||||
|
||||
struct in_addr a;
|
||||
ASSERT_OK(dhcp_message_get_option_be32(m, SD_DHCP_OPTION_NTP_SERVER, &a.s_addr));
|
||||
@@ -81,6 +82,14 @@ static void verify_addresses(
|
||||
ASSERT_OK(dhcp_message_get_option_addresses(m, SD_DHCP_OPTION_NTP_SERVER, &n, &addrs));
|
||||
ASSERT_EQ(n, n_ntp);
|
||||
ASSERT_EQ(memcmp(addrs, ntp, sizeof(struct in_addr) * n), 0);
|
||||
|
||||
ASSERT_ERROR(dhcp_message_get_option_be32(m, SD_DHCP_OPTION_SIP_SERVER, NULL), ENODATA);
|
||||
ASSERT_ERROR(dhcp_message_get_option_address(m, SD_DHCP_OPTION_SIP_SERVER, NULL), ENODATA);
|
||||
|
||||
addrs = mfree(addrs);
|
||||
ASSERT_OK(dhcp_message_get_option_addresses(m, SD_DHCP_OPTION_SIP_SERVER, &n, &addrs));
|
||||
ASSERT_EQ(n, n_sip);
|
||||
ASSERT_EQ(memcmp(addrs, sip, sizeof(struct in_addr) * n), 0);
|
||||
}
|
||||
|
||||
static void verify_string(sd_dhcp_message *m, const char *expected) {
|
||||
@@ -160,6 +169,14 @@ TEST(dhcp_message) {
|
||||
{ .s_addr = htobe32(0xC0000204) },
|
||||
};
|
||||
|
||||
/* 192.0.2.17 - 20 */
|
||||
struct in_addr sip[4] = {
|
||||
{ .s_addr = htobe32(0xC0000211) },
|
||||
{ .s_addr = htobe32(0xC0000212) },
|
||||
{ .s_addr = htobe32(0xC0000213) },
|
||||
{ .s_addr = htobe32(0xC0000214) },
|
||||
};
|
||||
|
||||
sd_dhcp_client_id id = {
|
||||
.raw = { 1, 3, 3, 3, 3, 3, 3, },
|
||||
.size = 7,
|
||||
@@ -242,7 +259,10 @@ TEST(dhcp_message) {
|
||||
/* multiple addresses */
|
||||
ASSERT_OK(dhcp_message_append_option_address(m, SD_DHCP_OPTION_NTP_SERVER, &ntp[0]));
|
||||
ASSERT_OK(dhcp_message_append_option_addresses(m, SD_DHCP_OPTION_NTP_SERVER, ELEMENTSOF(ntp) - 1, ntp + 1));
|
||||
verify_addresses(m, ELEMENTSOF(ntp), ntp);
|
||||
ASSERT_OK(dhcp_message_append_option_addresses(m, SD_DHCP_OPTION_SIP_SERVER, ELEMENTSOF(sip), sip));
|
||||
ASSERT_ERROR(dhcp_message_append_option_addresses(m, SD_DHCP_OPTION_SIP_SERVER, ELEMENTSOF(sip), sip), EEXIST);
|
||||
ASSERT_OK(dhcp_message_append_option_addresses(m, SD_DHCP_OPTION_SIP_SERVER, 0, NULL));
|
||||
verify_addresses(m, ELEMENTSOF(ntp), ntp, ELEMENTSOF(sip), sip);
|
||||
|
||||
/* string */
|
||||
ASSERT_ERROR(dhcp_message_get_option_string(m, SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER, NULL), ENODATA);
|
||||
@@ -316,7 +336,7 @@ TEST(dhcp_message) {
|
||||
verify_u16(m2, 512);
|
||||
verify_sec(m2, lease_time);
|
||||
verify_address(m2, &addr);
|
||||
verify_addresses(m2, ELEMENTSOF(ntp), ntp);
|
||||
verify_addresses(m2, ELEMENTSOF(ntp), ntp, ELEMENTSOF(sip), sip);
|
||||
verify_string(m2, vendor_class);
|
||||
verify_client_id(m2, &id);
|
||||
verify_prl(m2, prl);
|
||||
@@ -346,6 +366,24 @@ static void test_domains_one(size_t len, const uint8_t *data, char * const *expe
|
||||
ASSERT_OK(dhcp_message_append_option(m, SD_DHCP_OPTION_DOMAIN_SEARCH, len - len / 2, data + len / 2));
|
||||
ASSERT_OK(dhcp_message_get_option_domains(m, SD_DHCP_OPTION_DOMAIN_SEARCH, &strv));
|
||||
ASSERT_TRUE(strv_equal(strv, expected));
|
||||
|
||||
strv = strv_free(strv);
|
||||
|
||||
_cleanup_free_ uint8_t *sip = new(uint8_t, len + 1);
|
||||
sip[0] = 0;
|
||||
memcpy(sip + 1, data, len);
|
||||
|
||||
ASSERT_OK(dhcp_message_append_option(m, SD_DHCP_OPTION_SIP_SERVER, len + 1, sip));
|
||||
ASSERT_OK(dhcp_message_get_option_domains(m, SD_DHCP_OPTION_SIP_SERVER, &strv));
|
||||
ASSERT_TRUE(strv_equal(strv, expected));
|
||||
|
||||
dhcp_message_remove_option(m, SD_DHCP_OPTION_SIP_SERVER);
|
||||
strv = strv_free(strv);
|
||||
|
||||
ASSERT_OK(dhcp_message_append_option(m, SD_DHCP_OPTION_SIP_SERVER, (len + 1) / 2, sip));
|
||||
ASSERT_OK(dhcp_message_append_option(m, SD_DHCP_OPTION_SIP_SERVER, len + 1 - (len + 1) / 2, sip + (len + 1) / 2));
|
||||
ASSERT_OK(dhcp_message_get_option_domains(m, SD_DHCP_OPTION_SIP_SERVER, &strv));
|
||||
ASSERT_TRUE(strv_equal(strv, expected));
|
||||
}
|
||||
|
||||
static void test_domains_fail(size_t len, const uint8_t *data) {
|
||||
|
||||
Reference in New Issue
Block a user