Ejemplo n.º 1
0
/*
 * restrict_source - maintains dynamic "restrict source ..." entries as
 *		     peers come and go.
 */
void
restrict_source(
	sockaddr_u *	addr,
	int		farewell,	/* 0 to add, 1 to remove */
	u_long		expire		/* 0 is infinite, valid until */
	)
{
	sockaddr_u	onesmask;
	restrict_u *	res;
	int		found_specific;

	if (!restrict_source_enabled || SOCK_UNSPEC(addr) ||
	    IS_MCAST(addr) || ISREFCLOCKADR(addr))
		return;

	REQUIRE(AF_INET == AF(addr) || AF_INET6 == AF(addr));

	SET_HOSTMASK(&onesmask, AF(addr));
	if (farewell) {
		hack_restrict(RESTRICT_REMOVE, addr, &onesmask,
			      0, 0, 0);
		DPRINTF(1, ("restrict_source: %s removed", stoa(addr)));
		return;
	}

	/*
	 * If there is a specific entry for this address, hands
	 * off, as it is condidered more specific than "restrict
	 * server ...".
	 * However, if the specific entry found is a fleeting one
	 * added by pool_xmit() before soliciting, replace it
	 * immediately regardless of the expire value to make way
	 * for the more persistent entry.
	 */
	if (IS_IPV4(addr)) {
		res = match_restrict4_addr(SRCADR(addr), SRCPORT(addr));
		INSIST(res != NULL);
		found_specific = (SRCADR(&onesmask) == res->u.v4.mask);
	} else {
		res = match_restrict6_addr(&SOCK_ADDR6(addr),
					   SRCPORT(addr));
		INSIST(res != NULL);
		found_specific = ADDR6_EQ(&res->u.v6.mask,
					  &SOCK_ADDR6(&onesmask));
	}
	if (!expire && found_specific && res->expire) {
		found_specific = 0;
		free_res(res, IS_IPV6(addr));
	}
	if (found_specific)
		return;

	hack_restrict(RESTRICT_FLAGS, addr, &onesmask,
		      restrict_source_mflags, restrict_source_flags,
		      expire);
	DPRINTF(1, ("restrict_source: %s host restriction added\n", 
		    stoa(addr)));
}
Ejemplo n.º 2
0
/*
 * sock_hash - hash a sockaddr_u structure
 */
u_short
sock_hash(
	sockaddr_u *addr
	)
{
	u_int hashVal;
	u_int j;
	size_t len;
	u_char *pch;
	hashVal = 0;
	len = 0;

	/*
	 * We can't just hash the whole thing because there are hidden
	 * fields in sockaddr_in6 that might be filled in by recvfrom(),
	 * so just use the family, port and address.
	 */
	pch = (u_char *)&AF(addr);
	hashVal = 37 * hashVal + *pch;
	if (sizeof(AF(addr)) > 1) {
		pch++;
		hashVal = 37 * hashVal + *pch;
	}
	switch(AF(addr)) {
	case AF_INET:
		pch = (u_char *)&SOCK_ADDR4(addr);
		len = sizeof(SOCK_ADDR4(addr));
		break;

	case AF_INET6:
		pch = (u_char *)&SOCK_ADDR6(addr);
		len = sizeof(SOCK_ADDR6(addr));
		break;
	}

	for (j = 0; j < len ; j++)
		hashVal = 37 * hashVal + pch[j];

	hashVal = hashVal & NTP_HASH_MASK;

	return (u_short)hashVal;
}
Ejemplo n.º 3
0
/* Receive data from broadcast. Couldn't finish that. Need to do some digging
 * here, especially for protocol independence and IPv6 multicast */
