From: Miroslav Lichvar Date: Tue, 24 May 2011 16:06:01 +0000 (+0200) Subject: Set source IPv6 address on NTP reply X-Git-Tag: 1.26-pre1~31 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=de4d14843fbb34db0a8af9e805fad96d1151d390;p=thirdparty%2Fchrony.git Set source IPv6 address on NTP reply This is needed on systems with multiple IPv6 addresses to reply with the same source address as the destination address of the NTP request. --- diff --git a/configure b/configure index cf2555f5..3fa76dbb 100755 --- a/configure +++ b/configure @@ -360,6 +360,15 @@ if [ $feat_ipv6 = "1" ] && \ return !inet_ntop(AF_INET6, &n.sin6_addr.s6_addr, p, sizeof(p));' then add_def HAVE_IPV6 + if ! test_code 'in6_pktinfo' 'sys/socket.h netinet/in.h' '' '' ' + return sizeof(struct in6_pktinfo);' + then + if test_code 'in6_pktinfo with _GNU_SOURCE' 'sys/socket.h netinet/in.h' \ + '-D_GNU_SOURCE' '' 'return sizeof(struct in6_pktinfo);' + then + add_def _GNU_SOURCE + fi + fi fi if [ $feat_pps = "1" ] && \ diff --git a/ntp_io.c b/ntp_io.c index 9bad2bca..7fdff425 100644 --- a/ntp_io.c +++ b/ntp_io.c @@ -159,6 +159,16 @@ prepare_socket(int family) LOG(LOGS_ERR, LOGF_NtpIO, "Could not request IPV6_V6ONLY socket option"); } #endif + +#ifdef IPV6_RECVPKTINFO + if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, (char *)&on_off, sizeof(on_off)) < 0) { + LOG(LOGS_ERR, LOGF_NtpIO, "Could not request IPv6 packet info socket option"); + } +#elif defined(IPV6_PKTINFO) + if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_PKTINFO, (char *)&on_off, sizeof(on_off)) < 0) { + LOG(LOGS_ERR, LOGF_NtpIO, "Could not request IPv6 packet info socket option"); + } +#endif } #endif @@ -345,6 +355,17 @@ read_from_socket(void *anything) } #endif +#ifdef IPV6_PKTINFO + if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) { + struct in6_pktinfo ipi; + + memcpy(&ipi, CMSG_DATA(cmsg), sizeof(ipi)); + memcpy(&remote_addr.local_ip_addr.addr.in6, &ipi.ipi6_addr.s6_addr, + sizeof (remote_addr.local_ip_addr.addr.in6)); + remote_addr.local_ip_addr.family = IPADDR_INET6; + } +#endif + #ifdef SO_TIMESTAMP if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SO_TIMESTAMP) { struct timeval tv; @@ -445,6 +466,25 @@ send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr) } #endif +#ifdef IPV6_PKTINFO + if (remote_addr->local_ip_addr.family == IPADDR_INET6) { + struct cmsghdr *cmsg; + struct in6_pktinfo *ipi; + + cmsg = CMSG_FIRSTHDR(&msg); + memset(cmsg, 0, CMSG_SPACE(sizeof(struct in6_pktinfo))); + cmsglen += CMSG_SPACE(sizeof(struct in6_pktinfo)); + + cmsg->cmsg_level = IPPROTO_IPV6; + cmsg->cmsg_type = IPV6_PKTINFO; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); + + ipi = (struct in6_pktinfo *) CMSG_DATA(cmsg); + memcpy(&ipi->ipi6_addr.s6_addr, &remote_addr->local_ip_addr.addr.in6, + sizeof(ipi->ipi6_addr.s6_addr)); + } +#endif + #if 0 LOG(LOGS_INFO, LOGF_NtpIO, "sending to %s:%d from %s", UTI_IPToString(&remote_addr->ip_addr), remote_addr->port, UTI_IPToString(&remote_addr->local_ip_addr));