]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
Merge bk://www.ntp.org/home/bk/ntp-dev
authorFrank Kardel <kardel@ntp.org>
Tue, 14 Mar 2006 08:12:18 +0000 (08:12 +0000)
committerFrank Kardel <kardel@ntp.org>
Tue, 14 Mar 2006 08:12:18 +0000 (08:12 +0000)
into  pogo.udel.edu:/pogo/users/kardel/dynamic-if/ntp-dev

bk: 44167ae2SGwDQ61o9pG6H24dlGpdPg

14 files changed:
1  2 
html/ntpdc.html
include/ntp.h
include/ntp_request.h
ntpd/ntp_config.c
ntpd/ntp_control.c
ntpd/ntp_crypto.c
ntpd/ntp_io.c
ntpd/ntp_peer.c
ntpd/ntp_proto.c
ntpd/ntp_request.c
ntpd/ntp_util.c
ntpd/refclock_parse.c
ntpdc/ntpdc.c
ntpdc/ntpdc_ops.c

diff --cc html/ntpdc.html
index d6b7ab9e9934ce07660fd091626a629f7f9a8d20,14f01e436ef8ecf2fcd7368c58d160a07b1bc8c8..62f184a4d4be5229ce20ed69f3c0dab9513245e6
                <p>Authenticated requests always include a timestamp in the packet data, which is included in the computation of the authentication code. This timestamp is compared by the server to its receive time stamp. If they differ by more than a small amount the request is rejected. This is done for two reasons. First, it makes simple replay attacks on the server, by someone who might be able to overhear traffic on your LAN, much more difficult. Second, it makes it more difficult to request configuration changes to your server from topologically remote hosts. While the reconfiguration facility will work well with a server on the local host, and may work adequately between time-synchronized hosts on the same LAN, it will work very poorly for more distant hosts. As such, if reasonable passwords are chosen, care is taken in the distribution and protection of keys and appropriate source address restrictions are applied, the run time reconfiguration facility should provide an adequate level of security.</p>
                <p>The following commands all make authenticated requests.</p>
                <dl>
 -                      <dt><tt>addpeer <i>peer_address</i> [ <i>keyid</i> ] [ <i>version</i> ] [ <i>prefer</i> ] [ <i>dynamic</i> ]</tt>
 -                      <dd>Add a configured peer association at the given address and operating in symmetric active mode. Note that an existing association with the same peer may be deleted when this command is executed, or may simply be converted to conform to the new configuration, as appropriate. If the optional <tt>keyid</tt> is a nonzero integer, all outgoing packets to the remote server will have an authentication field attached encrypted with this key. If the value is 0 (or not given) no authentication will be done. The <tt>version#</tt> can be 1, 2 or 3 and defaults to 3. The <tt>prefer</tt> keyword indicates a preferred peer (and thus will be used primarily for clock synchronisation if possible). The preferred peer also determines the validity of the PPS signal - if the preferred peer is suitable for synchronisation so is the PPS signal. The <tt>dynamic</tt> keyword allows association configuration even when no suitable network interface is found at configuration time. The dynamic interface update mechanism may complete the configuration when new interfaces appear (e.g. WLAN/PPP interfaces) at a later time and thus render the association operable.
 -                      <dt><tt>addserver <i>peer_address</i> [ <i>keyid</i> ] [ <i>version</i> ] [ <i>prefer</i> ] [ <i>dynamic</i> ]</tt>
 +              <dt><tt>addpeer <i>peer_address</i> [
 +              <i>keyid</i> ] [ <i>version</i> ] [
 +              <tt>minpoll# | prefer | iburst  | burst | minpoll
-               <i>N</i> | <tt>maxpoll</tt> <i>N</i> [...] ]</tt>
++              <i>N</i> | <tt>maxpoll</tt> <i>N</i> [ <i>dynamic</i> ] [...] ]</tt>
 +              <dt><tt>addpeer <i>peer_address</i> [
 +              <tt>prefer | iburst | burst | minpoll
 +              <i>N</i> | <tt>maxpoll</tt> <i>N</i> | <tt>keyid</tt>
 +                      <i>N</i> | <tt>version</tt> <i>N</i> [...] ]</tt>
 +                      <dd>Add a configured peer association at the
 +                      given address and operating in symmetric
 +                      active mode. Note that an existing association
 +                      with the same peer may be deleted when this
 +                      command is executed, or may simply be
 +                      converted to conform to the new configuration,
 +                      as appropriate. If the <tt>keyid</tt>
 +                      is nonzero, all outgoing packets to
 +                      the remote server will have an authentication
 +                      field attached encrypted with this key. If the
 +                      value is 0 (or not given) no authentication
 +                      will be done. If ntpdc's key number has not
 +                      yet been set (<i>e.g.,</i> by the keyid
 +                      command), it will be set to this value.
 +                      The <tt>version#</tt> can be 1 through 4 and defaults to 3.  The remaining
 +                      options are either a numeric value for <tt>minpoll</tt> or
 +                      literals <tt>prefer</tt>, <tt>iburst</tt>, 
 +                      <tt>burst</tt>, <tt>minpoll  </tt><i>N</i>,
 +                      <tt>keyid </tt><i>N</i>, <tt>version </tt> <i>N</i>, or
 +                      <tt>maxpoll  </tt><i>N</i> (where <i>N</i> is a numeric value), and have the action as specified in the
 +                      <tt>peer</tt> configuration file command of
 +                      ntpd.  See the <a href="confopt.html">Server Options</a> page for further information.
 +                      Each flag (or its absence) replaces the
 +                      previous setting. The <tt>prefer</tt> keyword indicates a preferred peer (and thus will be used primarily for clock synchronisation if possible). The preferred peer also determines the validity of the PPS signal - if the preferred peer is suitable for synchronisation so is the PPS signal.