int 
recv_bcst_data (
	SOCKET rsock,
	char *rdata,
	int rdata_len,
	sockaddr_u *sas,
	sockaddr_u *ras
	)
{
	char *buf;
	int btrue = 1;
	int recv_bytes = 0;
	int rdy_socks;
	GETSOCKNAME_SOCKLEN_TYPE ss_len;
	struct timeval timeout_tv;
	fd_set bcst_fd;
#ifdef MCAST
	struct ip_mreq mdevadr;
	TYPEOF_IP_MULTICAST_LOOP mtrue = 1;
#endif
#ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
	struct ipv6_mreq mdevadr6;
#endif

	setsockopt(rsock, SOL_SOCKET, SO_REUSEADDR, &btrue, sizeof(btrue));
	if (IS_IPV4(sas)) {
		if (bind(rsock, &sas->sa, SOCKLEN(sas)) < 0) {
			if (ENABLED_OPT(NORMALVERBOSE))
				printf("sntp recv_bcst_data: Couldn't bind() address %s:%d.\n",
				       stoa(sas), SRCPORT(sas));
		}

#ifdef MCAST
		if (setsockopt(rsock, IPPROTO_IP, IP_MULTICAST_LOOP, &mtrue, sizeof(mtrue)) < 0) {
			/* some error message regarding setting up multicast loop */
			return BROADCAST_FAILED;
		}
		mdevadr.imr_multiaddr.s_addr = NSRCADR(sas); 
		mdevadr.imr_interface.s_addr = htonl(INADDR_ANY);
		if (mdevadr.imr_multiaddr.s_addr == ~(unsigned)0) {
			if (ENABLED_OPT(NORMALVERBOSE)) {
				printf("sntp recv_bcst_data: %s:%d is not a broad-/multicast address, aborting...\n",
				       stoa(sas), SRCPORT(sas));
			}
			return BROADCAST_FAILED;
		}
		if (setsockopt(rsock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mdevadr, sizeof(mdevadr)) < 0) {
			if (ENABLED_OPT(NORMALVERBOSE)) {
				buf = ss_to_str(sas);
				printf("sntp recv_bcst_data: Couldn't add IP membership for %s\n", buf);
				free(buf);
			}
		}
#endif	/* MCAST */
	}
#ifdef ISC_PLATFORM_HAVEIPV6
	else if (IS_IPV6(sas)) {
		if (bind(rsock, &sas->sa, SOCKLEN(sas)) < 0) {
			if (ENABLED_OPT(NORMALVERBOSE))
				printf("sntp recv_bcst_data: Couldn't bind() address.\n");
		}
#ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
		if (setsockopt(rsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &btrue, sizeof (btrue)) < 0) {
			/* some error message regarding setting up multicast loop */
			return BROADCAST_FAILED;
		}
		memset(&mdevadr6, 0, sizeof(mdevadr6));
		mdevadr6.ipv6mr_multiaddr = SOCK_ADDR6(sas);
		if (!IN6_IS_ADDR_MULTICAST(&mdevadr6.ipv6mr_multiaddr)) {
			if (ENABLED_OPT(NORMALVERBOSE)) {
				buf = ss_to_str(sas); 
				printf("sntp recv_bcst_data: %s is not a broad-/multicast address, aborting...\n", buf);
				free(buf);
			}
			return BROADCAST_FAILED;
		}
		if (setsockopt(rsock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
			       &mdevadr6, sizeof(mdevadr6)) < 0) {
			if (ENABLED_OPT(NORMALVERBOSE)) {
				buf = ss_to_str(sas); 
				printf("sntp recv_bcst_data: Couldn't join group for %s\n", buf);
				free(buf);
			}
		}
#endif	/* INCLUDE_IPV6_MULTICAST_SUPPORT */
	}
#endif	/* ISC_PLATFORM_HAVEIPV6 */
	FD_ZERO(&bcst_fd);
	FD_SET(rsock, &bcst_fd);
	if (ENABLED_OPT(TIMEOUT)) 
		timeout_tv.tv_sec = (int) atol(OPT_ARG(TIMEOUT));
	else 
		timeout_tv.tv_sec = 68; /* ntpd broadcasts every 64s */
	timeout_tv.tv_usec = 0;
	rdy_socks = select(rsock + 1, &bcst_fd, 0, 0, &timeout_tv);
	switch (rdy_socks) {
	case -1: 
		if (ENABLED_OPT(NORMALVERBOSE)) 
			perror("sntp recv_bcst_data: select()");
		return BROADCAST_FAILED;
		break;
	case 0:
		if (ENABLED_OPT(NORMALVERBOSE))
			printf("sntp recv_bcst_data: select() reached timeout (%u sec), aborting.\n", 
			       (unsigned)timeout_tv.tv_sec);
		return BROADCAST_FAILED;
		break;
	default:
		ss_len = sizeof(*ras);
		recv_bytes = recvfrom(rsock, rdata, rdata_len, 0, &ras->sa, &ss_len);
		break;
	}
	if (recv_bytes == -1) {
		if (ENABLED_OPT(NORMALVERBOSE))
			perror("sntp recv_bcst_data: recvfrom:");
		recv_bytes = BROADCAST_FAILED;
	}
#ifdef MCAST
	if (IS_IPV4(sas)) 
		setsockopt(rsock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &btrue, sizeof(btrue));
#endif
#ifdef INCLUDE_IPV6_MULTICAST_SUPPORT
	if (IS_IPV6(sas))
		setsockopt(rsock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &btrue, sizeof(btrue));
#endif
	return recv_bytes;
}
Ejemplo n.º 4
0
/*
 * hack_restrict - add/subtract/manipulate entries on the restrict list
 */
