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