Bug 9146

Summary: ntpd uses wrong IP address in reply to query
Product: Busybox Reporter: Stijn Tintel <stijn+busybox>
Component: NetworkingAssignee: unassigned
Status: RESOLVED FIXED    
Severity: normal CC: busybox-cvs
Priority: P5    
Version: 1.24.x   
Target Milestone: ---   
Hardware: Other   
OS: Linux   
Host: Target:
Build:
Attachments: busybox config

Description Stijn Tintel 2016-08-08 08:19:00 UTC
Created attachment 6591 [details]
busybox config

When sending NTP queries to a secondary IP addresses of a device running busybox ntpd, the replies are sent from the primary IP address. This happens for both IPv4 and IPv6.

Interface addresses:
15: eth0.54@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 04:18:d6:31:38:b3 brd ff:ff:ff:ff:ff:ff
    inet 192.168.54.254/24 brd 192.168.54.255 scope global eth0.54
       valid_lft forever preferred_lft forever
    inet 192.168.54.1/24 brd 192.168.54.255 scope global secondary eth0.54
       valid_lft forever preferred_lft forever
    inet6 [hidden]/64 scope global noprefixroute
       valid_lft forever preferred_lft forever
    inet6 fe80::1/64 scope link nodad
       valid_lft forever preferred_lft forever
    inet6 fe80::618:d6ff:fe31:38b3/64 scope link
       valid_lft forever preferred_lft forever

IPv4 tcpdump:
11:15:22.468631 IP 192.168.54.121.123 > 192.168.54.1.123: NTPv4, Client, length 48
11:15:22.469272 IP 192.168.54.254.123 > 192.168.54.121.123: NTPv4, Server, length 48
11:15:24.468616 IP 192.168.54.121.123 > 192.168.54.1.123: NTPv4, Client, length 48
11:15:24.469014 IP 192.168.54.254.123 > 192.168.54.121.123: NTPv4, Server, length 48
11:15:26.468606 IP 192.168.54.121.123 > 192.168.54.1.123: NTPv4, Client, length 48
11:15:26.468999 IP 192.168.54.254.123 > 192.168.54.121.123: NTPv4, Server, length 48
11:15:28.468622 IP 192.168.54.121.123 > 192.168.54.1.123: NTPv4, Client, length 48
11:15:28.469010 IP 192.168.54.254.123 > 192.168.54.121.123: NTPv4, Server, length 48

Result on the client:
 8 Aug 11:15:30 ntpdate[13088]: no server suitable for synchronization found

IPv6 tcpdump:
11:17:48.020528 IP6 fe80::be5f:f4ff:fe67:1f9a.123 > fe80::618:d6ff:fe31:38b3.123: NTPv4, Client, length 48
11:17:48.021053 IP6 fe80::1.123 > fe80::be5f:f4ff:fe67:1f9a.123: NTPv4, Server, length 48
11:17:50.020552 IP6 fe80::be5f:f4ff:fe67:1f9a.123 > fe80::618:d6ff:fe31:38b3.123: NTPv4, Client, length 48
11:17:50.020989 IP6 fe80::1.123 > fe80::be5f:f4ff:fe67:1f9a.123: NTPv4, Server, length 48
11:17:52.020525 IP6 fe80::be5f:f4ff:fe67:1f9a.123 > fe80::618:d6ff:fe31:38b3.123: NTPv4, Client, length 48
11:17:52.020963 IP6 fe80::1.123 > fe80::be5f:f4ff:fe67:1f9a.123: NTPv4, Server, length 48
11:17:54.020563 IP6 fe80::be5f:f4ff:fe67:1f9a.123 > fe80::618:d6ff:fe31:38b3.123: NTPv4, Client, length 48
11:17:54.021004 IP6 fe80::1.123 > fe80::be5f:f4ff:fe67:1f9a.123: NTPv4, Server, length 48

Result on the client:
 8 Aug 11:17:56 ntpdate[13099]: no server suitable for synchronization found
Comment 1 Stijn Tintel 2016-08-08 08:24:48 UTC
Also reported on the OpenWrt bug tracker:
https://dev.openwrt.org/ticket/18404
https://dev.openwrt.org/ticket/22976
Comment 2 Denys Vlasenko 2016-08-13 21:36:57 UTC
Please check that the libc you compile against provides IP_PKTINFO.
Specifically, this ifndef in udp_io.c
should not be taken:


ssize_t FAST_FUNC
send_to_from(int fd, void *buf, size_t len, int flags,
                const struct sockaddr *to,
                const struct sockaddr *from,
                socklen_t tolen)
{
#ifndef IP_PKTINFO
        (void)from; /* suppress "unused from" warning */
        return sendto(fd, buf, len, flags, to, tolen);
#else


If you are sure that the "else" branch is taken here, then please strace your ntpd invocation, *from the beginning* (not strace -p PID) and attach the log here.
Comment 3 Stijn Tintel 2016-08-15 00:13:00 UTC
This is on LEDE, currently using musl libc v1.1.15. It provides IP_PKTINFO in netinet/in.h [1], which is only included on FreeBSD, OpenBSD and Apple.

It also happened a on OpenWrt at the time it was still using uClibc by default. In uClibc, IP_PKTINFO is defined in https://git.uclibc.org/uClibc/tree/libc/sysdeps/linux/common/bits/in.h

Is this something you are willing to fix, or do we need to patch it in LEDE?

[1] http://git.musl-libc.org/cgit/musl/tree/include/netinet/in.h?h=v1.1.15&id=faf69b9a73d09fafcbe4fd3007b8d8724293d8e1#n182
Comment 4 Denys Vlasenko 2016-08-16 12:21:08 UTC
(In reply to Stijn Tintel from comment #3)
> It also happened a on OpenWrt at the time it was still using uClibc by default. In uClibc, IP_PKTINFO is defined in https://git.uclibc.org/uClibc/tree/libc/sysdeps/linux/common/bits/in.h

On uclibc, IP_PKTINFO is successfully picked up. At least for me.

> Is this something you are willing to fix, or do we need to patch it in LEDE?

Please let me know which modification of includes in ntpd.c makes your build against musl work? Currently it has

#include "libbb.h"
#include <math.h>
#include <netinet/ip.h> /* For IPTOS_LOWDELAY definition */
#include <sys/resource.h> /* setpriority */
#include <sys/timex.h>
Comment 5 Stijn Tintel 2016-09-15 02:57:15 UTC
(In reply to Denys Vlasenko from comment #4)
Turns out this isn't related to missing includes, or IP_PKTINFO not being defined.

For IPv4, the problem seems to be that to->sa_family is AF_INET6 instead of AF_INET4. With this change in send_to_from() in libbb/udp_io.c, it works fine:

@@ -70,7 +71,7 @@ send_to_from(int fd, void *buf, size_t l
        msg.msg_flags = flags;

        cmsgptr = CMSG_FIRSTHDR(&msg);
-       if (to->sa_family == AF_INET && from->sa_family == AF_INET) {
+       if (from->sa_family == AF_INET) {
                struct in_pktinfo *pktptr;
                cmsgptr->cmsg_level = IPPROTO_IP;
                cmsgptr->cmsg_type = IP_PKTINFO;


For IPv6, both to->sa_family and from->sa_family are AF_INET6. I'll need to debug this further, but that'll be for another day.
Comment 6 Denys Vlasenko 2016-09-15 11:21:54 UTC
Fixed in git, thanks!