Avoid RA code trampling on DHCPv6 messages.
Calling lease_update_file() _can_ result in a call to periodic_ra()
Since both the DHCPv6 and RA subsystems use the same packet buffer
this can overwrite the DHCPv6 packet. To avoid this we ensure the
DHCPv6 packet has been sent before calling lease_update_file().
diff --git a/src/dhcp6.c b/src/dhcp6.c
index 5f4b839..d7b4e8b 100644
--- a/src/dhcp6.c
+++ b/src/dhcp6.c
@@ -135,7 +135,14 @@
if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name))
return;
- if ((port = relay_reply6(&from, sz, ifr.ifr_name)) == 0)
+ if ((port = relay_reply6(&from, sz, ifr.ifr_name)) != 0)
+ {
+ from.sin6_port = htons(port);
+ while (retry_send(sendto(daemon->dhcp6fd, daemon->outpacket.iov_base,
+ save_counter(-1), 0, (struct sockaddr *)&from,
+ sizeof(from))));
+ }
+ else
{
struct dhcp_bridge *bridge, *alias;
@@ -233,21 +240,23 @@
port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback,
&parm.ll_addr, &parm.ula_addr, sz, &from.sin6_addr, now);
+ /* The port in the source address of the original request should
+ be correct, but at least once client sends from the server port,
+ so we explicitly send to the client port to a client, and the
+ server port to a relay. */
+ if (port != 0)
+ {
+ from.sin6_port = htons(port);
+ while (retry_send(sendto(daemon->dhcp6fd, daemon->outpacket.iov_base,
+ save_counter(-1), 0, (struct sockaddr *)&from,
+ sizeof(from))));
+ }
+
+ /* These need to be called _after_ we send DHCPv6 packet, since lease_update_file()
+ may trigger sending an RA packet, which overwrites our buffer. */
lease_update_file(now);
lease_update_dns(0);
}
-
- /* The port in the source address of the original request should
- be correct, but at least once client sends from the server port,
- so we explicitly send to the client port to a client, and the
- server port to a relay. */
- if (port != 0)
- {
- from.sin6_port = htons(port);
- while (retry_send(sendto(daemon->dhcp6fd, daemon->outpacket.iov_base,
- save_counter(-1), 0, (struct sockaddr *)&from,
- sizeof(from))));
- }
}
void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsigned int *maclenp, unsigned int *mactypep, time_t now)