Esempio n. 1
0
/* Process M-SEARCH requests */
static void
processMSEARCH(int s, const char * st, int st_len,
               const struct sockaddr * addr)
{
	struct service * serv;
#ifdef ENABLE_IPV6
	char buf[64];
#endif

	if(!st || st_len==0)
		return;
#ifdef ENABLE_IPV6
	sockaddr_to_string(addr, buf, sizeof(buf));
	syslog(LOG_INFO, "SSDP M-SEARCH from %s ST:%.*s",
	       buf, st_len, st);
#else
	syslog(LOG_INFO, "SSDP M-SEARCH from %s:%d ST: %.*s",
	       inet_ntoa(((const struct sockaddr_in *)addr)->sin_addr),
	       ntohs(((const struct sockaddr_in *)addr)->sin_port),
	       st_len, st);
#endif
	/* TODO : ignore packet if not coming from a LAN */
	if(st_len==8 && (0==memcmp(st, "ssdp:all", 8))) {
		/* send a response for all services */
		for(serv = servicelisthead.lh_first;
		    serv;
		    serv = serv->entries.le_next) {
			SendSSDPMSEARCHResponse(s, addr,
			                        serv->st, serv->usn,
			                        serv->server, serv->location);
		}
	} else if(st_len > 5 && (0==memcmp(st, "uuid:", 5))) {
		/* find a matching UUID value */
		for(serv = servicelisthead.lh_first;
		    serv;
		    serv = serv->entries.le_next) {
			if(0 == strncmp(serv->usn, st, st_len)) {
				SendSSDPMSEARCHResponse(s, addr,
				                        serv->st, serv->usn,
				                        serv->server, serv->location);
			}
		}
	} else {
		/* find matching services */
		/* remove version at the end of the ST string */
		if(st[st_len-2]==':' && isdigit(st[st_len-1]))
			st_len -= 2;
		/* answer for each matching service */
		for(serv = servicelisthead.lh_first;
		    serv;
		    serv = serv->entries.le_next) {
			if(0 == strncmp(serv->st, st, st_len)) {
				SendSSDPMSEARCHResponse(s, addr,
				                        serv->st, serv->usn,
				                        serv->server, serv->location);
			}
		}
	}
}
Esempio n. 2
0
/**
 * Wraper for sockaddr_to_string() which never fails.
 */
static char *
one_socket_to_string(const struct one_socket *s)
{
	char *p = sockaddr_to_string(&s->address, s->address_length, NULL);
	if (p == NULL)
		p = g_strdup("[unknown]");
	return p;
}
char *pingu_route_to_string(struct pingu_route *route,
                            char *buf, size_t bufsize)
{
    char deststr[64] = "", gwstr[64] = "", viastr[68] = "";
    char ifname[IF_NAMESIZE] = "", devstr[IF_NAMESIZE + 5] = "";

    sockaddr_to_string(&route->dest, deststr, sizeof(deststr));
    sockaddr_to_string(&route->gw_addr, gwstr, sizeof(gwstr));
    if (gwstr[0] != '\0')
        snprintf(viastr, sizeof(viastr), "via %s ", gwstr);
    if (if_indextoname(route->dev_index, ifname) != NULL)
        snprintf(devstr, sizeof(devstr), "dev %s ", ifname);

    snprintf(buf, bufsize, "%s/%i %s%smetric %i", deststr,
             route->dst_len, viastr, devstr, route->metric);
    return buf;
}
Esempio n. 4
0
static void
httpd_listen_in_event(int fd, const struct sockaddr *address,
		      size_t address_length, G_GNUC_UNUSED int uid, void *ctx)
{
	struct httpd_output *httpd = ctx;

	/* the listener socket has become readable - a client has
	   connected */

#ifdef HAVE_LIBWRAP
	if (address->sa_family != AF_UNIX) {
		char *hostaddr = sockaddr_to_string(address, address_length, NULL);
		const char *progname = g_get_prgname();

		struct request_info req;
		request_init(&req, RQ_FILE, fd, RQ_DAEMON, progname, 0);

		fromhost(&req);

		if (!hosts_access(&req)) {
			/* tcp wrappers says no */
			g_warning("libwrap refused connection (libwrap=%s) from %s",
			      progname, hostaddr);
			g_free(hostaddr);
			close_socket(fd);
			g_mutex_unlock(httpd->mutex);
			return;
		}

		g_free(hostaddr);
	}
#else
	(void)address;
	(void)address_length;
#endif	/* HAVE_WRAP */

	g_mutex_lock(httpd->mutex);

	if (fd >= 0) {
		/* can we allow additional client */
		if (httpd->open &&
		    (httpd->clients_max == 0 ||
		     httpd->clients_cnt < httpd->clients_max))
			httpd_client_add(httpd, fd);
		else
			close_socket(fd);
	} else if (fd < 0 && errno != EINTR) {
		g_warning("accept() failed: %s", g_strerror(errno));
	}

	g_mutex_unlock(httpd->mutex);
}
Esempio n. 5
0
/*
====================
__tcp_accept
====================
*/
I32	__tcp_accept(lua_State* ls)
{
	U32 listen_sock = INVALID_SOCKET;
  U32 fd = INVALID_SOCKET;
  I32	opt = 0;
  I32 ret = -1;
  struct sockaddr_in sock_addr;
  I32 addr_len = sizeof(sock_addr);
  const CHAR* ip;

  LUA_STACK;
  LUA_WATCH(ls);

  // check the socket
  if(lua_gettop(ls) != 1 || lua_type(ls, 1) != LUA_TNUMBER)
  {
    GLog(LT_ERROR, "__tcp_accept : invalid socket!");
    return 0;
  }
  listen_sock = (U32)lua_tointeger(ls, 1);
  CHECK(listen_sock != INVALID_SOCKET);

  // accept a new connection
  memset(&sock_addr, 0, sizeof(sock_addr));	
  fd = accept(listen_sock, (struct sockaddr*)&sock_addr, &addr_len);
  if(fd == INVALID_SOCKET)
  {
		if(WSAGetLastError() != WSAEWOULDBLOCK) 
		{
			GLog(LT_ERROR, "__tcp_accept: There was an error accept a socket : %s\n", get_socket_error_string());
			return 0;
		}
		return 0;
  }

  // make it non-blocking
  opt = 1;
  ret = ioctlsocket(fd, FIONBIO, (U32*)&opt);
  if(ret < 0)
  {
    GLog(LT_ERROR, "__tcp_accept: There was an error making a socket non-blocking : %s\n", get_socket_error_string());
    return 0;
  }
  
  // return the socket and the ipaddr
	lua_pushinteger(ls, fd);
	LUA_WATCH(ls);
  ip = sockaddr_to_string(&sock_addr);
  lua_pushstring(ls, ip);
  LUA_WATCH(ls);
  return 2;
}
Esempio n. 6
0
/* not really an SSDP "announce" as it is the response
 * to a SSDP "M-SEARCH" */