++                      The <tt>dynamic</tt> keyword allows association configuration even when no suitable network interface is found at configuration time. The dynamic interface update mechanism may complete the configuration when new interfaces appear (e.g. WLAN/PPP interfaces) at a later time and thus render the association operable.
 +                      <dt><tt>addserver <i>peer_address</i> [
 +              <i>keyid</i> ] [ <i>version</i> ] [
 +              <tt>minpoll# | prefer | iburst  | burst | minpoll
 +              <i>N</i> | <tt>maxpoll</tt> <i>N</i> [...] ]</tt>
 +              <dt><tt>addserver <i>peer_address</i> [
 +              <tt>prefer | iburst | burst | minpoll
 +              <i>N</i> | <tt>maxpoll</tt> <i>N</i> | <tt>keyid</tt>
-                       <i>N</i> | <tt>version</tt> <i>N</i> [...] ]</tt>
++                      <i>N</i> | <tt>version</tt> <i>N</i> [...] [ <i>dynamic</i> ] ]</tt>
                        <dd>Identical to the addpeer command, except that the operating mode is client.
 -                      <dt><tt>broadcast <i>peer_address</i> [ <i>keyid</i> ] [ <i>version</i> ] [ <i>prefer</i> ]</tt>
 -                      <dd>Identical to the addpeer command, except that the operating mode is broadcast. In this case a valid key identifier and key are required. The <tt>peer_address</tt> parameter can be the broadcast address of the local network or a multicast group address assigned to NTP. If a multicast address, a multicast-capable kernel is required.
 +                      <dt><tt>broadcast <i>peer_address</i> [
 +                      <i>keyid</i> ] [ <i>version</i> ] [ <i>prefer</i> ]</tt>
 +                      <dd>Identical to the addpeer command, except
 +                      that the operating mode is broadcast. In this
 +                      case a valid non-zero key identifier and key are required. The <tt>peer_address</tt> parameter can be the broadcast address of the local network or a multicast group address assigned to NTP. If a multicast address, a multicast-capable kernel is required.
                        <dt><tt>unconfig <i>peer_address</i> [...]</tt>
                        <dd>This command causes the configured bit to be removed from the specified peer(s). In many cases this will cause the peer association to be deleted. When appropriate, however, the association may persist in an unconfigured mode if the remote peer is willing to continue on in this fashion.
                        <dt><tt>fudge <i>peer_address</i> [ <i>time1</i> ] [ <i>time2</i> ] [ <i>stratum</i> ] [ <i>refid</i> ]</tt>
diff --cc include/ntp.h
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
diff --cc ntpd/ntp_io.c
index 1fb107a6a759065d903cbd8efb81d537b546bf55,36b791f54311b271e8581dbd970a036fccca52ae..0b24a6aea22529daf207e10c2d756157e82382db
@@@ -142,21 -139,18 +139,21 @@@ static  struct refclockio *refio
   */
  fd_set activefds;
  int maxactivefd;
+ /*
+  * bit alternating value to detect verified interfaces during an update cycle
+  */
+ static  u_char          sys_interphase = 0;
+ static  struct interface *new_interface P((struct interface *));
+ static  void add_interface P((struct interface *));
+ static  void update_interfaces P((u_short, interface_receiver_t, void *));
+ static  void remove_interface P((struct interface *));
+ static  struct interface *create_interface P((u_short, struct interface *));
  
- static        int create_sockets      P((u_short));
- static        SOCKET  open_socket     P((struct sockaddr_storage *, int, int, struct interface *, int));
- static        void    close_socket    P((SOCKET));
- #ifdef REFCLOCK
- static        void    close_file      P((SOCKET));
- #endif
 +#ifdef F_DUPFD
 +static int    dup_fd          P((int));
 +#endif
  
- static        char *  fdbits          P((int, fd_set *));
- static        void    set_reuseaddr   P((int));
- static        isc_boolean_t   socket_broadcast_enable  P((struct interface *, SOCKET, struct sockaddr_storage *));
- static        isc_boolean_t   socket_broadcast_disable P((struct interface *, int, struct sockaddr_storage *));
  /*
   * Multicast functions
   */
@@@ -245,27 -280,42 +283,63 @@@ connection_reset_fix(SOCKET fd) 
  }
  #endif
  
 +#ifdef F_DUPFD
 +static int dup_fd(int fd)
 +{
 +      int tmp, newfd;
 +        /*
 +         * Leave a space for stdio to work in.
 +         */
 +        if (fd >= 0 && fd < 20) {
 +                newfd = fcntl(fd, F_DUPFD, 20);
 +
 +                tmp = errno;
 +                if (newfd == -1)
 +                        perror("fcntl");
 +                (void)close(fd);
 +                errno = tmp;
 +                return (newfd);
 +        }
 +}
 +#endif
 +
 +
+ /*
+  * About dynamic interfaces, sockets, reception and more...
+  *
+  * the code solves following tasks:
+  *
+  *   - keep a current list of active interfaces in order
+  *     to bind to to the interface address on NTP_PORT so that
+  *     all wild and specific bindings for NTP_PORT are taken by ntpd
+  *     to avoid other daemons messing with the time or sockets.
+  *   - all interfaces keep a list of peers that are referencing 
+  *     the interface in order to quickly re-assign the peers to
+  *     new interface in case an interface is deleted (=> gone from system or
+  *     down)
+  *   - have a preconfigured socket ready with the right local address
+  *     for transmission and reception
+  *   - have an address list for all destination addresses used within ntpd
+  *     to find the "right" preconfigured socket.
+  *   - facilitate updating the internal interface list with respect to
+  *     the current kernel state
+  *
+  * special issues:
+  *
+  *   - mapping of multicast addresses to the interface affected is not always
+  *     one to one - exspecially on hosts with multiple interfaces
+  *     the code here currently allocates a separate interface entry for those
+  *     multicast addresses
+  *     iff it is able to bind to a *new* socket with the multicast address (flags |= MCASTIF)
+  *     in case of failure the multicast address of bound to an existing interface.
+  *   - on some systems it is perfectly legal to assign the same address to
+  *     multiple interfaces. Therefore this code does not really keep a list of interfaces
+  *     but a list of interfaces that represent a unique address as determined by the kernel
+  *     by the procedure in findlocalinterface. Thus it is perfectly legal to see only
+  *     one representavive of a group of real interfaces if they share the same address.
+  * 
+  * Frank Kardel 20050910
+  */
  
  /*
   * init_io - initialize I/O data structures and call socket creation routine
@@@ -913,26 -1382,11 +1408,22 @@@ enable_multicast_if(struct interface *i
                        iface->fd, stoa(&iface->sin), stoa(maddr));
                        return;
                }
- #ifdef DEBUG
-               if (debug > 0) {
-                       printf(
-                       "Added IPv4 multicast interface on socket %d, addr %s for multicast address %s\n",
-                       iface->fd, stoa(&iface->sin),
-                       stoa(maddr));
-               }
- #endif
 +#ifdef IP_MULTICAST_LOOP
 +              /*
 +               * Don't send back to itself, but allow it to fail to set it
 +               */
 +              if (setsockopt(iface->fd, IPPROTO_IP, IP_MULTICAST_LOOP,
 +                     (char *)&off, sizeof(off)) == -1) {
 +                      netsyslog(LOG_ERR,
 +                      "setsockopt IP_MULTICAST_LOOP failure: %m on socket %d, addr %s for multicast address %s",
 +                      iface->fd, stoa(&iface->sin), stoa(maddr));
 +              }
 +#endif
