add option "query from <ip>" to ntpd.conf, to specify a local IP
authorbenno <benno@openbsd.org>
Tue, 30 May 2017 23:30:48 +0000 (23:30 +0000)
committerbenno <benno@openbsd.org>
Tue, 30 May 2017 23:30:48 +0000 (23:30 +0000)
address for outgoing ntp queries.
From Job Snijders, thanks!
with feedback and ok henning@

usr.sbin/ntpd/client.c
usr.sbin/ntpd/ntp.c
usr.sbin/ntpd/ntpd.conf.5
usr.sbin/ntpd/ntpd.h
usr.sbin/ntpd/parse.y

index ad53f60..3de5268 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: client.c,v 1.104 2016/09/03 11:52:06 reyk Exp $ */
+/*     $OpenBSD: client.c,v 1.105 2017/05/30 23:30:48 benno Exp $ */
 
 /*
  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -137,11 +137,23 @@ client_query(struct ntp_peer *p)
 
        if (p->query->fd == -1) {
                struct sockaddr *sa = (struct sockaddr *)&p->addr->ss;
+               struct sockaddr *qa4 = (struct sockaddr *)&p->query_addr4;
+               struct sockaddr *qa6 = (struct sockaddr *)&p->query_addr6;
 
                if ((p->query->fd = socket(p->addr->ss.ss_family, SOCK_DGRAM,
                    0)) == -1)
                        fatal("client_query socket");
 
+               if (p->addr->ss.ss_family == qa4->sa_family) {
+                       if (bind(p->query->fd, qa4, SA_LEN(qa4)) == -1)
+                               fatal("couldn't bind to IPv4 query address: %s",
+                                   log_sockaddr(qa4));
+               } else if (p->addr->ss.ss_family == qa6->sa_family) {
+                       if (bind(p->query->fd, qa6, SA_LEN(qa6)) == -1)
+                               fatal("couldn't bind to IPv6 query address: %s",
+                                   log_sockaddr(qa6));
+               }
+
                if (connect(p->query->fd, sa, SA_LEN(sa)) == -1) {
                        if (errno == ECONNREFUSED || errno == ENETUNREACH ||
                            errno == EHOSTUNREACH || errno == EADDRNOTAVAIL) {
index 2fbaaf7..f7a6ede 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ntp.c,v 1.145 2017/01/20 01:21:18 phessler Exp $ */
+/*     $OpenBSD: ntp.c,v 1.146 2017/05/30 23:30:48 benno Exp $ */
 
 /*
  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -521,6 +521,8 @@ ntp_dispatch_imsg_dns(void)
                                if (peer->addr_head.pool) {
                                        npeer = new_peer();
                                        npeer->weight = peer->weight;
+                                       npeer->query_addr4 = peer->query_addr4;
+                                       npeer->query_addr6 = peer->query_addr6;
                                        h->next = NULL;
                                        npeer->addr = h;
                                        npeer->addr_head.a = h;
index 4d2d15c..963ce27 100644 (file)
@@ -1,4 +1,4 @@
-.\" $OpenBSD: ntpd.conf.5,v 1.34 2016/12/30 10:24:15 jmc Exp $
+.\" $OpenBSD: ntpd.conf.5,v 1.35 2017/05/30 23:30:48 benno Exp $
 .\"
 .\" Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
 .\"
@@ -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: December 30 2016 $
+.Dd $Mdocdate: May 30 2017 $
 .Dt NTPD.CONF 5
 .Os
 .Sh NAME
@@ -67,6 +67,14 @@ or
 listen on 127.0.0.1
 listen on ::1
 listen on 127.0.0.1 rtable 4
+.It Xo Ic query from Ar address
+.Xc
+Specify a Local IP address the
+.Xr ntpd 8
+daemon should use for outgoing queries.
+.Bd -literal -offset indent
+query from 192.0.2.1
+query from 2001:db8::1
 .Ed
 .It Xo Ic sensor Ar device
 .Op Ic correction Ar microseconds
index fb9cd87..30ef206 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ntpd.h,v 1.134 2017/01/09 14:49:22 reyk Exp $ */
+/*     $OpenBSD: ntpd.h,v 1.135 2017/05/30 23:30:48 benno Exp $ */
 
 /*
  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -153,6 +153,8 @@ struct ntp_peer {
        struct ntp_query                *query;
        struct ntp_offset                reply[OFFSET_ARRAY_SIZE];
        struct ntp_offset                update;
+       struct sockaddr_in               query_addr4;
+       struct sockaddr_in6              query_addr6;
        enum client_state                state;
        time_t                           next;
        time_t                           deadline;
@@ -219,6 +221,8 @@ struct ntpd_conf {
        TAILQ_HEAD(constraints, constraint)             constraints;
        struct ntp_status                               status;
        struct ntp_freq                                 freq;
+       struct sockaddr_in                              query_addr4;
+       struct sockaddr_in6                             query_addr6;
        u_int32_t                                       scale;
        int                                             debug;
        int                                             verbose;
index 8da19a2..af4ad17 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: parse.y,v 1.65 2015/10/31 19:32:18 naddy Exp $ */
+/*     $OpenBSD: parse.y,v 1.66 2017/05/30 23:30:48 benno Exp $ */
 
 /*
  * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -58,6 +58,8 @@ int            lungetc(int);
 int             findeol(void);
 
 struct ntpd_conf               *conf;
+struct sockaddr_in              query_addr4;
+struct sockaddr_in6             query_addr6;
 
 struct opts {
        int             weight;
@@ -80,7 +82,7 @@ typedef struct {
 
 %}
 
-%token LISTEN ON CONSTRAINT CONSTRAINTS FROM
+%token LISTEN ON CONSTRAINT CONSTRAINTS FROM QUERY
 %token SERVER SERVERS SENSOR CORRECTION RTABLE REFID STRATUM WEIGHT
 %token ERROR
 %token <v.string>              STRING
@@ -130,6 +132,28 @@ main               : LISTEN ON address listen_opts {
                        free($3->name);
                        free($3);
                }
+               | QUERY FROM STRING {
+                       struct sockaddr_in sin4;
+                       struct sockaddr_in6 sin6;
+
+                       sin4.sin_family = AF_INET;
+                       sin4.sin_len = sizeof(struct sockaddr_in);
+                       sin6.sin6_family = AF_INET6;
+                       sin6.sin6_len = sizeof(struct sockaddr_in6);
+
+                       if (inet_pton(AF_INET, $3, &sin4.sin_addr) == 1)
+                               memcpy(&query_addr4, &sin4, sin4.sin_len);
+                       else if (inet_pton(AF_INET6, $3, &sin6.sin6_addr) == 1)
+                               memcpy(&query_addr6, &sin6, sin6.sin6_len);
+                       else {
+                               yyerror("invalid IPv4 or IPv6 address: %s\n",
+                                   $3);
+                               free($3);
+                               YYERROR;
+                       }
+
+                       free($3);
+               }
                | SERVERS address server_opts   {
                        struct ntp_peer         *p;
                        struct ntp_addr         *h, *next;
@@ -153,6 +177,8 @@ main                : LISTEN ON address listen_opts {
 
                                p = new_peer();
                                p->weight = $3.weight;
+                               p->query_addr4 = query_addr4;
+                               p->query_addr6 = query_addr6;
                                p->addr = h;
                                p->addr_head.a = h;
                                p->addr_head.pool = 1;
@@ -190,6 +216,8 @@ main                : LISTEN ON address listen_opts {
                        }
 
                        p->weight = $3.weight;
+                       p->query_addr4 = query_addr4;
+                       p->query_addr6 = query_addr6;
                        p->addr_head.a = p->addr;
                        p->addr_head.pool = 0;
                        p->addr_head.name = strdup($2->name);
@@ -461,6 +489,7 @@ lookup(char *s)
                { "from",               FROM},
                { "listen",             LISTEN},
                { "on",                 ON},
+               { "query",              QUERY},
                { "refid",              REFID},
                { "rtable",             RTABLE},
                { "sensor",             SENSOR},