/* * 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; NTP_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)); found_specific = (SRCADR(&onesmask) == res->u.v4.mask); } else { res = match_restrict6_addr(&SOCK_ADDR6(addr), SRCPORT(addr)); 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))); }
uint32_t caltontp( const struct calendar *jt ) { int32_t eraday; /* CE Rata Die number */ vint64 ntptime;/* resulting NTP time */ NTP_INSIST(jt != NULL); NTP_REQUIRE(jt->month <= 13); /* permit month 0..13! */ NTP_REQUIRE(jt->monthday <= 32); NTP_REQUIRE(jt->yearday <= 366); NTP_REQUIRE(jt->hour <= 24); NTP_REQUIRE(jt->minute <= MINSPERHR); NTP_REQUIRE(jt->second <= SECSPERMIN); /* * First convert the date to he corresponding RataDie * number. If yearday is not zero, assume that it contains a * useable value and avoid all calculations involving month * and day-of-month. Do a full evaluation otherwise. */ if (jt->yearday) eraday = ntpcal_year_to_ystart(jt->year) + jt->yearday - 1; else eraday = ntpcal_date_to_rd(jt); ntptime = ntpcal_dayjoin(eraday - DAY_NTP_STARTS, ntpcal_etime_to_seconds(jt->hour, jt->minute, jt->second)); return ntptime.d_s.lo; }
/* * on Unix systems the stdio library typically * makes use of file descriptors in the lower * integer range. stdio usually will make use * of the file descriptors in the range of * [0..FOPEN_MAX) * in order to keep this range clean, for socket * file descriptors we attempt to move them above * FOPEN_MAX. This is not as easy as it sounds as * FOPEN_MAX changes from implementation to implementation * and may exceed to current file decriptor limits. * We are using following strategy: * - keep a current socket fd boundary initialized with * max(0, min(GETDTABLESIZE() - FD_CHUNK, FOPEN_MAX)) * - attempt to move the descriptor to the boundary or * above. * - if that fails and boundary > 0 set boundary * to min(0, socket_fd_boundary - FD_CHUNK) * -> retry * if failure and boundary == 0 return old fd * - on success close old fd return new fd * * effects: * - fds will be moved above the socket fd boundary * if at all possible. * - the socket boundary will be reduced until * allocation is possible or 0 is reached - at this * point the algrithm will be disabled */ SOCKET move_fd( SOCKET fd ) { #if !defined(SYS_WINNT) && defined(F_DUPFD) #ifndef FD_CHUNK #define FD_CHUNK 10 #endif #ifndef FOPEN_MAX #define FOPEN_MAX 20 #endif /* * number of fds we would like to have for * stdio FILE* available. * we can pick a "low" number as our use of * FILE* is limited to log files and temporarily * to data and config files. Except for log files * we don't keep the other FILE* open beyond the * scope of the function that opened it. */ #ifndef FD_PREFERRED_SOCKBOUNDARY #define FD_PREFERRED_SOCKBOUNDARY 48 #endif static SOCKET socket_boundary = -1; SOCKET newfd; NTP_REQUIRE((int)fd >= 0); /* * check whether boundary has be set up * already */ if (socket_boundary == -1) { socket_boundary = max(0, min(GETDTABLESIZE() - FD_CHUNK, min(FOPEN_MAX, FD_PREFERRED_SOCKBOUNDARY))); TRACE(1, ("move_fd: estimated max descriptors: %d, " "initial socket boundary: %d\n", GETDTABLESIZE(), socket_boundary)); } /* * Leave a space for stdio to work in. potentially moving the * socket_boundary lower until allocation succeeds. */ do { if (fd >= 0 && fd < socket_boundary) { /* inside reserved range: attempt to move fd */ newfd = fcntl(fd, F_DUPFD, socket_boundary); if (newfd != -1) { /* success: drop the old one - return the new one */ close(fd); return newfd; } } else { /* outside reserved range: no work - return the original one */ return fd; } socket_boundary = max(0, socket_boundary - FD_CHUNK); TRACE(1, ("move_fd: selecting new socket boundary: %d\n", socket_boundary)); } while (socket_boundary > 0); #else NTP_REQUIRE((int)fd >= 0); #endif /* !defined(SYS_WINNT) && defined(F_DUPFD) */ return fd; }
int atolfp( const char *str, l_fp *lfp ) { register const char *cp; register u_long dec_i; register u_long dec_f; char *ind; int ndec; int isneg; static const char *digits = "0123456789"; NTP_REQUIRE(str != NULL); isneg = 0; dec_i = dec_f = 0; ndec = 0; cp = str; /* * We understand numbers of the form: * * [spaces][-|+][digits][.][digits][spaces|\n|\0] */ while (isspace((unsigned char)*cp)) cp++; if (*cp == '-') { cp++; isneg = 1; } if (*cp == '+') cp++; if (*cp != '.' && !isdigit((unsigned char)*cp)) return 0; while (*cp != '\0' && (ind = strchr(digits, *cp)) != NULL) { dec_i = (dec_i << 3) + (dec_i << 1); /* multiply by 10 */ dec_i += (ind - digits); cp++; } if (*cp != '\0' && !isspace((unsigned char)*cp)) { if (*cp++ != '.') return 0; while (ndec < 9 && *cp != '\0' && (ind = strchr(digits, *cp)) != NULL) { ndec++; dec_f = (dec_f << 3) + (dec_f << 1); /* *10 */ dec_f += (ind - digits); cp++; } while (isdigit((unsigned char)*cp)) cp++; if (*cp != '\0' && !isspace((unsigned char)*cp)) return 0; } if (ndec > 0) { register u_long tmp; register u_long bit; register u_long ten_fact; ten_fact = ten_to_the_n[ndec]; tmp = 0; bit = 0x80000000; while (bit != 0) { dec_f <<= 1; if (dec_f >= ten_fact) { tmp |= bit; dec_f -= ten_fact; } bit >>= 1; } if ((dec_f << 1) > ten_fact) tmp++; dec_f = tmp; } if (isneg) M_NEG(dec_i, dec_f); lfp->l_ui = dec_i; lfp->l_uf = dec_f; return 1; }
/* * change_logfile() * * Used to change from syslog to a logfile, or from one logfile to * another, and to reopen logfiles after forking. On systems where * ntpd forks, deals with converting relative logfile paths to * absolute (root-based) because we reopen logfiles after the current * directory has changed. */ int change_logfile( const char * fname, int leave_crumbs ) { FILE * new_file; const char * log_fname; char * abs_fname; #if !defined(SYS_WINNT) && !defined(SYS_VXWORKS) && !defined(VMS) char curdir[512]; size_t cd_octets; size_t octets; #endif /* POSIX */ NTP_REQUIRE(fname != NULL); log_fname = fname; /* * In a forked child of a parent which is logging to a file * instead of syslog, syslog_file will be NULL and both * syslog_fname and syslog_abs_fname will be non-NULL. * If we are given the same filename previously opened * and it's still open, there's nothing to do here. */ if (syslog_file != NULL && syslog_fname != NULL && 0 == strcmp(syslog_fname, log_fname)) return 0; if (0 == strcmp(log_fname, "stderr")) { new_file = stderr; abs_fname = estrdup(log_fname); } else if (0 == strcmp(log_fname, "stdout")) { new_file = stdout; abs_fname = estrdup(log_fname); } else { if (syslog_fname != NULL && 0 == strcmp(log_fname, syslog_fname)) log_fname = syslog_abs_fname; #if !defined(SYS_WINNT) && !defined(SYS_VXWORKS) && !defined(VMS) if (log_fname != syslog_abs_fname && DIR_SEP != log_fname[0] && 0 != strcmp(log_fname, "stderr") && 0 != strcmp(log_fname, "stdout") && NULL != getcwd(curdir, sizeof(curdir))) { cd_octets = strlen(curdir); /* trim any trailing '/' */ if (cd_octets > 1 && DIR_SEP == curdir[cd_octets - 1]) cd_octets--; octets = cd_octets; octets += 1; /* separator '/' */ octets += strlen(log_fname); octets += 1; /* NUL terminator */ abs_fname = emalloc(octets); snprintf(abs_fname, octets, "%.*s%c%s", (int)cd_octets, curdir, DIR_SEP, log_fname); } else #endif abs_fname = estrdup(log_fname); TRACE(1, ("attempting to open log %s\n", abs_fname)); new_file = fopen(abs_fname, "a"); } if (NULL == new_file) { free(abs_fname); return -1; } /* leave a pointer in the old log */ if (leave_crumbs && (syslogit || log_fname != syslog_abs_fname)) msyslog(LOG_NOTICE, "switching logging to file %s", abs_fname); if (syslog_file != NULL && syslog_file != stderr && syslog_file != stdout && fileno(syslog_file) != fileno(new_file)) fclose(syslog_file); syslog_file = new_file; if (log_fname == syslog_abs_fname) { free(abs_fname); } else { if (syslog_abs_fname != NULL && syslog_abs_fname != syslog_fname) free(syslog_abs_fname); if (syslog_fname != NULL) free(syslog_fname); syslog_fname = estrdup(log_fname); syslog_abs_fname = abs_fname; } syslogit = FALSE; return 0; }
/* * hack_restrict - add/subtract/manipulate entries on the restrict list */ void hack_restrict( int op, sockaddr_u * resaddr, sockaddr_u * resmask, u_short mflags, u_short flags, u_long expire ) { int v6; restrict_u match; restrict_u * res; restrict_u ** plisthead; DPRINTF(1, ("restrict: op %d addr %s mask %s mflags %08x flags %08x\n", op, stoa(resaddr), stoa(resmask), mflags, flags)); if (NULL == resaddr) { NTP_REQUIRE(NULL == resmask); NTP_REQUIRE(RESTRICT_FLAGS == op); restrict_source_flags = flags; restrict_source_mflags = mflags; restrict_source_enabled = 1; return; } ZERO(match); /* silence VC9 potentially uninit warnings */ res = NULL; v6 = 0; if (IS_IPV4(resaddr)) { v6 = 0; /* * Get address and mask in host byte order for easy * comparison as u_int32 */ match.u.v4.addr = SRCADR(resaddr); match.u.v4.mask = SRCADR(resmask); match.u.v4.addr &= match.u.v4.mask; } else if (IS_IPV6(resaddr)) { v6 = 1; /* * Get address and mask in network byte order for easy * comparison as byte sequences (e.g. memcmp()) */ match.u.v6.mask = SOCK_ADDR6(resmask); MASK_IPV6_ADDR(&match.u.v6.addr, PSOCK_ADDR6(resaddr), &match.u.v6.mask); } else /* not IPv4 nor IPv6 */ NTP_REQUIRE(0); match.flags = flags; match.mflags = mflags; match.expire = expire; res = match_restrict_entry(&match, v6); switch (op) { case RESTRICT_FLAGS: /* * Here we add bits to the flags. If this is a * new restriction add it. */ if (NULL == res) { if (v6) { res = alloc_res6(); memcpy(res, &match, V6_SIZEOF_RESTRICT_U); plisthead = &restrictlist6; } else { res = alloc_res4(); memcpy(res, &match, V4_SIZEOF_RESTRICT_U); plisthead = &restrictlist4; } LINK_SORT_SLIST( *plisthead, res, (v6) ? res_sorts_before6(res, L_S_S_CUR()) : res_sorts_before4(res, L_S_S_CUR()), link, restrict_u); restrictcount++; if (RES_LIMITED & flags) inc_res_limited(); } else { if ((RES_LIMITED & flags) && !(RES_LIMITED & res->flags)) inc_res_limited(); res->flags |= flags; } break; case RESTRICT_UNFLAG: /* * Remove some bits from the flags. If we didn't * find this one, just return. */ if (res != NULL) { if ((RES_LIMITED & res->flags) && (RES_LIMITED & flags)) dec_res_limited(); res->flags &= ~flags; } break; case RESTRICT_REMOVE: case RESTRICT_REMOVEIF: /* * Remove an entry from the table entirely if we * found one. Don't remove the default entry and * don't remove an interface entry. */ if (res != NULL && (RESTRICT_REMOVEIF == op || !(RESM_INTERFACE & res->mflags)) && res != &restrict_def4 && res != &restrict_def6) free_res(res, v6); break; default: /* unknown op */ NTP_INSIST(0); break; } }
/* * decodenetnum convert text IP address and port to sockaddr_u * * Returns 0 for failure, 1 for success. */ int decodenetnum( const char *num, sockaddr_u *netnum ) { struct addrinfo hints, *ai = NULL; int err; u_short port; const char *cp; const char *port_str; char *pp; char *np; char name[80]; NTP_REQUIRE(num != NULL); NTP_REQUIRE(strlen(num) < sizeof(name)); port_str = NULL; if ('[' != num[0]) { /* * to distinguish IPv6 embedded colons from a port * specification on an IPv4 address, assume all * legal IPv6 addresses have at least two colons. */ pp = strchr(num, ':'); if (NULL == pp) cp = num; /* no colons */ else if (NULL != strchr(pp + 1, ':')) cp = num; /* two or more colons */ else { /* one colon */ strlcpy(name, num, sizeof(name)); cp = name; pp = strchr(cp, ':'); *pp = '\0'; port_str = pp + 1; } } else { cp = num + 1; np = name; while (*cp && ']' != *cp) *np++ = *cp++; *np = 0; if (']' == cp[0] && ':' == cp[1] && '\0' != cp[2]) port_str = &cp[2]; cp = name; } ZERO(hints); hints.ai_flags = Z_AI_NUMERICHOST; err = getaddrinfo(cp, "ntp", &hints, &ai); if (err != 0) return 0; NTP_INSIST(ai->ai_addrlen <= sizeof(*netnum)); ZERO(*netnum); memcpy(netnum, ai->ai_addr, ai->ai_addrlen); freeaddrinfo(ai); if (NULL == port_str || 1 != sscanf(port_str, "%hu", &port)) port = NTP_PORT; SET_PORT(netnum, port); return 1; }
/* * Juergen Perlinger, 2008-11-12 * Add support for full calendar calculatios. If the day-of-year is provided * (that is, not zero) it will be used instead of month and day-of-month; * otherwise a full turn through the calendar calculations will be taken. * * I know that Harlan Stenn likes to see assertions in production code, and I * agree there, but it would be a tricky thing here. The algorithm is quite * capable of producing sensible answers even to seemingly weird inputs: the * date <any year here>-03-00, the 0.th March of the year, will be automtically * treated as the last day of February, no matter whether the year is a leap * year or not. So adding constraints is merely for the benefit of the callers, * because the only thing we can check for consistency is our input, produced * by somebody else. * * BTW: A total roundtrip using 'caljulian' would be a quite shaky thing: * Because of the truncation of the NTP time stamp to 32 bits and the epoch * unfolding around the current time done by 'caljulian' the roundtrip does * *not* necessarily reproduce the input, especially if the time spec is more * than 68 years off from the current time... */ u_long caltontp( const struct calendar *jt ) { ntp_u_int32_t days; /* full days in NTP epoch */ ntp_u_int32_t years; /* complete ACE years before date */ ntp_u_int32_t month; /* adjusted month for calendar */ NTP_INSIST(jt != NULL); NTP_REQUIRE(jt->month <= 13); /* permit month 0..13! */ NTP_REQUIRE(jt->monthday <= 32); NTP_REQUIRE(jt->yearday <= 366); NTP_REQUIRE(jt->hour <= 24); NTP_REQUIRE(jt->minute <= MINSPERHR); NTP_REQUIRE(jt->second <= SECSPERMIN); /* * First convert the date to fully elapsed days since NTP epoch. The * expressions used here give us initially days since 0001-01-01, the * beginning of the christian era in the proleptic gregorian calendar; * they are rebased on-the-fly into days since beginning of the NTP * epoch, 1900-01-01. */ if (jt->yearday) { /* * Assume that the day-of-year contains a useable value and * avoid all calculations involving month and day-of-month. */ years = jt->year - 1; days = years * DAYSPERYEAR /* days in previous years */ + years / 4 /* plus prior years's leap days */ - years / 100 /* minus leapless century years */ + years / 400 /* plus leapful Gregorian yrs */ + jt->yearday /* days this year */ - DAY_NTP_STARTS; /* rebase to NTP epoch */ } else { /* * The following code is according to the excellent book * 'Calendrical Calculations' by Nachum Dershowitz and Edward * Reingold. It does a full calendar evaluation, using one of * the alternate algorithms: Shift to a hypothetical year * starting on the previous march,1st; merge years, month and * days; undo the the 9 month shift (which is 306 days). The * advantage is that we do NOT need to now whether a year is a * leap year or not, because the leap day is the LAST day of * the year. */ month = (ntp_u_int32_t)jt->month + 9; years = jt->year - 1 + month / 12; month %= 12; days = years * DAYSPERYEAR /* days in previous years */ + years / 4 /* plus prior years's leap days */ - years / 100 /* minus leapless century years */ + years / 400 /* plus leapful Gregorian yrs */ + (month * 153 + 2) / 5 /* plus days before month */ + jt->monthday /* plus day-of-month */ - 306 /* minus 9 months */ - DAY_NTP_STARTS; /* rebase to NTP epoch */ } /* * Do the obvious: Merge everything together, making sure integer * promotion doesn't play dirty tricks on us; there is probably some * redundancy in the casts, but this drives it home with force. All * arithmetic is done modulo 2**32, because the result is truncated * anyway. */ return days * SECSPERDAY + (ntp_u_int32_t)jt->hour * MINSPERHR*SECSPERMIN + (ntp_u_int32_t)jt->minute * SECSPERMIN + (ntp_u_int32_t)jt->second; }