+               DPRINTF(1, ("Added IPv4 multicast interface on socket %d, addr %s for multicast address %s\n",
+                           iface->fd, stoa(&iface->sin),
+                           stoa(maddr)));
                break;
        case AF_INET6:
  #ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
                if (setsockopt(iface->fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
                        stoa(maddr));
                        return;
                }
- #ifdef DEBUG
-               if (debug > 0) {
-                       printf(
-                       "Added IPv6 multicast interface on socket %d, addr %s, scope %d for multicast address %s\n",
-                       iface->fd,  stoa(&iface->sin), iface->scopeid,
-                       stoa(maddr));
-               }
- #endif
 +#ifdef IPV6_MULTICAST_LOOP
 +              /*
 +               * Don't send back to itself, but allow it to fail to set it
 +               */
 +              if (setsockopt(iface->fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
 +                     (char *)&off, sizeof(off)) == -1) {
 +                      netsyslog(LOG_ERR,
 +                      "setsockopt IP_MULTICAST_LOOP failure: %m on socket %d, addr %s for multicast address %s",
 +                      iface->fd, stoa(&iface->sin), stoa(maddr));
 +              }
 +#endif
+               DPRINTF(1, ("Added IPv6 multicast interface on socket %d, addr %s, scope %d for multicast address %s\n",
+                           iface->fd,  stoa(&iface->sin), iface->scopeid,
+                           stoa(maddr)));
                break;
  #else
                return;
