From 18a6bdd5414131699090d978b104e7f56ca0562a Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Fri, 20 Dec 2019 18:19:20 +0000 Subject: [PATCH] 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(). --- src/dhcp6.c | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) 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 @@ void dhcp6_packet(time_t now) 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 @@ void dhcp6_packet(time_t now) 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)