]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
Set reply source IP from query destination IP
authorTimo Teras <timo.teras@iki.fi>
Fri, 7 Aug 2009 14:26:15 +0000 (16:26 +0200)
committerMiroslav Lichvar <mlichvar@redhat.com>
Fri, 7 Aug 2009 15:02:11 +0000 (17:02 +0200)
Currently, on multihomed host, when chrony is not bound to a specific
IP address, a query is sent to an interface and the default source IP
hint for the back route differs, the reply will have a source IP
different than where the query was destinied to. This will cause
problems because connection tracking firewalls will drop the replies
and most likely the client program will get confused too.

This patch uses the IP_PKTINFO mechanism to get the IP address where
received packets where targetted to and use that IP address as source
hint when sending a reply.

addressing.h
broadcast.c
cmdmon.c
conf.c
ntp_io.c

index aa20ed9227f325730013efda8f10be8ee363f845..89e82d43ef4434f877ec163f2ef2f15e6c4ff0c9 100644 (file)
@@ -35,6 +35,7 @@
    number.  Both parts are in HOST order, NOT network order. */
 typedef struct {
   unsigned long ip_addr;
+  unsigned long local_ip_addr;
   unsigned short port;
 } NTP_Remote_Address;
 
index be217e7dc5b83cfa7ad15e5365c9f63c0a8c6f0d..35df56fd2dd991c386b8472b08e3bd1276b3c9d3 100644 (file)
@@ -145,6 +145,7 @@ BRD_AddDestination(unsigned long addr, unsigned short port, int interval)
   }
 
   destinations[n_destinations].addr.ip_addr = addr;
+  destinations[n_destinations].addr.local_ip_addr = 0;
   destinations[n_destinations].addr.port = port;
   destinations[n_destinations].interval = interval;
 
index e2d2ded864d3847249b8040708792fc37de9be37..f5e3c8b9c259d0d47d25565e46c276abca3d0954 100644 (file)
--- a/cmdmon.c
+++ b/cmdmon.c
@@ -1104,6 +1104,7 @@ handle_add_server(CMD_Request *rx_message, CMD_Reply *tx_message)
   NSR_Status status;
   
   rem_addr.ip_addr = ntohl(rx_message->data.ntp_source.ip_addr);
+  rem_addr.local_ip_addr = 0;
   rem_addr.port = (unsigned short)(ntohl(rx_message->data.ntp_source.port));
   params.minpoll = ntohl(rx_message->data.ntp_source.minpoll);
   params.maxpoll = ntohl(rx_message->data.ntp_source.maxpoll);
@@ -1140,6 +1141,7 @@ handle_add_peer(CMD_Request *rx_message, CMD_Reply *tx_message)
   NSR_Status status;
   
   rem_addr.ip_addr = ntohl(rx_message->data.ntp_source.ip_addr);
+  rem_addr.local_ip_addr = 0;
   rem_addr.port = (unsigned short)(ntohl(rx_message->data.ntp_source.port));
   params.minpoll = ntohl(rx_message->data.ntp_source.minpoll);
   params.maxpoll = ntohl(rx_message->data.ntp_source.maxpoll);
@@ -1174,6 +1176,7 @@ handle_del_source(CMD_Request *rx_message, CMD_Reply *tx_message)
   NSR_Status status;
   
   rem_addr.ip_addr = ntohl(rx_message->data.del_source.ip_addr);
+  rem_addr.local_ip_addr = 0;
   rem_addr.port = 0;
   
   status = NSR_RemoveSource(&rem_addr);
