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