1#include <l_stdlib.h>
2#include <ntp_fp.h>
3#include <ntp.h>
4#include <ntp_stdlib.h>
5#include <ntp_unixtime.h>
6#include <isc/result.h>
7#include <isc/net.h>
8#include <stdio.h>
9
10#include <sntp-opts.h>
11
12#include "crypto.h"
13#include "kod_management.h"
14#include "networking.h"
15#include "utilities.h"
16#include "log.h"
17
18char *progname = "sntp";	/* for msyslog */
19
20int ai_fam_pref = AF_UNSPEC;
21volatile int debug;
22
23struct key *keys = NULL;
24
25void set_li_vn_mode (struct pkt *spkt, char leap, char version, char mode);
26int sntp_main (int argc, char **argv);
27int on_wire (struct addrinfo *host);
28int set_time (double offset);
29
30
31int
32main (
33		int argc,
34		char **argv
35		)
36{
37	return sntp_main(argc, argv);
38}
39
40/*
41 * The actual main function.
42 */
43int
44sntp_main (
45		int argc,
46		char **argv
47		)
48{
49	register int c;
50	struct kod_entry *reason = NULL;
51	int optct;
52	int sync_data_suc = 0;
53	struct addrinfo **resh = NULL;
54	struct addrinfo *ai;
55	int resc;
56	int kodc;
57	int ow_ret = -1;
58	char *hostname;
59
60	optct = optionProcess(&sntpOptions, argc, argv);
61	argc -= optct;
62	argv += optct;
63
64	/* IPv6 available? */
65	if (isc_net_probeipv6() != ISC_R_SUCCESS) {
66		ai_fam_pref = AF_INET;
67#ifdef DEBUG
68		printf("No ipv6 support available, forcing ipv4\n");
69#endif
70	}
71	else {
72		/* Check for options -4 and -6 */
73		if (HAVE_OPT(IPV4))
74			ai_fam_pref = AF_INET;
75		else if (HAVE_OPT(IPV6))
76			ai_fam_pref = AF_INET6;
77	}
78
79	/* Parse config file if declared TODO */
80
81	/* Initialize logging system */
82	if (HAVE_OPT(FILELOG))
83		init_log(OPT_ARG(FILELOG));
84
85	/*
86	 * If there's a specified KOD file init KOD system.  If not use
87	 * default file.  For embedded systems with no writable
88	 * filesystem, -K /dev/null can be used to disable KoD storage.
89	 */
90	if (HAVE_OPT(KOD))
91		kod_init_kod_db(OPT_ARG(KOD));
92	else
93		kod_init_kod_db("/var/db/ntp-kod");
94
95	if (HAVE_OPT(KEYFILE))
96		auth_init(OPT_ARG(KEYFILE), &keys);
97
98#ifdef EXERCISE_KOD_DB
99	add_entry("192.168.169.170", "DENY");
100	add_entry("192.168.169.171", "DENY");
101	add_entry("192.168.169.172", "DENY");
102	add_entry("192.168.169.173", "DENY");
103	add_entry("192.168.169.174", "DENY");
104	delete_entry("192.168.169.174", "DENY");
105	delete_entry("192.168.169.172", "DENY");
106	delete_entry("192.168.169.170", "DENY");
107	if ((kodc = search_entry("192.168.169.173", &reason)) == 0)
108		printf("entry for 192.168.169.173 not found but should have been!\n");
109	else
110		free(reason);
111#endif
112
113	/* Considering employing a variable that prevents functions of doing anything until
114	 * everything is initialized properly
115	 */
116	resc = resolve_hosts(argv, argc, "123", &resh, ai_fam_pref);
117
118	if (resc < 1) {
119		printf("Unable to resolve hostname(s)\n");
120		return -1;
121	}
122
123	/* Select a certain ntp server according to simple criteria? For now
124	 * let's just pay attention to previous KoDs.
125	 */
126	for (c = 0; c < resc && !sync_data_suc; c++) {
127		ai = resh[c];
128		do {
129			hostname = addrinfo_to_str(ai);
130
131			if ((kodc = search_entry(hostname, &reason)) == 0) {
132				if (is_reachable(ai)) {
133					ow_ret = on_wire(ai);
134					if (ow_ret < 0)
135						printf("on_wire failed for server %s!\n", hostname);
136					else
137						sync_data_suc = 1;
138				}
139			} else {
140				printf("%d prior KoD%s for %s, skipping.\n",
141					kodc, (kodc > 1) ? "s" : "", hostname);
142				free(reason);
143			}
144			free(hostname);
145			ai = ai->ai_next;
146		} while (NULL != ai && !sync_data_suc);
147		freeaddrinfo(resh[c]);
148	}
149	free(resh);
150
151	return ow_ret != 0;
152}
153
154/* The heart of (S)NTP, exchange NTP packets and compute values to correct the local clock */
155int
156on_wire (
157		struct addrinfo *host
158					)
159{
160	char logmsg[32 + INET6_ADDRSTRLEN];
161	char addr_buf[INET6_ADDRSTRLEN];
162	register int try;
163	SOCKET sock;
164	struct pkt x_pkt;
165	struct pkt r_pkt;
166	char *ref;
167
168	for(try=0; try<5; try++) {
169		struct timeval tv_xmt, tv_dst;
170		double t21, t34, delta, offset, precision, root_dispersion;
171		int digits, error, rpktl, sw_case;
172		char *hostname = NULL, *ts_str = NULL;
173		char *log_str;
174		u_fp p_rdly, p_rdsp;
175		l_fp p_rec, p_xmt, p_ref, p_org, xmt, tmp, dst;
176
177		memset(&r_pkt, 0, sizeof(r_pkt));
178		memset(&x_pkt, 0, sizeof(x_pkt));
179
180		error = GETTIMEOFDAY(&tv_xmt, (struct timezone *)NULL);
181
182		tv_xmt.tv_sec += JAN_1970;
183
184#ifdef DEBUG
185		printf("sntp on_wire: Current time sec: %i msec: %i\n", (unsigned int) tv_xmt.tv_sec,
186				(unsigned int) tv_xmt.tv_usec);
187#endif
188
189		TVTOTS(&tv_xmt, &xmt);
190		HTONL_FP(&xmt, &(x_pkt.xmt));
191
192		x_pkt.stratum = STRATUM_TO_PKT(STRATUM_UNSPEC);
193		x_pkt.ppoll = 8;
194		/* FIXME! Modus broadcast + adr. check -> bdr. pkt */
195		set_li_vn_mode(&x_pkt, LEAP_NOTINSYNC, 4, 3);
196
197		create_socket(&sock, (sockaddr_u *)host->ai_addr);
198
199        struct timeval timeout_tv = { 0 };
200        if(ENABLED_OPT(TIMEOUT)) {
201            timeout_tv.tv_sec = (int) OPT_ARG(TIMEOUT);
202        } else {
203            timeout_tv.tv_sec = 15;
204        }
205
206		if (0 == sendpkt(sock, (sockaddr_u *)host->ai_addr, &x_pkt, LEN_PKT_NOMAC)) {
207			rpktl = recvpkt(sock, timeout_tv, &r_pkt, &x_pkt);
208		} else {
209			rpktl = SERVER_UNUSEABLE;
210		}
211
212
213		closesocket(sock);
214
215		if(rpktl > 0)
216			sw_case = 1;
217		else
218			sw_case = rpktl;
219
220		switch(sw_case) {
221			case SERVER_UNUSEABLE:
222				if (ENABLED_OPT(NORMALVERBOSE)) {
223					printf("Server unusable\n");
224				}
225				return -1;
226				break;
227
228			case PACKET_UNUSEABLE:
229				if (ENABLED_OPT(NORMALVERBOSE)) {
230					printf("Packet unusable\n");
231				}
232				break;
233
234			case SERVER_AUTH_FAIL:
235				if (ENABLED_OPT(NORMALVERBOSE)) {
236					printf("Server authorization failure\n");
237				}
238				break;
239
240			case KOD_DEMOBILIZE:
241				/* Received a DENY or RESTR KOD packet */
242				hostname = addrinfo_to_str(host);
243				ref = (char *)&r_pkt.refid;
244				add_entry(hostname, ref);
245
246				if (ENABLED_OPT(NORMALVERBOSE))
247					printf("sntp on_wire: Received KOD packet with code: %c%c%c%c from %s, demobilizing all connections\n",
248					       ref[0], ref[1], ref[2], ref[3],
249					       hostname);
250
251				log_str = emalloc(INET6_ADDRSTRLEN + 72);
252				snprintf(log_str, INET6_ADDRSTRLEN + 72,
253					 "Received a KOD packet with code %c%c%c%c from %s, demobilizing all connections",
254					 ref[0], ref[1], ref[2], ref[3],
255					 hostname);
256				log_msg(log_str, 2);
257				free(log_str);
258				break;
259
260			case KOD_RATE:
261				/* Hmm... probably we should sleep a bit here */
262				break;
263
264			case 1:
265
266			/* Convert timestamps from network to host byte order */
267			p_rdly = NTOHS_FP(r_pkt.rootdelay);
268			p_rdsp = NTOHS_FP(r_pkt.rootdisp);
269			NTOHL_FP(&r_pkt.reftime, &p_ref);
270			NTOHL_FP(&r_pkt.org, &p_org);
271			NTOHL_FP(&r_pkt.rec, &p_rec);
272			NTOHL_FP(&r_pkt.xmt, &p_xmt);
273
274			if (ENABLED_OPT(NORMALVERBOSE)) {
275				getnameinfo(host->ai_addr, host->ai_addrlen, addr_buf,
276						sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
277
278				printf("sntp on_wire: Received %i bytes from %s\n", rpktl, addr_buf);
279			}
280
281			precision = LOGTOD(r_pkt.precision);
282#ifdef DEBUG
283			printf("sntp precision: %f\n", precision);
284#endif /* DEBUG */
285			for (digits = 0; (precision *= 10.) < 1.; ++digits)
286				/* empty */ ;
287			if (digits > 6)
288				digits = 6;
289
290			root_dispersion = FPTOD(p_rdsp);
291
292#ifdef DEBUG
293			printf("sntp rootdelay: %f\n", FPTOD(p_rdly));
294			printf("sntp rootdisp: %f\n", root_dispersion);
295
296			pkt_output(&r_pkt, rpktl, stdout);
297
298			printf("sntp on_wire: r_pkt.reftime:\n");
299			l_fp_output(&(r_pkt.reftime), stdout);
300			printf("sntp on_wire: r_pkt.org:\n");
301			l_fp_output(&(r_pkt.org), stdout);
302			printf("sntp on_wire: r_pkt.rec:\n");
303			l_fp_output(&(r_pkt.rec), stdout);
304			printf("sntp on_wire: r_pkt.rec:\n");
305			l_fp_output_bin(&(r_pkt.rec), stdout);
306			printf("sntp on_wire: r_pkt.rec:\n");
307			l_fp_output_dec(&(r_pkt.rec), stdout);
308			printf("sntp on_wire: r_pkt.xmt:\n");
309			l_fp_output(&(r_pkt.xmt), stdout);
310#endif
311
312			/* Compute offset etc. */
313			GETTIMEOFDAY(&tv_dst, (struct timezone *)NULL);
314
315			tv_dst.tv_sec += JAN_1970;
316
317			tmp = p_rec;
318			L_SUB(&tmp, &p_org);
319
320			LFPTOD(&tmp, t21);
321
322			TVTOTS(&tv_dst, &dst);
323
324			tmp = p_xmt;
325			L_SUB(&tmp, &dst);
326
327			LFPTOD(&tmp, t34);
328
329			offset = (t21 + t34) / 2.;
330			delta = t21 - t34;
331
332			if(ENABLED_OPT(NORMALVERBOSE))
333				printf("sntp on_wire:\tt21: %.6f\t\t t34: %.6f\n\t\tdelta: %.6f\t offset: %.6f\n",
334					t21, t34, delta, offset);
335
336			ts_str = tv_to_str(&tv_dst);
337
338			printf("%s ", ts_str);
339
340			if(offset > 0)
341				printf("+");
342
343			printf("%.*f", digits, offset);
344
345			if (root_dispersion > 0.)
346				printf(" +/- %f secs", root_dispersion);
347
348			printf("\n");
349
350			free(ts_str);
351
352			if(ENABLED_OPT(SETTOD) || ENABLED_OPT(ADJTIME))
353				return set_time(offset);
354
355			return 0;
356		}
357	}
358
359	getnameinfo(host->ai_addr, host->ai_addrlen, addr_buf, sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
360
361	snprintf(logmsg, sizeof(logmsg), "Received no useable packet from %s!", addr_buf);
362	log_msg(logmsg, 1);
363
364	if (ENABLED_OPT(NORMALVERBOSE))
365		printf("sntp on_wire: Received no useable packet from %s!\n", addr_buf);
366
367	return -1;
368}
369
370/* Compute the 8 bits for li_vn_mode */
371void
372set_li_vn_mode (
373		struct pkt *spkt,
374		char leap,
375		char version,
376		char mode
377	       )
378{
379
380	if(leap > 3) {
381		debug_msg("set_li_vn_mode: leap > 3 using max. 3");
382		leap = 3;
383	}
384
385	if(mode > 7) {
386		debug_msg("set_li_vn_mode: mode > 7, using client mode 3");
387		mode = 3;
388	}
389
390	spkt->li_vn_mode  = leap << 6;
391	spkt->li_vn_mode |= version << 3;
392	spkt->li_vn_mode |= mode;
393}
394
395/* set_time corrects the local clock by offset with either settimeofday() or by default
396 * with adjtime()/adjusttimeofday().
397 */
398int
399set_time (
400		double offset
401	 )
402{
403	const int USEC_PER_SEC = 1000000;
404	struct timeval tp;
405	double frac, whole;
406	frac = modf(offset, &whole);
407	if(ENABLED_OPT(SETTOD)) {
408		GETTIMEOFDAY(&tp, (struct timezone *)NULL);
409
410		tp.tv_sec += (int) offset;
411		tp.tv_usec += frac * USEC_PER_SEC;
412		if (tp.tv_usec < 0) {
413			tp.tv_usec += USEC_PER_SEC;
414			tp.tv_sec--;
415		} else if (tp.tv_usec > USEC_PER_SEC) {
416			tp.tv_usec -= USEC_PER_SEC;
417			tp.tv_sec++;
418		}
419
420		if(SETTIMEOFDAY(&tp, (struct timezone *)NULL) < 0) {
421			printf("set_time: settimeofday(): Time not set: %s\n",
422				strerror(errno));
423			return -1;
424		}
425		else {
426			msyslog(LOG_NOTICE, "time set %+.6f s", offset);
427			return 0;
428		}
429	}
430	else {
431		tp.tv_sec = (int) offset;
432		tp.tv_usec = frac * USEC_PER_SEC;
433
434		if(ADJTIMEOFDAY(&tp, NULL) < 0) {
435			printf("set_time: adjtime(): Time not set: %s\n",
436				strerror(errno));
437			return -1;
438		}
439		else {
440			return 0;
441		}
442	}
443}
444