Exemplo n.º 1
0
int
OpenAndConfSSDPReceiveSocket(int n_listen_addr,
							 const char * * listen_addr,
                             int ipv6)
{
	int s;
	int opt = 1;
#ifdef ENABLE_IPV6
	struct sockaddr_storage sockname;
#else
	struct sockaddr_in sockname;
#endif
	socklen_t sockname_len;
	
#ifdef ENABLE_IPV6
	if( (s = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0)) < 0)
#else
	if( (s = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
#endif
	{
		syslog(LOG_ERR, "socket(udp): %m");
		return -1;
	}	
	
#ifdef ENABLE_IPV6
	memset(&sockname, 0, sizeof(struct sockaddr_storage));
	if(ipv6)
	{
#ifdef IPV6_V6ONLY
		if(setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
		              (char *)&opt, sizeof(opt)) < 0)
		{
			syslog(LOG_WARNING, "setsockopt(IPV6_V6ONLY): %m");
		}
#endif
		struct sockaddr_in6 * sa = (struct sockaddr_in6 *)&sockname;
    	sa->sin6_family = AF_INET6;
    	sa->sin6_port = htons(SSDP_PORT);
		sa->sin6_addr = in6addr_any;
		sockname_len = sizeof(struct sockaddr_in6);
	}
	else
	{
		struct sockaddr_in * sa = (struct sockaddr_in *)&sockname;
    	sa->sin_family = AF_INET;
    	sa->sin_port = htons(SSDP_PORT);
    	sa->sin_addr.s_addr = htonl(INADDR_ANY);
		sockname_len = sizeof(struct sockaddr_in);
	}
#else
	memset(&sockname, 0, sizeof(struct sockaddr_in));
    sockname.sin_family = AF_INET;
    sockname.sin_port = htons(SSDP_PORT);
	/* NOTE : it seems it doesnt work when binding on the specific address */
    /*sockname.sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);*/
    sockname.sin_addr.s_addr = htonl(INADDR_ANY);
    /*sockname.sin_addr.s_addr = inet_addr(ifaddr);*/
	sockname_len = sizeof(struct sockaddr_in);
#endif

	if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0)
	{
		syslog(LOG_WARNING, "setsockopt(SO_REUSEADDR): %m");
	}

    if(bind(s, (struct sockaddr *)&sockname, sockname_len) < 0)
	{
		syslog(LOG_ERR, "bind(udp%s): %m", ipv6 ? "6" : "");
		close(s);
		return -1;
    }

	while(n_listen_addr>0)
	{
		n_listen_addr--;
		if(AddDropMulticastMembership(s, listen_addr[n_listen_addr], ipv6, 0) < 0)
		{
			syslog(LOG_WARNING, "Failed to add IPv%d multicast membership for interface %s.",
			       ipv6 ? 6 : 4,
			       listen_addr[n_listen_addr] );
		}
	}

	return s;
}
Exemplo n.º 2
0
int
OpenAndConfSSDPReceiveSocket(int ipv6)
{
	int s;
	int opt = 1;
#ifdef ENABLE_IPV6
	struct sockaddr_storage sockname;
#else /* ENABLE_IPV6 */
	struct sockaddr_in sockname;
#endif /* ENABLE_IPV6 */
	socklen_t sockname_len;
	struct lan_addr_s * lan_addr;

#ifndef ENABLE_IPV6
	if(ipv6) {
		syslog(LOG_ERR, "%s: please compile with ENABLE_IPV6 to allow ipv6=1", __func__);
		return -1;
	}
#endif /* ENABLE_IPV6 */

#ifdef ENABLE_IPV6
	if( (s = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0)) < 0)
