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, &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 if (0 == sendpkt(sock, (sockaddr_u *)host->ai_addr, &x_pkt, LEN_PKT_NOMAC)) { 200 rpktl = recvpkt(sock, &r_pkt, &x_pkt); 201 } else { 202 rpktl = SERVER_UNUSEABLE; 203 } 204 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 if (ENABLED_OPT(NORMALVERBOSE)) { 216 printf("Server unusable\n"); 217 } 218 return -1; 219 break; 220 221 case PACKET_UNUSEABLE: 222 if (ENABLED_OPT(NORMALVERBOSE)) { 223 printf("Packet unusable\n"); 224 } 225 break; 226 227 case SERVER_AUTH_FAIL: 228 if (ENABLED_OPT(NORMALVERBOSE)) { 229 printf("Server authorization failure\n"); 230 } 231 break; 232 233 case KOD_DEMOBILIZE: 234 /* Received a DENY or RESTR KOD packet */ 235 hostname = addrinfo_to_str(host); 236 ref = (char *)&r_pkt.refid; 237 add_entry(hostname, ref); 238 239 if (ENABLED_OPT(NORMALVERBOSE)) 240 printf("sntp on_wire: Received KOD packet with code: %c%c%c%c from %s, demobilizing all connections\n", 241 ref[0], ref[1], ref[2], ref[3], 242 hostname); 243 244 log_str = emalloc(INET6_ADDRSTRLEN + 72); 245 snprintf(log_str, INET6_ADDRSTRLEN + 72, 246 "Received a KOD packet with code %c%c%c%c from %s, demobilizing all connections", 247 ref[0], ref[1], ref[2], ref[3], 248 hostname); 249 log_msg(log_str, 2); 250 free(log_str); 251 break; 252 253 case KOD_RATE: 254 /* Hmm... probably we should sleep a bit here */ 255 break; 256 257 case 1: 258 259 /* Convert timestamps from network to host byte order */ 260 p_rdly = NTOHS_FP(r_pkt.rootdelay); 261 p_rdsp = NTOHS_FP(r_pkt.rootdisp); 262 NTOHL_FP(&r_pkt.reftime, &p_ref); 263 NTOHL_FP(&r_pkt.org, &p_org); 264 NTOHL_FP(&r_pkt.rec, &p_rec); 265 NTOHL_FP(&r_pkt.xmt, &p_xmt); 266 267 if (ENABLED_OPT(NORMALVERBOSE)) { 268 getnameinfo(host->ai_addr, host->ai_addrlen, addr_buf, 269 sizeof(addr_buf), NULL, 0, NI_NUMERICHOST); 270 271 printf("sntp on_wire: Received %i bytes from %s\n", rpktl, addr_buf); 272 } 273 274 precision = LOGTOD(r_pkt.precision); 275#ifdef DEBUG 276 printf("sntp precision: %f\n", precision); 277#endif /* DEBUG */ 278 for (digits = 0; (precision *= 10.) < 1.; ++digits) 279 /* empty */ ; 280 if (digits > 6) 281 digits = 6; 282 283 root_dispersion = FPTOD(p_rdsp); 284 285#ifdef DEBUG 286 printf("sntp rootdelay: %f\n", FPTOD(p_rdly)); 287 printf("sntp rootdisp: %f\n", root_dispersion); 288 289 pkt_output(&r_pkt, rpktl, stdout); 290 291 printf("sntp on_wire: r_pkt.reftime:\n"); 292 l_fp_output(&(r_pkt.reftime), stdout); 293 printf("sntp on_wire: r_pkt.org:\n"); 294 l_fp_output(&(r_pkt.org), stdout); 295 printf("sntp on_wire: r_pkt.rec:\n"); 296 l_fp_output(&(r_pkt.rec), stdout); 297 printf("sntp on_wire: r_pkt.rec:\n"); 298 l_fp_output_bin(&(r_pkt.rec), stdout); 299 printf("sntp on_wire: r_pkt.rec:\n"); 300 l_fp_output_dec(&(r_pkt.rec), stdout); 301 printf("sntp on_wire: r_pkt.xmt:\n"); 302 l_fp_output(&(r_pkt.xmt), stdout); 303#endif 304 305 /* Compute offset etc. */ 306 GETTIMEOFDAY(&tv_dst, (struct timezone *)NULL); 307 308 tv_dst.tv_sec += JAN_1970; 309 310 tmp = p_rec; 311 L_SUB(&tmp, &p_org); 312 313 LFPTOD(&tmp, t21); 314 315 TVTOTS(&tv_dst, &dst); 316 317 tmp = p_xmt; 318 L_SUB(&tmp, &dst); 319 320 LFPTOD(&tmp, t34); 321 322 offset = (t21 + t34) / 2.; 323 delta = t21 - t34; 324 325 if(ENABLED_OPT(NORMALVERBOSE)) 326 printf("sntp on_wire:\tt21: %.6f\t\t t34: %.6f\n\t\tdelta: %.6f\t offset: %.6f\n", 327 t21, t34, delta, offset); 328 329 ts_str = tv_to_str(&tv_dst); 330 331 printf("%s ", ts_str); 332 333 if(offset > 0) 334 printf("+"); 335 336 printf("%.*f", digits, offset); 337 338 if (root_dispersion > 0.) 339 printf(" +/- %f secs", root_dispersion); 340 341 printf("\n"); 342 343 free(ts_str); 344 345 if(ENABLED_OPT(SETTOD) || ENABLED_OPT(ADJTIME)) 346 return set_time(offset); 347 348 return 0; 349 } 350 } 351 352 getnameinfo(host->ai_addr, host->ai_addrlen, addr_buf, sizeof(addr_buf), NULL, 0, NI_NUMERICHOST); 353 354 snprintf(logmsg, sizeof(logmsg), "Received no useable packet from %s!", addr_buf); 355 log_msg(logmsg, 1); 356 357 if (ENABLED_OPT(NORMALVERBOSE)) 358 printf("sntp on_wire: Received no useable packet from %s!\n", addr_buf); 359 360 return -1; 361} 362 363/* Compute the 8 bits for li_vn_mode */ 364void 365set_li_vn_mode ( 366 struct pkt *spkt, 367 char leap, 368 char version, 369 char mode 370 ) 371{ 372 373 if(leap > 3) { 374 debug_msg("set_li_vn_mode: leap > 3 using max. 3"); 375 leap = 3; 376 } 377 378 if(mode > 7) { 379 debug_msg("set_li_vn_mode: mode > 7, using client mode 3"); 380 mode = 3; 381 } 382 383 spkt->li_vn_mode = leap << 6; 384 spkt->li_vn_mode |= version << 3; 385 spkt->li_vn_mode |= mode; 386} 387 388/* set_time corrects the local clock by offset with either settimeofday() or by default 389 * with adjtime()/adjusttimeofday(). 390 */ 391int 392set_time ( 393 double offset 394 ) 395{ 396 const int USEC_PER_SEC = 1000000; 397 struct timeval tp; 398 double frac, whole; 399 frac = modf(offset, &whole); 400 if(ENABLED_OPT(SETTOD)) { 401 GETTIMEOFDAY(&tp, (struct timezone *)NULL); 402 403 tp.tv_sec += (int) offset; 404 tp.tv_usec += frac * USEC_PER_SEC; 405 if (tp.tv_usec < 0) { 406 tp.tv_usec += USEC_PER_SEC; 407 tp.tv_sec--; 408 } else if (tp.tv_usec > USEC_PER_SEC) { 409 tp.tv_usec -= USEC_PER_SEC; 410 tp.tv_sec++; 411 } 412 413 if(SETTIMEOFDAY(&tp, (struct timezone *)NULL) < 0) { 414 printf("set_time: settimeofday(): Time not set: %s\n", 415 strerror(errno)); 416 return -1; 417 } 418 else { 419 return 0; 420 } 421 } 422 else { 423 tp.tv_sec = (int) offset; 424 tp.tv_usec = frac * USEC_PER_SEC; 425 426 if(ADJTIMEOFDAY(&tp, NULL) < 0) { 427 printf("set_time: adjtime(): Time not set: %s\n", 428 strerror(errno)); 429 return -1; 430 } 431 else { 432 return 0; 433 } 434 } 435} 436