1 From 65c721200023ef0023114459a8d12f8b0a24cfd8 Mon Sep 17 00:00:00 2001
2 From: Lung-Pin Chang <changlp@cs.nctu.edu.tw>
3 Date: Thu, 19 Mar 2015 23:22:21 +0000
4 Subject: [PATCH 60/71] dhcp: set outbound interface via cmsg in unicast reply
6 If multiple routes to the same network exist, Linux blindly picks
7 the first interface (route) based on destination address, which might not be
8 the one we're actually offering leases. Rather than relying on this,
9 always set the interface for outgoing unicast DHCP packets.
11 src/dhcp.c | 45 +++++++++++++++++++++++++--------------------
12 1 file changed, 25 insertions(+), 20 deletions(-)
14 diff --git a/src/dhcp.c b/src/dhcp.c
15 index 5c3089ab94ff..f1f43f8d8f90 100644
18 @@ -376,10 +376,9 @@ void dhcp_packet(time_t now, int pxe_fd)
21 #if defined(HAVE_LINUX_NETWORK)
22 - else if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 ||
23 - mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0)
26 - /* broadcast to 255.255.255.255 (or mac address invalid) */
27 + /* fill cmsg for outbound interface (both broadcast & unicast) */
28 struct in_pktinfo *pkt;
29 msg.msg_control = control_u.control;
30 msg.msg_controllen = sizeof(control_u);
31 @@ -389,23 +388,29 @@ void dhcp_packet(time_t now, int pxe_fd)
32 pkt->ipi_spec_dst.s_addr = 0;
33 msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
34 cmptr->cmsg_level = IPPROTO_IP;
35 - cmptr->cmsg_type = IP_PKTINFO;
36 - dest.sin_addr.s_addr = INADDR_BROADCAST;
37 - dest.sin_port = htons(daemon->dhcp_client_port);
41 - /* unicast to unconfigured client. Inject mac address direct into ARP cache.
42 - struct sockaddr limits size to 14 bytes. */
43 - dest.sin_addr = mess->yiaddr;
44 - dest.sin_port = htons(daemon->dhcp_client_port);
45 - memcpy(&arp_req.arp_pa, &dest, sizeof(struct sockaddr_in));
46 - arp_req.arp_ha.sa_family = mess->htype;
47 - memcpy(arp_req.arp_ha.sa_data, mess->chaddr, mess->hlen);
48 - /* interface name already copied in */
49 - arp_req.arp_flags = ATF_COM;
50 - if (ioctl(daemon->dhcpfd, SIOCSARP, &arp_req) == -1)
51 - my_syslog(MS_DHCP | LOG_ERR, _("ARP-cache injection failed: %s"), strerror(errno));
52 + cmptr->cmsg_type = IP_PKTINFO;
54 + if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 ||
55 + mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0)
57 + /* broadcast to 255.255.255.255 (or mac address invalid) */
58 + dest.sin_addr.s_addr = INADDR_BROADCAST;
59 + dest.sin_port = htons(daemon->dhcp_client_port);
63 + /* unicast to unconfigured client. Inject mac address direct into ARP cache.
64 + struct sockaddr limits size to 14 bytes. */
65 + dest.sin_addr = mess->yiaddr;
66 + dest.sin_port = htons(daemon->dhcp_client_port);
67 + memcpy(&arp_req.arp_pa, &dest, sizeof(struct sockaddr_in));
68 + arp_req.arp_ha.sa_family = mess->htype;
69 + memcpy(arp_req.arp_ha.sa_data, mess->chaddr, mess->hlen);
70 + /* interface name already copied in */
71 + arp_req.arp_flags = ATF_COM;
72 + if (ioctl(daemon->dhcpfd, SIOCSARP, &arp_req) == -1)
73 + my_syslog(MS_DHCP | LOG_ERR, _("ARP-cache injection failed: %s"), strerror(errno));
76 #elif defined(HAVE_SOLARIS_NETWORK)
77 else if ((ntohs(mess->flags) & 0x8000) || mess->hlen != ETHER_ADDR_LEN || mess->htype != ARPHRD_ETHER)