#else /* ENABLE_IPV6 */
	if( (s = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
#endif /* ENABLE_IPV6 */
	{
		syslog(LOG_ERR, "socket(udp): %m");
		return -1;
	}

	if(!set_non_blocking(s)) {
		syslog(LOG_WARNING, "Failed to set SSDP socket non blocking : %m");
	}

#ifdef ENABLE_IPV6
	memset(&sockname, 0, sizeof(struct sockaddr_storage));
	if(ipv6)
	{
#ifdef IPV6_V6ONLY
		if(setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
		              (char *)&opt, sizeof(opt)) < 0)
		{
			syslog(LOG_WARNING, "setsockopt(IPV6_V6ONLY): %m");
		}
#endif /* IPV6_V6ONLY */
		struct sockaddr_in6 * sa = (struct sockaddr_in6 *)&sockname;
		sa->sin6_family = AF_INET6;
		sa->sin6_port = htons(SSDP_PORT);
		sa->sin6_addr = in6addr_any;
		sockname_len = sizeof(struct sockaddr_in6);
	}
	else
	{
		struct sockaddr_in * sa = (struct sockaddr_in *)&sockname;
		sa->sin_family = AF_INET;
		sa->sin_port = htons(SSDP_PORT);
#ifdef SSDP_LISTEN_ON_SPECIFIC_ADDR
		if(n_listen_addr == 1)
		{
			sa->sin_addr.s_addr = GetIfAddrIPv4(listen_addr[0]);
			if(sa->sin_addr.s_addr == INADDR_NONE)
			{
				syslog(LOG_ERR, "no IPv4 address for interface %s",
				       listen_addr[0]);
				close(s);
				return -1;
			}
		}
		else
#endif /* SSDP_LISTEN_ON_SPECIFIC_ADDR */
			sa->sin_addr.s_addr = htonl(INADDR_ANY);
		sockname_len = sizeof(struct sockaddr_in);
	}
#else /* ENABLE_IPV6 */
	memset(&sockname, 0, sizeof(struct sockaddr_in));
    sockname.sin_family = AF_INET;
    sockname.sin_port = htons(SSDP_PORT);
#ifdef SSDP_LISTEN_ON_SPECIFIC_ADDR
	if(n_listen_addr == 1)
	{
		sockname.sin_addr.s_addr = GetIfAddrIPv4(listen_addr[0]);
		if(sockname.sin_addr.s_addr == INADDR_NONE)
		{
			syslog(LOG_ERR, "no IPv4 address for interface %s",
			       listen_addr[0]);
			close(s);
			return -1;
		}
	}
	else
#endif /* SSDP_LISTEN_ON_SPECIFIC_ADDR */
	    sockname.sin_addr.s_addr = htonl(INADDR_ANY);
	sockname_len = sizeof(struct sockaddr_in);
#endif /* ENABLE_IPV6 */

	if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0)
	{
		syslog(LOG_WARNING, "setsockopt(SO_REUSEADDR): %m");
	}

    if(bind(s, (struct sockaddr *)&sockname, sockname_len) < 0)
	{
		syslog(LOG_ERR, "bind(udp%s): %m", ipv6 ? "6" : "");
		close(s);
		return -1;
    }

	for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next)
	{
		if(AddDropMulticastMembership(s, lan_addr, ipv6, 0) < 0)
		{
			syslog(LOG_WARNING, "Failed to add IPv%d multicast membership for interface %s.",
			       ipv6 ? 6 : 4,
			       lan_addr->ifname);
		}
	}

	return s;
}
Exemplo n.º 3
0
/**
 * Process the message and add/drop multicast membership if needed
 */
