6 #include <ntp_stdlib.h>
7 #include <ntp_unixtime.h>
8 #include <isc/result.h>
12 #include <sntp-opts.h>
15 #include "kod_management.h"
16 #include "networking.h"
17 #include "utilities.h"
20 char *progname
= "sntp"; /* for msyslog */
22 int ai_fam_pref
= AF_UNSPEC
;
25 struct key
*keys
= NULL
;
27 void set_li_vn_mode (struct pkt
*spkt
, char leap
, char version
, char mode
);
28 int sntp_main (int argc
, char **argv
);
29 int on_wire (struct addrinfo
*host
);
30 int set_time (double offset
);
39 return sntp_main(argc
, argv
);
43 * The actual main function.
52 struct kod_entry
*reason
= NULL
;
54 int sync_data_suc
= 0;
55 struct addrinfo
**resh
= NULL
;
63 if (isc_net_probeipv6() != ISC_R_SUCCESS
) {
64 ai_fam_pref
= AF_INET
;
66 printf("No ipv6 support available, forcing ipv4\n");
70 /* Check for options -4 and -6 */
72 ai_fam_pref
= AF_INET
;
73 else if (HAVE_OPT(IPV6
))
74 ai_fam_pref
= AF_INET6
;
77 log_msg("Started sntp", 0);
79 optct
= optionProcess(&sntpOptions
, argc
, argv
);
83 /* Parse config file if declared TODO */
85 /* Initialize logging system */
86 if (HAVE_OPT(FILELOG
))
87 init_log(OPT_ARG(FILELOG
));
90 * If there's a specified KOD file init KOD system. If not use
91 * default file. For embedded systems with no writable
92 * filesystem, -K /dev/null can be used to disable KoD storage.
95 kod_init_kod_db(OPT_ARG(KOD
));
97 kod_init_kod_db("/var/db/ntp-kod");
99 if (HAVE_OPT(KEYFILE
))
100 auth_init(OPT_ARG(KEYFILE
), &keys
);
102 #ifdef EXERCISE_KOD_DB
103 add_entry("192.168.169.170", "DENY");
104 add_entry("192.168.169.171", "DENY");
105 add_entry("192.168.169.172", "DENY");
106 add_entry("192.168.169.173", "DENY");
107 add_entry("192.168.169.174", "DENY");
108 delete_entry("192.168.169.174", "DENY");
109 delete_entry("192.168.169.172", "DENY");
110 delete_entry("192.168.169.170", "DENY");
111 if ((kodc
= search_entry("192.168.169.173", &reason
)) == 0)
112 printf("entry for 192.168.169.173 not found but should have been!\n");
117 /* Considering employing a variable that prevents functions of doing anything until
118 * everything is initialized properly
120 resc
= resolve_hosts(argv
, argc
, &resh
, ai_fam_pref
);
123 printf("Unable to resolve hostname(s)\n");
127 /* Select a certain ntp server according to simple criteria? For now
128 * let's just pay attention to previous KoDs.
130 for (c
= 0; c
< resc
&& !sync_data_suc
; c
++) {
133 hostname
= addrinfo_to_str(ai
);
135 if ((kodc
= search_entry(hostname
, &reason
)) == 0) {
136 if (is_reachable(ai
)) {
137 ow_ret
= on_wire(ai
);
139 printf("on_wire failed for server %s!\n", hostname
);
144 printf("%d prior KoD%s for %s, skipping.\n",
145 kodc
, (kodc
> 1) ? "s" : "", hostname
);
150 } while (NULL
!= ai
);
151 freeaddrinfo(resh
[c
]);
158 /* The heart of (S)NTP, exchange NTP packets and compute values to correct the local clock */
161 struct addrinfo
*host
164 char logmsg
[32 + INET6_ADDRSTRLEN
];
165 char addr_buf
[INET6_ADDRSTRLEN
];
172 for(try=0; try<5; try++) {
173 struct timeval tv_xmt
, tv_dst
;
174 double t21
, t34
, delta
, offset
, precision
, root_dispersion
;
175 int digits
, error
, rpktl
, sw_case
;
176 char *hostname
= NULL
, *ts_str
= NULL
;
179 l_fp p_rec
, p_xmt
, p_ref
, p_org
, xmt
, tmp
, dst
;
181 memset(&r_pkt
, 0, sizeof(r_pkt
));
182 memset(&x_pkt
, 0, sizeof(x_pkt
));
184 error
= GETTIMEOFDAY(&tv_xmt
, (struct timezone
*)NULL
);
186 tv_xmt
.tv_sec
+= JAN_1970
;
189 printf("sntp on_wire: Current time sec: %i msec: %i\n", (unsigned int) tv_xmt
.tv_sec
,
190 (unsigned int) tv_xmt
.tv_usec
);
193 TVTOTS(&tv_xmt
, &xmt
);
194 HTONL_FP(&xmt
, &(x_pkt
.xmt
));
196 x_pkt
.stratum
= STRATUM_TO_PKT(STRATUM_UNSPEC
);
198 /* FIXME! Modus broadcast + adr. check -> bdr. pkt */
199 set_li_vn_mode(&x_pkt
, LEAP_NOTINSYNC
, 4, 3);
201 create_socket(&sock
, (sockaddr_u
*)host
->ai_addr
);
203 sendpkt(sock
, (sockaddr_u
*)host
->ai_addr
, &x_pkt
, LEN_PKT_NOMAC
);
204 rpktl
= recvpkt(sock
, &r_pkt
, &x_pkt
);
214 case SERVER_UNUSEABLE
:
218 case PACKET_UNUSEABLE
:
221 case SERVER_AUTH_FAIL
:
225 /* Received a DENY or RESTR KOD packet */
226 hostname
= addrinfo_to_str(host
);
227 ref
= (char *)&r_pkt
.refid
;
228 add_entry(hostname
, ref
);
230 if (ENABLED_OPT(NORMALVERBOSE
))
231 printf("sntp on_wire: Received KOD packet with code: %c%c%c%c from %s, demobilizing all connections\n",
232 ref
[0], ref
[1], ref
[2], ref
[3],
235 log_str
= emalloc(INET6_ADDRSTRLEN
+ 72);
236 snprintf(log_str
, INET6_ADDRSTRLEN
+ 72,
237 "Received a KOD packet with code %c%c%c%c from %s, demobilizing all connections",
238 ref
[0], ref
[1], ref
[2], ref
[3],
245 /* Hmm... probably we should sleep a bit here */
250 /* Convert timestamps from network to host byte order */
251 p_rdly
= NTOHS_FP(r_pkt
.rootdelay
);
252 p_rdsp
= NTOHS_FP(r_pkt
.rootdisp
);
253 NTOHL_FP(&r_pkt
.reftime
, &p_ref
);
254 NTOHL_FP(&r_pkt
.org
, &p_org
);
255 NTOHL_FP(&r_pkt
.rec
, &p_rec
);
256 NTOHL_FP(&r_pkt
.xmt
, &p_xmt
);
258 if (ENABLED_OPT(NORMALVERBOSE
)) {
259 getnameinfo(host
->ai_addr
, host
->ai_addrlen
, addr_buf
,
260 sizeof(addr_buf
), NULL
, 0, NI_NUMERICHOST
);
262 printf("sntp on_wire: Received %i bytes from %s\n", rpktl
, addr_buf
);
265 precision
= LOGTOD(r_pkt
.precision
);
267 printf("sntp precision: %f\n", precision
);
269 for (digits
= 0; (precision
*= 10.) < 1.; ++digits
)
274 root_dispersion
= FPTOD(p_rdsp
);
277 printf("sntp rootdelay: %f\n", FPTOD(p_rdly
));
278 printf("sntp rootdisp: %f\n", root_dispersion
);
280 pkt_output(&r_pkt
, rpktl
, stdout
);
282 printf("sntp on_wire: r_pkt.reftime:\n");
283 l_fp_output(&(r_pkt
.reftime
), stdout
);
284 printf("sntp on_wire: r_pkt.org:\n");
285 l_fp_output(&(r_pkt
.org
), stdout
);
286 printf("sntp on_wire: r_pkt.rec:\n");
287 l_fp_output(&(r_pkt
.rec
), stdout
);
288 printf("sntp on_wire: r_pkt.rec:\n");
289 l_fp_output_bin(&(r_pkt
.rec
), stdout
);
290 printf("sntp on_wire: r_pkt.rec:\n");
291 l_fp_output_dec(&(r_pkt
.rec
), stdout
);
292 printf("sntp on_wire: r_pkt.xmt:\n");
293 l_fp_output(&(r_pkt
.xmt
), stdout
);
296 /* Compute offset etc. */
297 GETTIMEOFDAY(&tv_dst
, (struct timezone
*)NULL
);
299 tv_dst
.tv_sec
+= JAN_1970
;
306 TVTOTS(&tv_dst
, &dst
);
313 offset
= (t21
+ t34
) / 2.;
316 if(ENABLED_OPT(NORMALVERBOSE
))
317 printf("sntp on_wire:\tt21: %.6f\t\t t34: %.6f\n\t\tdelta: %.6f\t offset: %.6f\n",
318 t21
, t34
, delta
, offset
);
320 ts_str
= tv_to_str(&tv_dst
);
322 printf("%s ", ts_str
);
327 printf("%.*f", digits
, offset
);
329 if (root_dispersion
> 0.)
330 printf(" +/- %f secs", root_dispersion
);
336 if(ENABLED_OPT(SETTOD
) || ENABLED_OPT(ADJTIME
))
337 return set_time(offset
);
343 getnameinfo(host
->ai_addr
, host
->ai_addrlen
, addr_buf
, sizeof(addr_buf
), NULL
, 0, NI_NUMERICHOST
);
345 snprintf(logmsg
, sizeof(logmsg
), "Received no useable packet from %s!", addr_buf
);
348 if (ENABLED_OPT(NORMALVERBOSE
))
349 printf("sntp on_wire: Received no useable packet from %s!\n", addr_buf
);
354 /* Compute the 8 bits for li_vn_mode */
365 debug_msg("set_li_vn_mode: leap > 3 using max. 3");
370 debug_msg("set_li_vn_mode: mode > 7, using client mode 3");
374 spkt
->li_vn_mode
= leap
<< 6;
375 spkt
->li_vn_mode
|= version
<< 3;
376 spkt
->li_vn_mode
|= mode
;
379 /* set_time corrects the local clock by offset with either settimeofday() or by default
380 * with adjtime()/adjusttimeofday().
389 if(ENABLED_OPT(SETTOD
)) {
390 GETTIMEOFDAY(&tp
, (struct timezone
*)NULL
);
392 tp
.tv_sec
+= (int) offset
;
393 tp
.tv_usec
+= offset
- (double)((int)offset
);
395 if(SETTIMEOFDAY(&tp
, (struct timezone
*)NULL
) < 0) {
396 printf("set_time: settimeofday(): Time not set: %s\n",
405 tp
.tv_sec
= (int) offset
;
406 tp
.tv_usec
= offset
- (double)((int)offset
);
408 if(ADJTIMEOFDAY(&tp
, NULL
) < 0) {
409 printf("set_time: adjtime(): Time not set: %s\n",