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>