diff --git a/src/usr.sbin/ntpd/client.c b/src/usr.sbin/ntpd/client.c index 807ba8db..c6f20a25 100644 --- a/src/usr.sbin/ntpd/client.c +++ b/src/usr.sbin/ntpd/client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: client.c,v 1.88 2009/06/24 17:34:32 henning Exp $ */ +/* $OpenBSD: client.c,v 1.89 2011/09/21 15:41:30 phessler Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -134,12 +134,20 @@ client_query(struct ntp_peer *p) if (p->state < STATE_DNS_DONE || p->addr == NULL) return (-1); + if (p->addr->ss.ss_family != AF_INET && p->rtable != -1) + return (-1); + if (p->query->fd == -1) { struct sockaddr *sa = (struct sockaddr *)&p->addr->ss; if ((p->query->fd = socket(p->addr->ss.ss_family, SOCK_DGRAM, 0)) == -1) fatal("client_query socket"); + + if (p->addr->ss.ss_family == AF_INET && p->rtable != -1 && + setsockopt(p->query->fd, IPPROTO_IP, SO_RTABLE, + &p->rtable, sizeof(p->rtable)) == -1) + fatal("client_query setsockopt SO_RTABLE"); if (connect(p->query->fd, sa, SA_LEN(sa)) == -1) { if (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EHOSTUNREACH || errno == EADDRNOTAVAIL) { @@ -243,6 +251,11 @@ client_dispatch(struct ntp_peer *p, u_int8_t settime) return (0); } + if (p->rtable != -1 && + setsockopt(p->query->fd, IPPROTO_IP, SO_RTABLE, &p->rtable, + sizeof(p->rtable)) == -1) + fatal("client_dispatch setsockopt SO_RTABLE"); + for (cmsg = CMSG_FIRSTHDR(&somsg); cmsg != NULL; cmsg = CMSG_NXTHDR(&somsg, cmsg)) { if (cmsg->cmsg_level == SOL_SOCKET && @@ -374,8 +387,10 @@ client_dispatch(struct ntp_peer *p, u_int8_t settime) } log_debug("reply from %s: offset %f delay %f, " - "next query %ds", log_sockaddr((struct sockaddr *)&p->addr->ss), - p->reply[p->shift].offset, p->reply[p->shift].delay, interval); + "next query %ds %s", + log_sockaddr((struct sockaddr *)&p->addr->ss), + p->reply[p->shift].offset, p->reply[p->shift].delay, interval, + print_rtable(p->rtable)); client_update(p); if (settime) diff --git a/src/usr.sbin/ntpd/ntp.c b/src/usr.sbin/ntpd/ntp.c index f4c6c88c..23713fc5 100644 --- a/src/usr.sbin/ntpd/ntp.c +++ b/src/usr.sbin/ntpd/ntp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ntp.c,v 1.116 2011/06/17 18:12:05 henning Exp $ */ +/* $OpenBSD: ntp.c,v 1.117 2011/09/21 15:41:30 phessler Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -245,8 +245,9 @@ ntp_main(int pipe_prnt[2], struct ntpd_conf *nconf, struct passwd *pw) if (p->deadline > 0 && p->deadline <= getmonotime()) { timeout = 300; log_debug("no reply from %s received in time, " - "next query %ds", log_sockaddr( - (struct sockaddr *)&p->addr->ss), timeout); + "next query %ds %s", log_sockaddr( + (struct sockaddr *)&p->addr->ss), timeout, + print_rtable(p->rtable)); if (p->trustlevel >= TRUSTLEVEL_BADPEER && (p->trustlevel /= 2) < TRUSTLEVEL_BADPEER) log_info("peer %s now invalid", @@ -482,6 +483,7 @@ ntp_dispatch_imsg_dns(void) npeer->addr_head.name = peer->addr_head.name; npeer->addr_head.pool = 1; + npeer->rtable = peer->rtable; client_peer_init(npeer); npeer->state = STATE_DNS_DONE; peer_add(npeer); @@ -770,8 +772,9 @@ report_peers(int always) (struct sockaddr *)&p->addr->ss); if (p->addr_head.pool) pool = "from pool "; - log_warnx("bad peer %s%s (%s)", pool, - p->addr_head.name, a); + log_warnx("bad peer %s%s (%s) %s", + pool, p->addr_head.name, a, + print_rtable(p->rtable)); } } } diff --git a/src/usr.sbin/ntpd/ntpd.conf.5 b/src/usr.sbin/ntpd/ntpd.conf.5 index 1a80a206..ca000971 100644 --- a/src/usr.sbin/ntpd/ntpd.conf.5 +++ b/src/usr.sbin/ntpd/ntpd.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ntpd.conf.5,v 1.22 2009/05/18 20:08:24 stevesk Exp $ +.\" $OpenBSD: ntpd.conf.5,v 1.23 2011/09/21 15:41:30 phessler Exp $ .\" .\" Copyright (c) 2003, 2004 Henning Brauer .\" @@ -14,7 +14,7 @@ .\" AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT .\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: May 18 2009 $ +.Dd $Mdocdate: September 21 2011 $ .Dt NTPD.CONF 5 .Os .Sh NAME @@ -35,7 +35,9 @@ character are ignored. Keywords may be specified multiple times within the configuration file. They are as follows: .Bl -tag -width Ds -.It Ic listen on Ar address +.It Xo Ic listen on Ar address +.Op Ic rtable Ar table-id +.Xc Specify a local IP address or a hostname the .Xr ntpd 8 daemon should listen on. @@ -46,9 +48,15 @@ If .Sq * is given as an address, .Xr ntpd 8 -will listen on all local addresses. +will listen on all local addresses using the specified routing table. .Xr ntpd 8 does not listen on any address by default. +The optional +.Ic rtable +keyword will specify which routing table to listen on. +By default +.Xr ntpd 8 +will listen using the current routing table. For example: .Bd -literal -offset indent listen on * @@ -58,6 +66,7 @@ or .Bd -literal -offset indent listen on 127.0.0.1 listen on ::1 +listen on 127.0.0.1 rtable 4 .Ed .It Xo Ic sensor Ar device .Op Ic correction Ar microseconds @@ -117,12 +126,17 @@ sensor nmea0 refid GPS .Ed .It Xo Ic server Ar address .Op Ic weight Ar weight-value +.Op Ic rtable Ar table-id .Xc Specify the IP address or the hostname of an NTP server to synchronize to. If it appears multiple times, .Xr ntpd 8 will try to synchronize to all of the servers specified. +The +.Cm rtable +option specifies which routing table should be used for connection attempts. +Hostname resolution will still happen using the default routing table. If a hostname resolves to multiple IPv4 and/or IPv6 addresses, .Xr ntpd 8 uses the first address. @@ -133,7 +147,7 @@ is found. For example: .Bd -literal -offset indent server 10.0.0.2 weight 5 -server ntp.example.org weight 1 +server ntp.example.org weight 1 rtable 4 .Ed .Pp To provide redundancy, it is good practice to configure multiple servers. @@ -141,6 +155,7 @@ In general, best accuracy is obtained by using servers that have a low network latency. .It Xo Ic servers Ar address .Op Ic weight Ar weight-value +.Op Ic rtable Ar table-id .Xc As with .Cm server , @@ -154,6 +169,7 @@ will try to synchronize to all of them. For example: .Bd -literal -offset indent servers pool.ntp.org +servers pool.ntp.org rtable 5 .Ed .El .Sh FILES @@ -171,3 +187,9 @@ The .Nm file format first appeared in .Ox 3.6 . +.Sh CAVEATS +When using different +.Cm rtable +options, +.Xr ntpd 8 +must be started in rtable 0. diff --git a/src/usr.sbin/ntpd/ntpd.h b/src/usr.sbin/ntpd/ntpd.h index 9546bb33..1140eaf2 100644 --- a/src/usr.sbin/ntpd/ntpd.h +++ b/src/usr.sbin/ntpd/ntpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ntpd.h,v 1.103 2009/06/06 18:45:01 ckuethe Exp $ */ +/* $OpenBSD: ntpd.h,v 1.104 2011/09/21 15:41:30 phessler Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -81,11 +81,13 @@ struct listen_addr { TAILQ_ENTRY(listen_addr) entry; struct sockaddr_storage sa; int fd; + int rtable; }; struct ntp_addr { struct ntp_addr *next; struct sockaddr_storage ss; + int rtable; }; struct ntp_addr_wrap { @@ -132,6 +134,7 @@ struct ntp_peer { u_int8_t weight; int lasterror; int senderrors; + int rtable; }; struct ntp_sensor { @@ -247,6 +250,7 @@ double lfp_to_d(struct l_fixedpt); struct l_fixedpt d_to_lfp(double); double sfp_to_d(struct s_fixedpt); struct s_fixedpt d_to_sfp(double); +char *print_rtable(int); /* sensors.c */ void sensor_init(void); diff --git a/src/usr.sbin/ntpd/parse.y b/src/usr.sbin/ntpd/parse.y index 5751682b..2934b68d 100644 --- a/src/usr.sbin/ntpd/parse.y +++ b/src/usr.sbin/ntpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.47 2010/08/03 18:42:40 henning Exp $ */ +/* $OpenBSD: parse.y,v 1.48 2011/09/21 15:41:30 phessler Exp $ */ /* * Copyright (c) 2002, 2003, 2004 Henning Brauer @@ -60,6 +60,7 @@ struct ntpd_conf *conf; struct opts { int weight; int correction; + int rtable; char *refstr; } opts; void opts_default(void); @@ -77,14 +78,16 @@ typedef struct { %} %token LISTEN ON -%token SERVER SERVERS SENSOR CORRECTION REFID WEIGHT +%token SERVER SERVERS SENSOR CORRECTION RTABLE REFID WEIGHT %token ERROR %token STRING %token NUMBER %type address +%type listen_opts listen_opts_l listen_opt %type server_opts server_opts_l server_opt %type sensor_opts sensor_opts_l sensor_opt %type correction +%type rtable %type refid %type weight %% @@ -95,11 +98,11 @@ grammar : /* empty */ | grammar error '\n' { file->errors++; } ; -main : LISTEN ON address { +main : LISTEN ON address listen_opts { struct listen_addr *la; struct ntp_addr *h, *next; - if ((h = $3->a) == NULL && + if ((h = $3->a) == NULL && (h->rtable = $4.rtable) && (host_dns($3->name, &h) == -1 || !h)) { yyerror("could not resolve \"%s\"", $3->name); free($3->name); @@ -109,15 +112,11 @@ main : LISTEN ON address { for (; h != NULL; h = next) { next = h->next; - if (h->ss.ss_family == AF_UNSPEC) { - conf->listen_all = 1; - free(h); - continue; - } la = calloc(1, sizeof(struct listen_addr)); if (la == NULL) fatal("listen on calloc"); la->fd = -1; + la->rtable = $4.rtable; memcpy(&la->sa, &h->ss, sizeof(struct sockaddr_storage)); TAILQ_INSERT_TAIL(&conf->listen_addrs, la, @@ -150,6 +149,7 @@ main : LISTEN ON address { p = new_peer(); p->weight = $3.weight; + p->rtable = $3.rtable; p->addr = h; p->addr_head.a = h; p->addr_head.pool = 1; @@ -158,8 +158,10 @@ main : LISTEN ON address { fatal(NULL); if (p->addr != NULL) p->state = STATE_DNS_DONE; - TAILQ_INSERT_TAIL(&conf->ntp_peers, p, entry); - + if (!(p->rtable > 0 && p->addr && + p->addr->ss.ss_family != AF_INET)) + TAILQ_INSERT_TAIL(&conf->ntp_peers, + p, entry); h = next; } while (h != NULL); @@ -188,6 +190,7 @@ main : LISTEN ON address { } p->weight = $3.weight; + p->rtable = $3.rtable; p->addr_head.a = p->addr; p->addr_head.pool = 0; p->addr_head.name = strdup($2->name); @@ -195,7 +198,9 @@ main : LISTEN ON address { fatal(NULL); if (p->addr != NULL) p->state = STATE_DNS_DONE; - TAILQ_INSERT_TAIL(&conf->ntp_peers, p, entry); + if (!(p->rtable > 0 && p->addr && + p->addr->ss.ss_family != AF_INET)) + TAILQ_INSERT_TAIL(&conf->ntp_peers, p, entry); free($2->name); free($2); } @@ -226,6 +231,17 @@ address : STRING { } ; +listen_opts : { opts_default(); } + listen_opts_l + { $$ = opts; } + | { opts_default(); $$ = opts; } + ; +listen_opts_l : listen_opts_l listen_opt + | listen_opt + ; +listen_opt : rtable + ; + server_opts : { opts_default(); } server_opts_l { $$ = opts; } @@ -235,6 +251,7 @@ server_opts_l : server_opts_l server_opt | server_opt ; server_opt : weight + | rtable ; sensor_opts : { opts_default(); } @@ -279,6 +296,13 @@ weight : WEIGHT NUMBER { } opts.weight = $2; } +rtable : RTABLE NUMBER { + if ($2 < 0 || $2 > RT_TABLEID_MAX) { + yyerror("rtable must be between 1 and RT_TABLEID_MAX"); + YYERROR; + } + opts.rtable = $2; + } ; %% @@ -288,6 +312,7 @@ opts_default(void) { bzero(&opts, sizeof opts); opts.weight = 1; + opts.rtable = -1; } struct keywords { @@ -326,6 +351,7 @@ lookup(char *s) { "listen", LISTEN}, { "on", ON}, { "refid", REFID}, + { "rtable", RTABLE}, { "sensor", SENSOR}, { "server", SERVER}, { "servers", SERVERS}, diff --git a/src/usr.sbin/ntpd/server.c b/src/usr.sbin/ntpd/server.c index 87dca9e5..21852468 100644 --- a/src/usr.sbin/ntpd/server.c +++ b/src/usr.sbin/ntpd/server.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server.c,v 1.35 2009/05/20 14:55:59 henning Exp $ */ +/* $OpenBSD: server.c,v 1.36 2011/09/21 15:41:30 phessler Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -17,8 +17,10 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include #include +#include #include #include #include @@ -30,51 +32,73 @@ int setup_listeners(struct servent *se, struct ntpd_conf *lconf, u_int *cnt) { - struct listen_addr *la; + struct listen_addr *la, *nla, *lap; struct ifaddrs *ifa, *ifap; struct sockaddr *sa; + struct ifreq ifr; u_int8_t *a6; size_t sa6len = sizeof(struct in6_addr); u_int new_cnt = 0; - int tos = IPTOS_LOWDELAY; - - if (lconf->listen_all) { - if (getifaddrs(&ifa) == -1) - fatal("getifaddrs"); - - for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) { - sa = ifap->ifa_addr; - - if (sa == NULL || - (sa->sa_family != AF_INET && - sa->sa_family != AF_INET6)) - continue; - if (SA_LEN(sa) == 0) - continue; - - if (sa->sa_family == AF_INET && - ((struct sockaddr_in *)sa)->sin_addr.s_addr == - INADDR_ANY) - continue; - - if (sa->sa_family == AF_INET6) { - a6 = ((struct sockaddr_in6 *)sa)-> - sin6_addr.s6_addr; - if (memcmp(a6, &in6addr_any, sa6len) == 0) + int tos = IPTOS_LOWDELAY, rdomain, fd; + + TAILQ_FOREACH(lap, &lconf->listen_addrs, entry) { + switch (lap->sa.ss_family) { + case AF_UNSPEC: + if (getifaddrs(&ifa) == -1) + fatal("getifaddrs"); + + for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) { + sa = ifap->ifa_addr; + if (sa == NULL || + (sa->sa_family != AF_INET && + sa->sa_family != AF_INET6)) + continue; + if (SA_LEN(sa) == 0) continue; - } - if ((la = calloc(1, sizeof(struct listen_addr))) == - NULL) - fatal("setup_listeners calloc"); + strlcpy(ifr.ifr_name, ifap->ifa_name, + sizeof(ifr.ifr_name)); - memcpy(&la->sa, sa, SA_LEN(sa)); - TAILQ_INSERT_TAIL(&lconf->listen_addrs, la, entry); - } + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (ioctl(fd, SIOCGIFRDOMAIN, + (caddr_t)&ifr) == -1) + rdomain = 0; + else + rdomain = ifr.ifr_rdomainid; + close(fd); + + if (lap->rtable != -1 && rdomain != lap->rtable) + continue; + + if (sa->sa_family == AF_INET && + ((struct sockaddr_in *)sa)->sin_addr.s_addr == + INADDR_ANY) + continue; + + if (sa->sa_family == AF_INET6) { + a6 = ((struct sockaddr_in6 *)sa)-> + sin6_addr.s6_addr; + if (memcmp(a6, &in6addr_any, sa6len) == 0) + continue; + } + + if ((la = calloc(1, sizeof(struct listen_addr))) == + NULL) + fatal("setup_listeners calloc"); + + memcpy(&la->sa, sa, SA_LEN(sa)); + la->rtable = rdomain; + + TAILQ_INSERT_TAIL(&lconf->listen_addrs, la, entry); + } - freeifaddrs(ifa); + freeifaddrs(ifa); + default: + continue; + } } + for (la = TAILQ_FIRST(&lconf->listen_addrs); la; ) { switch (la->sa.ss_family) { case AF_INET: @@ -87,12 +111,19 @@ setup_listeners(struct servent *se, struct ntpd_conf *lconf, u_int *cnt) ((struct sockaddr_in6 *)&la->sa)->sin6_port = se->s_port; break; + case AF_UNSPEC: + nla = TAILQ_NEXT(la, entry); + TAILQ_REMOVE(&lconf->listen_addrs, la, entry); + free(la); + la = nla; + continue; default: fatalx("king bula sez: af borked"); } - log_info("listening on %s", - log_sockaddr((struct sockaddr *)&la->sa)); + log_info("listening on %s %s", + log_sockaddr((struct sockaddr *)&la->sa), + print_rtable(la->rtable)); if ((la->fd = socket(la->sa.ss_family, SOCK_DGRAM, 0)) == -1) fatal("socket"); @@ -101,10 +132,13 @@ setup_listeners(struct servent *se, struct ntpd_conf *lconf, u_int *cnt) IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) == -1) log_warn("setsockopt IPTOS_LOWDELAY"); + if (la->sa.ss_family == AF_INET && la->rtable != -1 && + setsockopt(la->fd, IPPROTO_IP, SO_RTABLE, &la->rtable, + sizeof(la->rtable)) == -1) + fatal("setup_listeners setsockopt SO_RTABLE"); + if (bind(la->fd, (struct sockaddr *)&la->sa, SA_LEN((struct sockaddr *)&la->sa)) == -1) { - struct listen_addr *nla; - log_warn("bind on %s failed, skipping", log_sockaddr((struct sockaddr *)&la->sa)); close(la->fd); diff --git a/src/usr.sbin/ntpd/util.c b/src/usr.sbin/ntpd/util.c index 10075076..a9e02316 100644 --- a/src/usr.sbin/ntpd/util.c +++ b/src/usr.sbin/ntpd/util.c @@ -1,4 +1,4 @@ -/* $OpenBSD: util.c,v 1.13 2007/03/27 18:22:02 otto Exp $ */ +/* $OpenBSD: util.c,v 1.14 2011/09/21 15:41:30 phessler Exp $ */ /* * Copyright (c) 2004 Alexander Guy @@ -18,6 +18,7 @@ #include #include +#include #include "ntpd.h" @@ -117,3 +118,15 @@ d_to_sfp(double d) return (sfp); } + +char * +print_rtable(int r) +{ + static char b[11]; + + b[0] = 0; + if (r > 0) + snprintf(b, sizeof(b), "rtable %d", r); + + return(b); +}