From: Frank Kardel Date: Tue, 14 Mar 2006 08:12:18 +0000 (+0000) Subject: Merge bk://www.ntp.org/home/bk/ntp-dev X-Git-Tag: NTP_4_2_3P2~5^2~14 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a539269e442e620f3a42ac72d6277d7e336e90cc;p=thirdparty%2Fntp.git Merge bk://www.ntp.org/home/bk/ntp-dev into pogo.udel.edu:/pogo/users/kardel/dynamic-if/ntp-dev bk: 44167ae2SGwDQ61o9pG6H24dlGpdPg --- a539269e442e620f3a42ac72d6277d7e336e90cc diff --cc html/ntpdc.html index d6b7ab9e9,14f01e436..62f184a4d --- a/html/ntpdc.html +++ b/html/ntpdc.html @@@ -127,53 -119,12 +131,53 @@@

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.

The following commands all make authenticated requests.

-
addpeer peer_address [ keyid ] [ version ] [ prefer ] [ dynamic ] -
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 keyid 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 version# can be 1, 2 or 3 and defaults to 3. The prefer 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 dynamic 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. -
addserver peer_address [ keyid ] [ version ] [ prefer ] [ dynamic ] +
addpeer peer_address [ + keyid ] [ version ] [ + minpoll# | prefer | iburst | burst | minpoll - N | maxpoll N [...] ] ++ N | maxpoll N [ dynamic ] [...] ] +
addpeer peer_address [ + prefer | iburst | burst | minpoll + N | maxpoll N | keyid + N | version N [...] ] +
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 keyid + 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 (e.g., by the keyid + command), it will be set to this value. + The version# can be 1 through 4 and defaults to 3. The remaining + options are either a numeric value for minpoll or + literals prefer, iburst, + burst, minpoll N, + keyid N, version N, or + maxpoll N (where N is a numeric value), and have the action as specified in the + peer configuration file command of + ntpd. See the Server Options page for further information. + Each flag (or its absence) replaces the + previous setting. The prefer 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 dynamic 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. +
addserver peer_address [ + keyid ] [ version ] [ + minpoll# | prefer | iburst | burst | minpoll + N | maxpoll N [...] ] +
addserver peer_address [ + prefer | iburst | burst | minpoll + N | maxpoll N | keyid - N | version N [...] ] - ++ N | version N [...] [ dynamic ] ]
Identical to the addpeer command, except that the operating mode is client. -
broadcast peer_address [ keyid ] [ version ] [ prefer ] -
Identical to the addpeer command, except that the operating mode is broadcast. In this case a valid key identifier and key are required. The peer_address 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. +
broadcast peer_address [ + keyid ] [ version ] [ prefer ] +
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 peer_address 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.
unconfig peer_address [...]
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.
fudge peer_address [ time1 ] [ time2 ] [ stratum ] [ refid ] diff --cc ntpd/ntp_io.c index 1fb107a6a,36b791f54..0b24a6aea --- a/ntpd/ntp_io.c +++ b/ntpd/ntp_io.c @@@ -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 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 - #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 + 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, @@@ -943,25 -1397,9 +1434,20 @@@ stoa(maddr)); return; } +#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 - #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 + 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_request.c index 34401666e,288781252..9d03b3527 --- a/ntpd/ntp_request.c +++ b/ntpd/ntp_request.c @@@ -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)); @@@ -1341,15 -1353,16 +1369,18 @@@ 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 ntpdc/ntpdc.c index dc3d1a929,7afd66829..ade870a4c --- a/ntpdc/ntpdc.c +++ b/ntpdc/ntpdc.c @@@ -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 { diff --cc ntpdc/ntpdc_ops.c index d1310d961,b3daf6adb..20bee3a41 --- a/ntpdc/ntpdc_ops.c +++ b/ntpdc/ntpdc_ops.c @@@ -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;