Blame ntp_io.c

Packit 96c956
/*
Packit 96c956
  chronyd/chronyc - Programs for keeping computer clocks accurate.
Packit 96c956
Packit 96c956
 **********************************************************************
Packit 96c956
 * Copyright (C) Richard P. Curnow  1997-2003
Packit 96c956
 * Copyright (C) Timo Teras  2009
Packit 96c956
 * Copyright (C) Miroslav Lichvar  2009, 2013-2016, 2018
Packit 96c956
 * 
Packit 96c956
 * This program is free software; you can redistribute it and/or modify
Packit 96c956
 * it under the terms of version 2 of the GNU General Public License as
Packit 96c956
 * published by the Free Software Foundation.
Packit 96c956
 * 
Packit 96c956
 * This program is distributed in the hope that it will be useful, but
Packit 96c956
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 96c956
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 96c956
 * General Public License for more details.
Packit 96c956
 * 
Packit 96c956
 * You should have received a copy of the GNU General Public License along
Packit 96c956
 * with this program; if not, write to the Free Software Foundation, Inc.,
Packit 96c956
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
Packit 96c956
 * 
Packit 96c956
 **********************************************************************
Packit 96c956
Packit 96c956
  =======================================================================
Packit 96c956
Packit 96c956
  This file deals with the IO aspects of reading and writing NTP packets
Packit 96c956
  */
Packit 96c956
Packit 96c956
#include "config.h"
Packit 96c956
Packit 96c956
#include "sysincl.h"
Packit 96c956
Packit 96c956
#include "array.h"
Packit 96c956
#include "ntp_io.h"
Packit 96c956
#include "ntp_core.h"
Packit 96c956
#include "ntp_sources.h"
Packit 96c956
#include "sched.h"
Packit 96c956
#include "local.h"
Packit 96c956
#include "logging.h"
Packit 96c956
#include "conf.h"
Packit 96c956
#include "privops.h"
Packit 96c956
#include "util.h"
Packit 96c956
Packit 96c956
#ifdef HAVE_LINUX_TIMESTAMPING
Packit 96c956
#include "ntp_io_linux.h"
Packit 96c956
#endif
Packit 96c956
Packit 96c956
#define INVALID_SOCK_FD -1
Packit 96c956
#define CMSGBUF_SIZE 256
Packit 96c956
Packit 96c956
union sockaddr_in46 {
Packit 96c956
  struct sockaddr_in in4;
Packit 96c956
#ifdef FEAT_IPV6
Packit 96c956
  struct sockaddr_in6 in6;
Packit 96c956
#endif
Packit 96c956
  struct sockaddr u;
Packit 96c956
};
Packit 96c956
Packit 96c956
struct Message {
Packit 96c956
  union sockaddr_in46 name;
Packit 96c956
  struct iovec iov;
Packit 96c956
  NTP_Receive_Buffer buf;
Packit 96c956
  /* Aligned buffer for control messages */
Packit 96c956
  struct cmsghdr cmsgbuf[CMSGBUF_SIZE / sizeof (struct cmsghdr)];
Packit 96c956
};
Packit 96c956
Packit 96c956
#ifdef HAVE_RECVMMSG
Packit 96c956
#define MAX_RECV_MESSAGES 4
Packit 96c956
#define MessageHeader mmsghdr
Packit 96c956
#else
Packit 96c956
/* Compatible with mmsghdr */
Packit 96c956
struct MessageHeader {
Packit 96c956
  struct msghdr msg_hdr;
Packit 96c956
  unsigned int msg_len;
Packit 96c956
};
Packit 96c956
Packit 96c956
#define MAX_RECV_MESSAGES 1
Packit 96c956
#endif
Packit 96c956
Packit 96c956
/* Arrays of Message and MessageHeader */
Packit 96c956
static ARR_Instance recv_messages;
Packit 96c956
static ARR_Instance recv_headers;
Packit 96c956
Packit 96c956
/* The server/peer and client sockets for IPv4 and IPv6 */
Packit 96c956
static int server_sock_fd4;
Packit 96c956
static int client_sock_fd4;
Packit 96c956
#ifdef FEAT_IPV6
Packit 96c956
static int server_sock_fd6;
Packit 96c956
static int client_sock_fd6;
Packit 96c956
#endif
Packit 96c956
Packit 96c956
/* Reference counters for server sockets to keep them open only when needed */
Packit 96c956
static int server_sock_ref4;
Packit 96c956
#ifdef FEAT_IPV6
Packit 96c956
static int server_sock_ref6;
Packit 96c956
#endif
Packit 96c956
Packit 96c956
/* Flag indicating we create a new connected client socket for each
Packit 96c956
   server instead of sharing client_sock_fd4 and client_sock_fd6 */
Packit 96c956
static int separate_client_sockets;
Packit 96c956
Packit 96c956
/* Flag indicating the server sockets are not created dynamically when needed,
Packit 96c956
   either to have a socket for client requests when separate client sockets
Packit 96c956
   are disabled and client port is equal to server port, or the server port is
Packit 96c956
   disabled */
