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