From 8265ff2890802e2e1a746f4a7239083b2902a3a3 Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Fri, 9 Oct 2009 15:00:59 +0200 Subject: [PATCH] Add IPv6 support --- acquire.c | 163 +++++++++++++++----- acquire.h | 4 +- addressing.h | 27 +++- addrfilt.c | 209 ++++++++++++++++++------- addrfilt.h | 12 +- broadcast.c | 6 +- broadcast.h | 4 +- candm.h | 48 +++--- client.c | 416 +++++++++++++++++++++++++++++--------------------- clientlog.c | 177 +++++++++++++++------ clientlog.h | 14 +- cmdmon.c | 408 +++++++++++++++++++++++++++++++++---------------- cmdmon.h | 6 +- cmdparse.c | 3 +- cmdparse.h | 3 +- conf.c | 183 ++++++++++++---------- conf.h | 6 +- configure | 39 +++++ nameserv.c | 171 +++++++++++++-------- nameserv.h | 8 +- ntp_core.c | 56 +++---- ntp_core.h | 4 +- ntp_io.c | 204 +++++++++++++++++++------ ntp_sources.c | 76 +++++---- ntp_sources.h | 17 ++- refclock.c | 5 +- reports.h | 7 +- sources.c | 22 ++- sources.h | 2 +- sysincl.h | 5 + util.c | 164 ++++++++++++++++++++ util.h | 10 +- 32 files changed, 1709 insertions(+), 770 deletions(-) diff --git a/acquire.c b/acquire.c index 94b4e61..2a6fb46 100644 --- a/acquire.c +++ b/acquire.c @@ -65,7 +65,8 @@ #define RETRANSMISSION_TIMEOUT (1.0) -typedef struct { unsigned long ip_addr; +typedef struct { + IPAddr ip_addr; /* Address of the server */ int sanity; /* Flag indicating whether source looks sane or not */ int n_dead_probes; /* Number of probes sent to the server @@ -93,7 +94,18 @@ static int n_completed_sources; static int init_slew_threshold = -1; -static int sock_fd = -1; +union sockaddr_in46 { + struct sockaddr_in in4; +#ifdef HAVE_IPV6 + struct sockaddr_in6 in6; +#endif + struct sockaddr u; +}; + +static int sock_fd4 = -1; +#ifdef HAVE_IPV6 +static int sock_fd6 = -1; +#endif /* ================================================== */ @@ -143,12 +155,13 @@ ACQ_Finalise(void) /* ================================================== */ -static void -initialise_io(void) +static int +prepare_socket(int family) { unsigned short port_number = CNF_GetAcquisitionPort(); + int sock_fd; - sock_fd = socket(AF_INET, SOCK_DGRAM, 0); + sock_fd = socket(family, SOCK_DGRAM, 0); if (sock_fd < 0) { LOG_FATAL(LOGF_Acquire, "Could not open socket : %s", strerror(errno)); @@ -158,18 +171,48 @@ initialise_io(void) /* Don't bother binding this socket - we're not fussed what port number it gets */ } else { - struct sockaddr_in my_addr; - my_addr.sin_family = AF_INET; - my_addr.sin_port = htons(port_number); - my_addr.sin_addr.s_addr = htonl(INADDR_ANY); - if (bind(sock_fd, (struct sockaddr *) &my_addr, sizeof(my_addr)) < 0) { + union sockaddr_in46 my_addr; + + memset(&my_addr, 0, sizeof (my_addr)); + + switch (family) { + case AF_INET: + my_addr.in4.sin_family = family; + my_addr.in4.sin_port = htons(port_number); + my_addr.in4.sin_addr.s_addr = htonl(INADDR_ANY); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + my_addr.in6.sin6_family = family; + my_addr.in6.sin6_port = htons(port_number); + my_addr.in6.sin6_addr = in6addr_any; + break; +#endif + default: + assert(0); + } + + if (bind(sock_fd, &my_addr.u, sizeof(my_addr)) < 0) { LOG(LOGS_ERR, LOGF_Acquire, "Could not bind socket : %s\n", strerror(errno)); /* but keep running */ } } - SCH_AddInputFileHandler(sock_fd, read_from_socket, NULL); + SCH_AddInputFileHandler(sock_fd, read_from_socket, (void *)(long)sock_fd); + return sock_fd; +} +/* ================================================== */ + +static void +initialise_io(int family) +{ + if (family == IPADDR_INET4 || family == IPADDR_UNSPEC) + sock_fd4 = prepare_socket(AF_INET); +#ifdef HAVE_IPV6 + if (family == IPADDR_INET6 || family == IPADDR_UNSPEC) + sock_fd6 = prepare_socket(AF_INET6); +#endif } /* ================================================== */ @@ -177,10 +220,18 @@ initialise_io(void) static void finalise_io(void) { - if (sock_fd >= 0) { - SCH_RemoveInputFileHandler(sock_fd); - close(sock_fd); + if (sock_fd4 >= 0) { + SCH_RemoveInputFileHandler(sock_fd4); + close(sock_fd4); } + sock_fd4 = -1; +#ifdef HAVE_IPV6 + if (sock_fd6 >= 0) { + SCH_RemoveInputFileHandler(sock_fd6); + close(sock_fd6); + } + sock_fd6 = -1; +#endif return; } @@ -195,10 +246,11 @@ probe_source(SourceRecord *src) NTP_Mode my_mode = MODE_CLIENT; struct timeval cooked; double local_time_err; - struct sockaddr_in his_addr; + union sockaddr_in46 his_addr; + int sock_fd; #if 0 - printf("Sending probe to %08lx sent=%d samples=%d\n", src->ip_addr, src->n_probes_sent, src->n_samples); + printf("Sending probe to %s sent=%d samples=%d\n", UTI_IPToString(&src->ip_addr), src->n_probes_sent, src->n_samples); #endif pkt.lvm = (((LEAP_Unsynchronised << 6) & 0xc0) | @@ -219,18 +271,37 @@ probe_source(SourceRecord *src) pkt.receive_ts.lo = 0; /* Set to 0 */ /* And do transmission */ - his_addr.sin_addr.s_addr = htonl(src->ip_addr); - his_addr.sin_port = htons(123); /* Fixed for now */ - his_addr.sin_family = AF_INET; + + memset(&his_addr, 0, sizeof (his_addr)); + switch (src->ip_addr.family) { + case IPADDR_INET4: + his_addr.in4.sin_addr.s_addr = htonl(src->ip_addr.addr.in4); + his_addr.in4.sin_port = htons(123); /* Fixed for now */ + his_addr.in4.sin_family = AF_INET; + sock_fd = sock_fd4; + break; +#ifdef HAVE_IPV6 + case IPADDR_INET6: + memcpy(&his_addr.in6.sin6_addr.s6_addr, &src->ip_addr.addr.in6, + sizeof (his_addr.in6.sin6_addr.s6_addr)); + his_addr.in6.sin6_port = htons(123); /* Fixed for now */ + his_addr.in6.sin6_family = AF_INET6; + sock_fd = sock_fd6; + break; +#endif + default: + assert(0); + } + LCL_ReadCookedTime(&cooked, &local_time_err); UTI_TimevalToInt64(&cooked, &pkt.transmit_ts); if (sendto(sock_fd, (void *) &pkt, NTP_NORMAL_PACKET_SIZE, 0, - (struct sockaddr *) &his_addr, sizeof(his_addr)) < 0) { + &his_addr.u, sizeof(his_addr)) < 0) { LOG(LOGS_WARN, LOGF_Acquire, "Could not send to %s : %s", - UTI_IPToDottedQuad(src->ip_addr), + UTI_IPToString(&src->ip_addr), strerror(errno)); } @@ -253,7 +324,7 @@ transmit_timeout(void *x) src->timer_running = 0; #if 0 - printf("Timeout expired for server %08lx\n", src->ip_addr); + printf("Timeout expired for server %s\n", UTI_IPToString(&src->ip_addr)); #endif if (src->n_dead_probes < MAX_DEAD_PROBES) { @@ -357,11 +428,12 @@ read_from_socket(void *anything) { int status; ReceiveBuffer msg; - struct sockaddr_in his_addr; + union sockaddr_in46 his_addr; + int sock_fd; socklen_t his_addr_len; int flags; int message_length; - unsigned long remote_ip; + IPAddr remote_ip; int i, ok; struct timeval now; double local_time_err; @@ -374,24 +446,39 @@ read_from_socket(void *anything) /* Get timestamp */ LCL_ReadCookedTime(&now, &local_time_err); + sock_fd = (long)anything; status = recvfrom (sock_fd, (char *)&msg, message_length, flags, - (struct sockaddr *) &his_addr, &his_addr_len); + &his_addr.u, &his_addr_len); if (status < 0) { LOG(LOGS_WARN, LOGF_Acquire, "Error reading from socket, %s", strerror(errno)); return; } - remote_ip = ntohl(his_addr.sin_addr.s_addr); + switch (his_addr.u.sa_family) { + case AF_INET: + remote_ip.family = IPADDR_INET4; + remote_ip.addr.in4 = ntohl(his_addr.in4.sin_addr.s_addr); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + remote_ip.family = IPADDR_INET6; + memcpy(&remote_ip.addr.in6, his_addr.in6.sin6_addr.s6_addr, + sizeof (remote_ip.addr.in6)); + break; +#endif + default: + assert(0); + } #if 0 - printf("Got message from %08lx\n", remote_ip); + printf("Got message from %s\n", UTI_IPToString(&remote_ip)); #endif /* Find matching host */ ok = 0; for (i=0; in_total_samples >= MAX_SAMPLES)) { ++n_completed_sources; #if 0 - printf("Source %08lx completed\n", src->ip_addr); + printf("Source %s completed\n", UTI_IPToString(&src->ip_addr)); #endif if (n_completed_sources == n_sources) { wind_up_acquisition(); @@ -440,7 +527,7 @@ start_next_source(void) { probe_source(sources + n_started_sources); #if 0 - printf("Trying to start source %08lx\n", sources[n_started_sources].ip_addr); + printf("Trying to start source %s\n", UTI_IPToString(&sources[n_started_sources].ip_addr)); #endif n_started_sources++; @@ -552,10 +639,10 @@ process_measurements(void) for (i=0; i<2*n_sane_sources; i++) { #if 0 - fprintf(stderr, "Endpoint type %s source index %d [ip=%08lx] offset=%.6f\n", + fprintf(stderr, "Endpoint type %s source index %d [ip=%s] offset=%.6f\n", (eps[i].type == LO) ? "LO" : "HIGH", eps[i].index, - sources[eps[i].index].ip_addr, + UTI_IPToString(&sources[eps[i].index].ip_addr), eps[i].offset); #endif @@ -655,10 +742,10 @@ start_source_timeout_handler(void *not_used) /* ================================================== */ void -ACQ_StartAcquisition(int n, unsigned long *ip_addrs, int threshold, void (*after_hook)(void *), void *anything) +ACQ_StartAcquisition(int n, IPAddr *ip_addrs, int threshold, void (*after_hook)(void *), void *anything) { - int i; + int i, ip4, ip6; saved_after_hook = after_hook; saved_after_hook_anything = anything; @@ -670,14 +757,18 @@ ACQ_StartAcquisition(int n, unsigned long *ip_addrs, int threshold, void (*after n_sources = n; sources = MallocArray(SourceRecord, n); - for (i=0; i> (32-NBITS)) & ((1UL<addr.in6[i * 4 + 0] << 24 | + ip->addr.in6[i * 4 + 1] << 16 | + ip->addr.in6[i * 4 + 2] << 8 | + ip->addr.in6[i * 4 + 3]; } /* ================================================== */ -inline static unsigned long -get_residual(unsigned long addr) +inline static uint32_t +get_subnet(uint32_t *addr, unsigned int where) { - return (addr << NBITS); + int off; + + off = where / 32; + where %= 32; + + return (addr[off] >> (32 - NBITS - where)) & ((1UL << NBITS) - 1); } /* ================================================== */ @@ -79,8 +91,10 @@ ADF_CreateTable(void) result = MallocNew(struct ADF_AuthTableInst); /* Default is that nothing is allowed */ - result->base.state = DENY; - result->base.extended = NULL; + result->base4.state = DENY; + result->base4.extended = NULL; + result->base6.state = DENY; + result->base6.extended = NULL; return result; } @@ -135,22 +149,22 @@ open_node(TableNode *node) static ADF_Status set_subnet(TableNode *start_node, - unsigned long ip, + uint32_t *ip, + int ip_len, int subnet_bits, State new_state, int delete_children) { - int bits_to_go; - unsigned long residual; - unsigned long subnet; + int bits_to_go, bits_consumed; + uint32_t subnet; TableNode *node; + bits_consumed = 0; bits_to_go = subnet_bits; - residual = ip; node = start_node; if ((subnet_bits < 0) || - (subnet_bits > 32)) { + (subnet_bits > 32 * ip_len)) { return ADF_BADSUBNET; @@ -159,13 +173,13 @@ set_subnet(TableNode *start_node, if ((bits_to_go & (NBITS-1)) == 0) { while (bits_to_go > 0) { - subnet = get_subnet(residual); - residual = get_residual(residual); + subnet = get_subnet(ip, bits_consumed); if (!(node->extended)) { open_node(node); } node = &(node->extended[subnet]); bits_to_go -= NBITS; + bits_consumed += NBITS; } if (delete_children) { @@ -178,18 +192,18 @@ set_subnet(TableNode *start_node, TableNode *this_node; while (bits_to_go >= NBITS) { - subnet = get_subnet(residual); - residual = get_residual(residual); + subnet = get_subnet(ip, bits_consumed); if (!(node->extended)) { open_node(node); } node = &(node->extended[subnet]); bits_to_go -= NBITS; + bits_consumed += NBITS; } /* How many subnet entries to set : 1->8, 2->4, 3->2 */ N = 1 << (NBITS-bits_to_go); - subnet = get_subnet(residual); + subnet = get_subnet(ip, bits_consumed); if (!(node->extended)) { open_node(node); } @@ -210,12 +224,41 @@ set_subnet(TableNode *start_node, /* ================================================== */ +static ADF_Status +set_subnet_(ADF_AuthTable table, + IPAddr *ip_addr, + int subnet_bits, + State new_state, + int delete_children) +{ + uint32_t ip6[4]; + + switch (ip_addr->family) { + case IPADDR_INET4: + return set_subnet(&table->base4, &ip_addr->addr.in4, 1, subnet_bits, new_state, delete_children); + case IPADDR_INET6: + split_ip6(ip_addr, ip6); + return set_subnet(&table->base6, ip6, 4, subnet_bits, new_state, delete_children); + case IPADDR_UNSPEC: + /* Apply to both, subnet_bits has to be 0 */ + if (subnet_bits != 0) + return ADF_BADSUBNET; + memset(ip6, 0, sizeof (ip6)); + if (set_subnet(&table->base4, ip6, 1, 0, new_state, delete_children) == ADF_SUCCESS && + set_subnet(&table->base6, ip6, 4, 0, new_state, delete_children) == ADF_SUCCESS) + return ADF_SUCCESS; + break; + } + + return ADF_BADSUBNET; +} + ADF_Status ADF_Allow(ADF_AuthTable table, - unsigned long ip, + IPAddr *ip, int subnet_bits) { - return set_subnet(&(table->base), ip, subnet_bits, ALLOW, 0); + return set_subnet_(table, ip, subnet_bits, ALLOW, 0); } /* ================================================== */ @@ -223,30 +266,30 @@ ADF_Allow(ADF_AuthTable table, ADF_Status ADF_AllowAll(ADF_AuthTable table, - unsigned long ip, + IPAddr *ip, int subnet_bits) { - return set_subnet(&(table->base), ip, subnet_bits, ALLOW, 1); + return set_subnet_(table, ip, subnet_bits, ALLOW, 1); } /* ================================================== */ ADF_Status ADF_Deny(ADF_AuthTable table, - unsigned long ip, + IPAddr *ip, int subnet_bits) { - return set_subnet(&(table->base), ip, subnet_bits, DENY, 0); + return set_subnet_(table, ip, subnet_bits, DENY, 0); } /* ================================================== */ ADF_Status ADF_DenyAll(ADF_AuthTable table, - unsigned long ip, + IPAddr *ip, int subnet_bits) { - return set_subnet(&(table->base), ip, subnet_bits, DENY, 1); + return set_subnet_(table, ip, subnet_bits, DENY, 1); } /* ================================================== */ @@ -254,32 +297,33 @@ ADF_DenyAll(ADF_AuthTable table, void ADF_DestroyTable(ADF_AuthTable table) { - close_node(&(table->base)); + close_node(&table->base4); + close_node(&table->base6); Free(table); } /* ================================================== */ static int -check_ip_in_node(TableNode *start_node, unsigned long ip) +check_ip_in_node(TableNode *start_node, uint32_t *ip) { - unsigned long residual, subnet; + uint32_t subnet; + int bits_consumed = 0; int result = 0; int finished = 0; TableNode *node; State state=DENY; node = start_node; - residual = ip; do { if (node->state != AS_PARENT) { state = node->state; } if (node->extended) { - subnet = get_subnet(residual); - residual = get_residual(residual); + subnet = get_subnet(ip, bits_consumed); node = &(node->extended[subnet]); + bits_consumed += NBITS; } else { /* Make decision on this node */ finished = 1; @@ -306,38 +350,63 @@ check_ip_in_node(TableNode *start_node, unsigned long ip) int ADF_IsAllowed(ADF_AuthTable table, - unsigned long ip) + IPAddr *ip_addr) { + uint32_t ip6[4]; - return check_ip_in_node(&(table->base), ip); + switch (ip_addr->family) { + case IPADDR_INET4: + return check_ip_in_node(&table->base4, &ip_addr->addr.in4); + case IPADDR_INET6: + split_ip6(ip_addr, ip6); + return check_ip_in_node(&table->base6, ip6); + } + return 0; } /* ================================================== */ #if defined TEST -static void print_node(TableNode *node, unsigned long addr, int shift, int subnet_bits) +static void print_node(TableNode *node, uint32_t *addr, int ip_len, int shift, int subnet_bits) { - unsigned long new_addr; + uint32_t new_addr[4]; int i; TableNode *sub_node; for (i=0; i> 24) & 255), - ((addr >> 16) & 255), - ((addr >> 8) & 255), - ((addr ) & 255), + if (ip_len == 1) + printf("%d.%d.%d.%d", + ((addr[0] >> 24) & 255), + ((addr[0] >> 16) & 255), + ((addr[0] >> 8) & 255), + ((addr[0] ) & 255)); + else { + for (i=0; i<4; i++) { + if (addr[i]) + printf("%d.%d.%d.%d", + ((addr[i] >> 24) & 255), + ((addr[i] >> 16) & 255), + ((addr[i] >> 8) & 255), + ((addr[i] ) & 255)); + putchar(i < 3 ? ':' : '\0'); + } + } + printf("/%d : %s\n", subnet_bits, (node->state == ALLOW) ? "allow" : (node->state == DENY) ? "deny" : "as parent"); if (node->extended) { for (i=0; i<16; i++) { - sub_node = &((*(node->extended))[i]); - new_addr = addr | ((unsigned long) i << shift); - print_node(sub_node, new_addr, shift - 4, subnet_bits + 4); + sub_node = &(node->extended[i]); + new_addr[0] = addr[0]; + new_addr[1] = addr[1]; + new_addr[2] = addr[2]; + new_addr[3] = addr[3]; + new_addr[ip_len - 1 - shift / 32] |= ((uint32_t)i << (shift % 32)); + print_node(sub_node, new_addr, ip_len, shift - 4, subnet_bits + 4); } } return; @@ -346,11 +415,15 @@ static void print_node(TableNode *node, unsigned long addr, int shift, int subne static void print_table(ADF_AuthTable table) { - unsigned long addr = 0; - int shift = 28; - int subnet_bits = 0; + uint32_t addr[4]; - print_node(&table->base, addr, shift, subnet_bits); + memset(addr, 0, sizeof (addr)); + printf("IPv4 table:\n"); + print_node(&table->base4, addr, 1, 28, 0); + + memset(addr, 0, sizeof (addr)); + printf("IPv6 table:\n"); + print_node(&table->base6, addr, 4, 124, 0); return; } @@ -358,13 +431,41 @@ static void print_table(ADF_AuthTable table) int main (int argc, char **argv) { + IPAddr ip; ADF_AuthTable table; table = ADF_CreateTable(); - ADF_Allow(table, 0x7e800000, 9); - ADF_Deny(table, 0x7ecc0000, 14); - /* ADF_Deny(table, 0x7f000001, 32); */ - /* ADF_Allow(table, 0x7f000000, 8); */ + ip.family = IPADDR_INET4; + + ip.addr.in4 = 0x7e800000; + ADF_Allow(table, &ip, 9); + ip.addr.in4 = 0x7ecc0000; + ADF_Deny(table, &ip, 14); +#if 0 + ip.addr.in4 = 0x7f000001; + ADF_Deny(table, &ip, 32); + ip.addr.in4 = 0x7f000000; + ADF_Allow(table, &ip, 8); +#endif + + printf("allowed: %d\n", ADF_IsAllowed(table, &ip)); + ip.addr.in4 ^= 1; + printf("allowed: %d\n", ADF_IsAllowed(table, &ip)); + + ip.family = IPADDR_INET6; + + memcpy(ip.addr.in6, "abcdefghijklmnop", 16); + ADF_Deny(table, &ip, 66); + ADF_Allow(table, &ip, 59); + + memcpy(ip.addr.in6, "xbcdefghijklmnop", 16); + ADF_Deny(table, &ip, 128); + ip.addr.in6[15] ^= 3; + ADF_Allow(table, &ip, 127); + + printf("allowed: %d\n", ADF_IsAllowed(table, &ip)); + ip.addr.in4 ^= 1; + printf("allowed: %d\n", ADF_IsAllowed(table, &ip)); print_table(table); diff --git a/addrfilt.h b/addrfilt.h index f96f0fb..42e8350 100644 --- a/addrfilt.h +++ b/addrfilt.h @@ -31,6 +31,8 @@ #ifndef GOT_ADDRFILT_H #define GOT_ADDRFILT_H +#include "addressing.h" + typedef struct ADF_AuthTableInst *ADF_AuthTable; typedef enum { @@ -45,25 +47,25 @@ extern ADF_AuthTable ADF_CreateTable(void); /* Allow anything in the supplied subnet, EXCEPT for any more specific subnets that are already defined */ extern ADF_Status ADF_Allow(ADF_AuthTable table, - unsigned long ip, + IPAddr *ip, int subnet_bits); /* Allow anything in the supplied subnet, overwriting existing definitions for any more specific subnets */ extern ADF_Status ADF_AllowAll(ADF_AuthTable table, - unsigned long ip, + IPAddr *ip, int subnet_bits); /* Deny anything in the supplied subnet, EXCEPT for any more specific subnets that are already defined */ extern ADF_Status ADF_Deny(ADF_AuthTable table, - unsigned long ip, + IPAddr *ip, int subnet_bits); /* Deny anything in the supplied subnet, overwriting existing definitions for any more specific subnets */ extern ADF_Status ADF_DenyAll(ADF_AuthTable table, - unsigned long ip, + IPAddr *ip, int subnet_bits); /* Clear up the table */ @@ -72,6 +74,6 @@ extern void ADF_DestroyTable(ADF_AuthTable table); /* Check whether a given IP address is allowed by the rules in the table */ extern int ADF_IsAllowed(ADF_AuthTable table, - unsigned long ip); + IPAddr *ip); #endif /* GOT_ADDRFILT_H */ diff --git a/broadcast.c b/broadcast.c index 35df56f..f177e32 100644 --- a/broadcast.c +++ b/broadcast.c @@ -132,7 +132,7 @@ timeout_handler(void *arbitrary) /* ================================================== */ void -BRD_AddDestination(unsigned long addr, unsigned short port, int interval) +BRD_AddDestination(IPAddr *addr, unsigned short port, int interval) { if (max_destinations == n_destinations) { /* Expand array */ @@ -144,8 +144,8 @@ 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.ip_addr = *addr; + destinations[n_destinations].addr.local_ip_addr.family = IPADDR_UNSPEC; destinations[n_destinations].addr.port = port; destinations[n_destinations].interval = interval; diff --git a/broadcast.h b/broadcast.h index 01013bc..21650c8 100644 --- a/broadcast.h +++ b/broadcast.h @@ -31,9 +31,11 @@ #ifndef GOT_BROADCAST_H #define GOT_BROADCAST_H +#include "addressing.h" + extern void BRD_Initialise(void); extern void BRD_Finalise(void); -extern void BRD_AddDestination(unsigned long addr, unsigned short port, int interval); +extern void BRD_AddDestination(IPAddr *addr, unsigned short port, int interval); #endif /* GOT_BROADCAST_H */ diff --git a/candm.h b/candm.h index c0d05cb..52f58d3 100644 --- a/candm.h +++ b/candm.h @@ -34,6 +34,7 @@ #define GOT_CANDM_H #include "sysincl.h" +#include "addressing.h" /* This is the default port to use for CANDM, if no alternative is defined */ @@ -96,33 +97,33 @@ transmitted for each packet type. */ typedef struct { - uint32_t mask; - uint32_t address; + IPAddr mask; + IPAddr address; int32_t EOR; } REQ_Online; typedef struct { - uint32_t mask; - uint32_t address; + IPAddr mask; + IPAddr address; int32_t EOR; } REQ_Offline; typedef struct { - uint32_t mask; - uint32_t address; + IPAddr mask; + IPAddr address; int32_t n_good_samples; int32_t n_total_samples; int32_t EOR; } REQ_Burst; typedef struct { - uint32_t address; + IPAddr address; int32_t new_minpoll; int32_t EOR; } REQ_Modify_Minpoll; typedef struct { - uint32_t address; + IPAddr address; int32_t new_maxpoll; int32_t EOR; } REQ_Modify_Maxpoll; @@ -133,13 +134,13 @@ typedef struct { } REQ_Dump; typedef struct { - uint32_t address; + IPAddr address; int32_t new_max_delay; int32_t EOR; } REQ_Modify_Maxdelay; typedef struct { - uint32_t address; + IPAddr address; int32_t new_max_delay_ratio; int32_t EOR; } REQ_Modify_Maxdelayratio; @@ -184,18 +185,18 @@ typedef struct { } REQ_Rekey; typedef struct { - uint32_t ip; + IPAddr ip; int32_t subnet_bits; int32_t EOR; } REQ_Allow_Deny; typedef struct { - uint32_t ip; + IPAddr ip; int32_t EOR; } REQ_Ac_Check; typedef struct { - uint32_t ip_addr; + IPAddr ip_addr; uint32_t port; int32_t minpoll; int32_t maxpoll; @@ -209,7 +210,7 @@ typedef struct { } REQ_NTP_Source; typedef struct { - uint32_t ip_addr; + IPAddr ip_addr; int32_t EOR; } REQ_Del_Source; @@ -250,7 +251,7 @@ typedef struct { } REQ_CycleLogs; typedef struct { - uint32_t ip; + IPAddr ip; uint32_t bits_specd; } REQ_SubnetsAccessed_Subnet; @@ -263,11 +264,11 @@ typedef struct { /* This is based on the response size rather than the request size */ -#define MAX_CLIENT_ACCESSES 16 +#define MAX_CLIENT_ACCESSES 8 typedef struct { uint32_t n_clients; - uint32_t client_ips[MAX_CLIENT_ACCESSES]; + IPAddr client_ips[MAX_CLIENT_ACCESSES]; } REQ_ClientAccesses; typedef struct { @@ -310,9 +311,11 @@ typedef struct { Version 3 : NTP_Source message lengthened (auto_offline) + Version 4 : IPv6 addressing added + */ -#define PROTO_VERSION_NUMBER 3 +#define PROTO_VERSION_NUMBER 4 /* ================================================== */ @@ -419,6 +422,7 @@ typedef struct { #define STT_BADRTCFILE 14 #define STT_INACTIVE 15 #define STT_BADSAMPLE 16 +#define STT_INVALIDAF 17 typedef struct { int32_t EOR; @@ -440,7 +444,7 @@ typedef struct { #define RPY_SD_ST_OTHER 4 typedef struct { - uint32_t ip_addr; + IPAddr ip_addr; uint16_t poll; uint16_t stratum; uint16_t state; @@ -472,7 +476,7 @@ typedef struct { } RPY_Tracking; typedef struct { - uint32_t ip_addr; + IPAddr ip_addr; uint32_t n_samples; uint32_t n_runs; uint32_t span_seconds; @@ -500,7 +504,7 @@ typedef struct { } RPY_ManualTimestamp; typedef struct { - uint32_t ip; + IPAddr ip; uint32_t bits_specd; uint32_t bitmap[8]; } RPY_SubnetsAccessed_Subnet; @@ -511,7 +515,7 @@ typedef struct { } RPY_SubnetsAccessed; typedef struct { - uint32_t ip; + IPAddr ip; uint32_t client_hits; uint32_t peer_hits; uint32_t cmd_hits_auth; diff --git a/client.c b/client.c index bd250fe..de074e1 100644 --- a/client.c +++ b/client.c @@ -58,8 +58,16 @@ /* ================================================== */ +union sockaddr_in46 { + struct sockaddr_in in4; +#ifdef HAVE_IPV6 + struct sockaddr_in6 in6; +#endif + struct sockaddr u; +}; + static int sock_fd; -struct sockaddr_in his_addr; +union sockaddr_in46 his_addr; static int on_terminal = 0; @@ -137,62 +145,64 @@ read_line(void) } -/* ================================================== */ - -static unsigned long -get_address(const char *hostname) -{ - char *address0; - struct hostent *host; - unsigned long result; - - /* Note, this call could block for a while */ - host = gethostbyname(hostname); - if (host == NULL) { - fprintf(stderr, "Could not get IP address for %s\n", hostname); - exit(1); - } else { - address0 = host->h_addr_list[0]; - result = ((((unsigned long) address0[0] & 0xff) << 24) | - (((unsigned long) address0[1] & 0xff) << 16) | - (((unsigned long) address0[2] & 0xff) << 8) | - (((unsigned long) address0[3] & 0xff))); - } - - return result; - -} - /* ================================================== */ /* Initialise the socket used to talk to the daemon */ static void open_io(const char *hostname, int port) { - struct sockaddr_in my_addr; + union sockaddr_in46 my_addr; + IPAddr ip; + + /* Note, this call could block for a while */ + if (!DNS_Name2IPAddress(hostname, &ip, 0)) { + fprintf(stderr, "Could not get IP address for %s\n", hostname); + exit(1); + } + + memset(&my_addr, 0, sizeof (my_addr)); + memset(&his_addr, 0, sizeof (his_addr)); + + switch (ip.family) { + case IPADDR_INET4: + sock_fd = socket(AF_INET, SOCK_DGRAM, 0); + + my_addr.in4.sin_family = AF_INET; + my_addr.in4.sin_port = htons(INADDR_ANY); + my_addr.in4.sin_addr.s_addr = htonl(INADDR_ANY); + + his_addr.in4.sin_family = AF_INET; + his_addr.in4.sin_addr.s_addr = htonl(ip.addr.in4); + his_addr.in4.sin_port = htons(port); + break; +#ifdef HAVE_IPV6 + case IPADDR_INET6: + sock_fd = socket(AF_INET6, SOCK_DGRAM, 0); + + my_addr.in6.sin6_family = AF_INET6; + my_addr.in6.sin6_port = htons(INADDR_ANY); + my_addr.in6.sin6_addr = in6addr_any; + + his_addr.in6.sin6_family = AF_INET6; + memcpy(his_addr.in6.sin6_addr.s6_addr, ip.addr.in6, + sizeof (his_addr.in6.sin6_addr.s6_addr)); + his_addr.in6.sin6_port = htons(port); + break; +#endif + default: + assert(0); + } - sock_fd = socket(AF_INET, SOCK_DGRAM, 0); if (sock_fd < 0) { perror("Can't create socket"); exit(1); } - my_addr.sin_family = AF_INET; - my_addr.sin_port = htons(INADDR_ANY); - my_addr.sin_addr.s_addr = htonl(INADDR_ANY); - - if(bind(sock_fd, (struct sockaddr *) &my_addr, sizeof(my_addr)) < 0) { + if(bind(sock_fd, &my_addr.u, sizeof(my_addr)) < 0) { perror("Can't bind socket"); exit(1); } - /* Build the socket address structure for sending packets */ - his_addr.sin_family = AF_INET; - his_addr.sin_addr.s_addr = htonl(get_address(hostname)); - - /* Eventually the port number needs to be a command line param */ - his_addr.sin_port = htons(port); - return; } @@ -208,34 +218,78 @@ close_io(void) /* ================================================== */ -static int -read_mask_address(char *line, unsigned long *mask, unsigned long *address) +static void +bits_to_mask(int bits, int family, IPAddr *mask) { - unsigned int ma, mb, mc, md, aa, ab, ac, ad; - int ok = 0; - char *p; + int i; + + mask->family = family; + switch (family) { + case IPADDR_INET4: + if (bits < 0) + bits = 32; + if (bits > 0) { + mask->addr.in4 = -1; + mask->addr.in4 <<= 32 - bits; + } else { + mask->addr.in4 = 0; + } + break; + case IPADDR_INET6: + if (bits > 128 || bits < 0) + bits = 128; + for (i = 0; i < bits / 8; i++) + mask->addr.in6[i] = 0xff; + if (i < 16) + mask->addr.in6[i++] = (0xff << (8 - bits % 8)) & 0xff; + for (; i < 16; i++) + mask->addr.in6[i] = 0x0; + break; + default: + assert(0); + } +} + +/* ================================================== */ + +static int +read_mask_address(char *line, IPAddr *mask, IPAddr *address) +{ + unsigned int bits; + char *p, *q; p = line; while (*p && isspace((unsigned char)*p)) p++; if (!*p) { - *mask = *address = 0; - ok = 1; + mask->family = address->family = IPADDR_UNSPEC; + return 1; } else { - - if (sscanf(line, "%u.%u.%u.%u/%u.%u.%u.%u", - &ma, &mb, &mc, &md, - &aa, &ab, &ac, &ad) != 8) { - fprintf(stderr, "Invalid syntax for mask/address\n"); - ok = 0; + q = strchr(p, '/'); + if (q) { + *q++ = 0; + if (UTI_StringToIP(p, mask)) { + p = q; + while (*q && !isspace((unsigned char)*q)) q++; + *q = 0; + if (UTI_StringToIP(p, address)) { + if (address->family == mask->family) + return 1; + } else if (sscanf(p, "%u", &bits) == 1) { + *address = *mask; + bits_to_mask(bits, address->family, mask); + return 1; + } + } } else { - *mask = (ma << 24) | (mb << 16) | (mc << 8) | md; - *address = (aa << 24) | (ab << 16) | (ac << 8) | ad; - ok = 1; + if (UTI_StringToIP(p, address)) { + bits_to_mask(-1, address->family, mask); + return 1; + } } } - return ok; - + fprintf(stderr, "Invalid syntax for mask/address\n"); + return 0; } /* ================================================== */ @@ -243,12 +297,12 @@ read_mask_address(char *line, unsigned long *mask, unsigned long *address) static int process_cmd_offline(CMD_Request *msg, char *line) { - unsigned long mask, address; + IPAddr mask, address; int ok; if (read_mask_address(line, &mask, &address)) { - msg->data.offline.mask = htonl(mask); - msg->data.offline.address = htonl(address); + UTI_IPHostToNetwork(&mask, &msg->data.offline.mask); + UTI_IPHostToNetwork(&address, &msg->data.offline.address); msg->command = htons(REQ_OFFLINE); ok = 1; } else { @@ -265,12 +319,12 @@ process_cmd_offline(CMD_Request *msg, char *line) static int process_cmd_online(CMD_Request *msg, char *line) { - unsigned long mask, address; + IPAddr mask, address; int ok; if (read_mask_address(line, &mask, &address)) { - msg->data.online.mask = htonl(mask); - msg->data.online.address = htonl(address); + UTI_IPHostToNetwork(&mask, &msg->data.online.mask); + UTI_IPHostToNetwork(&address, &msg->data.online.address); msg->command = htons(REQ_ONLINE); ok = 1; } else { @@ -284,7 +338,7 @@ process_cmd_online(CMD_Request *msg, char *line) /* ================================================== */ static int -read_address_integer(char *line, unsigned long *address, int *value) +read_address_integer(char *line, IPAddr *address, int *value) { char hostname[2048]; int ok = 0; @@ -293,8 +347,7 @@ read_address_integer(char *line, unsigned long *address, int *value) fprintf(stderr, "Invalid syntax for address value\n"); ok = 0; } else { - *address = DNS_Name2IPAddress(hostname); - if (*address == DNS_Failed_Address) { + if (!DNS_Name2IPAddress(hostname, address, 0)) { fprintf(stderr, "Could not get address for hostname\n"); ok = 0; } else { @@ -310,7 +363,7 @@ read_address_integer(char *line, unsigned long *address, int *value) /* ================================================== */ static int -read_address_double(char *line, unsigned long *address, double *value) +read_address_double(char *line, IPAddr *address, double *value) { char hostname[2048]; int ok = 0; @@ -319,8 +372,7 @@ read_address_double(char *line, unsigned long *address, double *value) fprintf(stderr, "Invalid syntax for address value\n"); ok = 0; } else { - *address = DNS_Name2IPAddress(hostname); - if (*address == DNS_Failed_Address) { + if (!DNS_Name2IPAddress(hostname, address, 0)) { fprintf(stderr, "Could not get address for hostname\n"); ok = 0; } else { @@ -338,12 +390,12 @@ read_address_double(char *line, unsigned long *address, double *value) static int process_cmd_minpoll(CMD_Request *msg, char *line) { - unsigned long address; + IPAddr address; int minpoll; int ok; if (read_address_integer(line, &address, &minpoll)) { - msg->data.modify_minpoll.address = htonl(address); + UTI_IPHostToNetwork(&address, &msg->data.modify_minpoll.address); msg->data.modify_minpoll.new_minpoll = htonl(minpoll); msg->command = htons(REQ_MODIFY_MINPOLL); ok = 1; @@ -360,12 +412,12 @@ process_cmd_minpoll(CMD_Request *msg, char *line) static int process_cmd_maxpoll(CMD_Request *msg, char *line) { - unsigned long address; + IPAddr address; int maxpoll; int ok; if (read_address_integer(line, &address, &maxpoll)) { - msg->data.modify_maxpoll.address = htonl(address); + UTI_IPHostToNetwork(&address, &msg->data.modify_maxpoll.address); msg->data.modify_maxpoll.new_maxpoll = htonl(maxpoll); msg->command = htons(REQ_MODIFY_MAXPOLL); ok = 1; @@ -382,12 +434,12 @@ process_cmd_maxpoll(CMD_Request *msg, char *line) static int process_cmd_maxdelay(CMD_Request *msg, char *line) { - unsigned long address; + IPAddr address; double max_delay; int ok; if (read_address_double(line, &address, &max_delay)) { - msg->data.modify_maxdelay.address = htonl(address); + UTI_IPHostToNetwork(&address, &msg->data.modify_maxdelay.address); msg->data.modify_maxdelay.new_max_delay = REAL2WIRE(max_delay); msg->command = htons(REQ_MODIFY_MAXDELAY); ok = 1; @@ -404,12 +456,12 @@ process_cmd_maxdelay(CMD_Request *msg, char *line) static int process_cmd_maxdelayratio(CMD_Request *msg, char *line) { - unsigned long address; + IPAddr address; double max_delay_ratio; int ok; if (read_address_double(line, &address, &max_delay_ratio)) { - msg->data.modify_maxdelayratio.address = htonl(address); + UTI_IPHostToNetwork(&address, &msg->data.modify_maxdelayratio.address); msg->data.modify_maxdelayratio.new_max_delay_ratio = REAL2WIRE(max_delay_ratio); msg->command = htons(REQ_MODIFY_MAXDELAYRATIO); ok = 1; @@ -478,36 +530,28 @@ process_cmd_cyclelogs(CMD_Request *msg, char *line) static int process_cmd_burst(CMD_Request *msg, char *line) { - int ok; int n_good_samples, n_total_samples; - unsigned int ma, mb, mc, md, aa, ab, ac, ad; int n_parsed; + char s[101]; + IPAddr address, mask; - n_parsed = sscanf(line, "%d/%d %u.%u.%u.%u/%u.%u.%u.%u", - &n_good_samples, - &n_total_samples, - &ma, &mb, &mc, &md, - &aa, &ab, &ac, &ad); + n_parsed = sscanf(line, "%d/%d %100s", &n_good_samples, &n_total_samples, s); msg->command = htons(REQ_BURST); msg->data.burst.n_good_samples = ntohl(n_good_samples); msg->data.burst.n_total_samples = ntohl(n_total_samples); - if (n_parsed == 10) { - msg->data.burst.mask = htonl((ma << 24) | (mb << 16) | (mc << 8) | md); - msg->data.burst.address = htonl((aa << 24) | (ab << 16) | (ac << 8) | ad); - ok = 1; - } else if (n_parsed == 2) { - msg->data.burst.mask = 0; - msg->data.burst.address = 0; - ok = 1; - } else { - ok = 0; + mask.family = address.family = IPADDR_UNSPEC; + + if (n_parsed < 2 || (n_parsed == 3 && !read_mask_address(s, &mask, &address))) { fprintf(stderr, "Invalid syntax for burst command\n"); + return 0; } - return ok; + UTI_IPHostToNetwork(&mask, &msg->data.burst.mask); + UTI_IPHostToNetwork(&address, &msg->data.burst.address); + return 1; } /* ================================================== */ @@ -574,66 +618,81 @@ process_cmd_manual(CMD_Request *msg, const char *line) static int parse_allow_deny(CMD_Request *msg, char *line) { - unsigned long a, b, c, d, n, ip; + unsigned long a, b, c, d, n; + IPAddr ip; char *p, *q; p = line; while (*p && isspace((unsigned char)*p)) p++; if (!*p) { /* blank line - applies to all addresses */ - msg->data.allow_deny.ip = htonl(0); + ip.family = IPADDR_UNSPEC; + UTI_IPHostToNetwork(&ip, &msg->data.allow_deny.ip); msg->data.allow_deny.subnet_bits = htonl(0); } else { char *slashpos; slashpos = strchr(p, '/'); if (slashpos) *slashpos = 0; - n = sscanf(p, "%lu.%lu.%lu.%lu", &a, &b, &c, &d); + n = 0; + if (!UTI_StringToIP(p, &ip) && + (n = sscanf(p, "%lu.%lu.%lu.%lu", &a, &b, &c, &d)) == 0) { - if (n == 0) { /* Try to parse as the name of a machine */ q = p; while (*q) { if (*q == '\n') *q = 0; q++; } - ip = DNS_Name2IPAddress(p); - if (ip == DNS_Failed_Address) { + if (!DNS_Name2IPAddress(p, &ip, 0)) { fprintf(stderr, "Could not read address\n"); return 0; } else { - msg->data.allow_deny.ip = htonl(ip); - msg->data.allow_deny.subnet_bits = htonl(32); + UTI_IPHostToNetwork(&ip, &msg->data.allow_deny.ip); + if (ip.family == IPADDR_INET6) + msg->data.allow_deny.subnet_bits = htonl(128); + else + msg->data.allow_deny.subnet_bits = htonl(32); } } else { - a &= 0xff; - b &= 0xff; - c &= 0xff; - d &= 0xff; - - switch (n) { - case 1: - msg->data.allow_deny.ip = htonl((a<<24)); - msg->data.allow_deny.subnet_bits = htonl(8); - break; - case 2: - msg->data.allow_deny.ip = htonl((a<<24) | (b<<16)); - msg->data.allow_deny.subnet_bits = htonl(16); - break; - case 3: - msg->data.allow_deny.ip = htonl((a<<24) | (b<<16) | (c<<8)); - msg->data.allow_deny.subnet_bits = htonl(24); - break; - case 4: - msg->data.allow_deny.ip = htonl((a<<24) | (b<<16) | (c<<8) | d); + if (n == 0) { + if (ip.family == IPADDR_INET6) + msg->data.allow_deny.subnet_bits = htonl(128); + else msg->data.allow_deny.subnet_bits = htonl(32); - break; - default: - assert(0); - + } else { + ip.family = IPADDR_INET4; + + a &= 0xff; + b &= 0xff; + c &= 0xff; + d &= 0xff; + + switch (n) { + case 1: + ip.addr.in4 = htonl((a<<24)); + msg->data.allow_deny.subnet_bits = htonl(8); + break; + case 2: + ip.addr.in4 = htonl((a<<24) | (b<<16)); + msg->data.allow_deny.subnet_bits = htonl(16); + break; + case 3: + ip.addr.in4 = htonl((a<<24) | (b<<16) | (c<<8)); + msg->data.allow_deny.subnet_bits = htonl(24); + break; + case 4: + ip.addr.in4 = htonl((a<<24) | (b<<16) | (c<<8) | d); + msg->data.allow_deny.subnet_bits = htonl(32); + break; + default: + assert(0); + } } + UTI_IPHostToNetwork(&ip, &msg->data.allow_deny.ip); + if (slashpos) { int specified_subnet_bits, n; n = sscanf(slashpos+1, "%d", &specified_subnet_bits); @@ -739,9 +798,10 @@ process_cmd_cmddenyall(CMD_Request *msg, char *line) /* ================================================== */ static int -accheck_getaddr(char *line, unsigned long *addr) +accheck_getaddr(char *line, IPAddr *addr) { - unsigned long a, b, c, d, ip; + unsigned long a, b, c, d; + IPAddr ip; char *p, *q; p = line; while (*p && isspace(*p)) p++; @@ -749,7 +809,8 @@ accheck_getaddr(char *line, unsigned long *addr) return 0; } else { if (sscanf(p, "%lu.%lu.%lu.%lu", &a, &b, &c, &d) == 4) { - *addr = (a<<24) | (b<<16) | (c<<8) | d; + addr->family = IPADDR_INET4; + addr->addr.in4 = (a<<24) | (b<<16) | (c<<8) | d; return 1; } else { q = p; @@ -757,8 +818,7 @@ accheck_getaddr(char *line, unsigned long *addr) if (*q == '\n') *q = 0; q++; } - ip = DNS_Name2IPAddress(p); - if (ip == DNS_Failed_Address) { + if (!DNS_Name2IPAddress(p, &ip, 0)) { return 0; } else { *addr = ip; @@ -773,10 +833,10 @@ accheck_getaddr(char *line, unsigned long *addr) static int process_cmd_accheck(CMD_Request *msg, char *line) { - unsigned long ip; + IPAddr ip; msg->command = htons(REQ_ACCHECK); if (accheck_getaddr(line, &ip)) { - msg->data.ac_check.ip = htonl(ip); + UTI_IPHostToNetwork(&ip, &msg->data.ac_check.ip); return 1; } else { fprintf(stderr, "Could not read address\n"); @@ -789,10 +849,10 @@ process_cmd_accheck(CMD_Request *msg, char *line) static int process_cmd_cmdaccheck(CMD_Request *msg, char *line) { - unsigned long ip; + IPAddr ip; msg->command = htons(REQ_CMDACCHECK); if (accheck_getaddr(line, &ip)) { - msg->data.ac_check.ip = htonl(ip); + UTI_IPHostToNetwork(&ip, &msg->data.ac_check.ip); return 1; } else { fprintf(stderr, "Could not read address\n"); @@ -866,7 +926,7 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line) switch (status) { case CPS_Success: msg->data.ntp_source.port = htonl((unsigned long) data.port); - msg->data.ntp_source.ip_addr = htonl(data.ip_addr); + UTI_IPHostToNetwork(&data.ip_addr, &msg->data.ntp_source.ip_addr); msg->data.ntp_source.minpoll = htonl(data.params.minpoll); msg->data.ntp_source.maxpoll = htonl(data.params.maxpoll); msg->data.ntp_source.presend_minpoll = htonl(data.params.presend_minpoll); @@ -935,7 +995,7 @@ process_cmd_delete(CMD_Request *msg, char *line) { char hostname[2048]; int ok = 0; - unsigned long address = 0UL; + IPAddr address; msg->command = htons(REQ_DEL_SOURCE); @@ -943,8 +1003,7 @@ process_cmd_delete(CMD_Request *msg, char *line) fprintf(stderr, "Invalid syntax for address\n"); ok = 0; } else { - address = DNS_Name2IPAddress(hostname); - if (address == DNS_Failed_Address) { + if (!DNS_Name2IPAddress(hostname, &address, 0)) { fprintf(stderr, "Could not get address for hostname\n"); ok = 0; } else { @@ -952,7 +1011,7 @@ process_cmd_delete(CMD_Request *msg, char *line) } } - msg->data.del_source.ip_addr = htonl(address); + UTI_IPHostToNetwork(&address, &msg->data.del_source.ip_addr); return ok; @@ -1121,7 +1180,7 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok) { unsigned long tx_sequence; socklen_t where_from_len; - struct sockaddr_in where_from; + union sockaddr_in46 where_from; int bad_length, bad_sender, bad_sequence, bad_header; int select_status; int recvfrom_status; @@ -1168,7 +1227,7 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok) #endif if (sendto(sock_fd, (void *) request, command_length, 0, - (struct sockaddr *) &his_addr, sizeof(his_addr)) < 0) { + &his_addr.u, sizeof(his_addr)) < 0) { #if 0 @@ -1210,7 +1269,7 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok) where_from_len = sizeof(where_from); recvfrom_status = recvfrom(sock_fd, (void *) reply, sizeof(CMD_Reply), 0, - (struct sockaddr *) &where_from, &where_from_len); + &where_from.u, &where_from_len); #if 0 @@ -1231,8 +1290,17 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok) expected_length = PKL_ReplyLength(reply); bad_length = (read_length != expected_length); - bad_sender = ((where_from.sin_addr.s_addr != his_addr.sin_addr.s_addr) || - (where_from.sin_port != his_addr.sin_port)); + bad_sender = (where_from.u.sa_family != his_addr.u.sa_family || + (where_from.u.sa_family == AF_INET && + (where_from.in4.sin_addr.s_addr != his_addr.in4.sin_addr.s_addr || + where_from.in4.sin_port != his_addr.in4.sin_port)) || +#ifdef HAVE_IPV6 + (where_from.u.sa_family == AF_INET6 && + (memcmp(where_from.in6.sin6_addr.s6_addr, his_addr.in6.sin6_addr.s6_addr, + sizeof (where_from.in6.sin6_addr.s6_addr)) != 0 || + where_from.in6.sin6_port != his_addr.in6.sin6_port)) || +#endif + 0); if (!bad_length) { bad_sequence = (ntohl(reply->sequence) != tx_sequence); @@ -1382,13 +1450,12 @@ process_cmd_sources(char *line) int verbose = 0; int32_t orig_latest_meas, latest_meas, est_offset; - uint32_t ip_addr; + IPAddr ip_addr; uint32_t latest_meas_err, est_offset_err; uint32_t latest_meas_ago; uint16_t poll, stratum; uint16_t state, mode; double resid_freq, resid_skew; - const char *dns_lookup; char hostname_buf[32]; uint16_t status; @@ -1439,7 +1506,7 @@ process_cmd_sources(char *line) if (submit_ok) { if (ntohs(reply.status) == STT_SUCCESS) { - ip_addr = ntohl(reply.data.source_data.ip_addr); + UTI_IPNetworkToHost(&reply.data.source_data.ip_addr, &ip_addr); poll = ntohs(reply.data.source_data.poll); stratum = ntohs(reply.data.source_data.stratum); state = ntohs(reply.data.source_data.state); @@ -1453,14 +1520,13 @@ process_cmd_sources(char *line) resid_freq = (double) ((long) ntohl(reply.data.source_data.resid_freq)) * 1.0e-3; resid_skew = (double) (ntohl(reply.data.source_data.resid_skew)) * 1.0e-3; - hostname_buf[25] = 0; if (mode == RPY_SD_MD_REF) { - snprintf(hostname_buf, sizeof(hostname_buf), "%s", UTI_RefidToString(ip_addr)); + snprintf(hostname_buf, sizeof(hostname_buf), "%s", UTI_RefidToString(ip_addr.addr.in4)); } else if (no_dns) { - snprintf(hostname_buf, sizeof(hostname_buf), "%s", UTI_IPToDottedQuad(ip_addr)); + snprintf(hostname_buf, sizeof(hostname_buf), "%s", UTI_IPToString(&ip_addr)); } else { - dns_lookup = DNS_IPAddress2Name(ip_addr); - strncpy(hostname_buf, dns_lookup, 25); + DNS_IPAddress2Name(&ip_addr, hostname_buf, sizeof(hostname_buf)); + hostname_buf[25] = 0; } switch (mode) { @@ -1515,12 +1581,11 @@ process_cmd_sourcestats(char *line) int n_sources, i; int verbose = 0; - const char *dns_lookup; char hostname_buf[32]; unsigned long n_samples, n_runs, span_seconds; double resid_freq_ppm, skew_ppm; unsigned long sd_us; - unsigned long ip_addr; + IPAddr ip_addr; unsigned short status; verbose = check_for_verbose_flag(line); @@ -1569,7 +1634,7 @@ process_cmd_sourcestats(char *line) if (submit_ok) { if (ntohs(reply.status) == STT_SUCCESS) { - ip_addr = ntohl(reply.data.sourcestats.ip_addr); + UTI_IPNetworkToHost(&reply.data.sourcestats.ip_addr, &ip_addr); n_samples = ntohl(reply.data.sourcestats.n_samples); n_runs = ntohl(reply.data.sourcestats.n_runs); span_seconds = ntohl(reply.data.sourcestats.span_seconds); @@ -1577,12 +1642,11 @@ process_cmd_sourcestats(char *line) skew_ppm = WIRE2REAL(reply.data.sourcestats.skew_ppm); sd_us = ntohl(reply.data.sourcestats.sd_us); - hostname_buf[25] = 0; if (no_dns) { - snprintf(hostname_buf, sizeof(hostname_buf), "%s", UTI_IPToDottedQuad(ip_addr)); + snprintf(hostname_buf, sizeof(hostname_buf), "%s", UTI_IPToString(&ip_addr)); } else { - dns_lookup = DNS_IPAddress2Name(ip_addr); - strncpy(hostname_buf, dns_lookup, 25); + DNS_IPAddress2Name(&ip_addr, hostname_buf, sizeof(hostname_buf)); + hostname_buf[25] = 0; } printf("%-25s %2lu %2lu ", hostname_buf, n_samples, n_runs); @@ -1644,9 +1708,10 @@ process_cmd_tracking(char *line) b = (ref_id >> 16) & 0xff; c = (ref_id >> 8) & 0xff; d = (ref_id) & 0xff; + printf("Reference ID : %lu.%lu.%lu.%lu (%s)\n", - a, b, c, d, - (no_dns) ? UTI_IPToDottedQuad(ref_id) : DNS_IPAddress2Name(ref_id)); + a, b, c, d, ""); + //* TODO (no_dns) ? UTI_IPToDottedQuad(ref_id) : DNS_IPAddress2Name(ref_id)); */ printf("Stratum : %lu\n", (unsigned long) ntohl(reply.data.tracking.stratum)); ref_time.tv_sec = ntohl(reply.data.tracking.ref_time_s); ref_time.tv_usec = ntohl(reply.data.tracking.ref_time_us); @@ -1766,7 +1831,6 @@ process_cmd_clients(char *line) unsigned long last_ntp_hit_ago; unsigned long last_cmd_hit_ago; char hostname_buf[32]; - const char *dns_lookup; int n_replies; @@ -1922,9 +1986,8 @@ process_cmd_clients(char *line) snprintf(hostname_buf, sizeof(hostname_buf), "%s", UTI_IPToDottedQuad(ip)); } else { - dns_lookup = DNS_IPAddress2Name(ip); + DNS_IPAddress2Name(ip, hostname_buf, sizeof(hostname_buf)); hostname_buf[25] = 0; - strncpy(hostname_buf, dns_lookup, 25); } printf("%-25s %6d %6d %6d %6d %6d ", hostname_buf, @@ -1988,7 +2051,7 @@ process_cmd_clients(char *line) int status; unsigned long next_index; int j; - unsigned long ip; + IPAddr ip; unsigned long client_hits; unsigned long peer_hits; unsigned long cmd_hits_auth; @@ -1997,7 +2060,6 @@ process_cmd_clients(char *line) unsigned long last_ntp_hit_ago; unsigned long last_cmd_hit_ago; char hostname_buf[32]; - const char *dns_lookup; int n_replies; int n_indices_in_table; @@ -2025,9 +2087,9 @@ process_cmd_clients(char *line) goto finished; } for (j=0; jaddr.in6[i * 4 + 0] << 24 | + ip->addr.in6[i * 4 + 1] << 16 | + ip->addr.in6[i * 4 + 2] << 8 | + ip->addr.in6[i * 4 + 3]; +} + +/* ================================================== */ + +inline static uint32_t +get_subnet(uint32_t *addr, unsigned int where) +{ + int off; + + off = where / 32; + where %= 32; + + return (addr[off] >> (32 - NBITS - where)) & ((1UL << NBITS) - 1); +} + +/* ================================================== */ + + static void clear_subnet(Subnet *subnet) { @@ -118,7 +148,8 @@ clear_node(Node *node) void CLG_Initialise(void) { - clear_subnet(&top_subnet); + clear_subnet(&top_subnet4); + clear_subnet(&top_subnet6); if (CNF_GetNoClientLog()) { active = 0; } else { @@ -178,27 +209,18 @@ create_node(Subnet *parent_subnet, int the_entry) expanding subnet tables and node entries as we go if necessary. */ static void * -find_subnet(Subnet *subnet, CLG_IP_Addr addr, int bits_left) +find_subnet(Subnet *subnet, uint32_t *addr, int addr_len, int bits_consumed) { - unsigned long this_subnet, new_subnet, mask, shift; - unsigned long new_bits_left; - - shift = 32 - NBITS; - mask = (1UL<> shift; - new_subnet = (addr & mask) << NBITS; - new_bits_left = bits_left - NBITS; + uint32_t this_subnet; -#if 0 - fprintf(stderr, "fs addr=%08lx bl=%d ma=%08lx this=%08lx newsn=%08lx nbl=%d\n", - addr, bits_left, mask, this_subnet, new_subnet, new_bits_left); -#endif + this_subnet = get_subnet(addr, bits_consumed); + bits_consumed += NBITS; - if (new_bits_left > 0) { + if (bits_consumed < 32 * addr_len) { if (!subnet->entry[this_subnet]) { create_subnet(subnet, this_subnet); } - return find_subnet((Subnet *) subnet->entry[this_subnet], new_subnet, new_bits_left); + return find_subnet((Subnet *) subnet->entry[this_subnet], addr, addr_len, bits_consumed); } else { if (!subnet->entry[this_subnet]) { create_node(subnet, this_subnet); @@ -213,30 +235,21 @@ find_subnet(Subnet *subnet, CLG_IP_Addr addr, int bits_left) one of the parents does not exist - never open a node out */ static void * -find_subnet_dont_open(Subnet *subnet, CLG_IP_Addr addr, int bits_left) +find_subnet_dont_open(Subnet *subnet, uint32_t *addr, int addr_len, int bits_consumed) { - unsigned long this_subnet, new_subnet, mask, shift; - unsigned long new_bits_left; + uint32_t this_subnet; - if (bits_left == 0) { + if (bits_consumed >= 32 * addr_len) { return subnet; } else { - shift = 32 - NBITS; - mask = (1UL<> shift; - new_subnet = (addr & mask) << NBITS; - new_bits_left = bits_left - NBITS; + this_subnet = get_subnet(addr, bits_consumed); + bits_consumed += NBITS; -#if 0 - fprintf(stderr, "fsdo addr=%08lx bl=%d this=%08lx newsn=%08lx nbl=%d\n", - addr, bits_left, this_subnet, new_subnet, new_bits_left); -#endif - if (!subnet->entry[this_subnet]) { return NULL; } else { - return find_subnet_dont_open((Subnet *) subnet->entry[this_subnet], new_subnet, new_bits_left); + return find_subnet_dont_open((Subnet *) subnet->entry[this_subnet], addr, addr_len, bits_consumed); } } } @@ -244,12 +257,25 @@ find_subnet_dont_open(Subnet *subnet, CLG_IP_Addr addr, int bits_left) /* ================================================== */ void -CLG_LogNTPClientAccess (CLG_IP_Addr client, time_t now) +CLG_LogNTPClientAccess (IPAddr *client, time_t now) { + uint32_t ip6[4]; Node *node; + if (active) { - node = (Node *) find_subnet(&top_subnet, client, 32); - node->ip_addr = client; + switch (client->family) { + case IPADDR_INET4: + node = (Node *) find_subnet(&top_subnet4, &client->addr.in4, 1, 0); + break; + case IPADDR_INET6: + split_ip6(client, ip6); + node = (Node *) find_subnet(&top_subnet6, ip6, 4, 0); + break; + default: + assert(0); + } + + node->ip_addr = *client; ++node->client_hits; node->last_ntp_hit = now; } @@ -258,12 +284,25 @@ CLG_LogNTPClientAccess (CLG_IP_Addr client, time_t now) /* ================================================== */ void -CLG_LogNTPPeerAccess(CLG_IP_Addr client, time_t now) +CLG_LogNTPPeerAccess(IPAddr *client, time_t now) { + uint32_t ip6[4]; Node *node; + if (active) { - node = (Node *) find_subnet(&top_subnet, client, 32); - node->ip_addr = client; + switch (client->family) { + case IPADDR_INET4: + node = (Node *) find_subnet(&top_subnet4, &client->addr.in4, 1, 0); + break; + case IPADDR_INET6: + split_ip6(client, ip6); + node = (Node *) find_subnet(&top_subnet6, ip6, 4, 0); + break; + default: + assert(0); + } + + node->ip_addr = *client; ++node->peer_hits; node->last_ntp_hit = now; } @@ -272,12 +311,25 @@ CLG_LogNTPPeerAccess(CLG_IP_Addr client, time_t now) /* ================================================== */ void -CLG_LogCommandAccess(CLG_IP_Addr client, CLG_Command_Type type, time_t now) +CLG_LogCommandAccess(IPAddr *client, CLG_Command_Type type, time_t now) { + uint32_t ip6[4]; Node *node; + if (active) { - node = (Node *) find_subnet(&top_subnet, client, 32); - node->ip_addr = client; + switch (client->family) { + case IPADDR_INET4: + node = (Node *) find_subnet(&top_subnet4, &client->addr.in4, 1, 0); + break; + case IPADDR_INET6: + split_ip6(client, ip6); + node = (Node *) find_subnet(&top_subnet6, ip6, 4, 0); + break; + default: + assert(0); + } + + node->ip_addr = *client; node->last_cmd_hit = now; switch (type) { case CLG_CMD_AUTH: @@ -299,16 +351,32 @@ CLG_LogCommandAccess(CLG_IP_Addr client, CLG_Command_Type type, time_t now) /* ================================================== */ CLG_Status -CLG_GetSubnetBitmap(CLG_IP_Addr subnet, int bits, CLG_Bitmap result) +CLG_GetSubnetBitmap(IPAddr *subnet, int bits, CLG_Bitmap result) { Subnet *s; + uint32_t ip6[4]; unsigned long i; unsigned long word, bit, mask; - if ((bits == 0) || (bits == 8) || (bits == 16) || (bits == 24)) { + if (bits >= 0 && bits % 8 == 0) { memset (result, 0, TABLE_SIZE/8); if (active) { - s = find_subnet_dont_open(&top_subnet, subnet, bits); + switch (subnet->family) { + case IPADDR_INET4: + if (bits >= 32) + return CLG_BADSUBNET; + s = find_subnet_dont_open(&top_subnet4, &subnet->addr.in4, 1, 32 - bits); + break; + case IPADDR_INET6: + if (bits >= 128) + return CLG_BADSUBNET; + split_ip6(subnet, ip6); + s = find_subnet_dont_open(&top_subnet6, ip6, 4, 128 - bits); + break; + default: + return CLG_BADSUBNET; + } + if (s) { for (i=0; i<256; i++) { if (s->entry[i]) { @@ -333,15 +401,26 @@ CLG_GetSubnetBitmap(CLG_IP_Addr subnet, int bits, CLG_Bitmap result) /* ================================================== */ CLG_Status -CLG_GetClientAccessReportByIP(unsigned long ip, RPT_ClientAccess_Report *report, time_t now) +CLG_GetClientAccessReportByIP(IPAddr *ip, RPT_ClientAccess_Report *report, time_t now) { + uint32_t ip6[4]; Node *node; if (!active) { return CLG_INACTIVE; } else { - node = (Node *) find_subnet_dont_open(&top_subnet, ip, 32); - + switch (ip->family) { + case IPADDR_INET4: + node = (Node *) find_subnet_dont_open(&top_subnet4, &ip->addr.in4, 1, 0); + break; + case IPADDR_INET6: + split_ip6(ip, ip6); + node = (Node *) find_subnet_dont_open(&top_subnet6, ip6, 4, 0); + break; + default: + return CLG_EMPTYSUBNET; + } + if (!node) { return CLG_EMPTYSUBNET; } else { diff --git a/clientlog.h b/clientlog.h index ab7c470..0df9de8 100644 --- a/clientlog.h +++ b/clientlog.h @@ -35,15 +35,13 @@ #include "sysincl.h" #include "reports.h" -typedef unsigned long CLG_IP_Addr; - /* Enough to hold flags for 256 hosts in a class C */ typedef uint32_t CLG_Bitmap[8]; extern void CLG_Initialise(void); extern void CLG_Finalise(void); -extern void CLG_LogNTPClientAccess(CLG_IP_Addr client, time_t now); -extern void CLG_LogNTPPeerAccess(CLG_IP_Addr client, time_t now); +extern void CLG_LogNTPClientAccess(IPAddr *client, time_t now); +extern void CLG_LogNTPPeerAccess(IPAddr *client, time_t now); /* When logging command packets, there are several subtypes */ @@ -53,7 +51,7 @@ typedef enum { CLG_CMD_BAD_PKT /* bad version or packet length */ } CLG_Command_Type; -extern void CLG_LogCommandAccess(CLG_IP_Addr client, CLG_Command_Type type, time_t now); +extern void CLG_LogCommandAccess(IPAddr *client, CLG_Command_Type type, time_t now); /* And some reporting functions, for use by chronyc. */ /* TBD */ @@ -70,10 +68,10 @@ typedef enum { known. For bits=24, flag which hosts in that subnet are known. Other values, return 0 (failed) */ -extern CLG_Status CLG_GetSubnetBitmap(CLG_IP_Addr subnet, int bits, CLG_Bitmap result); +extern CLG_Status CLG_GetSubnetBitmap(IPAddr *subnet, int bits, CLG_Bitmap result); extern CLG_Status -CLG_GetClientAccessReportByIP(unsigned long ip, RPT_ClientAccess_Report *report, time_t now); +CLG_GetClientAccessReportByIP(IPAddr *ip, RPT_ClientAccess_Report *report, time_t now); CLG_Status CLG_GetClientAccessReportByIndex(int index, RPT_ClientAccessByIndex_Report *report, @@ -83,7 +81,7 @@ CLG_GetClientAccessReportByIndex(int index, RPT_ClientAccessByIndex_Report *repo that has accessed us since 'since'. */ extern void CLG_IterateNTPClients -(void (*fn)(CLG_IP_Addr client, void *arb), +(void (*fn)(IPAddr *client, void *arb), void *arb, time_t since); diff --git a/cmdmon.c b/cmdmon.c index f5e3c8b..0408755 100644 --- a/cmdmon.c +++ b/cmdmon.c @@ -54,8 +54,19 @@ /* ================================================== */ -/* File descriptor for command and monitoring socket */ -static int sock_fd; +union sockaddr_in46 { + struct sockaddr_in in4; +#ifdef HAVE_IPV6 + struct sockaddr_in6 in6; +#endif + struct sockaddr u; +}; + +/* File descriptors for command and monitoring sockets */ +static int sock_fd4; +#ifdef HAVE_IPV6 +static int sock_fd6; +#endif /* Flag indicating whether this module has been initialised or not */ static int initialised = 0; @@ -157,17 +168,93 @@ static ADF_AuthTable access_auth_table; /* ================================================== */ /* Forward prototypes */ +static int prepare_socket(int family); static void read_from_cmd_socket(void *anything); /* ================================================== */ +static int +prepare_socket(int family) +{ + int port_number, sock_fd; + union sockaddr_in46 my_addr; + IPAddr bind_address; + int on_off = 1; + + port_number = CNF_GetCommandPort(); + if (port_number < 0) { + port_number = DEFAULT_CANDM_PORT; + } + + sock_fd = socket(family, SOCK_DGRAM, 0); + if (sock_fd < 0) { + LOG(LOGS_ERR, LOGF_CmdMon, "Could not open socket : %s", strerror(errno)); + return -1; + } + + /* Allow reuse of port number */ + if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on_off, sizeof(on_off)) < 0) { + LOG(LOGS_ERR, LOGF_CmdMon, "Could not set socket options"); + /* Don't quit - we might survive anyway */ + } +#ifdef HAVE_IPV6 + if (family == AF_INET6) { +#ifdef IPV6_V6ONLY + /* Receive IPv6 packets only */ + if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on_off, sizeof(on_off)) < 0) { + LOG(LOGS_ERR, LOGF_NtpIO, "Could not request IPV6_V6ONLY socket option"); + } +#endif + } +#endif + + memset(&my_addr, 0, sizeof (my_addr)); + + switch (family) { + case AF_INET: + my_addr.in4.sin_family = family; + my_addr.in4.sin_port = htons((unsigned short)port_number); + + CNF_GetBindCommandAddress(IPADDR_INET4, &bind_address); + + if (bind_address.family == IPADDR_INET4) + my_addr.in4.sin_addr.s_addr = htonl(bind_address.addr.in4); + else + my_addr.in4.sin_addr.s_addr = htonl(INADDR_ANY); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + my_addr.in6.sin6_family = family; + my_addr.in6.sin6_port = htons((unsigned short)port_number); + + CNF_GetBindCommandAddress(IPADDR_INET6, &bind_address); + + if (bind_address.family == IPADDR_INET6) + memcpy(my_addr.in6.sin6_addr.s6_addr, bind_address.addr.in6, + sizeof (my_addr.in6.sin6_addr.s6_addr)); + else + my_addr.in6.sin6_addr = in6addr_any; + break; +#endif + default: + assert(0); + } + + if (bind(sock_fd, &my_addr.u, sizeof(my_addr)) < 0) { + LOG_FATAL(LOGF_CmdMon, "Could not bind socket : %s", strerror(errno)); + } + + /* Register handler for read events on the socket */ + SCH_AddInputFileHandler(sock_fd, read_from_cmd_socket, (void *)(long)sock_fd); + + return sock_fd; +} + +/* ================================================== */ + void CAM_Initialise(void) { - int port_number; - struct sockaddr_in my_addr; - unsigned long bind_address; - int on_off = 1; if (initialised) { CROAK("Shouldn't be initialised"); @@ -188,40 +275,19 @@ CAM_Initialise(void) free_replies = NULL; kept_replies.next = NULL; - port_number = CNF_GetCommandPort(); - if (port_number < 0) { - port_number = DEFAULT_CANDM_PORT; + sock_fd4 = prepare_socket(AF_INET); +#ifdef HAVE_IPV6 + sock_fd6 = prepare_socket(AF_INET6); +#endif + + if (sock_fd4 < 0 +#ifdef HAVE_IPV6 + && sock_fd6 < 0 +#endif + ) { + LOG_FATAL(LOGF_CmdMon, "Could not open any command socket"); } - sock_fd = socket(AF_INET, SOCK_DGRAM, 0); - if (sock_fd < 0) { - LOG_FATAL(LOGF_CmdMon, "Could not open socket : %s", strerror(errno)); - } - - /* Allow reuse of port number */ - if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on_off, sizeof(on_off)) < 0) { - LOG(LOGS_ERR, LOGF_CmdMon, "Could not set socket options"); - /* Don't quit - we might survive anyway */ - } - - my_addr.sin_family = AF_INET; - my_addr.sin_port = htons((unsigned short) port_number); - - CNF_GetBindCommandAddress(&bind_address); - - if (bind_address != 0UL) { - my_addr.sin_addr.s_addr = htonl(bind_address); - } else { - my_addr.sin_addr.s_addr = htonl(INADDR_ANY); - } - - if (bind(sock_fd, (struct sockaddr *) &my_addr, sizeof(my_addr)) < 0) { - LOG_FATAL(LOGF_CmdMon, "Could not bind socket : %s", strerror(errno)); - } - - /* Register handler for read events on the socket */ - SCH_AddInputFileHandler(sock_fd, read_from_cmd_socket, NULL); - access_auth_table = ADF_CreateTable(); } @@ -231,9 +297,18 @@ CAM_Initialise(void) void CAM_Finalise(void) { - SCH_RemoveInputFileHandler(sock_fd); - close(sock_fd); - sock_fd = -1; + if (sock_fd4 >= 0) { + SCH_RemoveInputFileHandler(sock_fd4); + close(sock_fd4); + } + sock_fd4 = -1; +#ifdef HAVE_IPV6 + if (sock_fd6 >= 0) { + SCH_RemoveInputFileHandler(sock_fd6); + close(sock_fd6); + } + sock_fd6 = -1; +#endif ADF_DestroyTable(access_auth_table); @@ -644,21 +719,51 @@ print_reply_packet(CMD_Reply *pkt) /* ================================================== */ static void -transmit_reply(CMD_Reply *msg, struct sockaddr_in *where_to) +transmit_reply(CMD_Reply *msg, union sockaddr_in46 *where_to) { int status; int tx_message_length; - unsigned long remote_ip; - unsigned short remote_port; + int sock_fd; + + switch (where_to->u.sa_family) { + case AF_INET: + sock_fd = sock_fd4; + break; +#ifdef HAVE_IPV6 + case AF_INET6: + sock_fd = sock_fd6; + break; +#endif + default: + assert(0); + } tx_message_length = PKL_ReplyLength(msg); status = sendto(sock_fd, (void *) msg, tx_message_length, 0, - (struct sockaddr *) where_to, sizeof(struct sockaddr_in)); + &where_to->u, sizeof(union sockaddr_in46)); if (status < 0) { - remote_ip = ntohl(where_to->sin_addr.s_addr); - remote_port = ntohs(where_to->sin_port); - LOG(LOGS_WARN, LOGF_CmdMon, "Could not send response to %s:%hu", UTI_IPToDottedQuad(remote_ip), remote_port); + unsigned short port; + IPAddr ip; + + switch (where_to->u.sa_family) { + case AF_INET: + ip.family = IPADDR_INET4; + ip.addr.in4 = ntohl(where_to->in4.sin_addr.s_addr); + port = ntohs(where_to->in4.sin_port); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + ip.family = IPADDR_INET6; + memcpy(ip.addr.in6, (where_to->in6.sin6_addr.s6_addr), sizeof(ip.addr.in6)); + port = ntohs(where_to->in6.sin6_port); + break; +#endif + default: + assert(0); + } + + LOG(LOGS_WARN, LOGF_CmdMon, "Could not send response to %s:%hu", UTI_IPToString(&ip), port); } return; @@ -679,7 +784,10 @@ static void handle_online(CMD_Request *rx_message, CMD_Reply *tx_message) { int status; - status = NSR_TakeSourcesOnline(ntohl(rx_message->data.online.mask), ntohl(rx_message->data.online.address)); + IPAddr address, mask; + UTI_IPNetworkToHost(&rx_message->data.online.mask, &mask); + UTI_IPNetworkToHost(&rx_message->data.online.address, &address); + status = NSR_TakeSourcesOnline(&mask, &address); if (status) { tx_message->status = htons(STT_SUCCESS); } else { @@ -693,7 +801,10 @@ static void handle_offline(CMD_Request *rx_message, CMD_Reply *tx_message) { int status; - status = NSR_TakeSourcesOffline(ntohl(rx_message->data.offline.mask), ntohl(rx_message->data.offline.address)); + IPAddr address, mask; + UTI_IPNetworkToHost(&rx_message->data.offline.mask, &mask); + UTI_IPNetworkToHost(&rx_message->data.offline.address, &address); + status = NSR_TakeSourcesOffline(&mask, &address); if (status) { tx_message->status = htons(STT_SUCCESS); } else { @@ -707,10 +818,12 @@ static void handle_burst(CMD_Request *rx_message, CMD_Reply *tx_message) { int status; + IPAddr address, mask; + UTI_IPNetworkToHost(&rx_message->data.burst.mask, &mask); + UTI_IPNetworkToHost(&rx_message->data.burst.address, &address); status = NSR_InitiateSampleBurst(ntohl(rx_message->data.burst.n_good_samples), ntohl(rx_message->data.burst.n_total_samples), - ntohl(rx_message->data.burst.mask), - ntohl(rx_message->data.burst.address)); + &mask, &address); if (status) { tx_message->status = htons(STT_SUCCESS); @@ -725,7 +838,9 @@ static void handle_modify_minpoll(CMD_Request *rx_message, CMD_Reply *tx_message) { int status; - status = NSR_ModifyMinpoll(ntohl(rx_message->data.modify_minpoll.address), + IPAddr address; + UTI_IPNetworkToHost(&rx_message->data.modify_minpoll.address, &address); + status = NSR_ModifyMinpoll(&address, ntohl(rx_message->data.modify_minpoll.new_minpoll)); if (status) { @@ -741,7 +856,9 @@ static void handle_modify_maxpoll(CMD_Request *rx_message, CMD_Reply *tx_message) { int status; - status = NSR_ModifyMaxpoll(ntohl(rx_message->data.modify_minpoll.address), + IPAddr address; + UTI_IPNetworkToHost(&rx_message->data.modify_minpoll.address, &address); + status = NSR_ModifyMaxpoll(&address, ntohl(rx_message->data.modify_minpoll.new_minpoll)); if (status) { @@ -757,7 +874,9 @@ static void handle_modify_maxdelay(CMD_Request *rx_message, CMD_Reply *tx_message) { int status; - status = NSR_ModifyMaxdelay(ntohl(rx_message->data.modify_maxdelay.address), + IPAddr address; + UTI_IPNetworkToHost(&rx_message->data.modify_maxdelay.address, &address); + status = NSR_ModifyMaxdelay(&address, WIRE2REAL(rx_message->data.modify_maxdelay.new_max_delay)); if (status) { tx_message->status = htons(STT_SUCCESS); @@ -772,7 +891,9 @@ static void handle_modify_maxdelayratio(CMD_Request *rx_message, CMD_Reply *tx_message) { int status; - status = NSR_ModifyMaxdelayratio(ntohl(rx_message->data.modify_maxdelayratio.address), + IPAddr address; + UTI_IPNetworkToHost(&rx_message->data.modify_maxdelayratio.address, &address); + status = NSR_ModifyMaxdelayratio(&address, WIRE2REAL(rx_message->data.modify_maxdelayratio.new_max_delay_ratio)); if (status) { tx_message->status = htons(STT_SUCCESS); @@ -884,7 +1005,7 @@ handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message) tx_message->status = htons(STT_SUCCESS); tx_message->reply = htons(RPY_SOURCE_DATA); - tx_message->data.source_data.ip_addr = htonl(report.ip_addr); + UTI_IPHostToNetwork(&report.ip_addr, &tx_message->data.source_data.ip_addr); tx_message->data.source_data.stratum = htons(report.stratum); tx_message->data.source_data.poll = htons(report.poll); switch (report.state) { @@ -943,11 +1064,11 @@ handle_rekey(CMD_Request *rx_message, CMD_Reply *tx_message) static void handle_allow(CMD_Request *rx_message, CMD_Reply *tx_message) { - unsigned long ip; + IPAddr ip; int subnet_bits; - ip = ntohl(rx_message->data.allow_deny.ip); + UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip); subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits); - if (NCR_AddAccessRestriction(ip, subnet_bits, 1, 0)) { + if (NCR_AddAccessRestriction(&ip, subnet_bits, 1, 0)) { tx_message->status = htons(STT_SUCCESS); } else { tx_message->status = htons(STT_BADSUBNET); @@ -959,11 +1080,11 @@ handle_allow(CMD_Request *rx_message, CMD_Reply *tx_message) static void handle_allowall(CMD_Request *rx_message, CMD_Reply *tx_message) { - unsigned long ip; + IPAddr ip; int subnet_bits; - ip = ntohl(rx_message->data.allow_deny.ip); + UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip); subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits); - if (NCR_AddAccessRestriction(ip, subnet_bits, 1, 1)) { + if (NCR_AddAccessRestriction(&ip, subnet_bits, 1, 1)) { tx_message->status = htons(STT_SUCCESS); } else { tx_message->status = htons(STT_BADSUBNET); @@ -975,11 +1096,11 @@ handle_allowall(CMD_Request *rx_message, CMD_Reply *tx_message) static void handle_deny(CMD_Request *rx_message, CMD_Reply *tx_message) { - unsigned long ip; + IPAddr ip; int subnet_bits; - ip = ntohl(rx_message->data.allow_deny.ip); + UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip); subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits); - if (NCR_AddAccessRestriction(ip, subnet_bits, 0, 0)) { + if (NCR_AddAccessRestriction(&ip, subnet_bits, 0, 0)) { tx_message->status = htons(STT_SUCCESS); } else { tx_message->status = htons(STT_BADSUBNET); @@ -991,11 +1112,11 @@ handle_deny(CMD_Request *rx_message, CMD_Reply *tx_message) static void handle_denyall(CMD_Request *rx_message, CMD_Reply *tx_message) { - unsigned long ip; + IPAddr ip; int subnet_bits; - ip = ntohl(rx_message->data.allow_deny.ip); + UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip); subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits); - if (NCR_AddAccessRestriction(ip, subnet_bits, 0, 1)) { + if (NCR_AddAccessRestriction(&ip, subnet_bits, 0, 1)) { tx_message->status = htons(STT_SUCCESS); } else { tx_message->status = htons(STT_BADSUBNET); @@ -1007,11 +1128,11 @@ handle_denyall(CMD_Request *rx_message, CMD_Reply *tx_message) static void handle_cmdallow(CMD_Request *rx_message, CMD_Reply *tx_message) { - unsigned long ip; + IPAddr ip; int subnet_bits; - ip = ntohl(rx_message->data.allow_deny.ip); + UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip); subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits); - if (CAM_AddAccessRestriction(ip, subnet_bits, 1, 0)) { + if (CAM_AddAccessRestriction(&ip, subnet_bits, 1, 0)) { tx_message->status = htons(STT_SUCCESS); } else { tx_message->status = htons(STT_BADSUBNET); @@ -1023,11 +1144,11 @@ handle_cmdallow(CMD_Request *rx_message, CMD_Reply *tx_message) static void handle_cmdallowall(CMD_Request *rx_message, CMD_Reply *tx_message) { - unsigned long ip; + IPAddr ip; int subnet_bits; - ip = ntohl(rx_message->data.allow_deny.ip); + UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip); subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits); - if (CAM_AddAccessRestriction(ip, subnet_bits, 1, 1)) { + if (CAM_AddAccessRestriction(&ip, subnet_bits, 1, 1)) { tx_message->status = htons(STT_SUCCESS); } else { tx_message->status = htons(STT_BADSUBNET); @@ -1039,11 +1160,11 @@ handle_cmdallowall(CMD_Request *rx_message, CMD_Reply *tx_message) static void handle_cmddeny(CMD_Request *rx_message, CMD_Reply *tx_message) { - unsigned long ip; + IPAddr ip; int subnet_bits; - ip = ntohl(rx_message->data.allow_deny.ip); + UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip); subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits); - if (CAM_AddAccessRestriction(ip, subnet_bits, 0, 0)) { + if (CAM_AddAccessRestriction(&ip, subnet_bits, 0, 0)) { tx_message->status = htons(STT_SUCCESS); } else { tx_message->status = htons(STT_BADSUBNET); @@ -1055,11 +1176,11 @@ handle_cmddeny(CMD_Request *rx_message, CMD_Reply *tx_message) static void handle_cmddenyall(CMD_Request *rx_message, CMD_Reply *tx_message) { - unsigned long ip; + IPAddr ip; int subnet_bits; - ip = ntohl(rx_message->data.allow_deny.ip); + UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip); subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits); - if (CAM_AddAccessRestriction(ip, subnet_bits, 0, 1)) { + if (CAM_AddAccessRestriction(&ip, subnet_bits, 0, 1)) { tx_message->status = htons(STT_SUCCESS); } else { tx_message->status = htons(STT_BADSUBNET); @@ -1071,9 +1192,9 @@ handle_cmddenyall(CMD_Request *rx_message, CMD_Reply *tx_message) static void handle_accheck(CMD_Request *rx_message, CMD_Reply *tx_message) { - unsigned long ip; - ip = ntohl(rx_message->data.ac_check.ip); - if (NCR_CheckAccessRestriction(ip)) { + IPAddr ip; + UTI_IPNetworkToHost(&rx_message->data.ac_check.ip, &ip); + if (NCR_CheckAccessRestriction(&ip)) { tx_message->status = htons(STT_ACCESSALLOWED); } else { tx_message->status = htons(STT_ACCESSDENIED); @@ -1085,9 +1206,9 @@ handle_accheck(CMD_Request *rx_message, CMD_Reply *tx_message) static void handle_cmdaccheck(CMD_Request *rx_message, CMD_Reply *tx_message) { - unsigned long ip; - ip = ntohl(rx_message->data.ac_check.ip); - if (CAM_CheckAccessRestriction(ip)) { + IPAddr ip; + UTI_IPNetworkToHost(&rx_message->data.ac_check.ip, &ip); + if (CAM_CheckAccessRestriction(&ip)) { tx_message->status = htons(STT_ACCESSALLOWED); } else { tx_message->status = htons(STT_ACCESSDENIED); @@ -1103,8 +1224,8 @@ handle_add_server(CMD_Request *rx_message, CMD_Reply *tx_message) SourceParameters params; NSR_Status status; - rem_addr.ip_addr = ntohl(rx_message->data.ntp_source.ip_addr); - rem_addr.local_ip_addr = 0; + UTI_IPNetworkToHost(&rx_message->data.ntp_source.ip_addr, &rem_addr.ip_addr); + rem_addr.local_ip_addr.family = IPADDR_UNSPEC; 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); @@ -1125,6 +1246,9 @@ handle_add_server(CMD_Request *rx_message, CMD_Reply *tx_message) case NSR_TooManySources: tx_message->status = htons(STT_TOOMANYSOURCES); break; + case NSR_InvalidAF: + tx_message->status = htons(STT_INVALIDAF); + break; case NSR_NoSuchSource: CROAK("Impossible"); break; @@ -1140,8 +1264,8 @@ handle_add_peer(CMD_Request *rx_message, CMD_Reply *tx_message) SourceParameters params; NSR_Status status; - rem_addr.ip_addr = ntohl(rx_message->data.ntp_source.ip_addr); - rem_addr.local_ip_addr = 0; + UTI_IPNetworkToHost(&rx_message->data.ntp_source.ip_addr, &rem_addr.ip_addr); + rem_addr.local_ip_addr.family = IPADDR_UNSPEC; 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); @@ -1161,6 +1285,9 @@ handle_add_peer(CMD_Request *rx_message, CMD_Reply *tx_message) case NSR_TooManySources: tx_message->status = htons(STT_TOOMANYSOURCES); break; + case NSR_InvalidAF: + tx_message->status = htons(STT_INVALIDAF); + break; case NSR_NoSuchSource: CROAK("Impossible"); break; @@ -1175,8 +1302,8 @@ handle_del_source(CMD_Request *rx_message, CMD_Reply *tx_message) NTP_Remote_Address rem_addr; NSR_Status status; - rem_addr.ip_addr = ntohl(rx_message->data.del_source.ip_addr); - rem_addr.local_ip_addr = 0; + UTI_IPNetworkToHost(&rx_message->data.del_source.ip_addr, &rem_addr.ip_addr); + rem_addr.local_ip_addr.family = IPADDR_UNSPEC; rem_addr.port = 0; status = NSR_RemoveSource(&rem_addr); @@ -1189,6 +1316,7 @@ handle_del_source(CMD_Request *rx_message, CMD_Reply *tx_message) break; case NSR_TooManySources: case NSR_AlreadyInUse: + case NSR_InvalidAF: CROAK("Impossible"); break; } @@ -1273,7 +1401,7 @@ handle_sourcestats(CMD_Request *rx_message, CMD_Reply *tx_message) if (status) { tx_message->status = htons(STT_SUCCESS); tx_message->reply = htons(RPY_SOURCESTATS); - tx_message->data.sourcestats.ip_addr = htonl(report.ip_addr); + UTI_IPHostToNetwork(&report.ip_addr, &tx_message->data.sourcestats.ip_addr); tx_message->data.sourcestats.n_samples = htonl(report.n_samples); tx_message->data.sourcestats.n_runs = htonl(report.n_runs); tx_message->data.sourcestats.span_seconds = htonl(report.span_seconds); @@ -1345,8 +1473,8 @@ static void handle_subnets_accessed(CMD_Request *rx_message, CMD_Reply *tx_message) { int i, j; - unsigned long ns; - unsigned long ip, bits_specd; + unsigned long ns, bits_specd; + IPAddr ip; CLG_Status result; ns = ntohl(rx_message->data.subnets_accessed.n_subnets); @@ -1355,13 +1483,13 @@ handle_subnets_accessed(CMD_Request *rx_message, CMD_Reply *tx_message) tx_message->data.subnets_accessed.n_subnets = htonl(ns); for (i=0; idata.subnets_accessed.subnets[i].ip); + UTI_IPNetworkToHost(&rx_message->data.subnets_accessed.subnets[i].ip, &ip); bits_specd = ntohl(rx_message->data.subnets_accessed.subnets[i].bits_specd); - tx_message->data.subnets_accessed.subnets[i].ip = htonl(ip); + UTI_IPHostToNetwork(&ip, &tx_message->data.subnets_accessed.subnets[i].ip); tx_message->data.subnets_accessed.subnets[i].bits_specd = htonl(bits_specd); - result = CLG_GetSubnetBitmap(ip, bits_specd, tx_message->data.subnets_accessed.subnets[i].bitmap); + result = CLG_GetSubnetBitmap(&ip, bits_specd, tx_message->data.subnets_accessed.subnets[i].bitmap); switch (result) { case CLG_SUCCESS: case CLG_EMPTYSUBNET: @@ -1394,7 +1522,7 @@ handle_client_accesses(CMD_Request *rx_message, CMD_Reply *tx_message) CLG_Status result; RPT_ClientAccess_Report report; unsigned long nc; - unsigned long ip; + IPAddr ip; int i; struct timeval now; double local_time_error; @@ -1409,10 +1537,10 @@ handle_client_accesses(CMD_Request *rx_message, CMD_Reply *tx_message) printf("%d %d\n", (int)sizeof(RPY_ClientAccesses_Client), (int)offsetof(CMD_Reply, data.client_accesses.clients)); for (i=0; idata.client_accesses.client_ips[i]); - tx_message->data.client_accesses.clients[i].ip = htonl(ip); + UTI_IPNetworkToHost(&rx_message->data.client_accesses.client_ips[i], &ip); + UTI_IPHostToNetwork(&ip, &tx_message->data.client_accesses.clients[i].ip); - result = CLG_GetClientAccessReportByIP(ip, &report, now.tv_sec); + result = CLG_GetClientAccessReportByIP(&ip, &report, now.tv_sec); switch (result) { case CLG_SUCCESS: tx_message->data.client_accesses.clients[i].client_hits = htonl(report.client_hits); @@ -1422,13 +1550,13 @@ handle_client_accesses(CMD_Request *rx_message, CMD_Reply *tx_message) tx_message->data.client_accesses.clients[i].cmd_hits_bad = htonl(report.cmd_hits_bad); tx_message->data.client_accesses.clients[i].last_ntp_hit_ago = htonl(report.last_ntp_hit_ago); tx_message->data.client_accesses.clients[i].last_cmd_hit_ago = htonl(report.last_cmd_hit_ago); - printf("%08lx %lu %lu %lu %lu %lu %lu %lu\n", ip, report.client_hits, report.peer_hits, report.cmd_hits_auth, report.cmd_hits_normal, report.cmd_hits_bad, report.last_ntp_hit_ago, report.last_cmd_hit_ago); + printf("%s %lu %lu %lu %lu %lu %lu %lu\n", UTI_IPToString(&ip), report.client_hits, report.peer_hits, report.cmd_hits_auth, report.cmd_hits_normal, report.cmd_hits_bad, report.last_ntp_hit_ago, report.last_cmd_hit_ago); break; case CLG_EMPTYSUBNET: /* Signal back to the client that this single client address - was unknown, by specifying the zero ip address, which will - always be invalid (hopefully) */ - tx_message->data.client_accesses.clients[i].ip = htonl(0); + was unknown */ + ip.family = IPADDR_UNSPEC; + UTI_IPHostToNetwork(&ip, &tx_message->data.client_accesses.clients[i].ip); break; case CLG_INACTIVE: tx_message->status = htons(STT_INACTIVE); @@ -1471,7 +1599,7 @@ handle_client_accesses_by_index(CMD_Request *rx_message, CMD_Reply *tx_message) switch (result) { case CLG_SUCCESS: - tx_message->data.client_accesses_by_index.clients[j].ip = htonl(report.ip_addr); + UTI_IPHostToNetwork(&report.ip_addr, &tx_message->data.client_accesses_by_index.clients[j].ip); tx_message->data.client_accesses_by_index.clients[j].client_hits = htonl(report.client_hits); tx_message->data.client_accesses_by_index.clients[j].peer_hits = htonl(report.peer_hits); tx_message->data.client_accesses_by_index.clients[j].cmd_hits_auth = htonl(report.cmd_hits_auth); @@ -1594,9 +1722,10 @@ read_from_cmd_socket(void *anything) CMD_Request rx_message; CMD_Reply tx_message, *prev_tx_message; int rx_message_length, tx_message_length; - struct sockaddr_in where_from; + int sock_fd; + union sockaddr_in46 where_from; socklen_t from_length; - unsigned long remote_ip; + IPAddr remote_ip; unsigned short remote_port; int md5_ok; int utoken_ok, token_ok; @@ -1617,14 +1746,14 @@ read_from_cmd_socket(void *anything) rx_message_length = sizeof(rx_message); from_length = sizeof(where_from); + sock_fd = (long)anything; status = recvfrom(sock_fd, (char *)&rx_message, rx_message_length, flags, - (struct sockaddr *)&where_from, &from_length); + &where_from.u, &from_length); if (status < 0) { - LOG(LOGS_WARN, LOGF_CmdMon, "Error [%s] reading from control socket (IP=%s port=%d)", - strerror(errno), - UTI_IPToDottedQuad(ntohl(where_from.sin_addr.s_addr)), - ntohs(where_from.sin_port)); + LOG(LOGS_WARN, LOGF_CmdMon, "Error [%s] reading from control socket %d", + strerror(errno), sock_fd); + return; } read_length = status; @@ -1650,12 +1779,31 @@ read_from_cmd_socket(void *anything) tx_message.token = htonl(0xffffffffUL); memset(&tx_message.auth, 0, sizeof(tx_message.auth)); - remote_ip = ntohl(where_from.sin_addr.s_addr); - remote_port = ntohs(where_from.sin_port); + switch (where_from.u.sa_family) { + case AF_INET: + remote_ip.family = IPADDR_INET4; + remote_ip.addr.in4 = ntohl(where_from.in4.sin_addr.s_addr); + remote_port = ntohs(where_from.in4.sin_port); + localhost = (remote_ip.addr.in4 == 0x7f000001UL); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + remote_ip.family = IPADDR_INET6; + memcpy(&remote_ip.addr.in6, where_from.in6.sin6_addr.s6_addr, + sizeof (remote_ip.addr.in6)); + remote_port = ntohs(where_from.in6.sin6_port); + /* Check for ::1 */ + for (localhost = 0; localhost < 16; localhost++) + if (remote_ip.addr.in6[localhost] != 0) + break; + localhost = (localhost == 15 && remote_ip.addr.in6[localhost] == 1); + break; +#endif + default: + assert(0); + } - localhost = (remote_ip == 0x7f000001UL); - - if ((!ADF_IsAllowed(access_auth_table, remote_ip)) && + if ((!ADF_IsAllowed(access_auth_table, &remote_ip)) && (!localhost)) { /* The client is not allowed access, so don't waste any more time on him. Note that localhost is always allowed access @@ -1667,7 +1815,7 @@ read_from_cmd_socket(void *anything) hitting us with bad packets until our log file(s) fill up. */ LOG(LOGS_WARN, LOGF_CmdMon, "Command packet received from unauthorised host %s port %d", - UTI_IPToDottedQuad(remote_ip), + UTI_IPToString(&remote_ip), remote_port); tx_message.status = htons(STT_NOHOSTACCESS); @@ -1678,8 +1826,8 @@ read_from_cmd_socket(void *anything) if (read_length != expected_length) { - LOG(LOGS_WARN, LOGF_CmdMon, "Read incorrectly sized packet from %s:%hu", UTI_IPToDottedQuad(remote_ip), remote_port); - CLG_LogCommandAccess(remote_ip, CLG_CMD_BAD_PKT, cooked_now.tv_sec); + LOG(LOGS_WARN, LOGF_CmdMon, "Read incorrectly sized packet from %s:%hu", UTI_IPToString(&remote_ip), remote_port); + CLG_LogCommandAccess(&remote_ip, CLG_CMD_BAD_PKT, cooked_now.tv_sec); /* For now, just ignore the packet. We may want to send a reply back eventually */ return; @@ -1691,7 +1839,7 @@ read_from_cmd_socket(void *anything) (rx_message.res2 != 0)) { /* We don't know how to process anything like this */ - CLG_LogCommandAccess(remote_ip, CLG_CMD_BAD_PKT, cooked_now.tv_sec); + CLG_LogCommandAccess(&remote_ip, CLG_CMD_BAD_PKT, cooked_now.tv_sec); return; } @@ -1773,7 +1921,7 @@ read_from_cmd_socket(void *anything) status = sendto(sock_fd, (void *) prev_tx_message, tx_message_length, 0, (struct sockaddr *) &where_from, sizeof(where_from)); if (status < 0) { - LOG(LOGS_WARN, LOGF_CmdMon, "Could not send response to %s:%hu", UTI_IPToDottedQuad(remote_ip), remote_port); + LOG(LOGS_WARN, LOGF_CmdMon, "Could not send response to %s:%hu", UTI_IPToString(&remote_ip), remote_port); } return; } @@ -1800,9 +1948,9 @@ read_from_cmd_socket(void *anything) authenticated = md5_ok & utoken_ok & token_ok; if (authenticated) { - CLG_LogCommandAccess(remote_ip, CLG_CMD_AUTH, cooked_now.tv_sec); + CLG_LogCommandAccess(&remote_ip, CLG_CMD_AUTH, cooked_now.tv_sec); } else { - CLG_LogCommandAccess(remote_ip, CLG_CMD_NORMAL, cooked_now.tv_sec); + CLG_LogCommandAccess(&remote_ip, CLG_CMD_NORMAL, cooked_now.tv_sec); } if (issue_token) { @@ -1895,7 +2043,7 @@ read_from_cmd_socket(void *anything) if (!issue_token) { LOG(LOGS_WARN, LOGF_CmdMon, "Bad command logon from %s port %d (md5_ok=%d valid_ts=%d)\n", - UTI_IPToDottedQuad(remote_ip), + UTI_IPToString(&remote_ip), remote_port, md5_ok, valid_ts); } @@ -2092,7 +2240,7 @@ read_from_cmd_socket(void *anything) /* ================================================== */ int -CAM_AddAccessRestriction(unsigned long ip_addr, int subnet_bits, int allow, int all) +CAM_AddAccessRestriction(IPAddr *ip_addr, int subnet_bits, int allow, int all) { ADF_Status status; @@ -2122,7 +2270,7 @@ CAM_AddAccessRestriction(unsigned long ip_addr, int subnet_bits, int allow, int /* ================================================== */ int -CAM_CheckAccessRestriction(unsigned long ip_addr) +CAM_CheckAccessRestriction(IPAddr *ip_addr) { return ADF_IsAllowed(access_auth_table, ip_addr); } diff --git a/cmdmon.h b/cmdmon.h index 7dcd539..9e63403 100644 --- a/cmdmon.h +++ b/cmdmon.h @@ -31,11 +31,13 @@ #ifndef GOT_CMDMON_H #define GOT_CMDMON_H +#include "addressing.h" + extern void CAM_Initialise(void); extern void CAM_Finalise(void); -extern int CAM_AddAccessRestriction(unsigned long ip_addr, int subnet_bits, int allow, int all); -extern int CAM_CheckAccessRestriction(unsigned long ip_addr); +extern int CAM_AddAccessRestriction(IPAddr *ip_addr, int subnet_bits, int allow, int all); +extern int CAM_CheckAccessRestriction(IPAddr *ip_addr); #endif /* GOT_CMDMON_H */ diff --git a/cmdparse.c b/cmdparse.c index e09db45..609f5ba 100644 --- a/cmdparse.c +++ b/cmdparse.c @@ -61,8 +61,7 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src) ok = 0; if (sscanf(line, "%" SMAXLEN "s%n", hostname, &n) == 1) { - src->ip_addr = DNS_Name2IPAddressRetry(hostname); - if (src->ip_addr != DNS_Failed_Address) { + if (DNS_Name2IPAddress(hostname, &src->ip_addr, 1)) { ok = 1; } } diff --git a/cmdparse.h b/cmdparse.h index 38cc74c..d9af657 100644 --- a/cmdparse.h +++ b/cmdparse.h @@ -32,6 +32,7 @@ #define GOT_CMDPARSE_H #include "srcparams.h" +#include "addressing.h" typedef enum { CPS_Success, @@ -47,7 +48,7 @@ typedef enum { } CPS_Status; typedef struct { - unsigned long ip_addr; + IPAddr ip_addr; unsigned short port; SourceParameters params; } CPS_NTP_Source; diff --git a/conf.c b/conf.c index 9bad6a1..2135c76 100644 --- a/conf.c +++ b/conf.c @@ -53,6 +53,7 @@ #include "acquire.h" #include "cmdparse.h" #include "broadcast.h" +#include "util.h" /* ================================================== */ @@ -136,7 +137,7 @@ static int n_init_srcs; than this, slew instead of stepping */ static int init_slew_threshold = -1; #define MAX_INIT_SRCS 8 -static unsigned long init_srcs_ip[MAX_INIT_SRCS]; +static IPAddr init_srcs_ip[MAX_INIT_SRCS]; static int enable_manual=0; @@ -156,13 +157,13 @@ static double mail_change_threshold = 0.0; memory */ static int no_client_log = 0; -/* IP address (host order) for binding the NTP socket to. 0 means INADDR_ANY +/* IP addresses for binding the NTP socket to. UNSPEC family means INADDR_ANY will be used */ -static unsigned long bind_address = 0UL; +static IPAddr bind_address4, bind_address6; -/* IP address (host order) for binding the command socket to. 0 means +/* IP addresses for binding the command socket to. UNSPEC family means use the value of bind_address */ -static unsigned long bind_cmd_address = 0UL; +static IPAddr bind_cmd_address4, bind_cmd_address6; /* Filename to use for storing pid of running chronyd, to prevent multiple * chronyds being started. */ @@ -243,7 +244,7 @@ typedef enum { typedef struct { NTP_Source_Type type; - unsigned long ip_addr; + IPAddr ip_addr; unsigned short port; SourceParameters params; } NTP_Source; @@ -263,7 +264,7 @@ static int n_refclock_sources = 0; typedef struct _AllowDeny { struct _AllowDeny *next; struct _AllowDeny *prev; - unsigned long ip; + IPAddr ip; int subnet_bits; int all; /* 1 to override existing more specific defns */ int allow; /* 0 for deny, 1 for allow */ @@ -697,7 +698,7 @@ parse_initstepslew(const char *line) char hostname[HOSTNAME_LEN+1]; int n; int threshold; - unsigned long ip_addr; + IPAddr ip_addr; n_init_srcs = 0; p = line; @@ -710,8 +711,7 @@ parse_initstepslew(const char *line) } while (*p) { if (sscanf(p, "%" SHOSTNAME_LEN "s%n", hostname, &n) == 1) { - ip_addr = DNS_Name2IPAddressRetry(hostname); - if (ip_addr != DNS_Failed_Address) { + if (DNS_Name2IPAddress(hostname, &ip_addr, 1)) { init_srcs_ip[n_init_srcs] = ip_addr; ++n_init_srcs; } @@ -803,7 +803,7 @@ parse_allow_deny(const char *line, AllowDeny *list, int allow) unsigned long a, b, c, d, n; int all = 0; AllowDeny *new_node = NULL; - unsigned long ip_addr; + IPAddr ip_addr; p = line; @@ -820,45 +820,54 @@ parse_allow_deny(const char *line, AllowDeny *list, int allow) new_node = MallocNew(AllowDeny); new_node->allow = allow; new_node->all = all; - new_node->ip = 0UL; + new_node->ip.family = IPADDR_UNSPEC; new_node->subnet_bits = 0; } else { char *slashpos; slashpos = strchr(p, '/'); if (slashpos) *slashpos = 0; - n = sscanf(p, "%lu.%lu.%lu.%lu", &a, &b, &c, &d); - - if (n >= 1) { + n = 0; + if (UTI_StringToIP(p, &ip_addr) || + (n = sscanf(p, "%lu.%lu.%lu.%lu", &a, &b, &c, &d)) >= 1) { new_node = MallocNew(AllowDeny); new_node->allow = allow; new_node->all = all; - a &= 0xff; - b &= 0xff; - c &= 0xff; - d &= 0xff; - - switch (n) { - case 1: - new_node->ip = (a<<24); - new_node->subnet_bits = 8; - break; - case 2: - new_node->ip = (a<<24) | (b<<16); - new_node->subnet_bits = 16; - break; - case 3: - new_node->ip = (a<<24) | (b<<16) | (c<<8); - new_node->subnet_bits = 24; - break; - case 4: - new_node->ip = (a<<24) | (b<<16) | (c<<8) | d; + if (n == 0) { + new_node->ip = ip_addr; + if (ip_addr.family == IPADDR_INET6) + new_node->subnet_bits = 128; + else new_node->subnet_bits = 32; - break; - default: - assert(0); - + } else { + new_node->ip.family = IPADDR_INET4; + + a &= 0xff; + b &= 0xff; + c &= 0xff; + d &= 0xff; + + switch (n) { + case 1: + new_node->ip.addr.in4 = (a<<24); + new_node->subnet_bits = 8; + break; + case 2: + new_node->ip.addr.in4 = (a<<24) | (b<<16); + new_node->subnet_bits = 16; + break; + case 3: + new_node->ip.addr.in4 = (a<<24) | (b<<16) | (c<<8); + new_node->subnet_bits = 24; + break; + case 4: + new_node->ip.addr.in4 = (a<<24) | (b<<16) | (c<<8) | d; + new_node->subnet_bits = 32; + break; + default: + assert(0); + } } if (slashpos) { @@ -872,13 +881,15 @@ parse_allow_deny(const char *line, AllowDeny *list, int allow) } } else { - ip_addr = DNS_Name2IPAddressRetry(p); - if (ip_addr != DNS_Failed_Address) { + if (DNS_Name2IPAddress(p, &ip_addr, 1)) { new_node = MallocNew(AllowDeny); new_node->allow = allow; new_node->all = all; new_node->ip = ip_addr; - new_node->subnet_bits = 32; + if (ip_addr.family == IPADDR_INET6) + new_node->subnet_bits = 128; + else + new_node->subnet_bits = 32; } else { LOG(LOGS_WARN, LOGF_Configure, "Could not read address at line %d", line_number); } @@ -931,27 +942,20 @@ parse_cmddeny(const char *line) /* ================================================== */ -static unsigned long -parse_an_address(const char *line, const char *errmsg) -{ - unsigned long a, b, c, d; - int n; - n = sscanf(line, "%lu.%lu.%lu.%lu", &a, &b, &c, &d); - if (n == 4) { - return (((a&0xff)<<24) | ((b&0xff)<<16) | - ((c&0xff)<<8) | (d&0xff)); - } else { - LOG(LOGS_WARN, LOGF_Configure, errmsg, line_number); - return 0UL; - } -} - -/* ================================================== */ - static void parse_bindaddress(const char *line) { - bind_address = parse_an_address(line, "Could not read bind address at line %d\n"); + IPAddr ip; + char addr[51]; + + if (sscanf(line, "%50s", addr) == 1 && UTI_StringToIP(addr, &ip)) { + if (ip.family == IPADDR_INET4) + bind_address4 = ip; + else if (ip.family == IPADDR_INET6) + bind_address6 = ip; + } else { + LOG(LOGS_WARN, LOGF_Configure, "Could not read bind address at line %d\n", line_number); + } } /* ================================================== */ @@ -959,7 +963,17 @@ parse_bindaddress(const char *line) static void parse_bindcmdaddress(const char *line) { - bind_cmd_address = parse_an_address(line, "Could not read bind command address at line %d\n"); + IPAddr ip; + char addr[51]; + + if (sscanf(line, "%50s", addr) == 1 && UTI_StringToIP(addr, &ip)) { + if (ip.family == IPADDR_INET4) + bind_cmd_address4 = ip; + else if (ip.family == IPADDR_INET6) + bind_cmd_address6 = ip; + } else { + LOG(LOGS_WARN, LOGF_Configure, "Could not read bind command address at line %d\n", line_number); + } } /* ================================================== */ @@ -976,7 +990,7 @@ parse_pidfile(const char *line) typedef struct { /* Both in host (not necessarily network) order */ - unsigned long addr; + IPAddr addr; unsigned short port; int interval; } NTP_Broadcast_Destination; @@ -992,27 +1006,22 @@ parse_broadcast(const char *line) { /* Syntax : broadcast [] */ int port; - unsigned int a, b, c, d; int n; int interval; - unsigned long addr; + char addr[51]; + IPAddr ip; - n = sscanf(line, "%d %u.%u.%u.%u %d", &interval, &a, &b, &c, &d, &port); - if (n < 5) { + n = sscanf(line, "%d %50s %d", &interval, addr, &port); + if (n < 2 || !UTI_StringToIP(addr, &ip)) { LOG(LOGS_WARN, LOGF_Configure, "Could not parse broadcast directive at line %d", line_number); return; - } else if (n == 5) { + } else if (n == 2) { /* default port */ port = 123; - } else if (n > 6) { + } else if (n > 3) { LOG(LOGS_WARN, LOGF_Configure, "Too many fields in broadcast directive at line %d", line_number); } - addr = ((unsigned long) a << 24) | - ((unsigned long) b << 16) | - ((unsigned long) c << 8) | - ((unsigned long) d ); - if (max_broadcasts == n_broadcasts) { /* Expand array */ max_broadcasts += 8; @@ -1023,7 +1032,7 @@ parse_broadcast(const char *line) } } - broadcasts[n_broadcasts].addr = addr; + broadcasts[n_broadcasts].addr = ip; broadcasts[n_broadcasts].port = port; broadcasts[n_broadcasts].interval = interval; ++n_broadcasts; @@ -1074,7 +1083,7 @@ CNF_AddSources(void) { for (i=0; inext) { - status = NCR_AddAccessRestriction(node->ip, node->subnet_bits, node->allow, node->all); + status = NCR_AddAccessRestriction(&node->ip, node->subnet_bits, node->allow, node->all); if (!status) { LOG(LOGS_WARN, LOGF_Configure, "Bad subnet for %08lx", node->ip); } } for (node = cmd_auth_list.next; node != &cmd_auth_list; node = node->next) { - status = CAM_AddAccessRestriction(node->ip, node->subnet_bits, node->allow, node->all); + status = CAM_AddAccessRestriction(&node->ip, node->subnet_bits, node->allow, node->all); if (!status) { LOG(LOGS_WARN, LOGF_Configure, "Bad subnet for %08lx", node->ip); } @@ -1334,17 +1343,27 @@ CNF_GetNoClientLog(void) /* ================================================== */ void -CNF_GetBindAddress(unsigned long *addr) +CNF_GetBindAddress(int family, IPAddr *addr) { - *addr = bind_address; + if (family == IPADDR_INET4) + *addr = bind_address4; + else if (family == IPADDR_INET6) + *addr = bind_address6; + else + addr->family = IPADDR_UNSPEC; } /* ================================================== */ void -CNF_GetBindCommandAddress(unsigned long *addr) +CNF_GetBindCommandAddress(int family, IPAddr *addr) { - *addr = bind_cmd_address ? bind_cmd_address : bind_address; + if (family == IPADDR_INET4) + *addr = bind_cmd_address4.family != IPADDR_UNSPEC ? bind_cmd_address4 : bind_address4; + else if (family == IPADDR_INET6) + *addr = bind_cmd_address6.family != IPADDR_UNSPEC ? bind_cmd_address6 : bind_address6; + else + addr->family = IPADDR_UNSPEC; } /* ================================================== */ diff --git a/conf.h b/conf.h index d2dd361..80e6120 100644 --- a/conf.h +++ b/conf.h @@ -31,6 +31,8 @@ #ifndef GOT_CONF_H #define GOT_CONF_H +#include "addressing.h" + extern char *CNF_GetRtcDevice(void); extern void CNF_ReadFile(const char *filename); @@ -60,8 +62,8 @@ extern int CNF_GetRTCOnUTC(void); extern void CNF_GetLogChange(int *enabled, double *threshold); extern void CNF_GetMailOnChange(int *enabled, double *threshold, char **user); extern int CNF_GetNoClientLog(void); -extern void CNF_GetBindAddress(unsigned long *addr); -extern void CNF_GetBindCommandAddress(unsigned long *addr); +extern void CNF_GetBindAddress(int family, IPAddr *addr); +extern void CNF_GetBindCommandAddress(int family, IPAddr *addr); extern char *CNF_GetPidFile(void); extern void CNF_GetLinuxHz(int *set, int *hz); extern void CNF_GetLinuxFreqScale(int *set, double *freq_scale); diff --git a/configure b/configure index 3762903..d86efa1 100755 --- a/configure +++ b/configure @@ -106,6 +106,32 @@ EOF echo $result } #}}} +#{{{ test_for_ipv6 +test_for_ipv6 () { + cat >docheck.c < +#include +#include +int main(int argc, char **argv) { + struct sockaddr_in6 n; + char p[100]; + n.sin6_addr = in6addr_any; + return !inet_ntop(AF_INET6, &n.sin6_addr.s6_addr, p, sizeof(p)); +} +EOF + + ${MYCC} ${MYCFLAGS} -c -o docheck.o docheck.c >/dev/null 2>&1 + if [ $? -eq 0 ] + then + result=0 + else + result=1 + fi + + rm -f docheck.c docheck.o + echo $result +} +#}}} #{{{ usage usage () { cat < /* ================================================== */ +#define MAXRETRIES 10 static unsigned int retries = 0; -static unsigned long -Name2IPAddress(const char *name, int retry) +int +DNS_Name2IPAddress(const char *name, IPAddr *addr, int retry) { - struct hostent *host; - unsigned char *address0; - unsigned long result; +#ifdef HAVE_IPV6 + struct addrinfo hints, *res, *ai; + int result; + + memset(&hints, 0, sizeof (hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_ADDRCONFIG; try_again: - host = gethostbyname(name); - if (host == NULL) { - if (retry && h_errno == TRY_AGAIN && retries < 10) { + result = getaddrinfo(name, NULL, &hints, &res); + + if (result) { + if (retry && result == EAI_AGAIN && retries < MAXRETRIES) { sleep(2 << retries); retries++; res_init(); goto try_again; } - result = DNS_Failed_Address; - } else { - address0 = host->h_addr_list[0]; - result = ((((unsigned long)address0[0])<<24) | - (((unsigned long)address0[1])<<16) | - (((unsigned long)address0[2])<<8) | - (((unsigned long)address0[3]))); + return 0; } - return result; -} - -/* ================================================== */ - -unsigned long -DNS_Name2IPAddress(const char *name) -{ - return Name2IPAddress(name, 0); -} - -/* ================================================== */ - -unsigned long -DNS_Name2IPAddressRetry(const char *name) -{ - return Name2IPAddress(name, 1); -} - -/* ================================================== */ - -const char * -DNS_IPAddress2Name(unsigned long ip_addr) -{ - struct hostent *host; - static char buffer[16]; - unsigned int a, b, c, d; - uint32_t addr; - - addr = htonl(ip_addr); - if (addr == 0UL) { - /* Catch this as a special case that will never resolve to - anything */ - strcpy(buffer, "0.0.0.0"); - return buffer; - } else { - host = gethostbyaddr((const char *) &addr, sizeof(ip_addr), AF_INET); - if (!host) { - a = (ip_addr >> 24) & 0xff; - b = (ip_addr >> 16) & 0xff; - c = (ip_addr >> 8) & 0xff; - d = (ip_addr) & 0xff; - snprintf(buffer, sizeof(buffer), "%u.%u.%u.%u", a, b, c, d); - return buffer; - } else { - return host->h_name; + for (ai = res; !result && ai != NULL; ai = ai->ai_next) { + switch (ai->ai_family) { + case AF_INET: + addr->family = IPADDR_INET4; + addr->addr.in4 = ntohl(((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr); + result = 1; + break; +#ifdef HAVE_IPV6 + case AF_INET6: + addr->family = IPADDR_INET6; + memcpy(&addr->addr.in6, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr.s6_addr, sizeof (addr->addr.in6)); + result = 1; + break; +#endif } } + + freeaddrinfo(res); + return result; +#else + struct hostent *host; + char *address0; + +try_again: + host = gethostbyname(name); + + if (host == NULL) { + if (retry && h_errno == TRY_AGAIN && retries < MAXRETRIES) { + sleep(2 << retries); + retries++; + res_init(); + goto try_again; + } + } else { + addr->family = IPADDR_INET4; + address0 = host->h_addr_list[0]; + addr->addr.in4 = ((((unsigned long)address0[0])<<24) | + (((unsigned long)address0[1])<<16) | + (((unsigned long)address0[2])<<8) | + (((unsigned long)address0[3]))); + return 1; + } + + return 0; +#endif +} + +/* ================================================== */ + +void +DNS_IPAddress2Name(IPAddr *ip_addr, char *name, int len) +{ +#ifdef HAVE_IPV6 + int result; + struct sockaddr_in in4; + struct sockaddr_in6 in6; + + switch (ip_addr->family) { + case IPADDR_INET4: + memset(&in4, 0, sizeof (in4)); + in4.sin_family = AF_INET; + in4.sin_addr.s_addr = htonl(ip_addr->addr.in4); + result = getnameinfo((const struct sockaddr *)&in4, sizeof (in4), name, len, NULL, 0, 0); + break; + case IPADDR_INET6: + memset(&in6, 0, sizeof (in6)); + in6.sin6_family = AF_INET6; + memcpy(&in6.sin6_addr.s6_addr, ip_addr->addr.in6, sizeof (in6.sin6_addr.s6_addr)); + result = getnameinfo((const struct sockaddr *)&in6, sizeof (in6), name, len, NULL, 0, 0); + break; + default: + result = 1; + } + + if (result) + snprintf(name, len, "%s", UTI_IPToString(ip_addr)); +#else + struct hostent *host; + uint32_t addr; + + switch (ip_addr->family) { + case IPADDR_INET4: + addr = htonl(ip_addr->addr.in4); + host = gethostbyaddr((const char *) &addr, sizeof (ip_addr), AF_INET); + break; +#ifdef HAVE_IPV6 + case IPADDR_INET6: + host = gethostbyaddr((const void *) ip_addr->addr.in6, sizeof (ip_addr->addr.in6), AF_INET6); + break; +#endif + default: + host = NULL; + } + snprintf(name, len, "%s", host ? host->h_name : UTI_IPToString(ip_addr)); +#endif } /* ================================================== */ diff --git a/nameserv.h b/nameserv.h index 69ceef8..1451b9b 100644 --- a/nameserv.h +++ b/nameserv.h @@ -32,13 +32,11 @@ #ifndef GOT_NAMESERV_H #define GOT_NAMESERV_H -static const unsigned long DNS_Failed_Address = 0x0UL; +#include "addressing.h" -extern unsigned long DNS_Name2IPAddress(const char *name); +extern int DNS_Name2IPAddress(const char *name, IPAddr *addr, int retry); -extern unsigned long DNS_Name2IPAddressRetry(const char *name); - -const char *DNS_IPAddress2Name(unsigned long ip_addr); +extern void DNS_IPAddress2Name(IPAddr *ip_addr, char *name, int len); #endif /* GOT_NAMESERV_H */ diff --git a/ntp_core.c b/ntp_core.c index 4f0eb41..daee104 100644 --- a/ntp_core.c +++ b/ntp_core.c @@ -319,7 +319,7 @@ create_instance(NTP_Remote_Address *remote_addr, NTP_Mode mode, SourceParameters result->local_poll = params->minpoll; /* Create a source instance for this NTP source */ - result->source = SRC_CreateNewInstance(remote_addr->ip_addr, SRC_NTP); + result->source = SRC_CreateNewInstance(UTI_IPToRefid(&remote_addr->ip_addr), SRC_NTP, &result->remote_addr.ip_addr); result->local_rx.tv_sec = 0; result->local_rx.tv_usec = 0; @@ -626,7 +626,7 @@ transmit_timeout(void *arg) #ifdef TRACEON LOG(LOGS_INFO, LOGF_NtpCore, "Transmit timeout for [%s:%d]", - UTI_IPToDottedQuad(inst->remote_addr.ip_addr), inst->remote_addr.port); + UTI_IPToString(&inst->remote_addr.ip_addr), inst->remote_addr.port); #endif /* Check whether we need to 'warm up' the link to the other end by @@ -1043,8 +1043,8 @@ receive_packet(NTP_Packet *message, struct timeval *now, NCR_Instance inst, int message->lvm, message->stratum, message->poll, message->precision); LOG(LOGS_INFO, LOGF_NtpCore, "Root delay=%08lx (%f), dispersion=%08lx (%f)", message->root_delay, pkt_root_delay, message->root_dispersion, pkt_root_dispersion); - LOG(LOGS_INFO, LOGF_NtpCore, "Ref id=[%s], ref_time=%08lx.%08lx [%s]", - UTI_IPToDottedQuad(ntohl(message->reference_id)), + LOG(LOGS_INFO, LOGF_NtpCore, "Ref id=[%lx], ref_time=%08lx.%08lx [%s]", + ntohl(message->reference_id), message->reference_ts.hi, message->reference_ts.lo, UTI_TimestampToString(&message->reference_ts)); LOG(LOGS_INFO, LOGF_NtpCore, "Originate=%08lx.%08lx [%s]", @@ -1243,7 +1243,7 @@ receive_packet(NTP_Packet *message, struct timeval *now, NCR_Instance inst, int inst->maxpoll = inst->minpoll; if (inst->minpoll > inst->local_poll) inst->local_poll = inst->minpoll; - LOG(LOGS_INFO, LOGF_NtpCore, "Received KoD RATE from %s, minpoll set to %d", UTI_IPToDottedQuad(inst->remote_addr.ip_addr), inst->minpoll); + LOG(LOGS_INFO, LOGF_NtpCore, "Received KoD RATE from %s, minpoll set to %d", UTI_IPToString(&inst->remote_addr.ip_addr), inst->minpoll); } /* Back off for a while */ delay_time += (double) (4 * (1UL << inst->minpoll)); @@ -1268,7 +1268,7 @@ receive_packet(NTP_Packet *message, struct timeval *now, NCR_Instance inst, int fprintf(logfile, "%s %-15s %1c %2d %1d%1d%1d%1d %1d%1d %1d%1d%1d%1d %2d %2d %2d %10.3e %10.3e %10.3e %10.3e %10.3e\n", UTI_TimeToLogForm(sample_time.tv_sec), - UTI_IPToDottedQuad(inst->remote_addr.ip_addr), + UTI_IPToString(&inst->remote_addr.ip_addr), sync_stats[pkt_leap], message->stratum, test1, test2, test3, test4, @@ -1357,9 +1357,9 @@ process_known one of the secondaries to flywheel it. The behaviour coded here is required in the secondaries to make this possible. */ - if (ADF_IsAllowed(access_auth_table, inst->remote_addr.ip_addr)) { + if (ADF_IsAllowed(access_auth_table, &inst->remote_addr.ip_addr)) { - CLG_LogNTPClientAccess(inst->remote_addr.ip_addr, (time_t) now->tv_sec); + CLG_LogNTPClientAccess(&inst->remote_addr.ip_addr, (time_t) now->tv_sec); if (do_auth) { auth_key_id = ntohl(message->auth_keyid); @@ -1392,7 +1392,7 @@ process_known } else { LOG(LOGS_WARN, LOGF_NtpCore, "NTP packet received from unauthorised host %s port %d", - UTI_IPToDottedQuad(inst->remote_addr.ip_addr), + UTI_IPToString(&inst->remote_addr.ip_addr), inst->remote_addr.port); } @@ -1403,7 +1403,7 @@ process_known switch(inst->mode) { case MODE_ACTIVE: /* Ordinary symmetric peering */ - CLG_LogNTPPeerAccess(inst->remote_addr.ip_addr, (time_t) now->tv_sec); + CLG_LogNTPPeerAccess(&inst->remote_addr.ip_addr, (time_t) now->tv_sec); receive_packet(message, now, inst, do_auth); break; case MODE_PASSIVE: @@ -1413,7 +1413,7 @@ process_known case MODE_CLIENT: /* This is where we have the remote configured as a server and he has us configured as a peer - fair enough. */ - CLG_LogNTPPeerAccess(inst->remote_addr.ip_addr, (time_t) now->tv_sec); + CLG_LogNTPPeerAccess(&inst->remote_addr.ip_addr, (time_t) now->tv_sec); receive_packet(message, now, inst, do_auth); break; case MODE_SERVER: @@ -1434,7 +1434,7 @@ process_known switch(inst->mode) { case MODE_ACTIVE: /* Slightly bizarre combination, but we can still process it */ - CLG_LogNTPPeerAccess(inst->remote_addr.ip_addr, (time_t) now->tv_sec); + CLG_LogNTPPeerAccess(&inst->remote_addr.ip_addr, (time_t) now->tv_sec); receive_packet(message, now, inst, do_auth); break; case MODE_PASSIVE: @@ -1462,7 +1462,7 @@ process_known case MODE_ACTIVE: /* This would arise if we have the remote configured as a peer and he does not have us configured */ - CLG_LogNTPPeerAccess(inst->remote_addr.ip_addr, (time_t) now->tv_sec); + CLG_LogNTPPeerAccess(&inst->remote_addr.ip_addr, (time_t) now->tv_sec); receive_packet(message, now, inst, do_auth); break; case MODE_PASSIVE: @@ -1524,19 +1524,19 @@ NCR_ProcessNoauthUnknown(NTP_Packet *message, struct timeval *now, NTP_Remote_Ad NTP_Mode my_mode; int my_poll; - if (ADF_IsAllowed(access_auth_table, remote_addr->ip_addr)) { + if (ADF_IsAllowed(access_auth_table, &remote_addr->ip_addr)) { his_mode = message->lvm & 0x07; if (his_mode == MODE_CLIENT) { /* We are server */ my_mode = MODE_SERVER; - CLG_LogNTPClientAccess(remote_addr->ip_addr, (time_t) now->tv_sec); + CLG_LogNTPClientAccess(&remote_addr->ip_addr, (time_t) now->tv_sec); } else if (his_mode == MODE_ACTIVE) { /* We are symmetric passive, even though we don't ever lock to him */ my_mode = MODE_PASSIVE; - CLG_LogNTPPeerAccess(remote_addr->ip_addr, (time_t) now->tv_sec); + CLG_LogNTPPeerAccess(&remote_addr->ip_addr, (time_t) now->tv_sec); } else { my_mode = MODE_UNDEFINED; @@ -1560,7 +1560,7 @@ NCR_ProcessNoauthUnknown(NTP_Packet *message, struct timeval *now, NTP_Remote_Ad } } else { LOG(LOGS_WARN, LOGF_NtpCore, "NTP packet received from unauthorised host %s port %d", - UTI_IPToDottedQuad(remote_addr->ip_addr), + UTI_IPToString(&remote_addr->ip_addr), remote_addr->port); } @@ -1594,19 +1594,19 @@ NCR_ProcessAuthUnknown(NTP_Packet *message, struct timeval *now, NTP_Remote_Addr int valid_key, valid_auth; unsigned long key_id; - if (ADF_IsAllowed(access_auth_table, remote_addr->ip_addr)) { + if (ADF_IsAllowed(access_auth_table, &remote_addr->ip_addr)) { his_mode = message->lvm & 0x07; if (his_mode == MODE_CLIENT) { /* We are server */ my_mode = MODE_SERVER; - CLG_LogNTPClientAccess(remote_addr->ip_addr, (time_t) now->tv_sec); + CLG_LogNTPClientAccess(&remote_addr->ip_addr, (time_t) now->tv_sec); } else if (his_mode == MODE_ACTIVE) { /* We are symmetric passive, even though we don't ever lock to him */ my_mode = MODE_PASSIVE; - CLG_LogNTPPeerAccess(remote_addr->ip_addr, (time_t) now->tv_sec); + CLG_LogNTPPeerAccess(&remote_addr->ip_addr, (time_t) now->tv_sec); } else { my_mode = MODE_UNDEFINED; @@ -1678,7 +1678,7 @@ NCR_TakeSourceOnline(NCR_Instance inst) case MD_OFFLINE: if (!inst->timer_running) { /* We are not already actively polling it */ - LOG(LOGS_INFO, LOGF_NtpCore, "Source %s online", UTI_IPToDottedQuad(inst->remote_addr.ip_addr)); + LOG(LOGS_INFO, LOGF_NtpCore, "Source %s online", UTI_IPToString(&inst->remote_addr.ip_addr)); inst->local_poll = inst->minpoll; inst->score = (ZONE_WIDTH >> 1); inst->opmode = MD_ONLINE; @@ -1702,7 +1702,7 @@ NCR_TakeSourceOffline(NCR_Instance inst) switch (inst->opmode) { case MD_ONLINE: if (inst->timer_running) { - LOG(LOGS_INFO, LOGF_NtpCore, "Source %s offline", UTI_IPToDottedQuad(inst->remote_addr.ip_addr)); + LOG(LOGS_INFO, LOGF_NtpCore, "Source %s offline", UTI_IPToString(&inst->remote_addr.ip_addr)); SCH_RemoveTimeout(inst->timeout_id); inst->timer_running = 0; inst->opmode = MD_OFFLINE; @@ -1725,7 +1725,7 @@ void NCR_ModifyMinpoll(NCR_Instance inst, int new_minpoll) { inst->minpoll = new_minpoll; - LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new minpoll %d", UTI_IPToDottedQuad(inst->remote_addr.ip_addr), new_minpoll); + LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new minpoll %d", UTI_IPToString(&inst->remote_addr.ip_addr), new_minpoll); } /* ================================================== */ @@ -1734,7 +1734,7 @@ void NCR_ModifyMaxpoll(NCR_Instance inst, int new_maxpoll) { inst->maxpoll = new_maxpoll; - LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new maxpoll %d", UTI_IPToDottedQuad(inst->remote_addr.ip_addr), new_maxpoll); + LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new maxpoll %d", UTI_IPToString(&inst->remote_addr.ip_addr), new_maxpoll); } /* ================================================== */ @@ -1744,7 +1744,7 @@ NCR_ModifyMaxdelay(NCR_Instance inst, double new_max_delay) { inst->max_delay = new_max_delay; LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new max delay %f", - UTI_IPToDottedQuad(inst->remote_addr.ip_addr), new_max_delay); + UTI_IPToString(&inst->remote_addr.ip_addr), new_max_delay); } /* ================================================== */ @@ -1754,7 +1754,7 @@ NCR_ModifyMaxdelayratio(NCR_Instance inst, double new_max_delay_ratio) { inst->max_delay_ratio = new_max_delay_ratio; LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new max delay ratio %f", - UTI_IPToDottedQuad(inst->remote_addr.ip_addr), new_max_delay_ratio); + UTI_IPToString(&inst->remote_addr.ip_addr), new_max_delay_ratio); } /* ================================================== */ @@ -1836,7 +1836,7 @@ NCR_ReportSource(NCR_Instance inst, RPT_SourceReport *report, struct timeval *no /* ================================================== */ int -NCR_AddAccessRestriction(unsigned long ip_addr, int subnet_bits, int allow, int all) +NCR_AddAccessRestriction(IPAddr *ip_addr, int subnet_bits, int allow, int all) { ADF_Status status; @@ -1866,7 +1866,7 @@ NCR_AddAccessRestriction(unsigned long ip_addr, int subnet_bits, int allow, int /* ================================================== */ int -NCR_CheckAccessRestriction(unsigned long ip_addr) +NCR_CheckAccessRestriction(IPAddr *ip_addr) { return ADF_IsAllowed(access_auth_table, ip_addr); } diff --git a/ntp_core.h b/ntp_core.h index 84b21d9..86926c4 100644 --- a/ntp_core.h +++ b/ntp_core.h @@ -94,8 +94,8 @@ extern void NCR_InitiateSampleBurst(NCR_Instance inst, int n_good_samples, int n extern void NCR_ReportSource(NCR_Instance inst, RPT_SourceReport *report, struct timeval *now); -extern int NCR_AddAccessRestriction(unsigned long ip_addr, int subnet_bits, int allow, int all); -extern int NCR_CheckAccessRestriction(unsigned long ip_addr); +extern int NCR_AddAccessRestriction(IPAddr *ip_addr, int subnet_bits, int allow, int all); +extern int NCR_CheckAccessRestriction(IPAddr *ip_addr); extern void NCR_CycleLogFile(void); diff --git a/ntp_io.c b/ntp_io.c index d673105..7d4f880 100644 --- a/ntp_io.c +++ b/ntp_io.c @@ -41,8 +41,19 @@ #include -/* The file descriptor for the socket */ -static int sock_fd; +union sockaddr_in46 { + struct sockaddr_in in4; +#ifdef HAVE_IPV6 + struct sockaddr_in6 in6; +#endif + struct sockaddr u; +}; + +/* The file descriptors for the IPv4 and IPv6 sockets */ +static int sock_fd4; +#ifdef HAVE_IPV6 +static int sock_fd6; +#endif /* Flag indicating that we have been initialised */ static int initialised=0; @@ -50,6 +61,7 @@ static int initialised=0; /* ================================================== */ /* Forward prototypes */ +static int prepare_socket(int family); static void read_from_socket(void *anything); /* ================================================== */ @@ -81,30 +93,28 @@ do_size_checks(void) /* ================================================== */ -void -NIO_Initialise(void) +static int +prepare_socket(int family) { - struct sockaddr_in my_addr; + union sockaddr_in46 my_addr; + int sock_fd; unsigned short port_number; - unsigned long bind_address; + IPAddr bind_address; int on_off = 1; - assert(!initialised); - initialised = 1; - - do_size_checks(); - port_number = CNF_GetNTPPort(); /* Open Internet domain UDP socket for NTP message transmissions */ #if 0 - sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + sock_fd = socket(family, SOCK_DGRAM, IPPROTO_UDP); #else - sock_fd = socket(AF_INET, SOCK_DGRAM, 0); + sock_fd = socket(family, SOCK_DGRAM, 0); #endif + if (sock_fd < 0) { - LOG_FATAL(LOGF_NtpIO, "Could not open socket : %s", strerror(errno)); + LOG(LOGS_ERR, LOGF_NtpIO, "Could not open socket : %s", strerror(errno)); + return -1; } /* Make the socket capable of re-using an old address */ @@ -125,34 +135,67 @@ 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 */ + if (family == AF_INET) { + /* 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 */ + } } +#ifdef HAVE_IPV6 + else if (family == AF_INET6) { +#ifdef IPV6_V6ONLY + /* Receive IPv6 packets only */ + if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on_off, sizeof(on_off)) < 0) { + LOG(LOGS_ERR, LOGF_NtpIO, "Could not request IPV6_V6ONLY socket option"); + } +#endif + } +#endif /* Bind the port */ - my_addr.sin_family = AF_INET; - my_addr.sin_port = htons(port_number); + memset(&my_addr, 0, sizeof (my_addr)); - CNF_GetBindAddress(&bind_address); + switch (family) { + case AF_INET: + my_addr.in4.sin_family = family; + my_addr.in4.sin_port = htons(port_number); - if (bind_address != 0UL) { - my_addr.sin_addr.s_addr = htonl(bind_address); - } else { - my_addr.sin_addr.s_addr = htonl(INADDR_ANY); + CNF_GetBindAddress(IPADDR_INET4, &bind_address); + + if (bind_address.family == IPADDR_INET4) + my_addr.in4.sin_addr.s_addr = htonl(bind_address.addr.in4); + else + my_addr.in4.sin_addr.s_addr = htonl(INADDR_ANY); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + my_addr.in6.sin6_family = family; + my_addr.in6.sin6_port = htons(port_number); + + CNF_GetBindAddress(IPADDR_INET6, &bind_address); + + if (bind_address.family == IPADDR_INET6) + memcpy(my_addr.in6.sin6_addr.s6_addr, bind_address.addr.in6, + sizeof (my_addr.in6.sin6_addr.s6_addr)); + else + my_addr.in6.sin6_addr = in6addr_any; + break; +#endif + default: + assert(0); } #if 0 LOG(LOGS_INFO, LOGF_NtpIO, "Initialising, socket fd=%d", sock_fd); #endif - if (bind(sock_fd, (struct sockaddr *) &my_addr, sizeof(my_addr)) < 0) { + if (bind(sock_fd, &my_addr.u, sizeof(my_addr)) < 0) { LOG_FATAL(LOGF_NtpIO, "Could not bind socket : %s", strerror(errno)); } /* Register handler for read events on the socket */ - SCH_AddInputFileHandler(sock_fd, read_from_socket, NULL); + SCH_AddInputFileHandler(sock_fd, read_from_socket, (void *)(long)sock_fd); #if 0 if (fcntl(sock_fd, F_SETFL, O_NONBLOCK | O_NDELAY) < 0) { @@ -163,6 +206,29 @@ NIO_Initialise(void) LOG(LOGS_ERR, LOGF_NtpIO, "Could not enable signal"); } #endif + return sock_fd; +} + +void +NIO_Initialise(void) +{ + assert(!initialised); + initialised = 1; + + do_size_checks(); + + sock_fd4 = prepare_socket(AF_INET); +#ifdef HAVE_IPV6 + sock_fd6 = prepare_socket(AF_INET6); +#endif + + if (sock_fd4 < 0 +#ifdef HAVE_IPV6 + && sock_fd6 < 0 +#endif + ) { + LOG_FATAL(LOGF_NtpIO, "Could not open any NTP socket"); + } return; } @@ -172,11 +238,18 @@ NIO_Initialise(void) void NIO_Finalise(void) { - if (sock_fd >= 0) { - SCH_RemoveInputFileHandler(sock_fd); - close(sock_fd); + if (sock_fd4 >= 0) { + SCH_RemoveInputFileHandler(sock_fd4); + close(sock_fd4); } - sock_fd = -1; + sock_fd4 = -1; +#ifdef HAVE_IPV6 + if (sock_fd6 >= 0) { + SCH_RemoveInputFileHandler(sock_fd6); + close(sock_fd6); + } + sock_fd6 = -1; +#endif initialised = 0; return; } @@ -192,9 +265,9 @@ read_from_socket(void *anything) /* This should only be called when there is something to read, otherwise it will block. */ - int status; + int status, sock_fd; ReceiveBuffer message; - struct sockaddr_in where_from; + union sockaddr_in46 where_from; unsigned int flags = 0; struct timeval now; NTP_Remote_Address remote_addr; @@ -218,6 +291,7 @@ read_from_socket(void *anything) msg.msg_controllen = sizeof(cmsgbuf); msg.msg_flags = 0; + sock_fd = (long)anything; status = recvmsg(sock_fd, &msg, flags); /* Don't bother checking if read failed or why if it did. More @@ -228,16 +302,33 @@ read_from_socket(void *anything) reponse on a subsequent recvfrom). */ 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); + memset(&remote_addr, 0, sizeof (remote_addr)); + + switch (where_from.u.sa_family) { + case AF_INET: + remote_addr.ip_addr.family = IPADDR_INET4; + remote_addr.ip_addr.addr.in4 = ntohl(where_from.in4.sin_addr.s_addr); + remote_addr.port = ntohs(where_from.in4.sin_port); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + remote_addr.ip_addr.family = IPADDR_INET6; + memcpy(&remote_addr.ip_addr.addr.in6, where_from.in6.sin6_addr.s6_addr, + sizeof (remote_addr.ip_addr.addr.in6)); + remote_addr.port = ntohs(where_from.in6.sin6_port); + break; +#endif + default: + assert(0); + } 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); + remote_addr.local_ip_addr.addr.in4 = ntohl(ipi.ipi_spec_dst.s_addr); + remote_addr.local_ip_addr.family = IPADDR_INET4; } if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SO_TIMESTAMP) { @@ -279,22 +370,43 @@ read_from_socket(void *anything) static void send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr) { - struct sockaddr_in remote; + union sockaddr_in46 remote; struct msghdr msg; struct iovec iov; struct cmsghdr *cmsg; char cmsgbuf[256]; int cmsglen; + int sock_fd; assert(initialised); - remote.sin_family = AF_INET; - remote.sin_port = htons(remote_addr->port); - remote.sin_addr.s_addr = htonl(remote_addr->ip_addr); + memset(&remote, 0, sizeof (remote)); + switch (remote_addr->ip_addr.family) { + case IPADDR_INET4: + remote.in4.sin_family = AF_INET; + remote.in4.sin_port = htons(remote_addr->port); + remote.in4.sin_addr.s_addr = htonl(remote_addr->ip_addr.addr.in4); + sock_fd = sock_fd4; + break; +#ifdef HAVE_IPV6 + case IPADDR_INET6: + remote.in6.sin6_family = AF_INET6; + remote.in6.sin6_port = htons(remote_addr->port); + memcpy(&remote.in6.sin6_addr.s6_addr, &remote_addr->ip_addr.addr.in6, + sizeof (remote.in6.sin6_addr.s6_addr)); + sock_fd = sock_fd6; + break; +#endif + default: + return; + } + + if (sock_fd < 0) + return; iov.iov_base = packet; iov.iov_len = packetlen; - msg.msg_name = &remote; + msg.msg_name = &remote.u; msg.msg_namelen = sizeof(remote); msg.msg_iov = &iov; msg.msg_iovlen = 1; @@ -303,7 +415,7 @@ send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr) msg.msg_flags = 0; cmsglen = 0; - if (remote_addr->local_ip_addr) { + if (remote_addr->local_ip_addr.family == IPADDR_INET4) { struct in_pktinfo *ipi; cmsg = CMSG_FIRSTHDR(&msg); @@ -315,10 +427,10 @@ send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr) cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); ipi = (struct in_pktinfo *) CMSG_DATA(cmsg); - ipi->ipi_spec_dst.s_addr = htonl(remote_addr->local_ip_addr); + ipi->ipi_spec_dst.s_addr = htonl(remote_addr->local_ip_addr.addr.in4); #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)); + UTI_IPToString(&remote_addr->ip_addr), remote_addr->port, UTI_IPToString(&remote_addr->local_ip_addr)); #endif } @@ -326,7 +438,7 @@ send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr) if (sendmsg(sock_fd, &msg, 0) < 0) { LOG(LOGS_WARN, LOGF_NtpIO, "Could not send to %s:%d : %s", - UTI_IPToDottedQuad(remote_addr->ip_addr), remote_addr->port, strerror(errno)); + UTI_IPToString(&remote_addr->ip_addr), remote_addr->port, strerror(errno)); } return; diff --git a/ntp_sources.c b/ntp_sources.c index d47573b..7d4c5ba 100644 --- a/ntp_sources.c +++ b/ntp_sources.c @@ -120,17 +120,36 @@ static void find_slot(NTP_Remote_Address *remote_addr, int *slot, int *found) { unsigned long hash; - unsigned long ip = remote_addr->ip_addr; - unsigned short port = remote_addr->port; + unsigned long ip; + unsigned short port; + uint8_t *ip6; assert(N_RECORDS == 256); + switch (remote_addr->ip_addr.family) { + case IPADDR_INET6: + ip6 = remote_addr->ip_addr.addr.in6; + ip = (ip6[0] ^ ip6[4] ^ ip6[8] ^ ip6[12]) | + (ip6[1] ^ ip6[5] ^ ip6[9] ^ ip6[13]) << 8 | + (ip6[2] ^ ip6[6] ^ ip6[10] ^ ip6[14]) << 16 | + (ip6[3] ^ ip6[7] ^ ip6[11] ^ ip6[15]) << 24; + break; + case IPADDR_INET4: + ip = remote_addr->ip_addr.addr.in4; + break; + default: + *found = *slot = 0; + return; + } + + port = remote_addr->port; /* Compute hash value just by xor'ing the 4 bytes of the address together */ hash = ip ^ (ip >> 16); hash = (hash ^ (hash >> 8)) & 0xff; while ((records[hash].in_use) && - (records[hash].remote_addr.ip_addr != ip)) { + UTI_CompareIPs(&records[hash].remote_addr.ip_addr, + &remote_addr->ip_addr, NULL)) { hash++; if (hash == 256) hash = 0; } @@ -162,7 +181,7 @@ NSR_AddServer(NTP_Remote_Address *remote_addr, SourceParameters *params) assert(initialised); #if 0 - LOG(LOGS_INFO, LOGF_NtpSources, "IP=%08lx port=%d", (unsigned long)remote_addr->ip_addr, remote_addr->port); + LOG(LOGS_INFO, LOGF_NtpSources, "IP=%s port=%d", UTI_IPToString(&remote_addr->ip_addr), remote_addr->port); #endif /* Find empty bin & check that we don't have the address already */ @@ -172,6 +191,9 @@ NSR_AddServer(NTP_Remote_Address *remote_addr, SourceParameters *params) } else { if (n_sources == MAX_SOURCES) { return NSR_TooManySources; + } else if (remote_addr->ip_addr.family != IPADDR_INET4 && + remote_addr->ip_addr.family != IPADDR_INET6) { + return NSR_InvalidAF; } else { n_sources++; records[slot].remote_addr = *remote_addr; @@ -193,7 +215,7 @@ NSR_AddPeer(NTP_Remote_Address *remote_addr, SourceParameters *params) assert(initialised); #if 0 - LOG(LOGS_INFO, LOGF_NtpSources, "IP=%08lx port=%d", (unsigned long) remote_addr->ip_addr, remote_addr->port); + LOG(LOGS_INFO, LOGF_NtpSources, "IP=%s port=%d", UTI_IPToString(&remote_addr->ip_addr), remote_addr->port); #endif /* Find empty bin & check that we don't have the address already */ @@ -203,6 +225,9 @@ NSR_AddPeer(NTP_Remote_Address *remote_addr, SourceParameters *params) } else { if (n_sources == MAX_SOURCES) { return NSR_TooManySources; + } else if (remote_addr->ip_addr.family != IPADDR_INET4 && + remote_addr->ip_addr.family != IPADDR_INET6) { + return NSR_InvalidAF; } else { n_sources++; records[slot].remote_addr = *remote_addr; @@ -249,7 +274,7 @@ NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, NTP_Remote_Address #if 0 LOG(LOGS_INFO, LOGF_NtpSources, "from (%s,%d) at %s", - UTI_IPToDottedQuad(remote_addr->ip_addr), + UTI_IPToString(&remote_addr->ip_addr), remote_addr->port, UTI_TimevalToString(now)); #endif @@ -296,7 +321,7 @@ slew_sources(struct timeval *raw, if (records[i].in_use) { #if 0 LOG(LOGS_INFO, LOGF_Sources, "IP=%s dfreq=%f doff=%f", - UTI_IPToDottedQuad(records[i].remote_addr.ip_addr), dfreq, doffset); + UTI_IPToString(&records[i].remote_addr.ip_addr), dfreq, doffset); #endif NCR_SlewTimes(records[i].data, cooked, dfreq, doffset); @@ -308,17 +333,16 @@ slew_sources(struct timeval *raw, /* ================================================== */ int -NSR_TakeSourcesOnline(unsigned long mask, unsigned long address) +NSR_TakeSourcesOnline(IPAddr *mask, IPAddr *address) { int i; int any; - unsigned long ip; any = 0; for (i=0; ifamily == IPADDR_UNSPEC || + !UTI_CompareIPs(&records[i].remote_addr.ip_addr, address, mask)) { any = 1; NCR_TakeSourceOnline(records[i].data); } @@ -331,17 +355,16 @@ NSR_TakeSourcesOnline(unsigned long mask, unsigned long address) /* ================================================== */ int -NSR_TakeSourcesOffline(unsigned long mask, unsigned long address) +NSR_TakeSourcesOffline(IPAddr *mask, IPAddr *address) { int i; int any; - unsigned long ip; any = 0; for (i=0; ifamily == IPADDR_UNSPEC || + !UTI_CompareIPs(&records[i].remote_addr.ip_addr, address, mask)) { any = 1; NCR_TakeSourceOffline(records[i].data); } @@ -354,11 +377,11 @@ NSR_TakeSourcesOffline(unsigned long mask, unsigned long address) /* ================================================== */ int -NSR_ModifyMinpoll(unsigned long address, int new_minpoll) +NSR_ModifyMinpoll(IPAddr *address, int new_minpoll) { int slot, found; NTP_Remote_Address addr; - addr.ip_addr = address; + addr.ip_addr = *address; addr.port = 0; find_slot(&addr, &slot, &found); @@ -373,11 +396,11 @@ NSR_ModifyMinpoll(unsigned long address, int new_minpoll) /* ================================================== */ int -NSR_ModifyMaxpoll(unsigned long address, int new_maxpoll) +NSR_ModifyMaxpoll(IPAddr *address, int new_maxpoll) { int slot, found; NTP_Remote_Address addr; - addr.ip_addr = address; + addr.ip_addr = *address; addr.port = 0; find_slot(&addr, &slot, &found); @@ -392,11 +415,11 @@ NSR_ModifyMaxpoll(unsigned long address, int new_maxpoll) /* ================================================== */ int -NSR_ModifyMaxdelay(unsigned long address, double new_max_delay) +NSR_ModifyMaxdelay(IPAddr *address, double new_max_delay) { int slot, found; NTP_Remote_Address addr; - addr.ip_addr = address; + addr.ip_addr = *address; addr.port = 0; find_slot(&addr, &slot, &found); @@ -411,11 +434,11 @@ NSR_ModifyMaxdelay(unsigned long address, double new_max_delay) /* ================================================== */ int -NSR_ModifyMaxdelayratio(unsigned long address, double new_max_delay_ratio) +NSR_ModifyMaxdelayratio(IPAddr *address, double new_max_delay_ratio) { int slot, found; NTP_Remote_Address addr; - addr.ip_addr = address; + addr.ip_addr = *address; addr.port = 0; find_slot(&addr, &slot, &found); @@ -431,17 +454,16 @@ NSR_ModifyMaxdelayratio(unsigned long address, double new_max_delay_ratio) int NSR_InitiateSampleBurst(int n_good_samples, int n_total_samples, - unsigned long mask, unsigned long address) + IPAddr *mask, IPAddr *address) { int i; int any; - unsigned long ip; any = 0; for (i=0; ifamily == IPADDR_UNSPEC || + !UTI_CompareIPs(&records[i].remote_addr.ip_addr, address, mask)) { any = 1; NCR_InitiateSampleBurst(records[i].data, n_good_samples, n_total_samples); } diff --git a/ntp_sources.h b/ntp_sources.h index 2e8499c..c4ff8d7 100644 --- a/ntp_sources.h +++ b/ntp_sources.h @@ -46,7 +46,8 @@ typedef enum { NSR_Success, /* Operation successful */ NSR_NoSuchSource, /* Remove - attempt to remove a source that is not known */ NSR_AlreadyInUse, /* AddServer, AddPeer - attempt to add a source that is already known */ - NSR_TooManySources /* AddServer, AddPeer - too many sources already present */ + NSR_TooManySources, /* AddServer, AddPeer - too many sources already present */ + NSR_InvalidAF /* AddServer, AddPeer - attempt to add a source with invalid address family */ } NSR_Status; /* Procedure to add a new server source (to which this machine will be @@ -75,22 +76,22 @@ extern void NSR_Finalise(void); /* This routine is used to indicate that sources whose IP addresses match a particular subnet should be set online again. Returns a flag indicating whether any hosts matched the address */ -extern int NSR_TakeSourcesOnline(unsigned long mask, unsigned long address); +extern int NSR_TakeSourcesOnline(IPAddr *mask, IPAddr *address); /* This routine is used to indicate that sources whose IP addresses match a particular subnet should be set offline. Returns a flag indicating whether any hosts matched the address */ -extern int NSR_TakeSourcesOffline(unsigned long mask, unsigned long address); +extern int NSR_TakeSourcesOffline(IPAddr *mask, IPAddr *address); -extern int NSR_ModifyMinpoll(unsigned long address, int new_minpoll); +extern int NSR_ModifyMinpoll(IPAddr *address, int new_minpoll); -extern int NSR_ModifyMaxpoll(unsigned long address, int new_maxpoll); +extern int NSR_ModifyMaxpoll(IPAddr *address, int new_maxpoll); -extern int NSR_ModifyMaxdelay(unsigned long address, double new_max_delay); +extern int NSR_ModifyMaxdelay(IPAddr *address, double new_max_delay); -extern int NSR_ModifyMaxdelayratio(unsigned long address, double new_max_delay_ratio); +extern int NSR_ModifyMaxdelayratio(IPAddr *address, double new_max_delay_ratio); -extern int NSR_InitiateSampleBurst(int n_good_samples, int n_total_samples, unsigned long mask, unsigned long address); +extern int NSR_InitiateSampleBurst(int n_good_samples, int n_total_samples, IPAddr *mask, IPAddr *address); extern void NSR_ReportSource(RPT_SourceReport *report, struct timeval *now); diff --git a/refclock.c b/refclock.c index 1d8167f..50c3a42 100644 --- a/refclock.c +++ b/refclock.c @@ -172,7 +172,7 @@ RCL_StartRefclocks(void) for (i = 0; i < n_sources; i++) { RCL_Instance inst = &refclocks[i]; - inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK); + inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK, NULL); inst->timeout_id = SCH_AddTimeoutByDelay(0.0, poll_timeout, (void *)inst); } @@ -186,7 +186,8 @@ RCL_ReportSource(RPT_SourceReport *report, struct timeval *now) int i; unsigned long ref_id; - ref_id = report->ip_addr; + assert(report->ip_addr.family == IPADDR_INET4); + ref_id = report->ip_addr.addr.in4; for (i = 0; i < n_sources; i++) { RCL_Instance inst = &refclocks[i]; diff --git a/reports.h b/reports.h index a2bdb97..06a0b42 100644 --- a/reports.h +++ b/reports.h @@ -32,11 +32,12 @@ #define GOT_REPORTS_H #include "sysincl.h" +#include "addressing.h" #define REPORT_INVALID_OFFSET 0x80000000 typedef struct { - unsigned long ip_addr; + IPAddr ip_addr; int stratum; int poll; enum {RPT_NTP_CLIENT, RPT_NTP_PEER, RPT_LOCAL_REFERENCE} mode; @@ -65,7 +66,7 @@ typedef struct { } RPT_TrackingReport; typedef struct { - unsigned long ip_addr; + IPAddr ip_addr; unsigned long n_samples; unsigned long n_runs; unsigned long span_seconds; @@ -94,7 +95,7 @@ typedef struct { } RPT_ClientAccess_Report; typedef struct { - unsigned long ip_addr; + IPAddr ip_addr; unsigned long client_hits; unsigned long peer_hits; unsigned long cmd_hits_auth; diff --git a/sources.c b/sources.c index db8795b..ffe63cd 100644 --- a/sources.c +++ b/sources.c @@ -88,6 +88,7 @@ struct SRC_Instance_Record { unsigned long ref_id; /* The reference ID of this source (i.e. its IP address, NOT the reference _it_ is sync'd to) */ + IPAddr *ip_addr; /* Its IP address if NTP source */ /* Flag indicating that we are receiving packets with valid headers from this source and can use it as a reference */ @@ -160,7 +161,7 @@ void SRC_Finalise(void) /* Function to create a new instance. This would be called by one of the individual source-type instance creation routines. */ -SRC_Instance SRC_CreateNewInstance(unsigned long ref_id, SRC_Type type) +SRC_Instance SRC_CreateNewInstance(unsigned long ref_id, SRC_Type type, IPAddr *addr) { SRC_Instance result; @@ -189,6 +190,7 @@ SRC_Instance SRC_CreateNewInstance(unsigned long ref_id, SRC_Type type) result->index = n_sources; result->leap_status = LEAP_Normal; result->ref_id = ref_id; + result->ip_addr = addr; result->reachable = 0; result->status = SRC_BAD_STATS; result->type = type; @@ -362,7 +364,7 @@ source_to_string(SRC_Instance inst) { switch (inst->type) { case SRC_NTP: - return UTI_IPToDottedQuad(inst->ref_id); + return UTI_IPToString(inst->ip_addr); case SRC_REFCLOCK: return UTI_RefidToString(inst->ref_id); default: @@ -912,7 +914,16 @@ SRC_ReportSource(int index, RPT_SourceReport *report, struct timeval *now) return 0; } else { src = sources[index]; - report->ip_addr = src->ref_id; + + memset(&report->ip_addr, 0, sizeof (report->ip_addr)); + if (src->ip_addr) + report->ip_addr = *src->ip_addr; + else { + /* Use refid as an address */ + report->ip_addr.addr.in4 = src->ref_id; + report->ip_addr.family = IPADDR_INET4; + } + switch (src->status) { case SRC_SYNC: report->state = RPT_SYNC; @@ -949,7 +960,10 @@ SRC_ReportSourcestats(int index, RPT_SourcestatsReport *report) return 0; } else { src = sources[index]; - report->ip_addr = src->ref_id; + if (src->ip_addr) + report->ip_addr = *src->ip_addr; + else + report->ip_addr.family = IPADDR_UNSPEC; SST_DoSourcestatsReport(src->stats, report); return 1; } diff --git a/sources.h b/sources.h index 3afd806..e563036 100644 --- a/sources.h +++ b/sources.h @@ -58,7 +58,7 @@ typedef enum { /* Function to create a new instance. This would be called by one of the individual source-type instance creation routines. */ -extern SRC_Instance SRC_CreateNewInstance(unsigned long ref_id, SRC_Type type); +extern SRC_Instance SRC_CreateNewInstance(unsigned long ref_id, SRC_Type type, IPAddr *addr); /* Function to get rid of a source when it is being unconfigured. This may cause the current reference source to be reselected, if this diff --git a/sysincl.h b/sysincl.h index 4cb1da8..34cc3b7 100644 --- a/sysincl.h +++ b/sysincl.h @@ -79,6 +79,11 @@ #endif +#ifdef HAVE_IPV6 +/* For inet_ntop() */ +#include +#endif + #if defined (SOLARIS) || defined(SUNOS) /* Only needed on these platforms, and doesn't exist on some Linux versions. */ diff --git a/util.c b/util.c index b5f3cdf..5717d54 100644 --- a/util.c +++ b/util.c @@ -31,6 +31,7 @@ #include "sysincl.h" #include "util.h" +#include "md5.h" /* ================================================== */ @@ -271,6 +272,169 @@ UTI_IPToDottedQuad(unsigned long ip) /* ================================================== */ +char * +UTI_IPToString(IPAddr *addr) +{ + unsigned long a, b, c, d, ip; + uint8_t *ip6; + char *result; + + result = NEXT_BUFFER; + switch (addr->family) { + case IPADDR_UNSPEC: + snprintf(result, BUFFER_LENGTH, "[UNSPEC]"); + break; + case IPADDR_INET4: + ip = addr->addr.in4; + a = (ip>>24) & 0xff; + b = (ip>>16) & 0xff; + c = (ip>> 8) & 0xff; + d = (ip>> 0) & 0xff; + snprintf(result, BUFFER_LENGTH, "%ld.%ld.%ld.%ld", a, b, c, d); + break; + case IPADDR_INET6: + ip6 = addr->addr.in6; +#ifdef HAVE_IPV6 + inet_ntop(AF_INET6, ip6, result, BUFFER_LENGTH); +#else + snprintf(result, BUFFER_LENGTH, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", + ip6[0], ip6[1], ip6[2], ip6[3], ip6[4], ip6[5], ip6[6], ip6[7], + ip6[8], ip6[9], ip6[10], ip6[11], ip6[12], ip6[13], ip6[14], ip6[15]); +#endif + break; + default: + snprintf(result, BUFFER_LENGTH, "[UNKNOWN]"); + } + return result; +} + +/* ================================================== */ + +int +UTI_StringToIP(const char *addr, IPAddr *ip) +{ +#ifdef HAVE_IPV6 + struct in_addr in4; + struct in6_addr in6; + + if (inet_pton(AF_INET, addr, &in4) > 0) { + ip->family = IPADDR_INET4; + ip->addr.in4 = ntohl(in4.s_addr); + return 1; + } + + if (inet_pton(AF_INET6, addr, &in6) > 0) { + ip->family = IPADDR_INET6; + memcpy(ip->addr.in6, in6.s6_addr, sizeof (ip->addr.in6)); + return 1; + } +#else + unsigned long a, b, c, d, n; + + n = sscanf(addr, "%lu.%lu.%lu.%lu", &a, &b, &c, &d); + if (n == 4) { + ip->family = IPADDR_INET4; + ip->addr.in4 = ((a & 0xff) << 24) | ((b & 0xff) << 16) | + ((c & 0xff) << 8) | (d & 0xff); + return 1; + } +#endif + + return 0; +} + +/* ================================================== */ + +unsigned long +UTI_IPToRefid(IPAddr *ip) +{ + MD5_CTX ctx; + + switch (ip->family) { + case IPADDR_INET4: + return ip->addr.in4; + case IPADDR_INET6: + MD5Init(&ctx); + MD5Update(&ctx, (unsigned const char *) ip->addr.in6, sizeof (ip->addr.in6)); + MD5Final(&ctx); + return ctx.digest[0] << 24 | ctx.digest[1] << 16 | ctx.digest[2] << 8 | ctx.digest[3]; + } + return 0; +} + +/* ================================================== */ + +void +UTI_IPHostToNetwork(IPAddr *src, IPAddr *dest) +{ + /* Don't send uninitialized bytes over network */ + memset(dest, 0, sizeof (IPAddr)); + + dest->family = htons(src->family); + + switch (src->family) { + case IPADDR_INET4: + dest->addr.in4 = htonl(src->addr.in4); + break; + case IPADDR_INET6: + memcpy(dest->addr.in6, src->addr.in6, sizeof (dest->addr.in6)); + break; + } +} + +/* ================================================== */ + +void +UTI_IPNetworkToHost(IPAddr *src, IPAddr *dest) +{ + dest->family = ntohs(src->family); + + switch (dest->family) { + case IPADDR_INET4: + dest->addr.in4 = ntohl(src->addr.in4); + break; + case IPADDR_INET6: + memcpy(dest->addr.in6, src->addr.in6, sizeof (dest->addr.in6)); + break; + } +} + +/* ================================================== */ + +int +UTI_CompareIPs(IPAddr *a, IPAddr *b, IPAddr *mask) +{ + int i, d; + + if (a->family != b->family) + return a->family - b->family; + + if (mask && mask->family != b->family) + mask = NULL; + + switch (a->family) { + case IPADDR_UNSPEC: + return 0; + case IPADDR_INET4: + if (mask) + return (a->addr.in4 & mask->addr.in4) - (b->addr.in4 & mask->addr.in4); + else + return a->addr.in4 - b->addr.in4; + case IPADDR_INET6: + for (i = 0, d = 0; !d && i < 16; i++) { + if (mask) + d = (a->addr.in6[i] & mask->addr.in6[i]) - + (b->addr.in6[i] & mask->addr.in6[i]); + else + d = a->addr.in6[i] - b->addr.in6[i]; + } + return d; + } + return 0; +} + +/* ================================================== */ + char * UTI_TimeToLogForm(time_t t) { diff --git a/util.h b/util.h index 1c41b74..1ec2184 100644 --- a/util.h +++ b/util.h @@ -33,6 +33,7 @@ #include "sysincl.h" +#include "addressing.h" #include "ntp.h" /* Convert a timeval into a floating point number of seconds */ @@ -75,8 +76,15 @@ extern char *UTI_TimestampToString(NTP_int64 *ts); /* Convert ref_id into a temporary string, for diagnostics */ extern char *UTI_RefidToString(unsigned long ref_id); -/* Convert an IP address to dotted quad notation, for diagnostics */ +/* Convert an IP address to string, for diagnostics */ extern char *UTI_IPToDottedQuad(unsigned long ip); +extern char *UTI_IPToString(IPAddr *ip); + +extern int UTI_StringToIP(const char *addr, IPAddr *ip); +extern unsigned long UTI_IPToRefid(IPAddr *ip); +extern void UTI_IPHostToNetwork(IPAddr *src, IPAddr *dest); +extern void UTI_IPNetworkToHost(IPAddr *src, IPAddr *dest); +extern int UTI_CompareIPs(IPAddr *a, IPAddr *b, IPAddr *mask); extern char *UTI_TimeToLogForm(time_t t);