Works for me, verified both v4 and v6 selection actually uses that
address.  Suggested a small improvement for ntpd.conf(5) to Job
privately.

Would love to see this feature get imported :)

Thanks Job!

Paul

On Tue, May 30, 2017 at 06:10:03PM +0200, Job Snijders wrote:
| On Sun, May 28, 2017 at 10:52:24PM +0200, Sebastian Benoit wrote:
| > which makes me think:
| > would a global local-address be good enough?
| 
| Attached is a patch that allows you to specify the source for outgoing
| queries, as a global option. Example ntpd.conf:
| 
|     query from 165.254.255.33
|     query from 2001:728:1808::26
|     servers ntp.ring.nlnog.net
| 
| I have a number of remarks myself:
| 
|     - unsure about the bzero() in parse_config()
| 
|     - should we check 2+ declarations of 'query from', or just use the
|       last one like this patch does now, (we don't check for duplicate
|       'weight' etc either)
| 
|     - the ipv4 / ipv6 approach with 'struct dual_addr' seems clumsy, is
|       this what life is like in an ipv4 + ipv6 world? Any suggestions
|       how to improve?
| 
| Kind regards,
| 
| Job
| 
| ---
|  src/usr.sbin/ntpd/client.c    | 13 +++++++++++++
|  src/usr.sbin/ntpd/ntp.c       |  1 +
|  src/usr.sbin/ntpd/ntpd.conf.5 |  8 ++++++++
|  src/usr.sbin/ntpd/ntpd.h      |  7 +++++++
|  src/usr.sbin/ntpd/parse.y     | 31 ++++++++++++++++++++++++++++++-
|  5 files changed, 59 insertions(+), 1 deletion(-)
| 
| diff --git a/src/usr.sbin/ntpd/client.c b/src/usr.sbin/ntpd/client.c
| index ddbb1281..7d921dcf 100644
| --- a/src/usr.sbin/ntpd/client.c
| +++ b/src/usr.sbin/ntpd/client.c
| @@ -137,11 +137,24 @@ 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_addr.v4;
| +             struct sockaddr *qa6 = (struct sockaddr *)&p->query_addr.v6;
|  
|               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/src/usr.sbin/ntpd/ntp.c b/src/usr.sbin/ntpd/ntp.c
| index f3366640..b0f80294 100644
| --- a/src/usr.sbin/ntpd/ntp.c
| +++ b/src/usr.sbin/ntpd/ntp.c
| @@ -521,6 +521,7 @@ ntp_dispatch_imsg_dns(void)
|                               if (peer->addr_head.pool) {
|                                       npeer = new_peer();
|                                       npeer->weight = peer->weight;
| +                                     npeer->query_addr = peer->query_addr;
|                                       h->next = NULL;
|                                       npeer->addr = h;
|                                       npeer->addr_head.a = h;
| diff --git a/src/usr.sbin/ntpd/ntpd.conf.5 b/src/usr.sbin/ntpd/ntpd.conf.5
| index 6e4e0012..b8f03b22 100644
| --- a/src/usr.sbin/ntpd/ntpd.conf.5
| +++ b/src/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 source 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 10.0.0.1
| +query from 2001:db8::1
|  .Ed
|  .It Xo Ic sensor Ar device
|  .Op Ic correction Ar microseconds
| diff --git a/src/usr.sbin/ntpd/ntpd.h b/src/usr.sbin/ntpd/ntpd.h
| index 613b29b2..ded2948a 100644
| --- a/src/usr.sbin/ntpd/ntpd.h
| +++ b/src/usr.sbin/ntpd/ntpd.h
| @@ -106,6 +106,11 @@ struct listen_addr {
|       int                              rtable;
|  };
|  
| +struct dual_addr {
| +     struct sockaddr_storage v4;
| +     struct sockaddr_storage v6;
| +};
| +
|  struct ntp_addr {
|       struct ntp_addr         *next;
|       struct sockaddr_storage  ss;
| @@ -153,6 +158,7 @@ struct ntp_peer {
|       struct ntp_query                *query;
|       struct ntp_offset                reply[OFFSET_ARRAY_SIZE];
|       struct ntp_offset                update;
| +     struct dual_addr                 query_addr;
|       enum client_state                state;
|       time_t                           next;
|       time_t                           deadline;
| @@ -219,6 +225,7 @@ struct ntpd_conf {
|       TAILQ_HEAD(constraints, constraint)             constraints;
|       struct ntp_status                               status;
|       struct ntp_freq                                 freq;
| +     struct dual_addr                                query_addr;
|       u_int32_t                                       scale;
|       int                                             debug;
|       int                                             verbose;
| diff --git a/src/usr.sbin/ntpd/parse.y b/src/usr.sbin/ntpd/parse.y
| index 6d507957..dc131270 100644
| --- a/src/usr.sbin/ntpd/parse.y
| +++ b/src/usr.sbin/ntpd/parse.y
| @@ -58,6 +58,7 @@ int          lungetc(int);
|  int           findeol(void);
|  
|  struct ntpd_conf             *conf;
| +struct dual_addr             query_addr;
|  
|  struct opts {
|       int             weight;
| @@ -80,7 +81,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 +131,30 @@ main             : LISTEN ON address listen_opts {
|                       free($3->name);
|                       free($3);
|               }
| +             | QUERY FROM STRING {
| +                        struct sockaddr_in sin4 = {
| +                                .sin_family = AF_INET,
| +                                .sin_len = sizeof(struct sockaddr_in)
| +                        };
| +                        struct sockaddr_in6 sin6 = {
| +                                .sin6_family = AF_INET6,
| +                                .sin6_len = sizeof(struct sockaddr_in6)
| +                        };
| +
| +                        if (inet_pton(AF_INET, $3, &sin4.sin_addr) == 1) {
| +                                memcpy(&query_addr.v4, &sin4, sin4.sin_len);
| +                     }
| +                        else if (inet_pton(AF_INET6, $3, &sin6.sin6_addr) == 
1) {
| +                                memcpy(&query_addr.v6, &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 +178,7 @@ main              : LISTEN ON address listen_opts {
|  
|                               p = new_peer();
|                               p->weight = $3.weight;
| +                             p->query_addr = query_addr;
|                               p->addr = h;
|                               p->addr_head.a = h;
|                               p->addr_head.pool = 1;
| @@ -190,6 +216,7 @@ main              : LISTEN ON address listen_opts {
|                       }
|  
|                       p->weight = $3.weight;
| +                     p->query_addr = query_addr;
|                       p->addr_head.a = p->addr;
|                       p->addr_head.pool = 0;
|                       p->addr_head.name = strdup($2->name);
| @@ -461,6 +488,7 @@ lookup(char *s)
|               { "from",               FROM},
|               { "listen",             LISTEN},
|               { "on",                 ON},
| +             { "query",              QUERY},
|               { "refid",              REFID},
|               { "rtable",             RTABLE},
|               { "sensor",             SENSOR},
| @@ -747,6 +775,7 @@ parse_config(const char *filename, struct ntpd_conf 
*xconf)
|       TAILQ_INIT(&conf->ntp_peers);
|       TAILQ_INIT(&conf->ntp_conf_sensors);
|       TAILQ_INIT(&conf->constraints);
| +     bzero(&conf->query_addr, sizeof(struct dual_addr));
|  
|       if ((file = pushfile(filename)) == NULL) {
|               return (-1);
| 

-- 
>++++++++[<++++++++++>-]<+++++++.>+++[<------>-]<.>+++[<+
+++++++++++>-]<.>++[<------------>-]<+.--------------.[-]
                 http://www.weirdnet.nl/                 

Reply via email to