From 0666d04ab22e43a299177760a79c564543faeda2 Mon Sep 17 00:00:00 2001 From: Timo Teras Date: Fri, 7 Aug 2009 16:26:15 +0200 Subject: [PATCH] Set reply source IP from query destination IP 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 | 1 + broadcast.c | 1 + cmdmon.c | 3 +++ conf.c | 1 + ntp_io.c | 45 +++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 49 insertions(+), 2 deletions(-) diff --git a/addressing.h b/addressing.h index aa20ed9..89e82d4 100644 --- a/addressing.h +++ b/addressing.h @@ -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; diff --git a/broadcast.c b/broadcast.c index be217e7..35df56f 100644 --- a/broadcast.c +++ b/broadcast.c @@ -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; diff --git a/cmdmon.c b/cmdmon.c index e2d2ded..f5e3c8b 100644 --- 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 b64f390..fdd9d97 100644 --- a/conf.c +++ b/conf.c @@ -1059,6 +1059,7 @@ CNF_AddSources(void) { for (i=0; i 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",