void
hack_restrict(
	int		op,
	sockaddr_u *	resaddr,
	sockaddr_u *	resmask,
	u_short		mflags,
	u_short		flags,
	u_long		expire
	)
{
	int		v6;
	restrict_u	match;
	restrict_u *	res;
	restrict_u **	plisthead;

	DPRINTF(1, ("restrict: op %d addr %s mask %s mflags %08x flags %08x\n",
		    op, stoa(resaddr), stoa(resmask), mflags, flags));

	if (NULL == resaddr) {
		REQUIRE(NULL == resmask);
		REQUIRE(RESTRICT_FLAGS == op);
		restrict_source_flags = flags;
		restrict_source_mflags = mflags;
		restrict_source_enabled = 1;
		return;
	}

	ZERO(match);

#if 0
	/* silence VC9 potentially uninit warnings */
	// HMS: let's use a compiler-specific "enable" for this.
	res = NULL;
	v6 = 0;
#endif

	if (IS_IPV4(resaddr)) {
		v6 = 0;
		/*
		 * Get address and mask in host byte order for easy
		 * comparison as u_int32
		 */
		match.u.v4.addr = SRCADR(resaddr);
		match.u.v4.mask = SRCADR(resmask);
		match.u.v4.addr &= match.u.v4.mask;

	} else if (IS_IPV6(resaddr)) {
		v6 = 1;
		/*
		 * Get address and mask in network byte order for easy
		 * comparison as byte sequences (e.g. memcmp())
		 */
		match.u.v6.mask = SOCK_ADDR6(resmask);
		MASK_IPV6_ADDR(&match.u.v6.addr, PSOCK_ADDR6(resaddr),
			       &match.u.v6.mask);

	} else	/* not IPv4 nor IPv6 */
		REQUIRE(0);

	match.flags = flags;
	match.mflags = mflags;
	match.expire = expire;
	res = match_restrict_entry(&match, v6);

	switch (op) {

	case RESTRICT_FLAGS:
		/*
		 * Here we add bits to the flags. If this is a
		 * new restriction add it.
		 */
		if (NULL == res) {
			if (v6) {
				res = alloc_res6();
				memcpy(res, &match,
				       V6_SIZEOF_RESTRICT_U);
				plisthead = &restrictlist6;
			} else {
				res = alloc_res4();
				memcpy(res, &match,
				       V4_SIZEOF_RESTRICT_U);
				plisthead = &restrictlist4;
			}
			LINK_SORT_SLIST(
				*plisthead, res,
				(v6)
				  ? res_sorts_before6(res, L_S_S_CUR())
				  : res_sorts_before4(res, L_S_S_CUR()),
				link, restrict_u);
			restrictcount++;
			if (RES_LIMITED & flags)
				inc_res_limited();
		} else {
			if ((RES_LIMITED & flags) &&
			    !(RES_LIMITED & res->flags))
				inc_res_limited();
			res->flags |= flags;
		}
		break;

	case RESTRICT_UNFLAG:
		/*
		 * Remove some bits from the flags. If we didn't
		 * find this one, just return.
		 */
		if (res != NULL) {
			if ((RES_LIMITED & res->flags)
			    && (RES_LIMITED & flags))
				dec_res_limited();
			res->flags &= ~flags;
		}
		break;

	case RESTRICT_REMOVE:
	case RESTRICT_REMOVEIF:
		/*
		 * Remove an entry from the table entirely if we
		 * found one. Don't remove the default entry and
		 * don't remove an interface entry.
		 */
		if (res != NULL
		    && (RESTRICT_REMOVEIF == op
			|| !(RESM_INTERFACE & res->mflags))
		    && res != &restrict_def4
		    && res != &restrict_def6)
			free_res(res, v6);
		break;

	default:	/* unknown op */
		INSIST(0);
		break;
	}

}
Ejemplo n.º 5
0
/*
 * findhostaddr - resolve a host name into an address (Or vice-versa)
 *
 * Given one of {ce_peeraddr,ce_name}, find the other one.
 * It returns 1 for "success" and 0 for an uncorrectable failure.
 * Note that "success" includes try again errors.  You can tell that you
 *  got a "try again" since {ce_peeraddr,ce_name} will still be zero.
 */
