FreeBSD/contrib/ntp/ntpd/ntp_io.c
/*
 * update_interface strategy
 *
 * toggle configuration phase
 *
 * Phase 1:
 * forall currently existing interfaces
 *   if address is known:
 *	drop socket - rebind again
 *
 *   if address is NOT known:
 *	attempt to create a new interface entry
 *
 * Phase 2:
 * forall currently known non MCAST and WILDCARD interfaces
 *   if interface does not match configuration phase (not seen in phase 1):
 *	remove interface from known interface list
 *	forall peers associated with this interface
 *         disconnect peer from this interface
 *
 * Phase 3:
 *   attempt to re-assign interfaces to peers
 *
 */
update_interface strategy
toggle configuration phase

Phase 1:
forall currently existing interfaces
if address is known:
drop socket - rebind again

if address is NOT known:
attempt to create a new interface entry

Phase 2:
forall currently known non MCAST and WILDCARD interfaces
if interface does not match configuration phase (not seen in phase 1):
remove interface from known interface list
forall peers associated with this interface
disconnect peer from this interface

Phase 3:
attempt to re-assign interfaces to peers
update_interface strategy toggle configuration phase Phase 1 : forall currently existing interfaces if address is known : drop socket - rebind again if address is NOT known : attempt to create a new interface entry Phase 2 : forall currently known non MCAST and WILDCARD interfaces if interface does not match configuration phase ( not seen in phase 1 ) : remove interface from known interface list forall peers associated with this interface disconnect peer from this interface Phase 3 : attempt to re - assign interfaces to peers
static int
update_interfaces(
	u_short			port,
	interface_receiver_t	receiver,
	void *			data
	)
{
	isc_mem_t *		mctx = (void *)-1;
	interface_info_t	ifi;
	isc_interfaceiter_t *	iter;
	isc_result_t		result;
	isc_interface_t		isc_if;
	int			new_interface_found;
	unsigned int		family;
	endpt			enumep;
	endpt *			ep;
	endpt *			next_ep;
	DPRINTF(3, ("update_interfaces(%d)\n", port));
	new_interface_found = FALSE;
	iter = NULL;
	result = isc_interfaceiter_create(mctx, &iter);
	if (result != ISC_R_SUCCESS)
		return 0;
	sys_interphase ^= 0x1;
	for (result = isc_interfaceiter_first(iter);
	     ISC_R_SUCCESS == result;
	     result = isc_interfaceiter_next(iter)) {
		result = isc_interfaceiter_current(iter, &isc_if);
		if (result != ISC_R_SUCCESS)
			break;
		family = isc_if.address.family;
		if (AF_INET != family && AF_INET6 != family)
			continue;
		if (AF_INET == family && !ipv4_works)
			continue;
		if (AF_INET6 == family && !ipv6_works)
			continue;
		init_interface(&enumep);
		convert_isc_if(&isc_if, &enumep, port);
		DPRINT_INTERFACE(4, (&enumep, "examining ", "\n"));
		switch (interface_action(enumep.name, &enumep.sin,
					 enumep.flags)) {
		case ACTION_IGNORE:
			DPRINTF(4, ("ignoring interface %s (%s) - by nic rules\n",
				    enumep.name, stoa(&enumep.sin)));
			continue;
		case ACTION_LISTEN:
			DPRINTF(4, ("listen interface %s (%s) - by nic rules\n",
				    enumep.name, stoa(&enumep.sin)));
			enumep.ignore_packets = ISC_FALSE;
			break;
		case ACTION_DROP:
			DPRINTF(4, ("drop on interface %s (%s) - by nic rules\n",
				    enumep.name, stoa(&enumep.sin)));
			enumep.ignore_packets = ISC_TRUE;
			break;
		}
		if (!(enumep.flags & INT_UP)) {
			DPRINTF(4, ("skipping interface %s (%s) - DOWN\n",
				    enumep.name, stoa(&enumep.sin)));
			continue;
		}
		if (is_wildcard_addr(&enumep.sin))
			continue;
		if (is_anycast(&enumep.sin, isc_if.name))
			continue;
		if (!is_valid(&enumep.sin, isc_if.name))
			continue;
		ep = getinterface(&enumep.sin, INT_WILDCARD);
		if (ep != NULL && refresh_interface(ep)) {
			if (ep->phase != sys_interphase) {
				strlcpy(ep->name, enumep.name,
					sizeof(ep->name));
				ep->ignore_packets =
					    enumep.ignore_packets;
			} else {
				strlcpy(ep->name, "*multiple*",
					sizeof(ep->name));
			}
			DPRINT_INTERFACE(4, (ep, "updating ",
					     " present\n"));
			if (ep->ignore_packets !=
			    enumep.ignore_packets) {
				msyslog(LOG_ERR,
					"WARNING: conflicting enable configuration for interfaces %s and %s for address %s - unsupported configuration - address DISABLED",
					enumep.name, ep->name,
					stoa(&enumep.sin));
				ep->ignore_packets = ISC_TRUE;
			}
			ep->phase = sys_interphase;
			ifi.action = IFS_EXISTS;
			ifi.ep = ep;
			if (receiver != NULL)
				(*receiver)(data, &ifi);
		} else {
			ep = create_interface(port, &enumep);
			if (ep != NULL) {
				ifi.action = IFS_CREATED;
				ifi.ep = ep;
				if (receiver != NULL)
					(*receiver)(data, &ifi);
				new_interface_found = TRUE;
				DPRINT_INTERFACE(3,
					(ep, "updating ",
					 " new - created\n"));
			} else {
				DPRINT_INTERFACE(3,
					(&enumep, "updating ",
					 " new - creation FAILED"));
				msyslog(LOG_INFO,
					"failed to init interface for address %s",
					stoa(&enumep.sin));
				continue;
			}
		}
	}
	isc_interfaceiter_destroy(&iter);
	for (ep = ep_list; ep != NULL; ep = next_ep) {
		next_ep = ep->elink;
		if (((INT_WILDCARD | INT_MCASTIF) & ep->flags) ||
		    ep->phase == sys_interphase)
			continue;
		DPRINT_INTERFACE(3, (ep, "updating ",
				     "GONE - deleting\n"));
		remove_interface(ep);
		ifi.action = IFS_DELETED;
		ifi.ep = ep;
		if (receiver != NULL)
			(*receiver)(data, &ifi);
		while (ep->peers != NULL)
			set_peerdstadr(ep->peers, NULL);
		if (ep == loopback_interface)
			loopback_interface = NULL;
		delete_interface(ep);
	}
	refresh_all_peerinterfaces();
	if (broadcast_client_enabled)
		io_setbclient();
	if (sys_bclient)
		io_setbclient();
#ifdef MCAST
	for (ep = ep_list; ep != NULL; ep = ep->elink) {
		remaddr_t *entry;
		if (!(INT_MCASTIF & ep->flags) || (INT_MCASTOPEN & ep->flags))
			continue;
		for (entry = remoteaddr_list;
		     entry != NULL;
		     entry = entry->link) {
			if (entry->ep == ep) {
				if (socket_multicast_enable(ep, &entry->addr)) {
					msyslog(LOG_INFO,
						"Joined %s socket to multicast group %s",
						stoa(&ep->sin),
						stoa(&entry->addr));
				}
				break;
			}
		}
	}
#endif 
	return new_interface_found;
}
static int update_interfaces ( u_short port , interface_receiver_t receiver , void * data ) { isc_mem_t * mctx = ( void * ) -1 ; interface_info_t ifi ; isc_interfaceiter_t * iter ; isc_result_t result ; isc_interface_t isc_if ; int new_interface_found ; unsigned int family ; endpt enumep ; endpt * ep ; endpt * next_ep ; DPRINTF ( 3 , ( " \n " , port ) ) ; new_interface_found = FALSE ; iter = NULL ; result = isc_interfaceiter_create ( mctx , & iter ) ; if ( result != ISC_R_SUCCESS ) return 0 ; sys_interphase ^= 0x1 ; for ( result = isc_interfaceiter_first ( iter ) ; ISC_R_SUCCESS == result ; result = isc_interfaceiter_next ( iter ) ) { result = isc_interfaceiter_current ( iter , & isc_if ) ; if ( result != ISC_R_SUCCESS ) break ; family = isc_if . address . family ; if ( AF_INET != family && AF_INET6 != family ) continue ; if ( AF_INET == family && ! ipv4_works ) continue ; if ( AF_INET6 == family && ! ipv6_works ) continue ; init_interface ( & enumep ) ; convert_isc_if ( & isc_if , & enumep , port ) ; DPRINT_INTERFACE ( 4 , ( & enumep , " " , " \n " ) ) ; switch ( interface_action ( enumep . name , & enumep . sin , enumep . flags ) ) { case ACTION_IGNORE : DPRINTF ( 4 , ( " \n " , enumep . name , stoa ( & enumep . sin ) ) ) ; continue ; case ACTION_LISTEN : DPRINTF ( 4 , ( " \n " , enumep . name , stoa ( & enumep . sin ) ) ) ; enumep . ignore_packets = ISC_FALSE ; break ; case ACTION_DROP : DPRINTF ( 4 , ( " \n " , enumep . name , stoa ( & enumep . sin ) ) ) ; enumep . ignore_packets = ISC_TRUE ; break ; } if ( ! ( enumep . flags & INT_UP ) ) { DPRINTF ( 4 , ( " \n " , enumep . name , stoa ( & enumep . sin ) ) ) ; continue ; } if ( is_wildcard_addr ( & enumep . sin ) ) continue ; if ( is_anycast ( & enumep . sin , isc_if . name ) ) continue ; if ( ! is_valid ( & enumep . sin , isc_if . name ) ) continue ; ep = getinterface ( & enumep . sin , INT_WILDCARD ) ; if ( ep != NULL && refresh_interface ( ep ) ) { if ( ep -> phase != sys_interphase ) { strlcpy ( ep -> name , enumep . name , sizeof ( ep -> name ) ) ; ep -> ignore_packets = enumep . ignore_packets ; } else { strlcpy ( ep -> name , " " , sizeof ( ep -> name ) ) ; } DPRINT_INTERFACE ( 4 , ( ep , " " , " \n " ) ) ; if ( ep -> ignore_packets != enumep . ignore_packets ) { msyslog ( LOG_ERR , " " , enumep . name , ep -> name , stoa ( & enumep . sin ) ) ; ep -> ignore_packets = ISC_TRUE ; } ep -> phase = sys_interphase ; ifi . action = IFS_EXISTS ; ifi . ep = ep ; if ( receiver != NULL ) ( * receiver ) ( data , & ifi ) ; } else { ep = create_interface ( port , & enumep ) ; if ( ep != NULL ) { ifi . action = IFS_CREATED ; ifi . ep = ep ; if ( receiver != NULL ) ( * receiver ) ( data , & ifi ) ; new_interface_found = TRUE ; DPRINT_INTERFACE ( 3 , ( ep , " " , " \n " ) ) ; } else { DPRINT_INTERFACE ( 3 , ( & enumep , " " , " " ) ) ; msyslog ( LOG_INFO , " " , stoa ( & enumep . sin ) ) ; continue ; } } } isc_interfaceiter_destroy ( & iter ) ; for ( ep = ep_list ; ep != NULL ; ep = next_ep ) { next_ep = ep -> elink ; if ( ( ( INT_WILDCARD | INT_MCASTIF ) & ep -> flags ) || ep -> phase == sys_interphase ) continue ; DPRINT_INTERFACE ( 3 , ( ep , " " , " \n " ) ) ; remove_interface ( ep ) ; ifi . action = IFS_DELETED ; ifi . ep = ep ; if ( receiver != NULL ) ( * receiver ) ( data , & ifi ) ; while ( ep -> peers != NULL ) set_peerdstadr ( ep -> peers , NULL ) ; if ( ep == loopback_interface ) loopback_interface = NULL ; delete_interface ( ep ) ; } refresh_all_peerinterfaces ( ) ; if ( broadcast_client_enabled ) io_setbclient ( ) ; if ( sys_bclient ) io_setbclient ( ) ; #ifdef MCAST for ( ep = ep_list ; ep != NULL ; ep = ep -> elink ) { remaddr_t * entry ; if ( ! ( INT_MCASTIF & ep -> flags ) || ( INT_MCASTOPEN & ep -> flags ) ) continue ; for ( entry = remoteaddr_list ; entry != NULL ; entry = entry -> link ) { if ( entry -> ep == ep ) { if ( socket_multicast_enable ( ep , & entry -> addr ) ) { msyslog ( LOG_INFO , " " , stoa ( & ep -> sin ) , stoa ( & entry -> addr ) ) ; } break ; } } } #endif return new_interface_found ; }
update_interface strategy
 toggle configuration phase
update_interface strategy toggle configuration phase
/*
	 * phase one - scan interfaces
	 * - create those that are not found
	 * - update those that are found
	 */ /*
	 * Toggle system interface scan phase to find untouched
	 * interfaces to be deleted.
	 */ /* See if we have a valid family to use */ /* create prototype */ /*
		 * Check if and how we are going to use the interface.
		 */ /* interfaces must be UP to be usable */ /*
		 * skip any interfaces UP and bound to a wildcard
		 * address - some dhcp clients produce that in the
		 * wild
		 */ /*
		 * skip any address that is an invalid state to be used
		 */ /*
		 * map to local *address* in order to map all duplicate
		 * interfaces to an endpt structure with the appropriate
		 * socket.  Our name space is (ip-address), NOT
		 * (interface name, ip-address).
		 */ /*
			 * found existing and up to date interface -
			 * mark present.
			 */ /*
				 * On a new round we reset the name so
				 * the interface name shows up again if
				 * this address is no longer shared.
				 * We reset ignore_packets from the
				 * new prototype to respect any runtime
				 * changes to the nic rules.
				 */ /* name collision - rename interface */ /*
				 * We have conflicting configurations
				 * for the interface address. This is
				 * caused by using -I <interfacename>
				 * for an interface that shares its
				 * address with other interfaces. We
				 * can not disambiguate incoming
				 * packets delivered to this socket
				 * without extra syscalls/features.
				 * These are not (commonly) available.
				 * Note this is a more unusual
				 * configuration where several
				 * interfaces share an address but
				 * filtering via interface name is
				 * attempted.  We resolve the
				 * configuration conflict by disabling
				 * the processing of received packets.
				 * This leads to no service on the
				 * interface address where the conflict
				 * occurs.
				 */ /*
			 * This is new or refreshing failed - add to
			 * our interface list.  If refreshing failed we
			 * will delete the interface structure in phase
			 * 2 as the interface was not marked current.
			 * We can bind to the address as the refresh
			 * code already closed the offending socket
			 */ /*
	 * phase 2 - delete gone interfaces - reassigning peers to
	 * other interfaces
	 */ /*
		 * if phase does not match sys_phase this interface was
		 * not enumerated during the last interface scan - so it
		 * is gone and will be deleted here unless it did not
		 * originate from interface enumeration (INT_WILDCARD,
		 * INT_MCASTIF).
		 */ /* disconnect peers from deleted endpt. */ /*
		 * update globals in case we lose
		 * a loopback interface
		 */ /*
	 * phase 3 - re-configure as the world has possibly changed
	 *
	 * never ever make this conditional again - it is needed to track
	 * routing updates. see bug #2506
	 */ /*
	 * Check multicast interfaces and try to join multicast groups if
         * not joined yet.
         */ /* Find remote address that was linked to this interface */ /* MCAST */