/* * 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; } }
/* * 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))); }
/* * peer_config - configure a new association */ struct peer * peer_config( sockaddr_u * srcadr, const char * hostname, endpt * dstadr, u_char hmode, u_char version, u_char minpoll, u_char maxpoll, u_int flags, u_int32 ttl, keyid_t key, const char * ident /* autokey group */ ) { u_char cast_flags; /* * We do a dirty little jig to figure the cast flags. This is * probably not the best place to do this, at least until the * configure code is rebuilt. Note only one flag can be set. */ switch (hmode) { case MODE_BROADCAST: if (IS_MCAST(srcadr)) cast_flags = MDF_MCAST; else cast_flags = MDF_BCAST; break; case MODE_CLIENT: if (hostname != NULL && SOCK_UNSPEC(srcadr)) cast_flags = MDF_POOL; else if (IS_MCAST(srcadr)) cast_flags = MDF_ACAST; else cast_flags = MDF_UCAST; break; default: cast_flags = MDF_UCAST; } /* * Mobilize the association and initialize its variables. If * emulating ntpdate, force iburst. For pool and manycastclient * strip FLAG_PREEMPT as the prototype associations are not * themselves preemptible, though the resulting associations * are. */ flags |= FLAG_CONFIG; if (mode_ntpdate) flags |= FLAG_IBURST; if ((MDF_ACAST | MDF_POOL) & cast_flags) flags &= ~FLAG_PREEMPT; return newpeer(srcadr, hostname, dstadr, hmode, version, minpoll, maxpoll, flags, cast_flags, ttl, key, ident); }
/* * 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); }
/* * Decode an incoming data buffer and print a line in the peer list */ static int doprintpeers( struct varlist *pvl, int associd, int rstatus, int datalen, const char *data, FILE *fp, int af ) { char *name; char *value = NULL; int i; int c; sockaddr_u srcadr; sockaddr_u dstadr; sockaddr_u refidadr; u_long srcport = 0; char *dstadr_refid = "0.0.0.0"; char *serverlocal; size_t drlen; u_long stratum = 0; long ppoll = 0; long hpoll = 0; u_long reach = 0; l_fp estoffset; l_fp estdelay; l_fp estjitter; l_fp estdisp; l_fp reftime; l_fp rec; l_fp ts; u_char havevar[MAXHAVE]; u_long poll_sec; char type = '?'; char refid_string[10]; char whenbuf[8], pollbuf[8]; char clock_name[LENHOSTNAME]; memset((char *)havevar, 0, sizeof(havevar)); get_systime(&ts); ZERO_SOCK(&srcadr); ZERO_SOCK(&dstadr); /* Initialize by zeroing out estimate variables */ memset((char *)&estoffset, 0, sizeof(l_fp)); memset((char *)&estdelay, 0, sizeof(l_fp)); memset((char *)&estjitter, 0, sizeof(l_fp)); memset((char *)&estdisp, 0, sizeof(l_fp)); while (nextvar(&datalen, &data, &name, &value)) { sockaddr_u dum_store; i = findvar(name, peer_var, 1); if (i == 0) continue; /* don't know this one */ switch (i) { case CP_SRCADR: if (decodenetnum(value, &srcadr)) { havevar[HAVE_SRCADR] = 1; } break; case CP_DSTADR: if (decodenetnum(value, &dum_store)) { type = decodeaddrtype(&dum_store); havevar[HAVE_DSTADR] = 1; dstadr = dum_store; if (pvl == opeervarlist) { dstadr_refid = trunc_left(stoa(&dstadr), 15); } } break; case CP_REFID: if (pvl == peervarlist) { havevar[HAVE_REFID] = 1; if (*value == '\0') { dstadr_refid = ""; } else if (strlen(value) <= 4) { refid_string[0] = '.'; (void) strcpy(&refid_string[1], value); i = strlen(refid_string); refid_string[i] = '.'; refid_string[i+1] = '\0'; dstadr_refid = refid_string; } else if (decodenetnum(value, &refidadr)) { if (SOCK_UNSPEC(&refidadr)) dstadr_refid = "0.0.0.0"; else if (ISREFCLOCKADR(&refidadr)) dstadr_refid = refnumtoa(&refidadr); else dstadr_refid = stoa(&refidadr); } else { havevar[HAVE_REFID] = 0; } } break; case CP_STRATUM: if (decodeuint(value, &stratum)) havevar[HAVE_STRATUM] = 1; break; case CP_HPOLL: if (decodeint(value, &hpoll)) { havevar[HAVE_HPOLL] = 1; if (hpoll < 0) hpoll = NTP_MINPOLL; } break; case CP_PPOLL: if (decodeint(value, &ppoll)) { havevar[HAVE_PPOLL] = 1; if (ppoll < 0) ppoll = NTP_MINPOLL; } break; case CP_REACH: if (decodeuint(value, &reach)) havevar[HAVE_REACH] = 1; break; case CP_DELAY: if (decodetime(value, &estdelay)) havevar[HAVE_DELAY] = 1; break; case CP_OFFSET: if (decodetime(value, &estoffset)) havevar[HAVE_OFFSET] = 1; break; case CP_JITTER: if (pvl == peervarlist) if (decodetime(value, &estjitter)) havevar[HAVE_JITTER] = 1; break; case CP_DISPERSION: if (decodetime(value, &estdisp)) havevar[HAVE_DISPERSION] = 1; break; case CP_REC: if (decodets(value, &rec)) havevar[HAVE_REC] = 1; break; case CP_SRCPORT: if (decodeuint(value, &srcport)) havevar[HAVE_SRCPORT] = 1; break; case CP_REFTIME: havevar[HAVE_REFTIME] = 1; if (!decodets(value, &reftime)) L_CLR(&reftime); break; default: break; } } /* * Check to see if the srcport is NTP's port. If not this probably * isn't a valid peer association. */ if (havevar[HAVE_SRCPORT] && srcport != NTP_PORT) return (1); /* * Got everything, format the line */ poll_sec = 1<<max(min3(ppoll, hpoll, NTP_MAXPOLL), NTP_MINPOLL); if (pktversion > NTP_OLDVERSION) c = flash3[CTL_PEER_STATVAL(rstatus) & 0x7]; else c = flash2[CTL_PEER_STATVAL(rstatus) & 0x3]; if (numhosts > 1) { if (peervarlist == pvl && havevar[HAVE_DSTADR]) { serverlocal = nntohost_col(&dstadr, (size_t)min(LIB_BUFLENGTH - 1, maxhostlen), TRUE); } else { if (currenthostisnum) serverlocal = trunc_left(currenthost, maxhostlen); else serverlocal = currenthost; } fprintf(fp, "%-*s ", maxhostlen, serverlocal); } if (AF_UNSPEC == af || AF(&srcadr) == af) { strncpy(clock_name, nntohost(&srcadr), sizeof(clock_name)); fprintf(fp, "%c%-15.15s ", c, clock_name); drlen = strlen(dstadr_refid); makeascii(drlen, dstadr_refid, fp); while (drlen++ < 15) fputc(' ', fp); fprintf(fp, " %2ld %c %4.4s %4.4s %3lo %7.7s %8.7s %7.7s\n", stratum, type, prettyinterval(whenbuf, sizeof(whenbuf), when(&ts, &rec, &reftime)), prettyinterval(pollbuf, sizeof(pollbuf), (int)poll_sec), reach, lfptoms(&estdelay, 3), lfptoms(&estoffset, 3), (havevar[HAVE_JITTER]) ? lfptoms(&estjitter, 3) : lfptoms(&estdisp, 3)); return (1); } else return(1); }
/* * findhostaddr - resolve a host name into an address (Or vice-versa) * * Given one of {ce_peeraddr,ce_name}, find the other one. * It returns 1 for "success" and 0 for an uncorrectable failure. * Note that "success" includes try again errors. You can tell that you * got a "try again" since {ce_peeraddr,ce_name} will still be zero. */ static int findhostaddr( struct conf_entry *entry ) { static int eai_again_seen = 0; struct addrinfo *addr; struct addrinfo hints; int again; int error; checkparent(); /* make sure our guy is still running */ if (entry->ce_name != NULL && !SOCK_UNSPEC(&entry->peer_store)) { /* HMS: Squawk? */ msyslog(LOG_ERR, "findhostaddr: both ce_name and ce_peeraddr are defined..."); return 1; } if (entry->ce_name == NULL && SOCK_UNSPEC(&entry->peer_store)) { msyslog(LOG_ERR, "findhostaddr: both ce_name and ce_peeraddr are undefined!"); return 0; } if (entry->ce_name) { DPRINTF(2, ("findhostaddr: Resolving <%s>\n", entry->ce_name)); memset(&hints, 0, sizeof(hints)); hints.ai_family = entry->type; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; /* * If IPv6 is not available look only for v4 addresses */ if (!ipv6_works) hints.ai_family = AF_INET; error = getaddrinfo(entry->ce_name, NULL, &hints, &addr); if (error == 0) { entry->peer_store = *((sockaddr_u *)(addr->ai_addr)); if (IS_IPV4(&entry->peer_store)) { entry->ce_peeraddr = NSRCADR(&entry->peer_store); entry->ce_config.v6_flag = 0; } else { entry->ce_peeraddr6 = SOCK_ADDR6(&entry->peer_store); entry->ce_config.v6_flag = 1; } freeaddrinfo(addr); } } else { DPRINTF(2, ("findhostaddr: Resolving <%s>\n", stoa(&entry->peer_store))); entry->ce_name = emalloc(MAXHOSTNAMELEN); error = getnameinfo((const struct sockaddr *)&entry->peer_store, SOCKLEN(&entry->peer_store), (char *)&entry->ce_name, MAXHOSTNAMELEN, NULL, 0, 0); } if (0 == error) { /* again is our return value, for success it is 1 */ again = 1; DPRINTF(2, ("findhostaddr: %s resolved.\n", (entry->ce_name) ? "name" : "address")); } else { /* * If the resolver failed, see if the failure is * temporary. If so, return success. */ again = 0; switch (error) { case EAI_FAIL: again = 1; break; case EAI_AGAIN: again = 1; eai_again_seen = 1; break; case EAI_NONAME: #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) case EAI_NODATA: #endif msyslog(LOG_ERR, "host name not found%s%s: %s", (EAI_NONAME == error) ? "" : " EAI_NODATA", (eai_again_seen) ? " (permanent)" : "", entry->ce_name); again = !eai_again_seen; break; #ifdef EAI_SYSTEM case EAI_SYSTEM: /* * EAI_SYSTEM means the real error is in errno. We should be more * discriminating about which errno values require retrying, but * this matches existing behavior. */ again = 1; DPRINTF(1, ("intres: EAI_SYSTEM errno %d (%s) means try again, right?\n", errno, strerror(errno))); break; #endif } /* do this here to avoid perturbing errno earlier */ DPRINTF(2, ("intres: got error status of: %d\n", error)); } return again; }