int
ProcessInterfaceWatch(int s, int s_ssdp, int s_ssdp6)
{
	struct lan_addr_s * lan_addr;
	ssize_t len;
	char buffer[4096];
#ifdef __linux__
	struct iovec iov;
	struct msghdr hdr;
	struct nlmsghdr *nlhdr;
	struct ifaddrmsg *ifa;
	struct rtattr *rta;
	int ifa_len;

	iov.iov_base = buffer;
	iov.iov_len = sizeof(buffer);

	memset(&hdr, 0, sizeof(hdr));
	hdr.msg_iov = &iov;
	hdr.msg_iovlen = 1;

	len = recvmsg(s, &hdr, 0);
	if(len < 0) {
		syslog(LOG_ERR, "recvmsg(s, &hdr, 0): %m");
		return -1;
	}

	for(nlhdr = (struct nlmsghdr *)buffer;
		NLMSG_OK(nlhdr, len);
		nlhdr = NLMSG_NEXT(nlhdr, len)) {
		int is_del = 0;
		char address[48];
		char ifname[IFNAMSIZ];
		address[0] = '\0';
		ifname[0] = '\0';
		if(nlhdr->nlmsg_type == NLMSG_DONE)
			break;
		switch(nlhdr->nlmsg_type) {
		/* case RTM_NEWLINK: */
		/* case RTM_DELLINK: */
		case RTM_DELADDR:
			is_del = 1;
		case RTM_NEWADDR:
			/* http://linux-hacks.blogspot.fr/2009/01/sample-code-to-learn-netlink.html */
			ifa = (struct ifaddrmsg *)NLMSG_DATA(nlhdr);
			rta = (struct rtattr *)IFA_RTA(ifa);
			ifa_len = IFA_PAYLOAD(nlhdr);
			syslog(LOG_DEBUG, "%s %s index=%d fam=%d prefixlen=%d flags=%d scope=%d",
			       "ProcessInterfaceWatchNotify", is_del ? "RTM_DELADDR" : "RTM_NEWADDR",
			       ifa->ifa_index, ifa->ifa_family, ifa->ifa_prefixlen,
			       ifa->ifa_flags, ifa->ifa_scope);
			for(;RTA_OK(rta, ifa_len); rta = RTA_NEXT(rta, ifa_len)) {
				/*RTA_DATA(rta)*/
				/*rta_type : IFA_ADDRESS, IFA_LOCAL, etc. */
				char tmp[128];
				memset(tmp, 0, sizeof(tmp));
				switch(rta->rta_type) {
				case IFA_ADDRESS:
				case IFA_LOCAL:
				case IFA_BROADCAST:
				case IFA_ANYCAST:
					inet_ntop(ifa->ifa_family, RTA_DATA(rta), tmp, sizeof(tmp));
					if(rta->rta_type == IFA_ADDRESS)
						strncpy(address, tmp, sizeof(address));
					break;
				case IFA_LABEL:
					strncpy(tmp, RTA_DATA(rta), sizeof(tmp));
					strncpy(ifname, tmp, sizeof(ifname));
					break;
				case IFA_CACHEINFO:
					{
						struct ifa_cacheinfo *cache_info;
						cache_info = RTA_DATA(rta);
						snprintf(tmp, sizeof(tmp), "valid=%u prefered=%u",
						         cache_info->ifa_valid, cache_info->ifa_prefered);
					}
					break;
				default:
					strncpy(tmp, "*unknown*", sizeof(tmp));
				}
				syslog(LOG_DEBUG, " rta_len=%d rta_type=%d '%s'", rta->rta_len, rta->rta_type, tmp);
			}
			syslog(LOG_INFO, "%s: %s/%d %s",
			       is_del ? "RTM_DELADDR" : "RTM_NEWADDR",
			       address, ifa->ifa_prefixlen, ifname);
			for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next) {
				if((0 == strcmp(address, lan_addr->str)) ||
				   (0 == strcmp(ifname, lan_addr->ifname)) ||
				   (ifa->ifa_index == lan_addr->index)) {
					if(ifa->ifa_family == AF_INET)
						AddDropMulticastMembership(s_ssdp, lan_addr, 0, is_del);
					else if(ifa->ifa_family == AF_INET6)
						AddDropMulticastMembership(s_ssdp6, lan_addr, 1, is_del);
					break;
				}
			}
			break;
		default:
			syslog(LOG_DEBUG, "unknown nlmsg_type=%d", nlhdr->nlmsg_type);
		}
	}
