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