Commit 65c72120 authored by Lung-Pin Chang's avatar Lung-Pin Chang Committed by Simon Kelley

dhcp: set outbound interface via cmsg in unicast reply

  If multiple routes to the same network exist, Linux blindly picks
  the first interface (route) based on destination address, which might not be
  the one we're actually offering leases. Rather than relying on this,
  always set the interface for outgoing unicast DHCP packets.
parent 979fe86b
...@@ -376,10 +376,9 @@ void dhcp_packet(time_t now, int pxe_fd) ...@@ -376,10 +376,9 @@ void dhcp_packet(time_t now, int pxe_fd)
} }
} }
#if defined(HAVE_LINUX_NETWORK) #if defined(HAVE_LINUX_NETWORK)
else if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 || else
mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0)
{ {
/* broadcast to 255.255.255.255 (or mac address invalid) */ /* fill cmsg for outbound interface (both broadcast & unicast) */
struct in_pktinfo *pkt; struct in_pktinfo *pkt;
msg.msg_control = control_u.control; msg.msg_control = control_u.control;
msg.msg_controllen = sizeof(control_u); msg.msg_controllen = sizeof(control_u);
...@@ -389,23 +388,29 @@ void dhcp_packet(time_t now, int pxe_fd) ...@@ -389,23 +388,29 @@ void dhcp_packet(time_t now, int pxe_fd)
pkt->ipi_spec_dst.s_addr = 0; pkt->ipi_spec_dst.s_addr = 0;
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
cmptr->cmsg_level = IPPROTO_IP; cmptr->cmsg_level = IPPROTO_IP;
cmptr->cmsg_type = IP_PKTINFO; cmptr->cmsg_type = IP_PKTINFO;
dest.sin_addr.s_addr = INADDR_BROADCAST;
dest.sin_port = htons(daemon->dhcp_client_port); if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 ||
} mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0)
else {
{ /* broadcast to 255.255.255.255 (or mac address invalid) */
/* unicast to unconfigured client. Inject mac address direct into ARP cache. dest.sin_addr.s_addr = INADDR_BROADCAST;
struct sockaddr limits size to 14 bytes. */ dest.sin_port = htons(daemon->dhcp_client_port);
dest.sin_addr = mess->yiaddr; }
dest.sin_port = htons(daemon->dhcp_client_port); else
memcpy(&arp_req.arp_pa, &dest, sizeof(struct sockaddr_in)); {
arp_req.arp_ha.sa_family = mess->htype; /* unicast to unconfigured client. Inject mac address direct into ARP cache.
memcpy(arp_req.arp_ha.sa_data, mess->chaddr, mess->hlen); struct sockaddr limits size to 14 bytes. */
/* interface name already copied in */ dest.sin_addr = mess->yiaddr;
arp_req.arp_flags = ATF_COM; dest.sin_port = htons(daemon->dhcp_client_port);
if (ioctl(daemon->dhcpfd, SIOCSARP, &arp_req) == -1) memcpy(&arp_req.arp_pa, &dest, sizeof(struct sockaddr_in));
my_syslog(MS_DHCP | LOG_ERR, _("ARP-cache injection failed: %s"), strerror(errno)); arp_req.arp_ha.sa_family = mess->htype;
memcpy(arp_req.arp_ha.sa_data, mess->chaddr, mess->hlen);
/* interface name already copied in */
arp_req.arp_flags = ATF_COM;
if (ioctl(daemon->dhcpfd, SIOCSARP, &arp_req) == -1)
my_syslog(MS_DHCP | LOG_ERR, _("ARP-cache injection failed: %s"), strerror(errno));
}
} }
#elif defined(HAVE_SOLARIS_NETWORK) #elif defined(HAVE_SOLARIS_NETWORK)
else if ((ntohs(mess->flags) & 0x8000) || mess->hlen != ETHER_ADDR_LEN || mess->htype != ARPHRD_ETHER) else if ((ntohs(mess->flags) & 0x8000) || mess->hlen != ETHER_ADDR_LEN || mess->htype != ARPHRD_ETHER)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment