Dear team,

Henning Brauer (off-list) made a few suggestions, which I summerized in
the following four points:

1) poor initialization style, instead of:
        struct xxx yyy = {
            .property = zzz
        };

    use:
        struct xxx yyy;
        yyy.property = zzz;

2) avoid creation of a dubiously named newly defined 'struct dual_addr'
    filled with sockaddr_storage strucs: we already know what needs to
    be shipped around: sockaddr_in & sockaddr_in6.

3) the bzero() wasn't needed. conf is passed in (as xconf) is lconf in
    main() which is zero'd there, which isn't even necessary.

4) memset/memcpy/memmove are nowadays prefered over bzero/bcopy for
    performance reasons.

Below is a new version of the patch.

Kind regards,

Job

---
 usr.sbin/ntpd/client.c    | 12 ++++++++++++
 usr.sbin/ntpd/ntp.c       |  2 ++
 usr.sbin/ntpd/ntpd.conf.5 |  8 ++++++++
 usr.sbin/ntpd/ntpd.h      |  4 ++++
 usr.sbin/ntpd/parse.y     | 31 ++++++++++++++++++++++++++++++-
 5 files changed, 56 insertions(+), 1 deletion(-)

diff --git a/usr.sbin/ntpd/client.c b/usr.sbin/ntpd/client.c
index ad53f6098c1..f7379946fd4 100644
--- a/usr.sbin/ntpd/client.c
+++ b/usr.sbin/ntpd/client.c
@@ -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) {
diff --git a/usr.sbin/ntpd/ntp.c b/usr.sbin/ntpd/ntp.c
index 2fbaaf7149f..2184028cbc4 100644
--- a/usr.sbin/ntpd/ntp.c
+++ b/usr.sbin/ntpd/ntp.c
@@ -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;
diff --git a/usr.sbin/ntpd/ntpd.conf.5 b/usr.sbin/ntpd/ntpd.conf.5
index 4d2d15c66d7..d2ebd67edb5 100644
--- a/usr.sbin/ntpd/ntpd.conf.5
+++ b/usr.sbin/ntpd/ntpd.conf.5
@@ -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
diff --git a/usr.sbin/ntpd/ntpd.h b/usr.sbin/ntpd/ntpd.h
index fb9cd87118a..c1e8ce469fc 100644
--- a/usr.sbin/ntpd/ntpd.h
+++ b/usr.sbin/ntpd/ntpd.h
@@ -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;
diff --git a/usr.sbin/ntpd/parse.y b/usr.sbin/ntpd/parse.y
index 8da19a218e0..c39ccf57ef7 100644
--- a/usr.sbin/ntpd/parse.y
+++ b/usr.sbin/ntpd/parse.y
@@ -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},

Reply via email to