1*eabc0478Schristos /* $NetBSD: main.c,v 1.19 2024/08/18 20:47:20 christos Exp $ */ 2abb0f93cSkardel 33123f114Skardel #include <config.h> 4abb0f93cSkardel 52950cc38Schristos #include <event2/util.h> 62950cc38Schristos #include <event2/event.h> 72950cc38Schristos 82950cc38Schristos #include "ntp_workimpl.h" 92950cc38Schristos #ifdef WORK_THREAD 102950cc38Schristos # include <event2/thread.h> 112950cc38Schristos #endif 122950cc38Schristos 13cdfa2a7eSchristos #ifdef HAVE_SYSEXITS_H 14cdfa2a7eSchristos # include <sysexits.h> 15cdfa2a7eSchristos #endif 16cdfa2a7eSchristos 173123f114Skardel #include "main.h" 182950cc38Schristos #include "ntp_libopts.h" 19abb0f93cSkardel #include "kod_management.h" 20abb0f93cSkardel #include "networking.h" 21abb0f93cSkardel #include "utilities.h" 22abb0f93cSkardel #include "log.h" 232950cc38Schristos #include "libntp.h" 24abb0f93cSkardel 25*eabc0478Schristos extern const char *progname; 262950cc38Schristos 272950cc38Schristos int shutting_down; 282950cc38Schristos int time_derived; 292950cc38Schristos int time_adjusted; 302950cc38Schristos int n_pending_dns = 0; 312950cc38Schristos int n_pending_ntp = 0; 32abb0f93cSkardel int ai_fam_pref = AF_UNSPEC; 332950cc38Schristos int ntpver = 4; 342950cc38Schristos double steplimit = -1; 352950cc38Schristos SOCKET sock4 = -1; /* Socket for IPv4 */ 362950cc38Schristos SOCKET sock6 = -1; /* Socket for IPv6 */ 372950cc38Schristos /* 382950cc38Schristos ** BCAST *must* listen on port 123 (by default), so we can only 392950cc38Schristos ** use the UCST sockets (above) if they too are using port 123 402950cc38Schristos */ 412950cc38Schristos SOCKET bsock4 = -1; /* Broadcast Socket for IPv4 */ 422950cc38Schristos SOCKET bsock6 = -1; /* Broadcast Socket for IPv6 */ 432950cc38Schristos struct event_base *base; 442950cc38Schristos struct event *ev_sock4; 452950cc38Schristos struct event *ev_sock6; 462950cc38Schristos struct event *ev_worker_timeout; 472950cc38Schristos struct event *ev_xmt_timer; 48abb0f93cSkardel 492950cc38Schristos struct dns_ctx { 502950cc38Schristos const char * name; 512950cc38Schristos int flags; 522950cc38Schristos #define CTX_BCST 0x0001 532950cc38Schristos #define CTX_UCST 0x0002 542950cc38Schristos #define CTX_xCST 0x0003 552950cc38Schristos #define CTX_CONC 0x0004 562950cc38Schristos #define CTX_unused 0xfffd 572950cc38Schristos int key_id; 582950cc38Schristos struct timeval timeout; 592950cc38Schristos struct key * key; 602950cc38Schristos }; 612950cc38Schristos 622950cc38Schristos typedef struct sent_pkt_tag sent_pkt; 632950cc38Schristos struct sent_pkt_tag { 642950cc38Schristos sent_pkt * link; 652950cc38Schristos struct dns_ctx * dctx; 662950cc38Schristos sockaddr_u addr; 672950cc38Schristos time_t stime; 682950cc38Schristos int done; 692950cc38Schristos struct pkt x_pkt; 702950cc38Schristos }; 712950cc38Schristos 722950cc38Schristos typedef struct xmt_ctx_tag xmt_ctx; 732950cc38Schristos struct xmt_ctx_tag { 742950cc38Schristos xmt_ctx * link; 752950cc38Schristos SOCKET sock; 762950cc38Schristos time_t sched; 772950cc38Schristos sent_pkt * spkt; 782950cc38Schristos }; 792950cc38Schristos 802950cc38Schristos struct timeval gap; 812950cc38Schristos xmt_ctx * xmt_q; 82abb0f93cSkardel struct key * keys = NULL; 832950cc38Schristos int response_timeout; 842950cc38Schristos struct timeval response_tv; 852950cc38Schristos struct timeval start_tv; 862950cc38Schristos /* check the timeout at least once per second */ 872950cc38Schristos struct timeval wakeup_tv = { 0, 888888 }; 88abb0f93cSkardel 892950cc38Schristos sent_pkt * fam_listheads[2]; 902950cc38Schristos #define v4_pkts_list (fam_listheads[0]) 912950cc38Schristos #define v6_pkts_list (fam_listheads[1]) 922950cc38Schristos 932950cc38Schristos static union { 942950cc38Schristos struct pkt pkt; 95ea66d795Schristos char buf[LEN_PKT_NOMAC + NTP_MAXEXTEN + MAX_MAC_LEN]; 962950cc38Schristos } rbuf; 972950cc38Schristos 982950cc38Schristos #define r_pkt rbuf.pkt 992950cc38Schristos 1002950cc38Schristos #ifdef HAVE_DROPROOT 1012950cc38Schristos int droproot; /* intres imports these */ 1022950cc38Schristos int root_dropped; 1032950cc38Schristos #endif 1042950cc38Schristos u_long current_time; /* libntp/authkeys.c */ 1052950cc38Schristos 1062950cc38Schristos void open_sockets(void); 1072950cc38Schristos void handle_lookup(const char *name, int flags); 1082950cc38Schristos void sntp_addremove_fd(int fd, int is_pipe, int remove_it); 1092950cc38Schristos void worker_timeout(evutil_socket_t, short, void *); 1102950cc38Schristos void worker_resp_cb(evutil_socket_t, short, void *); 1112950cc38Schristos void sntp_name_resolved(int, int, void *, const char *, const char *, 1122950cc38Schristos const struct addrinfo *, 1132950cc38Schristos const struct addrinfo *); 1142950cc38Schristos void queue_xmt(SOCKET sock, struct dns_ctx *dctx, sent_pkt *spkt, 1152950cc38Schristos u_int xmt_delay); 1162950cc38Schristos void xmt_timer_cb(evutil_socket_t, short, void *ptr); 1172950cc38Schristos void xmt(xmt_ctx *xctx); 1182950cc38Schristos int check_kod(const struct addrinfo *ai); 1192950cc38Schristos void timeout_query(sent_pkt *); 1202950cc38Schristos void timeout_queries(void); 1212950cc38Schristos void sock_cb(evutil_socket_t, short, void *); 1222950cc38Schristos void check_exit_conditions(void); 1232950cc38Schristos void sntp_libevent_log_cb(int, const char *); 124abb0f93cSkardel void set_li_vn_mode(struct pkt *spkt, char leap, char version, char mode); 125abb0f93cSkardel int set_time(double offset); 1262950cc38Schristos void dec_pending_ntp(const char *, sockaddr_u *); 1272950cc38Schristos int libevent_version_ok(void); 1282950cc38Schristos int gettimeofday_cached(struct event_base *b, struct timeval *tv); 129abb0f93cSkardel 130abb0f93cSkardel 131abb0f93cSkardel /* 132abb0f93cSkardel * The actual main function. 133abb0f93cSkardel */ 134abb0f93cSkardel int 135abb0f93cSkardel sntp_main ( 136abb0f93cSkardel int argc, 1372950cc38Schristos char **argv, 1382950cc38Schristos const char *sntpVersion 139abb0f93cSkardel ) 140abb0f93cSkardel { 1412950cc38Schristos int i; 1422950cc38Schristos int exitcode; 143abb0f93cSkardel int optct; 1442950cc38Schristos struct event_config * evcfg; 145abb0f93cSkardel 1462950cc38Schristos /* Initialize logging system - sets up progname */ 1472950cc38Schristos sntp_init_logging(argv[0]); 1482950cc38Schristos 1492950cc38Schristos if (!libevent_version_ok()) 1502950cc38Schristos exit(EX_SOFTWARE); 1512950cc38Schristos 1522950cc38Schristos init_lib(); 1532950cc38Schristos init_auth(); 1542950cc38Schristos 1552950cc38Schristos optct = ntpOptionProcess(&sntpOptions, argc, argv); 1563123f114Skardel argc -= optct; 1573123f114Skardel argv += optct; 1583123f114Skardel 1592950cc38Schristos 1602950cc38Schristos debug = OPT_VALUE_SET_DEBUG_LEVEL; 1612950cc38Schristos 1622950cc38Schristos TRACE(2, ("init_lib() done, %s%s\n", 1632950cc38Schristos (ipv4_works) 1642950cc38Schristos ? "ipv4_works " 1652950cc38Schristos : "", 1662950cc38Schristos (ipv6_works) 1672950cc38Schristos ? "ipv6_works " 1682950cc38Schristos : "")); 1692950cc38Schristos ntpver = OPT_VALUE_NTPVERSION; 1702950cc38Schristos steplimit = OPT_VALUE_STEPLIMIT / 1e3; 1712950cc38Schristos gap.tv_usec = max(0, OPT_VALUE_GAP * 1000); 1722950cc38Schristos gap.tv_usec = min(gap.tv_usec, 999999); 1732950cc38Schristos 1743123f114Skardel if (HAVE_OPT(LOGFILE)) 1753123f114Skardel open_logfile(OPT_ARG(LOGFILE)); 1763123f114Skardel 1772950cc38Schristos msyslog(LOG_INFO, "%s", sntpVersion); 1782950cc38Schristos 1792950cc38Schristos if (0 == argc && !HAVE_OPT(BROADCAST) && !HAVE_OPT(CONCURRENT)) { 1802950cc38Schristos printf("%s: Must supply at least one of -b hostname, -c hostname, or hostname.\n", 1812950cc38Schristos progname); 1822950cc38Schristos exit(EX_USAGE); 1832950cc38Schristos } 1842950cc38Schristos 1852950cc38Schristos 1862950cc38Schristos /* 1872950cc38Schristos ** Eventually, we probably want: 1882950cc38Schristos ** - separate bcst and ucst timeouts (why?) 1892950cc38Schristos ** - multiple --timeout values in the commandline 1902950cc38Schristos */ 1912950cc38Schristos 1922950cc38Schristos response_timeout = OPT_VALUE_TIMEOUT; 1932950cc38Schristos response_tv.tv_sec = response_timeout; 1942950cc38Schristos response_tv.tv_usec = 0; 1953123f114Skardel 196abb0f93cSkardel /* IPv6 available? */ 197abb0f93cSkardel if (isc_net_probeipv6() != ISC_R_SUCCESS) { 198abb0f93cSkardel ai_fam_pref = AF_INET; 1992950cc38Schristos TRACE(1, ("No ipv6 support available, forcing ipv4\n")); 2003123f114Skardel } else { 201abb0f93cSkardel /* Check for options -4 and -6 */ 202abb0f93cSkardel if (HAVE_OPT(IPV4)) 203abb0f93cSkardel ai_fam_pref = AF_INET; 204abb0f93cSkardel else if (HAVE_OPT(IPV6)) 205abb0f93cSkardel ai_fam_pref = AF_INET6; 206abb0f93cSkardel } 207abb0f93cSkardel 2082950cc38Schristos /* TODO: Parse config file if declared */ 209abb0f93cSkardel 210abb0f93cSkardel /* 2112950cc38Schristos ** Init the KOD system. 2122950cc38Schristos ** For embedded systems with no writable filesystem, 2132950cc38Schristos ** -K /dev/null can be used to disable KoD storage. 214abb0f93cSkardel */ 2152950cc38Schristos kod_init_kod_db(OPT_ARG(KOD), FALSE); 216abb0f93cSkardel 2174eea345dSchristos /* HMS: Check and see what happens if KEYFILE doesn't exist */ 218abb0f93cSkardel auth_init(OPT_ARG(KEYFILE), &keys); 219abb0f93cSkardel 2202950cc38Schristos /* 2212950cc38Schristos ** Considering employing a variable that prevents functions of doing 2222950cc38Schristos ** anything until everything is initialized properly 2232950cc38Schristos ** 2242950cc38Schristos ** HMS: What exactly does the above mean? 225abb0f93cSkardel */ 2262950cc38Schristos event_set_log_callback(&sntp_libevent_log_cb); 2272950cc38Schristos if (debug > 0) 2282950cc38Schristos event_enable_debug_mode(); 2292950cc38Schristos #ifdef WORK_THREAD 2302950cc38Schristos evthread_use_pthreads(); 2312950cc38Schristos /* we use libevent from main thread only, locks should be academic */ 2322950cc38Schristos if (debug > 0) 2332950cc38Schristos evthread_enable_lock_debuging(); 2342950cc38Schristos #endif 2352950cc38Schristos evcfg = event_config_new(); 2362950cc38Schristos if (NULL == evcfg) { 2372950cc38Schristos printf("%s: event_config_new() failed!\n", progname); 238abb0f93cSkardel return -1; 239abb0f93cSkardel } 2402950cc38Schristos #ifndef HAVE_SOCKETPAIR 2412950cc38Schristos event_config_require_features(evcfg, EV_FEATURE_FDS); 2422950cc38Schristos #endif 2432950cc38Schristos /* all libevent calls are from main thread */ 2442950cc38Schristos /* event_config_set_flag(evcfg, EVENT_BASE_FLAG_NOLOCK); */ 2452950cc38Schristos base = event_base_new_with_config(evcfg); 2462950cc38Schristos event_config_free(evcfg); 2472950cc38Schristos if (NULL == base) { 2482950cc38Schristos printf("%s: event_base_new() failed!\n", progname); 2492950cc38Schristos return -1; 2503123f114Skardel } 251abb0f93cSkardel 2522950cc38Schristos /* wire into intres resolver */ 2532950cc38Schristos worker_per_query = TRUE; 2542950cc38Schristos addremove_io_fd = &sntp_addremove_fd; 2552950cc38Schristos 2562950cc38Schristos open_sockets(); 2572950cc38Schristos 2582950cc38Schristos if (HAVE_OPT(BROADCAST)) { 2592950cc38Schristos int cn = STACKCT_OPT( BROADCAST ); 2602950cc38Schristos const char ** cp = STACKLST_OPT( BROADCAST ); 2612950cc38Schristos 2622950cc38Schristos while (cn-- > 0) { 2632950cc38Schristos handle_lookup(*cp, CTX_BCST); 2642950cc38Schristos cp++; 2652950cc38Schristos } 2662950cc38Schristos } 2672950cc38Schristos 2682950cc38Schristos if (HAVE_OPT(CONCURRENT)) { 2692950cc38Schristos int cn = STACKCT_OPT( CONCURRENT ); 2702950cc38Schristos const char ** cp = STACKLST_OPT( CONCURRENT ); 2712950cc38Schristos 2722950cc38Schristos while (cn-- > 0) { 2732950cc38Schristos handle_lookup(*cp, CTX_UCST | CTX_CONC); 2742950cc38Schristos cp++; 2752950cc38Schristos } 2762950cc38Schristos } 2772950cc38Schristos 2782950cc38Schristos for (i = 0; i < argc; ++i) 2792950cc38Schristos handle_lookup(argv[i], CTX_UCST); 2802950cc38Schristos 2812950cc38Schristos gettimeofday_cached(base, &start_tv); 2822950cc38Schristos event_base_dispatch(base); 2832950cc38Schristos event_base_free(base); 2842950cc38Schristos 2852950cc38Schristos if (!time_adjusted && 2862950cc38Schristos (ENABLED_OPT(STEP) || ENABLED_OPT(SLEW))) 2872950cc38Schristos exitcode = 1; 2882950cc38Schristos else 2892950cc38Schristos exitcode = 0; 2902950cc38Schristos 2912950cc38Schristos return exitcode; 2922950cc38Schristos } 2932950cc38Schristos 2942950cc38Schristos 2952950cc38Schristos /* 2962950cc38Schristos ** open sockets and make them non-blocking 297abb0f93cSkardel */ 2982950cc38Schristos void 2992950cc38Schristos open_sockets( 3002950cc38Schristos void 3012950cc38Schristos ) 3022950cc38Schristos { 3032950cc38Schristos sockaddr_u name; 3042950cc38Schristos 3052950cc38Schristos if (-1 == sock4) { 3062950cc38Schristos sock4 = socket(PF_INET, SOCK_DGRAM, 0); 3072950cc38Schristos if (-1 == sock4) { 3082950cc38Schristos /* error getting a socket */ 3092950cc38Schristos msyslog(LOG_ERR, "open_sockets: socket(PF_INET) failed: %m"); 3102950cc38Schristos exit(1); 311abb0f93cSkardel } 3122950cc38Schristos /* Make it non-blocking */ 3132950cc38Schristos make_socket_nonblocking(sock4); 3142950cc38Schristos 3152950cc38Schristos /* Let's try using a wildcard... */ 3162950cc38Schristos ZERO(name); 3172950cc38Schristos AF(&name) = AF_INET; 3182950cc38Schristos SET_ADDR4N(&name, INADDR_ANY); 3192950cc38Schristos SET_PORT(&name, (HAVE_OPT(USERESERVEDPORT) ? 123 : 0)); 3202950cc38Schristos 3212950cc38Schristos if (-1 == bind(sock4, &name.sa, 3222950cc38Schristos SOCKLEN(&name))) { 3232950cc38Schristos msyslog(LOG_ERR, "open_sockets: bind(sock4) failed: %m"); 3242950cc38Schristos exit(1); 3252950cc38Schristos } 3262950cc38Schristos 3272950cc38Schristos /* Register an NTP callback for recv/timeout */ 3282950cc38Schristos ev_sock4 = event_new(base, sock4, 3292950cc38Schristos EV_TIMEOUT | EV_READ | EV_PERSIST, 3302950cc38Schristos &sock_cb, NULL); 3312950cc38Schristos if (NULL == ev_sock4) { 3322950cc38Schristos msyslog(LOG_ERR, 3332950cc38Schristos "open_sockets: event_new(base, sock4) failed!"); 334abb0f93cSkardel } else { 3352950cc38Schristos event_add(ev_sock4, &wakeup_tv); 3362950cc38Schristos } 3372950cc38Schristos } 3382950cc38Schristos 3392950cc38Schristos /* We may not always have IPv6... */ 3402950cc38Schristos if (-1 == sock6 && ipv6_works) { 3412950cc38Schristos sock6 = socket(PF_INET6, SOCK_DGRAM, 0); 3422950cc38Schristos if (-1 == sock6 && ipv6_works) { 3432950cc38Schristos /* error getting a socket */ 3442950cc38Schristos msyslog(LOG_ERR, "open_sockets: socket(PF_INET6) failed: %m"); 3452950cc38Schristos exit(1); 3462950cc38Schristos } 3472950cc38Schristos /* Make it non-blocking */ 3482950cc38Schristos make_socket_nonblocking(sock6); 3492950cc38Schristos 3502950cc38Schristos /* Let's try using a wildcard... */ 3512950cc38Schristos ZERO(name); 3522950cc38Schristos AF(&name) = AF_INET6; 3532950cc38Schristos SET_ADDR6N(&name, in6addr_any); 3542950cc38Schristos SET_PORT(&name, (HAVE_OPT(USERESERVEDPORT) ? 123 : 0)); 3552950cc38Schristos 3562950cc38Schristos if (-1 == bind(sock6, &name.sa, 3572950cc38Schristos SOCKLEN(&name))) { 3582950cc38Schristos msyslog(LOG_ERR, "open_sockets: bind(sock6) failed: %m"); 3592950cc38Schristos exit(1); 3602950cc38Schristos } 3612950cc38Schristos /* Register an NTP callback for recv/timeout */ 3622950cc38Schristos ev_sock6 = event_new(base, sock6, 3632950cc38Schristos EV_TIMEOUT | EV_READ | EV_PERSIST, 3642950cc38Schristos &sock_cb, NULL); 3652950cc38Schristos if (NULL == ev_sock6) { 3662950cc38Schristos msyslog(LOG_ERR, 3672950cc38Schristos "open_sockets: event_new(base, sock6) failed!"); 3682950cc38Schristos } else { 3692950cc38Schristos event_add(ev_sock6, &wakeup_tv); 3702950cc38Schristos } 3712950cc38Schristos } 3722950cc38Schristos 3732950cc38Schristos return; 3742950cc38Schristos } 3752950cc38Schristos 3762950cc38Schristos 3772950cc38Schristos /* 3782950cc38Schristos ** handle_lookup 3792950cc38Schristos */ 3802950cc38Schristos void 3812950cc38Schristos handle_lookup( 3822950cc38Schristos const char *name, 3832950cc38Schristos int flags 3842950cc38Schristos ) 3852950cc38Schristos { 3862950cc38Schristos struct addrinfo hints; /* Local copy is OK */ 3872950cc38Schristos struct dns_ctx *ctx; 3882950cc38Schristos char * name_copy; 3892950cc38Schristos size_t name_sz; 3902950cc38Schristos size_t octets; 3912950cc38Schristos 3922950cc38Schristos TRACE(1, ("handle_lookup(%s,%#x)\n", name, flags)); 3932950cc38Schristos 3942950cc38Schristos ZERO(hints); 3952950cc38Schristos hints.ai_family = ai_fam_pref; 3962950cc38Schristos hints.ai_flags = AI_CANONNAME | Z_AI_NUMERICSERV; 3972950cc38Schristos /* 3982950cc38Schristos ** Unless we specify a socktype, we'll get at least two 3992950cc38Schristos ** entries for each address: one for TCP and one for 4002950cc38Schristos ** UDP. That's not what we want. 4012950cc38Schristos */ 4022950cc38Schristos hints.ai_socktype = SOCK_DGRAM; 4032950cc38Schristos hints.ai_protocol = IPPROTO_UDP; 4042950cc38Schristos 4052950cc38Schristos name_sz = 1 + strlen(name); 4062950cc38Schristos octets = sizeof(*ctx) + name_sz; // Space for a ctx and the name 4072950cc38Schristos ctx = emalloc_zero(octets); // ctx at ctx[0] 4082950cc38Schristos name_copy = (char *)(ctx + 1); // Put the name at ctx[1] 4092950cc38Schristos memcpy(name_copy, name, name_sz); // copy the name to ctx[1] 4102950cc38Schristos ctx->name = name_copy; // point to it... 4112950cc38Schristos ctx->flags = flags; 4122950cc38Schristos ctx->timeout = response_tv; 4134eea345dSchristos ctx->key = NULL; 4142950cc38Schristos 4152950cc38Schristos /* The following should arguably be passed in... */ 4164eea345dSchristos if (ENABLED_OPT(AUTHENTICATION)) { 4174eea345dSchristos ctx->key_id = OPT_VALUE_AUTHENTICATION; 4182950cc38Schristos get_key(ctx->key_id, &ctx->key); 4194eea345dSchristos if (NULL == ctx->key) { 4204eea345dSchristos fprintf(stderr, "%s: Authentication with keyID %d requested, but no matching keyID found in <%s>!\n", 4214eea345dSchristos progname, ctx->key_id, OPT_ARG(KEYFILE)); 4224eea345dSchristos exit(1); 4234eea345dSchristos } 4242950cc38Schristos } else { 4252950cc38Schristos ctx->key_id = -1; 4262950cc38Schristos } 4272950cc38Schristos 4282950cc38Schristos ++n_pending_dns; 4292950cc38Schristos getaddrinfo_sometime(name, "123", &hints, 0, 4302950cc38Schristos &sntp_name_resolved, ctx); 4312950cc38Schristos } 4322950cc38Schristos 4332950cc38Schristos 4342950cc38Schristos /* 4352950cc38Schristos ** DNS Callback: 4362950cc38Schristos ** - For each IP: 4372950cc38Schristos ** - - open a socket 4382950cc38Schristos ** - - increment n_pending_ntp 4392950cc38Schristos ** - - send a request if this is a Unicast callback 4402950cc38Schristos ** - - queue wait for response 4412950cc38Schristos ** - decrement n_pending_dns 4422950cc38Schristos */ 4432950cc38Schristos void 4442950cc38Schristos sntp_name_resolved( 4452950cc38Schristos int rescode, 4462950cc38Schristos int gai_errno, 4472950cc38Schristos void * context, 4482950cc38Schristos const char * name, 4492950cc38Schristos const char * service, 4502950cc38Schristos const struct addrinfo * hints, 4512950cc38Schristos const struct addrinfo * addr 4522950cc38Schristos ) 4532950cc38Schristos { 4542950cc38Schristos struct dns_ctx * dctx; 4552950cc38Schristos sent_pkt * spkt; 4562950cc38Schristos const struct addrinfo * ai; 4572950cc38Schristos SOCKET sock; 4582950cc38Schristos u_int xmt_delay_v4; 4592950cc38Schristos u_int xmt_delay_v6; 4602950cc38Schristos u_int xmt_delay; 4612950cc38Schristos size_t octets; 4622950cc38Schristos 4632950cc38Schristos xmt_delay_v4 = 0; 4642950cc38Schristos xmt_delay_v6 = 0; 4652950cc38Schristos dctx = context; 4662950cc38Schristos if (rescode) { 4672950cc38Schristos #ifdef EAI_SYSTEM 4682950cc38Schristos if (EAI_SYSTEM == rescode) { 4692950cc38Schristos errno = gai_errno; 4702950cc38Schristos mfprintf(stderr, "%s lookup error %m\n", 4712950cc38Schristos dctx->name); 4722950cc38Schristos } else 4732950cc38Schristos #endif 4742950cc38Schristos fprintf(stderr, "%s lookup error %s\n", 4752950cc38Schristos dctx->name, gai_strerror(rescode)); 4762950cc38Schristos } else { 4772950cc38Schristos TRACE(3, ("%s [%s]\n", dctx->name, 4782950cc38Schristos (addr->ai_canonname != NULL) 4792950cc38Schristos ? addr->ai_canonname 4802950cc38Schristos : "")); 4812950cc38Schristos 4822950cc38Schristos for (ai = addr; ai != NULL; ai = ai->ai_next) { 4832950cc38Schristos 4842950cc38Schristos if (check_kod(ai)) 4852950cc38Schristos continue; 4862950cc38Schristos 4872950cc38Schristos switch (ai->ai_family) { 4882950cc38Schristos 4892950cc38Schristos case AF_INET: 4902950cc38Schristos sock = sock4; 4912950cc38Schristos xmt_delay = xmt_delay_v4; 4922950cc38Schristos xmt_delay_v4++; 4932950cc38Schristos break; 4942950cc38Schristos 4952950cc38Schristos case AF_INET6: 4962950cc38Schristos if (!ipv6_works) 4972950cc38Schristos continue; 4982950cc38Schristos 4992950cc38Schristos sock = sock6; 5002950cc38Schristos xmt_delay = xmt_delay_v6; 5012950cc38Schristos xmt_delay_v6++; 5022950cc38Schristos break; 5032950cc38Schristos 5042950cc38Schristos default: 5052950cc38Schristos msyslog(LOG_ERR, "sntp_name_resolved: unexpected ai_family: %d", 5062950cc38Schristos ai->ai_family); 5072950cc38Schristos exit(1); 5082950cc38Schristos break; 5092950cc38Schristos } 5102950cc38Schristos 5112950cc38Schristos /* 5122950cc38Schristos ** We're waiting for a response for either unicast 5132950cc38Schristos ** or broadcast, so... 5142950cc38Schristos */ 5152950cc38Schristos ++n_pending_ntp; 5162950cc38Schristos 5172950cc38Schristos /* If this is for a unicast IP, queue a request */ 5182950cc38Schristos if (dctx->flags & CTX_UCST) { 5192950cc38Schristos spkt = emalloc_zero(sizeof(*spkt)); 5202950cc38Schristos spkt->dctx = dctx; 5212950cc38Schristos octets = min(ai->ai_addrlen, sizeof(spkt->addr)); 5222950cc38Schristos memcpy(&spkt->addr, ai->ai_addr, octets); 5232950cc38Schristos queue_xmt(sock, dctx, spkt, xmt_delay); 5242950cc38Schristos } 5252950cc38Schristos } 5262950cc38Schristos } 5272950cc38Schristos /* n_pending_dns really should be >0 here... */ 5282950cc38Schristos --n_pending_dns; 5292950cc38Schristos check_exit_conditions(); 5302950cc38Schristos } 5312950cc38Schristos 5322950cc38Schristos 5332950cc38Schristos /* 5342950cc38Schristos ** queue_xmt 5352950cc38Schristos */ 5362950cc38Schristos void 5372950cc38Schristos queue_xmt( 5382950cc38Schristos SOCKET sock, 5392950cc38Schristos struct dns_ctx * dctx, 5402950cc38Schristos sent_pkt * spkt, 5412950cc38Schristos u_int xmt_delay 5422950cc38Schristos ) 5432950cc38Schristos { 5442950cc38Schristos sockaddr_u * dest; 5452950cc38Schristos sent_pkt ** pkt_listp; 5462950cc38Schristos sent_pkt * match; 5472950cc38Schristos xmt_ctx * xctx; 5482950cc38Schristos struct timeval start_cb; 5492950cc38Schristos struct timeval delay; 5502950cc38Schristos 5512950cc38Schristos dest = &spkt->addr; 5522950cc38Schristos if (IS_IPV6(dest)) 5532950cc38Schristos pkt_listp = &v6_pkts_list; 5542950cc38Schristos else 5552950cc38Schristos pkt_listp = &v4_pkts_list; 5562950cc38Schristos 5572950cc38Schristos /* reject attempts to add address already listed */ 5582950cc38Schristos for (match = *pkt_listp; match != NULL; match = match->link) { 5592950cc38Schristos if (ADDR_PORT_EQ(&spkt->addr, &match->addr)) { 5602950cc38Schristos if (strcasecmp(spkt->dctx->name, 5612950cc38Schristos match->dctx->name)) 5622950cc38Schristos printf("%s %s duplicate address from %s ignored.\n", 5632950cc38Schristos sptoa(&match->addr), 5642950cc38Schristos match->dctx->name, 5652950cc38Schristos spkt->dctx->name); 5662950cc38Schristos else 5672950cc38Schristos printf("%s %s, duplicate address ignored.\n", 5682950cc38Schristos sptoa(&match->addr), 5692950cc38Schristos match->dctx->name); 5702950cc38Schristos dec_pending_ntp(spkt->dctx->name, &spkt->addr); 5712950cc38Schristos free(spkt); 5722950cc38Schristos return; 5732950cc38Schristos } 5742950cc38Schristos } 5752950cc38Schristos 5762950cc38Schristos LINK_SLIST(*pkt_listp, spkt, link); 5772950cc38Schristos 5782950cc38Schristos xctx = emalloc_zero(sizeof(*xctx)); 5792950cc38Schristos xctx->sock = sock; 5802950cc38Schristos xctx->spkt = spkt; 5812950cc38Schristos gettimeofday_cached(base, &start_cb); 5822950cc38Schristos xctx->sched = start_cb.tv_sec + (2 * xmt_delay); 5832950cc38Schristos 5842950cc38Schristos LINK_SORT_SLIST(xmt_q, xctx, (xctx->sched < L_S_S_CUR()->sched), 5852950cc38Schristos link, xmt_ctx); 5862950cc38Schristos if (xmt_q == xctx) { 5872950cc38Schristos /* 5882950cc38Schristos * The new entry is the first scheduled. The timer is 5892950cc38Schristos * either not active or is set for the second xmt 5902950cc38Schristos * context in xmt_q. 5912950cc38Schristos */ 5922950cc38Schristos if (NULL == ev_xmt_timer) 5932950cc38Schristos ev_xmt_timer = event_new(base, INVALID_SOCKET, 5942950cc38Schristos EV_TIMEOUT, 5952950cc38Schristos &xmt_timer_cb, NULL); 5962950cc38Schristos if (NULL == ev_xmt_timer) { 5972950cc38Schristos msyslog(LOG_ERR, 5982950cc38Schristos "queue_xmt: event_new(base, -1, EV_TIMEOUT) failed!"); 5992950cc38Schristos exit(1); 6002950cc38Schristos } 6012950cc38Schristos ZERO(delay); 6022950cc38Schristos if (xctx->sched > start_cb.tv_sec) 6032950cc38Schristos delay.tv_sec = xctx->sched - start_cb.tv_sec; 6042950cc38Schristos event_add(ev_xmt_timer, &delay); 6052950cc38Schristos TRACE(2, ("queue_xmt: xmt timer for %u usec\n", 6062950cc38Schristos (u_int)delay.tv_usec)); 6072950cc38Schristos } 6082950cc38Schristos } 6092950cc38Schristos 6102950cc38Schristos 6112950cc38Schristos /* 6122950cc38Schristos ** xmt_timer_cb 6132950cc38Schristos */ 6142950cc38Schristos void 6152950cc38Schristos xmt_timer_cb( 6162950cc38Schristos evutil_socket_t fd, 6172950cc38Schristos short what, 6182950cc38Schristos void * ctx 6192950cc38Schristos ) 6202950cc38Schristos { 6212950cc38Schristos struct timeval start_cb; 6222950cc38Schristos struct timeval delay; 6232950cc38Schristos xmt_ctx * x; 6242950cc38Schristos 6252950cc38Schristos UNUSED_ARG(fd); 6262950cc38Schristos UNUSED_ARG(ctx); 6272950cc38Schristos DEBUG_INSIST(EV_TIMEOUT == what); 6282950cc38Schristos 6292950cc38Schristos if (NULL == xmt_q || shutting_down) 6302950cc38Schristos return; 6312950cc38Schristos gettimeofday_cached(base, &start_cb); 6322950cc38Schristos if (xmt_q->sched <= start_cb.tv_sec) { 6332950cc38Schristos UNLINK_HEAD_SLIST(x, xmt_q, link); 6342950cc38Schristos TRACE(2, ("xmt_timer_cb: at .%6.6u -> %s\n", 6352950cc38Schristos (u_int)start_cb.tv_usec, stoa(&x->spkt->addr))); 6362950cc38Schristos xmt(x); 6372950cc38Schristos free(x); 6382950cc38Schristos if (NULL == xmt_q) 6392950cc38Schristos return; 6402950cc38Schristos } 6412950cc38Schristos if (xmt_q->sched <= start_cb.tv_sec) { 6422950cc38Schristos event_add(ev_xmt_timer, &gap); 6432950cc38Schristos TRACE(2, ("xmt_timer_cb: at .%6.6u gap %6.6u\n", 6442950cc38Schristos (u_int)start_cb.tv_usec, 6452950cc38Schristos (u_int)gap.tv_usec)); 6462950cc38Schristos } else { 6472950cc38Schristos delay.tv_sec = xmt_q->sched - start_cb.tv_sec; 6482950cc38Schristos delay.tv_usec = 0; 6492950cc38Schristos event_add(ev_xmt_timer, &delay); 6502950cc38Schristos TRACE(2, ("xmt_timer_cb: at .%6.6u next %ld seconds\n", 6512950cc38Schristos (u_int)start_cb.tv_usec, 6522950cc38Schristos (long)delay.tv_sec)); 6532950cc38Schristos } 6542950cc38Schristos } 6552950cc38Schristos 6562950cc38Schristos 6572950cc38Schristos /* 6582950cc38Schristos ** xmt() 6592950cc38Schristos */ 6602950cc38Schristos void 6612950cc38Schristos xmt( 6622950cc38Schristos xmt_ctx * xctx 6632950cc38Schristos ) 6642950cc38Schristos { 6652950cc38Schristos SOCKET sock = xctx->sock; 6662950cc38Schristos struct dns_ctx *dctx = xctx->spkt->dctx; 6672950cc38Schristos sent_pkt * spkt = xctx->spkt; 6682950cc38Schristos sockaddr_u * dst = &spkt->addr; 6692950cc38Schristos struct timeval tv_xmt; 6702950cc38Schristos struct pkt x_pkt; 6712950cc38Schristos size_t pkt_len; 6722950cc38Schristos int sent; 6732950cc38Schristos 6742950cc38Schristos if (0 != gettimeofday(&tv_xmt, NULL)) { 6752950cc38Schristos msyslog(LOG_ERR, 6762950cc38Schristos "xmt: gettimeofday() failed: %m"); 6772950cc38Schristos exit(1); 6782950cc38Schristos } 6792950cc38Schristos tv_xmt.tv_sec += JAN_1970; 6802950cc38Schristos 6812950cc38Schristos pkt_len = generate_pkt(&x_pkt, &tv_xmt, dctx->key_id, 6822950cc38Schristos dctx->key); 6832950cc38Schristos 6842950cc38Schristos sent = sendpkt(sock, dst, &x_pkt, pkt_len); 6852950cc38Schristos if (sent) { 6862950cc38Schristos /* Save the packet we sent... */ 6872950cc38Schristos memcpy(&spkt->x_pkt, &x_pkt, min(sizeof(spkt->x_pkt), 6882950cc38Schristos pkt_len)); 6892950cc38Schristos spkt->stime = tv_xmt.tv_sec - JAN_1970; 6902950cc38Schristos 6912950cc38Schristos TRACE(2, ("xmt: %lx.%6.6u %s %s\n", (u_long)tv_xmt.tv_sec, 6922950cc38Schristos (u_int)tv_xmt.tv_usec, dctx->name, stoa(dst))); 6932950cc38Schristos } else { 6942950cc38Schristos dec_pending_ntp(dctx->name, dst); 6952950cc38Schristos } 6962950cc38Schristos 6972950cc38Schristos return; 6982950cc38Schristos } 6992950cc38Schristos 7002950cc38Schristos 7012950cc38Schristos /* 7022950cc38Schristos * timeout_queries() -- give up on unrequited NTP queries 7032950cc38Schristos */ 7042950cc38Schristos void 7052950cc38Schristos timeout_queries(void) 7062950cc38Schristos { 7072950cc38Schristos struct timeval start_cb; 7082950cc38Schristos u_int idx; 7092950cc38Schristos sent_pkt * head; 7102950cc38Schristos sent_pkt * spkt; 7112950cc38Schristos sent_pkt * spkt_next; 7122950cc38Schristos long age; 7132950cc38Schristos int didsomething = 0; 7142950cc38Schristos 7152950cc38Schristos TRACE(3, ("timeout_queries: called to check %u items\n", 7162950cc38Schristos (unsigned)COUNTOF(fam_listheads))); 7172950cc38Schristos 7182950cc38Schristos gettimeofday_cached(base, &start_cb); 7192950cc38Schristos for (idx = 0; idx < COUNTOF(fam_listheads); idx++) { 7202950cc38Schristos head = fam_listheads[idx]; 7212950cc38Schristos for (spkt = head; spkt != NULL; spkt = spkt_next) { 7222950cc38Schristos char xcst; 7232950cc38Schristos 7242950cc38Schristos didsomething = 1; 7252950cc38Schristos switch (spkt->dctx->flags & CTX_xCST) { 7262950cc38Schristos case CTX_BCST: 7272950cc38Schristos xcst = 'B'; 7282950cc38Schristos break; 7292950cc38Schristos 7302950cc38Schristos case CTX_UCST: 7312950cc38Schristos xcst = 'U'; 7322950cc38Schristos break; 7332950cc38Schristos 7342950cc38Schristos default: 7352950cc38Schristos INSIST(!"spkt->dctx->flags neither UCST nor BCST"); 7362950cc38Schristos break; 7372950cc38Schristos } 7382950cc38Schristos 7392950cc38Schristos spkt_next = spkt->link; 7402950cc38Schristos if (0 == spkt->stime || spkt->done) 7412950cc38Schristos continue; 7422950cc38Schristos age = start_cb.tv_sec - spkt->stime; 7432950cc38Schristos TRACE(3, ("%s %s %cCST age %ld\n", 7442950cc38Schristos stoa(&spkt->addr), 7452950cc38Schristos spkt->dctx->name, xcst, age)); 7462950cc38Schristos if (age > response_timeout) 7472950cc38Schristos timeout_query(spkt); 7482950cc38Schristos } 7492950cc38Schristos } 7502950cc38Schristos // Do we care about didsomething? 7512950cc38Schristos TRACE(3, ("timeout_queries: didsomething is %d, age is %ld\n", 7522950cc38Schristos didsomething, (long) (start_cb.tv_sec - start_tv.tv_sec))); 7532950cc38Schristos if (start_cb.tv_sec - start_tv.tv_sec > response_timeout) { 7542950cc38Schristos TRACE(3, ("timeout_queries: bail!\n")); 7552950cc38Schristos event_base_loopexit(base, NULL); 7562950cc38Schristos shutting_down = TRUE; 7572950cc38Schristos } 7582950cc38Schristos } 7592950cc38Schristos 7602950cc38Schristos 7612950cc38Schristos void dec_pending_ntp( 7622950cc38Schristos const char * name, 7632950cc38Schristos sockaddr_u * server 7642950cc38Schristos ) 7652950cc38Schristos { 7662950cc38Schristos if (n_pending_ntp > 0) { 7672950cc38Schristos --n_pending_ntp; 7682950cc38Schristos check_exit_conditions(); 7692950cc38Schristos } else { 7702950cc38Schristos INSIST(0 == n_pending_ntp); 7712950cc38Schristos TRACE(1, ("n_pending_ntp was zero before decrement for %s\n", 7722950cc38Schristos hostnameaddr(name, server))); 7732950cc38Schristos } 7742950cc38Schristos } 7752950cc38Schristos 7762950cc38Schristos 7772950cc38Schristos void timeout_query( 7782950cc38Schristos sent_pkt * spkt 7792950cc38Schristos ) 7802950cc38Schristos { 7812950cc38Schristos sockaddr_u * server; 7822950cc38Schristos char xcst; 7832950cc38Schristos 7842950cc38Schristos 7852950cc38Schristos switch (spkt->dctx->flags & CTX_xCST) { 7862950cc38Schristos case CTX_BCST: 7872950cc38Schristos xcst = 'B'; 7882950cc38Schristos break; 7892950cc38Schristos 7902950cc38Schristos case CTX_UCST: 7912950cc38Schristos xcst = 'U'; 7922950cc38Schristos break; 7932950cc38Schristos 7942950cc38Schristos default: 7952950cc38Schristos INSIST(!"spkt->dctx->flags neither UCST nor BCST"); 7962950cc38Schristos break; 7972950cc38Schristos } 7982950cc38Schristos spkt->done = TRUE; 7992950cc38Schristos server = &spkt->addr; 8002950cc38Schristos msyslog(LOG_INFO, "%s no %cCST response after %d seconds", 8012950cc38Schristos hostnameaddr(spkt->dctx->name, server), xcst, 8022950cc38Schristos response_timeout); 8032950cc38Schristos dec_pending_ntp(spkt->dctx->name, server); 8042950cc38Schristos return; 8052950cc38Schristos } 8062950cc38Schristos 8072950cc38Schristos 8082950cc38Schristos /* 8092950cc38Schristos ** check_kod 8102950cc38Schristos */ 8112950cc38Schristos int 8122950cc38Schristos check_kod( 8132950cc38Schristos const struct addrinfo * ai 8142950cc38Schristos ) 8152950cc38Schristos { 8162950cc38Schristos char *hostname; 8172950cc38Schristos struct kod_entry *reason; 8182950cc38Schristos 8192950cc38Schristos /* Is there a KoD on file for this address? */ 8202950cc38Schristos hostname = addrinfo_to_str(ai); 8212950cc38Schristos TRACE(2, ("check_kod: checking <%s>\n", hostname)); 8222950cc38Schristos if (search_entry(hostname, &reason)) { 8232950cc38Schristos printf("prior KoD for %s, skipping.\n", 8242950cc38Schristos hostname); 825abb0f93cSkardel free(reason); 8262950cc38Schristos free(hostname); 8272950cc38Schristos 8282950cc38Schristos return 1; 829abb0f93cSkardel } 830abb0f93cSkardel free(hostname); 831abb0f93cSkardel 832abb0f93cSkardel return 0; 833abb0f93cSkardel } 834abb0f93cSkardel 8353123f114Skardel 8362950cc38Schristos /* 8372950cc38Schristos ** Socket readable/timeout Callback: 8382950cc38Schristos ** Read in the packet 8392950cc38Schristos ** Unicast: 8402950cc38Schristos ** - close socket 8412950cc38Schristos ** - decrement n_pending_ntp 8422950cc38Schristos ** - If packet is good, set the time and "exit" 8432950cc38Schristos ** Broadcast: 8442950cc38Schristos ** - If packet is good, set the time and "exit" 8452950cc38Schristos */ 8462950cc38Schristos void 8472950cc38Schristos sock_cb( 8482950cc38Schristos evutil_socket_t fd, 8492950cc38Schristos short what, 8502950cc38Schristos void *ptr 8512950cc38Schristos ) 8522950cc38Schristos { 8532950cc38Schristos sockaddr_u sender; 8542950cc38Schristos sockaddr_u * psau; 8552950cc38Schristos sent_pkt ** p_pktlist; 8562950cc38Schristos sent_pkt * spkt; 8572950cc38Schristos int rpktl; 8582950cc38Schristos int rc; 8592950cc38Schristos 8602950cc38Schristos INSIST(sock4 == fd || sock6 == fd); 8612950cc38Schristos 8622950cc38Schristos TRACE(3, ("sock_cb: event on sock%s:%s%s%s%s\n", 8632950cc38Schristos (fd == sock6) 8642950cc38Schristos ? "6" 8652950cc38Schristos : "4", 8662950cc38Schristos (what & EV_TIMEOUT) ? " timeout" : "", 8672950cc38Schristos (what & EV_READ) ? " read" : "", 8682950cc38Schristos (what & EV_WRITE) ? " write" : "", 8692950cc38Schristos (what & EV_SIGNAL) ? " signal" : "")); 8702950cc38Schristos 8712950cc38Schristos if (!(EV_READ & what)) { 8722950cc38Schristos if (EV_TIMEOUT & what) 8732950cc38Schristos timeout_queries(); 8742950cc38Schristos 8752950cc38Schristos return; 8762950cc38Schristos } 8772950cc38Schristos 8782950cc38Schristos /* Read in the packet */ 8792950cc38Schristos rpktl = recvdata(fd, &sender, &rbuf, sizeof(rbuf)); 8802950cc38Schristos if (rpktl < 0) { 8812950cc38Schristos msyslog(LOG_DEBUG, "recvfrom error %m"); 8822950cc38Schristos return; 8832950cc38Schristos } 8842950cc38Schristos 8852950cc38Schristos if (sock6 == fd) 8862950cc38Schristos p_pktlist = &v6_pkts_list; 8872950cc38Schristos else 8882950cc38Schristos p_pktlist = &v4_pkts_list; 8892950cc38Schristos 8902950cc38Schristos for (spkt = *p_pktlist; spkt != NULL; spkt = spkt->link) { 8912950cc38Schristos psau = &spkt->addr; 8922950cc38Schristos if (SOCK_EQ(&sender, psau)) 8932950cc38Schristos break; 8942950cc38Schristos } 8952950cc38Schristos if (NULL == spkt) { 8962950cc38Schristos msyslog(LOG_WARNING, 8972950cc38Schristos "Packet from unexpected source %s dropped", 8982950cc38Schristos sptoa(&sender)); 8992950cc38Schristos return; 9002950cc38Schristos } 9012950cc38Schristos 9022950cc38Schristos TRACE(1, ("sock_cb: %s %s\n", spkt->dctx->name, 9032950cc38Schristos sptoa(&sender))); 9042950cc38Schristos 9052950cc38Schristos rpktl = process_pkt(&r_pkt, &sender, rpktl, MODE_SERVER, 9062950cc38Schristos &spkt->x_pkt, "sock_cb"); 9072950cc38Schristos 9082950cc38Schristos TRACE(2, ("sock_cb: process_pkt returned %d\n", rpktl)); 9092950cc38Schristos 9102950cc38Schristos /* If this is a Unicast packet, one down ... */ 9112950cc38Schristos if (!spkt->done && (CTX_UCST & spkt->dctx->flags)) { 9122950cc38Schristos dec_pending_ntp(spkt->dctx->name, &spkt->addr); 9132950cc38Schristos spkt->done = TRUE; 9142950cc38Schristos } 9152950cc38Schristos 9162950cc38Schristos 9172950cc38Schristos /* If the packet is good, set the time and we're all done */ 9182950cc38Schristos rc = handle_pkt(rpktl, &r_pkt, &spkt->addr, spkt->dctx->name); 9192950cc38Schristos if (0 != rc) 9202950cc38Schristos TRACE(1, ("sock_cb: handle_pkt() returned %d\n", rc)); 9212950cc38Schristos check_exit_conditions(); 9222950cc38Schristos } 9232950cc38Schristos 9242950cc38Schristos 9252950cc38Schristos /* 9262950cc38Schristos * check_exit_conditions() 9272950cc38Schristos * 9282950cc38Schristos * If sntp has a reply, ask the event loop to stop after this round of 9292950cc38Schristos * callbacks, unless --wait was used. 9302950cc38Schristos */ 9312950cc38Schristos void 9322950cc38Schristos check_exit_conditions(void) 9332950cc38Schristos { 9342950cc38Schristos if ((0 == n_pending_ntp && 0 == n_pending_dns) || 9352950cc38Schristos (time_derived && !HAVE_OPT(WAIT))) { 9362950cc38Schristos event_base_loopexit(base, NULL); 9372950cc38Schristos shutting_down = TRUE; 9382950cc38Schristos } else { 9392950cc38Schristos TRACE(2, ("%d NTP and %d name queries pending\n", 9402950cc38Schristos n_pending_ntp, n_pending_dns)); 9412950cc38Schristos } 9422950cc38Schristos } 9432950cc38Schristos 9442950cc38Schristos 9452950cc38Schristos /* 9462950cc38Schristos * sntp_addremove_fd() is invoked by the intres blocking worker code 9472950cc38Schristos * to read from a pipe, or to stop same. 9482950cc38Schristos */ 9492950cc38Schristos void sntp_addremove_fd( 9502950cc38Schristos int fd, 9512950cc38Schristos int is_pipe, 9522950cc38Schristos int remove_it 9532950cc38Schristos ) 9542950cc38Schristos { 9552950cc38Schristos u_int idx; 9562950cc38Schristos blocking_child *c; 9572950cc38Schristos struct event * ev; 9582950cc38Schristos 9592950cc38Schristos #ifdef HAVE_SOCKETPAIR 9602950cc38Schristos if (is_pipe) { 9612950cc38Schristos /* sntp only asks for EV_FEATURE_FDS without HAVE_SOCKETPAIR */ 9622950cc38Schristos msyslog(LOG_ERR, "fatal: pipes not supported on systems with socketpair()"); 9632950cc38Schristos exit(1); 9642950cc38Schristos } 9652950cc38Schristos #endif 9662950cc38Schristos 9672950cc38Schristos c = NULL; 9682950cc38Schristos for (idx = 0; idx < blocking_children_alloc; idx++) { 9692950cc38Schristos c = blocking_children[idx]; 9702950cc38Schristos if (NULL == c) 9712950cc38Schristos continue; 9722950cc38Schristos if (fd == c->resp_read_pipe) 9732950cc38Schristos break; 9742950cc38Schristos } 9752950cc38Schristos if (idx == blocking_children_alloc) 9762950cc38Schristos return; 9772950cc38Schristos 9782950cc38Schristos if (remove_it) { 9792950cc38Schristos ev = c->resp_read_ctx; 9802950cc38Schristos c->resp_read_ctx = NULL; 9812950cc38Schristos event_del(ev); 9822950cc38Schristos event_free(ev); 9832950cc38Schristos 9842950cc38Schristos return; 9852950cc38Schristos } 9862950cc38Schristos 9872950cc38Schristos ev = event_new(base, fd, EV_READ | EV_PERSIST, 9882950cc38Schristos &worker_resp_cb, c); 9892950cc38Schristos if (NULL == ev) { 9902950cc38Schristos msyslog(LOG_ERR, 9912950cc38Schristos "sntp_addremove_fd: event_new(base, fd) failed!"); 9922950cc38Schristos return; 9932950cc38Schristos } 9942950cc38Schristos c->resp_read_ctx = ev; 9952950cc38Schristos event_add(ev, NULL); 9962950cc38Schristos } 9972950cc38Schristos 9982950cc38Schristos 9992950cc38Schristos /* called by forked intres child to close open descriptors */ 10002950cc38Schristos #ifdef WORK_FORK 10012950cc38Schristos void 10022950cc38Schristos kill_asyncio( 10032950cc38Schristos int startfd 10042950cc38Schristos ) 10052950cc38Schristos { 10062950cc38Schristos if (INVALID_SOCKET != sock4) { 10072950cc38Schristos closesocket(sock4); 10082950cc38Schristos sock4 = INVALID_SOCKET; 10092950cc38Schristos } 10102950cc38Schristos if (INVALID_SOCKET != sock6) { 10112950cc38Schristos closesocket(sock6); 10122950cc38Schristos sock6 = INVALID_SOCKET; 10132950cc38Schristos } 10142950cc38Schristos if (INVALID_SOCKET != bsock4) { 1015*eabc0478Schristos closesocket(bsock4); 1016*eabc0478Schristos bsock4 = INVALID_SOCKET; 10172950cc38Schristos } 10182950cc38Schristos if (INVALID_SOCKET != bsock6) { 1019*eabc0478Schristos closesocket(bsock6); 1020*eabc0478Schristos bsock6 = INVALID_SOCKET; 10212950cc38Schristos } 10222950cc38Schristos } 10232950cc38Schristos #endif 10242950cc38Schristos 10252950cc38Schristos 10262950cc38Schristos /* 10272950cc38Schristos * worker_resp_cb() is invoked when resp_read_pipe is readable. 10282950cc38Schristos */ 10292950cc38Schristos void 10302950cc38Schristos worker_resp_cb( 10312950cc38Schristos evutil_socket_t fd, 10322950cc38Schristos short what, 10332950cc38Schristos void * ctx /* blocking_child * */ 10342950cc38Schristos ) 10352950cc38Schristos { 10362950cc38Schristos blocking_child * c; 10372950cc38Schristos 1038*eabc0478Schristos REQUIRE(EV_READ & what); 10392950cc38Schristos c = ctx; 1040*eabc0478Schristos INSIST(fd == c->resp_read_pipe); 10412950cc38Schristos process_blocking_resp(c); 10422950cc38Schristos } 10432950cc38Schristos 10442950cc38Schristos 10452950cc38Schristos /* 10462950cc38Schristos * intres_timeout_req(s) is invoked in the parent to schedule an idle 10472950cc38Schristos * timeout to fire in s seconds, if not reset earlier by a call to 10482950cc38Schristos * intres_timeout_req(0), which clears any pending timeout. When the 10492950cc38Schristos * timeout expires, worker_idle_timer_fired() is invoked (again, in the 10502950cc38Schristos * parent). 10512950cc38Schristos * 10522950cc38Schristos * sntp and ntpd each provide implementations adapted to their timers. 10532950cc38Schristos */ 10542950cc38Schristos void 10552950cc38Schristos intres_timeout_req( 10562950cc38Schristos u_int seconds /* 0 cancels */ 10572950cc38Schristos ) 10582950cc38Schristos { 10592950cc38Schristos struct timeval tv_to; 10602950cc38Schristos 10612950cc38Schristos if (NULL == ev_worker_timeout) { 10622950cc38Schristos ev_worker_timeout = event_new(base, -1, 10632950cc38Schristos EV_TIMEOUT | EV_PERSIST, 10642950cc38Schristos &worker_timeout, NULL); 1065*eabc0478Schristos INSIST(NULL != ev_worker_timeout); 10662950cc38Schristos } else { 10672950cc38Schristos event_del(ev_worker_timeout); 10682950cc38Schristos } 10692950cc38Schristos if (0 == seconds) 10702950cc38Schristos return; 10712950cc38Schristos tv_to.tv_sec = seconds; 10722950cc38Schristos tv_to.tv_usec = 0; 10732950cc38Schristos event_add(ev_worker_timeout, &tv_to); 10742950cc38Schristos } 10752950cc38Schristos 10762950cc38Schristos 10772950cc38Schristos void 10782950cc38Schristos worker_timeout( 10792950cc38Schristos evutil_socket_t fd, 10802950cc38Schristos short what, 10812950cc38Schristos void * ctx 10822950cc38Schristos ) 10832950cc38Schristos { 10842950cc38Schristos UNUSED_ARG(fd); 10852950cc38Schristos UNUSED_ARG(ctx); 10862950cc38Schristos 1087*eabc0478Schristos REQUIRE(EV_TIMEOUT & what); 10882950cc38Schristos worker_idle_timer_fired(); 10892950cc38Schristos } 10902950cc38Schristos 10912950cc38Schristos 10922950cc38Schristos void 10932950cc38Schristos sntp_libevent_log_cb( 10942950cc38Schristos int severity, 10952950cc38Schristos const char * msg 10962950cc38Schristos ) 10972950cc38Schristos { 10982950cc38Schristos int level; 10992950cc38Schristos 11002950cc38Schristos switch (severity) { 11012950cc38Schristos 11022950cc38Schristos default: 11032950cc38Schristos case _EVENT_LOG_DEBUG: 11042950cc38Schristos level = LOG_DEBUG; 11052950cc38Schristos break; 11062950cc38Schristos 11072950cc38Schristos case _EVENT_LOG_MSG: 11082950cc38Schristos level = LOG_NOTICE; 11092950cc38Schristos break; 11102950cc38Schristos 11112950cc38Schristos case _EVENT_LOG_WARN: 11122950cc38Schristos level = LOG_WARNING; 11132950cc38Schristos break; 11142950cc38Schristos 11152950cc38Schristos case _EVENT_LOG_ERR: 11162950cc38Schristos level = LOG_ERR; 11172950cc38Schristos break; 11182950cc38Schristos } 11192950cc38Schristos 11202950cc38Schristos msyslog(level, "%s", msg); 11212950cc38Schristos } 11222950cc38Schristos 11233123f114Skardel 1124abb0f93cSkardel int 11253123f114Skardel generate_pkt ( 11263123f114Skardel struct pkt *x_pkt, 11273123f114Skardel const struct timeval *tv_xmt, 11283123f114Skardel int key_id, 11293123f114Skardel struct key *pkt_key 11303123f114Skardel ) 11313123f114Skardel { 11322950cc38Schristos l_fp xmt_fp; 11332950cc38Schristos int pkt_len; 11342950cc38Schristos int mac_size; 11352950cc38Schristos 11362950cc38Schristos pkt_len = LEN_PKT_NOMAC; 11372950cc38Schristos ZERO(*x_pkt); 11382950cc38Schristos TVTOTS(tv_xmt, &xmt_fp); 11392950cc38Schristos HTONL_FP(&xmt_fp, &x_pkt->xmt); 11403123f114Skardel x_pkt->stratum = STRATUM_TO_PKT(STRATUM_UNSPEC); 11413123f114Skardel x_pkt->ppoll = 8; 11423123f114Skardel /* FIXME! Modus broadcast + adr. check -> bdr. pkt */ 11432950cc38Schristos set_li_vn_mode(x_pkt, LEAP_NOTINSYNC, ntpver, 3); 11444eea345dSchristos if (debug > 0) { 11454eea345dSchristos printf("generate_pkt: key_id %d, key pointer %p\n", key_id, pkt_key); 11464eea345dSchristos } 11473123f114Skardel if (pkt_key != NULL) { 11483123f114Skardel x_pkt->exten[0] = htonl(key_id); 1149*eabc0478Schristos mac_size = make_mac(x_pkt, pkt_len, pkt_key, 1150*eabc0478Schristos (char *)&x_pkt->exten[1], MAX_MDG_LEN); 11512950cc38Schristos if (mac_size > 0) 11524eea345dSchristos pkt_len += mac_size + KEY_MAC_LEN; 11534eea345dSchristos #ifdef DEBUG 11544eea345dSchristos if (debug > 0) { 11554eea345dSchristos printf("generate_pkt: mac_size is %d\n", mac_size); 11564eea345dSchristos } 11574eea345dSchristos #endif 11584eea345dSchristos 11593123f114Skardel } 11603123f114Skardel return pkt_len; 11613123f114Skardel } 11623123f114Skardel 11632950cc38Schristos 11643123f114Skardel int 11653123f114Skardel handle_pkt( 11663123f114Skardel int rpktl, 11673123f114Skardel struct pkt * rpkt, 11682950cc38Schristos sockaddr_u * host, 11692950cc38Schristos const char * hostname 1170abb0f93cSkardel ) 1171abb0f93cSkardel { 11722950cc38Schristos char disptxt[32]; 11732950cc38Schristos const char * addrtxt; 11743123f114Skardel struct timeval tv_dst; 11752950cc38Schristos int cnt; 11762950cc38Schristos int sw_case; 11772950cc38Schristos int digits; 11782950cc38Schristos int stratum; 11792950cc38Schristos char * ref; 11802950cc38Schristos char * ts_str; 11817476e6e4Schristos const char * leaptxt; 11822950cc38Schristos double offset; 11832950cc38Schristos double precision; 11842950cc38Schristos double synch_distance; 11853123f114Skardel char * p_SNTP_PRETEND_TIME; 11862950cc38Schristos time_t pretend_time; 11872950cc38Schristos #if SIZEOF_TIME_T == 8 11882950cc38Schristos long long ll; 11892950cc38Schristos #else 11902950cc38Schristos long l; 11912950cc38Schristos #endif 11922950cc38Schristos 11932950cc38Schristos ts_str = NULL; 1194abb0f93cSkardel 1195abb0f93cSkardel if (rpktl > 0) 1196abb0f93cSkardel sw_case = 1; 1197abb0f93cSkardel else 1198abb0f93cSkardel sw_case = rpktl; 1199abb0f93cSkardel 1200abb0f93cSkardel switch (sw_case) { 12012950cc38Schristos 1202abb0f93cSkardel case SERVER_UNUSEABLE: 1203abb0f93cSkardel return -1; 1204abb0f93cSkardel break; 1205abb0f93cSkardel 1206abb0f93cSkardel case PACKET_UNUSEABLE: 1207abb0f93cSkardel break; 1208abb0f93cSkardel 1209abb0f93cSkardel case SERVER_AUTH_FAIL: 1210abb0f93cSkardel break; 1211abb0f93cSkardel 1212abb0f93cSkardel case KOD_DEMOBILIZE: 1213abb0f93cSkardel /* Received a DENY or RESTR KOD packet */ 12142950cc38Schristos addrtxt = stoa(host); 12153123f114Skardel ref = (char *)&rpkt->refid; 12162950cc38Schristos add_entry(addrtxt, ref); 12172950cc38Schristos msyslog(LOG_WARNING, "KOD code %c%c%c%c from %s %s", 12182950cc38Schristos ref[0], ref[1], ref[2], ref[3], addrtxt, hostname); 1219abb0f93cSkardel break; 1220abb0f93cSkardel 1221abb0f93cSkardel case KOD_RATE: 12222950cc38Schristos /* 12232950cc38Schristos ** Hmm... 12242950cc38Schristos ** We should probably call add_entry() with an 12252950cc38Schristos ** expiration timestamp of several seconds in the future, 12262950cc38Schristos ** and back-off even more if we get more RATE responses. 12272950cc38Schristos */ 1228abb0f93cSkardel break; 1229abb0f93cSkardel 1230abb0f93cSkardel case 1: 12312950cc38Schristos TRACE(3, ("handle_pkt: %d bytes from %s %s\n", 12322950cc38Schristos rpktl, stoa(host), hostname)); 1233abb0f93cSkardel 12342950cc38Schristos gettimeofday_cached(base, &tv_dst); 12353123f114Skardel 12363123f114Skardel p_SNTP_PRETEND_TIME = getenv("SNTP_PRETEND_TIME"); 12373123f114Skardel if (p_SNTP_PRETEND_TIME) { 12382950cc38Schristos pretend_time = 0; 12392950cc38Schristos #if SIZEOF_TIME_T == 4 12402950cc38Schristos if (1 == sscanf(p_SNTP_PRETEND_TIME, "%ld", &l)) 12412950cc38Schristos pretend_time = (time_t)l; 12422950cc38Schristos #elif SIZEOF_TIME_T == 8 12432950cc38Schristos if (1 == sscanf(p_SNTP_PRETEND_TIME, "%lld", &ll)) 12442950cc38Schristos pretend_time = (time_t)ll; 12452950cc38Schristos #else 12462950cc38Schristos # include "GRONK: unexpected value for SIZEOF_TIME_T" 12472950cc38Schristos #endif 12482950cc38Schristos if (0 != pretend_time) 12492950cc38Schristos tv_dst.tv_sec = pretend_time; 12503123f114Skardel } 12513123f114Skardel 12523123f114Skardel offset_calculation(rpkt, rpktl, &tv_dst, &offset, 12532950cc38Schristos &precision, &synch_distance); 12542950cc38Schristos time_derived = TRUE; 12553123f114Skardel 1256abb0f93cSkardel for (digits = 0; (precision *= 10.) < 1.; ++digits) 1257abb0f93cSkardel /* empty */ ; 1258abb0f93cSkardel if (digits > 6) 1259abb0f93cSkardel digits = 6; 1260abb0f93cSkardel 1261abb0f93cSkardel ts_str = tv_to_str(&tv_dst); 12622950cc38Schristos stratum = rpkt->stratum; 12632950cc38Schristos if (0 == stratum) 12642950cc38Schristos stratum = 16; 12652950cc38Schristos 12662950cc38Schristos if (synch_distance > 0.) { 12672950cc38Schristos cnt = snprintf(disptxt, sizeof(disptxt), 12682950cc38Schristos " +/- %f", synch_distance); 12692950cc38Schristos if ((size_t)cnt >= sizeof(disptxt)) 12702950cc38Schristos snprintf(disptxt, sizeof(disptxt), 12712950cc38Schristos "ERROR %d >= %d", cnt, 12722950cc38Schristos (int)sizeof(disptxt)); 12732950cc38Schristos } else { 12742950cc38Schristos disptxt[0] = '\0'; 12752950cc38Schristos } 12762950cc38Schristos 12777476e6e4Schristos switch (PKT_LEAP(rpkt->li_vn_mode)) { 12787476e6e4Schristos case LEAP_NOWARNING: 12797476e6e4Schristos leaptxt = "no-leap"; 12807476e6e4Schristos break; 12817476e6e4Schristos case LEAP_ADDSECOND: 12827476e6e4Schristos leaptxt = "add-leap"; 12837476e6e4Schristos break; 12847476e6e4Schristos case LEAP_DELSECOND: 12857476e6e4Schristos leaptxt = "del-leap"; 12867476e6e4Schristos break; 12877476e6e4Schristos case LEAP_NOTINSYNC: 12887476e6e4Schristos leaptxt = "unsync"; 12897476e6e4Schristos break; 12907476e6e4Schristos default: 12917476e6e4Schristos leaptxt = "LEAP-ERROR"; 12927476e6e4Schristos break; 12937476e6e4Schristos } 12947476e6e4Schristos 12957476e6e4Schristos msyslog(LOG_INFO, "%s %+.*f%s %s s%d %s%s", ts_str, 12962950cc38Schristos digits, offset, disptxt, 12972950cc38Schristos hostnameaddr(hostname, host), stratum, 12987476e6e4Schristos leaptxt, 12992950cc38Schristos (time_adjusted) 13002950cc38Schristos ? " [excess]" 13012950cc38Schristos : ""); 1302abb0f93cSkardel free(ts_str); 1303abb0f93cSkardel 13043123f114Skardel if (p_SNTP_PRETEND_TIME) 13053123f114Skardel return 0; 13063123f114Skardel 13072950cc38Schristos if (!time_adjusted && 13082950cc38Schristos (ENABLED_OPT(STEP) || ENABLED_OPT(SLEW))) 1309abb0f93cSkardel return set_time(offset); 1310abb0f93cSkardel 13112950cc38Schristos return EX_OK; 1312abb0f93cSkardel } 13133123f114Skardel 13143123f114Skardel return 1; 13153123f114Skardel } 13163123f114Skardel 13172950cc38Schristos 13183123f114Skardel void 13193123f114Skardel offset_calculation( 13203123f114Skardel struct pkt *rpkt, 13213123f114Skardel int rpktl, 13223123f114Skardel struct timeval *tv_dst, 13233123f114Skardel double *offset, 13243123f114Skardel double *precision, 13252950cc38Schristos double *synch_distance 13263123f114Skardel ) 13273123f114Skardel { 13283123f114Skardel l_fp p_rec, p_xmt, p_ref, p_org, tmp, dst; 13293123f114Skardel u_fp p_rdly, p_rdsp; 13303123f114Skardel double t21, t34, delta; 13313123f114Skardel 13323123f114Skardel /* Convert timestamps from network to host byte order */ 13333123f114Skardel p_rdly = NTOHS_FP(rpkt->rootdelay); 13343123f114Skardel p_rdsp = NTOHS_FP(rpkt->rootdisp); 13353123f114Skardel NTOHL_FP(&rpkt->reftime, &p_ref); 13363123f114Skardel NTOHL_FP(&rpkt->org, &p_org); 13373123f114Skardel NTOHL_FP(&rpkt->rec, &p_rec); 13383123f114Skardel NTOHL_FP(&rpkt->xmt, &p_xmt); 13393123f114Skardel 13403123f114Skardel *precision = LOGTOD(rpkt->precision); 13413123f114Skardel 13422950cc38Schristos TRACE(3, ("offset_calculation: LOGTOD(rpkt->precision): %f\n", *precision)); 13433123f114Skardel 13443123f114Skardel /* Compute offset etc. */ 13453123f114Skardel tmp = p_rec; 13463123f114Skardel L_SUB(&tmp, &p_org); 13473123f114Skardel LFPTOD(&tmp, t21); 13483123f114Skardel TVTOTS(tv_dst, &dst); 13493123f114Skardel dst.l_ui += JAN_1970; 13503123f114Skardel tmp = p_xmt; 13513123f114Skardel L_SUB(&tmp, &dst); 13523123f114Skardel LFPTOD(&tmp, t34); 13533123f114Skardel *offset = (t21 + t34) / 2.; 13543123f114Skardel delta = t21 - t34; 13553123f114Skardel 13562950cc38Schristos // synch_distance is: 13572950cc38Schristos // (peer->delay + peer->rootdelay) / 2 + peer->disp 13582950cc38Schristos // + peer->rootdisp + clock_phi * (current_time - peer->update) 13592950cc38Schristos // + peer->jitter; 13602950cc38Schristos // 13612950cc38Schristos // and peer->delay = fabs(peer->offset - p_offset) * 2; 13622950cc38Schristos // and peer->offset needs history, so we're left with 13632950cc38Schristos // p_offset = (t21 + t34) / 2.; 13642950cc38Schristos // peer->disp = 0; (we have no history to augment this) 13652950cc38Schristos // clock_phi = 15e-6; 13662950cc38Schristos // peer->jitter = LOGTOD(sys_precision); (we have no history to augment this) 13672950cc38Schristos // and ntp_proto.c:set_sys_tick_precision() should get us sys_precision. 13682950cc38Schristos // 13692950cc38Schristos // so our answer seems to be: 13702950cc38Schristos // 13712950cc38Schristos // (fabs(t21 + t34) + peer->rootdelay) / 3. 13722950cc38Schristos // + 0 (peer->disp) 13732950cc38Schristos // + peer->rootdisp 13742950cc38Schristos // + 15e-6 (clock_phi) 13752950cc38Schristos // + LOGTOD(sys_precision) 13763123f114Skardel 13772950cc38Schristos INSIST( FPTOD(p_rdly) >= 0. ); 13782950cc38Schristos #if 1 13792950cc38Schristos *synch_distance = (fabs(t21 + t34) + FPTOD(p_rdly)) / 3. 13802950cc38Schristos + 0. 13812950cc38Schristos + FPTOD(p_rdsp) 13822950cc38Schristos + 15e-6 13832950cc38Schristos + 0. /* LOGTOD(sys_precision) when we can get it */ 13842950cc38Schristos ; 13852950cc38Schristos INSIST( *synch_distance >= 0. ); 13862950cc38Schristos #else 13872950cc38Schristos *synch_distance = (FPTOD(p_rdly) + FPTOD(p_rdsp))/2.0; 13883123f114Skardel #endif 13893123f114Skardel 13902950cc38Schristos #ifdef DEBUG 13912950cc38Schristos if (debug > 3) { 13922950cc38Schristos printf("sntp rootdelay: %f\n", FPTOD(p_rdly)); 13932950cc38Schristos printf("sntp rootdisp: %f\n", FPTOD(p_rdsp)); 13942950cc38Schristos printf("sntp syncdist: %f\n", *synch_distance); 13953123f114Skardel 13962950cc38Schristos pkt_output(rpkt, rpktl, stdout); 13972950cc38Schristos 13982950cc38Schristos printf("sntp offset_calculation: rpkt->reftime:\n"); 13992950cc38Schristos l_fp_output(&p_ref, stdout); 14002950cc38Schristos printf("sntp offset_calculation: rpkt->org:\n"); 14012950cc38Schristos l_fp_output(&p_org, stdout); 14022950cc38Schristos printf("sntp offset_calculation: rpkt->rec:\n"); 14032950cc38Schristos l_fp_output(&p_rec, stdout); 14042950cc38Schristos printf("sntp offset_calculation: rpkt->xmt:\n"); 14052950cc38Schristos l_fp_output(&p_xmt, stdout); 14062950cc38Schristos } 14072950cc38Schristos #endif 14082950cc38Schristos 14092950cc38Schristos TRACE(3, ("sntp offset_calculation:\trec - org t21: %.6f\n" 14102950cc38Schristos "\txmt - dst t34: %.6f\tdelta: %.6f\toffset: %.6f\n", 14112950cc38Schristos t21, t34, delta, *offset)); 14122950cc38Schristos 14132950cc38Schristos return; 14143123f114Skardel } 14153123f114Skardel 1416abb0f93cSkardel 1417abb0f93cSkardel 1418abb0f93cSkardel /* Compute the 8 bits for li_vn_mode */ 1419abb0f93cSkardel void 1420abb0f93cSkardel set_li_vn_mode ( 1421abb0f93cSkardel struct pkt *spkt, 1422abb0f93cSkardel char leap, 1423abb0f93cSkardel char version, 1424abb0f93cSkardel char mode 1425abb0f93cSkardel ) 1426abb0f93cSkardel { 1427abb0f93cSkardel if (leap > 3) { 14282950cc38Schristos msyslog(LOG_DEBUG, "set_li_vn_mode: leap > 3, using max. 3"); 1429abb0f93cSkardel leap = 3; 1430abb0f93cSkardel } 1431abb0f93cSkardel 14326bb3b841Schristos if ((unsigned char)version > 7) { 14332950cc38Schristos msyslog(LOG_DEBUG, "set_li_vn_mode: version < 0 or > 7, using 4"); 14342950cc38Schristos version = 4; 14352950cc38Schristos } 14362950cc38Schristos 1437abb0f93cSkardel if (mode > 7) { 14383123f114Skardel msyslog(LOG_DEBUG, "set_li_vn_mode: mode > 7, using client mode 3"); 1439abb0f93cSkardel mode = 3; 1440abb0f93cSkardel } 1441abb0f93cSkardel 1442abb0f93cSkardel spkt->li_vn_mode = leap << 6; 1443abb0f93cSkardel spkt->li_vn_mode |= version << 3; 1444abb0f93cSkardel spkt->li_vn_mode |= mode; 1445abb0f93cSkardel } 1446abb0f93cSkardel 14472950cc38Schristos 14482950cc38Schristos /* 14492950cc38Schristos ** set_time applies 'offset' to the local clock. 1450abb0f93cSkardel */ 1451abb0f93cSkardel int 1452abb0f93cSkardel set_time( 1453abb0f93cSkardel double offset 1454abb0f93cSkardel ) 1455abb0f93cSkardel { 14562950cc38Schristos int rc; 1457abb0f93cSkardel 14582950cc38Schristos if (time_adjusted) 14592950cc38Schristos return EX_OK; 1460abb0f93cSkardel 14612950cc38Schristos /* 14622950cc38Schristos ** If we can step but we cannot slew, then step. 14632950cc38Schristos ** If we can step or slew and and |offset| > steplimit, then step. 14642950cc38Schristos */ 14652950cc38Schristos if (ENABLED_OPT(STEP) && 14662950cc38Schristos ( !ENABLED_OPT(SLEW) 14672950cc38Schristos || (ENABLED_OPT(SLEW) && (fabs(offset) > steplimit)) 14682950cc38Schristos )) { 14692950cc38Schristos rc = step_systime(offset); 1470abb0f93cSkardel 14712950cc38Schristos /* If there was a problem, can we rely on errno? */ 14722950cc38Schristos if (1 == rc) 14732950cc38Schristos time_adjusted = TRUE; 14742950cc38Schristos return (time_adjusted) 14752950cc38Schristos ? EX_OK 14762950cc38Schristos : 1; 14772950cc38Schristos /* 14782950cc38Schristos ** In case of error, what should we use? 14792950cc38Schristos ** EX_UNAVAILABLE? 14802950cc38Schristos ** EX_OSERR? 14812950cc38Schristos ** EX_NOPERM? 14822950cc38Schristos */ 1483abb0f93cSkardel } 14842950cc38Schristos 14852950cc38Schristos if (ENABLED_OPT(SLEW)) { 14862950cc38Schristos rc = adj_systime(offset); 14872950cc38Schristos 14882950cc38Schristos /* If there was a problem, can we rely on errno? */ 14892950cc38Schristos if (1 == rc) 14902950cc38Schristos time_adjusted = TRUE; 14912950cc38Schristos return (time_adjusted) 14922950cc38Schristos ? EX_OK 14932950cc38Schristos : 1; 14942950cc38Schristos /* 14952950cc38Schristos ** In case of error, what should we use? 14962950cc38Schristos ** EX_UNAVAILABLE? 14972950cc38Schristos ** EX_OSERR? 14982950cc38Schristos ** EX_NOPERM? 14992950cc38Schristos */ 15002950cc38Schristos } 15012950cc38Schristos 15022950cc38Schristos return EX_SOFTWARE; 15032950cc38Schristos } 15042950cc38Schristos 15052950cc38Schristos 15062950cc38Schristos int 15072950cc38Schristos libevent_version_ok(void) 15082950cc38Schristos { 15092950cc38Schristos ev_uint32_t v_compile_maj; 15102950cc38Schristos ev_uint32_t v_run_maj; 15112950cc38Schristos 15122950cc38Schristos v_compile_maj = LIBEVENT_VERSION_NUMBER & 0xffff0000; 15132950cc38Schristos v_run_maj = event_get_version_number() & 0xffff0000; 15142950cc38Schristos if (v_compile_maj != v_run_maj) { 15152950cc38Schristos fprintf(stderr, 15162950cc38Schristos "Incompatible libevent versions: have %s, built with %s\n", 15172950cc38Schristos event_get_version(), 15182950cc38Schristos LIBEVENT_VERSION); 1519abb0f93cSkardel return 0; 1520abb0f93cSkardel } 15212950cc38Schristos return 1; 1522abb0f93cSkardel } 15232950cc38Schristos 15242950cc38Schristos /* 15252950cc38Schristos * gettimeofday_cached() 15262950cc38Schristos * 15272950cc38Schristos * Clones the event_base_gettimeofday_cached() interface but ensures the 15282950cc38Schristos * times are always on the gettimeofday() 1970 scale. Older libevent 2 15292950cc38Schristos * sometimes used gettimeofday(), sometimes the since-system-start 15302950cc38Schristos * clock_gettime(CLOCK_MONOTONIC), depending on the platform. 15312950cc38Schristos * 15322950cc38Schristos * It is not cleanly possible to tell which timescale older libevent is 15332950cc38Schristos * using. 15342950cc38Schristos * 15352950cc38Schristos * The strategy involves 1 hour thresholds chosen to be far longer than 15362950cc38Schristos * the duration of a round of libevent callbacks, which share a cached 15372950cc38Schristos * start-of-round time. First compare the last cached time with the 15382950cc38Schristos * current gettimeofday() time. If they are within one hour, libevent 15392950cc38Schristos * is using the proper timescale so leave the offset 0. Otherwise, 15402950cc38Schristos * compare libevent's cached time and the current time on the monotonic 15412950cc38Schristos * scale. If they are within an hour, libevent is using the monotonic 15422950cc38Schristos * scale so calculate the offset to add to such times to bring them to 15432950cc38Schristos * gettimeofday()'s scale. 15442950cc38Schristos */ 15452950cc38Schristos int 15462950cc38Schristos gettimeofday_cached( 15472950cc38Schristos struct event_base * b, 15482950cc38Schristos struct timeval * caller_tv 15492950cc38Schristos ) 15502950cc38Schristos { 15512950cc38Schristos #if defined(_EVENT_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) 15522950cc38Schristos static struct event_base * cached_b; 15532950cc38Schristos static struct timeval cached; 15542950cc38Schristos static struct timeval adj_cached; 15552950cc38Schristos static struct timeval offset; 15562950cc38Schristos static int offset_ready; 15572950cc38Schristos struct timeval latest; 15582950cc38Schristos struct timeval systemt; 15592950cc38Schristos struct timespec ts; 15602950cc38Schristos struct timeval mono; 15612950cc38Schristos struct timeval diff; 15622950cc38Schristos int cgt_rc; 15632950cc38Schristos int gtod_rc; 15642950cc38Schristos 15652950cc38Schristos event_base_gettimeofday_cached(b, &latest); 15662950cc38Schristos if (b == cached_b && 15672950cc38Schristos !memcmp(&latest, &cached, sizeof(latest))) { 15682950cc38Schristos *caller_tv = adj_cached; 1569abb0f93cSkardel return 0; 1570abb0f93cSkardel } 15712950cc38Schristos cached = latest; 15722950cc38Schristos cached_b = b; 15732950cc38Schristos if (!offset_ready) { 15742950cc38Schristos cgt_rc = clock_gettime(CLOCK_MONOTONIC, &ts); 15752950cc38Schristos gtod_rc = gettimeofday(&systemt, NULL); 15762950cc38Schristos if (0 != gtod_rc) { 15772950cc38Schristos msyslog(LOG_ERR, 15782950cc38Schristos "%s: gettimeofday() error %m", 15792950cc38Schristos progname); 15802950cc38Schristos exit(1); 15812950cc38Schristos } 15822950cc38Schristos diff = sub_tval(systemt, latest); 15832950cc38Schristos if (debug > 1) 15842950cc38Schristos printf("system minus cached %+ld.%06ld\n", 15852950cc38Schristos (long)diff.tv_sec, (long)diff.tv_usec); 15862950cc38Schristos if (0 != cgt_rc || labs((long)diff.tv_sec) < 3600) { 15872950cc38Schristos /* 15882950cc38Schristos * Either use_monotonic == 0, or this libevent 15892950cc38Schristos * has been repaired. Leave offset at zero. 15902950cc38Schristos */ 15912950cc38Schristos } else { 15922950cc38Schristos mono.tv_sec = ts.tv_sec; 15932950cc38Schristos mono.tv_usec = ts.tv_nsec / 1000; 15942950cc38Schristos diff = sub_tval(latest, mono); 15952950cc38Schristos if (debug > 1) 15962950cc38Schristos printf("cached minus monotonic %+ld.%06ld\n", 15972950cc38Schristos (long)diff.tv_sec, (long)diff.tv_usec); 15982950cc38Schristos if (labs((long)diff.tv_sec) < 3600) { 15992950cc38Schristos /* older libevent2 using monotonic */ 16002950cc38Schristos offset = sub_tval(systemt, mono); 16012950cc38Schristos TRACE(1, ("%s: Offsetting libevent CLOCK_MONOTONIC times by %+ld.%06ld\n", 16022950cc38Schristos "gettimeofday_cached", 16032950cc38Schristos (long)offset.tv_sec, 16042950cc38Schristos (long)offset.tv_usec)); 16052950cc38Schristos } 16062950cc38Schristos } 16072950cc38Schristos offset_ready = TRUE; 16082950cc38Schristos } 16092950cc38Schristos adj_cached = add_tval(cached, offset); 16102950cc38Schristos *caller_tv = adj_cached; 16112950cc38Schristos 16122950cc38Schristos return 0; 16132950cc38Schristos #else 16142950cc38Schristos return event_base_gettimeofday_cached(b, caller_tv); 16152950cc38Schristos #endif 16162950cc38Schristos } 16172950cc38Schristos 161879045f13Schristos /* Dummy function to satisfy libntp/work_fork.c */ 1619cdfa2a7eSchristos extern int set_user_group_ids(void); 1620cdfa2a7eSchristos int set_user_group_ids(void) 162179045f13Schristos { 162279045f13Schristos return 1; 162379045f13Schristos } 1624