/* * setup peer dstadr field keeping it in sync with the interface structures */ void set_peerdstadr(struct peer *peer, struct interface *interface) { if (peer->dstadr != interface) { if (interface != NULL && (peer->cast_flags & MDF_BCLNT) && (interface->flags & INT_MCASTIF) && peer->burst) { /* * don't accept updates to a true multicast reception * interface while a BCLNT peer is running it's * unicast protocol */ return; } if (peer->dstadr != NULL) { peer->dstadr->peercnt--; ISC_LIST_UNLINK_TYPE(peer->dstadr->peers, peer, ilink, struct peer); } DPRINTF(4, ("set_peerdstadr(%s): change interface from %s to %s\n", stoa(&peer->srcadr), (peer->dstadr != NULL) ? stoa(&peer->dstadr->sin) : "<null>", (interface != NULL) ? stoa(&interface->sin) : "<null>")); peer->dstadr = interface; if (peer->dstadr != NULL) { ISC_LIST_APPEND(peer->dstadr->peers, peer, ilink); peer->dstadr->peercnt++; } }
/* * record_raw_stats - write raw timestamps to file * * file format * day (MJD) * time (s past midnight) * peer ip address * IP address * t1 t2 t3 t4 timestamps */ void record_raw_stats( sockaddr_u *srcadr, sockaddr_u *dstadr, l_fp *t1, /* originate timestamp */ l_fp *t2, /* receive timestamp */ l_fp *t3, /* transmit timestamp */ l_fp *t4 /* destination timestamp */ ) { l_fp now; u_long day; if (!stats_control) return; get_systime(&now); filegen_setup(&rawstats, now.l_ui); day = now.l_ui / 86400 + MJD_1900; now.l_ui %= 86400; if (rawstats.fp != NULL) { fprintf(rawstats.fp, "%lu %s %s %s %s %s %s %s\n", day, ulfptoa(&now, 3), stoa(srcadr), dstadr ? stoa(dstadr) : "-", ulfptoa(t1, 9), ulfptoa(t2, 9), ulfptoa(t3, 9), ulfptoa(t4, 9)); fflush(rawstats.fp); } }
/* * doconfigure - attempt to resolve names and configure the server */ static void doconfigure( int dores ) { register struct conf_entry *ce; #ifdef DEBUG if (debug > 1) msyslog(LOG_INFO, "Running doconfigure %s DNS", dores ? "with" : "without" ); #endif #if defined(HAVE_RES_INIT) || defined(HAVE___RES_INIT) if (dores) /* Reload /etc/resolv.conf - bug 1226 */ res_init(); #endif ce = confentries; while (ce != NULL) { #ifdef DEBUG if (debug > 1) msyslog(LOG_INFO, "doconfigure: <%s> has peeraddr %s", ce->ce_name, stoa(&ce->peer_store)); #endif if (dores && SOCK_UNSPEC(&ce->peer_store)) { if (!findhostaddr(ce)) { #ifndef IGNORE_DNS_ERRORS msyslog(LOG_ERR, "couldn't resolve `%s', giving up on it", ce->ce_name); ce = removeentry(ce); continue; #endif } else if (!SOCK_UNSPEC(&ce->peer_store)) msyslog(LOG_INFO, "DNS %s -> %s", ce->ce_name, stoa(&ce->peer_store)); } if (!SOCK_UNSPEC(&ce->peer_store)) { if (request(&ce->ce_config)) { ce = removeentry(ce); continue; } /* * Failed case. Should bump counter and give * up. */ #ifdef DEBUG if (debug > 1) { msyslog(LOG_INFO, "doconfigure: request() FAILED, maybe next time."); } #endif } ce = ce->ce_next; } }
/* * free_peer - internal routine to free memory referred to by a struct * peer and return it to the peer free list. If unlink is * nonzero, unlink from the various lists. */ static void free_peer( struct peer * p, int unlink_peer ) { struct peer * unlinked; int hash; if (unlink_peer) { hash = NTP_HASH_ADDR(&p->srcadr); peer_hash_count[hash]--; UNLINK_SLIST(unlinked, peer_hash[hash], p, adr_link, struct peer); if (NULL == unlinked) { peer_hash_count[hash]++; msyslog(LOG_ERR, "peer %s not in address table!", stoa(&p->srcadr)); } /* * Remove him from the association hash as well. */ hash = p->associd & NTP_HASH_MASK; assoc_hash_count[hash]--; UNLINK_SLIST(unlinked, assoc_hash[hash], p, aid_link, struct peer); if (NULL == unlinked) { assoc_hash_count[hash]++; msyslog(LOG_ERR, "peer %s not in association ID table!", stoa(&p->srcadr)); } /* Remove him from the overall list. */ UNLINK_SLIST(unlinked, peer_list, p, p_link, struct peer); if (NULL == unlinked) msyslog(LOG_ERR, "%s not in peer list!", stoa(&p->srcadr)); } if (p->hostname != NULL) free(p->hostname); if (p->ident != NULL) free(p->ident); if (p->addrs != NULL) free(p->addrs); /* from copy_addrinfo_list() */ /* Add his corporeal form to peer free list */ ZERO(*p); LINK_SLIST(peer_free, p, p_link); peer_free_count++; }
/* * restrict_source - maintains dynamic "restrict source ..." entries as * peers come and go. */ void restrict_source( sockaddr_u * addr, int farewell, /* 0 to add, 1 to remove */ u_long expire /* 0 is infinite, valid until */ ) { sockaddr_u onesmask; restrict_u * res; int found_specific; if (!restrict_source_enabled || SOCK_UNSPEC(addr) || IS_MCAST(addr) || ISREFCLOCKADR(addr)) return; REQUIRE(AF_INET == AF(addr) || AF_INET6 == AF(addr)); SET_HOSTMASK(&onesmask, AF(addr)); if (farewell) { hack_restrict(RESTRICT_REMOVE, addr, &onesmask, 0, 0, 0); DPRINTF(1, ("restrict_source: %s removed", stoa(addr))); return; } /* * If there is a specific entry for this address, hands * off, as it is condidered more specific than "restrict * server ...". * However, if the specific entry found is a fleeting one * added by pool_xmit() before soliciting, replace it * immediately regardless of the expire value to make way * for the more persistent entry. */ if (IS_IPV4(addr)) { res = match_restrict4_addr(SRCADR(addr), SRCPORT(addr)); INSIST(res != NULL); found_specific = (SRCADR(&onesmask) == res->u.v4.mask); } else { res = match_restrict6_addr(&SOCK_ADDR6(addr), SRCPORT(addr)); INSIST(res != NULL); found_specific = ADDR6_EQ(&res->u.v6.mask, &SOCK_ADDR6(&onesmask)); } if (!expire && found_specific && res->expire) { found_specific = 0; free_res(res, IS_IPV6(addr)); } if (found_specific) return; hack_restrict(RESTRICT_FLAGS, addr, &onesmask, restrict_source_mflags, restrict_source_flags, expire); DPRINTF(1, ("restrict_source: %s host restriction added\n", stoa(addr))); }
/* * setup peer dstadr field keeping it in sync with the interface * structures */ void set_peerdstadr( struct peer * p, endpt * dstadr ) { struct peer * unlinked; if (p->dstadr == dstadr) return; /* * Don't accept updates to a separate multicast receive-only * endpt while a BCLNT peer is running its unicast protocol. */ if (dstadr != NULL && (FLAG_BC_VOL & p->flags) && (INT_MCASTIF & dstadr->flags) && MODE_CLIENT == p->hmode) { return; } if (p->dstadr != NULL) { p->dstadr->peercnt--; UNLINK_SLIST(unlinked, p->dstadr->peers, p, ilink, struct peer); msyslog(LOG_INFO, "%s local addr %s -> %s", stoa(&p->srcadr), latoa(p->dstadr), latoa(dstadr)); }
/* Receive raw data */ int recvdata( SOCKET rsock, sockaddr_u *sender, char *rdata, int rdata_length ) { GETSOCKNAME_SOCKLEN_TYPE slen; int recvc; #ifdef DEBUG printf("sntp recvdata: Trying to receive data from...\n"); #endif slen = sizeof(*sender); recvc = recvfrom(rsock, rdata, rdata_length, 0, &sender->sa, &slen); #ifdef DEBUG if (recvc > 0) { printf("Received %d bytes from %s:\n", recvc, stoa(sender)); pkt_output((struct pkt *) rdata, recvc, stdout); } else { int saved_errno = errno; printf("recvfrom error %d (%s)\n", errno, strerror(errno)); errno = saved_errno; } #endif return recvc; }
/* * record_peer_stats - write peer statistics to file * * file format: * day (MJD) * time (s past UTC midnight) * IP address * status word (hex) * offset * delay * dispersion * jitter */ void record_peer_stats( sockaddr_u *addr, int status, double offset, /* offset */ double delay, /* delay */ double dispersion, /* dispersion */ double jitter /* jitter */ ) { l_fp now; u_long day; if (!stats_control) return; get_systime(&now); filegen_setup(&peerstats, now.l_ui); day = now.l_ui / 86400 + MJD_1900; now.l_ui %= 86400; if (peerstats.fp != NULL) { fprintf(peerstats.fp, "%lu %s %s %x %.9f %.9f %.9f %.9f\n", day, ulfptoa(&now, 3), stoa(addr), status, offset, delay, dispersion, jitter); fflush(peerstats.fp); } }
/* * record_crypto_stats - write crypto statistics to file * * file format: * day (mjd) * time (s past midnight) * peer ip address * text message */ void record_crypto_stats( sockaddr_u *addr, const char *text /* text message */ ) { l_fp now; u_long day; if (!stats_control) return; get_systime(&now); filegen_setup(&cryptostats, now.l_ui); day = now.l_ui / 86400 + MJD_1900; now.l_ui %= 86400; if (cryptostats.fp != NULL) { if (addr == NULL) fprintf(cryptostats.fp, "%lu %s 0.0.0.0 %s\n", day, ulfptoa(&now, 3), text); else fprintf(cryptostats.fp, "%lu %s %s %s\n", day, ulfptoa(&now, 3), stoa(addr), text); fflush(cryptostats.fp); } }
/* Convert a sockaddr_u to a string containing the address in * style of inet_ntoa * Why not switch callers to use stoa from libntp? No free() needed * in that case. */ char * ss_to_str( sockaddr_u *saddr ) { return estrdup(stoa(saddr)); }
/* * timeout_queries() -- give up on unrequited NTP queries */ void timeout_queries(void) { struct timeval start_cb; u_int idx; sent_pkt * head; sent_pkt * spkt; sent_pkt * spkt_next; long age; int didsomething = 0; TRACE(3, ("timeout_queries: called to check %u items\n", (unsigned)COUNTOF(fam_listheads))); gettimeofday_cached(base, &start_cb); for (idx = 0; idx < COUNTOF(fam_listheads); idx++) { head = fam_listheads[idx]; for (spkt = head; spkt != NULL; spkt = spkt_next) { char xcst; didsomething = 1; switch (spkt->dctx->flags & CTX_xCST) { case CTX_BCST: xcst = 'B'; break; case CTX_UCST: xcst = 'U'; break; default: INSIST(!"spkt->dctx->flags neither UCST nor BCST"); break; } spkt_next = spkt->link; if (0 == spkt->stime || spkt->done) continue; age = start_cb.tv_sec - spkt->stime; TRACE(3, ("%s %s %cCST age %ld\n", stoa(&spkt->addr), spkt->dctx->name, xcst, age)); if (age > response_timeout) timeout_query(spkt); } } // Do we care about didsomething? TRACE(3, ("timeout_queries: didsomething is %d, age is %ld\n", didsomething, (long) (start_cb.tv_sec - start_tv.tv_sec))); if (start_cb.tv_sec - start_tv.tv_sec > response_timeout) { TRACE(3, ("timeout_queries: bail!\n")); event_base_loopexit(base, NULL); shutting_down = TRUE; } }
/* Define a function to create the server associations */ void create_server_associations() { int i; for (i = 0;i < simulation.num_of_servers;++i) { printf("%s\n", stoa(simulation.servers[i].addr)); if (peer_config(simulation.servers[i].addr, ANY_INTERFACE_CHOOSE(simulation.servers[i].addr), MODE_CLIENT, NTP_VERSION, NTP_MINDPOLL, NTP_MAXDPOLL, 0, /* peerflags */ 0, /* ttl */ 0, /* peerkey */ (u_char *)"*" /* peerkeystr */) == 0) { fprintf(stderr, "ERROR!! Could not create association for: %s", stoa(simulation.servers[i].addr)); } } }
/* Receive raw data */ int recvdata ( SOCKET rsock, sockaddr_u *sender, char *rdata, int rdata_length ) { struct timeval timeout_tv = { 0 }; fd_set recv_fd; GETSOCKNAME_SOCKLEN_TYPE slen; int recvc; #ifdef DEBUG printf("sntp recvdata: Trying to receive data from...\n"); #endif // Is the socket ready? FD_ZERO(&recv_fd); FD_SET(rsock, &recv_fd); if(ENABLED_OPT(TIMEOUT)) { timeout_tv.tv_sec = (int) OPT_ARG(TIMEOUT); } else { timeout_tv.tv_sec = 15; } switch(select(rsock + 1, &recv_fd, 0, 0, &timeout_tv)) { case 0: if(ENABLED_OPT(NORMALVERBOSE)) printf("sntp recvdata: select() reached timeout (%u sec), aborting.\n", (unsigned)timeout_tv.tv_sec); return SERVER_UNUSEABLE; case -1: return SERVER_UNUSEABLE; default: slen = sizeof(sender->sas); recvc = recvfrom(rsock, rdata, rdata_length, 0, &sender->sa, &slen); #ifdef DEBUG if (recvc > 0) { printf("Received %d bytes from %s:\n", recvc, stoa(sender)); pkt_output((struct pkt *) rdata, recvc, stdout); } else { saved_errno = errno; printf("recvfrom error %d (%s)\n", errno, strerror(errno)); errno = saved_errno; } #endif } return recvc; }
/* * refclock_transmit - simulate the transmit procedure * * This routine implements the NTP transmit procedure for a reference * clock. This provides a mechanism to call the driver at the NTP poll * interval, as well as provides a reachability mechanism to detect a * broken radio or other madness. */ void refclock_transmit( struct peer *peer /* peer structure pointer */ ) { u_char clktype; int unit; clktype = peer->refclktype; unit = peer->refclkunit; peer->sent++; get_systime(&peer->xmt); /* * This is a ripoff of the peer transmit routine, but * specialized for reference clocks. We do a little less * protocol here and call the driver-specific transmit routine. */ if (peer->burst == 0) { u_char oreach; #ifdef DEBUG if (debug) printf("refclock_transmit: at %ld %s\n", current_time, stoa(&(peer->srcadr))); #endif /* * Update reachability and poll variables like the * network code. */ oreach = peer->reach; peer->reach <<= 1; peer->outdate = current_time; if (!peer->reach) { if (oreach) { report_event(EVNT_UNREACH, peer); peer->timereachable = current_time; } } else { if (!(oreach & 0x07)) { clock_filter(peer, 0., 0., MAXDISPERSE); clock_select(); } if (peer->flags & FLAG_BURST) peer->burst = NSTAGE; } } else { peer->burst--; } if (refclock_conf[clktype]->clock_poll != noentry) (refclock_conf[clktype]->clock_poll)(unit, peer); poll_update(peer, peer->hpoll); }
/* * nntohost - convert network number to host name. This routine enforces * the showhostnames setting. */ char * nntohost( sockaddr_u *netnum ) { if (!showhostnames) return stoa(netnum); if (ISREFCLOCKADR(netnum)) return refnumtoa(netnum); return socktohost(netnum); }
/* * nntohost - convert network number to host name. This routine enforces * the showhostnames setting. */ const char * nntohost( sockaddr_u *netnum ) { if (!showhostnames || SOCK_UNSPEC(netnum)) return stoa(netnum); else if (ISREFCLOCKADR(netnum)) return refnumtoa(netnum); else return socktohost(netnum); }
/* Convert a sockaddr_u to a string containing the address in * style of inet_ntoa * Why not switch callers to use stoa from libntp? No free() needed * in that case. */ char * ss_to_str ( sockaddr_u *saddr ) { char * buf; buf = emalloc(INET6_ADDRSTRLEN); strncpy(buf, stoa(saddr), INET6_ADDRSTRLEN); return buf; }
/* * record_raw_stats - write raw timestamps to file * * file format * day (MJD) * time (s past midnight) * peer ip address * IP address * t1 t2 t3 t4 timestamps */ void record_raw_stats( sockaddr_u *srcadr, sockaddr_u *dstadr, l_fp *t1, /* originate timestamp */ l_fp *t2, /* receive timestamp */ l_fp *t3, /* transmit timestamp */ l_fp *t4, /* destination timestamp */ int leap, int version, int mode, int stratum, int ppoll, int precision, double root_delay, /* seconds */ double root_dispersion,/* seconds */ u_int32 refid ) { l_fp now; u_long day; if (!stats_control) return; get_systime(&now); filegen_setup(&rawstats, now.l_ui); day = now.l_ui / 86400 + MJD_1900; now.l_ui %= 86400; if (rawstats.fp != NULL) { fprintf(rawstats.fp, "%lu %s %s %s %s %s %s %s %d %d %d %d %d %d %.6f %.6f %s\n", day, ulfptoa(&now, 3), stoa(srcadr), dstadr ? stoa(dstadr) : "-", ulfptoa(t1, 9), ulfptoa(t2, 9), ulfptoa(t3, 9), ulfptoa(t4, 9), leap, version, mode, stratum, ppoll, precision, root_delay, root_dispersion, refid_str(refid, stratum)); fflush(rawstats.fp); } }
/* * refclock_receive - simulate the receive and packet procedures * * This routine simulates the NTP receive and packet procedures for a * reference clock. This provides a mechanism in which the ordinary NTP * filter, selection and combining algorithms can be used to suppress * misbehaving radios and to mitigate between them when more than one is * available for backup. */ void refclock_receive( struct peer *peer /* peer structure pointer */ ) { struct refclockproc *pp; #ifdef DEBUG if (debug) printf("refclock_receive: at %lu %s\n", current_time, stoa(&peer->srcadr)); #endif /* * Do a little sanity dance and update the peer structure. Groom * the median filter samples and give the data to the clock * filter. */ pp = peer->procptr; peer->leap = pp->leap; if (peer->leap == LEAP_NOTINSYNC) return; peer->received++; peer->timereceived = current_time; if (!peer->reach) { report_event(EVNT_REACH, peer); peer->timereachable = current_time; } peer->reach |= 1; peer->reftime = pp->lastref; peer->org = pp->lastrec; peer->rootdispersion = pp->disp; get_systime(&peer->rec); if (!refclock_sample(pp)) return; clock_filter(peer, pp->offset, 0., pp->jitter); record_peer_stats(&peer->srcadr, ctlpeerstatus(peer), peer->offset, peer->delay, clock_phi * (current_time - peer->epoch), peer->jitter); if (cal_enable && last_offset < MINDISPERSE) { #ifdef KERNEL_PLL if (peer != sys_peer || pll_status & STA_PPSTIME) #else if (peer != sys_peer) #endif /* KERNEL_PLL */ pp->fudgetime1 -= pp->offset * FUDGEFAC; else pp->fudgetime1 -= pp->fudgetime1 * FUDGEFAC; } }
char * socktohost( struct sockaddr_storage* sock ) { register char *buffer; LIB_GETBUF(buffer); if (getnameinfo((struct sockaddr *)sock, SOCKLEN(sock), buffer, LIB_BUFLENGTH /* NI_MAXHOST*/, NULL, 0, 0)) return stoa(sock); return buffer; }
/* * refclock_receive - simulate the receive and packet procedures * * This routine simulates the NTP receive and packet procedures for a * reference clock. This provides a mechanism in which the ordinary NTP * filter, selection and combining algorithms can be used to suppress * misbehaving radios and to mitigate between them when more than one is * available for backup. */ void refclock_receive( struct peer *peer /* peer structure pointer */ ) { struct refclockproc *pp; #ifdef DEBUG if (debug) printf("refclock_receive: at %lu %s\n", current_time, stoa(&peer->srcadr)); #endif /* * Do a little sanity dance and update the peer structure. Groom * the median filter samples and give the data to the clock * filter. */ pp = peer->procptr; peer->leap = pp->leap; if (peer->leap == LEAP_NOTINSYNC) return; peer->received++; peer->timereceived = current_time; if (!peer->reach) { report_event(PEVNT_REACH, peer, NULL); peer->timereachable = current_time; } peer->reach |= 1; peer->reftime = pp->lastref; peer->aorg = pp->lastrec; peer->rootdisp = pp->disp; get_systime(&peer->dst); if (!refclock_sample(pp)) return; clock_filter(peer, pp->offset, 0., pp->jitter); if (cal_enable && fabs(last_offset) < sys_mindisp && sys_peer != NULL) { if (sys_peer->refclktype == REFCLK_ATOM_PPS && peer->refclktype != REFCLK_ATOM_PPS) pp->fudgetime1 -= pp->offset * FUDGEFAC; } }
/* ** xmt_timer_cb */ void xmt_timer_cb( evutil_socket_t fd, short what, void * ctx ) { struct timeval start_cb; struct timeval delay; xmt_ctx * x; UNUSED_ARG(fd); UNUSED_ARG(ctx); DEBUG_INSIST(EV_TIMEOUT == what); if (NULL == xmt_q || shutting_down) return; gettimeofday_cached(base, &start_cb); if (xmt_q->sched <= start_cb.tv_sec) { UNLINK_HEAD_SLIST(x, xmt_q, link); TRACE(2, ("xmt_timer_cb: at .%6.6u -> %s\n", (u_int)start_cb.tv_usec, stoa(&x->spkt->addr))); xmt(x); free(x); if (NULL == xmt_q) return; } if (xmt_q->sched <= start_cb.tv_sec) { event_add(ev_xmt_timer, &gap); TRACE(2, ("xmt_timer_cb: at .%6.6u gap %6.6u\n", (u_int)start_cb.tv_usec, (u_int)gap.tv_usec)); } else { delay.tv_sec = xmt_q->sched - start_cb.tv_sec; delay.tv_usec = 0; event_add(ev_xmt_timer, &delay); TRACE(2, ("xmt_timer_cb: at .%6.6u next %ld seconds\n", (u_int)start_cb.tv_usec, (long)delay.tv_sec)); } }
/* ** xmt() */ void xmt( xmt_ctx * xctx ) { SOCKET sock = xctx->sock; struct dns_ctx *dctx = xctx->spkt->dctx; sent_pkt * spkt = xctx->spkt; sockaddr_u * dst = &spkt->addr; struct timeval tv_xmt; struct pkt x_pkt; size_t pkt_len; int sent; if (0 != gettimeofday(&tv_xmt, NULL)) { msyslog(LOG_ERR, "xmt: gettimeofday() failed: %m"); exit(1); } tv_xmt.tv_sec += JAN_1970; pkt_len = generate_pkt(&x_pkt, &tv_xmt, dctx->key_id, dctx->key); sent = sendpkt(sock, dst, &x_pkt, pkt_len); if (sent) { /* Save the packet we sent... */ memcpy(&spkt->x_pkt, &x_pkt, min(sizeof(spkt->x_pkt), pkt_len)); spkt->stime = tv_xmt.tv_sec - JAN_1970; TRACE(2, ("xmt: %lx.%6.6u %s %s\n", (u_long)tv_xmt.tv_sec, (u_int)tv_xmt.tv_usec, dctx->name, stoa(dst))); } else { dec_pending_ntp(dctx->name, dst); } return; }
/* * record_clock_stats - write clock statistics to file * * file format: * day (MJD) * time (s past midnight) * IP address * text message */ void record_clock_stats( sockaddr_u *addr, const char *text /* timecode string */ ) { l_fp now; u_long day; if (!stats_control) return; get_systime(&now); filegen_setup(&clockstats, now.l_ui); day = now.l_ui / 86400 + MJD_1900; now.l_ui %= 86400; if (clockstats.fp != NULL) { fprintf(clockstats.fp, "%lu %s %s %s\n", day, ulfptoa(&now, 3), stoa(addr), text); fflush(clockstats.fp); } }
/* * * hostnameaddr() * * Formats the hostname and resulting numeric IP address into a string, * avoiding duplication if the "hostname" was in fact a numeric address. * */ const char * hostnameaddr( const char * hostname, const sockaddr_u * addr ) { const char * addrtxt; char * result; int cnt; addrtxt = stoa(addr); LIB_GETBUF(result); if (strcmp(hostname, addrtxt)) cnt = snprintf(result, LIB_BUFLENGTH, "%s %s", hostname, addrtxt); else cnt = snprintf(result, LIB_BUFLENGTH, "%s", addrtxt); if (cnt >= LIB_BUFLENGTH) snprintf(result, LIB_BUFLENGTH, "hostnameaddr ERROR have %d (%d needed)", LIB_BUFLENGTH, cnt + 1); return result; }
/* * unpeer - remove peer structure from hash table and free structure */ void unpeer( struct peer *peer_to_remove ) { int hash; #ifdef OPENSSL char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */ if (peer_to_remove->flags & FLAG_SKEY) { sprintf(statstr, "unpeer %d flash %x reach %03o flags %04x", peer_to_remove->associd, peer_to_remove->flash, peer_to_remove->reach, peer_to_remove->flags); record_crypto_stats(&peer_to_remove->srcadr, statstr); #ifdef DEBUG if (debug) printf("peer: %s\n", statstr); #endif } #endif /* OPENSSL */ #ifdef DEBUG if (debug) printf("demobilize %u %d %d\n", peer_to_remove->associd, peer_associations, peer_preempt); #endif set_peerdstadr(peer_to_remove, NULL); /* XXXMEMLEAK? peer_clear->crypto allocation */ hash = NTP_HASH_ADDR(&peer_to_remove->srcadr); peer_hash_count[hash]--; peer_demobilizations++; peer_associations--; if (peer_to_remove->flags & FLAG_PREEMPT) peer_preempt--; #ifdef REFCLOCK /* * If this peer is actually a clock, shut it down first */ if (peer_to_remove->flags & FLAG_REFCLOCK) refclock_unpeer(peer_to_remove); #endif peer_to_remove->action = 0; /* disable timeout actions */ if (peer_hash[hash] == peer_to_remove) peer_hash[hash] = peer_to_remove->next; else { register struct peer *peer; peer = peer_hash[hash]; while (peer != 0 && peer->next != peer_to_remove) peer = peer->next; if (peer == 0) { peer_hash_count[hash]++; msyslog(LOG_ERR, "peer struct for %s not in table!", stoa(&peer->srcadr)); } else { peer->next = peer_to_remove->next; } } /* * Remove him from the association hash as well. */ hash = peer_to_remove->associd & NTP_HASH_MASK; assoc_hash_count[hash]--; if (assoc_hash[hash] == peer_to_remove) assoc_hash[hash] = peer_to_remove->ass_next; else { register struct peer *peer; peer = assoc_hash[hash]; while (peer != 0 && peer->ass_next != peer_to_remove) peer = peer->ass_next; if (peer == 0) { assoc_hash_count[hash]++; msyslog(LOG_ERR, "peer struct for %s not in association table!", stoa(&peer->srcadr)); } else { peer->ass_next = peer_to_remove->ass_next; } } peer_to_remove->next = peer_free; peer_free = peer_to_remove; peer_free_count++; }
/* * refclock_newpeer - initialize and start a reference clock * * This routine allocates and initializes the interface structure which * supports a reference clock in the form of an ordinary NTP peer. A * driver-specific support routine completes the initialization, if * used. Default peer variables which identify the clock and establish * its reference ID and stratum are set here. It returns one if success * and zero if the clock address is invalid or already running, * insufficient resources are available or the driver declares a bum * rap. */ int refclock_newpeer( struct peer *peer /* peer structure pointer */ ) { struct refclockproc *pp; u_char clktype; int unit; /* * Check for valid clock address. If already running, shut it * down first. */ if (!ISREFCLOCKADR(&peer->srcadr)) { msyslog(LOG_ERR, "refclock_newpeer: clock address %s invalid", stoa(&peer->srcadr)); return (0); } clktype = (u_char)REFCLOCKTYPE(&peer->srcadr); unit = REFCLOCKUNIT(&peer->srcadr); if (clktype >= num_refclock_conf || refclock_conf[clktype]->clock_start == noentry) { msyslog(LOG_ERR, "refclock_newpeer: clock type %d invalid\n", clktype); return (0); } /* * Allocate and initialize interface structure */ pp = emalloc(sizeof(*pp)); memset(pp, 0, sizeof(*pp)); peer->procptr = pp; /* * Initialize structures */ peer->refclktype = clktype; peer->refclkunit = (u_char)unit; peer->flags |= FLAG_REFCLOCK; peer->leap = LEAP_NOTINSYNC; peer->stratum = STRATUM_REFCLOCK; peer->ppoll = peer->maxpoll; pp->type = clktype; pp->timestarted = current_time; /* * Set peer.pmode based on the hmode. For appearances only. */ switch (peer->hmode) { case MODE_ACTIVE: peer->pmode = MODE_PASSIVE; break; default: peer->pmode = MODE_SERVER; break; } /* * Do driver dependent initialization. The above defaults * can be wiggled, then finish up for consistency. */ if (!((refclock_conf[clktype]->clock_start)(unit, peer))) { refclock_unpeer(peer); return (0); } peer->refid = pp->refid; return (1); }
/* Receive data from broadcast. Couldn't finish that. Need to do some digging * here, especially for protocol independence and IPv6 multicast */ int recv_bcst_data ( SOCKET rsock, char *rdata, int rdata_len, sockaddr_u *sas, sockaddr_u *ras ) { char *buf; int btrue = 1; int recv_bytes = 0; int rdy_socks; GETSOCKNAME_SOCKLEN_TYPE ss_len; struct timeval timeout_tv; fd_set bcst_fd; #ifdef MCAST struct ip_mreq mdevadr; TYPEOF_IP_MULTICAST_LOOP mtrue = 1; #endif #ifdef INCLUDE_IPV6_MULTICAST_SUPPORT struct ipv6_mreq mdevadr6; #endif setsockopt(rsock, SOL_SOCKET, SO_REUSEADDR, &btrue, sizeof(btrue)); if (IS_IPV4(sas)) { if (bind(rsock, &sas->sa, SOCKLEN(sas)) < 0) { if (ENABLED_OPT(NORMALVERBOSE)) printf("sntp recv_bcst_data: Couldn't bind() address %s:%d.\n", stoa(sas), SRCPORT(sas)); } #ifdef MCAST if (setsockopt(rsock, IPPROTO_IP, IP_MULTICAST_LOOP, &mtrue, sizeof(mtrue)) < 0) { /* some error message regarding setting up multicast loop */ return BROADCAST_FAILED; } mdevadr.imr_multiaddr.s_addr = NSRCADR(sas); mdevadr.imr_interface.s_addr = htonl(INADDR_ANY); if (mdevadr.imr_multiaddr.s_addr == ~(unsigned)0) { if (ENABLED_OPT(NORMALVERBOSE)) { printf("sntp recv_bcst_data: %s:%d is not a broad-/multicast address, aborting...\n", stoa(sas), SRCPORT(sas)); } return BROADCAST_FAILED; } if (setsockopt(rsock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mdevadr, sizeof(mdevadr)) < 0) { if (ENABLED_OPT(NORMALVERBOSE)) { buf = ss_to_str(sas); printf("sntp recv_bcst_data: Couldn't add IP membership for %s\n", buf); free(buf); } } #endif /* MCAST */ } #ifdef ISC_PLATFORM_HAVEIPV6 else if (IS_IPV6(sas)) { if (bind(rsock, &sas->sa, SOCKLEN(sas)) < 0) { if (ENABLED_OPT(NORMALVERBOSE)) printf("sntp recv_bcst_data: Couldn't bind() address.\n"); } #ifdef INCLUDE_IPV6_MULTICAST_SUPPORT if (setsockopt(rsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &btrue, sizeof (btrue)) < 0) { /* some error message regarding setting up multicast loop */ return BROADCAST_FAILED; } memset(&mdevadr6, 0, sizeof(mdevadr6)); mdevadr6.ipv6mr_multiaddr = SOCK_ADDR6(sas); if (!IN6_IS_ADDR_MULTICAST(&mdevadr6.ipv6mr_multiaddr)) { if (ENABLED_OPT(NORMALVERBOSE)) { buf = ss_to_str(sas); printf("sntp recv_bcst_data: %s is not a broad-/multicast address, aborting...\n", buf); free(buf); } return BROADCAST_FAILED; } if (setsockopt(rsock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mdevadr6, sizeof(mdevadr6)) < 0) { if (ENABLED_OPT(NORMALVERBOSE)) { buf = ss_to_str(sas); printf("sntp recv_bcst_data: Couldn't join group for %s\n", buf); free(buf); } } #endif /* INCLUDE_IPV6_MULTICAST_SUPPORT */ } #endif /* ISC_PLATFORM_HAVEIPV6 */ FD_ZERO(&bcst_fd); FD_SET(rsock, &bcst_fd); if (ENABLED_OPT(TIMEOUT)) timeout_tv.tv_sec = (int) atol(OPT_ARG(TIMEOUT)); else timeout_tv.tv_sec = 68; /* ntpd broadcasts every 64s */ timeout_tv.tv_usec = 0; rdy_socks = select(rsock + 1, &bcst_fd, 0, 0, &timeout_tv); switch (rdy_socks) { case -1: if (ENABLED_OPT(NORMALVERBOSE)) perror("sntp recv_bcst_data: select()"); return BROADCAST_FAILED; break; case 0: if (ENABLED_OPT(NORMALVERBOSE)) printf("sntp recv_bcst_data: select() reached timeout (%u sec), aborting.\n", (unsigned)timeout_tv.tv_sec); return BROADCAST_FAILED; break; default: ss_len = sizeof(*ras); recv_bytes = recvfrom(rsock, rdata, rdata_len, 0, &ras->sa, &ss_len); break; } if (recv_bytes == -1) { if (ENABLED_OPT(NORMALVERBOSE)) perror("sntp recv_bcst_data: recvfrom:"); recv_bytes = BROADCAST_FAILED; } #ifdef MCAST if (IS_IPV4(sas)) setsockopt(rsock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &btrue, sizeof(btrue)); #endif #ifdef INCLUDE_IPV6_MULTICAST_SUPPORT if (IS_IPV6(sas)) setsockopt(rsock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &btrue, sizeof(btrue)); #endif return recv_bytes; }
const char * socktohost( const sockaddr_u *sock ) { const char svc[] = "ntp"; char * pbuf; char * pliar; int gni_flags; struct addrinfo hints; struct addrinfo * alist; struct addrinfo * ai; sockaddr_u addr; size_t octets; int a_info; /* reverse the address to purported DNS name */ LIB_GETBUF(pbuf); gni_flags = NI_DGRAM | NI_NAMEREQD; if (getnameinfo(&sock->sa, SOCKLEN(sock), pbuf, LIB_BUFLENGTH, NULL, 0, gni_flags)) return stoa(sock); /* use address */ TRACE(1, ("%s reversed to %s\n", stoa(sock), pbuf)); /* * Resolve the reversed name and make sure the reversed address * is among the results. */ ZERO(hints); hints.ai_family = AF(sock); hints.ai_protocol = IPPROTO_UDP; hints.ai_socktype = SOCK_DGRAM; hints.ai_flags = 0; alist = NULL; a_info = getaddrinfo(pbuf, svc, &hints, &alist); if (a_info == EAI_NONAME #ifdef EAI_NODATA || a_info == EAI_NODATA #endif ) { hints.ai_flags = AI_CANONNAME; #ifdef AI_ADDRCONFIG hints.ai_flags |= AI_ADDRCONFIG; #endif a_info = getaddrinfo(pbuf, svc, &hints, &alist); } #ifdef AI_ADDRCONFIG /* Some older implementations don't like AI_ADDRCONFIG. */ if (a_info == EAI_BADFLAGS) { hints.ai_flags &= ~AI_ADDRCONFIG; a_info = getaddrinfo(pbuf, svc, &hints, &alist); } #endif if (a_info) goto forward_fail; NTP_INSIST(alist != NULL); for (ai = alist; ai != NULL; ai = ai->ai_next) { /* * Make a convenience sockaddr_u copy from ai->ai_addr * because casting from sockaddr * to sockaddr_u * is * risking alignment problems on platforms where * sockaddr_u has stricter alignment than sockaddr, * such as sparc. */ ZERO_SOCK(&addr); octets = min(sizeof(addr), ai->ai_addrlen); memcpy(&addr, ai->ai_addr, octets); if (SOCK_EQ(sock, &addr)) break; } freeaddrinfo(alist); if (ai != NULL) return pbuf; /* forward check passed */ forward_fail: TRACE(1, ("%s forward check lookup fail: %s\n", pbuf, gai_strerror(a_info))); LIB_GETBUF(pliar); snprintf(pliar, LIB_BUFLENGTH, "%s (%s)", stoa(sock), pbuf); return pliar; }
/* Define a function to simulate a server. * This function processes the sent packet according to the server script, * creates a reply packet and pushes the reply packet onto the event queue */ int simulate_server( sockaddr_u *serv_addr, /* Address of the server */ struct interface *inter, /* Interface on which the reply should be inserted */ struct pkt *rpkt /* Packet sent to the server that needs to be processed. */ ) { struct pkt xpkt; /* Packet to be transmitted back to the client */ struct recvbuf rbuf; /* Buffer for the received packet */ Event *e; /* Packet receive event */ server_info *server; /* Pointer to the server being simulated */ script_info *curr_script; /* Current script being processed */ int i; double d1, d2, d3; /* Delays while the packet is enroute */ double t1, t2, t3, t4; /* The four timestamps in the packet */ memset(&xpkt, 0, sizeof(xpkt)); memset(&rbuf, 0, sizeof(rbuf)); /* Search for the server with the desired address */ server = NULL; for (i = 0; i < simulation.num_of_servers; ++i) { fprintf(stderr,"Checking address: %s\n", stoa(simulation.servers[i].addr)); if (memcmp(simulation.servers[i].addr, serv_addr, sizeof(*serv_addr)) == 0) { server = &simulation.servers[i]; break; } } fprintf(stderr, "Received packet for: %s\n", stoa(serv_addr)); if (server == NULL) abortsim("Server with specified address not found!!!"); /* Get the current script for the server */ curr_script = server->curr_script; /* Create a server reply packet. * Masquerade the reply as a stratum-1 server with a GPS clock */ xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING, NTP_VERSION, MODE_SERVER); xpkt.stratum = STRATUM_TO_PKT(((u_char)1)); memcpy(&xpkt.refid, "GPS", 4); xpkt.ppoll = rpkt->ppoll; xpkt.precision = rpkt->precision; xpkt.rootdelay = 0; xpkt.rootdisp = 0; /* TIMESTAMP CALCULATIONS t1 t4 \ / d1 \ / d3 \ / t2 ----------------- t3 d2 */ /* Compute the delays */ d1 = poisson(curr_script->prop_delay, curr_script->jitter); d2 = poisson(curr_script->proc_delay, 0); d3 = poisson(curr_script->prop_delay, curr_script->jitter); /* Note: In the transmitted packet: * 1. t1 and t4 are times in the client according to the local clock. * 2. t2 and t3 are server times according to the simulated server. * Compute t1, t2, t3 and t4 * Note: This function is called at time t1. */ LFPTOD(&rpkt->xmt, t1); t2 = server->server_time + d1; t3 = server->server_time + d1 + d2; t4 = t1 + d1 + d2 + d3; /* Save the timestamps */ xpkt.org = rpkt->xmt; DTOLFP(t2, &xpkt.rec); DTOLFP(t3, &xpkt.xmt); xpkt.reftime = xpkt.xmt; /* Ok, we are done with the packet. Now initialize the receive buffer for * the packet. */ rbuf.receiver = receive; /* Function to call to process the packet */ rbuf.recv_length = LEN_PKT_NOMAC; rbuf.recv_pkt = xpkt; rbuf.used = 1; memcpy(&rbuf.srcadr, serv_addr, sizeof(rbuf.srcadr)); memcpy(&rbuf.recv_srcadr, serv_addr, sizeof(rbuf.recv_srcadr)); if ((rbuf.dstadr = malloc(sizeof(*rbuf.dstadr))) == NULL) abortsim("malloc failed in simulate_server"); memcpy(rbuf.dstadr, inter, sizeof(*rbuf.dstadr)); /* rbuf.link = NULL; */ /* Create a packet event and insert it onto the event_queue at the * arrival time (t4) of the packet at the client */ e = event(t4, PACKET); e->rcv_buf = rbuf; enqueue(event_queue, e); /* Check if the time of the script has expired. If yes, delete the script. * If not, re-enqueue the script onto the server script queue */ if (curr_script->duration > simulation.sim_time && !empty(server->script)) { printf("Hello\n"); /* * For some reason freeing up the curr_script memory kills the * simulation. Further debugging is needed to determine why. * free_node(curr_script); */ curr_script = dequeue(server->script); } return (0); }