Add IPv6 support to dntpd
authorMatthias Schmidt <matthias@dragonflybsd.org>
Fri, 9 Jan 2009 11:35:25 +0000 (12:35 +0100)
committerMatthias Schmidt <matthias@dragonflybsd.org>
Fri, 9 Jan 2009 11:35:25 +0000 (12:35 +0100)
This commit allows dntpd to work with either IPv4 or IPv6 NTP servers.  I added
two new command line switches (-4/-6) to force dntpd to use only v4/v6 addresses.
Thanks to sephe@ for some good hints.

Reviewed-by: sephe@
usr.sbin/dntpd/client.h
usr.sbin/dntpd/defs.h
usr.sbin/dntpd/dntpd.8
usr.sbin/dntpd/main.c
usr.sbin/dntpd/socket.c

index 44ee78a..5a7fb2b 100644 (file)
@@ -42,7 +42,8 @@ struct server_info {
        int poll_mode;          /* mode of operation */
        int poll_count;         /* number of polls in current mode */
        int poll_failed;        /* count of NTP failures */
-       struct sockaddr_in sam; /* udp connection info */
+       struct sockaddr *sam;   /* udp connection info */
+       struct sockaddr_storage sam_st;         /* udp connection info (stor) */
        char *target;           /* target hostname or IP (string) */
        char *ipstr;            /* IP string */
 
index 18d6856..8cebc77 100644 (file)
@@ -73,9 +73,10 @@ extern int min_sleep_opt;
 extern int nom_sleep_opt;
 extern int max_sleep_opt;
 extern int log_stderr;
+extern int family;
 extern double insane_deviation;
 
-int udp_socket(const char *target, int port, struct sockaddr_in *sam);
+int udp_socket(const char *target, int port, struct sockaddr *sam);
 int udp_ntptimereq(int fd, struct timeval *rtvp, 
                   struct timeval *ltvp, struct timeval *lbtvp);
 void reconnect_server(server_info_t info);
index fa2dc0c..7f68312 100644 (file)
@@ -32,7 +32,7 @@
 .\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd January 19, 2008
+.Dd January 6, 2009
 .Dt DNTPD 8
 .Os
 .Sh NAME
@@ -41,7 +41,7 @@
 .Sh SYNOPSIS
 .Nm
 .Bk -words
-.Op Fl dnqstFSQ
+.Op Fl 46dnqstFSQ
 .Op Fl f Ar config_file
 .Op Fl i Ar insane_deviation
 .Op Fl l Ar log_level
@@ -81,6 +81,14 @@ no new daemon will be started.
 .Pp
 The following command line options are available:
 .Bl -tag -width Fl
+.It Fl 4
+Forces
+.Nm
+to use only IPv4 addresses.
+.It Fl 6
+Forces
+.Nm
+to use only IPv6 addresses.
 .It Fl d
 Run in debug mode.
 Implies
index c48e61a..9d15bab 100644 (file)
@@ -56,6 +56,7 @@ int no_update_opt = 0;                /* do not make any actual updates */
 int min_sleep_opt = 5;         /* 5 seconds minimum poll interval */
 int nom_sleep_opt = 300;       /* 5 minutes nominal poll interval */
 int max_sleep_opt = 1800;      /* 30 minutes maximum poll interval */
+int family = PF_UNSPEC;                /* Address family */
 double insane_deviation = 0.5; /* 0.5 seconds of deviation == insane */
 const char *config_opt;                /* config file */
 const char *pid_opt = "/var/run/dntpd.pid";
@@ -78,8 +79,14 @@ main(int ac, char **av)
     /*
      * Process Options
      */
-    while ((ch = getopt(ac, av, "df:i:l:np:qstFL:QST:")) != -1) {
+    while ((ch = getopt(ac, av, "46df:i:l:np:qstFL:QST:")) != -1) {
        switch(ch) {
+       case '4':
+           family = PF_INET;
+           break;
+       case '6':
+           family = PF_INET6;
+           break;
        case 'd':
            debug_opt = 1;
            daemon_opt = 0;
@@ -294,7 +301,8 @@ dotest(const char *target)
     struct server_info info;
 
     bzero(&info, sizeof(info));
-    info.fd = udp_socket(target, 123, &info.sam);
+    info.sam = (struct sockaddr *)&info.sam_st;
+    info.fd = udp_socket(target, 123, info.sam);
     if (info.fd < 0) {
        logerrstr("unable to create UDP socket for %s", target);
        return;
@@ -312,6 +320,26 @@ dotest(const char *target)
     /* not reached */
 }
 
+static char *
+myaddr2ascii(struct sockaddr *sa)
+{
+       static char str[INET6_ADDRSTRLEN];
+       struct sockaddr_in *soin;
+       struct sockaddr_in6 *sin6;
+
+       switch (sa->sa_family) {
+       case AF_INET:
+               soin = (struct sockaddr_in *) sa;
+               inet_ntop(AF_INET, &soin->sin_addr, str, sizeof(str));
+               break;
+       case AF_INET6:
+               sin6 = (struct sockaddr_in6 *) sa;
+               inet_ntop(AF_INET6, &sin6->sin6_addr, str, sizeof(str));
+               break;
+       }
+       return (str);
+}
+
 static void
 add_server(const char *target)
 {
@@ -326,11 +354,11 @@ add_server(const char *target)
     info = malloc(sizeof(struct server_info));
     servers[nservers] = info;
     bzero(info, sizeof(struct server_info));
-    info->fd = udp_socket(target, 123, &info->sam);
+    info->sam = (struct sockaddr *)&info->sam_st;
+    info->fd = udp_socket(target, 123, info->sam);
     info->target = strdup(target);
     if (info->fd >= 0) {
-       ipstr = addr2ascii(AF_INET, &info->sam.sin_addr,
-                          sizeof(info->sam.sin_addr), NULL);
+       ipstr = myaddr2ascii(info->sam);
        info->ipstr = strdup(ipstr);
     } else {
        client_setserverstate(info, -1, "DNS or IP lookup failure");
@@ -361,10 +389,10 @@ reconnect_server(server_info_t info)
        free(info->ipstr);
        info->ipstr = NULL;
     }
-    info->fd = udp_socket(info->target, 123, &info->sam);
+    info->sam = (struct sockaddr *)&info->sam_st;
+    info->fd = udp_socket(info->target, 123, info->sam);
     if (info->fd >= 0) {
-       ipstr = addr2ascii(AF_INET, &info->sam.sin_addr,
-                          sizeof(info->sam.sin_addr), NULL);
+       ipstr = myaddr2ascii(info->sam);
        info->ipstr = strdup(ipstr);
     }
 }
index 8f11381..dc72108 100644 (file)
 #include "defs.h"
 
 int
-udp_socket(const char *target, int port, struct sockaddr_in *sam)
+udp_socket(const char *target, int port, struct sockaddr *sam)
 {
-    struct hostent *hp;
-    int rc;
+    struct addrinfo hints, *res, *res0;
+    char servname[128];
+    const char *cause = NULL;
+    int error;
     int fd;
     int tos;
 
-    if ((rc = inet_aton(target, &sam->sin_addr)) == 0) {
-       if ((hp = gethostbyname2(target, AF_INET)) == NULL) {
-           logerr("Unable to resolve server %s", target);
-           return(-1);
-       }
-       bcopy(hp->h_addr_list[0], &sam->sin_addr, hp->h_length);
-    } else if (rc != 1) {
-       logerrstr("unable to resolve server %s", target);
-       return(-1);
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_family = family;
+    hints.ai_socktype = SOCK_DGRAM;
+    snprintf(servname, sizeof(servname), "%d", port);
+    error = getaddrinfo(target, servname, &hints, &res0);
+    if (error) {
+        logerr("getaddrinfo (%s) init error", target, gai_strerror(error));
+        return(-1);
     }
-    if ((fd = socket(PF_INET, SOCK_DGRAM, PF_UNSPEC)) < 0) {
-       logerr("socket(%s)", target);
-       return(-1);
-    }
-    if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
-       logerr("socket(%s) unable to set non-blocking mode", target);
-       close(fd);
-       return(-1);
+
+    fd = -1;
+    for (res = res0; res; res = res->ai_next) {
+        fd = socket(res->ai_family, res->ai_socktype,
+        res->ai_protocol);
+        if (fd < 0) {
+           cause = "socket";
+           continue;
+        }
+
+        if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
+            logerr("%s: unable to set non-blocking mode", target);
+            close(fd);
+            fd = -1;
+            continue;
+        }
+
+        if (connect(fd, res->ai_addr, res->ai_addrlen) < 0) {
+           cause = "connect";
+           close(fd);
+           fd = -1;
+           continue;
+        }
+
+        break;  /* okay we got one */
     }
-    sam->sin_port = htons(port);
-    sam->sin_len = sizeof(sam);
-    sam->sin_family = AF_INET;
-    if (connect(fd, (void *)sam, sizeof(*sam)) < 0) {
-       logerr("connect(%s)", target);
-       close(fd);
-       return(-1);
+
+    if (fd < 0) {
+        logerr("Unable to establish a connection with %s: %s", target, cause);
+        return(-1);
     }
+    memcpy(sam, res->ai_addr, res->ai_addr->sa_len);
+    freeaddrinfo(res0);
+
 #ifdef IPTOS_LOWDELAY
     tos = IPTOS_LOWDELAY;
-    setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); 
+    setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
 #endif
 #if 0
 #ifdef IP_PORTRANGE
     tos = IP_PORTRANGE_HIGH;
-    setsockopt(fd, IPPROTO_IP, IP_PORTRANGE, &tos, sizeof(tos)); 
+    setsockopt(fd, IPPROTO_IP, IP_PORTRANGE, &tos, sizeof(tos));
 #endif
 #endif
     return(fd);
 }
-