>     "servers ntp.ring.nlnog.net \
>         local-address 165.254.255.27,2001:728:1808::26"

yes

> 
> or allow one to repeat the 'local-address' keyword:
> 
>     "servers ntp.ring.nlnog.net \
>         local-address 165.254.255.27 \
>         local-address 2001:728:1808::26"
> 
> or use different keywords for ipv4 and ipv6:
> 
>     "servers ntp.ring.nlnog.net \
>         local-address4 165.254.255.27 \
>         local-address6 2001:728:1808::26"
> 
> It feels like a balance must be struck between between deterministic
> behaviour, and the software attempting to get the time from somewhere,
> somehow. Any guidance on the topic would be appreciated!
> 
> Personally I think i am somewhat in favor of the comma separated
> approach: "local-address 165.254.255.27,2001:728:1808::26" - if you only
> specifiy one address, that AFI will be determinstic, and the software
> will just automatically select a source address for the other AFI. If
> you specify two addresses (comma separated, one IPv4 and one IPv6),
> you'll have determinstic behavior for both AFIs.

thats the best solution.

for a seperate diff: constraints suffer the same problem, they need a
local-address too.

which makes me think:
would a global local-address be good enough?

comment below

> 
> Look forward to your feedback.
> 
> Kind regards,
> 
> Job
> 
> ---
>  src/usr.sbin/ntpd/client.c    |  6 ++++++
>  src/usr.sbin/ntpd/ntp.c       |  1 +
>  src/usr.sbin/ntpd/ntpd.conf.5 |  1 +
>  src/usr.sbin/ntpd/ntpd.h      |  1 +
>  src/usr.sbin/ntpd/parse.y     | 41 ++++++++++++++++++++++++++++++++++++++++-
>  5 files changed, 49 insertions(+), 1 deletion(-)
> 
> diff --git a/src/usr.sbin/ntpd/client.c b/src/usr.sbin/ntpd/client.c
> index ddbb1281..31ff782d 100644
> --- a/src/usr.sbin/ntpd/client.c
> +++ b/src/usr.sbin/ntpd/client.c
> @@ -137,11 +137,17 @@ client_query(struct ntp_peer *p)
>  
>       if (p->query->fd == -1) {
>               struct sockaddr *sa = (struct sockaddr *)&p->addr->ss;
> +             struct sockaddr *la = (struct sockaddr *)&p->local_addr;
>  
>               if ((p->query->fd = socket(p->addr->ss.ss_family, SOCK_DGRAM,
>                   0)) == -1)
>                       fatal("client_query socket");
>  
> +             if(p->addr->ss.ss_family == la->sa_family)
> +                     if (bind(p->query->fd, la, SA_LEN(la)) == -1)
> +                             fatal("couldn't bind to local-address: %s",
> +                                 log_sockaddr(la));
> +
>               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..f22f1ca4 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->local_addr = peer->local_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..07bc2174 100644
> --- a/src/usr.sbin/ntpd/ntpd.conf.5
> +++ b/src/usr.sbin/ntpd/ntpd.conf.5
> @@ -131,6 +131,7 @@ A stratum value other than the default of 1 can be 
> assigned using the
>  keyword.
>  .It Xo Ic server Ar address
>  .Op Ic weight Ar weight-value
> +.Op Ic local-address Ar address
>  .Xc
>  Specify the IP address or the hostname of an NTP
>  server to synchronize to.
> diff --git a/src/usr.sbin/ntpd/ntpd.h b/src/usr.sbin/ntpd/ntpd.h
> index 613b29b2..c1d7fa6e 100644
> --- a/src/usr.sbin/ntpd/ntpd.h
> +++ b/src/usr.sbin/ntpd/ntpd.h
> @@ -153,6 +153,7 @@ struct ntp_peer {
>       struct ntp_query                *query;
>       struct ntp_offset                reply[OFFSET_ARRAY_SIZE];
>       struct ntp_offset                update;
> +     struct sockaddr_storage          local_addr;
>       enum client_state                state;
>       time_t                           next;
>       time_t                           deadline;
> diff --git a/src/usr.sbin/ntpd/parse.y b/src/usr.sbin/ntpd/parse.y
> index 6d507957..8bdd28f6 100644
> --- a/src/usr.sbin/ntpd/parse.y
> +++ b/src/usr.sbin/ntpd/parse.y
> @@ -65,6 +65,7 @@ struct opts {
>       int             stratum;
>       int             rtable;
>       char            *refstr;
> +     struct sockaddr_storage local_addr;
>  } opts;
>  void         opts_default(void);
>  
> @@ -82,7 +83,7 @@ typedef struct {
>  
>  %token       LISTEN ON CONSTRAINT CONSTRAINTS FROM
>  %token       SERVER SERVERS SENSOR CORRECTION RTABLE REFID STRATUM WEIGHT
> -%token       ERROR
> +%token       ERROR LOCALADDR
>  %token       <v.string>              STRING
>  %token       <v.number>              NUMBER
>  %type        <v.addr>                address url
> @@ -94,6 +95,7 @@ typedef struct {
>  %type        <v.opts>                refid
>  %type        <v.opts>                stratum
>  %type        <v.opts>                weight
> +%type        <v.opts>                local_addr
>  %%
>  
>  grammar              : /* empty */
> @@ -153,6 +155,7 @@ main              : LISTEN ON address listen_opts {
>  
>                               p = new_peer();
>                               p->weight = $3.weight;
> +                             p->local_addr = $3.local_addr;
>                               p->addr = h;
>                               p->addr_head.a = h;
>                               p->addr_head.pool = 1;
> @@ -190,6 +193,7 @@ main              : LISTEN ON address listen_opts {
>                       }
>  
>                       p->weight = $3.weight;
> +                     p->local_addr = $3.local_addr;
>                       p->addr_head.a = p->addr;
>                       p->addr_head.pool = 0;
>                       p->addr_head.name = strdup($2->name);
> @@ -348,6 +352,7 @@ server_opts_l     : server_opts_l server_opt
>               | server_opt
>               ;
>  server_opt   : weight
> +             | local_addr
>               ;
>  
>  sensor_opts  :       { opts_default(); }
> @@ -403,6 +408,38 @@ weight           : WEIGHT NUMBER {
>                       }
>                       opts.weight = $2;
>               }
> +             ;
> +
> +local_addr   : LOCALADDR STRING {
> +                     if (opts.local_addr.ss_family != AF_UNSPEC) {
> +                             yyerror("local-address specified more than 
> once");
> +                             YYERROR;
> +                     }

this

> +                     struct sockaddr_storage ss;
> +                     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)
> +                     };

needs to move up before the "if (opts.local_addr.ss_family != AF_UNSPEC) {"
to get rid of a "ISO C90 forbids mixed declarations and code" warning

> +                     bzero(&ss, sizeof(ss));
> +                     if (inet_pton(AF_INET, $2, &sin4.sin_addr) == 1)
> +                             memcpy(&ss, &sin4, sin4.sin_len);
> +                     else if (inet_pton(AF_INET6, $2, &sin6.sin6_addr) == 1)
> +                             memcpy(&ss, &sin6, sin6.sin6_len);
> +                     else {
> +                             yyerror("invalid IPv4 or IPv6 address: %s\n",
> +                                 $2);
> +                             free($2);
> +                             YYERROR;
> +                     }
> +                     opts.local_addr = ss;
> +                     free($2);
> +             }
> +             ;
> +
>  rtable               : RTABLE NUMBER {
>                       if ($2 < 0 || $2 > RT_TABLEID_MAX) {
>                               yyerror("rtable must be between 1"
> @@ -421,6 +458,7 @@ opts_default(void)
>       memset(&opts, 0, sizeof opts);
>       opts.weight = 1;
>       opts.stratum = 1;
> +     opts.local_addr.ss_family = AF_UNSPEC;
>  }
>  
>  struct keywords {
> @@ -460,6 +498,7 @@ lookup(char *s)
>               { "correction",         CORRECTION},
>               { "from",               FROM},
>               { "listen",             LISTEN},
> +             { "local-address",      LOCALADDR},
>               { "on",                 ON},
>               { "refid",              REFID},
>               { "rtable",             RTABLE},
> 

Reply via email to