Packit 96c956
static int permanent_server_sockets;
Packit 96c956
Packit 96c956
/* Flag indicating the server IPv4 socket is bound to an address */
Packit 96c956
static int bound_server_sock_fd4;
Packit 96c956
Packit 96c956
/* Flag indicating that we have been initialised */
Packit 96c956
static int initialised=0;
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
/* Forward prototypes */
Packit 96c956
static void read_from_socket(int sock_fd, int event, void *anything);
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
static int
Packit 96c956
prepare_socket(int family, int port_number, int client_only)
Packit 96c956
{
Packit 96c956
  union sockaddr_in46 my_addr;
Packit 96c956
  socklen_t my_addr_len;
Packit 96c956
  int sock_fd;
Packit 96c956
  IPAddr bind_address;
Packit 96c956
  int events = SCH_FILE_INPUT, on_off = 1;
Packit 96c956
Packit 96c956
  /* Open Internet domain UDP socket for NTP message transmissions */
Packit 96c956
Packit 96c956
  sock_fd = socket(family, SOCK_DGRAM, 0);
Packit 96c956
Packit 96c956
  if (sock_fd < 0) {
Packit 96c956
    if (!client_only) {
Packit 96c956
      LOG(LOGS_ERR, "Could not open %s NTP socket : %s",
Packit 96c956
          UTI_SockaddrFamilyToString(family), strerror(errno));
Packit 96c956
    } else {
Packit 96c956
      DEBUG_LOG("Could not open %s NTP socket : %s",
Packit 96c956
                UTI_SockaddrFamilyToString(family), strerror(errno));
Packit 96c956
    }
Packit 96c956
    return INVALID_SOCK_FD;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  /* Close on exec */
Packit 96c956
  UTI_FdSetCloexec(sock_fd);
Packit 96c956
Packit 96c956
  /* Enable non-blocking mode on server sockets */
Packit 96c956
  if (!client_only && fcntl(sock_fd, F_SETFL, O_NONBLOCK))
Packit 96c956
    DEBUG_LOG("Could not set O_NONBLOCK : %s", strerror(errno));
Packit 96c956
Packit 96c956
  /* Prepare local address */
Packit 96c956
  memset(&my_addr, 0, sizeof (my_addr));
Packit 96c956
  my_addr_len = 0;
Packit 96c956
Packit 96c956
  switch (family) {
Packit 96c956
    case AF_INET:
Packit 96c956
      if (!client_only)
Packit 96c956
        CNF_GetBindAddress(IPADDR_INET4, &bind_address);
Packit 96c956
      else
Packit 96c956
        CNF_GetBindAcquisitionAddress(IPADDR_INET4, &bind_address);
Packit 96c956
Packit 96c956
      if (bind_address.family == IPADDR_INET4)
Packit 96c956
        my_addr.in4.sin_addr.s_addr = htonl(bind_address.addr.in4);
Packit 96c956
      else if (port_number)
Packit 96c956
        my_addr.in4.sin_addr.s_addr = htonl(INADDR_ANY);
Packit 96c956
      else
Packit 96c956
        break;
Packit 96c956
Packit 96c956
      my_addr.in4.sin_family = family;
Packit 96c956
      my_addr.in4.sin_port = htons(port_number);
Packit 96c956
      my_addr_len = sizeof (my_addr.in4);
Packit 96c956
Packit 96c956
      if (!client_only)
Packit 96c956
        bound_server_sock_fd4 = my_addr.in4.sin_addr.s_addr != htonl(INADDR_ANY);
Packit 96c956
Packit 96c956
      break;
Packit 96c956
#ifdef FEAT_IPV6
Packit 96c956
    case AF_INET6:
Packit 96c956
      if (!client_only)
Packit 96c956
        CNF_GetBindAddress(IPADDR_INET6, &bind_address);
Packit 96c956
      else
Packit 96c956
        CNF_GetBindAcquisitionAddress(IPADDR_INET6, &bind_address);
Packit 96c956
Packit 96c956
      if (bind_address.family == IPADDR_INET6)
Packit 96c956
        memcpy(my_addr.in6.sin6_addr.s6_addr, bind_address.addr.in6,
Packit 96c956
            sizeof (my_addr.in6.sin6_addr.s6_addr));
Packit 96c956
      else if (port_number)
Packit 96c956
        my_addr.in6.sin6_addr = in6addr_any;
Packit 96c956
      else
Packit 96c956
        break;
Packit 96c956
Packit 96c956
      my_addr.in6.sin6_family = family;
Packit 96c956
      my_addr.in6.sin6_port = htons(port_number);
Packit 96c956
      my_addr_len = sizeof (my_addr.in6);
Packit 96c956
Packit 96c956
      break;
Packit 96c956
#endif
Packit 96c956
    default:
Packit 96c956
      assert(0);
Packit 96c956
  }
Packit 96c956
Packit 96c956
  /* Make the socket capable of re-using an old address if binding to a specific port */
Packit 96c956
  if (port_number &&
Packit 96c956
      setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on_off, sizeof(on_off)) < 0) {
Packit 96c956
    LOG(LOGS_ERR, "Could not set %s socket option", "SO_REUSEADDR");
Packit 96c956
    /* Don't quit - we might survive anyway */
Packit 96c956
  }
Packit 96c956
  
Packit 96c956
  /* Make the socket capable of sending broadcast pkts - needed for NTP broadcast mode */
Packit 96c956
  if (!client_only &&
Packit 96c956
      setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, (char *)&on_off, sizeof(on_off)) < 0) {
Packit 96c956
    LOG(LOGS_ERR, "Could not set %s socket option", "SO_BROADCAST");
Packit 96c956
    /* Don't quit - we might survive anyway */
Packit 96c956
  }
Packit 96c956
Packit 96c956
  /* Enable kernel/HW timestamping of packets */
Packit 96c956
#ifdef HAVE_LINUX_TIMESTAMPING
Packit 96c956
  if (!NIO_Linux_SetTimestampSocketOptions(sock_fd, client_only, &events))
Packit 96c956
#endif
Packit 96c956
#ifdef SO_TIMESTAMPNS
Packit 96c956
    if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMPNS, (char *)&on_off, sizeof(on_off)) < 0)
Packit 96c956
#endif
Packit 96c956
#ifdef SO_TIMESTAMP
Packit 96c956
      if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMP, (char *)&on_off, sizeof(on_off)) < 0)
Packit 96c956
        LOG(LOGS_ERR, "Could not set %s socket option", "SO_TIMESTAMP");
Packit 96c956
#endif
Packit 96c956
      ;
