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