static void
SendSSDPAnnounce2(int s, const struct sockaddr * addr,
                  const char * st, int st_len, const char * suffix,
                  const char * host, unsigned short port)
{
	int l, n;
	char buf[512];
	char addr_str[64];
	socklen_t addrlen;
	/*
	 * follow guideline from document "UPnP Device Architecture 1.0"
	 * uppercase is recommended.
	 * DATE: is recommended
	 * SERVER: OS/ver UPnP/1.0 miniupnpd/1.0
	 * - check what to put in the 'Cache-Control' header
	 *
	 * have a look at the document "UPnP Device Architecture v1.1 */
	l = snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\r\n"
		"CACHE-CONTROL: max-age=120\r\n"
		/*"DATE: ...\r\n"*/
		"ST: %.*s%s\r\n"
		"USN: %s::%.*s%s\r\n"
		"EXT:\r\n"
		"SERVER: " MINIUPNPD_SERVER_STRING "\r\n"
		"LOCATION: http://%s:%u" ROOTDESC_PATH "\r\n"
		"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" /* UDA v1.1 */
		"01-NLS: %u\r\n" /* same as BOOTID. UDA v1.1 */
		"BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
		"CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
		"\r\n",
		st_len, st, suffix,
		uuidvalue, st_len, st, suffix,
		host, (unsigned int)port,
		upnp_bootid, upnp_bootid, upnp_configid);
	addrlen = (addr->sa_family == AF_INET6)
	          ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
	n = sendto(s, buf, l, 0,
	           addr, addrlen);
	sockaddr_to_string(addr, addr_str, sizeof(addr_str));
	syslog(LOG_INFO, "SSDP Announce %d bytes to %s ST: %.*s",n,
       		addr_str,
		l, buf);
	if(n < 0)
	{
		/* XXX handle EINTR, EAGAIN, EWOULDBLOCK */
		syslog(LOG_ERR, "sendto(udp): %m");
	}
}
Esempio n. 7
0
File: client.c Progetto: azuwis/mpd
void client_new(int fd, const struct sockaddr *sa, size_t sa_length, int uid)
{
    struct client *client;
    char *remote;

    if (num_clients >= client_max_connections) {
        g_warning("Max Connections Reached!");
        close(fd);
        return;
    }

    client = g_new0(struct client, 1);
    clients = g_list_prepend(clients, client);
    ++num_clients;

    client_init(client, fd);
    client->uid = uid;

    remote = sockaddr_to_string(sa, sa_length, NULL);
    g_log(G_LOG_DOMAIN, LOG_LEVEL_SECURE,
          "[%u] opened from %s", client->num, remote);
    g_free(remote);
}
Esempio n. 8
0
int
get_src_for_route_to(const struct sockaddr * dst,
                     void * src, size_t * src_len,
                     int * index)
{
	int found = 0;
	int s;
	int l, i;
	char * p;
	struct sockaddr * sa;
	struct {
	  struct rt_msghdr m_rtm;
	  char       m_space[512];
	} m_rtmsg;
#define rtm m_rtmsg.m_rtm

	if(dst == NULL)
		return -1;
#ifdef __APPLE__
	if(dst->sa_family == AF_INET6) {
		syslog(LOG_ERR, "Sorry, get_src_for_route_to() is known to fail with IPV6 on OS X...");
		return -1;
	}
#endif
	s = socket(PF_ROUTE, SOCK_RAW, dst->sa_family);
	if(s < 0) {
		syslog(LOG_ERR, "socket(PF_ROUTE) failed : %m");
		return -1;
	}
	memset(&rtm, 0, sizeof(rtm));
	rtm.rtm_type = RTM_GET;
	rtm.rtm_flags = RTF_UP;
	rtm.rtm_version = RTM_VERSION;
	rtm.rtm_seq = 1;
	rtm.rtm_addrs = RTA_DST;	/* destination address */
	memcpy(m_rtmsg.m_space, dst, sizeof(struct sockaddr));
	rtm.rtm_msglen = sizeof(struct rt_msghdr) + sizeof(struct sockaddr);
	if(write(s, &m_rtmsg, rtm.rtm_msglen) < 0) {
		syslog(LOG_ERR, "write: %m");
		close(s);
		return -1;
	}

	do {
		l = read(s, &m_rtmsg, sizeof(m_rtmsg));
		if(l<0) {
			syslog(LOG_ERR, "read: %m");
			close(s);
			return -1;
		}
		syslog(LOG_DEBUG, "read l=%d seq=%d pid=%d",
		       l, rtm.rtm_seq, rtm.rtm_pid);
	} while(l > 0 && (rtm.rtm_pid != getpid() || rtm.rtm_seq != 1));
	close(s);
	p = m_rtmsg.m_space;
	if(rtm.rtm_addrs) {
		for(i=1; i<0x8000; i <<= 1) {
			if(i & rtm.rtm_addrs) {
				char tmp[256] = { 0 };
				sa = (struct sockaddr *)p;
				sockaddr_to_string(sa, tmp, sizeof(tmp));
				syslog(LOG_DEBUG, "type=%d sa_len=%d sa_family=%d %s",
				       i, SA_LEN(sa), sa->sa_family, tmp);
				if((i == RTA_DST || i == RTA_GATEWAY) &&
				   (src_len && src)) {
					size_t len = 0;
					void * paddr = NULL;
					if(sa->sa_family == AF_INET) {
						paddr = &((struct sockaddr_in *)sa)->sin_addr;
						len = sizeof(struct in_addr);
					} else if(sa->sa_family == AF_INET6) {
						paddr = &((struct sockaddr_in6 *)sa)->sin6_addr;
						len = sizeof(struct in6_addr);
					}
					if(paddr) {
						if(*src_len < len) {
							syslog(LOG_WARNING, "cannot copy src. %u<%u",
							       (unsigned)*src_len, (unsigned)len);
							return -1;
						}
						memcpy(src, paddr, len);
						*src_len = len;
						found = 1;
					}
				}
#ifdef AF_LINK
				if(sa->sa_family == AF_LINK) {
					struct sockaddr_dl * sdl = (struct sockaddr_dl *)sa;
					if(index)
						*index = sdl->sdl_index;
				}
#endif
				p += SA_LEN(sa);
			}
		}
	}
	return found ? 0 : -1;
}
Esempio n. 9
0
struct lan_addr_s *
get_lan_for_peer(const struct sockaddr * peer)
{
	struct lan_addr_s * lan_addr = NULL;
#ifdef DEBUG
	char dbg_str[64];
#endif /* DEBUG */

#ifdef ENABLE_IPV6
	if(peer->sa_family == AF_INET6)
	{
		struct sockaddr_in6 * peer6 = (struct sockaddr_in6 *)peer;
		if(IN6_IS_ADDR_V4MAPPED(&peer6->sin6_addr))
		{
			struct in_addr peer_addr;
			memcpy(&peer_addr, &peer6->sin6_addr.s6_addr[12], 4);
			for(lan_addr = lan_addrs.lh_first;
			    lan_addr != NULL;
			    lan_addr = lan_addr->list.le_next)
			{
				if( (peer_addr.s_addr & lan_addr->mask.s_addr)
				   == (lan_addr->addr.s_addr & lan_addr->mask.s_addr))
					break;
			}
		}
		else
		{
			int index = -1;
			if(peer6->sin6_scope_id > 0)
				index = (int)peer6->sin6_scope_id;
			else
			{
				if(get_src_for_route_to(peer, NULL, NULL, &index) < 0)
					return NULL;
			}
			syslog(LOG_DEBUG, "%s looking for LAN interface index=%d",
			       "get_lan_for_peer()", index);
			for(lan_addr = lan_addrs.lh_first;
			    lan_addr != NULL;
			    lan_addr = lan_addr->list.le_next)
			{
				syslog(LOG_DEBUG,
				       "ifname=%s index=%u str=%s addr=%08x mask=%08x",
				       lan_addr->ifname, lan_addr->index,
				       lan_addr->str,
				       ntohl(lan_addr->addr.s_addr),
				       ntohl(lan_addr->mask.s_addr));
				if(index == (int)lan_addr->index)
					break;
			}
		}
	}
	else if(peer->sa_family == AF_INET)
	{
#endif /* ENABLE_IPV6 */
		for(lan_addr = lan_addrs.lh_first;
		    lan_addr != NULL;
		    lan_addr = lan_addr->list.le_next)
		{
			if( (((const struct sockaddr_in *)peer)->sin_addr.s_addr & lan_addr->mask.s_addr)
			   == (lan_addr->addr.s_addr & lan_addr->mask.s_addr))
				break;
		}
#ifdef ENABLE_IPV6
	}
#endif /* ENABLE_IPV6 */

#ifdef DEBUG
	sockaddr_to_string(peer, dbg_str, sizeof(dbg_str));
	if(lan_addr) {
		syslog(LOG_DEBUG, "%s: %s found in LAN %s %s",
		       "get_lan_for_peer()", dbg_str,
		       lan_addr->ifname, lan_addr->str);
	} else {
		syslog(LOG_DEBUG, "%s: %s not found !", "get_lan_for_peer()",
		       dbg_str);
	}
#endif /* DEBUG */
	return lan_addr;
}
Esempio n. 10
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;
}
Esempio n. 11
0
int qtrun(struct qtproto* p) {
	if (getconf("DEBUG")) debug = 1;
	struct qtsession session;
	session.poll_timeout = -1;
	session.protocol = *p;

	if (init_udp(&session) < 0) return -1;
	int sfd = session.fd_socket;

	session.sendnetworkpacket = qtsendnetworkpacket;

	if (init_tuntap(&session) < 0) return -1;
	int ttfd = session.fd_dev;

	char protocol_data[p->protocol_data_size];
	memset(protocol_data, 0, p->protocol_data_size);
	session.protocol_data = &protocol_data;
	if (p->init && p->init(&session) < 0) return -1;

	if (drop_privileges() < 0) return -1;

	fprintf(stderr, "The tunnel is now operational!\n");

	struct pollfd fds[2];
	fds[0].fd = ttfd;
	fds[0].events = POLLIN;
	fds[1].fd = sfd;
	fds[1].events = POLLIN;

	int pi_length = 0;
	if (session.use_pi == 2) pi_length = 4;

	char buffer_raw_a[p->buffersize_raw + pi_length];
	char buffer_enc_a[p->buffersize_enc];
	char* buffer_raw = buffer_raw_a;
	char* buffer_enc = buffer_enc_a;

	while (1) {
		int len = poll(fds, 2, session.poll_timeout);
		if (len < 0) return errorexitp("poll error");
		else if (fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) return errorexit("poll error on tap device");
		else if (fds[1].revents & (POLLHUP | POLLNVAL)) return errorexit("poll error on udp socket");
		if (len == 0 && p->idle) p->idle(&session);
		if (fds[0].revents & POLLIN) {
			len = read(ttfd, buffer_raw + p->offset_raw, p->buffersize_raw + pi_length);
			if (len < pi_length) errorexit("read packet smaller than header from tun device");
			if (session.remote_float == 0 || session.remote_float == 2) {
				len = p->encode(&session, buffer_raw + pi_length, buffer_enc, len - pi_length);
				if (len < 0) return len;
				if (len == 0) continue; //encoding is not yet possible
				qtsendnetworkpacket(&session, buffer_enc + p->offset_enc, len);
			}
		}
		if (fds[1].revents & POLLERR) {
			int out;
			len = sizeof(out);
			getsockopt(sfd, SOL_SOCKET, SO_ERROR, &out, &len);
			fprintf(stderr, "Received error %d on udp socket\n", out);
		}
		if (fds[1].revents & POLLIN) {
			sockaddr_any recvaddr;
			socklen_t recvaddr_len = sizeof(recvaddr);
			if (session.remote_float == 0) {
			 	len = read(sfd, buffer_enc + p->offset_enc, p->buffersize_enc);
			} else {
				len = recvfrom(sfd, buffer_enc + p->offset_enc, p->buffersize_enc, 0, (struct sockaddr*)&recvaddr, &recvaddr_len);
			}
			if (len < 0) {
				long long out;
				len = sizeof(out);
				getsockopt(sfd, SOL_SOCKET, SO_ERROR, &out, &len);
				fprintf(stderr, "Received end of file on udp socket (error %lld)\n", out);
			} else {
				len = p->decode(&session, buffer_enc, buffer_raw + pi_length, len);
				if (len < 0) continue;
				if (session.remote_float != 0 && !sockaddr_equal(&session.remote_addr, &recvaddr)) {
					char epname[INET6_ADDRSTRLEN + 1 + 2 + 1 + 5]; //addr%scope:port
					sockaddr_to_string(&recvaddr, epname, sizeof(epname));
					fprintf(stderr, "Remote endpoint has changed to %s\n", epname);
					session.remote_addr = recvaddr;
					session.remote_float = 2;
				}
				if (len > 0 && session.use_pi == 2) {
					int ipver = (buffer_raw[p->offset_raw + pi_length] >> 4) & 0xf;
					int pihdr = 0;
#if defined linux
					if (ipver == 4) pihdr = 0x0000 | (0x0008 << 16); //little endian: flags and protocol are swapped
					else if (ipver == 6) pihdr = 0x0000 | (0xdd86 << 16);
#else
					if (ipver == 4) pihdr = htonl(AF_INET);
					else if (ipver == 6) pihdr = htonl(AF_INET6);
#endif
					*(int*)(buffer_raw + p->offset_raw) = pihdr;
				}
				if (len > 0) write(ttfd, buffer_raw + p->offset_raw, len + pi_length);
			}
		}
Esempio n. 12
0
int
get_src_for_route_to(const struct sockaddr * dst,
                     void * src, size_t * src_len,
                     int * index)
{
	int found = 0;
	int s;
	int l, i;
	char * p;
	struct sockaddr * sa;
	struct {
	  struct rt_msghdr m_rtm;
	  char       m_space[512];
	} m_rtmsg;
#define rtm m_rtmsg.m_rtm

	if(dst == NULL)
		return -1;
	if(dst->sa_len > 0) {
		l = dst->sa_len;
	} else {
		if(dst->sa_family == AF_INET)
			l = sizeof(struct sockaddr_in);
		else if(dst->sa_family == AF_INET6)
			l = sizeof(struct sockaddr_in6);
		else {
			syslog(LOG_ERR, "unknown address family %d", dst->sa_family);
			return -1;
		}
	}
	s = socket(PF_ROUTE, SOCK_RAW, dst->sa_family);
	if(s < 0) {
		syslog(LOG_ERR, "socket(PF_ROUTE) failed : %m");
		return -1;
	}
	memset(&rtm, 0, sizeof(rtm));
	rtm.rtm_type = RTM_GET;
	rtm.rtm_flags = RTF_UP;
	rtm.rtm_version = RTM_VERSION;
	rtm.rtm_seq = 1;
	rtm.rtm_addrs = RTA_DST | RTA_IFA | RTA_IFP;	/* pass destination address, request source address & interface */
	memcpy(m_rtmsg.m_space, dst, l);
	((struct sockaddr *)m_rtmsg.m_space)->sa_len = l;
	rtm.rtm_msglen = sizeof(struct rt_msghdr) + l;
	if(write(s, &m_rtmsg, rtm.rtm_msglen) < 0) {
		syslog(LOG_ERR, "write: %m");
		close(s);
		return -1;
	}

	do {
		l = read(s, &m_rtmsg, sizeof(m_rtmsg));
		if(l<0) {
			syslog(LOG_ERR, "read: %m");
			close(s);
			return -1;
		}
		syslog(LOG_DEBUG, "read l=%d seq=%d pid=%d   sizeof(struct rt_msghdr)=%d",
		       l, rtm.rtm_seq, rtm.rtm_pid, (int)sizeof(struct rt_msghdr));
	} while(l > 0 && (rtm.rtm_pid != getpid() || rtm.rtm_seq != 1));
	close(s);
	if(l <= 0) {
		syslog(LOG_WARNING, "no matching ROUTE response message");
		return -1;
	}
	p = m_rtmsg.m_space;
	if(rtm.rtm_addrs) {
		for(i=1; i<0x8000; i <<= 1) {
			if(i & rtm.rtm_addrs) {
				char tmp[256] = { 0 };
				if(p >= (char *)&m_rtmsg + l) {
					syslog(LOG_ERR, "error parsing ROUTE response message");
					break;
				}
				sa = (struct sockaddr *)p;
				sockaddr_to_string(sa, tmp, sizeof(tmp));
				syslog(LOG_DEBUG, "type=%d sa_len=%d sa_family=%d %s",
				       i, sa->sa_len, sa->sa_family, tmp);
				if(i == RTA_IFA) {
					size_t len = 0;
					void * paddr = NULL;
					if(sa->sa_family == AF_INET) {
						paddr = &((struct sockaddr_in *)sa)->sin_addr;
						len = sizeof(struct in_addr);
					} else if(sa->sa_family == AF_INET6) {
						paddr = &((struct sockaddr_in6 *)sa)->sin6_addr;
						len = sizeof(struct in6_addr);
					}
					if(paddr) {
						if(src && src_len) {
							if(*src_len < len) {
								syslog(LOG_WARNING, "cannot copy src. %u<%u",
								       (unsigned)*src_len, (unsigned)len);
								return -1;
							}
							memcpy(src, paddr, len);
							*src_len = len;
						}
						found = 1;
					}
				}
#ifdef AF_LINK
				else if((i == RTA_IFP) && (sa->sa_family == AF_LINK)) {
					struct sockaddr_dl * sdl = (struct sockaddr_dl *)sa;
					if(index)
						*index = sdl->sdl_index;
				}
#endif
				/* at least 4 bytes per address are reserved,
				 * that is true with OpenBSD 4.3 */
				if(SA_SIZE(sa) > 0)
					p += SA_SIZE(sa);
				else
					p += 4;
			}
		}
	}
	return found ? 0 : -1;
}
Esempio n. 13
0
void
ProcessSSDPData(int s, const char *bufr, int n,
                const struct sockaddr * sender,
                unsigned short http_port)
#endif
{
	int i, l;
	struct lan_addr_s * lan_addr = NULL;
	const char * st = NULL;
	int st_len = 0;
	int st_ver = 0;
	char sender_str[64];
	char ver_str[4];
	const char * announced_host = NULL;
#ifdef UPNP_STRICT
#ifdef ENABLE_IPV6
	char announced_host_buf[64];
#endif
#endif
#if defined(UPNP_STRICT) || defined(DELAY_MSEARCH_RESPONSE)
	int mx_value = -1;
#endif
	unsigned int delay = 50; /* Non-zero default delay to prevent flooding */
	/* UPnP Device Architecture v1.1.  1.3.3 Search response :
	 * Devices responding to a multicast M-SEARCH SHOULD wait a random period
	 * of time between 0 seconds and the number of seconds specified in the
	 * MX field value of the search request before responding, in order to
	 * avoid flooding the requesting control point with search responses
	 * from multiple devices. If the search request results in the need for
	 * a multiple part response from the device, those multiple part
	 * responses SHOULD be spread at random intervals through the time period
	 * from 0 to the number of seconds specified in the MX header field. */

	/* get the string representation of the sender address */
	sockaddr_to_string(sender, sender_str, sizeof(sender_str));
	lan_addr = get_lan_for_peer(sender);
	if(lan_addr == NULL)
	{
		syslog(LOG_WARNING, "SSDP packet sender %s not from a LAN, ignoring",
		       sender_str);
		return;
	}

	if(memcmp(bufr, "NOTIFY", 6) == 0)
	{
		/* ignore NOTIFY packets. We could log the sender and device type */
		return;
	}
	else if(memcmp(bufr, "M-SEARCH", 8) == 0)
	{
		i = 0;
		while(i < n)
		{
			while((i < n - 1) && (bufr[i] != '\r' || bufr[i+1] != '\n'))
				i++;
			i += 2;
			if((i < n - 3) && (strncasecmp(bufr+i, "st:", 3) == 0))
			{
				st = bufr+i+3;
				st_len = 0;
				while((*st == ' ' || *st == '\t') && (st < bufr + n))
					st++;
				while(st[st_len]!='\r' && st[st_len]!='\n'
				     && (st + st_len < bufr + n))
					st_len++;
				l = st_len;
				while(l > 0 && st[l-1] != ':')
					l--;
				st_ver = atoi(st+l);
				syslog(LOG_DEBUG, "ST: %.*s (ver=%d)", st_len, st, st_ver);
				/*j = 0;*/
				/*while(bufr[i+j]!='\r') j++;*/
				/*syslog(LOG_INFO, "%.*s", j, bufr+i);*/
			}
#if defined(UPNP_STRICT) || defined(DELAY_MSEARCH_RESPONSE)
			else if((i < n - 3) && (strncasecmp(bufr+i, "mx:", 3) == 0))
			{
				const char * mx;
				int mx_len;
				mx = bufr+i+3;
				mx_len = 0;
				while((*mx == ' ' || *mx == '\t') && (mx < bufr + n))
					mx++;
				while(mx[mx_len]!='\r' && mx[mx_len]!='\n'
				     && (mx + mx_len < bufr + n))
					mx_len++;
				mx_value = atoi(mx);
				syslog(LOG_DEBUG, "MX: %.*s (value=%d)", mx_len, mx, mx_value);
			}
#endif
		}
#ifdef UPNP_STRICT
		/* For multicast M-SEARCH requests, if the search request does
		 * not contain an MX header field, the device MUST silently
		 * discard and ignore the search request. */
		if(mx_value < 0) {
			syslog(LOG_INFO, "ignoring SSDP packet missing MX: header");
			return;
		} else if(mx_value > 5) {
			/* If the MX header field specifies a field value greater
			 * than 5, the device SHOULD assume that it contained the
			 * value 5 or less. */
			mx_value = 5;
		}
#elif defined(DELAY_MSEARCH_RESPONSE)
		if(mx_value < 0) {
			mx_value = 1;
		} else if(mx_value > 5) {
			/* If the MX header field specifies a field value greater
			 * than 5, the device SHOULD assume that it contained the
			 * value 5 or less. */
			mx_value = 5;
		}
#endif
		/*syslog(LOG_INFO, "SSDP M-SEARCH packet received from %s",
	           sender_str );*/
		if(st && (st_len > 0))
		{
			syslog(LOG_INFO, "SSDP M-SEARCH from %s ST: %.*s",
			       sender_str, st_len, st);
			/* find in which sub network the client is */
			if(sender->sa_family == AF_INET)
			{
				if (lan_addr == NULL)
				{
					syslog(LOG_ERR, "Can't find in which sub network the client is");
					return;
				}
				announced_host = lan_addr->str;
			}
#ifdef ENABLE_IPV6
			else
			{
				/* IPv6 address with brackets */
#ifdef UPNP_STRICT
				int index;
				struct in6_addr addr6;
				size_t addr6_len = sizeof(addr6);
				/* retrieve the IPv6 address which
				 * will be used locally to reach sender */
				memset(&addr6, 0, sizeof(addr6));
				if(get_src_for_route_to (sender, &addr6, &addr6_len, &index) < 0) {
					syslog(LOG_WARNING, "get_src_for_route_to() failed, using %s", ipv6_addr_for_http_with_brackets);
					announced_host = ipv6_addr_for_http_with_brackets;
				} else {
					if(inet_ntop(AF_INET6, &addr6,
					             announced_host_buf+1,
					             sizeof(announced_host_buf) - 2)) {
						announced_host_buf[0] = '[';
						i = strlen(announced_host_buf);
						if(i < (int)sizeof(announced_host_buf) - 1) {
							announced_host_buf[i] = ']';
							announced_host_buf[i+1] = '\0';
						} else {
							syslog(LOG_NOTICE, "cannot suffix %s with ']'",
							       announced_host_buf);
						}
						announced_host = announced_host_buf;
					} else {
						syslog(LOG_NOTICE, "inet_ntop() failed %m");
						announced_host = ipv6_addr_for_http_with_brackets;
					}
				}
#else
				announced_host = ipv6_addr_for_http_with_brackets;
#endif
			}
#endif
			/* Responds to request with a device as ST header */
			for(i = 0; known_service_types[i].s; i++)
			{
				l = (int)strlen(known_service_types[i].s);
				if(l<=st_len && (0 == memcmp(st, known_service_types[i].s, l))
#ifdef UPNP_STRICT
				   && (st_ver <= known_service_types[i].version)
		/* only answer for service version lower or equal of supported one */
#endif
				   )
				{
					/* SSDP_RESPOND_SAME_VERSION :
					 * response is urn:schemas-upnp-org:service:WANIPConnection:1 when
					 * M-SEARCH included urn:schemas-upnp-org:service:WANIPConnection:1
					 * else the implemented versions is included in the response
					 *
					 * From UPnP Device Architecture v1.1 :
					 * 1.3.2 [...] Updated versions of device and service types
					 * are REQUIRED to be fully backward compatible with
					 * previous versions. Devices MUST respond to M-SEARCH
					 * requests for any supported version. For example, if a
					 * device implements “urn:schemas-upnporg:service:xyz:2”,
					 * it MUST respond to search requests for both that type
					 * and “urn:schemas-upnp-org:service:xyz:1”. The response
					 * MUST specify the same version as was contained in the
					 * search request. [...] */
#ifndef SSDP_RESPOND_SAME_VERSION
					if(i==0)
						ver_str[0] = '\0';
					else
						snprintf(ver_str, sizeof(ver_str), "%d", known_service_types[i].version);
#endif
					syslog(LOG_INFO, "Single search found");
#ifdef DELAY_MSEARCH_RESPONSE
					delay = random() / (1 + RAND_MAX / (1000 * mx_value));
#ifdef DEBUG
					syslog(LOG_DEBUG, "mx=%dsec delay=%ums", mx_value, delay);
#endif
#endif
					SendSSDPResponse(s, sender,
#ifdef SSDP_RESPOND_SAME_VERSION
					                 st, st_len, "",
#else
					                 known_service_types[i].s, l, ver_str,
#endif
					                 announced_host, http_port,
#ifdef ENABLE_HTTPS
					                 https_port,
#endif
					                 known_service_types[i].uuid,
					                 delay);
					break;
				}
			}
			/* Responds to request with ST: ssdp:all */
			/* strlen("ssdp:all") == 8 */
			if(st_len==8 && (0 == memcmp(st, "ssdp:all", 8)))
			{
#ifdef DELAY_MSEARCH_RESPONSE
				unsigned int delay_increment = (mx_value * 1000) / 15;
#endif
				syslog(LOG_INFO, "ssdp:all found");
				for(i=0; known_service_types[i].s; i++)
				{
#ifdef DELAY_MSEARCH_RESPONSE
					delay += delay_increment;
#endif
					if(i==0)
						ver_str[0] = '\0';
					else
						snprintf(ver_str, sizeof(ver_str), "%d", known_service_types[i].version);
					l = (int)strlen(known_service_types[i].s);
					SendSSDPResponse(s, sender,
					                 known_service_types[i].s, l, ver_str,
					                 announced_host, http_port,
#ifdef ENABLE_HTTPS
					                 https_port,
#endif
					                 known_service_types[i].uuid,
					                 delay);
				}
				/* also answer for uuid */
#ifdef DELAY_MSEARCH_RESPONSE
					delay += delay_increment;
#endif
				SendSSDPResponse(s, sender, uuidvalue_igd, strlen(uuidvalue_igd), "",
				                 announced_host, http_port,
#ifdef ENABLE_HTTPS
				                 https_port,
#endif
				                 uuidvalue_igd, delay);
#ifdef DELAY_MSEARCH_RESPONSE
					delay += delay_increment;
#endif
				SendSSDPResponse(s, sender, uuidvalue_wan, strlen(uuidvalue_wan), "",
				                 announced_host, http_port,
#ifdef ENABLE_HTTPS
				                 https_port,
#endif
				                 uuidvalue_wan, delay);
#ifdef DELAY_MSEARCH_RESPONSE
					delay += delay_increment;
#endif
				SendSSDPResponse(s, sender, uuidvalue_wcd, strlen(uuidvalue_wcd), "",
				                 announced_host, http_port,
#ifdef ENABLE_HTTPS
				                 https_port,
#endif
				                 uuidvalue_wcd, delay);
			}
			/* responds to request by UUID value */
			l = (int)strlen(uuidvalue_igd);
			if(l==st_len)
			{
#ifdef DELAY_MSEARCH_RESPONSE
				delay = random() / (1 + RAND_MAX / (1000 * mx_value));
#endif
				if(0 == memcmp(st, uuidvalue_igd, l))
				{
					syslog(LOG_INFO, "ssdp:uuid (IGD) found");
					SendSSDPResponse(s, sender, st, st_len, "",
					                 announced_host, http_port,
#ifdef ENABLE_HTTPS
					                 https_port,
#endif
					                 uuidvalue_igd, delay);
				}
				else if(0 == memcmp(st, uuidvalue_wan, l))
				{
					syslog(LOG_INFO, "ssdp:uuid (WAN) found");
					SendSSDPResponse(s, sender, st, st_len, "",
					                 announced_host, http_port,
#ifdef ENABLE_HTTPS
					                 https_port,
#endif
					                 uuidvalue_wan, delay);
				}
				else if(0 == memcmp(st, uuidvalue_wcd, l))
				{
					syslog(LOG_INFO, "ssdp:uuid (WCD) found");
					SendSSDPResponse(s, sender, st, st_len, "",
					                 announced_host, http_port,
#ifdef ENABLE_HTTPS
					                 https_port,
#endif
					                 uuidvalue_wcd, delay);
				}
			}
		}
		else
		{
			syslog(LOG_INFO, "Invalid SSDP M-SEARCH from %s", sender_str);
		}
	}
	else
	{
		syslog(LOG_NOTICE, "Unknown udp packet received from %s", sender_str);
	}
}
Esempio n. 14
0
void
ProcessInterfaceWatchNotify(int s)
{
	char buf[4096];
	ssize_t len;
	char tmp[64];
	struct rt_msghdr * rtm;
	struct if_msghdr * ifm;
	struct ifa_msghdr * ifam;
#ifdef RTM_IFANNOUNCE
	struct if_announcemsghdr * ifanm;
#endif
	char * p;
	struct sockaddr * sa;
	unsigned int ext_if_name_index = 0;

	len = recv(s, buf, sizeof(buf), 0);
	if(len < 0) {
		syslog(LOG_ERR, "ProcessInterfaceWatchNotify recv: %m");
		return;
	}
	if(ext_if_name) {
		ext_if_name_index = if_nametoindex(ext_if_name);
	}
	rtm = (struct rt_msghdr *)buf;
	syslog(LOG_DEBUG, "%u rt_msg : msglen=%d version=%d type=%d", (unsigned)len,
	       rtm->rtm_msglen, rtm->rtm_version, rtm->rtm_type);
	switch(rtm->rtm_type) {
	case RTM_IFINFO:	/* iface going up/down etc. */
		ifm = (struct if_msghdr *)buf;
		syslog(LOG_DEBUG, " RTM_IFINFO: addrs=%x flags=%x index=%hu",
		       ifm->ifm_addrs, ifm->ifm_flags, ifm->ifm_index);
		break;
	case RTM_ADD:	/* Add Route */
		syslog(LOG_DEBUG, " RTM_ADD");
		break;
	case RTM_DELETE:	/* Delete Route */
		syslog(LOG_DEBUG, " RTM_DELETE");
		break;
	case RTM_CHANGE:	/* Change Metrics or flags */
		syslog(LOG_DEBUG, " RTM_CHANGE");
		break;
	case RTM_GET:	/* Report Metrics */
		syslog(LOG_DEBUG, " RTM_GET");
		break;
#ifdef RTM_IFANNOUNCE
	case RTM_IFANNOUNCE:	/* iface arrival/departure */
		ifanm = (struct if_announcemsghdr *)buf;
		syslog(LOG_DEBUG, " RTM_IFANNOUNCE: index=%hu what=%hu ifname=%s",
		       ifanm->ifan_index, ifanm->ifan_what, ifanm->ifan_name);
		break;
#endif
#ifdef RTM_IEEE80211
	case RTM_IEEE80211:	/* IEEE80211 wireless event */
		syslog(LOG_DEBUG, " RTM_IEEE80211");
		break;
#endif
	case RTM_NEWADDR:	/* address being added to iface */
		ifam = (struct ifa_msghdr *)buf;
		syslog(LOG_DEBUG, " RTM_NEWADDR: addrs=%x flags=%x index=%hu",
		       ifam->ifam_addrs, ifam->ifam_flags, ifam->ifam_index);
		p = buf + sizeof(struct ifa_msghdr);
		while(p < buf + len) {
			sa = (struct sockaddr *)p;
			sockaddr_to_string(sa, tmp, sizeof(tmp));
			syslog(LOG_DEBUG, "  %s", tmp);
			p += SA_RLEN(sa);
		}
		if(ifam->ifam_index == ext_if_name_index) {
			should_send_public_address_change_notif = 1;
		}
		break;
	case RTM_DELADDR:	/* address being removed from iface */
		ifam = (struct ifa_msghdr *)buf;
		if(ifam->ifam_index == ext_if_name_index) {
			should_send_public_address_change_notif = 1;
		}
		break;
	default:
		syslog(LOG_DEBUG, "unprocessed RTM message type=%d", rtm->rtm_type);
	}
}
Esempio n. 15
0
int
get_src_for_route_to(const struct sockaddr * dst,
                     void * src, size_t * src_len,
                     int * index)
{
#if __linux__
	int fd = -1;
	struct nlmsghdr *h;
	int status;
	struct {
		struct nlmsghdr n;
		struct rtmsg r;
		char buf[1024];
	} req;
	struct sockaddr_nl nladdr;
	struct iovec iov = {
		.iov_base = (void*) &req.n,
	};
	struct msghdr msg = {
		.msg_name = &nladdr,
		.msg_namelen = sizeof(nladdr),
		.msg_iov = &iov,
		.msg_iovlen = 1,
	};
	const struct sockaddr_in * dst4;
	const struct sockaddr_in6 * dst6;

	memset(&req, 0, sizeof(req));
	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
	req.n.nlmsg_flags = NLM_F_REQUEST;
	req.n.nlmsg_type = RTM_GETROUTE;
	req.r.rtm_family = dst->sa_family;
	req.r.rtm_table = 0;
	req.r.rtm_protocol = 0;
	req.r.rtm_scope = 0;
	req.r.rtm_type = 0;
	req.r.rtm_src_len = 0;
	req.r.rtm_dst_len = 0;
	req.r.rtm_tos = 0;

	{
		char dst_str[128];
		sockaddr_to_string(dst, dst_str, sizeof(dst_str));
		syslog(LOG_DEBUG, "get_src_for_route_to (%s)", dst_str);
	}
	/* add address */
	if(dst->sa_family == AF_INET) {
		dst4 = (const struct sockaddr_in *)dst;
		nfnl_addattr_l(&req.n, sizeof(req), RTA_DST, &dst4->sin_addr, 4);
		req.r.rtm_dst_len = 32;
	} else {
		dst6 = (const struct sockaddr_in6 *)dst;
		nfnl_addattr_l(&req.n, sizeof(req), RTA_DST, &dst6->sin6_addr, 16);
		req.r.rtm_dst_len = 128;
	}

	fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
	if (fd < 0) {
		syslog(LOG_ERR, "socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE) : %m");
		return -1;
	}

	memset(&nladdr, 0, sizeof(nladdr));
	nladdr.nl_family = AF_NETLINK;

	req.n.nlmsg_seq = 1;
	iov.iov_len = req.n.nlmsg_len;

	status = sendmsg(fd, &msg, 0);

	if (status < 0) {
		syslog(LOG_ERR, "sendmsg(rtnetlink) : %m");
		goto error;
	}

	memset(&req, 0, sizeof(req));

	for(;;) {
		iov.iov_len = sizeof(req);
		status = recvmsg(fd, &msg, 0);
		if(status < 0) {
			if (errno == EINTR || errno == EAGAIN)
				continue;
			syslog(LOG_ERR, "recvmsg(rtnetlink) %m");
			goto error;
		}
		if(status == 0) {
			syslog(LOG_ERR, "recvmsg(rtnetlink) EOF");
			goto error;
		}
		for (h = (struct nlmsghdr*)&req.n; status >= (int)sizeof(*h); ) {
			int len = h->nlmsg_len;
			int l = len - sizeof(*h);

			if (l<0 || len>status) {
				if (msg.msg_flags & MSG_TRUNC) {
					syslog(LOG_ERR, "Truncated message");
				}
				syslog(LOG_ERR, "malformed message: len=%d", len);
				goto error;
			}

			if(nladdr.nl_pid != 0 || h->nlmsg_seq != 1/*seq*/) {
				syslog(LOG_ERR, "wrong seq = %d\n", h->nlmsg_seq);
				/* Don't forget to skip that message. */
				status -= NLMSG_ALIGN(len);
				h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
				continue;
			}

			if(h->nlmsg_type == NLMSG_ERROR) {
				struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
				syslog(LOG_ERR, "NLMSG_ERROR %d : %s", err->error, strerror(-err->error));
				goto error;
			}
			if(h->nlmsg_type == RTM_NEWROUTE) {
				struct rtattr * rta;
				int len = h->nlmsg_len;
				len -= NLMSG_LENGTH(sizeof(struct rtmsg));
				for(rta = RTM_RTA(NLMSG_DATA((h))); RTA_OK(rta, len); rta = RTA_NEXT(rta,len)) {
					unsigned char * data = RTA_DATA(rta);
					if(rta->rta_type == RTA_PREFSRC) {
						if(src_len && src) {
							if(*src_len < RTA_PAYLOAD(rta)) {
								syslog(LOG_WARNING, "cannot copy src: %u<%lu",
								       (unsigned)*src_len, (unsigned long)RTA_PAYLOAD(rta));
								goto error;
							}
							*src_len = RTA_PAYLOAD(rta);
							memcpy(src, data, RTA_PAYLOAD(rta));
						}
					} else if(rta->rta_type == RTA_OIF) {
						if(index)
							memcpy(index, data, sizeof(int));
					}
				}
				close(fd);
				return 0;
			}
			status -= NLMSG_ALIGN(len);
			h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
		}
	}
	syslog(LOG_WARNING, "get_src_for_route_to() : src not found");
error:
	if(fd >= 0)
		close(fd);
	return -1;
#else /* __linux__ */
	int found = 0;
	int s;
	int l, i;
	char * p;
	struct sockaddr * sa;
	struct {
	  struct rt_msghdr m_rtm;
	  char       m_space[512];
	} m_rtmsg;
#define rtm m_rtmsg.m_rtm

	if(dst == NULL)
		return -1;
#ifdef __APPLE__
	if(dst->sa_family == AF_INET6) {
		syslog(LOG_ERR, "Sorry, get_src_for_route_to() is known to fail with IPV6 on OS X...");
		return -1;
	}
#endif
	s = socket(PF_ROUTE, SOCK_RAW, dst->sa_family);
	if(s < 0) {
		syslog(LOG_ERR, "socket(PF_ROUTE) failed : %m");
		return -1;
	}
	memset(&rtm, 0, sizeof(rtm));
	rtm.rtm_type = RTM_GET;
	rtm.rtm_flags = RTF_UP;
	rtm.rtm_version = RTM_VERSION;
	rtm.rtm_seq = 1;
	rtm.rtm_addrs = RTA_DST;	/* destination address */
	memcpy(m_rtmsg.m_space, dst, sizeof(struct sockaddr));
	rtm.rtm_msglen = sizeof(struct rt_msghdr) + sizeof(struct sockaddr);
	if(write(s, &m_rtmsg, rtm.rtm_msglen) < 0) {
		syslog(LOG_ERR, "write: %m");
		close(s);
		return -1;
	}

	do {
		l = read(s, &m_rtmsg, sizeof(m_rtmsg));
		if(l<0) {
			syslog(LOG_ERR, "read: %m");
			close(s);
			return -1;
		}
		syslog(LOG_DEBUG, "read l=%d seq=%d pid=%d",
		       l, rtm.rtm_seq, rtm.rtm_pid);
	} while(l > 0 && (rtm.rtm_pid != getpid() || rtm.rtm_seq != 1));
	close(s);
	p = m_rtmsg.m_space;
	if(rtm.rtm_addrs) {
		for(i=1; i<0x8000; i <<= 1) {
			if(i & rtm.rtm_addrs) {
				char tmp[256] = { 0 };
				sa = (struct sockaddr *)p;
				sockaddr_to_string(sa, tmp, sizeof(tmp));
				syslog(LOG_DEBUG, "type=%d sa_len=%d sa_family=%d %s",
				       i, SA_LEN(sa), sa->sa_family, tmp);
				if((i == RTA_DST || i == RTA_GATEWAY) &&
				   (src_len && src)) {
					size_t len = 0;
					void * paddr = NULL;
					if(sa->sa_family == AF_INET) {
						paddr = &((struct sockaddr_in *)sa)->sin_addr;
						len = sizeof(struct in_addr);
					} else if(sa->sa_family == AF_INET6) {
						paddr = &((struct sockaddr_in6 *)sa)->sin6_addr;
						len = sizeof(struct in6_addr);
					}
					if(paddr) {
						if(*src_len < len) {
							syslog(LOG_WARNING, "cannot copy src. %u<%u",
							       (unsigned)*src_len, (unsigned)len);
							return -1;
						}
						memcpy(src, paddr, len);
						*src_len = len;
						found = 1;
					}
				}
#ifdef AF_LINK
				if(sa->sa_family == AF_LINK) {
					struct sockaddr_dl * sdl = (struct sockaddr_dl *)sa;
					if(index)
						*index = sdl->sdl_index;
				}
#endif
				p += SA_LEN(sa);
			}
		}
	}
	return found ? 0 : -1;
#endif /* __linux__ */
}
Esempio n. 16
0
int
main(int argc, char ** argv)
{
	struct sockaddr_in dst4;
	struct sockaddr_in6 dst6;
	struct sockaddr * dst;
	void * src;
	size_t src_len;
	int r;
	int index = -1;

	memset(&dst4, 0, sizeof(dst4));
	memset(&dst6, 0, sizeof(dst6));
	dst = NULL;
	if(argc < 2) {
		fprintf(stderr, "usage: %s <ip address>\n", argv[0]);
		fprintf(stderr, "both v4 and v6 IP addresses are supported.\n");
		return 1;
	}
	openlog("testgetroute", LOG_CONS|LOG_PERROR, LOG_USER);
	r = inet_pton (AF_INET, argv[1], &dst4.sin_addr);
	if(r < 0) {
		syslog(LOG_ERR, "inet_pton(AF_INET, %s) : %m", argv[1]);
		closelog();
		return 2;
	}
	if (r == 0) {
		r = inet_pton (AF_INET6, argv[1], &dst6.sin6_addr);
		if(r < 0) {
			syslog(LOG_ERR, "inet_pton(AF_INET6, %s) : %m", argv[1]);
			closelog();
			return 2;
		} else if(r > 0) {
			dst6.sin6_family = AF_INET6;
			dst = (struct sockaddr *)&dst6;
			src = &dst6.sin6_addr;
			src_len = sizeof(dst6.sin6_addr);
		} else {
			/* r == 0 */
			syslog(LOG_ERR, "%s is not a correct IPv4 or IPv6 address", argv[1]);
			closelog();
			return 1;
		}
	} else {
		dst4.sin_family = AF_INET;
		dst = (struct sockaddr *)&dst4;
		src = &dst4.sin_addr;
		src_len = sizeof(dst4.sin_addr);
	}

	if (dst) {
		syslog(LOG_DEBUG, "calling get_src_for_route_to(%p, NULL, NULL, %p)",
		       dst, &index);
		r = get_src_for_route_to (dst, NULL, NULL, &index);
		syslog(LOG_DEBUG, "get_src_for_route_to() returned %d", r);
		if(r >= 0) {
			syslog(LOG_DEBUG, "index=%d", index);
		}
		syslog(LOG_DEBUG, "calling get_src_for_route_to(%p, %p, %p(%u), %p)",
		       dst, src, &src_len, (unsigned)src_len, &index);
		r = get_src_for_route_to (dst, src, &src_len, &index);
		syslog(LOG_DEBUG, "get_src_for_route_to() returned %d", r);
		if(r >= 0) {
			char src_str[128];
			sockaddr_to_string(dst, src_str, sizeof(src_str));
			syslog(LOG_DEBUG, "src=%s", src_str);
			syslog(LOG_DEBUG, "index=%d", index);
		}
	}
	closelog();
	return 0;
}
Esempio n. 17
0
void
client_new(struct player_control *player_control,
	   int fd, const struct sockaddr *sa, size_t sa_length, int uid)
{
	static unsigned int next_client_num;
	struct client *client;
	char *remote;

	assert(player_control != NULL);
	assert(fd >= 0);

#ifdef HAVE_LIBWRAP
	if (sa->sa_family != AF_UNIX) {
		char *hostaddr = sockaddr_to_string(sa, sa_length, NULL);
		const char *progname = g_get_prgname();

		struct request_info req;
		request_init(&req, RQ_FILE, fd, RQ_DAEMON, progname, 0);

		fromhost(&req);

		if (!hosts_access(&req)) {
			/* tcp wrappers says no */
			g_log(G_LOG_DOMAIN, LOG_LEVEL_SECURE,
			      "libwrap refused connection (libwrap=%s) from %s",
			      progname, hostaddr);

			g_free(hostaddr);
			close_socket(fd);
			return;
		}

		g_free(hostaddr);
	}
#endif	/* HAVE_WRAP */

	if (client_list_is_full()) {
		g_warning("Max Connections Reached!");
		close_socket(fd);
		return;
	}

	client = g_new0(struct client, 1);
	client->player_control = player_control;

	client->channel = g_io_channel_new_socket(fd);
	/* GLib is responsible for closing the file descriptor */
	g_io_channel_set_close_on_unref(client->channel, true);
	/* NULL encoding means the stream is binary safe; the MPD
	   protocol is UTF-8 only, but we are doing this call anyway
	   to prevent GLib from messing around with the stream */
	g_io_channel_set_encoding(client->channel, NULL, NULL);
	/* we prefer to do buffering */
	g_io_channel_set_buffered(client->channel, false);

	client->source_id = g_io_add_watch(client->channel,
					   G_IO_IN|G_IO_ERR|G_IO_HUP,
					   client_in_event, client);

	client->input = fifo_buffer_new(4096);

	client->permission = getDefaultPermissions();
	client->uid = uid;

	client->last_activity = g_timer_new();

	client->cmd_list = NULL;
	client->cmd_list_OK = -1;
	client->cmd_list_size = 0;

	client->deferred_send = g_queue_new();
	client->deferred_bytes = 0;
	client->num = next_client_num++;

	client->send_buf_used = 0;

	client->subscriptions = NULL;
	client->messages = NULL;
	client->num_messages = 0;

	(void)send(fd, GREETING, sizeof(GREETING) - 1, 0);

	client_list_add(client);

	remote = sockaddr_to_string(sa, sa_length, NULL);
	g_log(G_LOG_DOMAIN, LOG_LEVEL_SECURE,
	      "[%u] opened from %s", client->num, remote);
	g_free(remote);
}
Esempio n. 18
0
/* Responds to a SSDP "M-SEARCH"
 * s :          socket to use
 * addr :       peer
 * st, st_len : ST: header
 * suffix :     suffix for USN: header
 * host, port : our HTTP host, port
 * delay :      in milli-seconds
 */
static void
SendSSDPResponse(int s, const struct sockaddr * addr,
                 const char * st, int st_len, const char * suffix,
                 const char * host, unsigned short http_port,
#ifdef ENABLE_HTTPS
                 unsigned short https_port,
#endif
                 const char * uuidvalue, unsigned int delay)
{
	int l, n;
	char buf[SSDP_PACKET_MAX_LEN];
	char addr_str[64];
	socklen_t addrlen;
	int st_is_uuid;
#ifdef ENABLE_HTTP_DATE
	char http_date[64];
	time_t t;
	struct tm tm;

	time(&t);
	gmtime_r(&t, &tm);
	strftime(http_date, sizeof(http_date),
		    "%a, %d %b %Y %H:%M:%S GMT", &tm);
#endif

	st_is_uuid = (st_len == (int)strlen(uuidvalue)) &&
	              (memcmp(uuidvalue, st, st_len) == 0);
	/*
	 * follow guideline from document "UPnP Device Architecture 1.0"
	 * uppercase is recommended.
	 * DATE: is recommended
	 * SERVER: OS/ver UPnP/1.0 miniupnpd/1.0
	 * - check what to put in the 'Cache-Control' header
	 *
	 * have a look at the document "UPnP Device Architecture v1.1 */
	l = snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\r\n"
		"CACHE-CONTROL: max-age=120\r\n"
#ifdef ENABLE_HTTP_DATE
		"DATE: %s\r\n"
#endif
		"ST: %.*s%s\r\n"
		"USN: %s%s%.*s%s\r\n"
		"EXT:\r\n"
		"SERVER: " MINIUPNPD_SERVER_STRING "\r\n"
		"LOCATION: http://%s:%u" ROOTDESC_PATH "\r\n"
#ifdef ENABLE_HTTPS
		"SECURELOCATION.UPNP.ORG: https://%s:%u" ROOTDESC_PATH "\r\n"
#endif
		"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" /* UDA v1.1 */
		"01-NLS: %u\r\n" /* same as BOOTID. UDA v1.1 */
		"BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
		"CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
		"\r\n",
#ifdef ENABLE_HTTP_DATE
		http_date,
#endif
		st_len, st, suffix,
		uuidvalue, st_is_uuid ? "" : "::",
		st_is_uuid ? 0 : st_len, st, suffix,
		host, (unsigned int)http_port,
#ifdef ENABLE_HTTPS
		host, (unsigned int)https_port,
#endif
		upnp_bootid, upnp_bootid, upnp_configid);
	if(l<0)
	{
		syslog(LOG_ERR, "%s: snprintf failed %m",
		       "SendSSDPResponse()");
		return;
	}
	else if((unsigned)l>=sizeof(buf))
	{
		syslog(LOG_WARNING, "%s: truncated output (%u>=%u)",
		       "SendSSDPResponse()", (unsigned)l, (unsigned)sizeof(buf));
		l = sizeof(buf) - 1;
	}
	addrlen = (addr->sa_family == AF_INET6)
	          ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
	n = sendto_schedule(s, buf, l, 0,
	                    addr, addrlen, delay);
	sockaddr_to_string(addr, addr_str, sizeof(addr_str));
	syslog(LOG_DEBUG, "%s: %d bytes to %s ST: %.*s",
	       "SendSSDPResponse()",
	       n, addr_str, l, buf);
	if(n < 0)
	{
		syslog(LOG_ERR, "%s: sendto(udp): %m",
		       "SendSSDPResponse()");
	}
}
Esempio n. 19
0
void
ProcessSSDPData(int s, const char *bufr, int n,
                const struct sockaddr * sender, unsigned short port) {
	int i, l;
	struct lan_addr_s * lan_addr = NULL;
	const char * st = NULL;
	int st_len = 0;
	char sender_str[64];
	const char * announced_host = NULL;
    /* BEGIN 2082304944 zhoujianchun 00203875 2012.8.29 added */
    char has_mx = 0;
    /* END   2082304944 zhoujianchun 00203875 2012.8.29 added */

	/* get the string representation of the sender address */
	sockaddr_to_string(sender, sender_str, sizeof(sender_str));

	if(memcmp(bufr, "NOTIFY", 6) == 0)
	{
		/* ignore NOTIFY packets. We could log the sender and device type */
		return;
	}
	else if(memcmp(bufr, "M-SEARCH", 8) == 0)
	{
		i = 0;
		while(i < n)
		{
			while((i < n - 1) && (bufr[i] != '\r' || bufr[i+1] != '\n'))
				i++;
			i += 2;
            /* BEGIN 2082304944 zhoujianchun 00203875 2012.8.29 added */
            if((i < n - 3) && (0 == strncasecmp(bufr+i, "mx:", 3)))
            {
                has_mx = 1;
            }
            /* END   2082304944 zhoujianchun 00203875 2012.8.29 added */
			if((i < n - 3) && (strncasecmp(bufr+i, "st:", 3) == 0))
			{
				st = bufr+i+3;
				st_len = 0;
				while((*st == ' ' || *st == '\t') && (st < bufr + n))
					st++;
				while(st[st_len]!='\r' && st[st_len]!='\n'
				     && (st + st_len < bufr + n))
					st_len++;
			}
		}
        /* BEGIN 2082304944 zhoujianchun 00203875 2012.8.29 added */
        if(0 == has_mx)
        {
            NP_UPNP_DEBUG("M-SEARCH, NO MX: RETURN.\n");
            return;
        }
        /* END   2082304944 zhoujianchun 00203875 2012.8.29 added */
		if(st && (st_len > 0))
		{
            /* BEGIN 2082304944 zhoujianchun 00203875 2012.8.29 added */
            if(strncmp("upnp:rootdevice", st, st_len) 
                    && strncmp("ssdp:all", st, st_len) 
                    && strncmp("urn:schemas-upnp-org:device:InternetGatewayDevice:1", st, st_len)
                    && strncmp("urn:schemas-upnp-org:device:WANConnectionDevice:1", st, st_len)
                    && strncmp("urn:schemas-upnp-org:device:WANDevice:1", st, st_len)
                    && strncmp("urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1", st, st_len)
                    && strncmp("urn:schemas-upnp-org:service:WANIPConnection:1", st, st_len)
                    && strncmp("urn:schemas-upnp-org:service:Layer3Forwarding:1", st, st_len)
                    && strncmp("urn:schemas-upnp-org:service:WANIPv6FirewallControl:1", st, st_len)
                    && strncmp(uuidvalue_root, st, st_len)
                    && strncmp(uuidvalue_wan, st, st_len)
                    && strncmp(uuidvalue_wan_conn, st, st_len)
              )
            {
                NP_UPNP_DEBUG("ST IS NOT CORRECT, RETURN.\n");
                return;
            }
            /* END   2082304944 zhoujianchun 00203875 2012.8.29 added */
			/* TODO : doesnt answer at once but wait for a random time */
			NP_UPNP_DEBUG("SSDP M-SEARCH from %s ST: %.*s\n",
			       sender_str, st_len, st);
			/* find in which sub network the client is */
			if(sender->sa_family == AF_INET)
			{
				for(lan_addr = lan_addrs.lh_first;
				    lan_addr != NULL;
				    lan_addr = lan_addr->list.le_next)
				{
					if( (((const struct sockaddr_in *)sender)->sin_addr.s_addr & lan_addr->mask.s_addr)
				   == (lan_addr->addr.s_addr & lan_addr->mask.s_addr))
						break;
				}
				if (lan_addr == NULL)
				{
					NP_UPNP_ERROR("Can't find in which sub network the client is\n");
					return;
				}
				announced_host = lan_addr->str;
			}
#ifdef ENABLE_IPV6
			else
			{
				/* IPv6 address with brackets */
				announced_host = ipv6_addr_for_http_with_brackets;
			}
#endif
			/* Responds to request with a device as ST header */
			for(i = 0; known_service_types[i]; i++)
			{
				l = (int)strlen(known_service_types[i]);
				if(l<=st_len && (0 == memcmp(st, known_service_types[i], l)))
				{
					NP_UPNP_DEBUG("Single search found\n");
					SendSSDPAnnounce2(s, sender,
					                  st, st_len, "",
                                      /* BEGIN 2082304944 zhoujianchun 00203875 2012.8.29 modified */
					                  announced_host, port, i);
                                      /* END   2082304944 zhoujianchun 00203875 2012.8.29 modified */
					break;
				}
			}
			/* Responds to request with ST: ssdp:all */
			/* strlen("ssdp:all") == 8 */
			if(st_len==8 && (0 == memcmp(st, "ssdp:all", 8)))
			{
				NP_UPNP_DEBUG("ssdp:all found\n");
				for(i=0; known_service_types[i]; i++)
				{
					l = (int)strlen(known_service_types[i]);
					SendSSDPAnnounce2(s, sender,
                                      /* BEGIN 2082304944 zhoujianchun 00203875 2012.8.29 modified */
					                  known_service_types[i], l, i==0 ? "" : "1",
					                  announced_host, port, i);
                                      /* END   2082304944 zhoujianchun 00203875 2012.8.29 modified */
				}
                /* BEGIN 2082304944 zhoujianchun 00203875 2012.8.29 added */
                for(i = 0; i < DEV_NUM; i++)
                {
				    SendSSDPAnnounce2(s, sender, uuid_value[i], st_len, "", announced_host, port, -1);
                }
                /* END   2082304944 zhoujianchun 00203875 2012.8.29 added */
			}
			/* responds to request by UUID value */
			l = (int)strlen(uuidvalue);
            /* BEGIN 2082304944 zhoujianchun 00203875 2012.8.29 modified */
			if(l==st_len && 0 == memcmp(st, uuidvalue_root, l)) 
			{
				NP_UPNP_DEBUG("ssdp:uuid found\n");
				SendSSDPAnnounce2(s, sender, uuidvalue_root, st_len, "",
				                  announced_host, port, -1);
			}
            /* END   2082304944 zhoujianchun 00203875 2012.8.29 modified */
            /* BEGIN 2082304944 zhoujianchun 00203875 2012.8.29 added */
            else if(l==st_len && 0 == memcmp(st, uuidvalue_wan, l))
            {
				NP_UPNP_DEBUG("ssdp:uuid found\n");
				SendSSDPAnnounce2(s, sender, uuidvalue_wan, st_len, "", announced_host, port, -1);
            }
            else if(l==st_len && 0 == memcmp(st, uuidvalue_wan_conn, l))
            {
				NP_UPNP_DEBUG("ssdp:uuid found\n");
				SendSSDPAnnounce2(s, sender, uuidvalue_wan_conn, st_len, "", announced_host, port, -1);
            }
            /* END   2082304944 zhoujianchun 00203875 2012.8.29 added */
		}
		else
		{
			NP_UPNP_DEBUG("Invalid SSDP M-SEARCH from %s\n", sender_str);
		}
	}
	else
	{
		NP_UPNP_DEBUG("Unknown udp packet received from %s\n", sender_str);
	}
}
Esempio n. 20
0
int
get_src_for_route_to(const struct sockaddr * dst,
                     void * src, size_t * src_len,
                     int * index)
{
	int fd = -1;
	struct nlmsghdr *h;
	int status;
	struct {
		struct nlmsghdr n;
		struct rtmsg r;
		char buf[1024];
	} req;
	struct sockaddr_nl nladdr;
	struct iovec iov = {
		.iov_base = (void*) &req.n,
	};
	struct msghdr msg = {
		.msg_name = &nladdr,
		.msg_namelen = sizeof(nladdr),
		.msg_iov = &iov,
		.msg_iovlen = 1,
	};
	const struct sockaddr_in * dst4;
	const struct sockaddr_in6 * dst6;

	memset(&req, 0, sizeof(req));
	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
	req.n.nlmsg_flags = NLM_F_REQUEST;
	req.n.nlmsg_type = RTM_GETROUTE;
	req.r.rtm_family = dst->sa_family;
	req.r.rtm_table = 0;
	req.r.rtm_protocol = 0;
	req.r.rtm_scope = 0;
	req.r.rtm_type = 0;
	req.r.rtm_src_len = 0;
	req.r.rtm_dst_len = 0;
	req.r.rtm_tos = 0;

	{
		char dst_str[128];
		sockaddr_to_string(dst, dst_str, sizeof(dst_str));
		syslog(LOG_DEBUG, "get_src_for_route_to (%s)", dst_str);
	}
	/* add address */
	if(dst->sa_family == AF_INET) {
		dst4 = (const struct sockaddr_in *)dst;
		nfnl_addattr_l(&req.n, sizeof(req), RTA_DST, &dst4->sin_addr, 4);
		req.r.rtm_dst_len = 32;
	} else {
		dst6 = (const struct sockaddr_in6 *)dst;
		nfnl_addattr_l(&req.n, sizeof(req), RTA_DST, &dst6->sin6_addr, 16);
		req.r.rtm_dst_len = 128;
	}

	fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
	if (fd < 0) {
		syslog(LOG_ERR, "socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE) : %m");
		return -1;
	}

	memset(&nladdr, 0, sizeof(nladdr));
	nladdr.nl_family = AF_NETLINK;

	req.n.nlmsg_seq = 1;
	iov.iov_len = req.n.nlmsg_len;

	status = sendmsg(fd, &msg, 0);

	if (status < 0) {
		syslog(LOG_ERR, "sendmsg(rtnetlink) : %m");
		goto error;
	}

	memset(&req, 0, sizeof(req));

	for(;;) {
		iov.iov_len = sizeof(req);
		status = recvmsg(fd, &msg, 0);
		if(status < 0) {
			if (errno == EINTR || errno == EAGAIN)
				continue;
			syslog(LOG_ERR, "recvmsg(rtnetlink) %m");
			goto error;
		}
		if(status == 0) {
			syslog(LOG_ERR, "recvmsg(rtnetlink) EOF");
			goto error;
		}
		for (h = (struct nlmsghdr*)&req.n; status >= (int)sizeof(*h); ) {
			int len = h->nlmsg_len;
			int l = len - sizeof(*h);

			if (l<0 || len>status) {
				if (msg.msg_flags & MSG_TRUNC) {
					syslog(LOG_ERR, "Truncated message");
				}
				syslog(LOG_ERR, "malformed message: len=%d", len);
				goto error;
			}

			if(nladdr.nl_pid != 0 || h->nlmsg_seq != 1/*seq*/) {
				syslog(LOG_ERR, "wrong seq = %d\n", h->nlmsg_seq);
				/* Don't forget to skip that message. */
				status -= NLMSG_ALIGN(len);
				h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
				continue;
			}

			if(h->nlmsg_type == NLMSG_ERROR) {
				struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
				syslog(LOG_ERR, "NLMSG_ERROR %d : %s", err->error, strerror(-err->error));
				goto error;
			}
			if(h->nlmsg_type == RTM_NEWROUTE) {
				struct rtattr * rta;
				int len = h->nlmsg_len;
				len -= NLMSG_LENGTH(sizeof(struct rtmsg));
				for(rta = RTM_RTA(NLMSG_DATA((h))); RTA_OK(rta, len); rta = RTA_NEXT(rta,len)) {
					unsigned char * data = RTA_DATA(rta);
					if(rta->rta_type == RTA_PREFSRC) {
						if(src_len && src) {
							if(*src_len < RTA_PAYLOAD(rta)) {
								syslog(LOG_WARNING, "cannot copy src: %u<%lu",
								       (unsigned)*src_len, RTA_PAYLOAD(rta));
								goto error;
							}
							*src_len = RTA_PAYLOAD(rta);
							memcpy(src, data, RTA_PAYLOAD(rta));
						}
					} else if(rta->rta_type == RTA_OIF) {
						if(index)
							memcpy(index, data, sizeof(int));
					}
				}
				close(fd);
				return 0;
			}
			status -= NLMSG_ALIGN(len);
			h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
		}
	}
	syslog(LOG_WARNING, "get_src_for_route_to() : src not found");
error:
	if(fd >= 0)
		close(fd);
	return -1;
}
Esempio n. 21
0
static mrb_value sysctl_net_list(mrb_state *mrb, mrb_value self)
{
  const char *ifname = NULL;
  struct ifaddrs *addrs, *curr;
  mrb_value r_ret;
  struct RClass *if_class = mrb_class_get(mrb, "NetworkAddress");
  
  mrb_get_args(mrb, "|z", &ifname);
  
  if( getifaddrs(&addrs) == -1 ){
    mrb_raisef(mrb, E_RUNTIME_ERROR, "getifaddrs: %S", mrb_str_new_cstr(mrb, strerror(errno)));
    goto ret;
  }
  
  if( ifname ){
    r_ret = mrb_ary_new(mrb);
  }
  else {
    r_ret = mrb_hash_new(mrb);
  }
  
  curr = addrs;
  
  while( curr != NULL ){
    char addr[INET6_ADDRSTRLEN];
    char netmask[INET6_ADDRSTRLEN];
    
    if( curr->ifa_netmask != NULL ){
      mrb_value r_key, r_addr, r_list;
      
      // only return wanted infos
      if( !ifname || !strcmp(ifname, curr->ifa_name) ){
        if( sockaddr_to_string(curr->ifa_addr, addr, sizeof(addr)) == -1)
          continue;
        
        if( sockaddr_to_string(curr->ifa_netmask, netmask, sizeof(netmask)) == -1)
          continue;
        
        r_key = mrb_str_new_cstr(mrb, curr->ifa_name);
        r_addr = mrb_funcall(mrb, mrb_obj_value(if_class), "new", 2,
            mrb_str_new_cstr(mrb, addr),
            mrb_str_new_cstr(mrb, netmask)
          );
        
        if( ifname ){
          mrb_ary_push(mrb, r_ret, r_addr);
        }
        else {
          // check if key exists
          r_list = mrb_hash_get(mrb, r_ret, r_key);
          if( mrb_nil_p(r_list) ){
            r_list = mrb_ary_new(mrb);
          }
          
          mrb_ary_push(mrb, r_list, r_addr);
          
          mrb_hash_set(mrb, r_ret, r_key, r_list);
        }
      }
    }
    
    curr = curr->ifa_next;
  }

ret:
  return r_ret;
}
Esempio n. 22
0
void
ProcessSSDPData(int s, const char *bufr, int n,
                const struct sockaddr * sender, unsigned short port) {
	int i, l;
	struct lan_addr_s * lan_addr = NULL;
	const char * st = NULL;
	int st_len = 0;
	char sender_str[64];
	const char * announced_host = NULL;
#ifdef UPNP_STRICT
	char announced_host_buf[64];
#endif

	/* get the string representation of the sender address */
	sockaddr_to_string(sender, sender_str, sizeof(sender_str));

	if(memcmp(bufr, "NOTIFY", 6) == 0)
	{
		/* ignore NOTIFY packets. We could log the sender and device type */
		return;
	}
	else if(memcmp(bufr, "M-SEARCH", 8) == 0)
	{
		i = 0;
		while(i < n)
		{
			while((i < n - 1) && (bufr[i] != '\r' || bufr[i+1] != '\n'))
				i++;
			i += 2;
			if((i < n - 3) && (strncasecmp(bufr+i, "st:", 3) == 0))
			{
				st = bufr+i+3;
				st_len = 0;
				while((*st == ' ' || *st == '\t') && (st < bufr + n))
					st++;
				while(st[st_len]!='\r' && st[st_len]!='\n'
				     && (st + st_len < bufr + n))
					st_len++;
				/*syslog(LOG_INFO, "ST: %.*s", st_len, st);*/
				/*j = 0;*/
				/*while(bufr[i+j]!='\r') j++;*/
				/*syslog(LOG_INFO, "%.*s", j, bufr+i);*/
			}
		}
		/*syslog(LOG_INFO, "SSDP M-SEARCH packet received from %s",
	           sender_str );*/
		if(st && (st_len > 0))
		{
			/* TODO : doesnt answer at once but wait for a random time */
			syslog(LOG_INFO, "SSDP M-SEARCH from %s ST: %.*s",
			       sender_str, st_len, st);
			/* find in which sub network the client is */
			if(sender->sa_family == AF_INET)
			{
				for(lan_addr = lan_addrs.lh_first;
				    lan_addr != NULL;
				    lan_addr = lan_addr->list.le_next)
				{
					if( (((const struct sockaddr_in *)sender)->sin_addr.s_addr & lan_addr->mask.s_addr)
					   == (lan_addr->addr.s_addr & lan_addr->mask.s_addr))
						break;
				}
				if (lan_addr == NULL)
				{
					syslog(LOG_ERR, "Can't find in which sub network the client is");
					return;
				}
				announced_host = lan_addr->str;
			}
#ifdef ENABLE_IPV6
			else
			{
				/* IPv6 address with brackets */
#ifdef UPNP_STRICT
				struct in6_addr addr6;
				size_t addr6_len = sizeof(addr6);
				/* retrieve the IPv6 address which
				 * will be used locally to reach sender */
				memset(&addr6, 0, sizeof(addr6));
				if(get_src_for_route_to (sender, &addr6, &addr6_len) < 0) {
					syslog(LOG_WARNING, "get_src_for_route_to() failed, using %s", ipv6_addr_for_http_with_brackets);
					announced_host = ipv6_addr_for_http_with_brackets;
				} else {
					if(inet_ntop(AF_INET6, &addr6,
					             announced_host_buf+1,
					             sizeof(announced_host_buf) - 2)) {
						announced_host_buf[0] = '[';
						i = strlen(announced_host_buf);
						if(i < (int)sizeof(announced_host_buf) - 1) {
							announced_host_buf[i] = ']';
							announced_host_buf[i+1] = '\0';
						} else {
							syslog(LOG_NOTICE, "cannot suffix %s with ']'",
							       announced_host_buf);
						}
						announced_host = announced_host_buf;
					} else {
						syslog(LOG_NOTICE, "inet_ntop() failed %m");
						announced_host = ipv6_addr_for_http_with_brackets;
					}
				}
#else
				announced_host = ipv6_addr_for_http_with_brackets;
#endif
			}
#endif
			/* Responds to request with a device as ST header */
			for(i = 0; known_service_types[i]; i++)
			{
				l = (int)strlen(known_service_types[i]);
				if(l<=st_len && (0 == memcmp(st, known_service_types[i], l)))
				{
					syslog(LOG_INFO, "Single search found");
					SendSSDPAnnounce2(s, sender,
					                  st, st_len, "",
					                  announced_host, port);
					break;
				}
			}
			/* Responds to request with ST: ssdp:all */
			/* strlen("ssdp:all") == 8 */
			if(st_len==8 && (0 == memcmp(st, "ssdp:all", 8)))
			{
				syslog(LOG_INFO, "ssdp:all found");
				for(i=0; known_service_types[i]; i++)
				{
					l = (int)strlen(known_service_types[i]);
					SendSSDPAnnounce2(s, sender,
					                  known_service_types[i], l, i==0?"":"1",
					                  announced_host, port);
				}
			}
			/* responds to request by UUID value */
			l = (int)strlen(uuidvalue);
			if(l==st_len && (0 == memcmp(st, uuidvalue, l)))
			{
				syslog(LOG_INFO, "ssdp:uuid found");
				SendSSDPAnnounce2(s, sender, st, st_len, "",
				                  announced_host, port);
			}
		}
		else
		{
			syslog(LOG_INFO, "Invalid SSDP M-SEARCH from %s", sender_str);
		}
	}
	else
	{
		syslog(LOG_NOTICE, "Unknown udp packet received from %s", sender_str);
	}
}
Esempio n. 23
0
/* process HTTP or SSDP requests */
int
main(int argc, char * * argv)
{
	int i;
	int shttpl = -1;	/* socket for HTTP */
	int sudp = -1;		/* IP v4 socket for receiving SSDP */
#ifdef ENABLE_IPV6
	int sudpv6 = -1;	/* IP v6 socket for receiving SSDP */
#endif
#ifdef ENABLE_NATPMP
	int * snatpmp = NULL;
#endif
#ifdef ENABLE_NFQUEUE
	int nfqh = -1;
#endif
#ifdef USE_IFACEWATCHER
	int sifacewatcher = -1;
#endif

	int * snotify = NULL;
	int addr_count;
	LIST_HEAD(httplisthead, upnphttp) upnphttphead;
	struct upnphttp * e = 0;
	struct upnphttp * next;
	fd_set readset;	/* for select() */
	fd_set writeset;
	struct timeval timeout, timeofday, lasttimeofday = {0, 0};
	int max_fd = -1;
#ifdef USE_MINIUPNPDCTL
	int sctl = -1;
	LIST_HEAD(ctlstructhead, ctlelem) ctllisthead;
	struct ctlelem * ectl;
	struct ctlelem * ectlnext;
#endif
	struct runtime_vars v;
	/* variables used for the unused-rule cleanup process */
	struct rule_state * rule_list = 0;
	struct timeval checktime = {0, 0};
	struct lan_addr_s * lan_addr;
#ifdef ENABLE_6FC_SERVICE
	unsigned int next_pinhole_ts;
#endif

	if(init(argc, argv, &v) != 0)
		return 1;
	/* count lan addrs */
	addr_count = 0;
	for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next)
		addr_count++;
	if(addr_count > 0) {
#ifndef ENABLE_IPV6
		snotify = calloc(addr_count, sizeof(int));
#else
		/* one for IPv4, one for IPv6 */
		snotify = calloc(addr_count * 2, sizeof(int));
#endif
	}
#ifdef ENABLE_NATPMP
	if(addr_count > 0) {
		snatpmp = malloc(addr_count * sizeof(int));
		for(i = 0; i < addr_count; i++)
			snatpmp[i] = -1;
	}
#endif

	LIST_INIT(&upnphttphead);
#ifdef USE_MINIUPNPDCTL
	LIST_INIT(&ctllisthead);
#endif

	if(
#ifdef ENABLE_NATPMP
        !GETFLAG(ENABLENATPMPMASK) &&
#endif
        !GETFLAG(ENABLEUPNPMASK) ) {
		syslog(LOG_ERR, "Why did you run me anyway?");
		return 0;
	}

	syslog(LOG_INFO, "Starting%s%swith external interface %s",
#ifdef ENABLE_NATPMP
	       GETFLAG(ENABLENATPMPMASK) ? " NAT-PMP " : " ",
#else
	       " ",
#endif
	       GETFLAG(ENABLEUPNPMASK) ? "UPnP-IGD " : "",
	       ext_if_name);

	if(GETFLAG(ENABLEUPNPMASK))
	{

		/* open socket for HTTP connections. Listen on the 1st LAN address */
		shttpl = OpenAndConfHTTPSocket((v.port > 0) ? v.port : 0);
		if(shttpl < 0)
		{
			syslog(LOG_ERR, "Failed to open socket for HTTP. EXITING");
			return 1;
		}
		if(v.port <= 0) {
			struct sockaddr_in sockinfo;
			socklen_t len = sizeof(struct sockaddr_in);
			if (getsockname(shttpl, (struct sockaddr *)&sockinfo, &len) < 0) {
				syslog(LOG_ERR, "getsockname(): %m");
				return 1;
			}
			v.port = ntohs(sockinfo.sin_port);
		}
		syslog(LOG_NOTICE, "HTTP listening on port %d", v.port);
#ifdef ENABLE_IPV6
		if(find_ipv6_addr(NULL, ipv6_addr_for_http_with_brackets, sizeof(ipv6_addr_for_http_with_brackets)) > 0) {
			syslog(LOG_NOTICE, "HTTP IPv6 address given to control points : %s",
			       ipv6_addr_for_http_with_brackets);
		} else {
			memcpy(ipv6_addr_for_http_with_brackets, "[::1]", 6);
			syslog(LOG_WARNING, "no HTTP IPv6 address");
		}
#endif

		/* open socket for SSDP connections */
		sudp = OpenAndConfSSDPReceiveSocket(0);
		if(sudp < 0)
		{
			syslog(LOG_NOTICE, "Failed to open socket for receiving SSDP. Trying to use MiniSSDPd");
			if(SubmitServicesToMiniSSDPD(lan_addrs.lh_first->str, v.port) < 0) {
				syslog(LOG_ERR, "Failed to connect to MiniSSDPd. EXITING");
				return 1;
			}
		}
#ifdef ENABLE_IPV6
		sudpv6 = OpenAndConfSSDPReceiveSocket(1);
		if(sudpv6 < 0)
		{
			syslog(LOG_WARNING, "Failed to open socket for receiving SSDP (IP v6).");
		}
#endif

		/* open socket for sending notifications */
		if(OpenAndConfSSDPNotifySockets(snotify) < 0)
		{
			syslog(LOG_ERR, "Failed to open sockets for sending SSDP notify "
		                "messages. EXITING");
			return 1;
		}

#ifdef USE_IFACEWATCHER
		/* open socket for kernel notifications about new network interfaces */
		if (sudp >= 0)
		{
			sifacewatcher = OpenAndConfInterfaceWatchSocket();
			if (sifacewatcher < 0)
			{
				syslog(LOG_ERR, "Failed to open socket for receiving network interface notifications");
			}
		}
#endif
	}

#ifdef ENABLE_NATPMP
	/* open socket for NAT PMP traffic */
	if(GETFLAG(ENABLENATPMPMASK))
	{
		if(OpenAndConfNATPMPSockets(snatpmp) < 0)
		{
			syslog(LOG_ERR, "Failed to open sockets for NAT PMP.");
		} else {
			syslog(LOG_NOTICE, "Listening for NAT-PMP traffic on port %u",
			       NATPMP_PORT);
		}
#if 0
		ScanNATPMPforExpiration();
#endif
	}
#endif

	/* for miniupnpdctl */
#ifdef USE_MINIUPNPDCTL
	sctl = OpenAndConfCtlUnixSocket("/var/run/miniupnpd.ctl");
#endif

#ifdef ENABLE_NFQUEUE
	if ( nfqueue != -1 && n_nfqix > 0) {
		nfqh = OpenAndConfNFqueue();
		if(nfqh < 0) {
			syslog(LOG_ERR, "Failed to open fd for NFQUEUE.");
			return 1;
		} else {
			syslog(LOG_NOTICE, "Opened NFQUEUE %d",nfqueue);
		}
	}
#endif

	/* main loop */
	while(!quitting)
	{
		/* Correct startup_time if it was set with a RTC close to 0 */
		if((startup_time<60*60*24) && (time(NULL)>60*60*24))
		{
			set_startup_time(GETFLAG(SYSUPTIMEMASK));
		}
		/* send public address change notifications if needed */
		if(should_send_public_address_change_notif)
		{
			syslog(LOG_DEBUG, "should send external iface address change notification(s)");
#ifdef ENABLE_NATPMP
			if(GETFLAG(ENABLENATPMPMASK))
				SendNATPMPPublicAddressChangeNotification(snatpmp, addr_count);
#endif
#ifdef ENABLE_EVENTS
			if(GETFLAG(ENABLEUPNPMASK))
			{
				upnp_event_var_change_notify(EWanIPC);
			}
#endif
			should_send_public_address_change_notif = 0;
		}
		/* Check if we need to send SSDP NOTIFY messages and do it if
		 * needed */
		if(gettimeofday(&timeofday, 0) < 0)
		{
			syslog(LOG_ERR, "gettimeofday(): %m");
			timeout.tv_sec = v.notify_interval;
			timeout.tv_usec = 0;
		}
		else
		{
			/* the comparaison is not very precise but who cares ? */
			if(timeofday.tv_sec >= (lasttimeofday.tv_sec + v.notify_interval))
			{
				if (GETFLAG(ENABLEUPNPMASK))
					SendSSDPNotifies2(snotify,
				                  (unsigned short)v.port,
				                  v.notify_interval << 1);
				memcpy(&lasttimeofday, &timeofday, sizeof(struct timeval));
				timeout.tv_sec = v.notify_interval;
				timeout.tv_usec = 0;
			}
			else
			{
				timeout.tv_sec = lasttimeofday.tv_sec + v.notify_interval
				                 - timeofday.tv_sec;
				if(timeofday.tv_usec > lasttimeofday.tv_usec)
				{
					timeout.tv_usec = 1000000 + lasttimeofday.tv_usec
					                  - timeofday.tv_usec;
					timeout.tv_sec--;
				}
				else
				{
					timeout.tv_usec = lasttimeofday.tv_usec - timeofday.tv_usec;
				}
			}
		}
		/* remove unused rules */
		if( v.clean_ruleset_interval
		  && (timeofday.tv_sec >= checktime.tv_sec + v.clean_ruleset_interval))
		{
			if(rule_list)
			{
				remove_unused_rules(rule_list);
				rule_list = NULL;
			}
			else
			{
				rule_list = get_upnp_rules_state_list(v.clean_ruleset_threshold);
			}
			memcpy(&checktime, &timeofday, sizeof(struct timeval));
		}
		/* Remove expired port mappings, based on UPnP IGD LeaseDuration
		 * or NAT-PMP lifetime) */
		if(nextruletoclean_timestamp
		  && ((unsigned int)timeofday.tv_sec >= nextruletoclean_timestamp))
		{
			syslog(LOG_DEBUG, "cleaning expired Port Mappings");
			get_upnp_rules_state_list(0);
		}
		if(nextruletoclean_timestamp
		  && ((unsigned int)timeout.tv_sec >= (nextruletoclean_timestamp - timeofday.tv_sec)))
		{
			timeout.tv_sec = nextruletoclean_timestamp - timeofday.tv_sec;
			timeout.tv_usec = 0;
			syslog(LOG_DEBUG, "setting timeout to %u sec",
			       (unsigned)timeout.tv_sec);
		}
#ifdef ENABLE_NATPMP
#if 0
		/* Remove expired NAT-PMP mappings */
		while(nextnatpmptoclean_timestamp
		     && (timeofday.tv_sec >= nextnatpmptoclean_timestamp + startup_time))
		{
			/*syslog(LOG_DEBUG, "cleaning expired NAT-PMP mappings");*/
			if(CleanExpiredNATPMP() < 0) {
				syslog(LOG_ERR, "CleanExpiredNATPMP() failed");
				break;
			}
		}
		if(nextnatpmptoclean_timestamp
		  && timeout.tv_sec >= (nextnatpmptoclean_timestamp + startup_time - timeofday.tv_sec))
		{
			/*syslog(LOG_DEBUG, "setting timeout to %d sec",
			       nextnatpmptoclean_timestamp + startup_time - timeofday.tv_sec);*/
			timeout.tv_sec = nextnatpmptoclean_timestamp + startup_time - timeofday.tv_sec;
			timeout.tv_usec = 0;
		}
#endif
#endif
#ifdef ENABLE_6FC_SERVICE
		/* Clean up expired IPv6 PinHoles */
		next_pinhole_ts = 0;
		upnp_clean_expired_pinholes(&next_pinhole_ts);
		if(next_pinhole_ts &&
		   timeout.tv_sec >= (int)(next_pinhole_ts - timeofday.tv_sec)) {
			timeout.tv_sec = next_pinhole_ts - timeofday.tv_sec;
			timeout.tv_usec = 0;
		}
#endif

		/* select open sockets (SSDP, HTTP listen, and all HTTP soap sockets) */
		FD_ZERO(&readset);
		FD_ZERO(&writeset);

		if (sudp >= 0)
		{
			FD_SET(sudp, &readset);
			max_fd = MAX( max_fd, sudp);
#ifdef USE_IFACEWATCHER
			if (sifacewatcher >= 0)
			{
				FD_SET(sifacewatcher, &readset);
				max_fd = MAX(max_fd, sifacewatcher);
			}
#endif
		}
		if (shttpl >= 0)
		{
			FD_SET(shttpl, &readset);
			max_fd = MAX( max_fd, shttpl);
		}
#ifdef ENABLE_IPV6
		if (sudpv6 >= 0)
		{
			FD_SET(sudpv6, &readset);
			max_fd = MAX( max_fd, sudpv6);
		}
#endif

#ifdef ENABLE_NFQUEUE
		if (nfqh >= 0)
		{
			FD_SET(nfqh, &readset);
			max_fd = MAX( max_fd, nfqh);
		}
#endif

		i = 0;	/* active HTTP connections count */
		for(e = upnphttphead.lh_first; e != NULL; e = e->entries.le_next)
		{
			if(e->socket >= 0)
			{
				if(e->state <= EWaitingForHttpContent)
					FD_SET(e->socket, &readset);
				else if(e->state == ESendingAndClosing)
					FD_SET(e->socket, &writeset);
				else
					continue;
				max_fd = MAX(max_fd, e->socket);
				i++;
			}
		}
		/* for debug */
#ifdef DEBUG
		if(i > 1)
		{
			syslog(LOG_DEBUG, "%d active incoming HTTP connections", i);
		}
#endif
#ifdef ENABLE_NATPMP
		for(i=0; i<addr_count; i++) {
			if(snatpmp[i] >= 0) {
				FD_SET(snatpmp[i], &readset);
				max_fd = MAX( max_fd, snatpmp[i]);
			}
		}
#endif
#ifdef USE_MINIUPNPDCTL
		if(sctl >= 0) {
			FD_SET(sctl, &readset);
			max_fd = MAX( max_fd, sctl);
		}

		for(ectl = ctllisthead.lh_first; ectl; ectl = ectl->entries.le_next)
		{
			if(ectl->socket >= 0) {
				FD_SET(ectl->socket, &readset);
				max_fd = MAX( max_fd, ectl->socket);
			}
		}
#endif

#ifdef ENABLE_EVENTS
		upnpevents_selectfds(&readset, &writeset, &max_fd);
#endif

		if(select(max_fd+1, &readset, &writeset, 0, &timeout) < 0)
		{
			if(quitting) goto shutdown;
			if(errno == EINTR) continue; /* interrupted by a signal, start again */
			syslog(LOG_ERR, "select(all): %m");
			syslog(LOG_ERR, "Failed to select open sockets. EXITING");
			return 1;	/* very serious cause of error */
		}
#ifdef USE_MINIUPNPDCTL
		for(ectl = ctllisthead.lh_first; ectl;)
		{
			ectlnext =  ectl->entries.le_next;
			if((ectl->socket >= 0) && FD_ISSET(ectl->socket, &readset))
			{
				char buf[256];
				int l;
				l = read(ectl->socket, buf, sizeof(buf));
				if(l > 0)
				{
					/*write(ectl->socket, buf, l);*/
					write_command_line(ectl->socket, argc, argv);
					write_option_list(ectl->socket);
					write_permlist(ectl->socket, upnppermlist, num_upnpperm);
					write_upnphttp_details(ectl->socket, upnphttphead.lh_first);
					write_ctlsockets_list(ectl->socket, ctllisthead.lh_first);
					write_ruleset_details(ectl->socket);
#ifdef ENABLE_EVENTS
					write_events_details(ectl->socket);
#endif
					/* close the socket */
					close(ectl->socket);
					ectl->socket = -1;
				}
				else
				{
					close(ectl->socket);
					ectl->socket = -1;
				}
			}
			if(ectl->socket < 0)
			{
				LIST_REMOVE(ectl, entries);
				free(ectl);
			}
			ectl = ectlnext;
		}
		if((sctl >= 0) && FD_ISSET(sctl, &readset))
		{
			int s;
			struct sockaddr_un clientname;
			struct ctlelem * tmp;
			socklen_t clientnamelen = sizeof(struct sockaddr_un);
			//syslog(LOG_DEBUG, "sctl!");
			s = accept(sctl, (struct sockaddr *)&clientname,
			           &clientnamelen);
			syslog(LOG_DEBUG, "sctl! : '%s'", clientname.sun_path);
			tmp = malloc(sizeof(struct ctlelem));
			tmp->socket = s;
			LIST_INSERT_HEAD(&ctllisthead, tmp, entries);
		}
#endif
#ifdef ENABLE_EVENTS
		upnpevents_processfds(&readset, &writeset);
#endif
#ifdef ENABLE_NATPMP
		/* process NAT-PMP packets */
		for(i=0; i<addr_count; i++)
		{
			if((snatpmp[i] >= 0) && FD_ISSET(snatpmp[i], &readset))
			{
				ProcessIncomingNATPMPPacket(snatpmp[i]);
			}
		}
#endif
		/* process SSDP packets */
		if(sudp >= 0 && FD_ISSET(sudp, &readset))
		{
			/*syslog(LOG_INFO, "Received UDP Packet");*/
			ProcessSSDPRequest(sudp, (unsigned short)v.port);
		}
#ifdef ENABLE_IPV6
		if(sudpv6 >= 0 && FD_ISSET(sudpv6, &readset))
		{
			syslog(LOG_INFO, "Received UDP Packet (IPv6)");
			ProcessSSDPRequest(sudpv6, (unsigned short)v.port);
		}
#endif
#ifdef USE_IFACEWATCHER
		/* process kernel notifications */
		if (sifacewatcher >= 0 && FD_ISSET(sifacewatcher, &readset))
			ProcessInterfaceWatchNotify(sifacewatcher);
#endif

		/* process active HTTP connections */
		/* LIST_FOREACH macro is not available under linux */
		for(e = upnphttphead.lh_first; e != NULL; e = e->entries.le_next)
		{
			if(e->socket >= 0)
			{
				if(FD_ISSET(e->socket, &readset) ||
				   FD_ISSET(e->socket, &writeset))
				{
					Process_upnphttp(e);
				}
			}
		}
		/* process incoming HTTP connections */
		if(shttpl >= 0 && FD_ISSET(shttpl, &readset))
		{
			int shttp;
			socklen_t clientnamelen;
#ifdef ENABLE_IPV6
			struct sockaddr_storage clientname;
			clientnamelen = sizeof(struct sockaddr_storage);
#else
			struct sockaddr_in clientname;
			clientnamelen = sizeof(struct sockaddr_in);
#endif
			shttp = accept(shttpl, (struct sockaddr *)&clientname, &clientnamelen);
			if(shttp<0)
			{
				/* ignore EAGAIN, EWOULDBLOCK, EINTR, we just try again later */
				if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
					syslog(LOG_ERR, "accept(http): %m");
			}
			else
			{
				struct upnphttp * tmp = 0;
				char addr_str[64];

				sockaddr_to_string((struct sockaddr *)&clientname, addr_str, sizeof(addr_str));
				syslog(LOG_INFO, "HTTP connection from %s", addr_str);
				/* Create a new upnphttp object and add it to
				 * the active upnphttp object list */
				tmp = New_upnphttp(shttp);
				if(tmp)
				{
#ifdef ENABLE_IPV6
					if(clientname.ss_family == AF_INET)
					{
						tmp->clientaddr = ((struct sockaddr_in *)&clientname)->sin_addr;
					}
					else if(clientname.ss_family == AF_INET6)
					{
						struct sockaddr_in6 * addr = (struct sockaddr_in6 *)&clientname;
						if(IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr))
						{
							memcpy(&tmp->clientaddr,
							       &addr->sin6_addr.s6_addr[12],
							       4);
						}
						else
						{
							tmp->ipv6 = 1;
							memcpy(&tmp->clientaddr_v6,
							       &addr->sin6_addr,
							       sizeof(struct in6_addr));
						}
					}
#else
					tmp->clientaddr = clientname.sin_addr;
#endif
					LIST_INSERT_HEAD(&upnphttphead, tmp, entries);
				}
				else
				{
					syslog(LOG_ERR, "New_upnphttp() failed");
					close(shttp);
				}
			}
		}
#ifdef ENABLE_NFQUEUE
		/* process NFQ packets */
		if(nfqh >= 0 && FD_ISSET(nfqh, &readset))
		{
			/* syslog(LOG_INFO, "Received NFQUEUE Packet");*/
			ProcessNFQUEUE(nfqh);
		}
#endif
		/* delete finished HTTP connections */
		for(e = upnphttphead.lh_first; e != NULL; )
		{
			next = e->entries.le_next;
			if(e->state >= EToDelete)
			{
				LIST_REMOVE(e, entries);
				Delete_upnphttp(e);
			}
			e = next;
		}

	}	/* end of main loop */

