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.
This commit is contained in:
Timo Teras 2009-08-07 16:26:15 +02:00 committed by Miroslav Lichvar
parent d87cddd6a5
commit 0666d04ab2
5 changed files with 49 additions and 2 deletions

View 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;

View 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;

View file

@ -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);

1
conf.c
View file

@ -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) {

View file

@ -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",