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},