Packit 96c956
Packit 96c956
#ifdef IP_FREEBIND
Packit 96c956
  /* Allow binding to address that doesn't exist yet */
Packit 96c956
  if (my_addr_len > 0 &&
Packit 96c956
      setsockopt(sock_fd, IPPROTO_IP, IP_FREEBIND, (char *)&on_off, sizeof(on_off)) < 0) {
Packit 96c956
    LOG(LOGS_ERR, "Could not set %s socket option", "IP_FREEBIND");
Packit 96c956
  }
Packit 96c956
#endif
Packit 96c956
Packit 96c956
  if (family == AF_INET) {
Packit 96c956
#ifdef HAVE_IN_PKTINFO
Packit 96c956
    if (setsockopt(sock_fd, IPPROTO_IP, IP_PKTINFO, (char *)&on_off, sizeof(on_off)) < 0)
Packit 96c956
      LOG(LOGS_ERR, "Could not set %s socket option", "IP_PKTINFO");
Packit 96c956
#elif defined(IP_RECVDSTADDR)
Packit 96c956
    if (setsockopt(sock_fd, IPPROTO_IP, IP_RECVDSTADDR, (char *)&on_off, sizeof(on_off)) < 0)
Packit 96c956
      LOG(LOGS_ERR, "Could not set %s socket option", "IP_RECVDSTADDR");
Packit 96c956
#endif
Packit 96c956
  }
Packit 96c956
#ifdef FEAT_IPV6
Packit 96c956
  else if (family == AF_INET6) {
Packit 96c956
#ifdef IPV6_V6ONLY
Packit 96c956
    /* Receive IPv6 packets only */
Packit 96c956
    if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on_off, sizeof(on_off)) < 0) {
Packit 96c956
      LOG(LOGS_ERR, "Could not set %s socket option", "IPV6_V6ONLY");
Packit 96c956
    }
Packit 96c956
#endif
Packit 96c956
Packit 96c956
#ifdef HAVE_IN6_PKTINFO
Packit 96c956
#ifdef IPV6_RECVPKTINFO
Packit 96c956
    if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
Packit 96c956
      LOG(LOGS_ERR, "Could not set %s socket option", "IPV6_RECVPKTINFO");
Packit 96c956
    }
Packit 96c956
#else
Packit 96c956
    if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_PKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
Packit 96c956
      LOG(LOGS_ERR, "Could not set %s socket option", "IPV6_PKTINFO");
Packit 96c956
    }
Packit 96c956
#endif
Packit 96c956
#endif
Packit 96c956
  }
Packit 96c956
#endif
Packit 96c956
Packit 96c956
  /* Bind the socket if a port or address was specified */