@@@ -986,7 -1421,9 +1469,8 @@@ socket_multicast_enable(struct interfac
        struct ipv6_mreq mreq6;
        struct in6_addr iaddr6;
  #endif /* INCLUDE_IPV6_MULTICAST_SUPPORT */
        struct ip_mreq mreq;
 -      memset((char *)&mreq, 0, sizeof(mreq));
  
        switch (maddr->ss_family)
        {
@@@ -1283,49 -1690,41 +1739,41 @@@ io_multicast_add
                break;
        case AF_INET6:
  #ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
-               memcpy(&(((struct sockaddr_in6 *)&inter_list[ind].sin)->sin6_addr),
+               memcpy(&(((struct sockaddr_in6 *)&interface->sin)->sin6_addr),
                       &((struct sockaddr_in6*)&addr)->sin6_addr,
                       sizeof(struct in6_addr));
-               ((struct sockaddr_in6*)&inter_list[ind].sin)->sin6_port = htons(NTP_PORT);
+               ((struct sockaddr_in6*)&interface->sin)->sin6_port = htons(NTP_PORT);
  #ifdef ISC_PLATFORM_HAVESCOPEID
-               ((struct sockaddr_in6*)&inter_list[ind].sin)->sin6_scope_id = ((struct sockaddr_in6*)&addr)->sin6_scope_id;
+               ((struct sockaddr_in6*)&interface->sin)->sin6_scope_id = ((struct sockaddr_in6*)&addr)->sin6_scope_id;
  #endif
-               memset(&((struct sockaddr_in6*)&inter_list[ind].mask)->sin6_addr.s6_addr, 0xff, sizeof(struct in6_addr));
+               memset(&((struct sockaddr_in6*)&interface->mask)->sin6_addr.s6_addr, 0xff, sizeof(struct in6_addr));
  #endif
-               i = findlocalcastinterface(&addr, INT_MULTICAST);
+               iface = findlocalcastinterface(&addr, INT_MULTICAST);
  # ifdef ISC_PLATFORM_HAVESCOPEID
-               if (i >= 0)
-                       lscope = ((struct sockaddr_in6*)&inter_list[i].sin)->sin6_scope_id;
+               if (iface) {
+                       lscope = ((struct sockaddr_in6*)&iface->sin)->sin6_scope_id;
+               }
  # endif
- #ifdef DEBUG
-       if (debug > 1)
-               printf("Found interface index %d, scope: %d for address %s\n",
-                       i, lscope, stoa(&addr));
- #endif
+               DPRINTF(1, ("Found interface #%d %s, scope: %d for address %s\n", iface->ifnum, iface->name, lscope, stoa(&addr)));
                break;
        }
+               
 +      set_reuseaddr(1);
-       inter_list[ind].bfd = INVALID_SOCKET;
-       inter_list[ind].fd = open_socket(&inter_list[ind].sin,
-                           INT_MULTICAST, 1, &inter_list[ind], ind);
-       set_reuseaddr(0);
+       interface->bfd = INVALID_SOCKET;
+       interface->fd = open_socket(&interface->sin,
+                           INT_MULTICAST, 1, interface);
  
-       if (inter_list[ind].fd != INVALID_SOCKET)
+       if (interface->fd != INVALID_SOCKET)
        {
-               inter_list[ind].bfd = INVALID_SOCKET;
-               inter_list[ind].ignore_packets = ISC_FALSE;
-               (void) strncpy(inter_list[ind].name, "multicast",
-                       sizeof(inter_list[ind].name));
-               ((struct sockaddr_in*)&inter_list[ind].mask)->sin_addr.s_addr =
+               interface->bfd = INVALID_SOCKET;
 -              interface->flags |= INT_MCASTIF;
+               interface->ignore_packets = ISC_FALSE;
+               
+               (void) strncpy(interface->name, "multicast",
+                       sizeof(interface->name));
+               ((struct sockaddr_in*)&interface->mask)->sin_addr.s_addr =
                                                htonl(~(u_int32)0);
-               if (ind >= ninterfaces)
-                       ninterfaces = ind + 1;
- #ifdef DEBUG
-               if(debug > 1)
-                       print_interface(ind);
- #endif
+               DPRINT_INTERFACE(2, (interface, "multicast add ", "\n"));
+               add_interface(interface);
        }
        else
        {
diff --cc ntpd/ntp_peer.c
Simple merge
Simple merge
index 34401666e6debcffa5eba580d08c5b63d2f1bbb9,28878125274c528d37f5383cf9079a51e2d26f29..9d03b3527851947d96b7397f6727ee2158649e2b
@@@ -963,19 -973,20 +983,23 @@@ peer_stats 
  
                if ((pp = findexistingpeer(&addr, (struct peer *)0, -1)) == 0)
                    continue;
 -              printf("peer_stats: found %s\n", stoa(&addr));
 +#ifdef DEBUG
 +              if (debug)
 +                   printf("peer_stats: found %s\n", stoa(&addr));
 +#endif
                if (pp->srcadr.ss_family == AF_INET) {
-                       ip->dstadr = (pp->processed) ?
-                               pp->cast_flags == MDF_BCAST ?
-                               GET_INADDR(pp->dstadr->bcast):
-                               pp->cast_flags ?
-                               GET_INADDR(pp->dstadr->sin) ?
-                               GET_INADDR(pp->dstadr->sin):
-                               GET_INADDR(pp->dstadr->bcast):
-                               3 : 7;
+                       if (pp->dstadr)
+                               ip->dstadr = (pp->processed) ?
+                                       pp->cast_flags == MDF_BCAST ?
+                                       GET_INADDR(pp->dstadr->bcast):
+                                       pp->cast_flags ?
+                                       GET_INADDR(pp->dstadr->sin) ?
+                                       GET_INADDR(pp->dstadr->sin):
+                                       GET_INADDR(pp->dstadr->bcast):
+                                       3 : 7;
+                       else
+                               memset(&ip->dstadr, 0, sizeof(ip->dstadr));
+                       
                        ip->srcadr = GET_INADDR(pp->srcadr);
                        if (client_v6_capable)
                                ip->v6_flag = 0;
@@@ -1317,7 -1329,7 +1345,7 @@@ do_conf
                    && temp_cp.hmode != MODE_BROADCAST)
                    fl = 1;
                if (temp_cp.flags & ~(CONF_FLAG_AUTHENABLE | CONF_FLAG_PREFER
-                                 | CONF_FLAG_BURST | CONF_FLAG_IBURST | CONF_FLAG_SKEY))
 -                                | CONF_FLAG_BURST | CONF_FLAG_SKEY | CONF_FLAG_DYNAMIC))
++                                | CONF_FLAG_BURST | CONF_FLAG_IBURST | CONF_FLAG_SKEY | CONF_FLAG_DYNAMIC))
                    fl = 1;
                cp = (struct conf_peer *)
                    ((char *)cp + INFO_ITEMSIZE(inpkt->mbz_itemsize));
  
                fl = 0;
                if (temp_cp.flags & CONF_FLAG_AUTHENABLE)
