@@ -251,6 +251,33 @@ int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains) {
251251 return - ENODATA ;
252252}
253253
254+ int sd_dhcp_lease_get_6rd (
255+ sd_dhcp_lease * lease ,
256+ uint8_t * ret_ipv4masklen ,
257+ uint8_t * ret_prefixlen ,
258+ struct in6_addr * ret_prefix ,
259+ const struct in_addr * * ret_br_addresses ,
260+ size_t * ret_n_br_addresses ) {
261+
262+ assert_return (lease , - EINVAL );
263+
264+ if (lease -> sixrd_n_br_addresses <= 0 )
265+ return - ENODATA ;
266+
267+ if (ret_ipv4masklen )
268+ * ret_ipv4masklen = lease -> sixrd_ipv4masklen ;
269+ if (ret_prefixlen )
270+ * ret_prefixlen = lease -> sixrd_prefixlen ;
271+ if (ret_prefix )
272+ * ret_prefix = lease -> sixrd_prefix ;
273+ if (ret_br_addresses )
274+ * ret_br_addresses = lease -> sixrd_br_addresses ;
275+ if (ret_n_br_addresses )
276+ * ret_n_br_addresses = lease -> sixrd_n_br_addresses ;
277+
278+ return 0 ;
279+ }
280+
254281int sd_dhcp_lease_get_vendor_specific (sd_dhcp_lease * lease , const void * * data , size_t * data_len ) {
255282 assert_return (lease , - EINVAL );
256283 assert_return (data , - EINVAL );
@@ -289,6 +316,7 @@ static sd_dhcp_lease *dhcp_lease_free(sd_dhcp_lease *lease) {
289316 free (lease -> client_id );
290317 free (lease -> vendor_specific );
291318 strv_free (lease -> search_domains );
319+ free (lease -> sixrd_br_addresses );
292320 return mfree (lease );
293321}
294322
@@ -534,6 +562,61 @@ static int lease_parse_classless_routes(
534562 return 0 ;
535563}
536564
565+ static int lease_parse_6rd (sd_dhcp_lease * lease , const uint8_t * option , size_t len ) {
566+ uint8_t ipv4masklen , prefixlen ;
567+ struct in6_addr prefix ;
568+ _cleanup_free_ struct in_addr * br_addresses = NULL ;
569+ size_t n_br_addresses ;
570+
571+ assert (lease );
572+ assert (option );
573+
574+ /* See RFC 5969 Section 7.1.1 */
575+
576+ if (lease -> sixrd_n_br_addresses > 0 )
577+ /* Multiple 6rd option?? */
578+ return - EINVAL ;
579+
580+ /* option-length: The length of the DHCP option in octets (22 octets with one BR IPv4 address). */
581+ if (len < 2 + sizeof (struct in6_addr ) + sizeof (struct in_addr ) ||
582+ (len - 2 - sizeof (struct in6_addr )) % sizeof (struct in_addr ) != 0 )
583+ return - EINVAL ;
584+
585+ /* IPv4MaskLen: The number of high-order bits that are identical across all CE IPv4 addresses
586+ * within a given 6rd domain. This may be any value between 0 and 32. Any value
587+ * greater than 32 is invalid. */
588+ ipv4masklen = option [0 ];
589+ if (ipv4masklen > 32 )
590+ return - EINVAL ;
591+
592+ /* 6rdPrefixLen: The IPv6 prefix length of the SP's 6rd IPv6 prefix in number of bits. For the
593+ * purpose of bounds checking by DHCP option processing, the sum of
594+ * (32 - IPv4MaskLen) + 6rdPrefixLen MUST be less than or equal to 128. */
595+ prefixlen = option [1 ];
596+ if (32 - ipv4masklen + prefixlen > 128 )
597+ return - EINVAL ;
598+
599+ /* 6rdPrefix: The service provider's 6rd IPv6 prefix represented as a 16-octet IPv6 address.
600+ * The bits in the prefix after the 6rdPrefixlen number of bits are reserved and
601+ * MUST be initialized to zero by the sender and ignored by the receiver. */
602+ memcpy (& prefix , option + 2 , sizeof (struct in6_addr ));
603+ (void ) in6_addr_mask (& prefix , prefixlen );
604+
605+ /* 6rdBRIPv4Address: One or more IPv4 addresses of the 6rd Border Relay(s) for a given 6rd domain. */
606+ n_br_addresses = (len - 2 - sizeof (struct in6_addr )) / sizeof (struct in_addr );
607+ br_addresses = newdup (struct in_addr , option + 2 + sizeof (struct in6_addr ), n_br_addresses );
608+ if (!br_addresses )
609+ return - ENOMEM ;
610+
611+ lease -> sixrd_ipv4masklen = ipv4masklen ;
612+ lease -> sixrd_prefixlen = prefixlen ;
613+ lease -> sixrd_prefix = prefix ;
614+ lease -> sixrd_br_addresses = TAKE_PTR (br_addresses );
615+ lease -> sixrd_n_br_addresses = n_br_addresses ;
616+
617+ return 0 ;
618+ }
619+
537620int dhcp_lease_parse_options (uint8_t code , uint8_t len , const void * option , void * userdata ) {
538621 sd_dhcp_lease * lease = userdata ;
539622 int r ;
@@ -719,6 +802,12 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void
719802 lease -> vendor_specific_len = len ;
720803 break ;
721804
805+ case SD_DHCP_OPTION_6RD :
806+ r = lease_parse_6rd (lease , option , len );
807+ if (r < 0 )
808+ log_debug_errno (r , "Failed to parse 6rd option, ignoring: %m" );
809+ break ;
810+
722811 case SD_DHCP_OPTION_PRIVATE_BASE ... SD_DHCP_OPTION_PRIVATE_LAST :
723812 r = dhcp_lease_insert_private_option (lease , code , option , len );
724813 if (r < 0 )
0 commit comments