static int
findhostaddr(
	struct conf_entry *entry
	)
{
	static int eai_again_seen = 0;
	struct addrinfo *addr;
	struct addrinfo hints;
	int again;
	int error;

	checkparent();		/* make sure our guy is still running */

	if (entry->ce_name != NULL && !SOCK_UNSPEC(&entry->peer_store)) {
		/* HMS: Squawk? */
		msyslog(LOG_ERR, "findhostaddr: both ce_name and ce_peeraddr are defined...");
		return 1;
	}

	if (entry->ce_name == NULL && SOCK_UNSPEC(&entry->peer_store)) {
		msyslog(LOG_ERR, "findhostaddr: both ce_name and ce_peeraddr are undefined!");
		return 0;
	}

	if (entry->ce_name) {
		DPRINTF(2, ("findhostaddr: Resolving <%s>\n",
			entry->ce_name));

		memset(&hints, 0, sizeof(hints));
		hints.ai_family = entry->type;
		hints.ai_socktype = SOCK_DGRAM;
		hints.ai_protocol = IPPROTO_UDP;
		/*
		 * If IPv6 is not available look only for v4 addresses
		 */
		if (!ipv6_works)
			hints.ai_family = AF_INET;
		error = getaddrinfo(entry->ce_name, NULL, &hints, &addr);
		if (error == 0) {
			entry->peer_store = *((sockaddr_u *)(addr->ai_addr));
			if (IS_IPV4(&entry->peer_store)) {
				entry->ce_peeraddr =
				    NSRCADR(&entry->peer_store);
				entry->ce_config.v6_flag = 0;
			} else {
				entry->ce_peeraddr6 =
				    SOCK_ADDR6(&entry->peer_store);
				entry->ce_config.v6_flag = 1;
			}
			freeaddrinfo(addr);
		}
	} else {
		DPRINTF(2, ("findhostaddr: Resolving <%s>\n",
			stoa(&entry->peer_store)));

		entry->ce_name = emalloc(MAXHOSTNAMELEN);
		error = getnameinfo((const struct sockaddr *)&entry->peer_store,
				   SOCKLEN(&entry->peer_store),
				   (char *)&entry->ce_name, MAXHOSTNAMELEN,
				   NULL, 0, 0);
	}

	if (0 == error) {

		/* again is our return value, for success it is 1 */
		again = 1;

		DPRINTF(2, ("findhostaddr: %s resolved.\n", 
			(entry->ce_name) ? "name" : "address"));
	} else {
		/*
		 * If the resolver failed, see if the failure is
		 * temporary. If so, return success.
		 */
		again = 0;

		switch (error) {

		case EAI_FAIL:
			again = 1;
			break;

		case EAI_AGAIN:
			again = 1;
			eai_again_seen = 1;
			break;

		case EAI_NONAME:
#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
		case EAI_NODATA:
#endif
			msyslog(LOG_ERR, "host name not found%s%s: %s",
				(EAI_NONAME == error) ? "" : " EAI_NODATA",
				(eai_again_seen) ? " (permanent)" : "",
				entry->ce_name);
			again = !eai_again_seen;
			break;

#ifdef EAI_SYSTEM
		case EAI_SYSTEM:
			/* 
			 * EAI_SYSTEM means the real error is in errno.  We should be more
			 * discriminating about which errno values require retrying, but
			 * this matches existing behavior.
			 */
			again = 1;
			DPRINTF(1, ("intres: EAI_SYSTEM errno %d (%s) means try again, right?\n",
				errno, strerror(errno)));
			break;
#endif
		}

		/* do this here to avoid perturbing errno earlier */
		DPRINTF(2, ("intres: got error status of: %d\n", error));
	}

	return again;
}