-                   fl |= FLAG_AUTHENABLE;
+                       fl |= FLAG_AUTHENABLE;
                if (temp_cp.flags & CONF_FLAG_PREFER)
-                   fl |= FLAG_PREFER;
+                       fl |= FLAG_PREFER;
                if (temp_cp.flags & CONF_FLAG_BURST)
 -                      fl |= FLAG_BURST;
 +                  fl |= FLAG_BURST;
 +              if (temp_cp.flags & CONF_FLAG_IBURST)
 +                  fl |= FLAG_IBURST;
                if (temp_cp.flags & CONF_FLAG_SKEY)
                        fl |= FLAG_SKEY;
+               if (temp_cp.flags & CONF_FLAG_DYNAMIC)
+                       fl |= FLAG_DYNAMIC;
+               
                if (client_v6_capable && temp_cp.v6_flag != 0) {
                        peeraddr.ss_family = AF_INET6;
                        GET_INADDR6(peeraddr) = temp_cp.peeraddr6; 
diff --cc ntpd/ntp_util.c
Simple merge
Simple merge
diff --cc ntpdc/ntpdc.c
index dc3d1a929e75497cd121c76766b292ac0c018bf0,7afd6682907ea9a78bae01f62b1b33d488428aea..ade870a4c0cd9cba6e9db6ba6253e00c0eea609b
@@@ -863,10 -857,10 +863,10 @@@ sendrequest
                qpkt.mbz_itemsize = MBZ_ITEMSIZE(qsize);
        } else {
                qpkt.err_nitems = ERR_NITEMS(0, 0);
-               qpkt.mbz_itemsize = MBZ_ITEMSIZE(0);
+               qpkt.mbz_itemsize = MBZ_ITEMSIZE(qsize);  /* allow for optional first item */
        }
  
 -      if (!auth) {
 +      if (!auth || (keyid_entered && info_auth_keyid == 0)) {
                qpkt.auth_seq = AUTH_SEQ(0, 0);
                return sendpkt((char *)&qpkt, req_pkt_size);
        } else {
index d1310d961e7e7cc590a02cf5ee2f25dc50531c04,b3daf6adb67fa9c6670ad5d29efe7628ec11dc06..20bee3a418577fa11411ae79e4d246dc24a3cbf4
@@@ -116,11 -118,11 +118,11 @@@ struct xcmd opcmds[] = 
        { "timerstats", timerstats,     { NO, NO, NO, NO },
          { "", "", "", "" },
          "display event timer subsystem statistics" },
 -      { "addpeer",    addpeer,        { NTP_ADD, OPT|NTP_UINT, OPT|NTP_UINT, OPT|NTP_STR },
 -        { "addr", "keyid", "version", "minpoll|prefer|dynamic" },
 +      { "addpeer",    addpeer,        { NTP_ADD, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR },
-         { "addr", "keyid", "version", "minpoll#|prefer|burst|iburst|'minpoll N'|'maxpoll N'|'keyid N'|'version N' ..." },
++        { "addr", "keyid", "version", "minpoll#|prefer|burst|iburst|dynamic|'minpoll N'|'maxpoll N'|'keyid N'|'version N' ..." },
          "configure a new peer association" },
 -      { "addserver",  addserver,      { NTP_ADD, OPT|NTP_UINT, OPT|NTP_UINT, OPT|NTP_STR },
 -        { "addr", "keyid", "version", "minpoll|prefer" },
 +      { "addserver",  addserver,      { NTP_ADD, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR },
-         { "addr", "keyid", "version", "minpoll#|prefer|burst|iburst|'minpoll N'|'maxpoll N'|'keyid N'|'version N' ..." },
++        { "addr", "keyid", "version", "minpoll#|prefer|burst|iburst|dynamic|'minpoll N'|'maxpoll N'|'keyid N'|'version N' ..." },
          "configure a new server" },
        { "addrefclock",addrefclock,    { NTP_ADD, OPT|NTP_UINT, OPT|NTP_STR, OPT|NTP_STR },
          { "addr", "mode", "minpoll|prefer", "minpoll|prefer" },
@@@ -1325,76 -1337,30 +1332,78 @@@ again
                    flags |= CONF_FLAG_PREFER;
                else if (STREQ(pcmd->argval[items].string, "burst"))
                    flags |= CONF_FLAG_BURST;
+               else if (STREQ(pcmd->argval[items].string, "dynamic"))
+                     flags |= CONF_FLAG_DYNAMIC;
 +              else if (STREQ(pcmd->argval[items].string, "iburst"))
 +                  flags |= CONF_FLAG_IBURST;
 +              else if (!refc && STREQ(pcmd->argval[items].string, "keyid"))
 +                  numtyp = 1;
 +              else if (!refc && STREQ(pcmd->argval[items].string, "version"))
 +                  numtyp = 2;
 +              else if (STREQ(pcmd->argval[items].string, "minpoll"))
 +                  numtyp = 3;
 +              else if (STREQ(pcmd->argval[items].string, "maxpoll"))
 +                  numtyp = 4;
                else {
                        long val;
 -                      if (!atoint(pcmd->argval[items].string, &val)) {
 -                              (void) fprintf(fp,
 -                                  "%s not understood\n",
 -                                  pcmd->argval[items].string);
 -                              res++;
 -                              break;
 -                      } else {
 -                              if (val >= NTP_MINPOLL && val <= NTP_MAXPOLL) {
 -                                      minpoll = (u_char)val;
 -                              } else {
 -                                      (void) fprintf(fp,
 -                                                     "minpol must be within %d..%d\n",
 -                                                     NTP_MINPOLL, NTP_MAXPOLL);
 -                                      res++;
 -                                      break;
 -                              }                                       
 +                      if (!atoint(pcmd->argval[items].string, &val))
 +                           numtyp = 0;                                  
 +                      switch (numtyp) {
 +                      case 1:
 +                           keyid = val;
 +                           numtyp = 2;                                  
 +                           break;
 +                           
 +                      case 2:
 +                           version = (u_int) val;
 +                           numtyp = 0;                                  
 +                           break;
 +
 +                      case 3:
 +                           minpoll = (u_char)val;
 +                           numtyp = 0;                                  
 +                           break;
 +
 +                      case 4:
 +                           maxpoll = (u_char)val;
 +                           numtyp = 0;                                  
 +                           break;
 +
 +                      case 5:
 +                           cmode = (u_char)val;
 +                           numtyp = 0;                                  
 +                           break;
 +
 +                      default:
 +                           (void) fprintf(fp, "*** '%s' not understood\n",
 +                                          pcmd->argval[items].string);
 +                           res++;
 +                           numtyp = 0;                                  
                        }
 -              }
 -              items++;
 +                      if (val < 0) {
 +                           (void) fprintf(stderr,
 +                                   "***Value '%s' should be unsigned\n",
 +                                    pcmd->argval[items].string);
 +                           res++;
 +                      }
 +                 }
 +           items++;
 +      }
 +      if (keyid > 0)
 +           flags |= CONF_FLAG_AUTHENABLE;
 +      if (version > NTP_VERSION ||
 +          version < NTP_OLDVERSION) {
 +           (void)fprintf(fp, "***invalid version number: %u\n",
 +                         version);
 +           res++;
        }
 +      if (minpoll < NTP_MINPOLL || minpoll > NTP_MAXPOLL || 
 +          maxpoll < NTP_MINPOLL || maxpoll > NTP_MAXPOLL || 
 +          minpoll > maxpoll) {
 +           (void) fprintf(fp, "***min/max-poll must be within %d..%d\n",
 +                          NTP_MINPOLL, NTP_MAXPOLL);
 +           res++;
 +      }                                       
  
        if (res)
            return;