diff --git a/configure b/configure index cf2555f..3fa76db 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 9bad2bc..7fdff42 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));