Refactor relay_reply6().

Traverse the nested data structures more efficiently,
more understandably, and with watertight checking of
buffer boundaries.
This commit is contained in:
Simon Kelley
2025-07-06 17:28:15 +01:00
parent c9342cb556
commit f74b74e521

View File

@@ -2276,10 +2276,10 @@ int relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface)
{
void *opt, *opts = inbuff + 34;
void *end = inbuff + sz;
for (opt = opts; opt; opt = opt6_next(opt, end))
if (opt6_type(opt) == OPTION6_RELAY_MSG && opt6_len(opt) > 0)
if ((opt = opt6_find(opts, end, OPTION6_RELAY_MSG, 4)))
{
int encap_type = *((unsigned char *)opt6_ptr(opt, 0));
int encap_type = opt6_uint(opt, 0, 1);
put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
memcpy(&peer->sin6_addr, &inbuff[18], IN6ADDRSZ);
peer->sin6_scope_id = relay->iface_index;
@@ -2295,20 +2295,18 @@ int relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface)
#ifdef HAVE_SCRIPT
if (daemon->lease_change_command && encap_type == DHCP6REPLY)
{
/* decapsulate relayed message */
/* skip over message type and transaction-id. to get to options. */
opts = opt6_ptr(opt, 4);
end = opt6_ptr(opt, opt6_len(opt));
for (opt = opts; opt; opt = opt6_next(opt, end))
if (opt6_type(opt) == OPTION6_IA_PD && opt6_len(opt) > 12)
if ((opt = opt6_find(opts, end, OPTION6_IA_PD, 12)))
{
void *ia_opts = opt6_ptr(opt, 12);
void *ia_end = opt6_ptr(opt, opt6_len(opt));
void *ia_opt;
opts = opt6_ptr(opt, 12);
end = opt6_ptr(opt, opt6_len(opt));
for (ia_opt = ia_opts; ia_opt; ia_opt = opt6_next(ia_opt, ia_end))
for (opt = opt6_find(opts, end, OPTION6_IAPREFIX, 25); opt; opt = opt6_find(opt6_next(opt, end), end, OPTION6_IAPREFIX, 25))
/* valid lifetime must not be zero. */
if (opt6_type(ia_opt) == OPTION6_IAPREFIX && opt6_len(ia_opt) >= 25 && opt6_uint(ia_opt, 4, 4) != 0)
if (opt6_uint(opt, 4, 4) != 0)
{
if (daemon->free_snoops ||
(daemon->free_snoops = whine_malloc(sizeof(struct snoop_record))))
@@ -2317,8 +2315,8 @@ int relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface)
daemon->free_snoops = snoop->next;
snoop->client = peer->sin6_addr;
snoop->prefix_len = opt6_uint(ia_opt, 8, 1);
memcpy(&snoop->prefix, opt6_ptr(ia_opt, 9), IN6ADDRSZ);
snoop->prefix_len = opt6_uint(opt, 8, 1);
memcpy(&snoop->prefix, opt6_ptr(opt, 9), IN6ADDRSZ);
snoop->next = relay->snoop_records;
relay->snoop_records = snoop;
}
@@ -2328,7 +2326,6 @@ int relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface)
#endif
return 1;
}
}
return 0;