summaryrefslogtreecommitdiff
path: root/src/libsystemd-network/sd-dhcp-lease.c
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2021-12-05 02:40:18 +0900
committerYu Watanabe <watanabe.yu+github@gmail.com>2021-12-07 20:32:02 +0900
commitdbdcaca3abbab0763f367f4e1a805323e4553b3a (patch)
treef17a92d77d2e508b7b90303d0c800b5f02b0a317 /src/libsystemd-network/sd-dhcp-lease.c
parent63dc602570218acf7b56923cf4733baf3e16909d (diff)
downloadsystemd-dbdcaca3abbab0763f367f4e1a805323e4553b3a.tar.gz
sd-dhcp-client: support 6rd option
Diffstat (limited to 'src/libsystemd-network/sd-dhcp-lease.c')
-rw-r--r--src/libsystemd-network/sd-dhcp-lease.c89
1 files changed, 89 insertions, 0 deletions
diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c
index dd82163d9f..7f6d15cb09 100644
--- a/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/libsystemd-network/sd-dhcp-lease.c
@@ -251,6 +251,33 @@ int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains) {
return -ENODATA;
}
+int sd_dhcp_lease_get_6rd(
+ sd_dhcp_lease *lease,
+ uint8_t *ret_ipv4masklen,
+ uint8_t *ret_prefixlen,
+ struct in6_addr *ret_prefix,
+ const struct in_addr **ret_br_addresses,
+ size_t *ret_n_br_addresses) {
+
+ assert_return(lease, -EINVAL);
+
+ if (lease->sixrd_n_br_addresses <= 0)
+ return -ENODATA;
+
+ if (ret_ipv4masklen)
+ *ret_ipv4masklen = lease->sixrd_ipv4masklen;
+ if (ret_prefixlen)
+ *ret_prefixlen = lease->sixrd_prefixlen;
+ if (ret_prefix)
+ *ret_prefix = lease->sixrd_prefix;
+ if (ret_br_addresses)
+ *ret_br_addresses = lease->sixrd_br_addresses;
+ if (ret_n_br_addresses)
+ *ret_n_br_addresses = lease->sixrd_n_br_addresses;
+
+ return 0;
+}
+
int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, size_t *data_len) {
assert_return(lease, -EINVAL);
assert_return(data, -EINVAL);
@@ -289,6 +316,7 @@ static sd_dhcp_lease *dhcp_lease_free(sd_dhcp_lease *lease) {
free(lease->client_id);
free(lease->vendor_specific);
strv_free(lease->search_domains);
+ free(lease->sixrd_br_addresses);
return mfree(lease);
}
@@ -534,6 +562,61 @@ static int lease_parse_classless_routes(
return 0;
}
+static int lease_parse_6rd(sd_dhcp_lease *lease, const uint8_t *option, size_t len) {
+ uint8_t ipv4masklen, prefixlen;
+ struct in6_addr prefix;
+ _cleanup_free_ struct in_addr *br_addresses = NULL;
+ size_t n_br_addresses;
+
+ assert(lease);
+ assert(option);
+
+ /* See RFC 5969 Section 7.1.1 */
+
+ if (lease->sixrd_n_br_addresses > 0)
+ /* Multiple 6rd option?? */
+ return -EINVAL;
+
+ /* option-length: The length of the DHCP option in octets (22 octets with one BR IPv4 address). */
+ if (len < 2 + sizeof(struct in6_addr) + sizeof(struct in_addr) ||
+ (len - 2 - sizeof(struct in6_addr)) % sizeof(struct in_addr) != 0)
+ return -EINVAL;
+
+ /* IPv4MaskLen: The number of high-order bits that are identical across all CE IPv4 addresses
+ * within a given 6rd domain. This may be any value between 0 and 32. Any value
+ * greater than 32 is invalid. */
+ ipv4masklen = option[0];
+ if (ipv4masklen > 32)
+ return -EINVAL;
+
+ /* 6rdPrefixLen: The IPv6 prefix length of the SP's 6rd IPv6 prefix in number of bits. For the
+ * purpose of bounds checking by DHCP option processing, the sum of
+ * (32 - IPv4MaskLen) + 6rdPrefixLen MUST be less than or equal to 128. */
+ prefixlen = option[1];
+ if (32 - ipv4masklen + prefixlen > 128)
+ return -EINVAL;
+
+ /* 6rdPrefix: The service provider's 6rd IPv6 prefix represented as a 16-octet IPv6 address.
+ * The bits in the prefix after the 6rdPrefixlen number of bits are reserved and
+ * MUST be initialized to zero by the sender and ignored by the receiver. */
+ memcpy(&prefix, option + 2, sizeof(struct in6_addr));
+ (void) in6_addr_mask(&prefix, prefixlen);
+
+ /* 6rdBRIPv4Address: One or more IPv4 addresses of the 6rd Border Relay(s) for a given 6rd domain. */
+ n_br_addresses = (len - 2 - sizeof(struct in6_addr)) / sizeof(struct in_addr);
+ br_addresses = newdup(struct in_addr, option + 2 + sizeof(struct in6_addr), n_br_addresses);
+ if (!br_addresses)
+ return -ENOMEM;
+
+ lease->sixrd_ipv4masklen = ipv4masklen;
+ lease->sixrd_prefixlen = prefixlen;
+ lease->sixrd_prefix = prefix;
+ lease->sixrd_br_addresses = TAKE_PTR(br_addresses);
+ lease->sixrd_n_br_addresses = n_br_addresses;
+
+ return 0;
+}
+
int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void *userdata) {
sd_dhcp_lease *lease = userdata;
int r;
@@ -719,6 +802,12 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void
lease->vendor_specific_len = len;
break;
+ case SD_DHCP_OPTION_6RD:
+ r = lease_parse_6rd(lease, option, len);
+ if (r < 0)
+ log_debug_errno(r, "Failed to parse 6rd option, ignoring: %m");
+ break;
+
case SD_DHCP_OPTION_PRIVATE_BASE ... SD_DHCP_OPTION_PRIVATE_LAST:
r = dhcp_lease_insert_private_option(lease, code, option, len);
if (r < 0)