After commit
e49aececceaa ("socket: don't set interface for sent
packets") the NTP and cmdmon server stopped responding to requests from
link-local addresses.
Set the interface specifically for packets sent to a link-local address.
{
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;
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 */
/* ================================================== */
+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))
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,