shutdown:
	/* close out open sockets */
	while(upnphttphead.lh_first != NULL)
	{
		e = upnphttphead.lh_first;
		LIST_REMOVE(e, entries);
		Delete_upnphttp(e);
	}

	if (sudp >= 0) close(sudp);
	if (shttpl >= 0) close(shttpl);
#ifdef ENABLE_IPV6
	if (sudpv6 >= 0) close(sudpv6);
#endif
#ifdef USE_IFACEWATCHER
	if(sifacewatcher >= 0) close(sifacewatcher);
#endif
#ifdef ENABLE_NATPMP
	for(i=0; i<addr_count; i++) {
		if(snatpmp[i]>=0)
		{
			close(snatpmp[i]);
			snatpmp[i] = -1;
		}
	}
#endif
#ifdef USE_MINIUPNPDCTL
	if(sctl>=0)
	{
		close(sctl);
		sctl = -1;
		if(unlink("/var/run/miniupnpd.ctl") < 0)
		{
			syslog(LOG_ERR, "unlink() %m");
		}
	}
#endif

	if (GETFLAG(ENABLEUPNPMASK))
	{
#ifndef ENABLE_IPV6
		if(SendSSDPGoodbye(snotify, addr_count) < 0)
#else
		if(SendSSDPGoodbye(snotify, addr_count * 2) < 0)
#endif
		{
			syslog(LOG_ERR, "Failed to broadcast good-bye notifications");
		}
#ifndef ENABLE_IPV6
		for(i = 0; i < addr_count; i++)
#else
		for(i = 0; i < addr_count * 2; i++)
#endif
			close(snotify[i]);
	}

	if(pidfilename && (unlink(pidfilename) < 0))
	{
		syslog(LOG_ERR, "Failed to remove pidfile %s: %m", pidfilename);
	}

	/* delete lists */
	while(lan_addrs.lh_first != NULL)
	{
		lan_addr = lan_addrs.lh_first;
		LIST_REMOVE(lan_addrs.lh_first, list);
		free(lan_addr);
	}

#ifdef ENABLE_NATPMP
	free(snatpmp);
#endif
	free(snotify);
	closelog();
#ifndef DISABLE_CONFIG_FILE
	freeoptions();
#endif

	return 0;
}