#else /* __linux__ */
	struct rt_msghdr * rtm;
	struct ifa_msghdr * ifam;
	int is_del = 0;
	char tmp[64];
	char * p;
	struct sockaddr * sa;
	int addr;
	char address[48];
	char ifname[IFNAMSIZ];
	int family = AF_UNSPEC;
	int prefixlen = 0;

	address[0] = '\0';
	ifname[0] = '\0';

	len = recv(s, buffer, sizeof(buffer), 0);
	if(len < 0) {
		syslog(LOG_ERR, "%s recv: %m", "ProcessInterfaceWatchNotify");
		return -1;
	}
	rtm = (struct rt_msghdr *)buffer;
	switch(rtm->rtm_type) {
	case RTM_DELADDR:
		is_del = 1;
	case RTM_NEWADDR:
		ifam = (struct ifa_msghdr *)buffer;
		syslog(LOG_DEBUG, "%s %s len=%d/%hu index=%hu addrs=%x flags=%x",
		       "ProcessInterfaceWatchNotify", is_del?"RTM_DELADDR":"RTM_NEWADDR",
		       (int)len, ifam->ifam_msglen,
		       ifam->ifam_index, ifam->ifam_addrs, ifam->ifam_flags);
		p = buffer + sizeof(struct ifa_msghdr);
		addr = 1;
		while(p < buffer + len) {
			sa = (struct sockaddr *)p;
			while(!(addr & ifam->ifam_addrs) && (addr <= ifam->ifam_addrs))
				addr = addr << 1;
			sockaddr_to_string(sa, tmp, sizeof(tmp));
			syslog(LOG_DEBUG, " %s", tmp);
			switch(addr) {
			case RTA_DST:
			case RTA_GATEWAY:
				break;
			case RTA_NETMASK:
				if(sa->sa_family == AF_INET
#if defined(__OpenBSD__)
				   || (sa->sa_family == 0 &&
				       sa->sa_len <= sizeof(struct sockaddr_in))
#endif
				   ) {
					uint32_t sin_addr = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
					while((prefixlen < 32) &&
					      ((sin_addr & (1 << (31 - prefixlen))) != 0))
						prefixlen++;
				} else if(sa->sa_family == AF_INET6
#if defined(__OpenBSD__)
				          || (sa->sa_family == 0 &&
				              sa->sa_len == sizeof(struct sockaddr_in6))
#endif
				          ) {
					int i = 0;
					uint8_t * q =  ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr;
					while((*q == 0xff) && (i < 16)) {
						prefixlen += 8;
						q++; i++;
					}
					if(i < 16) {
						i = 0;
						while((i < 8) &&
						      ((*q & (1 << (7 - i))) != 0))
							i++;
						prefixlen += i;
					}
				}
				break;
			case RTA_GENMASK:
				break;
			case RTA_IFP:
#ifdef AF_LINK
				if(sa->sa_family == AF_LINK) {
					struct sockaddr_dl * sdl = (struct sockaddr_dl *)sa;
					memset(ifname, 0, sizeof(ifname));
					memcpy(ifname, sdl->sdl_data, sdl->sdl_nlen);
				}
#endif
				break;
			case RTA_IFA:
				family = sa->sa_family;
				if(sa->sa_family == AF_INET) {
					inet_ntop(sa->sa_family,
					          &((struct sockaddr_in *)sa)->sin_addr,
					          address, sizeof(address));
				} else if(sa->sa_family == AF_INET6) {
					inet_ntop(sa->sa_family,
					          &((struct sockaddr_in6 *)sa)->sin6_addr,
					          address, sizeof(address));
				}
				break;
			case RTA_AUTHOR:
				break;
			case RTA_BRD:
				break;
			}
#if 0
			syslog(LOG_DEBUG, " %d.%d.%d.%d %02x%02x%02x%02x",
			       (uint8_t)p[0], (uint8_t)p[1], (uint8_t)p[2], (uint8_t)p[3],
			       (uint8_t)p[0], (uint8_t)p[1], (uint8_t)p[2], (uint8_t)p[3]); 
			syslog(LOG_DEBUG, " %d.%d.%d.%d %02x%02x%02x%02x",
			       (uint8_t)p[4], (uint8_t)p[5], (uint8_t)p[6], (uint8_t)p[7],
			       (uint8_t)p[4], (uint8_t)p[5], (uint8_t)p[6], (uint8_t)p[7]); 
#endif
			p += SA_RLEN(sa);
			addr = addr << 1;
		}
		syslog(LOG_INFO, "%s: %s/%d %s",
		       is_del ? "RTM_DELADDR" : "RTM_NEWADDR",
		       address, prefixlen, ifname);
		for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next) {
			if((0 == strcmp(address, lan_addr->str)) ||
			   (0 == strcmp(ifname, lan_addr->ifname)) ||
			   (ifam->ifam_index == lan_addr->index)) {
				if(family == AF_INET)
					AddDropMulticastMembership(s_ssdp, lan_addr, 0, is_del);
				else if(family == AF_INET6)
					AddDropMulticastMembership(s_ssdp6, lan_addr, 1, is_del);
				break;
			}
		}
		break;
	default:
		syslog(LOG_DEBUG, "Unknown RTM message : rtm->rtm_type=%d len=%d",
		       rtm->rtm_type, (int)len);
	}
