#include <l_stdlib.h>
#include <ntp_fp.h>
#include <ntp.h>
#include <ntp_stdlib.h>
#include <ntp_unixtime.h>
#include <isc/result.h>
#include <isc/net.h>
#include <stdio.h>
#include <sntp-opts.h>
#include "crypto.h"
#include "kod_management.h"
#include "networking.h"
#include "utilities.h"
#include "log.h"
char *progname = "sntp";
int ai_fam_pref = AF_UNSPEC;
volatile int debug;
struct key *keys = NULL;
void set_li_vn_mode (struct pkt *spkt, char leap, char version, char mode);
int sntp_main (int argc, char **argv);
int on_wire (struct addrinfo *host);
int set_time (double offset);
int
main (
int argc,
char **argv
)
{
return sntp_main(argc, argv);
}
int
sntp_main (
int argc,
char **argv
)
{
register int c;
struct kod_entry *reason = NULL;
int optct;
int sync_data_suc = 0;
struct addrinfo **resh = NULL;
struct addrinfo *ai;
int resc;
int kodc;
int ow_ret = -1;
char *hostname;
optct = optionProcess(&sntpOptions, argc, argv);
argc -= optct;
argv += optct;
if (isc_net_probeipv6() != ISC_R_SUCCESS) {
ai_fam_pref = AF_INET;
#ifdef DEBUG
printf("No ipv6 support available, forcing ipv4\n");
#endif
}
else {
if (HAVE_OPT(IPV4))
ai_fam_pref = AF_INET;
else if (HAVE_OPT(IPV6))
ai_fam_pref = AF_INET6;
}
if (HAVE_OPT(FILELOG))
init_log(OPT_ARG(FILELOG));
if (HAVE_OPT(KOD))
kod_init_kod_db(OPT_ARG(KOD));
else
kod_init_kod_db("/var/db/ntp-kod");
if (HAVE_OPT(KEYFILE))
auth_init(OPT_ARG(KEYFILE), &keys);
#ifdef EXERCISE_KOD_DB
add_entry("192.168.169.170", "DENY");
add_entry("192.168.169.171", "DENY");
add_entry("192.168.169.172", "DENY");
add_entry("192.168.169.173", "DENY");
add_entry("192.168.169.174", "DENY");
delete_entry("192.168.169.174", "DENY");
delete_entry("192.168.169.172", "DENY");
delete_entry("192.168.169.170", "DENY");
if ((kodc = search_entry("192.168.169.173", &reason)) == 0)
printf("entry for 192.168.169.173 not found but should have been!\n");
else
free(reason);
#endif
resc = resolve_hosts(argv, argc, &resh, ai_fam_pref);
if (resc < 1) {
printf("Unable to resolve hostname(s)\n");
return -1;
}
for (c = 0; c < resc && !sync_data_suc; c++) {
ai = resh[c];
do {
hostname = addrinfo_to_str(ai);
if ((kodc = search_entry(hostname, &reason)) == 0) {
if (is_reachable(ai)) {
ow_ret = on_wire(ai);
if (ow_ret < 0)
printf("on_wire failed for server %s!\n", hostname);
else
sync_data_suc = 1;
}
} else {
printf("%d prior KoD%s for %s, skipping.\n",
kodc, (kodc > 1) ? "s" : "", hostname);
free(reason);
}
free(hostname);
ai = ai->ai_next;
} while (NULL != ai && !sync_data_suc);
freeaddrinfo(resh[c]);
}
free(resh);
return ow_ret != 0;
}
int
on_wire (
struct addrinfo *host
)
{
char logmsg[32 + INET6_ADDRSTRLEN];
char addr_buf[INET6_ADDRSTRLEN];
register int try;
SOCKET sock;
struct pkt x_pkt;
struct pkt r_pkt;
char *ref;
for(try=0; try<5; try++) {
struct timeval tv_xmt, tv_dst;
double t21, t34, delta, offset, precision, root_dispersion;
int digits, error, rpktl, sw_case;
char *hostname = NULL, *ts_str = NULL;
char *log_str;
u_fp p_rdly, p_rdsp;
l_fp p_rec, p_xmt, p_ref, p_org, xmt, tmp, dst;
memset(&r_pkt, 0, sizeof(r_pkt));
memset(&x_pkt, 0, sizeof(x_pkt));
error = GETTIMEOFDAY(&tv_xmt, (struct timezone *)NULL);
tv_xmt.tv_sec += JAN_1970;
#ifdef DEBUG
printf("sntp on_wire: Current time sec: %i msec: %i\n", (unsigned int) tv_xmt.tv_sec,
(unsigned int) tv_xmt.tv_usec);
#endif
TVTOTS(&tv_xmt, &xmt);
HTONL_FP(&xmt, &(x_pkt.xmt));
x_pkt.stratum = STRATUM_TO_PKT(STRATUM_UNSPEC);
x_pkt.ppoll = 8;
set_li_vn_mode(&x_pkt, LEAP_NOTINSYNC, 4, 3);
create_socket(&sock, (sockaddr_u *)host->ai_addr);
if (0 == sendpkt(sock, (sockaddr_u *)host->ai_addr, &x_pkt, LEN_PKT_NOMAC)) {
rpktl = recvpkt(sock, &r_pkt, &x_pkt);
} else {
rpktl = SERVER_UNUSEABLE;
}
closesocket(sock);
if(rpktl > 0)
sw_case = 1;
else
sw_case = rpktl;
switch(sw_case) {
case SERVER_UNUSEABLE:
if (ENABLED_OPT(NORMALVERBOSE)) {
printf("Server unusable\n");
}
return -1;
break;
case PACKET_UNUSEABLE:
if (ENABLED_OPT(NORMALVERBOSE)) {
printf("Packet unusable\n");
}
break;
case SERVER_AUTH_FAIL:
if (ENABLED_OPT(NORMALVERBOSE)) {
printf("Server authorization failure\n");
}
break;
case KOD_DEMOBILIZE:
hostname = addrinfo_to_str(host);
ref = (char *)&r_pkt.refid;
add_entry(hostname, ref);
if (ENABLED_OPT(NORMALVERBOSE))
printf("sntp on_wire: Received KOD packet with code: %c%c%c%c from %s, demobilizing all connections\n",
ref[0], ref[1], ref[2], ref[3],
hostname);
log_str = emalloc(INET6_ADDRSTRLEN + 72);
snprintf(log_str, INET6_ADDRSTRLEN + 72,
"Received a KOD packet with code %c%c%c%c from %s, demobilizing all connections",
ref[0], ref[1], ref[2], ref[3],
hostname);
log_msg(log_str, 2);
free(log_str);
break;
case KOD_RATE:
break;
case 1:
p_rdly = NTOHS_FP(r_pkt.rootdelay);
p_rdsp = NTOHS_FP(r_pkt.rootdisp);
NTOHL_FP(&r_pkt.reftime, &p_ref);
NTOHL_FP(&r_pkt.org, &p_org);
NTOHL_FP(&r_pkt.rec, &p_rec);
NTOHL_FP(&r_pkt.xmt, &p_xmt);
if (ENABLED_OPT(NORMALVERBOSE)) {
getnameinfo(host->ai_addr, host->ai_addrlen, addr_buf,
sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
printf("sntp on_wire: Received %i bytes from %s\n", rpktl, addr_buf);
}
precision = LOGTOD(r_pkt.precision);
#ifdef DEBUG
printf("sntp precision: %f\n", precision);
#endif
for (digits = 0; (precision *= 10.) < 1.; ++digits)
;
if (digits > 6)
digits = 6;
root_dispersion = FPTOD(p_rdsp);
#ifdef DEBUG
printf("sntp rootdelay: %f\n", FPTOD(p_rdly));
printf("sntp rootdisp: %f\n", root_dispersion);
pkt_output(&r_pkt, rpktl, stdout);
printf("sntp on_wire: r_pkt.reftime:\n");
l_fp_output(&(r_pkt.reftime), stdout);
printf("sntp on_wire: r_pkt.org:\n");
l_fp_output(&(r_pkt.org), stdout);
printf("sntp on_wire: r_pkt.rec:\n");
l_fp_output(&(r_pkt.rec), stdout);
printf("sntp on_wire: r_pkt.rec:\n");
l_fp_output_bin(&(r_pkt.rec), stdout);
printf("sntp on_wire: r_pkt.rec:\n");
l_fp_output_dec(&(r_pkt.rec), stdout);
printf("sntp on_wire: r_pkt.xmt:\n");
l_fp_output(&(r_pkt.xmt), stdout);
#endif
GETTIMEOFDAY(&tv_dst, (struct timezone *)NULL);
tv_dst.tv_sec += JAN_1970;
tmp = p_rec;
L_SUB(&tmp, &p_org);
LFPTOD(&tmp, t21);
TVTOTS(&tv_dst, &dst);
tmp = p_xmt;
L_SUB(&tmp, &dst);
LFPTOD(&tmp, t34);
offset = (t21 + t34) / 2.;
delta = t21 - t34;
if(ENABLED_OPT(NORMALVERBOSE))
printf("sntp on_wire:\tt21: %.6f\t\t t34: %.6f\n\t\tdelta: %.6f\t offset: %.6f\n",
t21, t34, delta, offset);
ts_str = tv_to_str(&tv_dst);
printf("%s ", ts_str);
if(offset > 0)
printf("+");
printf("%.*f", digits, offset);
if (root_dispersion > 0.)
printf(" +/- %f secs", root_dispersion);
printf("\n");
free(ts_str);
if(ENABLED_OPT(SETTOD) || ENABLED_OPT(ADJTIME))
return set_time(offset);
return 0;
}
}
getnameinfo(host->ai_addr, host->ai_addrlen, addr_buf, sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
snprintf(logmsg, sizeof(logmsg), "Received no useable packet from %s!", addr_buf);
log_msg(logmsg, 1);
if (ENABLED_OPT(NORMALVERBOSE))
printf("sntp on_wire: Received no useable packet from %s!\n", addr_buf);
return -1;
}
void
set_li_vn_mode (
struct pkt *spkt,
char leap,
char version,
char mode
)
{
if(leap > 3) {
debug_msg("set_li_vn_mode: leap > 3 using max. 3");
leap = 3;
}
if(mode > 7) {
debug_msg("set_li_vn_mode: mode > 7, using client mode 3");
mode = 3;
}
spkt->li_vn_mode = leap << 6;
spkt->li_vn_mode |= version << 3;
spkt->li_vn_mode |= mode;
}
int
set_time (
double offset
)
{
const int USEC_PER_SEC = 1000000;
struct timeval tp;
double frac, whole;
frac = modf(offset, &whole);
if(ENABLED_OPT(SETTOD)) {
GETTIMEOFDAY(&tp, (struct timezone *)NULL);
tp.tv_sec += (int) offset;
tp.tv_usec += frac * USEC_PER_SEC;
if (tp.tv_usec < 0) {
tp.tv_usec += USEC_PER_SEC;
tp.tv_sec--;
} else if (tp.tv_usec > USEC_PER_SEC) {
tp.tv_usec -= USEC_PER_SEC;
tp.tv_sec++;
}
if(SETTIMEOFDAY(&tp, (struct timezone *)NULL) < 0) {
printf("set_time: settimeofday(): Time not set: %s\n",
strerror(errno));
return -1;
}
else {
return 0;
}
}
else {
tp.tv_sec = (int) offset;
tp.tv_usec = frac * USEC_PER_SEC;
if(ADJTIMEOFDAY(&tp, NULL) < 0) {
printf("set_time: adjtime(): Time not set: %s\n",
strerror(errno));
return -1;
}
else {
return 0;
}
}
}