diff -up -pr ../ntp-4.2.2/include/ntpd.h ./include/ntpd.h
--- ../ntp-4.2.2/include/ntpd.h 2006-06-06 13:16:20.000000000 -0700
+++ ./include/ntpd.h 2006-06-08 11:10:47.000000000 -0700
@@ -88,6 +88,7 @@ extern void wait_for_signal P((void));
extern void unblock_io_and_alarm P((void));
extern void block_io_and_alarm P((void));
#endif
+extern int rebind_interfaces P((void));
/* ntp_leap.c */
extern void init_leap P((void));
@@ -202,6 +203,7 @@ extern void init_timer P((void));
extern void reinit_timer P((void));
extern void timer P((void));
extern void timer_clr_stats P((void));
+extern u_long rebind_timer;
#ifdef OPENSSL
extern char *sys_hostname;
extern l_fp sys_revoketime;
diff -up -pr ../ntp-4.2.2/ntpd/ntp_io.c ./ntpd/ntp_io.c
--- ../ntp-4.2.2/ntpd/ntp_io.c 2006-06-06 13:16:41.000000000 -0700
+++ ./ntpd/ntp_io.c 2006-06-08 11:11:34.000000000 -0700
@@ -590,6 +590,165 @@ convert_isc_if(isc_interface_t *isc_if,
itf->flags |= INT_MULTICAST;
}
+
+static int
+find_isc_if(isc_interface_t *result_isc_if, char *name, int family,
+ struct sockaddr_storage *addr) {
+ isc_mem_t *mctx = NULL;
+ isc_interfaceiter_t *iter = NULL;
+ isc_result_t result;
+
+ result = isc_interfaceiter_create(mctx, &iter);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ for (result = isc_interfaceiter_first(iter);
+ result == ISC_R_SUCCESS;
+ result = isc_interfaceiter_next(iter))
+ {
+ result = isc_interfaceiter_current(iter, result_isc_if);
+ if (result != ISC_R_SUCCESS)
+ break;
+ if (strcmp(result_isc_if->name, name))
+ continue;
+ if (result_isc_if->af != family)
+ continue;
+ if (SOCKCMP(&result_isc_if->address.type.in, addr))
+ continue;
+ break; /* found it */
+ }
+ isc_interfaceiter_destroy(&iter);
+ return result;
+}
+
+static int
+disable_interface(struct interface *inter)
+{
+ int fd = inter->fd;
+ if (fd != INVALID_SOCKET) {
+ msyslog(LOG_INFO, "Interface %s %s unavailable", inter->name, stoa(&inter->sin));
+ inter->fd = INVALID_SOCKET;
+ if (inter->bfd == fd)
+ inter->bfd = INVALID_SOCKET;
+ BLOCKIO();
+ close_socket(fd);
+ UNBLOCKIO();
+ if (inter->bfd != INVALID_SOCKET) {
+ fd = inter->bfd;
+ inter->bfd = INVALID_SOCKET;
+ BLOCKIO();
+ close_socket(fd);
+ UNBLOCKIO();
+ }
+ inter->flags = 0;
+ inter->num_mcast = inter->received = inter->sent = inter->notsent = 0;
+ inter->ignore_packets = ISC_TRUE;
+ return 1;
+ }
+ return 0;
+}
+
+/* Call when sendto has EADDRNOTAVAIL */
+static int
+rebind_interface(struct interface *inter, isc_interface_t *isc_if, int *changed) {
+ isc_interface_t isc_if_local;
+ int fd;
+
+ if ((inter == any_interface) || /* never kill wildcards */
+ (inter == any6_interface))
+ return 0;
+ if (isc_if == NULL) {
+ isc_if = &isc_if_local;
+ if (ISC_R_SUCCESS != find_isc_if(isc_if, inter->name, inter->family, &inter->sin)) {
+ /* Interface is gone */
+ if (disable_interface(inter))
+ *changed = TRUE; /* rebind all clients */
+ return 0;
+ }
+ }
+ /* Did state or IP address change? */
+ if (((inter->family == AF_INET) &&
+ memcmp(&(((struct sockaddr_in*)&inter->sin)->sin_addr),
+ &(isc_if->address.type.in),
+ sizeof(struct in_addr))) ||
+ ((inter->family == AF_INET6) &&
+ memcmp(&(((struct sockaddr_in6 *)&inter->sin)->sin6_addr),
+ &(isc_if->address.type.in6),
+ sizeof(struct in6_addr)))) {
+ *changed = TRUE;
+ msyslog(LOG_DEBUG, "Address %s is going away", stoa(&inter->sin));
+ }
+ if (((isc_if->flags & INTERFACE_F_UP)!=0) != ((inter->flags & INT_UP)!=0)) {
+ *changed = TRUE;
+ msyslog(LOG_DEBUG, "Interface state toggled");
+ }
+ if (*changed) {
+ inter->flags = 0;
+ convert_isc_if(isc_if, inter, htons(NTP_PORT));
+ /*
+ * Calculate the address hash for each interface address.
+ */
+ inter->addr_refid = addr2refid(&inter->sin);
+ fd = inter->fd;
+ if (fd != INVALID_SOCKET) {
+ msyslog(LOG_DEBUG, "Closing socket for interface %s", isc_if->name);
+ inter->fd = INVALID_SOCKET;
+ if (fd == inter->bfd)
+ inter->bfd = INVALID_SOCKET;
+ BLOCKIO();
+ close_socket(fd);
+ UNBLOCKIO();
+ }
+ if (inter->bfd != INVALID_SOCKET) {
+ fd = inter->bfd;
+ inter->bfd = INVALID_SOCKET;
+ BLOCKIO();
+ close_socket(inter->bfd);
+ UNBLOCKIO();
+ }
+ if (inter->flags & INT_UP) {
+ set_reuseaddr(1);
+ inter->fd = open_socket(&inter->sin, inter->flags, 0, inter, inter->ifindex);
+ set_reuseaddr(0);
+ if (inter->fd != INVALID_SOCKET) {
+ inter->ignore_packets = ISC_FALSE;
+ msyslog(LOG_INFO, "Listening on interface %s, %s#%d %s",
+ inter->name,
+ stoa((&inter->sin)),
+ NTP_PORT,
+ (inter->ignore_packets == ISC_FALSE) ?
+ "Enabled": "Disabled");
+ } else {
+ msyslog(LOG_ERR, "Interface %s %s failed to bind", inter->name, stoa(&inter->sin));
+ return 1;
+ }
+ } else {
+ msyslog(LOG_ERR, "%s: should not get here %s:%d", __FUNCTION__, __FILE__, __LINE__);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* refresh interface of peers using inter */
+static void
+rebind_peers(struct interface *inter)
+{
+ struct peer *peer, *next_peer;
+ int n;
+
+ for (n = 0; n < NTP_HASH_SIZE; n++) {
+ for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
+ next_peer = peer->next;
+ if (peer->dstadr == inter || inter == 0) { /* inter==0 rebind all peers */
+ char *src = stoa(&peer->srcadr); /* stoa cycles thru buffers */
+ peer->dstadr = findinterface(&peer->srcadr);
+ msyslog(LOG_DEBUG, "Peer %s using interface %s %s", src, peer->dstadr->name, stoa(&peer->dstadr->sin));
+ }
+ }
+ }
+}
+
/*
* create_sockets - create a socket for each interface plus a default
* socket for when we don't know where to send
@@ -1977,6 +2136,28 @@ sendpkt(
netsyslog(LOG_ERR, "sendto(%s) (fd=%d): %m",
stoa(dest), inter->fd);
+#ifdef __APPLE__
+ switch (errno) { /* interface probably changed address or disconnected */
+ case ENETDOWN:
+ /* just ignore */
+ break;
+
+ case EADDRNOTAVAIL:
+ case EHOSTUNREACH:
+ case ENETUNREACH:
+ {
+ int changed = FALSE;
+ rebind_interface(inter, NULL, &changed);
+ if (changed)
+ rebind_peers(inter); /* refresh all peers using this interface */
+ break;
+ }
+
+ default:
+ msyslog(LOG_DEBUG, "rebind_interface not triggered on errno %d", errno);
+ break;
+ }
+#endif /* __APPLE__ */
}
}
else
@@ -2111,7 +2292,7 @@ read_refclock_packet(SOCKET fd, struct r
static inline int
read_network_packet(SOCKET fd, struct interface *itf, l_fp ts)
{
- int fromlen;
+ socklen_t fromlen;
int buflen;
register struct recvbuf *rb;
@@ -2397,7 +2578,7 @@ findlocalinterface(
SOCKET s;
int rtn, i, idx;
struct sockaddr_storage saddr;
- int saddrlen = SOCKLEN(addr);
+ socklen_t saddrlen = SOCKLEN(addr);
#ifdef DEBUG
if (debug>2)
printf("Finding interface for addr %s in list of addresses\n",
@@ -2957,3 +3138,146 @@ find_flagged_addr_in_list(struct sockadd
}
return (-1); /* Not found */
}
+
+static int
+add_interface(isc_interface_t *new_isc_if)
+{
+ /* Any free slots? */
+ int i;
+ struct interface *itf = inter_list+nwilds;
+ for (i = nwilds; i < ninterfaces; i++, itf++) {
+ if (itf->fd == INVALID_SOCKET &&
+ itf->bfd == INVALID_SOCKET)
+ break;
+ }
+ if (i >= MAXINTERFACES) {
+ msyslog(LOG_ERR, "Too many interfaces %d", i);
+ return 1;
+ } else {
+ struct sockaddr_storage resmask;
+ memset(itf, 0, sizeof(*itf));
+ itf->fd = INVALID_SOCKET;
+ itf->bfd = INVALID_SOCKET;
+ convert_isc_if(new_isc_if, itf, htons(NTP_PORT));
+ itf->addr_refid = addr2refid(&itf->sin);
+ itf->ignore_packets = !address_okay(new_isc_if);
+ if (i == ninterfaces) {
+ ninterfaces++;
+ }
+ SET_HOSTMASK(&resmask, itf->sin.ss_family);
+ hack_restrict(RESTRICT_FLAGS, &itf->sin, &resmask,
+ RESM_NTPONLY|RESM_INTERFACE, RES_IGNORE);
+ if (itf->flags & INT_UP) {
+ itf->ignore_packets = FALSE;
+ set_reuseaddr(1);
+ itf->fd = open_socket(&itf->sin, itf->flags, 0, itf, itf->ifindex);
+ set_reuseaddr(0);
+ if (itf->fd != INVALID_SOCKET) {
+ itf->ignore_packets = ISC_FALSE;
+ msyslog(LOG_INFO, "Listening on interface %s, %s#%d %s",
+ itf->name,
+ stoa((&itf->sin)),
+ NTP_PORT,
+ (itf->ignore_packets == ISC_FALSE) ?
+ "Enabled": "Disabled");
+ return 0;
+ } else {
+ msyslog(LOG_ERR, "Interface %s %s failed to bind", itf->name, stoa((&itf->sin)));
+ return 1;
+ }
+ } else {
+ msyslog(LOG_ERR, "Error: Adding down interface %s %s",
+ itf->name, stoa((&itf->sin)));
+ itf->ignore_packets = TRUE;
+ }
+ return 0;
+ }
+}
+
+int
+rebind_interfaces(void)
+{
+ int changed = FALSE;
+ isc_mem_t *mctx = NULL;
+ isc_interfaceiter_t *iter = NULL;
+ int adds = 0;
+ isc_interface_t *isc_if_add = NULL;
+ isc_result_t result;
+ int i;
+
+ result = isc_interfaceiter_create(mctx, &iter);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ int *still_alive = (int *)calloc(sizeof(int), ninterfaces);
+ if (!still_alive)
+ return -1;
+
+ for (result = isc_interfaceiter_first(iter);
+ result == ISC_R_SUCCESS;
+ result = isc_interfaceiter_next(iter))
+ {
+ isc_interface_t isc_if;
+
+ result = isc_interfaceiter_current(iter, &isc_if);
+ if (result != ISC_R_SUCCESS) {
+ msyslog(LOG_ERR, "isc_interfaceiter_current failed");
+ break;
+ }
+
+ if (0 == (isc_if.flags & INTERFACE_F_UP)) /* delete disabled interfaces */
+ continue;
+ /* First process known interfaces */
+ for (i = nwilds; i < ninterfaces; i++) { /* skip wilds */
+ if (inter_list[i].fd == INVALID_SOCKET)
+ continue;
+ if (isc_if.af != inter_list[i].family)
+ continue;
+ if (strcmp(isc_if.name, inter_list[i].name))
+ continue;
+ if ((inter_list[i].family == AF_INET) &&
+ memcmp(&(((struct sockaddr_in*)&inter_list[i].sin)->sin_addr),
+ &(isc_if.address.type.in),
+ sizeof(struct in_addr)))
+ continue;
+ if ((inter_list[i].family == AF_INET6) &&
+ memcmp(&(((struct sockaddr_in6 *)&inter_list[i].sin)->sin6_addr),
+ &(isc_if.address.type.in6),
+ sizeof(struct in6_addr)))
+ continue;
+
+ int c = FALSE;
+ rebind_interface(inter_list+i, &isc_if, &c);
+ changed |= c;
+ still_alive[i] = TRUE; /* don't disable this interface */
+ break;
+ }
+ if (0 == (isc_if.flags & INTERFACE_F_UP))
+ continue; /* down interfaces are not useful */
+
+ if (i == ninterfaces) { /* new interface/address */
+ changed = TRUE;
+ isc_if_add = reallocf(isc_if_add, sizeof(isc_interface_t) * (adds+1));
+ if (isc_if_add) {
+ isc_if_add[adds] = isc_if;
+ adds++;
+ }
+ }
+ }
+ isc_interfaceiter_destroy(&iter);
+
+ for (i = nwilds; i < ninterfaces; i++) {
+ if (!still_alive[i])
+ if (disable_interface(inter_list+i))
+ changed = TRUE;
+ }
+ free(still_alive);
+ for (i = 0; i < adds; i++) {
+ add_interface(isc_if_add+i);
+ }
+ realloc(isc_if_add, 0);
+
+ if (changed)
+ rebind_peers(0);
+ return result;
+}
diff -up -pr ../ntp-4.2.2/ntpd/ntp_proto.c ./ntpd/ntp_proto.c
--- ../ntp-4.2.2/ntpd/ntp_proto.c 2006-06-06 13:16:43.000000000 -0700
+++ ./ntpd/ntp_proto.c 2006-06-08 11:10:47.000000000 -0700
@@ -2053,6 +2053,7 @@ clock_select(void)
msyslog(LOG_INFO,
"no servers reachable");
report_event(EVNT_PEERSTCHG, NULL);
+ rebind_interfaces();
}
}
}
diff -up -pr ../ntp-4.2.2/ntpd/ntp_timer.c ./ntpd/ntp_timer.c
--- ../ntp-4.2.2/ntpd/ntp_timer.c 2006-06-06 13:16:46.000000000 -0700
+++ ./ntpd/ntp_timer.c 2006-06-08 11:10:47.000000000 -0700
@@ -46,6 +46,7 @@ static u_long adjust_timer; /* second t
static u_long keys_timer; /* minute timer */
static u_long stats_timer; /* stats timer */
static u_long huffpuff_timer; /* huff-n'-puff timer */
+u_long rebind_timer;
#ifdef OPENSSL
static u_long revoke_timer; /* keys revoke timer */
u_char sys_revoke = KEY_REVOKE; /* keys revoke timeout (log2 s) */
@@ -154,7 +155,7 @@ init_timer(void)
timer_overflows = 0;
timer_xmtcalls = 0;
timer_timereset = 0;
-
+ rebind_timer = 0;
#if !defined(SYS_WINNT)
/*
* Set up the alarm interrupt. The first comes 2**EVENT_TIMEOUT
@@ -343,6 +344,10 @@ timer(void)
write_stats();
stats_timer += stats_write_period;
}
+ if (rebind_timer != 0 && rebind_timer <= current_time) {
+ rebind_timer = 0;
+ rebind_interfaces();
+ }
}
diff -up -pr ../ntp-4.2.2/ntpd/ntpd.c ./ntpd/ntpd.c
--- ../ntp-4.2.2/ntpd/ntpd.c 2006-06-06 13:16:46.000000000 -0700
+++ ./ntpd/ntpd.c 2006-06-08 11:10:47.000000000 -0700
@@ -114,6 +114,9 @@
#endif
#endif
+#ifdef __APPLE__
+#include <notify.h>
+#endif /* __APPLE__ */
/*
* Signals we catch for debugging. If not debugging we ignore them.
*/
@@ -149,6 +152,7 @@ int priority_done = 2; /* 0 - Set prior
* Debugging flag
*/
volatile int debug;
+volatile int info_flag;
/*
* Set the processing not to be in the forground
@@ -206,6 +210,7 @@ static RETSIGTYPE lessdebug P((int));
static RETSIGTYPE no_debug P((int));
#endif /* not DEBUG */
+static RETSIGTYPE info P((int));
int ntpdmain P((int, char **));
static void set_process_priority P((void));
static void init_logging P((char *));
@@ -707,6 +712,11 @@ ntpdmain(
(void) signal_no_reset(SIGPIPE, SIG_IGN);
#endif /* SIGPIPE */
+#ifdef __APPLE__
+ int token;
+ (void) signal_no_reset(SIGINFO, info);
+ notify_register_signal("com.apple.system.config.network_change", SIGINFO, &token);
+#endif /* __APPLE__ */
/*
* Call the init_ routines to initialize the data structures.
*/
@@ -895,6 +905,11 @@ getgroup:
alarm_flag = 0;
}
+ if (info_flag) {
+ info_flag = 0;
+ /* 6 is too short for ipv6 duplicate address detection */
+ rebind_timer = current_time + 10; /* let all changes settle down */
+ }
if (!was_alarmed && has_full_recv_buffer() == ISC_FALSE)
{
/*
@@ -1080,3 +1095,11 @@ no_debug(
}
#endif /* not SYS_WINNT */
#endif /* not DEBUG */
+
+static RETSIGTYPE
+info(
+ int sig
+ )
+{
+ info_flag = 1;
+}
diff -up -pr ../ntp-4.2.2/ntpdc/nl.pl ./ntpdc/nl.pl
--- ../ntp-4.2.2/ntpdc/nl.pl 2006-06-06 14:11:24.000000000 -0700
+++ ./ntpdc/nl.pl 2006-06-08 11:10:47.000000000 -0700
@@ -1,4 +1,4 @@
-#! /usr/local/bin/perl -w
+#! /usr/bin/perl -w
$found = 0;
$last = 0;