コード例 #1
0
/*
 * Get protocol-independent source filter list in use on socket.
 * An slist of NULL may be used for guessing the required buffer size.
 */
int
getsourcefilter(int s, uint32_t interface, struct sockaddr *group,
	socklen_t grouplen, uint32_t *fmode, uint32_t *numsrc,
	struct sockaddr_storage *slist)
{
	struct __msfilterreq	 msfr;
	sockunion_t		*psu;
	int			 err, level, nsrcs, optlen, optname;

	if (interface == 0 || group == NULL || numsrc == NULL || fmode == NULL)
	{
		errno = EINVAL;
		return (-1);
	}

	nsrcs = *numsrc;
	*numsrc = 0;
	*fmode = 0;

	psu = (sockunion_t *)group;
	switch (psu->ss.ss_family)
	{
#ifdef INET
	case AF_INET:
		if ((grouplen != sizeof(struct sockaddr_in) ||
			!IN_MULTICAST(ntohl(psu->sin.sin_addr.s_addr))))
		{
			errno = EINVAL;
			return (-1);
		}
		level = IPPROTO_IP;
		optname = IP_MSFILTER;
		break;
#endif
#ifdef INET6
	case AF_INET6:
		if (grouplen != sizeof(struct sockaddr_in6) ||
			!IN6_IS_ADDR_MULTICAST(&psu->sin6.sin6_addr))
		{
			errno = EINVAL;
			return (-1);
		}

		level = IPPROTO_IPV6;
		optname = IPV6_MSFILTER;
		break;
#endif
	default:
		errno = EAFNOSUPPORT;
		return (-1);
		break;
	}

	optlen = sizeof(struct __msfilterreq);
	memset(&msfr, 0, optlen);
	msfr.msfr_ifindex = interface;
	msfr.msfr_fmode = 0;
	msfr.msfr_nsrcs = nsrcs;
	memcpy(&msfr.msfr_group, &psu->ss, psu->ss.ss_len);

	/*
	 * msfr_srcs is a pointer to a vector of sockaddr_storage. It
	 * may be NULL. The kernel will always return the total number
	 * of filter entries for the group in msfr.msfr_nsrcs.
	 */
	msfr.msfr_srcs = slist;
	err = _getsockopt(s, level, optname, &msfr, &optlen);

	if (err == 0)
	{
		*numsrc = msfr.msfr_nsrcs;
		*fmode = msfr.msfr_fmode;
	}

	return (err);
}
コード例 #2
0
ファイル: bindresvport.c プロジェクト: 2asoft/freebsd
/*
 * Bind a socket to a privileged IP port
 */
int
bindresvport_sa(int sd, struct sockaddr *sa)
{
	int old, error, af;
	struct sockaddr_storage myaddr;
	struct sockaddr_in *sin;
#ifdef INET6
	struct sockaddr_in6 *sin6;
#endif
	int proto, portrange, portlow;
	u_int16_t *portp;
	socklen_t salen;

	if (sa == NULL) {
		salen = sizeof(myaddr);
		sa = (struct sockaddr *)&myaddr;

		if (_getsockname(sd, sa, &salen) == -1)
			return -1;	/* errno is correctly set */

		af = sa->sa_family;
		memset(sa, 0, salen);
	} else
		af = sa->sa_family;

	switch (af) {
	case AF_INET:
		proto = IPPROTO_IP;
		portrange = IP_PORTRANGE;
		portlow = IP_PORTRANGE_LOW;
		sin = (struct sockaddr_in *)sa;
		salen = sizeof(struct sockaddr_in);
		portp = &sin->sin_port;
		break;
#ifdef INET6
	case AF_INET6:
		proto = IPPROTO_IPV6;
		portrange = IPV6_PORTRANGE;
		portlow = IPV6_PORTRANGE_LOW;
		sin6 = (struct sockaddr_in6 *)sa;
		salen = sizeof(struct sockaddr_in6);
		portp = &sin6->sin6_port;
		break;
#endif
	default:
		errno = EPFNOSUPPORT;
		return (-1);
	}
	sa->sa_family = af;
	sa->sa_len = salen;

	if (*portp == 0) {
		socklen_t oldlen = sizeof(old);

		error = _getsockopt(sd, proto, portrange, &old, &oldlen);
		if (error < 0)
			return (error);

		error = _setsockopt(sd, proto, portrange, &portlow,
		    sizeof(portlow));
		if (error < 0)
			return (error);
	}

	error = _bind(sd, sa, salen);

	if (*portp == 0) {
		int saved_errno = errno;

		if (error < 0) {
			if (_setsockopt(sd, proto, portrange, &old,
			    sizeof(old)) < 0)
				errno = saved_errno;
			return (error);
		}

		if (sa != (struct sockaddr *)&myaddr) {
			/* Hmm, what did the kernel assign? */
			if (_getsockname(sd, sa, &salen) < 0)
				errno = saved_errno;
			return (error);
		}
	}
	return (error);
}