diff --git a/conf.c b/conf.c
index b64f3909ad211ae5e87a72ff991620be2c2d8efc..fdd9d9701b5353c59c6627e3a36ee0301a69ebbb 100644 (file)
--- a/conf.c
+++ b/conf.c
@@ -1059,6 +1059,7 @@ CNF_AddSources(void) {
 
   for (i=0; i<n_ntp_sources; i++) {
     server.ip_addr = ntp_sources[i].ip_addr;
+    server.local_ip_addr = 0;
     server.port = ntp_sources[i].port;
 
     switch (ntp_sources[i].type) {
index ec93ae20d83e7197c62ed5dc9c3abd0f2badf254..c3594b3ae8754f95c1caa319ddb68ddd1698a7f0 100644 (file)
--- a/ntp_io.c
+++ b/ntp_io.c
@@ -119,6 +119,12 @@ NIO_Initialise(void)
     /* Don't quit - we might survive anyway */
   }
 
+  /* We want the local IP info too */
+  if (setsockopt(sock_fd, IPPROTO_IP, IP_PKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
+    LOG(LOGS_ERR, LOGF_NtpIO, "Could not request packet info using socket option");
+    /* Don't quit - we might survive anyway */
+  }
+
   /* Bind the port */
   my_addr.sin_family = AF_INET;
   my_addr.sin_port = htons(port_number);
@@ -190,6 +196,7 @@ read_from_socket(void *anything)
   char cmsgbuf[256];
   struct msghdr msg;
   struct iovec iov;
+  struct cmsghdr *cmsg;
 
   assert(initialised);
 
@@ -216,8 +223,18 @@ read_from_socket(void *anything)
 
   if (status > 0) {
     remote_addr.ip_addr = ntohl(where_from.sin_addr.s_addr);
+    remote_addr.local_ip_addr = 0;
     remote_addr.port = ntohs(where_from.sin_port);
 
+    for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+      if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) {
+        struct in_pktinfo ipi;
+
+        memcpy(&ipi, CMSG_DATA(cmsg), sizeof(ipi));
+        remote_addr.local_ip_addr = ntohl(ipi.ipi_spec_dst.s_addr);
+      }
+    }
+
     if (status == NTP_NORMAL_PACKET_SIZE) {
 
       NSR_ProcessReceive((NTP_Packet *) &message.ntp_pkt, &now, &remote_addr);
@@ -245,6 +262,9 @@ send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr)
   struct sockaddr_in remote;
   struct msghdr msg;
   struct iovec iov;
+  struct cmsghdr *cmsg;
+  char cmsgbuf[256];
+  int cmsglen;
 
   assert(initialised);
 
@@ -258,9 +278,30 @@ send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr)
   msg.msg_namelen = sizeof(remote);
   msg.msg_iov = &iov;
   msg.msg_iovlen = 1;
-  msg.msg_control = NULL;
-  msg.msg_controllen = 0;
+  msg.msg_control = cmsgbuf;
+  msg.msg_controllen = sizeof(cmsgbuf);
   msg.msg_flags = 0;
+  cmsglen = 0;
+
+  if (remote_addr->local_ip_addr) {
+    struct in_pktinfo *ipi;
+
+    cmsg = CMSG_FIRSTHDR(&msg);
+    cmsg->cmsg_level = IPPROTO_IP;
+    cmsg->cmsg_type = IP_PKTINFO;
+    cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+    cmsglen += CMSG_SPACE(sizeof(struct in_pktinfo));
+
+    ipi = (struct in_pktinfo *) CMSG_DATA(cmsg);
+    memset(ipi, 0, sizeof(struct in_pktinfo));
+    ipi->ipi_spec_dst.s_addr = htonl(remote_addr->local_ip_addr);
+#if 0
+    LOG(LOGS_INFO, LOGF_NtpIO, "sending to %s:%d from %s",
+        UTI_IPToDottedQuad(remote_addr->ip_addr), remote_addr->port, UTI_IPToDottedQuad(remote_addr->local_ip_addr));
+#endif
+  }
+
+  msg.msg_controllen = cmsglen;
 
   if (sendmsg(sock_fd, &msg, 0) < 0) {
     LOG(LOGS_WARN, LOGF_NtpIO, "Could not send to %s:%d : %s",