diff --git a/cmdmon.c b/cmdmon.c index 37dc944..2fdb867 100644 --- a/cmdmon.c +++ b/cmdmon.c @@ -301,8 +301,10 @@ transmit_reply(int sock_fd, SCK_Message *message) { message->length = PKL_ReplyLength((CMD_Reply *)message->data); - /* Don't require the response to use the same interface */ - message->if_index = INVALID_IF_INDEX; + /* Don't require responses to non-link-local addresses to use the same + interface */ + if (!SCK_IsLinkLocalIPAddress(&message->remote_addr.ip.ip_addr)) + message->if_index = INVALID_IF_INDEX; if (!SCK_SendMessage(sock_fd, message, 0)) return; diff --git a/ntp_io.c b/ntp_io.c index 58b2224..4bf3457 100644 --- a/ntp_io.c +++ b/ntp_io.c @@ -454,8 +454,10 @@ NIO_SendPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, message.local_addr.ip = local_addr->ip_addr; - /* Don't require the response to use the same interface */ - message.if_index = INVALID_IF_INDEX; + /* Don't require responses to non-link-local addresses to use the same + interface */ + message.if_index = SCK_IsLinkLocalIPAddress(&message.remote_addr.ip.ip_addr) ? + local_addr->if_index : INVALID_IF_INDEX; #if !defined(HAVE_IN_PKTINFO) && defined(IP_SENDSRCADDR) /* On FreeBSD a local IPv4 address cannot be specified on bound socket */ diff --git a/socket.c b/socket.c index dbcf624..99b43f5 100644 --- a/socket.c +++ b/socket.c @@ -1228,6 +1228,23 @@ SCK_GetLoopbackIPAddress(int family, IPAddr *local_addr) /* ================================================== */ +int +SCK_IsLinkLocalIPAddress(IPAddr *addr) +{ + switch (addr->family) { + case IPADDR_INET4: + /* 169.254.0.0/16 */ + return (addr->addr.in4 & 0xffff0000) == 0xa9fe0000; + case IPADDR_INET6: + /* fe80::/10 */ + return addr->addr.in6[0] == 0xfe && (addr->addr.in6[1] & 0xc0) == 0x80; + default: + return 0; + } +} + +/* ================================================== */ + void SCK_SetPrivBind(int (*function)(int sock_fd, struct sockaddr *address, socklen_t address_len)) diff --git a/socket.h b/socket.h index 9207a43..7d3fa9d 100644 --- a/socket.h +++ b/socket.h @@ -87,6 +87,9 @@ extern int SCK_IsIpFamilyEnabled(int family); extern void SCK_GetAnyLocalIPAddress(int family, IPAddr *local_addr); extern void SCK_GetLoopbackIPAddress(int family, IPAddr *local_addr); +/* Check if an IP address is a link-local address */ +extern int SCK_IsLinkLocalIPAddress(IPAddr *addr); + /* Specify a bind()-like function for binding sockets to privileged ports when running in a restricted process (e.g. after dropping root privileges) */ extern void SCK_SetPrivBind(int (*function)(int sock_fd, struct sockaddr *address,