#endif
	return 0;
}
Exemplo n.º 4
0
/**
 * Process the message and add/drop multicast membership if needed
 */
int
ProcessInterfaceWatch(int s, int s_ssdp, int s_ssdp6,
                      int n_if_addr, const char * * if_addr)
{
	ssize_t len;
	int i;
	char buffer[4096];
#ifdef __linux__
	struct iovec iov;
	struct msghdr hdr;
	struct nlmsghdr *nlhdr;
	struct ifaddrmsg *ifa;

	iov.iov_base = buffer;
	iov.iov_len = sizeof(buffer);

	memset(&hdr, 0, sizeof(hdr));
	hdr.msg_iov = &iov;
	hdr.msg_iovlen = 1;

	len = recvmsg(s, &hdr, 0);
	if(len < 0) {
		syslog(LOG_ERR, "recvmsg(s, &hdr, 0): %m");
		return -1;
	}

	for(nlhdr = (struct nlmsghdr *)buffer;
		NLMSG_OK(nlhdr, len);
		nlhdr = NLMSG_NEXT(nlhdr, len)) {
		syslog(LOG_DEBUG, "nlmsg_type=%d", nlhdr->nlmsg_type);
		if(nlhdr->nlmsg_type == NLMSG_DONE)
			break;
		if(nlhdr->nlmsg_type == RTM_NEWADDR) {
			ifa = (struct ifaddrmsg *)NLMSG_DATA(nlhdr);
			syslog(LOG_DEBUG, "ProcessInterfaceWatchNotify RTM_NEWADDR index=%d", ifa->ifa_index);
			for(i = 0; i < n_if_addr; i++) {
				if(ifa->ifa_index == if_nametoindex(if_addr[i])) {
					AddDropMulticastMembership(s_ssdp, if_addr[i], 0, 0);
					break;
				}
			}
		} else if(nlhdr->nlmsg_type == RTM_DELADDR) {
			ifa = (struct ifaddrmsg *)NLMSG_DATA(nlhdr);
			syslog(LOG_DEBUG, "ProcessInterfaceWatchNotify RTM_DELADDR index=%d", ifa->ifa_index);
			for(i = 0; i < n_if_addr; i++) {
				if(ifa->ifa_index == if_nametoindex(if_addr[i])) {
					AddDropMulticastMembership(s_ssdp, if_addr[i], 0, 1);
					break;
				}
			}
		}
	}
#else /* __linux__ */
	struct rt_msghdr * rtm;
	struct ifa_msghdr * ifam;

	len = recv(s, buffer, sizeof(buffer), 0);
	if(len < 0) {
		syslog(LOG_ERR, "ProcessInterfaceWatchNotify recv: %m");
		return -1;
	}
	rtm = (struct rt_msghdr *)buffer;
	switch(rtm->rtm_type) {
	case RTM_NEWADDR:
		ifam = (struct ifa_msghdr *)buffer;
		syslog(LOG_DEBUG, "ProcessInterfaceWatchNotify RTM_NEWADDR index=%d", ifam->ifam_index);
		for(i = 0; i < n_if_addr; i++) {
			if(ifam->ifam_index == if_nametoindex(if_addr[i])) {
				AddDropMulticastMembership(s_ssdp, if_addr[i], 0, 0);
				break;
			}
		}
		break;
	case RTM_DELADDR:
		ifam = (struct ifa_msghdr *)buffer;
		syslog(LOG_DEBUG, "ProcessInterfaceWatchNotify RTM_DELADDR index=%d", ifam->ifam_index);
		for(i = 0; i < n_if_addr; i++) {
			if(ifam->ifam_index == if_nametoindex(if_addr[i])) {
				/* I dont think it is useful */
				/*AddDropMulticastMembership(s_ssdp, if_addr[i], 0, 1);*/
				break;
			}
		}
		break;
	default:
		syslog(LOG_DEBUG, "rtm->rtm_type=%d", rtm->rtm_type);
	}
#endif
	return 0;
}