Packit 96c956
  if (my_addr_len > 0 && PRV_BindSocket(sock_fd, &my_addr.u, my_addr_len) < 0) {
Packit 96c956
    LOG(LOGS_ERR, "Could not bind %s NTP socket : %s",
Packit 96c956
        UTI_SockaddrFamilyToString(family), strerror(errno));
Packit 96c956
    close(sock_fd);
Packit 96c956
    return INVALID_SOCK_FD;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  /* Register handler for read and possibly exception events on the socket */
Packit 96c956
  SCH_AddFileHandler(sock_fd, events, read_from_socket, NULL);
Packit 96c956
Packit 96c956
  return sock_fd;
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
static int
Packit 96c956
prepare_separate_client_socket(int family)
Packit 96c956
{
Packit 96c956
  switch (family) {
Packit 96c956
    case IPADDR_INET4:
Packit 96c956
      return prepare_socket(AF_INET, 0, 1);
Packit 96c956
#ifdef FEAT_IPV6
Packit 96c956
    case IPADDR_INET6:
Packit 96c956
      return prepare_socket(AF_INET6, 0, 1);
Packit 96c956
#endif
Packit 96c956
    default:
Packit 96c956
      return INVALID_SOCK_FD;
Packit 96c956
  }
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
static int
Packit 96c956
connect_socket(int sock_fd, NTP_Remote_Address *remote_addr)
Packit 96c956
{
Packit 96c956
  union sockaddr_in46 addr;
Packit 96c956
  socklen_t addr_len;
Packit 96c956
Packit 96c956
  addr_len = UTI_IPAndPortToSockaddr(&remote_addr->ip_addr, remote_addr->port, &addr.u);
Packit 96c956
Packit 96c956
  assert(addr_len);
Packit 96c956
Packit 96c956
  if (connect(sock_fd, &addr.u, addr_len) < 0) {
Packit 96c956
    DEBUG_LOG("Could not connect NTP socket to %s:%d : %s",
Packit 96c956
        UTI_IPToString(&remote_addr->ip_addr), remote_addr->port,
Packit 96c956
        strerror(errno));
Packit 96c956
    return 0;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  return 1;
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
static void
Packit 96c956
close_socket(int sock_fd)
Packit 96c956
{
Packit 96c956
  if (sock_fd == INVALID_SOCK_FD)
Packit 96c956
    return;
Packit 96c956
Packit 96c956
#ifdef HAVE_LINUX_TIMESTAMPING
Packit 96c956
  NIO_Linux_NotifySocketClosing(sock_fd);
Packit 96c956
#endif
Packit 96c956
  SCH_RemoveFileHandler(sock_fd);
Packit 96c956
  close(sock_fd);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
static void
Packit 96c956
prepare_buffers(unsigned int n)
Packit 96c956
{
Packit 96c956
  struct MessageHeader *hdr;
Packit 96c956
  struct Message *msg;
Packit 96c956
  unsigned int i;
Packit 96c956
Packit 96c956
  for (i = 0; i < n; i++) {
Packit 96c956
    msg = ARR_GetElement(recv_messages, i);
Packit 96c956
    hdr = ARR_GetElement(recv_headers, i);
Packit 96c956
Packit 96c956
    msg->iov.iov_base = &msg->buf;
Packit 96c956
    msg->iov.iov_len = sizeof (msg->buf);
Packit 96c956
    hdr->msg_hdr.msg_name = &msg->name;
Packit 96c956
    hdr->msg_hdr.msg_namelen = sizeof (msg->name);
Packit 96c956
    hdr->msg_hdr.msg_iov = &msg->iov;
Packit 96c956
    hdr->msg_hdr.msg_iovlen = 1;
Packit 96c956
    hdr->msg_hdr.msg_control = &msg->cmsgbuf;
Packit 96c956
    hdr->msg_hdr.msg_controllen = sizeof (msg->cmsgbuf);
Packit 96c956
    hdr->msg_hdr.msg_flags = 0;
Packit 96c956
    hdr->msg_len = 0;
Packit 96c956
  }
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
void
Packit 96c956
NIO_Initialise(int family)
Packit 96c956
{
Packit 96c956
  int server_port, client_port;
Packit 96c956
Packit 96c956
  assert(!initialised);
Packit 96c956
  initialised = 1;
Packit 96c956
Packit 96c956
#ifdef HAVE_LINUX_TIMESTAMPING
Packit 96c956
  NIO_Linux_Initialise();
Packit 96c956
#else
Packit 96c956
  if (1) {
Packit 96c956
    CNF_HwTsInterface *conf_iface;
Packit 96c956
    if (CNF_GetHwTsInterface(0, &conf_iface))
Packit 96c956
      LOG_FATAL("HW timestamping not supported");
Packit 96c956
  }
Packit 96c956
#endif
Packit 96c956
Packit 96c956
  recv_messages = ARR_CreateInstance(sizeof (struct Message));
Packit 96c956
  ARR_SetSize(recv_messages, MAX_RECV_MESSAGES);
Packit 96c956
  recv_headers = ARR_CreateInstance(sizeof (struct MessageHeader));
Packit 96c956
  ARR_SetSize(recv_headers, MAX_RECV_MESSAGES);
Packit 96c956
  prepare_buffers(MAX_RECV_MESSAGES);
Packit 96c956
Packit 96c956
  server_port = CNF_GetNTPPort();
Packit 96c956
  client_port = CNF_GetAcquisitionPort();
Packit 96c956
Packit 96c956
  /* Use separate connected sockets if client port is negative */
Packit 96c956
  separate_client_sockets = client_port < 0;
Packit 96c956
  if (client_port < 0)
Packit 96c956
    client_port = 0;
Packit 96c956
Packit 96c956
  permanent_server_sockets = !server_port || (!separate_client_sockets &&
Packit 96c956
                                              client_port == server_port);
Packit 96c956
Packit 96c956
  server_sock_fd4 = INVALID_SOCK_FD;
Packit 96c956
  client_sock_fd4 = INVALID_SOCK_FD;
Packit 96c956
  server_sock_ref4 = 0;
Packit 96c956
#ifdef FEAT_IPV6
Packit 96c956
  server_sock_fd6 = INVALID_SOCK_FD;
Packit 96c956
  client_sock_fd6 = INVALID_SOCK_FD;
Packit 96c956
  server_sock_ref6 = 0;
Packit 96c956
#endif
Packit 96c956
Packit 96c956
  if (family == IPADDR_UNSPEC || family == IPADDR_INET4) {
Packit 96c956
    if (permanent_server_sockets && server_port)
Packit 96c956
      server_sock_fd4 = prepare_socket(AF_INET, server_port, 0);
Packit 96c956
    if (!separate_client_sockets) {
Packit 96c956
      if (client_port != server_port || !server_port)
Packit 96c956
        client_sock_fd4 = prepare_socket(AF_INET, client_port, 1);
Packit 96c956
      else
Packit 96c956
        client_sock_fd4 = server_sock_fd4;
Packit 96c956
    }
Packit 96c956
  }
Packit 96c956
#ifdef FEAT_IPV6
Packit 96c956
  if (family == IPADDR_UNSPEC || family == IPADDR_INET6) {
Packit 96c956
    if (permanent_server_sockets && server_port)
Packit 96c956
      server_sock_fd6 = prepare_socket(AF_INET6, server_port, 0);
Packit 96c956
    if (!separate_client_sockets) {
Packit 96c956
      if (client_port != server_port || !server_port)
Packit 96c956
        client_sock_fd6 = prepare_socket(AF_INET6, client_port, 1);
Packit 96c956
      else
Packit 96c956
        client_sock_fd6 = server_sock_fd6;
Packit 96c956
    }
Packit 96c956
  }
Packit 96c956
#endif
Packit 96c956
Packit 96c956
  if ((server_port && server_sock_fd4 == INVALID_SOCK_FD &&
Packit 96c956
       permanent_server_sockets 
Packit 96c956
#ifdef FEAT_IPV6
Packit 96c956
       && server_sock_fd6 == INVALID_SOCK_FD
Packit 96c956
#endif
Packit 96c956
      ) || (!separate_client_sockets && client_sock_fd4 == INVALID_SOCK_FD
Packit 96c956
#ifdef FEAT_IPV6
Packit 96c956
       && client_sock_fd6 == INVALID_SOCK_FD
Packit 96c956
#endif
Packit 96c956
      )) {
Packit 96c956
    LOG_FATAL("Could not open NTP sockets");
Packit 96c956
  }
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
void
Packit 96c956
NIO_Finalise(void)
Packit 96c956
{
Packit 96c956
  if (server_sock_fd4 != client_sock_fd4)
Packit 96c956
    close_socket(client_sock_fd4);
Packit 96c956
  close_socket(server_sock_fd4);
Packit 96c956
  server_sock_fd4 = client_sock_fd4 = INVALID_SOCK_FD;
Packit 96c956
#ifdef FEAT_IPV6
Packit 96c956
  if (server_sock_fd6 != client_sock_fd6)
Packit 96c956
    close_socket(client_sock_fd6);
Packit 96c956
  close_socket(server_sock_fd6);
Packit 96c956
  server_sock_fd6 = client_sock_fd6 = INVALID_SOCK_FD;
Packit 96c956
#endif
Packit 96c956
  ARR_DestroyInstance(recv_headers);
Packit 96c956
  ARR_DestroyInstance(recv_messages);
Packit 96c956
Packit 96c956
#ifdef HAVE_LINUX_TIMESTAMPING
Packit 96c956
  NIO_Linux_Finalise();
Packit 96c956
#endif
Packit 96c956
Packit 96c956
  initialised = 0;
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
int
Packit 96c956
NIO_OpenClientSocket(NTP_Remote_Address *remote_addr)
Packit 96c956
{
Packit 96c956
  if (separate_client_sockets) {
Packit 96c956
    int sock_fd = prepare_separate_client_socket(remote_addr->ip_addr.family);
Packit 96c956
Packit 96c956
    if (sock_fd == INVALID_SOCK_FD)
Packit 96c956
      return INVALID_SOCK_FD;
Packit 96c956
Packit 96c956
    if (!connect_socket(sock_fd, remote_addr)) {
Packit 96c956
      close_socket(sock_fd);
Packit 96c956
      return INVALID_SOCK_FD;
Packit 96c956
    }
Packit 96c956
Packit 96c956
    return sock_fd;
Packit 96c956
  } else {
Packit 96c956
    switch (remote_addr->ip_addr.family) {
Packit 96c956
      case IPADDR_INET4:
Packit 96c956
        return client_sock_fd4;
Packit 96c956
#ifdef FEAT_IPV6
Packit 96c956
      case IPADDR_INET6:
Packit 96c956
        return client_sock_fd6;
Packit 96c956
#endif
Packit 96c956
      default:
Packit 96c956
        return INVALID_SOCK_FD;
Packit 96c956
    }
Packit 96c956
  }
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
int
Packit 96c956
NIO_OpenServerSocket(NTP_Remote_Address *remote_addr)
Packit 96c956
{
Packit 96c956
  switch (remote_addr->ip_addr.family) {
Packit 96c956
    case IPADDR_INET4:
Packit 96c956
      if (permanent_server_sockets)
Packit 96c956
        return server_sock_fd4;
Packit 96c956
      if (server_sock_fd4 == INVALID_SOCK_FD)
Packit 96c956
        server_sock_fd4 = prepare_socket(AF_INET, CNF_GetNTPPort(), 0);
Packit 96c956
      if (server_sock_fd4 != INVALID_SOCK_FD)
Packit 96c956
        server_sock_ref4++;
Packit 96c956
      return server_sock_fd4;
Packit 96c956
#ifdef FEAT_IPV6
Packit 96c956
    case IPADDR_INET6:
Packit 96c956
      if (permanent_server_sockets)
Packit 96c956
        return server_sock_fd6;
Packit 96c956
      if (server_sock_fd6 == INVALID_SOCK_FD)
Packit 96c956
        server_sock_fd6 = prepare_socket(AF_INET6, CNF_GetNTPPort(), 0);
Packit 96c956
      if (server_sock_fd6 != INVALID_SOCK_FD)
Packit 96c956
        server_sock_ref6++;
Packit 96c956
      return server_sock_fd6;
Packit 96c956
#endif
Packit 96c956
    default:
Packit 96c956
      return INVALID_SOCK_FD;
Packit 96c956
  }
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
void
Packit 96c956
NIO_CloseClientSocket(int sock_fd)
Packit 96c956
{
Packit 96c956
  if (separate_client_sockets)
Packit 96c956
    close_socket(sock_fd);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
void
Packit 96c956
NIO_CloseServerSocket(int sock_fd)
Packit 96c956
{
Packit 96c956
  if (permanent_server_sockets || sock_fd == INVALID_SOCK_FD)
Packit 96c956
    return;
Packit 96c956
Packit 96c956
  if (sock_fd == server_sock_fd4) {
Packit 96c956
    if (--server_sock_ref4 <= 0) {
Packit 96c956
      close_socket(server_sock_fd4);
Packit 96c956
      server_sock_fd4 = INVALID_SOCK_FD;
Packit 96c956
    }
Packit 96c956
  }
Packit 96c956
#ifdef FEAT_IPV6
Packit 96c956
  else if (sock_fd == server_sock_fd6) {
Packit 96c956
    if (--server_sock_ref6 <= 0) {
Packit 96c956
      close_socket(server_sock_fd6);
Packit 96c956
      server_sock_fd6 = INVALID_SOCK_FD;
Packit 96c956
    }
Packit 96c956
  }
Packit 96c956
#endif
Packit 96c956
  else {
Packit 96c956
    assert(0);
Packit 96c956
  }
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
int
Packit 96c956
NIO_IsServerSocket(int sock_fd)
Packit 96c956
{
Packit 96c956
  return sock_fd != INVALID_SOCK_FD &&
Packit 96c956
    (sock_fd == server_sock_fd4
Packit 96c956
#ifdef FEAT_IPV6
Packit 96c956
     || sock_fd == server_sock_fd6
Packit 96c956
#endif
Packit 96c956
    );
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
int
Packit 96c956
NIO_IsServerConnectable(NTP_Remote_Address *remote_addr)
Packit 96c956
{
Packit 96c956
  int sock_fd, r;
Packit 96c956
Packit 96c956
  sock_fd = prepare_separate_client_socket(remote_addr->ip_addr.family);
Packit 96c956
  if (sock_fd == INVALID_SOCK_FD)
Packit 96c956
    return 0;
Packit 96c956
Packit 96c956
  r = connect_socket(sock_fd, remote_addr);
Packit 96c956
  close_socket(sock_fd);
Packit 96c956
Packit 96c956
  return r;
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
static void
Packit 96c956
process_message(struct msghdr *hdr, int length, int sock_fd)
Packit 96c956
{
Packit 96c956
  NTP_Remote_Address remote_addr;
Packit 96c956
  NTP_Local_Address local_addr;
Packit 96c956
  NTP_Local_Timestamp local_ts;
Packit 96c956
  struct timespec sched_ts;
Packit 96c956
  struct cmsghdr *cmsg;
Packit 96c956
Packit 96c956
  SCH_GetLastEventTime(&local_ts.ts, &local_ts.err, NULL);
Packit 96c956
  local_ts.source = NTP_TS_DAEMON;
Packit 96c956
  sched_ts = local_ts.ts;
Packit 96c956
Packit 96c956
  if (hdr->msg_namelen > sizeof (union sockaddr_in46)) {
Packit 96c956
    DEBUG_LOG("Truncated source address");
Packit 96c956
    return;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  if (hdr->msg_namelen >= sizeof (((struct sockaddr *)hdr->msg_name)->sa_family)) {
Packit 96c956
    UTI_SockaddrToIPAndPort((struct sockaddr *)hdr->msg_name,
Packit 96c956
                            &remote_addr.ip_addr, &remote_addr.port);
Packit 96c956
  } else {
Packit 96c956
    remote_addr.ip_addr.family = IPADDR_UNSPEC;
Packit 96c956
    remote_addr.port = 0;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  local_addr.ip_addr.family = IPADDR_UNSPEC;
Packit 96c956
  local_addr.if_index = INVALID_IF_INDEX;
Packit 96c956
  local_addr.sock_fd = sock_fd;
Packit 96c956
Packit 96c956
  if (hdr->msg_flags & MSG_TRUNC) {
Packit 96c956
    DEBUG_LOG("Received truncated message from %s:%d",
Packit 96c956
              UTI_IPToString(&remote_addr.ip_addr), remote_addr.port);
Packit 96c956
    return;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  if (hdr->msg_flags & MSG_CTRUNC) {
Packit 96c956
    DEBUG_LOG("Truncated control message");
Packit 96c956
    /* Continue */
Packit 96c956
  }
Packit 96c956
Packit 96c956
  for (cmsg = CMSG_FIRSTHDR(hdr); cmsg; cmsg = CMSG_NXTHDR(hdr, cmsg)) {
Packit 96c956
#ifdef HAVE_IN_PKTINFO
Packit 96c956
    if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) {
Packit 96c956
      struct in_pktinfo ipi;
Packit 96c956
Packit 96c956
      memcpy(&ipi, CMSG_DATA(cmsg), sizeof(ipi));
Packit 96c956
      local_addr.ip_addr.addr.in4 = ntohl(ipi.ipi_addr.s_addr);
Packit 96c956
      local_addr.ip_addr.family = IPADDR_INET4;
Packit 96c956
      local_addr.if_index = ipi.ipi_ifindex;
Packit 96c956
    }
Packit 96c956
#elif defined(IP_RECVDSTADDR)
Packit 96c956
    if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR) {
Packit 96c956
      struct in_addr addr;
Packit 96c956
Packit 96c956
      memcpy(&addr, CMSG_DATA(cmsg), sizeof (addr));
Packit 96c956
      local_addr.ip_addr.addr.in4 = ntohl(addr.s_addr);
Packit 96c956
      local_addr.ip_addr.family = IPADDR_INET4;
Packit 96c956
    }
Packit 96c956
#endif
Packit 96c956
Packit 96c956
#ifdef HAVE_IN6_PKTINFO
Packit 96c956
    if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
Packit 96c956
      struct in6_pktinfo ipi;
Packit 96c956
Packit 96c956
      memcpy(&ipi, CMSG_DATA(cmsg), sizeof(ipi));
Packit 96c956
      memcpy(&local_addr.ip_addr.addr.in6, &ipi.ipi6_addr.s6_addr,
Packit 96c956
             sizeof (local_addr.ip_addr.addr.in6));
Packit 96c956
      local_addr.ip_addr.family = IPADDR_INET6;
Packit 96c956
      local_addr.if_index = ipi.ipi6_ifindex;
Packit 96c956
    }
Packit 96c956
#endif
Packit 96c956
Packit 96c956
#ifdef SCM_TIMESTAMP
Packit 96c956
    if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMP) {
Packit 96c956
      struct timeval tv;
Packit 96c956
      struct timespec ts;
Packit 96c956
Packit 96c956
      memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv));
Packit 96c956
      UTI_TimevalToTimespec(&tv, &ts);
Packit 96c956
      LCL_CookTime(&ts, &local_ts.ts, &local_ts.err);
Packit 96c956
      local_ts.source = NTP_TS_KERNEL;
Packit 96c956
    }
Packit 96c956
#endif
Packit 96c956
Packit 96c956
#ifdef SCM_TIMESTAMPNS
Packit 96c956
    if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMPNS) {
Packit 96c956
      struct timespec ts;
Packit 96c956
Packit 96c956
      memcpy(&ts, CMSG_DATA(cmsg), sizeof (ts));
Packit 96c956
      LCL_CookTime(&ts, &local_ts.ts, &local_ts.err);
Packit 96c956
      local_ts.source = NTP_TS_KERNEL;
Packit 96c956
    }
Packit 96c956
#endif
Packit 96c956
  }
Packit 96c956
Packit 96c956
#ifdef HAVE_LINUX_TIMESTAMPING
Packit 96c956
  if (NIO_Linux_ProcessMessage(&remote_addr, &local_addr, &local_ts, hdr, length))
Packit 96c956
    return;
Packit 96c956
#endif
Packit 96c956
Packit 96c956
  DEBUG_LOG("Received %d bytes from %s:%d to %s fd=%d if=%d tss=%u delay=%.9f",
Packit 96c956
            length, UTI_IPToString(&remote_addr.ip_addr), remote_addr.port,
Packit 96c956
            UTI_IPToString(&local_addr.ip_addr), local_addr.sock_fd, local_addr.if_index,
Packit 96c956
            local_ts.source, UTI_DiffTimespecsToDouble(&sched_ts, &local_ts.ts));
Packit 96c956
Packit 96c956
  /* Just ignore the packet if it's not of a recognized length */
Packit 96c956
  if (length < NTP_NORMAL_PACKET_LENGTH || length > sizeof (NTP_Receive_Buffer))
Packit 96c956
    return;
Packit 96c956
Packit 96c956
  NSR_ProcessRx(&remote_addr, &local_addr, &local_ts,
Packit 96c956
                (NTP_Packet *)hdr->msg_iov[0].iov_base, length);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
static void
Packit 96c956
read_from_socket(int sock_fd, int event, void *anything)
Packit 96c956
{
Packit 96c956
  /* This should only be called when there is something
Packit 96c956
     to read, otherwise it may block */
Packit 96c956
Packit 96c956
  struct MessageHeader *hdr;
Packit 96c956
  unsigned int i, n;
Packit 96c956
  int status, flags = 0;
Packit 96c956
Packit 96c956
#ifdef HAVE_LINUX_TIMESTAMPING
Packit 96c956
  if (NIO_Linux_ProcessEvent(sock_fd, event))
Packit 96c956
    return;
Packit 96c956
#endif
Packit 96c956
Packit 96c956
  hdr = ARR_GetElements(recv_headers);
Packit 96c956
  n = ARR_GetSize(recv_headers);
Packit 96c956
  assert(n >= 1);
Packit 96c956
Packit 96c956
  if (event == SCH_FILE_EXCEPTION) {
Packit 96c956
#ifdef HAVE_LINUX_TIMESTAMPING
Packit 96c956
    flags |= MSG_ERRQUEUE;
Packit 96c956
#else
Packit 96c956
    assert(0);
Packit 96c956
#endif
Packit 96c956
  }
Packit 96c956
Packit 96c956
#ifdef HAVE_RECVMMSG
Packit 96c956
  status = recvmmsg(sock_fd, hdr, n, flags | MSG_DONTWAIT, NULL);
Packit 96c956
  if (status >= 0)
Packit 96c956
    n = status;
Packit 96c956
#else
Packit 96c956
  n = 1;
Packit 96c956
  status = recvmsg(sock_fd, &hdr[0].msg_hdr, flags);
Packit 96c956
  if (status >= 0)
Packit 96c956
    hdr[0].msg_len = status;
Packit 96c956
#endif
Packit 96c956
Packit 96c956
  if (status < 0) {
Packit 96c956
#ifdef HAVE_LINUX_TIMESTAMPING
Packit 96c956
    /* If reading from the error queue failed, the exception should be
Packit 96c956
       for a socket error.  Clear the error to avoid a busy loop. */
Packit 96c956
    if (flags & MSG_ERRQUEUE) {
Packit 96c956
      int error = 0;
Packit 96c956
      socklen_t len = sizeof (error);
Packit 96c956
Packit 96c956
      if (getsockopt(sock_fd, SOL_SOCKET, SO_ERROR, &error, &len))
Packit 96c956
        DEBUG_LOG("Could not get SO_ERROR");
Packit 96c956
      if (error)
Packit 96c956
        errno = error;
Packit 96c956
    }
Packit 96c956
#endif
Packit 96c956
Packit 96c956
    DEBUG_LOG("Could not receive from fd %d : %s", sock_fd,
Packit 96c956
              strerror(errno));
Packit 96c956
    return;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  for (i = 0; i < n; i++) {
Packit 96c956
    hdr = ARR_GetElement(recv_headers, i);
Packit 96c956
    process_message(&hdr->msg_hdr, hdr->msg_len, sock_fd);
Packit 96c956
  }
Packit 96c956
Packit 96c956
  /* Restore the buffers to their original state */
Packit 96c956
  prepare_buffers(n);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
/* Send a packet to remote address from local address */
Packit 96c956
Packit 96c956
int
Packit 96c956
NIO_SendPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr,
Packit 96c956
               NTP_Local_Address *local_addr, int length, int process_tx)
Packit 96c956
{
Packit 96c956
  union sockaddr_in46 remote;
Packit 96c956
  struct msghdr msg;
Packit 96c956
  struct iovec iov;
Packit 96c956
  struct cmsghdr *cmsg, cmsgbuf[CMSGBUF_SIZE / sizeof (struct cmsghdr)];
Packit 96c956
  int cmsglen;
Packit 96c956
  socklen_t addrlen = 0;
Packit 96c956
Packit 96c956
  assert(initialised);
Packit 96c956
Packit 96c956
  if (local_addr->sock_fd == INVALID_SOCK_FD) {
Packit 96c956
    DEBUG_LOG("No socket to send to %s:%d",
Packit 96c956
              UTI_IPToString(&remote_addr->ip_addr), remote_addr->port);
Packit 96c956
    return 0;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  /* Don't set address with connected socket */
Packit 96c956
  if (NIO_IsServerSocket(local_addr->sock_fd) || !separate_client_sockets) {
Packit 96c956
    addrlen = UTI_IPAndPortToSockaddr(&remote_addr->ip_addr, remote_addr->port,
Packit 96c956
                                      &remote.u);
Packit 96c956
    if (!addrlen)
Packit 96c956
      return 0;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  if (addrlen) {
Packit 96c956
    msg.msg_name = &remote.u;
Packit 96c956
    msg.msg_namelen = addrlen;
Packit 96c956
  } else {
Packit 96c956
    msg.msg_name = NULL;
Packit 96c956
    msg.msg_namelen = 0;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  iov.iov_base = packet;
Packit 96c956
  iov.iov_len = length;
Packit 96c956
  msg.msg_iov = &iov;
Packit 96c956
  msg.msg_iovlen = 1;
Packit 96c956
  msg.msg_control = cmsgbuf;
Packit 96c956
  msg.msg_controllen = sizeof(cmsgbuf);
Packit 96c956
  msg.msg_flags = 0;
Packit 96c956
  cmsglen = 0;
Packit 96c956
Packit 96c956
#ifdef HAVE_IN_PKTINFO
Packit 96c956
  if (local_addr->ip_addr.family == IPADDR_INET4) {
Packit 96c956
    struct in_pktinfo *ipi;
Packit 96c956
Packit 96c956
    cmsg = CMSG_FIRSTHDR(&msg;;
Packit 96c956
    memset(cmsg, 0, CMSG_SPACE(sizeof(struct in_pktinfo)));
Packit 96c956
    cmsglen += CMSG_SPACE(sizeof(struct in_pktinfo));
Packit 96c956
Packit 96c956
    cmsg->cmsg_level = IPPROTO_IP;
Packit 96c956
    cmsg->cmsg_type = IP_PKTINFO;
Packit 96c956
    cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
Packit 96c956
Packit 96c956
    ipi = (struct in_pktinfo *) CMSG_DATA(cmsg);
Packit 96c956
    ipi->ipi_spec_dst.s_addr = htonl(local_addr->ip_addr.addr.in4);
Packit 96c956
    if (local_addr->if_index != INVALID_IF_INDEX)
Packit 96c956
      ipi->ipi_ifindex = local_addr->if_index;
Packit 96c956
  }
Packit 96c956
#elif defined(IP_SENDSRCADDR)
Packit 96c956
  /* Specify the IPv4 source address only if the socket is not bound */
Packit 96c956
  if (local_addr->ip_addr.family == IPADDR_INET4 &&
Packit 96c956
      local_addr->sock_fd == server_sock_fd4 && !bound_server_sock_fd4) {
Packit 96c956
    struct in_addr *addr;
Packit 96c956
Packit 96c956
    cmsg = CMSG_FIRSTHDR(&msg;;
Packit 96c956
    memset(cmsg, 0, CMSG_SPACE(sizeof (struct in_addr)));
Packit 96c956
    cmsglen += CMSG_SPACE(sizeof (struct in_addr));
Packit 96c956
Packit 96c956
    cmsg->cmsg_level = IPPROTO_IP;
Packit 96c956
    cmsg->cmsg_type = IP_SENDSRCADDR;
Packit 96c956
    cmsg->cmsg_len = CMSG_LEN(sizeof (struct in_addr));
Packit 96c956
Packit 96c956
    addr = (struct in_addr *)CMSG_DATA(cmsg);
Packit 96c956
    addr->s_addr = htonl(local_addr->ip_addr.addr.in4);
Packit 96c956
  }
Packit 96c956
#endif
Packit 96c956
Packit 96c956
#ifdef HAVE_IN6_PKTINFO
Packit 96c956
  if (local_addr->ip_addr.family == IPADDR_INET6) {
Packit 96c956
    struct in6_pktinfo *ipi;
Packit 96c956
Packit 96c956
    cmsg = CMSG_FIRSTHDR(&msg;;
Packit 96c956
    memset(cmsg, 0, CMSG_SPACE(sizeof(struct in6_pktinfo)));
Packit 96c956
    cmsglen += CMSG_SPACE(sizeof(struct in6_pktinfo));
Packit 96c956
Packit 96c956
    cmsg->cmsg_level = IPPROTO_IPV6;
Packit 96c956
    cmsg->cmsg_type = IPV6_PKTINFO;
Packit 96c956
    cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
Packit 96c956
Packit 96c956
    ipi = (struct in6_pktinfo *) CMSG_DATA(cmsg);
Packit 96c956
    memcpy(&ipi->ipi6_addr.s6_addr, &local_addr->ip_addr.addr.in6,
Packit 96c956
        sizeof(ipi->ipi6_addr.s6_addr));
Packit 96c956
    if (local_addr->if_index != INVALID_IF_INDEX)
Packit 96c956
      ipi->ipi6_ifindex = local_addr->if_index;
Packit 96c956
  }
Packit 96c956
#endif
Packit 96c956
Packit 96c956
#ifdef HAVE_LINUX_TIMESTAMPING
Packit 96c956
  if (process_tx)
Packit 96c956
   cmsglen = NIO_Linux_RequestTxTimestamp(&msg, cmsglen, local_addr->sock_fd);
Packit 96c956
#endif
Packit 96c956
Packit 96c956
  msg.msg_controllen = cmsglen;
Packit 96c956
  /* This is apparently required on some systems */
Packit 96c956
  if (!cmsglen)
Packit 96c956
    msg.msg_control = NULL;
Packit 96c956
Packit 96c956
  if (sendmsg(local_addr->sock_fd, &msg, 0) < 0) {
Packit 96c956
    DEBUG_LOG("Could not send to %s:%d from %s fd %d : %s",
Packit 96c956
        UTI_IPToString(&remote_addr->ip_addr), remote_addr->port,
Packit 96c956
        UTI_IPToString(&local_addr->ip_addr), local_addr->sock_fd,
Packit 96c956
        strerror(errno));
Packit 96c956
    return 0;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  DEBUG_LOG("Sent %d bytes to %s:%d from %s fd %d", length,
Packit 96c956
      UTI_IPToString(&remote_addr->ip_addr), remote_addr->port,
Packit 96c956
      UTI_IPToString(&local_addr->ip_addr), local_addr->sock_fd);
Packit 96c956
Packit 96c956
  return 1;
Packit 96c956
}