minisspd: check that peer is from a LAN
Change the list of LAN addresses/interfaces (code taken from miniupnpd) Check that the peer is from a LAN for each SSDP packet
This commit is contained in:
parent
186c504070
commit
63179a1f7f
|
@ -1,8 +1,10 @@
|
||||||
$Id: Changelog.txt,v 1.36 2014/11/06 10:13:36 nanard Exp $
|
$Id: Changelog.txt,v 1.37 2014/11/28 16:20:57 nanard Exp $
|
||||||
|
|
||||||
2014/11/28:
|
2014/11/28:
|
||||||
revert "listen on only 1 IPv4 if only 1 interface is specified"
|
revert "listen on only 1 IPv4 if only 1 interface is specified"
|
||||||
because it prevents broadcast messages to be received
|
because it prevents broadcast messages to be received
|
||||||
|
Change the list of LAN addresses/interfaces (code taken from miniupnpd)
|
||||||
|
Check that the peer is from a LAN for each SSDP packet
|
||||||
|
|
||||||
2014/11/06:
|
2014/11/06:
|
||||||
listen on only 1 IPv4 if only 1 interface is specified
|
listen on only 1 IPv4 if only 1 interface is specified
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# $Id: Makefile,v 1.19 2014/06/10 10:00:18 nanard Exp $
|
# $Id: Makefile,v 1.21 2014/11/28 16:20:57 nanard Exp $
|
||||||
# MiniUPnP project
|
# MiniUPnP project
|
||||||
# author: Thomas Bernard
|
# author: Thomas Bernard
|
||||||
# website: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
# website: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
# make install (miniupnpd will be put in /usr/sbin)
|
# make install (miniupnpd will be put in /usr/sbin)
|
||||||
#
|
#
|
||||||
# install target is made for linux... sorry BSD users...
|
# install target is made for linux... sorry BSD users...
|
||||||
#CFLAGS = -g
|
#CFLAGS = -g -O0
|
||||||
CFLAGS ?= -Os
|
CFLAGS ?= -Os
|
||||||
CFLAGS += -Wall
|
CFLAGS += -Wall
|
||||||
CFLAGS += -W -Wstrict-prototypes
|
CFLAGS += -W -Wstrict-prototypes
|
||||||
|
@ -23,9 +23,17 @@ RM = rm -f
|
||||||
INSTALL = install
|
INSTALL = install
|
||||||
OS = $(shell uname -s)
|
OS = $(shell uname -s)
|
||||||
|
|
||||||
|
ifeq ($(OS), Linux)
|
||||||
|
LDLIBS += -lnfnetlink
|
||||||
|
endif
|
||||||
|
ifeq ($(DEB_BUILD_ARCH_OS), kfreebsd)
|
||||||
|
LDLIBS += -lfreebsd-glue
|
||||||
|
endif
|
||||||
|
|
||||||
#EXECUTABLES = minissdpd testminissdpd listifaces
|
#EXECUTABLES = minissdpd testminissdpd listifaces
|
||||||
EXECUTABLES = minissdpd testminissdpd testcodelength
|
EXECUTABLES = minissdpd testminissdpd testcodelength
|
||||||
MINISSDPDOBJS = minissdpd.o openssdpsocket.o daemonize.o upnputils.o ifacewatch.o
|
MINISSDPDOBJS = minissdpd.o openssdpsocket.o daemonize.o upnputils.o \
|
||||||
|
ifacewatch.o getroute.o getifaddr.o
|
||||||
TESTMINISSDPDOBJS = testminissdpd.o
|
TESTMINISSDPDOBJS = testminissdpd.o
|
||||||
|
|
||||||
ALLOBJS = $(MINISSDPDOBJS) $(TESTMINISSDPDOBJS) testcodelength.o
|
ALLOBJS = $(MINISSDPDOBJS) $(TESTMINISSDPDOBJS) testcodelength.o
|
||||||
|
@ -53,11 +61,6 @@ ifneq ($(OS), Darwin)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
minissdpd: $(MINISSDPDOBJS)
|
minissdpd: $(MINISSDPDOBJS)
|
||||||
if [ "$(DEB_BUILD_ARCH_OS)" = "kfreebsd" ] ; then \
|
|
||||||
$(CC) $(CFLAGS) $(LDFLAGS) -lfreebsd-glue -o $@ $(MINISSDPDOBJS) ; \
|
|
||||||
else \
|
|
||||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(MINISSDPDOBJS) ; \
|
|
||||||
fi
|
|
||||||
|
|
||||||
testminissdpd: $(TESTMINISSDPDOBJS)
|
testminissdpd: $(TESTMINISSDPDOBJS)
|
||||||
|
|
||||||
|
@ -71,10 +74,12 @@ depend:
|
||||||
|
|
||||||
# DO NOT DELETE
|
# DO NOT DELETE
|
||||||
|
|
||||||
minissdpd.o: config.h upnputils.h openssdpsocket.h daemonize.h codelength.h
|
minissdpd.o: config.h getifaddr.h upnputils.h openssdpsocket.h
|
||||||
minissdpd.o: ifacewatch.h
|
minissdpd.o: minissdpdtypes.h daemonize.h codelength.h ifacewatch.h
|
||||||
openssdpsocket.o: config.h openssdpsocket.h
|
openssdpsocket.o: config.h openssdpsocket.h minissdpdtypes.h upnputils.h
|
||||||
daemonize.o: daemonize.h config.h
|
daemonize.o: daemonize.h config.h
|
||||||
upnputils.o: config.h upnputils.h
|
upnputils.o: config.h upnputils.h getroute.h minissdpdtypes.h
|
||||||
ifacewatch.o: config.h openssdpsocket.h
|
ifacewatch.o: config.h openssdpsocket.h minissdpdtypes.h upnputils.h
|
||||||
|
getroute.o: getroute.h upnputils.h
|
||||||
|
getifaddr.o: config.h getifaddr.h
|
||||||
testcodelength.o: codelength.h
|
testcodelength.o: codelength.h
|
||||||
|
|
|
@ -0,0 +1,260 @@
|
||||||
|
/* $Id: getifaddr.c,v 1.23 2014/05/06 14:40:53 nanard Exp $ */
|
||||||
|
/* MiniUPnP project
|
||||||
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
|
* (c) 2006-2014 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed
|
||||||
|
* in the LICENCE file provided within the distribution */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#if defined(sun)
|
||||||
|
#include <sys/sockio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "getifaddr.h"
|
||||||
|
#if defined(USE_GETIFADDRS) || defined(ENABLE_IPV6) || defined(ENABLE_PCP)
|
||||||
|
#include <ifaddrs.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int
|
||||||
|
getifaddr(const char * ifname, char * buf, int len,
|
||||||
|
struct in_addr * addr, struct in_addr * mask)
|
||||||
|
{
|
||||||
|
#ifndef USE_GETIFADDRS
|
||||||
|
/* use ioctl SIOCGIFADDR. Works only for ip v4 */
|
||||||
|
/* SIOCGIFADDR struct ifreq * */
|
||||||
|
int s;
|
||||||
|
struct ifreq ifr;
|
||||||
|
int ifrlen;
|
||||||
|
struct sockaddr_in * ifaddr;
|
||||||
|
ifrlen = sizeof(ifr);
|
||||||
|
|
||||||
|
if(!ifname || ifname[0]=='\0')
|
||||||
|
return -1;
|
||||||
|
s = socket(PF_INET, SOCK_DGRAM, 0);
|
||||||
|
if(s < 0)
|
||||||
|
{
|
||||||
|
syslog(LOG_ERR, "socket(PF_INET, SOCK_DGRAM): %m");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
|
||||||
|
if(ioctl(s, SIOCGIFFLAGS, &ifr, &ifrlen) < 0)
|
||||||
|
{
|
||||||
|
syslog(LOG_DEBUG, "ioctl(s, SIOCGIFFLAGS, ...): %m");
|
||||||
|
close(s);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if ((ifr.ifr_flags & IFF_UP) == 0)
|
||||||
|
{
|
||||||
|
syslog(LOG_DEBUG, "network interface %s is down", ifname);
|
||||||
|
close(s);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
|
||||||
|
if(ioctl(s, SIOCGIFADDR, &ifr, &ifrlen) < 0)
|
||||||
|
{
|
||||||
|
syslog(LOG_ERR, "ioctl(s, SIOCGIFADDR, ...): %m");
|
||||||
|
close(s);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ifaddr = (struct sockaddr_in *)&ifr.ifr_addr;
|
||||||
|
if(addr) *addr = ifaddr->sin_addr;
|
||||||
|
if(buf)
|
||||||
|
{
|
||||||
|
if(!inet_ntop(AF_INET, &ifaddr->sin_addr, buf, len))
|
||||||
|
{
|
||||||
|
syslog(LOG_ERR, "inet_ntop(): %m");
|
||||||
|
close(s);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(mask)
|
||||||
|
{
|
||||||
|
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
|
||||||
|
if(ioctl(s, SIOCGIFNETMASK, &ifr, &ifrlen) < 0)
|
||||||
|
{
|
||||||
|
syslog(LOG_ERR, "ioctl(s, SIOCGIFNETMASK, ...): %m");
|
||||||
|
close(s);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#ifdef ifr_netmask
|
||||||
|
*mask = ((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr;
|
||||||
|
#else
|
||||||
|
*mask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
close(s);
|
||||||
|
#else /* ifndef USE_GETIFADDRS */
|
||||||
|
/* Works for all address families (both ip v4 and ip v6) */
|
||||||
|
struct ifaddrs * ifap;
|
||||||
|
struct ifaddrs * ife;
|
||||||
|
|
||||||
|
if(!ifname || ifname[0]=='\0')
|
||||||
|
return -1;
|
||||||
|
if(getifaddrs(&ifap)<0)
|
||||||
|
{
|
||||||
|
syslog(LOG_ERR, "getifaddrs: %m");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for(ife = ifap; ife; ife = ife->ifa_next)
|
||||||
|
{
|
||||||
|
/* skip other interfaces if one was specified */
|
||||||
|
if(ifname && (0 != strcmp(ifname, ife->ifa_name)))
|
||||||
|
continue;
|
||||||
|
if(ife->ifa_addr == NULL)
|
||||||
|
continue;
|
||||||
|
switch(ife->ifa_addr->sa_family)
|
||||||
|
{
|
||||||
|
case AF_INET:
|
||||||
|
if(buf)
|
||||||
|
{
|
||||||
|
inet_ntop(ife->ifa_addr->sa_family,
|
||||||
|
&((struct sockaddr_in *)ife->ifa_addr)->sin_addr,
|
||||||
|
buf, len);
|
||||||
|
}
|
||||||
|
if(addr) *addr = ((struct sockaddr_in *)ife->ifa_addr)->sin_addr;
|
||||||
|
if(mask) *mask = ((struct sockaddr_in *)ife->ifa_netmask)->sin_addr;
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
case AF_INET6:
|
||||||
|
inet_ntop(ife->ifa_addr->sa_family,
|
||||||
|
&((struct sockaddr_in6 *)ife->ifa_addr)->sin6_addr,
|
||||||
|
buf, len);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
freeifaddrs(ifap);
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_PCP
|
||||||
|
|
||||||
|
int getifaddr_in6(const char * ifname, int af, struct in6_addr * addr)
|
||||||
|
{
|
||||||
|
#if defined(ENABLE_IPV6) || defined(USE_GETIFADDRS)
|
||||||
|
struct ifaddrs * ifap;
|
||||||
|
struct ifaddrs * ife;
|
||||||
|
#ifdef ENABLE_IPV6
|
||||||
|
const struct sockaddr_in6 * tmpaddr;
|
||||||
|
#endif /* ENABLE_IPV6 */
|
||||||
|
int found = 0;
|
||||||
|
|
||||||
|
if(!ifname || ifname[0]=='\0')
|
||||||
|
return -1;
|
||||||
|
if(getifaddrs(&ifap)<0)
|
||||||
|
{
|
||||||
|
syslog(LOG_ERR, "getifaddrs: %m");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for(ife = ifap; ife && !found; ife = ife->ifa_next)
|
||||||
|
{
|
||||||
|
/* skip other interfaces if one was specified */
|
||||||
|
if(ifname && (0 != strcmp(ifname, ife->ifa_name)))
|
||||||
|
continue;
|
||||||
|
if(ife->ifa_addr == NULL)
|
||||||
|
continue;
|
||||||
|
if (ife->ifa_addr->sa_family != af)
|
||||||
|
continue;
|
||||||
|
switch(ife->ifa_addr->sa_family)
|
||||||
|
{
|
||||||
|
case AF_INET:
|
||||||
|
/* IPv4-mapped IPv6 address ::ffff:1.2.3.4 */
|
||||||
|
memset(addr->s6_addr, 0, 10);
|
||||||
|
addr->s6_addr[10] = 0xff;
|
||||||
|
addr->s6_addr[11] = 0xff;
|
||||||
|
memcpy(addr->s6_addr + 12,
|
||||||
|
&(((struct sockaddr_in *)ife->ifa_addr)->sin_addr.s_addr),
|
||||||
|
4);
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
#ifdef ENABLE_IPV6
|
||||||
|
case AF_INET6:
|
||||||
|
tmpaddr = (const struct sockaddr_in6 *)ife->ifa_addr;
|
||||||
|
if(!IN6_IS_ADDR_LOOPBACK(&tmpaddr->sin6_addr)
|
||||||
|
&& !IN6_IS_ADDR_LINKLOCAL(&tmpaddr->sin6_addr))
|
||||||
|
{
|
||||||
|
memcpy(addr->s6_addr,
|
||||||
|
&tmpaddr->sin6_addr,
|
||||||
|
16);
|
||||||
|
found = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif /* ENABLE_IPV6 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
freeifaddrs(ifap);
|
||||||
|
return (found ? 0 : -1);
|
||||||
|
#else /* defined(ENABLE_IPV6) || defined(USE_GETIFADDRS) */
|
||||||
|
/* IPv4 only */
|
||||||
|
struct in_addr addr4;
|
||||||
|
if(af != AF_INET)
|
||||||
|
return -1;
|
||||||
|
if(getifaddr(ifname, NULL, 0, &addr4, NULL) < 0)
|
||||||
|
return -1;
|
||||||
|
/* IPv4-mapped IPv6 address ::ffff:1.2.3.4 */
|
||||||
|
memset(addr->s6_addr, 0, 10);
|
||||||
|
addr->s6_addr[10] = 0xff;
|
||||||
|
addr->s6_addr[11] = 0xff;
|
||||||
|
memcpy(addr->s6_addr + 12, &addr4.s_addr, 4);
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif /* ENABLE_PCP */
|
||||||
|
|
||||||
|
#ifdef ENABLE_IPV6
|
||||||
|
int
|
||||||
|
find_ipv6_addr(const char * ifname,
|
||||||
|
char * dst, int n)
|
||||||
|
{
|
||||||
|
struct ifaddrs * ifap;
|
||||||
|
struct ifaddrs * ife;
|
||||||
|
const struct sockaddr_in6 * addr;
|
||||||
|
char buf[64];
|
||||||
|
int r = 0;
|
||||||
|
|
||||||
|
if(!dst)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if(getifaddrs(&ifap)<0)
|
||||||
|
{
|
||||||
|
syslog(LOG_ERR, "getifaddrs: %m");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for(ife = ifap; ife; ife = ife->ifa_next)
|
||||||
|
{
|
||||||
|
/* skip other interfaces if one was specified */
|
||||||
|
if(ifname && (0 != strcmp(ifname, ife->ifa_name)))
|
||||||
|
continue;
|
||||||
|
if(ife->ifa_addr == NULL)
|
||||||
|
continue;
|
||||||
|
if(ife->ifa_addr->sa_family == AF_INET6)
|
||||||
|
{
|
||||||
|
addr = (const struct sockaddr_in6 *)ife->ifa_addr;
|
||||||
|
if(!IN6_IS_ADDR_LOOPBACK(&addr->sin6_addr)
|
||||||
|
&& !IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr))
|
||||||
|
{
|
||||||
|
inet_ntop(ife->ifa_addr->sa_family,
|
||||||
|
&addr->sin6_addr,
|
||||||
|
buf, sizeof(buf));
|
||||||
|
/* add brackets */
|
||||||
|
snprintf(dst, n, "[%s]", buf);
|
||||||
|
r = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
freeifaddrs(ifap);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
/* $Id: getifaddr.h,v 1.10 2014/05/06 14:40:53 nanard Exp $ */
|
||||||
|
/* MiniUPnP project
|
||||||
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
|
* (c) 2006-2013 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed
|
||||||
|
* in the LICENCE file provided within the distribution */
|
||||||
|
|
||||||
|
#ifndef GETIFADDR_H_INCLUDED
|
||||||
|
#define GETIFADDR_H_INCLUDED
|
||||||
|
|
||||||
|
struct in_addr;
|
||||||
|
struct in6_addr;
|
||||||
|
|
||||||
|
/* getifaddr()
|
||||||
|
* take a network interface name and write the
|
||||||
|
* ip v4 address as text in the buffer
|
||||||
|
* returns: 0 success, -1 failure */
|
||||||
|
int
|
||||||
|
getifaddr(const char * ifname, char * buf, int len,
|
||||||
|
struct in_addr * addr, struct in_addr * mask);
|
||||||
|
|
||||||
|
int
|
||||||
|
getifaddr_in6(const char * ifname, int af, struct in6_addr* addr);
|
||||||
|
|
||||||
|
/* find a non link local IP v6 address for the interface.
|
||||||
|
* if ifname is NULL, look for all interfaces */
|
||||||
|
int
|
||||||
|
find_ipv6_addr(const char * ifname,
|
||||||
|
char * dst, int n);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,276 @@
|
||||||
|
/* $Id: getroute.c,v 1.3 2014/11/28 16:30:37 nanard Exp $ */
|
||||||
|
/* MiniUPnP project
|
||||||
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
|
* (c) 2006-2014 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed
|
||||||
|
* in the LICENCE file provided within the distribution */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#ifdef __linux__
|
||||||
|
/*#include <linux/in_route.h>*/
|
||||||
|
#include <linux/netlink.h>
|
||||||
|
#include <linux/rtnetlink.h>
|
||||||
|
#include <libnfnetlink/libnfnetlink.h>
|
||||||
|
#else /* __linux__ */
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <net/route.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#ifdef AF_LINK
|
||||||
|
#include <net/if_dl.h>
|
||||||
|
#endif /* AF_LINK */
|
||||||
|
#endif /* __linux__ */
|
||||||
|
|
||||||
|
#include "getroute.h"
|
||||||
|
#include "upnputils.h"
|
||||||
|
|
||||||
|
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, 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__ */
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
/* $Id: getroute.h,v 1.3 2013/02/06 10:50:04 nanard Exp $ */
|
||||||
|
/* MiniUPnP project
|
||||||
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
|
* (c) 2006-2013 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed
|
||||||
|
* in the LICENCE file provided within the distribution */
|
||||||
|
|
||||||
|
#ifndef GETROUTE_H_INCLUDED
|
||||||
|
#define GETROUTE_H_INCLUDED
|
||||||
|
|
||||||
|
int
|
||||||
|
get_src_for_route_to(const struct sockaddr * dst,
|
||||||
|
void * src, size_t * src_len,
|
||||||
|
int * index);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $Id: ifacewatch.c,v 1.13 2012/05/21 17:13:11 nanard Exp $ */
|
/* $Id: ifacewatch.c,v 1.15 2014/11/28 16:30:37 nanard Exp $ */
|
||||||
/* MiniUPnP project
|
/* MiniUPnP project
|
||||||
* (c) 2011-2012 Thomas Bernard
|
* (c) 2011-2012 Thomas Bernard
|
||||||
* website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
|
@ -28,6 +28,9 @@
|
||||||
|
|
||||||
#include "openssdpsocket.h"
|
#include "openssdpsocket.h"
|
||||||
#include "upnputils.h"
|
#include "upnputils.h"
|
||||||
|
#include "minissdpdtypes.h"
|
||||||
|
|
||||||
|
extern struct lan_addr_list lan_addrs;
|
||||||
|
|
||||||
#ifndef __linux__
|
#ifndef __linux__
|
||||||
#if defined(__OpenBSD__) || defined(__FreeBSD__)
|
#if defined(__OpenBSD__) || defined(__FreeBSD__)
|
||||||
|
@ -81,11 +84,10 @@ OpenAndConfInterfaceWatchSocket(void)
|
||||||
* Process the message and add/drop multicast membership if needed
|
* Process the message and add/drop multicast membership if needed
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
ProcessInterfaceWatch(int s, int s_ssdp, int s_ssdp6,
|
ProcessInterfaceWatch(int s, int s_ssdp, int s_ssdp6)
|
||||||
int n_if_addr, const char * * if_addr)
|
|
||||||
{
|
{
|
||||||
|
struct lan_addr_s * lan_addr;
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
int i;
|
|
||||||
char buffer[4096];
|
char buffer[4096];
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
|
@ -166,14 +168,14 @@ ProcessInterfaceWatch(int s, int s_ssdp, int s_ssdp6,
|
||||||
syslog(LOG_INFO, "%s: %s/%d %s",
|
syslog(LOG_INFO, "%s: %s/%d %s",
|
||||||
is_del ? "RTM_DELADDR" : "RTM_NEWADDR",
|
is_del ? "RTM_DELADDR" : "RTM_NEWADDR",
|
||||||
address, ifa->ifa_prefixlen, ifname);
|
address, ifa->ifa_prefixlen, ifname);
|
||||||
for(i = 0; i < n_if_addr; i++) {
|
for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next) {
|
||||||
if((0 == strcmp(address, if_addr[i])) ||
|
if((0 == strcmp(address, lan_addr->str)) ||
|
||||||
(0 == strcmp(ifname, if_addr[i])) ||
|
(0 == strcmp(ifname, lan_addr->ifname)) ||
|
||||||
(ifa->ifa_index == if_nametoindex(if_addr[i]))) {
|
(ifa->ifa_index == lan_addr->index)) {
|
||||||
if(ifa->ifa_family == AF_INET && address[0] != '\0')
|
if(ifa->ifa_family == AF_INET)
|
||||||
AddDropMulticastMembership(s_ssdp, address, 0, is_del);
|
AddDropMulticastMembership(s_ssdp, lan_addr, 0, is_del);
|
||||||
else if(ifa->ifa_family == AF_INET6)
|
else if(ifa->ifa_family == AF_INET6)
|
||||||
AddDropMulticastMembership(s_ssdp6, if_addr[i], 1, is_del);
|
AddDropMulticastMembership(s_ssdp6, lan_addr, 1, is_del);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -299,14 +301,14 @@ ProcessInterfaceWatch(int s, int s_ssdp, int s_ssdp6,
|
||||||
syslog(LOG_INFO, "%s: %s/%d %s",
|
syslog(LOG_INFO, "%s: %s/%d %s",
|
||||||
is_del ? "RTM_DELADDR" : "RTM_NEWADDR",
|
is_del ? "RTM_DELADDR" : "RTM_NEWADDR",
|
||||||
address, prefixlen, ifname);
|
address, prefixlen, ifname);
|
||||||
for(i = 0; i < n_if_addr; i++) {
|
for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next) {
|
||||||
if(0 == strcmp(address, if_addr[i]) ||
|
if((0 == strcmp(address, lan_addr->str)) ||
|
||||||
0 == strcmp(ifname, if_addr[i]) ||
|
(0 == strcmp(ifname, lan_addr->ifname)) ||
|
||||||
ifam->ifam_index == if_nametoindex(if_addr[i])) {
|
(ifam->ifam_index == lan_addr->index)) {
|
||||||
if(family == AF_INET && address[0] != '\0')
|
if(family == AF_INET)
|
||||||
AddDropMulticastMembership(s_ssdp, address, 0, is_del);
|
AddDropMulticastMembership(s_ssdp, lan_addr, 0, is_del);
|
||||||
else if(family == AF_INET6)
|
else if(family == AF_INET6)
|
||||||
AddDropMulticastMembership(s_ssdp6, if_addr[i], 1, is_del);
|
AddDropMulticastMembership(s_ssdp6, lan_addr, 1, is_del);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* $Id: ifacewatch.h,v 1.1 2011/07/29 15:21:13 nanard Exp $ */
|
/* $Id: ifacewatch.h,v 1.4 2014/11/28 16:20:57 nanard Exp $ */
|
||||||
/* MiniUPnP project
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
* (c) 2011 Thomas Bernard
|
* (c) 2011-2014 Thomas Bernard
|
||||||
* This software is subject to the conditions detailed
|
* This software is subject to the conditions detailed
|
||||||
* in the LICENCE file provided within the distribution */
|
* in the LICENCE file provided within the distribution */
|
||||||
|
|
||||||
|
@ -12,7 +12,6 @@ int
|
||||||
OpenAndConfInterfaceWatchSocket(void);
|
OpenAndConfInterfaceWatchSocket(void);
|
||||||
|
|
||||||
int
|
int
|
||||||
ProcessInterfaceWatch(int s, int s_ssdp, int s_ssdp6,
|
ProcessInterfaceWatch(int s, int s_ssdp, int s_ssdp6);
|
||||||
int n_if_addr, const char * * if_addr);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $Id: minissdpd.c,v 1.40 2014/11/28 14:31:44 nanard Exp $ */
|
/* $Id: minissdpd.c,v 1.41 2014/11/28 16:20:57 nanard Exp $ */
|
||||||
/* MiniUPnP project
|
/* MiniUPnP project
|
||||||
* (c) 2007-2014 Thomas Bernard
|
* (c) 2007-2014 Thomas Bernard
|
||||||
* website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
|
@ -30,11 +30,13 @@
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
|
|
||||||
|
#include "getifaddr.h"
|
||||||
#include "upnputils.h"
|
#include "upnputils.h"
|
||||||
#include "openssdpsocket.h"
|
#include "openssdpsocket.h"
|
||||||
#include "daemonize.h"
|
#include "daemonize.h"
|
||||||
#include "codelength.h"
|
#include "codelength.h"
|
||||||
#include "ifacewatch.h"
|
#include "ifacewatch.h"
|
||||||
|
#include "minissdpdtypes.h"
|
||||||
|
|
||||||
/* current request management stucture */
|
/* current request management stucture */
|
||||||
struct reqelem {
|
struct reqelem {
|
||||||
|
@ -42,7 +44,7 @@ struct reqelem {
|
||||||
LIST_ENTRY(reqelem) entries;
|
LIST_ENTRY(reqelem) entries;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* divice data structures */
|
/* device data structures */
|
||||||
struct header {
|
struct header {
|
||||||
const char * p; /* string pointer */
|
const char * p; /* string pointer */
|
||||||
int l; /* string length */
|
int l; /* string length */
|
||||||
|
@ -70,6 +72,95 @@ struct device * devlist = 0;
|
||||||
unsigned int upnp_bootid = 1;
|
unsigned int upnp_bootid = 1;
|
||||||
unsigned int upnp_configid = 1337;
|
unsigned int upnp_configid = 1337;
|
||||||
|
|
||||||
|
/* LAN interfaces/addresses */
|
||||||
|
struct lan_addr_list lan_addrs;
|
||||||
|
|
||||||
|
|
||||||
|
/* functions */
|
||||||
|
|
||||||
|
/* parselanaddr()
|
||||||
|
* parse address with mask
|
||||||
|
* ex: 192.168.1.1/24 or 192.168.1.1/255.255.255.0
|
||||||
|
*
|
||||||
|
* Can also use the interface name (ie eth0)
|
||||||
|
*
|
||||||
|
* return value :
|
||||||
|
* 0 : ok
|
||||||
|
* -1 : error */
|
||||||
|
static int
|
||||||
|
parselanaddr(struct lan_addr_s * lan_addr, const char * str)
|
||||||
|
{
|
||||||
|
const char * p;
|
||||||
|
int n;
|
||||||
|
char tmp[16];
|
||||||
|
|
||||||
|
memset(lan_addr, 0, sizeof(struct lan_addr_s));
|
||||||
|
p = str;
|
||||||
|
while(*p && *p != '/' && !isspace(*p))
|
||||||
|
p++;
|
||||||
|
n = p - str;
|
||||||
|
if(!isdigit(str[0]) && n < (int)sizeof(lan_addr->ifname)) {
|
||||||
|
/* not starting with a digit : suppose it is an interface name */
|
||||||
|
memcpy(lan_addr->ifname, str, n);
|
||||||
|
lan_addr->ifname[n] = '\0';
|
||||||
|
if(getifaddr(lan_addr->ifname, lan_addr->str, sizeof(lan_addr->str),
|
||||||
|
&lan_addr->addr, &lan_addr->mask) < 0)
|
||||||
|
goto parselan_error;
|
||||||
|
/*printf("%s => %s\n", lan_addr->ifname, lan_addr->str);*/
|
||||||
|
} else {
|
||||||
|
if(n>15)
|
||||||
|
goto parselan_error;
|
||||||
|
memcpy(lan_addr->str, str, n);
|
||||||
|
lan_addr->str[n] = '\0';
|
||||||
|
if(!inet_aton(lan_addr->str, &lan_addr->addr))
|
||||||
|
goto parselan_error;
|
||||||
|
}
|
||||||
|
if(*p == '/') {
|
||||||
|
const char * q = ++p;
|
||||||
|
while(*p && isdigit(*p))
|
||||||
|
p++;
|
||||||
|
if(*p=='.') {
|
||||||
|
/* parse mask in /255.255.255.0 format */
|
||||||
|
while(*p && (*p=='.' || isdigit(*p)))
|
||||||
|
p++;
|
||||||
|
n = p - q;
|
||||||
|
if(n>15)
|
||||||
|
goto parselan_error;
|
||||||
|
memcpy(tmp, q, n);
|
||||||
|
tmp[n] = '\0';
|
||||||
|
if(!inet_aton(tmp, &lan_addr->mask))
|
||||||
|
goto parselan_error;
|
||||||
|
} else {
|
||||||
|
/* it is a /24 format */
|
||||||
|
int nbits = atoi(q);
|
||||||
|
if(nbits > 32 || nbits < 0)
|
||||||
|
goto parselan_error;
|
||||||
|
lan_addr->mask.s_addr = htonl(nbits ? (0xffffffffu << (32 - nbits)) : 0);
|
||||||
|
}
|
||||||
|
} else if(lan_addr->mask.s_addr == 0) {
|
||||||
|
/* by default, networks are /24 */
|
||||||
|
lan_addr->mask.s_addr = htonl(0xffffff00u);
|
||||||
|
}
|
||||||
|
#ifdef ENABLE_IPV6
|
||||||
|
if(lan_addr->ifname[0] != '\0') {
|
||||||
|
lan_addr->index = if_nametoindex(lan_addr->ifname);
|
||||||
|
if(lan_addr->index == 0)
|
||||||
|
fprintf(stderr, "Cannot get index for network interface %s",
|
||||||
|
lan_addr->ifname);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Error: please specify LAN network interface by name instead of IPv4 address : %s\n",
|
||||||
|
str);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif /* ENABLE_IPV6 */
|
||||||
|
return 0;
|
||||||
|
parselan_error:
|
||||||
|
fprintf(stderr, "Error parsing address/mask (or interface name) : %s\n",
|
||||||
|
str);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
nts_to_str(int nts)
|
nts_to_str(int nts)
|
||||||
{
|
{
|
||||||
|
@ -260,8 +351,7 @@ processMSEARCH(int s, const char * st, int st_len,
|
||||||
inet_ntoa(((const struct sockaddr_in *)addr)->sin_addr),
|
inet_ntoa(((const struct sockaddr_in *)addr)->sin_addr),
|
||||||
ntohs(((const struct sockaddr_in *)addr)->sin_port),
|
ntohs(((const struct sockaddr_in *)addr)->sin_port),
|
||||||
st_len, st);
|
st_len, st);
|
||||||
#endif
|
#endif /* ENABLE_IPV6 */
|
||||||
/* TODO : ignore packet if not coming from a LAN */
|
|
||||||
if(st_len==8 && (0==memcmp(st, "ssdp:all", 8))) {
|
if(st_len==8 && (0==memcmp(st, "ssdp:all", 8))) {
|
||||||
/* send a response for all services */
|
/* send a response for all services */
|
||||||
for(serv = servicelisthead.lh_first;
|
for(serv = servicelisthead.lh_first;
|
||||||
|
@ -343,6 +433,16 @@ ParseSSDPPacket(int s, const char * p, ssize_t n,
|
||||||
const char * st = NULL;
|
const char * st = NULL;
|
||||||
int st_len = 0;
|
int st_len = 0;
|
||||||
|
|
||||||
|
/* first check from what subnet is the sender */
|
||||||
|
if(get_lan_for_peer(addr) == NULL) {
|
||||||
|
char addr_str[64];
|
||||||
|
sockaddr_to_string(addr, addr_str, sizeof(addr_str));
|
||||||
|
syslog(LOG_WARNING, "peer %s is not from a LAN",
|
||||||
|
addr_str);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* do the parsing */
|
||||||
memset(headers, 0, sizeof(headers));
|
memset(headers, 0, sizeof(headers));
|
||||||
for(methodlen = 0;
|
for(methodlen = 0;
|
||||||
methodlen < n && (isalpha(p[methodlen]) || p[methodlen]=='-');
|
methodlen < n && (isalpha(p[methodlen]) || p[methodlen]=='-');
|
||||||
|
@ -870,8 +970,7 @@ int main(int argc, char * * argv)
|
||||||
struct reqelem * req;
|
struct reqelem * req;
|
||||||
struct reqelem * reqnext;
|
struct reqelem * reqnext;
|
||||||
fd_set readfds;
|
fd_set readfds;
|
||||||
const char * if_addr[MAX_IF_ADDR];
|
struct lan_addr_s * lan_addr;
|
||||||
int n_if_addr = 0;
|
|
||||||
int i;
|
int i;
|
||||||
const char * sockpath = "/var/run/minissdpd.sock";
|
const char * sockpath = "/var/run/minissdpd.sock";
|
||||||
const char * pidfilename = "/var/run/minissdpd.pid";
|
const char * pidfilename = "/var/run/minissdpd.pid";
|
||||||
|
@ -889,15 +988,22 @@ int main(int argc, char * * argv)
|
||||||
|
|
||||||
LIST_INIT(&reqlisthead);
|
LIST_INIT(&reqlisthead);
|
||||||
LIST_INIT(&servicelisthead);
|
LIST_INIT(&servicelisthead);
|
||||||
|
LIST_INIT(&lan_addrs);
|
||||||
/* process command line */
|
/* process command line */
|
||||||
for(i=1; i<argc; i++)
|
for(i=1; i<argc; i++)
|
||||||
{
|
{
|
||||||
if(0==strcmp(argv[i], "-i")) {
|
if(0==strcmp(argv[i], "-i")) {
|
||||||
if(n_if_addr < MAX_IF_ADDR)
|
lan_addr = malloc(sizeof(struct lan_addr_s));
|
||||||
if_addr[n_if_addr++] = argv[++i];
|
if(lan_addr == NULL) {
|
||||||
else
|
fprintf(stderr, "malloc(%d) FAILED\n", (int)sizeof(struct lan_addr_s));
|
||||||
syslog(LOG_WARNING, "Max number of interface address set to %d, "
|
break;
|
||||||
"ignoring %s", MAX_IF_ADDR, argv[++i]);
|
}
|
||||||
|
if(parselanaddr(lan_addr, argv[++i]) != 0) {
|
||||||
|
fprintf(stderr, "can't parse \"%s\" as a valid address or interface name\n", argv[i]);
|
||||||
|
free(lan_addr);
|
||||||
|
} else {
|
||||||
|
LIST_INSERT_HEAD(&lan_addrs, lan_addr, list);
|
||||||
|
}
|
||||||
} else if(0==strcmp(argv[i], "-d"))
|
} else if(0==strcmp(argv[i], "-d"))
|
||||||
debug_flag = 1;
|
debug_flag = 1;
|
||||||
else if(0==strcmp(argv[i], "-s"))
|
else if(0==strcmp(argv[i], "-s"))
|
||||||
|
@ -909,7 +1015,7 @@ int main(int argc, char * * argv)
|
||||||
ipv6 = 1;
|
ipv6 = 1;
|
||||||
#endif /* ENABLE_IPV6 */
|
#endif /* ENABLE_IPV6 */
|
||||||
}
|
}
|
||||||
if(n_if_addr < 1)
|
if(lan_addrs.lh_first == NULL)
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Usage: %s [-d] "
|
"Usage: %s [-d] "
|
||||||
|
@ -920,7 +1026,8 @@ int main(int argc, char * * argv)
|
||||||
"-i <interface> [-i <interface2>] ...\n",
|
"-i <interface> [-i <interface2>] ...\n",
|
||||||
argv[0]);
|
argv[0]);
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"\n <interface> is either an IPv4 address such as 192.168.1.42, or an\ninterface name such as eth0.\n");
|
"\n <interface> is either an IPv4 address with mask such as\n"
|
||||||
|
" 192.168.1.42/255.255.255.0, or an interface name such as eth0.\n");
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"\n By default, socket will be open as %s\n"
|
"\n By default, socket will be open as %s\n"
|
||||||
"and pid written to file %s\n",
|
"and pid written to file %s\n",
|
||||||
|
@ -959,7 +1066,7 @@ int main(int argc, char * * argv)
|
||||||
/* open route/interface config changes socket */
|
/* open route/interface config changes socket */
|
||||||
s_ifacewatch = OpenAndConfInterfaceWatchSocket();
|
s_ifacewatch = OpenAndConfInterfaceWatchSocket();
|
||||||
/* open UDP socket(s) for receiving SSDP packets */
|
/* open UDP socket(s) for receiving SSDP packets */
|
||||||
s_ssdp = OpenAndConfSSDPReceiveSocket(n_if_addr, if_addr, 0);
|
s_ssdp = OpenAndConfSSDPReceiveSocket(0);
|
||||||
if(s_ssdp < 0)
|
if(s_ssdp < 0)
|
||||||
{
|
{
|
||||||
syslog(LOG_ERR, "Cannot open socket for receiving SSDP messages, exiting");
|
syslog(LOG_ERR, "Cannot open socket for receiving SSDP messages, exiting");
|
||||||
|
@ -968,7 +1075,7 @@ int main(int argc, char * * argv)
|
||||||
}
|
}
|
||||||
#ifdef ENABLE_IPV6
|
#ifdef ENABLE_IPV6
|
||||||
if(ipv6) {
|
if(ipv6) {
|
||||||
s_ssdp6 = OpenAndConfSSDPReceiveSocket(n_if_addr, if_addr, 1);
|
s_ssdp6 = OpenAndConfSSDPReceiveSocket(1);
|
||||||
if(s_ssdp6 < 0)
|
if(s_ssdp6 < 0)
|
||||||
{
|
{
|
||||||
syslog(LOG_ERR, "Cannot open socket for receiving SSDP messages (IPv6), exiting");
|
syslog(LOG_ERR, "Cannot open socket for receiving SSDP messages (IPv6), exiting");
|
||||||
|
@ -1183,9 +1290,10 @@ int main(int argc, char * * argv)
|
||||||
}
|
}
|
||||||
/* processing route/network interface config changes */
|
/* processing route/network interface config changes */
|
||||||
if((s_ifacewatch >= 0) && FD_ISSET(s_ifacewatch, &readfds)) {
|
if((s_ifacewatch >= 0) && FD_ISSET(s_ifacewatch, &readfds)) {
|
||||||
ProcessInterfaceWatch(s_ifacewatch, s_ssdp, s_ssdp6, n_if_addr, if_addr);
|
ProcessInterfaceWatch(s_ifacewatch, s_ssdp, s_ssdp6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
syslog(LOG_DEBUG, "quitting...");
|
||||||
|
|
||||||
/* closing and cleaning everything */
|
/* closing and cleaning everything */
|
||||||
quit:
|
quit:
|
||||||
|
@ -1209,6 +1317,18 @@ quit:
|
||||||
close(s_ifacewatch);
|
close(s_ifacewatch);
|
||||||
s_ifacewatch = -1;
|
s_ifacewatch = -1;
|
||||||
}
|
}
|
||||||
|
/* empty LAN interface/address list */
|
||||||
|
while(lan_addrs.lh_first != NULL) {
|
||||||
|
lan_addr = lan_addrs.lh_first;
|
||||||
|
LIST_REMOVE(lan_addrs.lh_first, list);
|
||||||
|
free(lan_addr);
|
||||||
|
}
|
||||||
|
/* empty device list */
|
||||||
|
while(devlist != NULL) {
|
||||||
|
struct device * next = devlist->next;
|
||||||
|
free(devlist);
|
||||||
|
devlist = next;
|
||||||
|
}
|
||||||
if(unlink(pidfilename) < 0)
|
if(unlink(pidfilename) < 0)
|
||||||
syslog(LOG_ERR, "unlink(%s): %m", pidfilename);
|
syslog(LOG_ERR, "unlink(%s): %m", pidfilename);
|
||||||
closelog();
|
closelog();
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/* $Id: minissdpdtypes.h,v 1.1 2014/11/28 16:20:58 nanard Exp $ */
|
||||||
|
/* MiniUPnP project
|
||||||
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
|
* (c) 2006-2014 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed
|
||||||
|
* in the LICENCE file provided within the distribution */
|
||||||
|
#ifndef MINISSDPDTYPES_H_INCLUDED
|
||||||
|
#define MINISSDPDTYPES_H_INCLUDED
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
|
||||||
|
/* structure and list for storing lan addresses
|
||||||
|
* with ascii representation and mask */
|
||||||
|
struct lan_addr_s {
|
||||||
|
char ifname[IFNAMSIZ]; /* example: eth0 */
|
||||||
|
#ifdef ENABLE_IPV6
|
||||||
|
unsigned int index; /* use if_nametoindex() */
|
||||||
|
#endif /* ENABLE_IPV6 */
|
||||||
|
char str[16]; /* example: 192.168.0.1 */
|
||||||
|
struct in_addr addr, mask; /* ip/mask */
|
||||||
|
LIST_ENTRY(lan_addr_s) list;
|
||||||
|
};
|
||||||
|
LIST_HEAD(lan_addr_list, lan_addr_s);
|
||||||
|
|
||||||
|
#endif /* MINISSDPDTYPES_H_INCLUDED */
|
|
@ -1,4 +1,4 @@
|
||||||
/* $Id: openssdpsocket.c,v 1.14 2014/11/06 10:13:36 nanard Exp $ */
|
/* $Id: openssdpsocket.c,v 1.15 2014/11/28 16:20:58 nanard Exp $ */
|
||||||
/* MiniUPnP project
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
* (c) 2006-2014 Thomas Bernard
|
* (c) 2006-2014 Thomas Bernard
|
||||||
|
@ -18,6 +18,9 @@
|
||||||
|
|
||||||
#include "openssdpsocket.h"
|
#include "openssdpsocket.h"
|
||||||
#include "upnputils.h"
|
#include "upnputils.h"
|
||||||
|
#include "minissdpdtypes.h"
|
||||||
|
|
||||||
|
extern struct lan_addr_list lan_addrs;
|
||||||
|
|
||||||
/* SSDP ip/port */
|
/* SSDP ip/port */
|
||||||
#define SSDP_PORT (1900)
|
#define SSDP_PORT (1900)
|
||||||
|
@ -26,44 +29,6 @@
|
||||||
#define LL_SSDP_MCAST_ADDR ("FF02::C")
|
#define LL_SSDP_MCAST_ADDR ("FF02::C")
|
||||||
#define SL_SSDP_MCAST_ADDR ("FF05::C")
|
#define SL_SSDP_MCAST_ADDR ("FF05::C")
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the IPv4 address from a string
|
|
||||||
* representing the address or the interface name
|
|
||||||
*/
|
|
||||||
static in_addr_t
|
|
||||||
GetIfAddrIPv4(const char * ifaddr)
|
|
||||||
{
|
|
||||||
in_addr_t addr;
|
|
||||||
int s;
|
|
||||||
struct ifreq ifr;
|
|
||||||
int ifrlen;
|
|
||||||
|
|
||||||
/* let's suppose ifaddr is a IPv4 address
|
|
||||||
* such as 192.168.1.1 */
|
|
||||||
addr = inet_addr(ifaddr);
|
|
||||||
if(addr != INADDR_NONE)
|
|
||||||
return addr;
|
|
||||||
/* let's suppose the ifaddr was in fact an interface name
|
|
||||||
* such as eth0 */
|
|
||||||
s = socket(PF_INET, SOCK_DGRAM, 0);
|
|
||||||
if(s < 0) {
|
|
||||||
syslog(LOG_ERR, "socket(PF_INET, SOCK_DGRAM): %m");
|
|
||||||
return INADDR_NONE;
|
|
||||||
}
|
|
||||||
memset(&ifr, 0, sizeof(struct ifreq));
|
|
||||||
strncpy(ifr.ifr_name, ifaddr, IFNAMSIZ);
|
|
||||||
if(ioctl(s, SIOCGIFADDR, &ifr, &ifrlen) < 0) {
|
|
||||||
syslog(LOG_ERR, "ioctl(s, SIOCGIFADDR, ...): %m");
|
|
||||||
close(s);
|
|
||||||
return INADDR_NONE;
|
|
||||||
}
|
|
||||||
syslog(LOG_DEBUG, "GetIfAddrIPv4(%s) = %s", ifaddr,
|
|
||||||
inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
|
|
||||||
addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
|
|
||||||
close(s);
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the multicast membership for SSDP on the interface
|
* Add the multicast membership for SSDP on the interface
|
||||||
* @param s the socket
|
* @param s the socket
|
||||||
|
@ -71,12 +36,11 @@ GetIfAddrIPv4(const char * ifaddr)
|
||||||
* @param ipv6 IPv6 or IPv4
|
* @param ipv6 IPv6 or IPv4
|
||||||
* return -1 on error, 0 on success */
|
* return -1 on error, 0 on success */
|
||||||
int
|
int
|
||||||
AddDropMulticastMembership(int s, const char * ifaddr, int ipv6, int drop)
|
AddDropMulticastMembership(int s, struct lan_addr_s * lan_addr, int ipv6, int drop)
|
||||||
{
|
{
|
||||||
struct ip_mreq imr; /* Ip multicast membership */
|
struct ip_mreq imr; /* Ip multicast membership */
|
||||||
#ifdef ENABLE_IPV6
|
#ifdef ENABLE_IPV6
|
||||||
struct ipv6_mreq mr;
|
struct ipv6_mreq mr;
|
||||||
unsigned int ifindex;
|
|
||||||
#else /* ENABLE_IPV6 */
|
#else /* ENABLE_IPV6 */
|
||||||
(void)ipv6;
|
(void)ipv6;
|
||||||
#endif /* ENABLE_IPV6 */
|
#endif /* ENABLE_IPV6 */
|
||||||
|
@ -86,17 +50,16 @@ AddDropMulticastMembership(int s, const char * ifaddr, int ipv6, int drop)
|
||||||
#ifdef ENABLE_IPV6
|
#ifdef ENABLE_IPV6
|
||||||
if(ipv6)
|
if(ipv6)
|
||||||
{
|
{
|
||||||
ifindex = if_nametoindex(ifaddr);
|
|
||||||
memset(&mr, 0, sizeof(mr));
|
memset(&mr, 0, sizeof(mr));
|
||||||
inet_pton(AF_INET6, LL_SSDP_MCAST_ADDR, &mr.ipv6mr_multiaddr);
|
inet_pton(AF_INET6, LL_SSDP_MCAST_ADDR, &mr.ipv6mr_multiaddr);
|
||||||
mr.ipv6mr_interface = ifindex;
|
mr.ipv6mr_interface = lan_addr->index;
|
||||||
if(setsockopt(s, IPPROTO_IPV6, drop ? IPV6_LEAVE_GROUP : IPV6_JOIN_GROUP,
|
if(setsockopt(s, IPPROTO_IPV6, drop ? IPV6_LEAVE_GROUP : IPV6_JOIN_GROUP,
|
||||||
&mr, sizeof(struct ipv6_mreq)) < 0)
|
&mr, sizeof(struct ipv6_mreq)) < 0)
|
||||||
{
|
{
|
||||||
syslog(LOG_ERR, "setsockopt(udp, %s)(%s, %s): %m",
|
syslog(LOG_ERR, "setsockopt(udp, %s)(%s, %s): %m",
|
||||||
drop ? "IPV6_LEAVE_GROUP" : "IPV6_JOIN_GROUP",
|
drop ? "IPV6_LEAVE_GROUP" : "IPV6_JOIN_GROUP",
|
||||||
LL_SSDP_MCAST_ADDR,
|
LL_SSDP_MCAST_ADDR,
|
||||||
ifaddr);
|
lan_addr->ifname);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
inet_pton(AF_INET6, SL_SSDP_MCAST_ADDR, &mr.ipv6mr_multiaddr);
|
inet_pton(AF_INET6, SL_SSDP_MCAST_ADDR, &mr.ipv6mr_multiaddr);
|
||||||
|
@ -106,7 +69,7 @@ AddDropMulticastMembership(int s, const char * ifaddr, int ipv6, int drop)
|
||||||
syslog(LOG_ERR, "setsockopt(udp, %s)(%s, %s): %m",
|
syslog(LOG_ERR, "setsockopt(udp, %s)(%s, %s): %m",
|
||||||
drop ? "IPV6_LEAVE_GROUP" : "IPV6_JOIN_GROUP",
|
drop ? "IPV6_LEAVE_GROUP" : "IPV6_JOIN_GROUP",
|
||||||
SL_SSDP_MCAST_ADDR,
|
SL_SSDP_MCAST_ADDR,
|
||||||
ifaddr);
|
lan_addr->ifname);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,11 +78,11 @@ AddDropMulticastMembership(int s, const char * ifaddr, int ipv6, int drop)
|
||||||
#endif /* ENABLE_IPV6 */
|
#endif /* ENABLE_IPV6 */
|
||||||
/* setting up imr structure */
|
/* setting up imr structure */
|
||||||
imr.imr_multiaddr.s_addr = inet_addr(SSDP_MCAST_ADDR);
|
imr.imr_multiaddr.s_addr = inet_addr(SSDP_MCAST_ADDR);
|
||||||
imr.imr_interface.s_addr = GetIfAddrIPv4(ifaddr);
|
imr.imr_interface.s_addr = lan_addr->addr.s_addr;
|
||||||
if(imr.imr_interface.s_addr == INADDR_NONE)
|
if(imr.imr_interface.s_addr == INADDR_NONE)
|
||||||
{
|
{
|
||||||
syslog(LOG_ERR, "no IPv4 address for interface %s",
|
syslog(LOG_ERR, "no IPv4 address for interface %s",
|
||||||
ifaddr);
|
lan_addr->ifname);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,7 +91,7 @@ AddDropMulticastMembership(int s, const char * ifaddr, int ipv6, int drop)
|
||||||
{
|
{
|
||||||
syslog(LOG_ERR, "setsockopt(udp, %s)(%s): %m",
|
syslog(LOG_ERR, "setsockopt(udp, %s)(%s): %m",
|
||||||
drop ? "IP_DROP_MEMBERSHIP" : "IP_ADD_MEMBERSHIP",
|
drop ? "IP_DROP_MEMBERSHIP" : "IP_ADD_MEMBERSHIP",
|
||||||
ifaddr);
|
lan_addr->ifname);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#ifdef ENABLE_IPV6
|
#ifdef ENABLE_IPV6
|
||||||
|
@ -139,9 +102,7 @@ AddDropMulticastMembership(int s, const char * ifaddr, int ipv6, int drop)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
OpenAndConfSSDPReceiveSocket(int n_listen_addr,
|
OpenAndConfSSDPReceiveSocket(int ipv6)
|
||||||
const char * * listen_addr,
|
|
||||||
int ipv6)
|
|
||||||
{
|
{
|
||||||
int s;
|
int s;
|
||||||
int opt = 1;
|
int opt = 1;
|
||||||
|
@ -151,6 +112,7 @@ OpenAndConfSSDPReceiveSocket(int n_listen_addr,
|
||||||
struct sockaddr_in sockname;
|
struct sockaddr_in sockname;
|
||||||
#endif /* ENABLE_IPV6 */
|
#endif /* ENABLE_IPV6 */
|
||||||
socklen_t sockname_len;
|
socklen_t sockname_len;
|
||||||
|
struct lan_addr_s * lan_addr;
|
||||||
|
|
||||||
#ifndef ENABLE_IPV6
|
#ifndef ENABLE_IPV6
|
||||||
if(ipv6) {
|
if(ipv6) {
|
||||||
|
@ -246,14 +208,13 @@ OpenAndConfSSDPReceiveSocket(int n_listen_addr,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(n_listen_addr>0)
|
for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next)
|
||||||
{
|
{
|
||||||
n_listen_addr--;
|
if(AddDropMulticastMembership(s, lan_addr, ipv6, 0) < 0)
|
||||||
if(AddDropMulticastMembership(s, listen_addr[n_listen_addr], ipv6, 0) < 0)
|
|
||||||
{
|
{
|
||||||
syslog(LOG_WARNING, "Failed to add IPv%d multicast membership for interface %s.",
|
syslog(LOG_WARNING, "Failed to add IPv%d multicast membership for interface %s.",
|
||||||
ipv6 ? 6 : 4,
|
ipv6 ? 6 : 4,
|
||||||
listen_addr[n_listen_addr] );
|
lan_addr->ifname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,34 +1,32 @@
|
||||||
/* $Id: openssdpsocket.h,v 1.4 2011/07/29 15:21:13 nanard Exp $ */
|
/* $Id: openssdpsocket.h,v 1.6 2014/11/28 16:20:58 nanard Exp $ */
|
||||||
/* MiniUPnP project
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
* (c) 2006-2011 Thomas Bernard
|
* (c) 2006-2014 Thomas Bernard
|
||||||
* This software is subject to the conditions detailed
|
* This software is subject to the conditions detailed
|
||||||
* in the LICENCE file provided within the distribution */
|
* in the LICENCE file provided within the distribution */
|
||||||
#ifndef OPENSSDPSOCKET_H_INCLUDED
|
#ifndef OPENSSDPSOCKET_H_INCLUDED
|
||||||
#define OPENSSDPSOCKET_H_INCLUDED
|
#define OPENSSDPSOCKET_H_INCLUDED
|
||||||
|
|
||||||
|
#include "minissdpdtypes.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open a socket and configure it for receiving SSDP packets
|
* Open a socket and configure it for receiving SSDP packets
|
||||||
*
|
*
|
||||||
* @param n_listen_addr size of listen_addr array
|
|
||||||
* @param listen_addr array of address (or interface names) to listen
|
|
||||||
* @param ipv6 open INET6 or INET socket
|
* @param ipv6 open INET6 or INET socket
|
||||||
* @return socket
|
* @return socket
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
OpenAndConfSSDPReceiveSocket(int n_if_addr,
|
OpenAndConfSSDPReceiveSocket(int ipv6);
|
||||||
const char * * if_addr,
|
|
||||||
int ipv6);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add or Drop the multicast membership for SSDP on the interface
|
* Add or Drop the multicast membership for SSDP on the interface
|
||||||
* @param s the socket
|
* @param s the socket
|
||||||
* @param ifaddr the IPv4 address or interface name
|
* @param lan_addr the LAN address or interface name
|
||||||
* @param ipv6 IPv6 or IPv4
|
* @param ipv6 IPv6 or IPv4
|
||||||
* @param drop 0 to add, 1 to drop
|
* @param drop 0 to add, 1 to drop
|
||||||
* return -1 on error, 0 on success */
|
* return -1 on error, 0 on success */
|
||||||
int
|
int
|
||||||
AddDropMulticastMembership(int s, const char * ifaddr, int ipv6, int drop);
|
AddDropMulticastMembership(int s, struct lan_addr_s * lan_addr, int ipv6, int drop);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* $Id: upnputils.c,v 1.1 2013/09/07 06:45:39 nanard Exp $ */
|
/* $Id: upnputils.c,v 1.2 2014/11/28 16:20:58 nanard Exp $ */
|
||||||
/* MiniUPnP project
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
* (c) 2006-2013 Thomas Bernard
|
* (c) 2006-2014 Thomas Bernard
|
||||||
* This software is subject to the conditions detailed
|
* This software is subject to the conditions detailed
|
||||||
* in the LICENCE file provided within the distribution */
|
* in the LICENCE file provided within the distribution */
|
||||||
|
|
||||||
|
@ -21,6 +21,10 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "upnputils.h"
|
#include "upnputils.h"
|
||||||
|
#include "getroute.h"
|
||||||
|
#include "minissdpdtypes.h"
|
||||||
|
|
||||||
|
extern struct lan_addr_list lan_addrs;
|
||||||
|
|
||||||
int
|
int
|
||||||
sockaddr_to_string(const struct sockaddr * addr, char * str, size_t size)
|
sockaddr_to_string(const struct sockaddr * addr, char * str, size_t size)
|
||||||
|
@ -85,3 +89,84 @@ set_non_blocking(int fd)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* $Id: upnputils.h,v 1.1 2013/09/07 06:45:39 nanard Exp $ */
|
/* $Id: upnputils.h,v 1.2 2014/11/28 16:20:07 nanard Exp $ */
|
||||||
/* MiniUPnP project
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
* (c) 2011-2013 Thomas Bernard
|
* (c) 2011-2014 Thomas Bernard
|
||||||
* This software is subject to the conditions detailed
|
* This software is subject to the conditions detailed
|
||||||
* in the LICENCE file provided within the distribution */
|
* in the LICENCE file provided within the distribution */
|
||||||
|
|
||||||
|
@ -23,5 +23,11 @@ sockaddr_to_string(const struct sockaddr * addr, char * str, size_t size);
|
||||||
int
|
int
|
||||||
set_non_blocking(int fd);
|
set_non_blocking(int fd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the LAN which the peer belongs to
|
||||||
|
*/
|
||||||
|
struct lan_addr_s *
|
||||||
|
get_lan_for_peer(const struct sockaddr * peer);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue