Browse Source

Add support for "constraints": when configured, ntpd(8) will query the

time from HTTPS servers, by parsing the Date: header, and use the
median constraint time as a boundary to verify NTP responses.  This
adds some level of authentication and protection against MITM attacks
while preserving the accuracy of the NTP protocol; without relying on
authentication options for NTP that are basically unavailable at
present.  This is an initial implementation and the semantics will be
improved once it is in the tree.
Discussed with deraadt@ and henning@
OK henning@
OPENBSD_5_7
reyk 9 years ago
parent
commit
7433fa0bce
13 changed files with 981 additions and 27 deletions
  1. +4
    -1
      src/etc/examples/ntpd.conf
  2. +4
    -4
      src/usr.sbin/ntpd/Makefile
  3. +10
    -1
      src/usr.sbin/ntpd/client.c
  4. +15
    -1
      src/usr.sbin/ntpd/config.c
  5. +659
    -0
      src/usr.sbin/ntpd/constraint.c
  6. +4
    -1
      src/usr.sbin/ntpd/control.c
  7. +56
    -7
      src/usr.sbin/ntpd/ntp.c
  8. +3
    -2
      src/usr.sbin/ntpd/ntpctl.8
  9. +14
    -1
      src/usr.sbin/ntpd/ntpd.c
  10. +36
    -2
      src/usr.sbin/ntpd/ntpd.conf.5
  11. +47
    -3
      src/usr.sbin/ntpd/ntpd.h
  12. +122
    -3
      src/usr.sbin/ntpd/parse.y
  13. +7
    -1
      src/usr.sbin/ntpd/util.c

+ 4
- 1
src/etc/examples/ntpd.conf View File

@ -1,4 +1,4 @@
# $OpenBSD: ntpd.conf,v 1.1 2014/07/13 13:53:36 rpe Exp $
# $OpenBSD: ntpd.conf,v 1.2 2015/02/10 06:40:08 reyk Exp $
# sample ntpd configuration file, see ntpd.conf(5) # sample ntpd configuration file, see ntpd.conf(5)
# Addresses to listen on (ntpd does not listen by default) # Addresses to listen on (ntpd does not listen by default)
@ -16,3 +16,6 @@ servers pool.ntp.org
# use all detected timedelta sensors # use all detected timedelta sensors
#sensor * #sensor *
# get the time constraint from a well-known HTTPS site
#constraints from "https://www.google.com/search?q=openntpd"

+ 4
- 4
src/usr.sbin/ntpd/Makefile View File

@ -1,17 +1,17 @@
# $OpenBSD: Makefile,v 1.12 2013/10/04 14:28:15 phessler Exp $
# $OpenBSD: Makefile,v 1.13 2015/02/10 06:40:08 reyk Exp $
PROG= ntpd PROG= ntpd
SRCS= ntpd.c log.c ntp.c ntp_msg.c parse.y config.c \ SRCS= ntpd.c log.c ntp.c ntp_msg.c parse.y config.c \
server.c client.c sensors.c util.c ntp_dns.c \ server.c client.c sensors.c util.c ntp_dns.c \
control.c
control.c constraint.c
CFLAGS+= -Wall -I${.CURDIR} CFLAGS+= -Wall -I${.CURDIR}
CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes
CFLAGS+= -Wmissing-declarations CFLAGS+= -Wmissing-declarations
CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual
CFLAGS+= -Wsign-compare CFLAGS+= -Wsign-compare
YFLAGS= YFLAGS=
LDADD+= -lutil
DPADD+= ${LIBUTIL}
LDADD+= -lutil -lcrypto -lssl -ltls
DPADD+= ${LIBUTIL} ${LIBCRYPTO} ${LIBSSL} ${LIBTLS}
LINKS= ${BINDIR}/ntpd ${BINDIR}/ntpctl LINKS= ${BINDIR}/ntpd ${BINDIR}/ntpctl
MAN= ntpd.8 ntpd.conf.5 ntpctl.8 MAN= ntpd.8 ntpd.conf.5 ntpctl.8


+ 10
- 1
src/usr.sbin/ntpd/client.c View File

@ -1,4 +1,4 @@
/* $OpenBSD: client.c,v 1.98 2015/01/19 20:47:03 bcook Exp $ */
/* $OpenBSD: client.c,v 1.99 2015/02/10 06:40:08 reyk Exp $ */
/* /*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@ -324,6 +324,15 @@ client_dispatch(struct ntp_peer *p, u_int8_t settime)
return (0); return (0);
} }
/* Detect liars */
if (conf->constraint_median != 0 &&
(constraint_check(T2) != 0 || constraint_check(T3) != 0)) {
log_info("reply from %s: constraint check failed",
log_sockaddr((struct sockaddr *)&p->addr->ss));
set_next(p, error_interval());
return (0);
}
p->reply[p->shift].offset = ((T2 - T1) + (T3 - T4)) / 2; p->reply[p->shift].offset = ((T2 - T1) + (T3 - T4)) / 2;
p->reply[p->shift].delay = (T4 - T1) - (T3 - T2); p->reply[p->shift].delay = (T4 - T1) - (T3 - T2);
p->reply[p->shift].status.stratum = msg.stratum; p->reply[p->shift].status.stratum = msg.stratum;


+ 15
- 1
src/usr.sbin/ntpd/config.c View File

@ -1,4 +1,4 @@
/* $OpenBSD: config.c,v 1.25 2015/02/08 04:54:15 reyk Exp $ */
/* $OpenBSD: config.c,v 1.26 2015/02/10 06:40:08 reyk Exp $ */
/* /*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@ -33,6 +33,7 @@ struct ntp_addr *host_v4(const char *);
struct ntp_addr *host_v6(const char *); struct ntp_addr *host_v6(const char *);
static u_int32_t maxid = 0; static u_int32_t maxid = 0;
static u_int32_t constraint_maxid = 0;
void void
host(const char *s, struct ntp_addr **hn) host(const char *s, struct ntp_addr **hn)
@ -193,3 +194,16 @@ new_sensor(char *device)
return (s); return (s);
} }
struct constraint *
new_constraint(void)
{
struct constraint *p;
if ((p = calloc(1, sizeof(struct constraint))) == NULL)
fatal("new_constraint calloc");
p->id = ++constraint_maxid;
return (p);
}

+ 659
- 0
src/usr.sbin/ntpd/constraint.c View File

@ -0,0 +1,659 @@
/* $OpenBSD: constraint.c,v 1.1 2015/02/10 06:40:08 reyk Exp $ */
/*
* Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/uio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <imsg.h>
#include <netdb.h>
#include <poll.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <tls.h>
#include "log.h"
#include "ntpd.h"
int constraint_addr_init(struct constraint *);
struct constraint *
constraint_byfd(int);
struct constraint *
constraint_bypid(pid_t);
int constraint_close(int);
void constraint_update(void);
void constraint_reset(void);
int constraint_cmp(const void *, const void *);
struct httpsdate *
httpsdate_init(const char *, const char *, const char *,
const char *, const u_int8_t *, size_t);
void httpsdate_free(void *);
int httpsdate_request(struct httpsdate *, struct timeval *);
void *httpsdate_query(const char *, const char *, const char *,
const char *, const u_int8_t *, size_t,
struct timeval *, struct timeval *);
char *tls_readline(struct tls *, size_t *, size_t *, struct timeval *);
struct httpsdate {
char *tls_host;
char *tls_port;
char *tls_name;
char *tls_path;
char *tls_request;
struct tls_config *tls_config;
struct tls *tls_ctx;
struct tm tls_tm;
};
int
constraint_init(struct constraint *cstr)
{
cstr->state = STATE_NONE;
cstr->fd = -1;
cstr->last = getmonotime();
cstr->constraint = 0;
return (constraint_addr_init(cstr));
}
int
constraint_addr_init(struct constraint *cstr)
{
struct sockaddr_in *sa_in;
struct sockaddr_in6 *sa_in6;
struct ntp_addr *h;
int cnt = 0;
for (h = cstr->addr; h != NULL; h = h->next) {
switch (h->ss.ss_family) {
case AF_INET:
sa_in = (struct sockaddr_in *)&h->ss;
if (ntohs(sa_in->sin_port) == 0)
sa_in->sin_port = htons(443);
cstr->state = STATE_DNS_DONE;
break;
case AF_INET6:
sa_in6 = (struct sockaddr_in6 *)&h->ss;
if (ntohs(sa_in6->sin6_port) == 0)
sa_in6->sin6_port = htons(443);
cstr->state = STATE_DNS_DONE;
break;
default:
/* XXX king bula sez it? */
fatalx("wrong AF in constraint_addr_init");
/* NOTREACHED */
}
cnt++;
}
return (cnt);
}
int
constraint_query(struct constraint *cstr)
{
int pipes[2];
struct timeval rectv, xmttv;
void *ctx;
static char hname[NI_MAXHOST];
time_t now;
struct iovec iov[2];
now = getmonotime();
if (cstr->state >= STATE_REPLY_RECEIVED) {
if (cstr->last + CONSTRAINT_SCAN_INTERVAL > now) {
/* Nothing to do */
return (-1);
}
/* Reset */
cstr->senderrors = 0;
constraint_close(cstr->fd);
} else if (cstr->state == STATE_QUERY_SENT) {
if (cstr->last + CONSTRAINT_SCAN_TIMEOUT > now) {
/* The caller should expect a reply */
return (0);
}
/* Timeout, just kill the process to reset it */
kill(cstr->pid, SIGTERM);
return (-1);
}
cstr->last = now;
if (getnameinfo((struct sockaddr *)&cstr->addr->ss,
SA_LEN((struct sockaddr *)&cstr->addr->ss),
hname, sizeof(hname), NULL, 0,
NI_NUMERICHOST) != 0)
fatalx("%s getnameinfo %s", __func__, cstr->addr_head.name);
log_debug("constraint request to %s", hname);
if (socketpair(AF_UNIX, SOCK_DGRAM, AF_UNSPEC, pipes) == -1)
fatal("%s pipes", __func__);
/* Fork child handlers */
switch (cstr->pid = fork()) {
case -1:
cstr->senderrors++;
close(pipes[0]);
close(pipes[1]);
return (-1);
case 0:
tzset();
log_init(conf->debug);
setproctitle("constraint from %s", hname);
/* Child process */
if (dup2(pipes[1], CONSTRAINT_PASSFD) == -1)
fatal("%s dup2 CONSTRAINT_PASSFD", __func__);
if (pipes[0] != CONSTRAINT_PASSFD)
close(pipes[0]);
if (pipes[1] != CONSTRAINT_PASSFD)
close(pipes[1]);
(void)closefrom(CONSTRAINT_PASSFD + 1);
if (fcntl(CONSTRAINT_PASSFD, F_SETFD, FD_CLOEXEC) == -1)
fatal("%s fcntl F_SETFD", __func__);
cstr->fd = CONSTRAINT_PASSFD;
imsg_init(&cstr->ibuf, cstr->fd);
if ((ctx = httpsdate_query(hname,
CONSTRAINT_PORT, cstr->addr_head.name, cstr->addr_head.path,
conf->ca, conf->ca_len, &rectv, &xmttv)) == NULL) {
/* Abort with failure but without warning */
exit(1);
}
iov[0].iov_base = &rectv;
iov[0].iov_len = sizeof(rectv);
iov[1].iov_base = &xmttv;
iov[1].iov_len = sizeof(xmttv);
imsg_composev(&cstr->ibuf, IMSG_CONSTRAINT, 0, 0, -1, iov, 2);
imsg_flush(&cstr->ibuf);
/* Tear down the TLS connection after sending the result */
httpsdate_free(ctx);
_exit(0);
/* NOTREACHED */
default:
/* Parent */
close(pipes[1]);
cstr->fd = pipes[0];
cstr->state = STATE_QUERY_SENT;
imsg_init(&cstr->ibuf, cstr->fd);
break;
}
return (0);
}
void
constraint_check_child(void)
{
struct constraint *cstr;
int status;
int fail;
char *cause;
pid_t pid;
do {
pid = waitpid(WAIT_ANY, &status, WNOHANG);
if (pid <= 0)
continue;
fail = 0;
if (WIFSIGNALED(status)) {
fail = 1;
asprintf(&cause, "terminated; signal %d",
WTERMSIG(status));
} else if (WIFEXITED(status)) {
if (WEXITSTATUS(status) != 0) {
fail = 1;
asprintf(&cause, "exited abnormally");
} else
asprintf(&cause, "exited okay");
} else
fatalx("unexpected cause of SIGCHLD");
if ((cstr = constraint_bypid(pid)) != NULL) {
if (fail) {
log_info("no constraint reply from %s"
" received in time, next query %ds",
log_sockaddr((struct sockaddr *)
&cstr->addr->ss), CONSTRAINT_SCAN_INTERVAL);
}
if (fail || cstr->state < STATE_REPLY_RECEIVED) {
cstr->senderrors++;
constraint_close(cstr->fd);
}
}
free(cause);
} while (pid > 0 || (pid == -1 && errno == EINTR));
}
struct constraint *
constraint_byfd(int fd)
{
struct constraint *cstr;
TAILQ_FOREACH(cstr, &conf->constraints, entry) {
if (cstr->fd == fd)
return (cstr);
}
return (NULL);
}
struct constraint *
constraint_bypid(pid_t pid)
{
struct constraint *cstr;
TAILQ_FOREACH(cstr, &conf->constraints, entry) {
if (cstr->pid == pid)
return (cstr);
}
return (NULL);
}
int
constraint_close(int fd)
{
struct constraint *cstr;
if ((cstr = constraint_byfd(fd)) == NULL) {
log_warn("%s: fd %d: not found", __func__, fd);
return (0);
}
msgbuf_clear(&cstr->ibuf.w);
close(cstr->fd);
cstr->fd = -1;
if (cstr->senderrors)
cstr->state = STATE_INVALID;
else if (cstr->state >= STATE_QUERY_SENT)
cstr->state = STATE_DNS_DONE;
cstr->last = getmonotime();
return (1);
}
int
constraint_dispatch_msg(struct pollfd *pfd)
{
struct imsg imsg;
struct constraint *cstr;
ssize_t n;
struct timeval tv[2];
double offset;
if ((cstr = constraint_byfd(pfd->fd)) == NULL)
return (0);
if (!(pfd->revents & POLLIN))
return (0);
if ((n = imsg_read(&cstr->ibuf)) == -1 || n == 0) {
constraint_close(pfd->fd);
return (1);
}
for (;;) {
if ((n = imsg_get(&cstr->ibuf, &imsg)) == -1) {
constraint_close(pfd->fd);
return (1);
}
if (n == 0)
break;
switch (imsg.hdr.type) {
case IMSG_CONSTRAINT:
if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(tv))
fatalx("invalid IMSG_CONSTRAINT received");
memcpy(tv, imsg.data, sizeof(tv));
offset = gettime_from_timeval(&tv[0]) -
gettime_from_timeval(&tv[1]);
log_info("constraint reply from %s: offset %f",
log_sockaddr((struct sockaddr *)&cstr->addr->ss),
offset);
cstr->state = STATE_REPLY_RECEIVED;
cstr->last = getmonotime();
cstr->constraint = tv[0].tv_sec;
constraint_update();
break;
default:
break;
}
imsg_free(&imsg);
}
return (0);
}
int
constraint_cmp(const void *a, const void *b)
{
return (*(const time_t *)a - *(const time_t *)b);
}
void
constraint_update(void)
{
struct constraint *cstr;
int cnt, i;
time_t *sum;
time_t now;
now = getmonotime();
cnt = 0;
TAILQ_FOREACH(cstr, &conf->constraints, entry) {
if (cstr->state != STATE_REPLY_RECEIVED)
continue;
cnt++;
}
if ((sum = calloc(cnt, sizeof(time_t))) == NULL)
fatal("calloc");
i = 0;
TAILQ_FOREACH(cstr, &conf->constraints, entry) {
if (cstr->state != STATE_REPLY_RECEIVED)
continue;
sum[i++] = cstr->constraint + (now - cstr->last);
}
qsort(sum, cnt, sizeof(time_t), constraint_cmp);
/* calculate median */
i = cnt / 2;
if (cnt % 2 == 0)
if (sum[i - 1] < sum[i])
i -= 1;
conf->constraint_last = now;
conf->constraint_median = sum[i];
free(sum);
}
void
constraint_reset(void)
{
struct constraint *cstr;
TAILQ_FOREACH(cstr, &conf->constraints, entry) {
if (cstr->state == STATE_QUERY_SENT)
continue;
constraint_close(cstr->fd);
}
conf->constraint_errors = 0;
}
int
constraint_check(double val)
{
struct timeval tv;
double constraint;
time_t now;
if (conf->constraint_median == 0)
return (0);
/* Calculate the constraint with the current offset */
now = getmonotime();
tv.tv_sec = conf->constraint_median + (now - conf->constraint_last);
tv.tv_usec = 0;
constraint = gettime_from_timeval(&tv);
if (((val - constraint) > CONSTRAINT_MARGIN) ||
((constraint - val) > CONSTRAINT_MARGIN)) {
/* XXX get new constraint if too many errors happened */
if (conf->constraint_errors++ > CONSTRAINT_ERROR_MARGIN) {
constraint_reset();
}
return (-1);
}
return (0);
}
struct httpsdate *
httpsdate_init(const char *hname, const char *port, const char *name,
const char *path, const u_int8_t *ca, size_t ca_len)
{
struct httpsdate *httpsdate = NULL;
if (tls_init() == -1)
return (NULL);
if ((httpsdate = calloc(1, sizeof(*httpsdate))) == NULL)
goto fail;
if (name == NULL)
name = hname;
if ((httpsdate->tls_host = strdup(hname)) == NULL ||
(httpsdate->tls_port = strdup(port)) == NULL ||
(httpsdate->tls_name = strdup(name)) == NULL ||
(httpsdate->tls_path = strdup(path)) == NULL)
goto fail;
if (asprintf(&httpsdate->tls_request,
"HEAD %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n",
httpsdate->tls_path, httpsdate->tls_name) == -1)
goto fail;
if ((httpsdate->tls_config = tls_config_new()) == NULL)
goto fail;
/* XXX we have to pre-resolve, so name and host are not equal */
tls_config_insecure_noverifyhost(httpsdate->tls_config);
if (ca == NULL || ca_len == 0)
tls_config_insecure_noverifycert(httpsdate->tls_config);
else
tls_config_set_ca_mem(httpsdate->tls_config, ca, ca_len);
return (httpsdate);
fail:
httpsdate_free(httpsdate);
return (NULL);
}
void
httpsdate_free(void *arg)
{
struct httpsdate *httpsdate = arg;
if (httpsdate == NULL)
return;
if (httpsdate->tls_ctx)
tls_close(httpsdate->tls_ctx);
tls_free(httpsdate->tls_ctx);
tls_config_free(httpsdate->tls_config);
free(httpsdate->tls_host);
free(httpsdate->tls_port);
free(httpsdate->tls_name);
free(httpsdate->tls_path);
free(httpsdate->tls_request);
free(httpsdate);
}
int
httpsdate_request(struct httpsdate *httpsdate, struct timeval *when)
{
size_t outlen = 0, maxlength = CONSTRAINT_MAXHEADERLENGTH;
char *line, *p;
if ((httpsdate->tls_ctx = tls_client()) == NULL)
goto fail;
if (tls_configure(httpsdate->tls_ctx, httpsdate->tls_config) == -1)
goto fail;
if (tls_connect(httpsdate->tls_ctx,
httpsdate->tls_host, httpsdate->tls_port) == -1) {
log_warnx("tls failed: %s: %s", httpsdate->tls_host,
tls_error(httpsdate->tls_ctx));
goto fail;
}
if (tls_write(httpsdate->tls_ctx,
httpsdate->tls_request, strlen(httpsdate->tls_request),
&outlen) == -1)
goto fail;
while ((line = tls_readline(httpsdate->tls_ctx, &outlen,
&maxlength, when)) != NULL) {
line[strcspn(line, "\r\n")] = '\0';
if ((p = strchr(line, ' ')) == NULL || *p == '\0')
goto next;
*p++ = '\0';
if (strcasecmp("Date:", line) != 0)
goto next;
/*
* Expect the date/time format as IMF-fixdate which is
* mandated by HTTP/1.1 in the new RFC 7231 and was
* preferred by RFC 2616. Other formats would be RFC 850
* or ANSI C's asctime() - the latter doesn't include
* the timezone which is required here.
*/
if (strptime(p, "%a, %d %h %Y %T %Z",
&httpsdate->tls_tm) == NULL) {
log_warnx("unsupported date format");
free(line);
return (-1);
}
free(line);
break;
next:
free(line);
}
return (0);
fail:
httpsdate_free(httpsdate);
return (-1);
}
void *
httpsdate_query(const char *hname, const char *port, const char *name,
const char *path, const u_int8_t *ca, size_t ca_len,
struct timeval *rectv, struct timeval *xmttv)
{
struct httpsdate *httpsdate;
struct timeval when;
time_t t;
if ((httpsdate = httpsdate_init(hname, port, name, path,
ca, ca_len)) == NULL)
return (NULL);
if (httpsdate_request(httpsdate, &when) == -1)
return (NULL);
/* Return parsed date as local time */
t = timegm(&httpsdate->tls_tm);
/* Report parsed Date: as "received time" */
rectv->tv_sec = t;
rectv->tv_usec = 0;
/* And add delay as "transmit time" */
xmttv->tv_sec = when.tv_sec;
xmttv->tv_usec = when.tv_usec;
return (httpsdate);
}
/* Based on SSL_readline in ftp/fetch.c */
char *
tls_readline(struct tls *tls, size_t *lenp, size_t *maxlength,
struct timeval *when)
{
size_t i, len, nr;
char *buf, *q, c;
int ret;
len = 128;
if ((buf = malloc(len)) == NULL)
fatal("Can't allocate memory for transfer buffer");
for (i = 0; ; i++) {
if (i >= len - 1) {
if ((q = reallocarray(buf, len, 2)) == NULL)
fatal("Can't expand transfer buffer");
buf = q;
len *= 2;
}
again:
ret = tls_read(tls, &c, 1, &nr);
if (ret == TLS_READ_AGAIN)
goto again;
if (ret != 0) {
/* SSL read error, ignore */
return (NULL);
}
if (maxlength != NULL && (*maxlength)-- == 0) {
log_warnx("maximum length exceeded");
return (NULL);
}
buf[i] = c;
if (c == '\n')
break;
}
*lenp = i;
if (gettimeofday(when, NULL) == -1)
fatal("gettimeofday");
return (buf);
}

+ 4
- 1
src/usr.sbin/ntpd/control.c View File

@ -1,4 +1,4 @@
/* $OpenBSD: control.c,v 1.4 2015/01/09 07:35:37 deraadt Exp $ */
/* $OpenBSD: control.c,v 1.5 2015/02/10 06:40:08 reyk Exp $ */
/* /*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@ -309,6 +309,9 @@ build_show_status(struct ctl_show_status *cs)
cs->synced = conf->status.synced; cs->synced = conf->status.synced;
cs->stratum = conf->status.stratum; cs->stratum = conf->status.stratum;
cs->clock_offset = getoffset() * 1000.0; cs->clock_offset = getoffset() * 1000.0;
cs->constraint_median = conf->constraint_median;
cs->constraint_last = conf->constraint_last;
cs->constraint_errors = conf->constraint_errors;
} }
void void


+ 56
- 7
src/usr.sbin/ntpd/ntp.c View File

@ -1,4 +1,4 @@
/* $OpenBSD: ntp.c,v 1.127 2015/02/10 06:03:43 bcook Exp $ */
/* $OpenBSD: ntp.c,v 1.128 2015/02/10 06:40:08 reyk Exp $ */
/* /*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@ -30,6 +30,7 @@
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#include <tls.h>
#include "ntpd.h" #include "ntpd.h"
@ -41,6 +42,7 @@
volatile sig_atomic_t ntp_quit = 0; volatile sig_atomic_t ntp_quit = 0;
volatile sig_atomic_t ntp_report = 0; volatile sig_atomic_t ntp_report = 0;
volatile sig_atomic_t ntp_sigchld = 0;
struct imsgbuf *ibuf_main; struct imsgbuf *ibuf_main;
struct imsgbuf *ibuf_dns; struct imsgbuf *ibuf_dns;
struct ntpd_conf *conf; struct ntpd_conf *conf;
@ -67,6 +69,9 @@ ntp_sighdlr(int sig)
case SIGINFO: case SIGINFO:
ntp_report = 1; ntp_report = 1;
break; break;
case SIGCHLD:
ntp_sigchld = 1;
break;
} }
} }
@ -76,9 +81,10 @@ ntp_main(int pipe_prnt[2], int fd_ctl, struct ntpd_conf *nconf,
{ {
int a, b, nfds, i, j, idx_peers, timeout; int a, b, nfds, i, j, idx_peers, timeout;
int hotplugfd, nullfd, pipe_dns[2], idx_clients; int hotplugfd, nullfd, pipe_dns[2], idx_clients;
int ctls, boundaries;
u_int pfd_elms = 0, idx2peer_elms = 0; u_int pfd_elms = 0, idx2peer_elms = 0;
u_int listener_cnt, new_cnt, sent_cnt, trial_cnt; u_int listener_cnt, new_cnt, sent_cnt, trial_cnt;
u_int ctl_cnt;
u_int ctl_cnt, constraint_cnt;
pid_t pid; pid_t pid;
struct pollfd *pfd = NULL; struct pollfd *pfd = NULL;
struct servent *se; struct servent *se;
@ -86,10 +92,11 @@ ntp_main(int pipe_prnt[2], int fd_ctl, struct ntpd_conf *nconf,
struct ntp_peer *p; struct ntp_peer *p;
struct ntp_peer **idx2peer = NULL; struct ntp_peer **idx2peer = NULL;
struct ntp_sensor *s, *next_s; struct ntp_sensor *s, *next_s;
struct constraint *cstr;
struct timespec tp; struct timespec tp;
struct stat stb; struct stat stb;
struct ctl_conn *cc; struct ctl_conn *cc;
time_t nextaction, last_sensor_scan = 0;
time_t nextaction, last_sensor_scan = 0, now;
void *newp; void *newp;
switch (pid = fork()) { switch (pid = fork()) {
@ -102,6 +109,13 @@ ntp_main(int pipe_prnt[2], int fd_ctl, struct ntpd_conf *nconf,
return (pid); return (pid);
} }
tls_init();
/* Verification will be turned off if CA is not found */
if ((conf->ca = tls_load_file(CONSTRAINT_CA,
&conf->ca_len, NULL)) == NULL)
log_warnx("constraint certificate verification turned off");
/* in this case the parent didn't init logging and didn't daemonize */ /* in this case the parent didn't init logging and didn't daemonize */
if (nconf->settime && !nconf->debug) { if (nconf->settime && !nconf->debug) {
log_init(nconf->debug); log_init(nconf->debug);
@ -157,7 +171,7 @@ ntp_main(int pipe_prnt[2], int fd_ctl, struct ntpd_conf *nconf,
signal(SIGINFO, ntp_sighdlr); signal(SIGINFO, ntp_sighdlr);
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
signal(SIGHUP, SIG_IGN); signal(SIGHUP, SIG_IGN);
signal(SIGCHLD, SIG_DFL);
signal(SIGCHLD, ntp_sighdlr);
if ((ibuf_main = malloc(sizeof(struct imsgbuf))) == NULL) if ((ibuf_main = malloc(sizeof(struct imsgbuf))) == NULL)
fatal(NULL); fatal(NULL);
@ -166,6 +180,12 @@ ntp_main(int pipe_prnt[2], int fd_ctl, struct ntpd_conf *nconf,
fatal(NULL); fatal(NULL);
imsg_init(ibuf_dns, pipe_dns[0]); imsg_init(ibuf_dns, pipe_dns[0]);
constraint_cnt = 0;
conf->constraint_median = 0;
conf->constraint_last = getmonotime();
TAILQ_FOREACH(cstr, &conf->constraints, entry)
constraint_cnt += constraint_init(cstr);
TAILQ_FOREACH(p, &conf->ntp_peers, entry) TAILQ_FOREACH(p, &conf->ntp_peers, entry)
client_peer_init(p); client_peer_init(p);
@ -213,7 +233,8 @@ ntp_main(int pipe_prnt[2], int fd_ctl, struct ntpd_conf *nconf,
idx2peer_elms = peer_cnt; idx2peer_elms = peer_cnt;
} }
new_cnt = PFD_MAX + peer_cnt + listener_cnt + ctl_cnt;
new_cnt = PFD_MAX +
peer_cnt + listener_cnt + ctl_cnt + constraint_cnt;
if (new_cnt > pfd_elms) { if (new_cnt > pfd_elms) {
if ((newp = reallocarray(pfd, new_cnt, if ((newp = reallocarray(pfd, new_cnt,
sizeof(*pfd))) == NULL) { sizeof(*pfd))) == NULL) {
@ -248,6 +269,9 @@ ntp_main(int pipe_prnt[2], int fd_ctl, struct ntpd_conf *nconf,
idx_peers = i; idx_peers = i;
sent_cnt = trial_cnt = 0; sent_cnt = trial_cnt = 0;
TAILQ_FOREACH(p, &conf->ntp_peers, entry) { TAILQ_FOREACH(p, &conf->ntp_peers, entry) {
if (constraint_cnt && conf->constraint_median == 0)
continue;
if (p->next > 0 && p->next <= getmonotime()) { if (p->next > 0 && p->next <= getmonotime()) {
if (p->state > STATE_DNS_INPROGRESS) if (p->state > STATE_DNS_INPROGRESS)
trial_cnt++; trial_cnt++;
@ -326,8 +350,23 @@ ntp_main(int pipe_prnt[2], int fd_ctl, struct ntpd_conf *nconf,
pfd[i].events |= POLLOUT; pfd[i].events |= POLLOUT;
i++; i++;
} }
ctls = i;
timeout = nextaction - getmonotime();
boundaries = 0;
TAILQ_FOREACH(cstr, &conf->constraints, entry) {
if (constraint_query(cstr) == -1)
continue;
pfd[i].fd = cstr->fd;
pfd[i].events = POLLIN;
i++;
}
boundaries = i;
now = getmonotime();
if (constraint_cnt)
nextaction = now + 1;
timeout = nextaction - now;
if (timeout < 0) if (timeout < 0)
timeout = 0; timeout = 0;
@ -389,8 +428,13 @@ ntp_main(int pipe_prnt[2], int fd_ctl, struct ntpd_conf *nconf,
} }
} }
for (; nfds > 0 && j < i; j++)
for (; nfds > 0 && j < ctls; j++) {
nfds -= control_dispatch_msg(&pfd[j], &ctl_cnt); nfds -= control_dispatch_msg(&pfd[j], &ctl_cnt);
}
for (; nfds > 0 && j < i; j++) {
nfds -= constraint_dispatch_msg(&pfd[j]);
}
for (s = TAILQ_FIRST(&conf->ntp_sensors); s != NULL; for (s = TAILQ_FIRST(&conf->ntp_sensors); s != NULL;
s = next_s) { s = next_s) {
@ -400,6 +444,11 @@ ntp_main(int pipe_prnt[2], int fd_ctl, struct ntpd_conf *nconf,
} }
report_peers(ntp_report); report_peers(ntp_report);
ntp_report = 0; ntp_report = 0;
if (ntp_sigchld) {
constraint_check_child();
ntp_sigchld = 0;
}
} }
msgbuf_write(&ibuf_main->w); msgbuf_write(&ibuf_main->w);


+ 3
- 2
src/usr.sbin/ntpd/ntpctl.8 View File

@ -1,4 +1,4 @@
.\" $OpenBSD: ntpctl.8,v 1.6 2014/01/22 02:55:15 benno Exp $
.\" $OpenBSD: ntpctl.8,v 1.7 2015/02/10 06:40:08 reyk Exp $
.\" .\"
.\" Copyright (c) 2012 Mike Miller <mmiller@mgm51.com> .\" Copyright (c) 2012 Mike Miller <mmiller@mgm51.com>
.\" .\"
@ -14,7 +14,7 @@
.\" AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT .\" AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
.\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.Dd $Mdocdate: January 22 2014 $
.Dd $Mdocdate: February 10 2015 $
.Dt NTPCTL 8 .Dt NTPCTL 8
.Os .Os
.Sh NAME .Sh NAME
@ -53,6 +53,7 @@ When the system clock is not synced, the offset of the system clock,
as reported by the as reported by the
.Xr adjtime 2 .Xr adjtime 2
system call, is displayed. system call, is displayed.
When the median constraint is set, the offset to the local time is displayed.
.El .El
.Sh FILES .Sh FILES
.Bl -tag -width "/var/run/ntpd.sockXXX" -compact .Bl -tag -width "/var/run/ntpd.sockXXX" -compact


+ 14
- 1
src/usr.sbin/ntpd/ntpd.c View File

@ -1,4 +1,4 @@
/* $OpenBSD: ntpd.c,v 1.88 2015/01/21 03:14:10 bcook Exp $ */
/* $OpenBSD: ntpd.c,v 1.89 2015/02/10 06:40:08 reyk Exp $ */
/* /*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@ -709,6 +709,7 @@ show_status_msg(struct imsg *imsg)
{ {
struct ctl_show_status *cstatus; struct ctl_show_status *cstatus;
double clock_offset; double clock_offset;
struct timeval tv;
if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(struct ctl_show_status)) if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(struct ctl_show_status))
fatalx("invalid IMSG_CTL_SHOW_STATUS received"); fatalx("invalid IMSG_CTL_SHOW_STATUS received");
@ -723,6 +724,18 @@ show_status_msg(struct imsg *imsg)
printf("%d/%d sensors valid, ", printf("%d/%d sensors valid, ",
cstatus->valid_sensors, cstatus->sensorcnt); cstatus->valid_sensors, cstatus->sensorcnt);
if (cstatus->constraint_median) {
tv.tv_sec = cstatus->constraint_median +
(getmonotime() - cstatus->constraint_last);
tv.tv_usec = 0;
printf("constraint offset %f",
gettime_from_timeval(&tv) - gettime());
if (cstatus->constraint_errors)
printf(" (%d errors)",
cstatus->constraint_errors);
printf(", ");
}
if (cstatus->peercnt + cstatus->sensorcnt == 0) if (cstatus->peercnt + cstatus->sensorcnt == 0)
printf("no peers and no sensors configured\n"); printf("no peers and no sensors configured\n");


+ 36
- 2
src/usr.sbin/ntpd/ntpd.conf.5 View File

@ -1,4 +1,4 @@
.\" $OpenBSD: ntpd.conf.5,v 1.24 2012/09/20 12:43:16 patrick Exp $
.\" $OpenBSD: ntpd.conf.5,v 1.25 2015/02/10 06:40:08 reyk Exp $
.\" .\"
.\" Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> .\" Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
.\" .\"
@ -14,7 +14,7 @@
.\" AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT .\" AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
.\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.Dd $Mdocdate: September 20 2012 $
.Dd $Mdocdate: February 10 2015 $
.Dt NTPD.CONF 5 .Dt NTPD.CONF 5
.Os .Os
.Sh NAME .Sh NAME
@ -35,6 +35,40 @@ character are ignored.
Keywords may be specified multiple times within the configuration file. Keywords may be specified multiple times within the configuration file.
They are as follows: They are as follows:
.Bl -tag -width Ds .Bl -tag -width Ds
.It Ic constraint from Ar url
Specify the URL, IP address or the hostname of a HTTPS server to
provide a constraint.
.Xr ntpd 8
will connect to the server and retrieve the remote time from the
.Eq Date
header.
This time will be used as a constraint on time synchronization;
received NTP packets with time information that is more than a few
minutes off will be discarded and the NTP
.Ic server
will be marked as invalid.
If multiple
.Ic constraint
keywords are used,
.Xr ntpd 8
will calculate a median constraint from all the servers specified.
.Bd -literal -offset indent
server ntp.example.org
constraint www.example.com
.Ed
.It Ic constraints from Ar url
As with
.Ic constraint ,
specify the URL, IP address or the hostname of a HTTPS server to
provide a constraint.
Should the hostname resolve to multiple IP addresses,
.Xr ntpd 8
will calculate a median constraint from all of them.
For example:
.Bd -literal -offset indent
servers pool.ntp.org
constraints from "https://www.google.com/search?q=openntpd"
.Ed
.It Xo Ic listen on Ar address .It Xo Ic listen on Ar address
.Op Ic rtable Ar table-id .Op Ic rtable Ar table-id
.Xc .Xc


+ 47
- 3
src/usr.sbin/ntpd/ntpd.h View File

@ -1,4 +1,4 @@
/* $OpenBSD: ntpd.h,v 1.117 2015/01/13 02:28:56 bcook Exp $ */
/* $OpenBSD: ntpd.h,v 1.118 2015/02/10 06:40:08 reyk Exp $ */
/* /*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@ -72,16 +72,26 @@
#define SENSOR_DATA_MAXAGE (15*60) #define SENSOR_DATA_MAXAGE (15*60)
#define SENSOR_QUERY_INTERVAL 15 #define SENSOR_QUERY_INTERVAL 15
#define SENSOR_QUERY_INTERVAL_SETTIME (SETTIME_TIMEOUT/3) #define SENSOR_QUERY_INTERVAL_SETTIME (SETTIME_TIMEOUT/3)
#define SENSOR_SCAN_INTERVAL (5*60)
#define SENSOR_SCAN_INTERVAL (1*60)
#define SENSOR_DEFAULT_REFID "HARD" #define SENSOR_DEFAULT_REFID "HARD"
#define CONSTRAINT_ERROR_MARGIN (4)
#define CONSTRAINT_SCAN_INTERVAL (15*60)
#define CONSTRAINT_SCAN_TIMEOUT (10)
#define CONSTRAINT_MARGIN (2.0*60)
#define CONSTRAINT_PORT "443" /* HTTPS port */
#define CONSTRAINT_MAXHEADERLENGTH 8192
#define CONSTRAINT_PASSFD (STDERR_FILENO + 1)
#define CONSTRAINT_CA "/etc/ssl/cert.pem"
enum client_state { enum client_state {
STATE_NONE, STATE_NONE,
STATE_DNS_INPROGRESS, STATE_DNS_INPROGRESS,
STATE_DNS_TEMPFAIL, STATE_DNS_TEMPFAIL,
STATE_DNS_DONE, STATE_DNS_DONE,
STATE_QUERY_SENT, STATE_QUERY_SENT,
STATE_REPLY_RECEIVED
STATE_REPLY_RECEIVED,
STATE_INVALID
}; };
struct listen_addr { struct listen_addr {
@ -99,6 +109,7 @@ struct ntp_addr {
struct ntp_addr_wrap { struct ntp_addr_wrap {
char *name; char *name;
char *path;
struct ntp_addr *a; struct ntp_addr *a;
u_int8_t pool; u_int8_t pool;
}; };
@ -160,6 +171,20 @@ struct ntp_sensor {
u_int8_t shift; u_int8_t shift;
}; };
struct constraint {
TAILQ_ENTRY(constraint) entry;
struct ntp_addr_wrap addr_head;
struct ntp_addr *addr;
int senderrors;
enum client_state state;
u_int32_t id;
int fd;
pid_t pid;
struct imsgbuf ibuf;
time_t last;
time_t constraint;
};
struct ntp_conf_sensor { struct ntp_conf_sensor {
TAILQ_ENTRY(ntp_conf_sensor) entry; TAILQ_ENTRY(ntp_conf_sensor) entry;
char *device; char *device;
@ -182,6 +207,7 @@ struct ntpd_conf {
TAILQ_HEAD(ntp_peers, ntp_peer) ntp_peers; TAILQ_HEAD(ntp_peers, ntp_peer) ntp_peers;
TAILQ_HEAD(ntp_sensors, ntp_sensor) ntp_sensors; TAILQ_HEAD(ntp_sensors, ntp_sensor) ntp_sensors;
TAILQ_HEAD(ntp_conf_sensors, ntp_conf_sensor) ntp_conf_sensors; TAILQ_HEAD(ntp_conf_sensors, ntp_conf_sensor) ntp_conf_sensors;
TAILQ_HEAD(constraints, constraint) constraints;
struct ntp_status status; struct ntp_status status;
struct ntp_freq freq; struct ntp_freq freq;
u_int32_t scale; u_int32_t scale;
@ -190,6 +216,11 @@ struct ntpd_conf {
u_int8_t debug; u_int8_t debug;
u_int8_t noaction; u_int8_t noaction;
u_int8_t filters; u_int8_t filters;
time_t constraint_last;
time_t constraint_median;
u_int constraint_errors;
u_int8_t *ca;
size_t ca_len;
}; };
struct ctl_show_status { struct ctl_show_status {
@ -200,6 +231,9 @@ struct ctl_show_status {
u_int8_t synced; u_int8_t synced;
u_int8_t stratum; u_int8_t stratum;
double clock_offset; double clock_offset;
time_t constraint_median;
time_t constraint_last;
u_int constraint_errors;
}; };
struct ctl_show_peer { struct ctl_show_peer {
@ -245,6 +279,7 @@ enum imsg_type {
IMSG_ADJFREQ, IMSG_ADJFREQ,
IMSG_SETTIME, IMSG_SETTIME,
IMSG_HOST_DNS, IMSG_HOST_DNS,
IMSG_CONSTRAINT,
IMSG_CTL_SHOW_STATUS, IMSG_CTL_SHOW_STATUS,
IMSG_CTL_SHOW_PEERS, IMSG_CTL_SHOW_PEERS,
IMSG_CTL_SHOW_PEERS_END, IMSG_CTL_SHOW_PEERS_END,
@ -284,6 +319,7 @@ int host_dns(const char *, struct ntp_addr **);
void host_dns_free(struct ntp_addr *); void host_dns_free(struct ntp_addr *);
struct ntp_peer *new_peer(void); struct ntp_peer *new_peer(void);
struct ntp_conf_sensor *new_sensor(char *); struct ntp_conf_sensor *new_sensor(char *);
struct constraint *new_constraint(void);
/* ntp_msg.c */ /* ntp_msg.c */
int ntp_getmsg(struct sockaddr *, char *, ssize_t, struct ntp_msg *); int ntp_getmsg(struct sockaddr *, char *, ssize_t, struct ntp_msg *);
@ -303,8 +339,16 @@ int client_dispatch(struct ntp_peer *, u_int8_t);
void client_log_error(struct ntp_peer *, const char *, int); void client_log_error(struct ntp_peer *, const char *, int);
void set_next(struct ntp_peer *, time_t); void set_next(struct ntp_peer *, time_t);
/* constraint.c */
int constraint_init(struct constraint *);
int constraint_query(struct constraint *);
int constraint_dispatch_msg(struct pollfd *);
void constraint_check_child(void);
int constraint_check(double);
/* util.c */ /* util.c */
double gettime_corrected(void); double gettime_corrected(void);
double gettime_from_timeval(struct timeval *);
double getoffset(void); double getoffset(void);
double gettime(void); double gettime(void);
time_t getmonotime(void); time_t getmonotime(void);


+ 122
- 3
src/usr.sbin/ntpd/parse.y View File

@ -1,4 +1,4 @@
/* $OpenBSD: parse.y,v 1.57 2015/01/10 13:47:05 tedu Exp $ */
/* $OpenBSD: parse.y,v 1.58 2015/02/10 06:40:08 reyk Exp $ */
/* /*
* Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org> * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
@ -80,12 +80,12 @@ typedef struct {
%} %}
%token LISTEN ON
%token LISTEN ON CONSTRAINT CONSTRAINTS FROM
%token SERVER SERVERS SENSOR CORRECTION RTABLE REFID STRATUM WEIGHT %token SERVER SERVERS SENSOR CORRECTION RTABLE REFID STRATUM WEIGHT
%token ERROR %token ERROR
%token <v.string> STRING %token <v.string> STRING
%token <v.number> NUMBER %token <v.number> NUMBER
%type <v.addr> address
%type <v.addr> address url
%type <v.opts> listen_opts listen_opts_l listen_opt %type <v.opts> listen_opts listen_opts_l listen_opt
%type <v.opts> server_opts server_opts_l server_opt %type <v.opts> server_opts server_opts_l server_opt
%type <v.opts> sensor_opts sensor_opts_l sensor_opt %type <v.opts> sensor_opts sensor_opts_l sensor_opt
@ -208,6 +208,82 @@ main : LISTEN ON address listen_opts {
free($2->name); free($2->name);
free($2); free($2);
} }
| CONSTRAINTS FROM url {
struct constraint *p;
struct ntp_addr *h, *next;
h = $3->a;
do {
if (h != NULL) {
next = h->next;
if (h->ss.ss_family != AF_INET &&
h->ss.ss_family != AF_INET6) {
yyerror("IPv4 or IPv6 address "
"or hostname expected");
free(h);
free($3->name);
free($3->path);
free($3);
YYERROR;
}
h->next = NULL;
} else
next = NULL;
p = new_constraint();
p->addr = h;
p->addr_head.a = h;
p->addr_head.pool = 1;
p->addr_head.name = strdup($3->name);
p->addr_head.path = strdup($3->path);
if (p->addr_head.name == NULL ||
p->addr_head.path == NULL)
fatal(NULL);
if (p->addr != NULL)
p->state = STATE_DNS_DONE;
TAILQ_INSERT_TAIL(&conf->constraints,
p, entry);
h = next;
} while (h != NULL);
free($3->name);
free($3);
}
| CONSTRAINT FROM url {
struct constraint *p;
struct ntp_addr *h, *next;
p = new_constraint();
for (h = $3->a; h != NULL; h = next) {
next = h->next;
if (h->ss.ss_family != AF_INET &&
h->ss.ss_family != AF_INET6) {
yyerror("IPv4 or IPv6 address "
"or hostname expected");
free(h);
free(p);
free($3->name);
free($3->path);
free($3);
YYERROR;
}
h->next = p->addr;
p->addr = h;
}
p->addr_head.a = p->addr;
p->addr_head.pool = 0;
p->addr_head.name = strdup($3->name);
p->addr_head.path = strdup($3->path);
if (p->addr_head.name == NULL ||
p->addr_head.path == NULL)
fatal(NULL);
if (p->addr != NULL)
p->state = STATE_DNS_DONE;
TAILQ_INSERT_TAIL(&conf->constraints, p, entry);
free($3->name);
free($3);
}
| SENSOR STRING sensor_opts { | SENSOR STRING sensor_opts {
struct ntp_conf_sensor *s; struct ntp_conf_sensor *s;
@ -230,6 +306,45 @@ address : STRING {
} }
; ;
url : STRING {
char *hname, *path;
if (($$ = calloc(1, sizeof(struct ntp_addr_wrap))) ==
NULL)
fatal("calloc");
if (strncmp("https://", $1,
strlen("https://")) != 0) {
host($1, &$$->a);
$$->name = $1;
if (($$->path = strdup("/")) == NULL)
fatal("strdup");
} else {
hname = $1 + strlen("https://");
path = hname + strcspn(hname, "/\\");
if (*path == '\0')
path = "/";
if (($$->path = strdup(path)) == NULL)
fatal("strdup");
*path = '\0';
host(hname, &$$->a);
if (($$->name = strdup(hname)) == NULL)
fatal("strdup");
}
if ($$->a == NULL &&
(host_dns($$->name, &$$->a) == -1 ||
$$->a == NULL)) {
yyerror("could not resolve \"%s\"", $$->name);
free($$->name);
free($$->path);
free($$);
YYERROR;
}
}
;
listen_opts : { opts_default(); } listen_opts : { opts_default(); }
listen_opts_l listen_opts_l
{ $$ = opts; } { $$ = opts; }
@ -358,7 +473,10 @@ lookup(char *s)
{ {
/* this has to be sorted always */ /* this has to be sorted always */
static const struct keywords keywords[] = { static const struct keywords keywords[] = {
{ "constraint", CONSTRAINT},
{ "constraints", CONSTRAINTS},
{ "correction", CORRECTION}, { "correction", CORRECTION},
{ "from", FROM},
{ "listen", LISTEN}, { "listen", LISTEN},
{ "on", ON}, { "on", ON},
{ "refid", REFID}, { "refid", REFID},
@ -646,6 +764,7 @@ parse_config(const char *filename, struct ntpd_conf *xconf)
TAILQ_INIT(&conf->listen_addrs); TAILQ_INIT(&conf->listen_addrs);
TAILQ_INIT(&conf->ntp_peers); TAILQ_INIT(&conf->ntp_peers);
TAILQ_INIT(&conf->ntp_conf_sensors); TAILQ_INIT(&conf->ntp_conf_sensors);
TAILQ_INIT(&conf->constraints);
if ((file = pushfile(filename)) == NULL) { if ((file = pushfile(filename)) == NULL) {
return (-1); return (-1);


+ 7
- 1
src/usr.sbin/ntpd/util.c View File

@ -1,4 +1,4 @@
/* $OpenBSD: util.c,v 1.16 2015/01/04 01:11:24 bcook Exp $ */
/* $OpenBSD: util.c,v 1.17 2015/02/10 06:40:08 reyk Exp $ */
/* /*
* Copyright (c) 2004 Alexander Guy <alexander.guy@andern.org> * Copyright (c) 2004 Alexander Guy <alexander.guy@andern.org>
@ -48,6 +48,12 @@ gettime(void)
return (tv.tv_sec + JAN_1970 + 1.0e-6 * tv.tv_usec); return (tv.tv_sec + JAN_1970 + 1.0e-6 * tv.tv_usec);
} }
double
gettime_from_timeval(struct timeval *tv)
{
return (tv->tv_sec + JAN_1970 + 1.0e-6 * tv->tv_usec);
}
time_t time_t
getmonotime(void) getmonotime(void)
{ {


Loading…
Cancel
Save