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:
|
||||
revert "listen on only 1 IPv4 if only 1 interface is specified"
|
||||
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:
|
||||
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
|
||||
# author: Thomas Bernard
|
||||
# website: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
|
@ -11,7 +11,7 @@
|
|||
# make install (miniupnpd will be put in /usr/sbin)
|
||||
#
|
||||
# install target is made for linux... sorry BSD users...
|
||||
#CFLAGS = -g
|
||||
#CFLAGS = -g -O0
|
||||
CFLAGS ?= -Os
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -W -Wstrict-prototypes
|
||||
|
@ -23,9 +23,17 @@ RM = rm -f
|
|||
INSTALL = install
|
||||
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 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
|
||||
|
||||
ALLOBJS = $(MINISSDPDOBJS) $(TESTMINISSDPDOBJS) testcodelength.o
|
||||
|
@ -53,11 +61,6 @@ ifneq ($(OS), Darwin)
|
|||
endif
|
||||
|
||||
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)
|
||||
|
||||
|
@ -71,10 +74,12 @@ depend:
|
|||
|
||||
# DO NOT DELETE
|
||||
|
||||
minissdpd.o: config.h upnputils.h openssdpsocket.h daemonize.h codelength.h
|
||||
minissdpd.o: ifacewatch.h
|
||||
openssdpsocket.o: config.h openssdpsocket.h
|
||||
minissdpd.o: config.h getifaddr.h upnputils.h openssdpsocket.h
|
||||
minissdpd.o: minissdpdtypes.h daemonize.h codelength.h ifacewatch.h
|
||||
openssdpsocket.o: config.h openssdpsocket.h minissdpdtypes.h upnputils.h
|
||||
daemonize.o: daemonize.h config.h
|
||||
upnputils.o: config.h upnputils.h
|
||||
ifacewatch.o: config.h openssdpsocket.h
|
||||
upnputils.o: config.h upnputils.h getroute.h minissdpdtypes.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
|
||||
|
|
|
@ -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
|
||||
* (c) 2011-2012 Thomas Bernard
|
||||
* website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
|
@ -28,6 +28,9 @@
|
|||
|
||||
#include "openssdpsocket.h"
|
||||
#include "upnputils.h"
|
||||
#include "minissdpdtypes.h"
|
||||
|
||||
extern struct lan_addr_list lan_addrs;
|
||||
|
||||
#ifndef __linux__
|
||||
#if defined(__OpenBSD__) || defined(__FreeBSD__)
|
||||
|
@ -81,11 +84,10 @@ OpenAndConfInterfaceWatchSocket(void)
|
|||
* Process the message and add/drop multicast membership if needed
|
||||
*/
|
||||
int
|
||||
ProcessInterfaceWatch(int s, int s_ssdp, int s_ssdp6,
|
||||
int n_if_addr, const char * * if_addr)
|
||||
ProcessInterfaceWatch(int s, int s_ssdp, int s_ssdp6)
|
||||
{
|
||||
struct lan_addr_s * lan_addr;
|
||||
ssize_t len;
|
||||
int i;
|
||||
char buffer[4096];
|
||||
#ifdef __linux__
|
||||
struct iovec iov;
|
||||
|
@ -166,14 +168,14 @@ ProcessInterfaceWatch(int s, int s_ssdp, int s_ssdp6,
|
|||
syslog(LOG_INFO, "%s: %s/%d %s",
|
||||
is_del ? "RTM_DELADDR" : "RTM_NEWADDR",
|
||||
address, ifa->ifa_prefixlen, ifname);
|
||||
for(i = 0; i < n_if_addr; i++) {
|
||||
if((0 == strcmp(address, if_addr[i])) ||
|
||||
(0 == strcmp(ifname, if_addr[i])) ||
|
||||
(ifa->ifa_index == if_nametoindex(if_addr[i]))) {
|
||||
if(ifa->ifa_family == AF_INET && address[0] != '\0')
|
||||
AddDropMulticastMembership(s_ssdp, address, 0, is_del);
|
||||
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, if_addr[i], 1, is_del);
|
||||
AddDropMulticastMembership(s_ssdp6, lan_addr, 1, is_del);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -299,14 +301,14 @@ ProcessInterfaceWatch(int s, int s_ssdp, int s_ssdp6,
|
|||
syslog(LOG_INFO, "%s: %s/%d %s",
|
||||
is_del ? "RTM_DELADDR" : "RTM_NEWADDR",
|
||||
address, prefixlen, ifname);
|
||||
for(i = 0; i < n_if_addr; i++) {
|
||||
if(0 == strcmp(address, if_addr[i]) ||
|
||||
0 == strcmp(ifname, if_addr[i]) ||
|
||||
ifam->ifam_index == if_nametoindex(if_addr[i])) {
|
||||
if(family == AF_INET && address[0] != '\0')
|
||||
AddDropMulticastMembership(s_ssdp, address, 0, is_del);
|
||||
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, if_addr[i], 1, is_del);
|
||||
AddDropMulticastMembership(s_ssdp6, lan_addr, 1, is_del);
|
||||
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
|
||||
* 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
|
||||
* in the LICENCE file provided within the distribution */
|
||||
|
||||
|
@ -12,7 +12,6 @@ int
|
|||
OpenAndConfInterfaceWatchSocket(void);
|
||||
|
||||
int
|
||||
ProcessInterfaceWatch(int s, int s_ssdp, int s_ssdp6,
|
||||
int n_if_addr, const char * * if_addr);
|
||||
ProcessInterfaceWatch(int s, int s_ssdp, int s_ssdp6);
|
||||
|
||||
#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
|
||||
* (c) 2007-2014 Thomas Bernard
|
||||
* website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
|
@ -30,11 +30,13 @@
|
|||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
#include "getifaddr.h"
|
||||
#include "upnputils.h"
|
||||
#include "openssdpsocket.h"
|
||||
#include "daemonize.h"
|
||||
#include "codelength.h"
|
||||
#include "ifacewatch.h"
|
||||
#include "minissdpdtypes.h"
|
||||
|
||||
/* current request management stucture */
|
||||
struct reqelem {
|
||||
|
@ -42,7 +44,7 @@ struct reqelem {
|
|||
LIST_ENTRY(reqelem) entries;
|
||||
};
|
||||
|
||||
/* divice data structures */
|
||||
/* device data structures */
|
||||
struct header {
|
||||
const char * p; /* string pointer */
|
||||
int l; /* string length */
|
||||
|
@ -70,6 +72,95 @@ struct device * devlist = 0;
|
|||
unsigned int upnp_bootid = 1;
|
||||
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 *
|
||||
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),
|
||||
ntohs(((const struct sockaddr_in *)addr)->sin_port),
|
||||
st_len, st);
|
||||
#endif
|
||||
/* TODO : ignore packet if not coming from a LAN */
|
||||
#endif /* ENABLE_IPV6 */
|
||||
if(st_len==8 && (0==memcmp(st, "ssdp:all", 8))) {
|
||||
/* send a response for all services */
|
||||
for(serv = servicelisthead.lh_first;
|
||||
|
@ -343,6 +433,16 @@ ParseSSDPPacket(int s, const char * p, ssize_t n,
|
|||
const char * st = NULL;
|
||||
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));
|
||||
for(methodlen = 0;
|
||||
methodlen < n && (isalpha(p[methodlen]) || p[methodlen]=='-');
|
||||
|
@ -870,8 +970,7 @@ int main(int argc, char * * argv)
|
|||
struct reqelem * req;
|
||||
struct reqelem * reqnext;
|
||||
fd_set readfds;
|
||||
const char * if_addr[MAX_IF_ADDR];
|
||||
int n_if_addr = 0;
|
||||
struct lan_addr_s * lan_addr;
|
||||
int i;
|
||||
const char * sockpath = "/var/run/minissdpd.sock";
|
||||
const char * pidfilename = "/var/run/minissdpd.pid";
|
||||
|
@ -889,15 +988,22 @@ int main(int argc, char * * argv)
|
|||
|
||||
LIST_INIT(&reqlisthead);
|
||||
LIST_INIT(&servicelisthead);
|
||||
LIST_INIT(&lan_addrs);
|
||||
/* process command line */
|
||||
for(i=1; i<argc; i++)
|
||||
{
|
||||
if(0==strcmp(argv[i], "-i")) {
|
||||
if(n_if_addr < MAX_IF_ADDR)
|
||||
if_addr[n_if_addr++] = argv[++i];
|
||||
else
|
||||
syslog(LOG_WARNING, "Max number of interface address set to %d, "
|
||||
"ignoring %s", MAX_IF_ADDR, argv[++i]);
|
||||
lan_addr = malloc(sizeof(struct lan_addr_s));
|
||||
if(lan_addr == NULL) {
|
||||
fprintf(stderr, "malloc(%d) FAILED\n", (int)sizeof(struct lan_addr_s));
|
||||
break;
|
||||
}
|
||||
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"))
|
||||
debug_flag = 1;
|
||||
else if(0==strcmp(argv[i], "-s"))
|
||||
|
@ -909,7 +1015,7 @@ int main(int argc, char * * argv)
|
|||
ipv6 = 1;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
}
|
||||
if(n_if_addr < 1)
|
||||
if(lan_addrs.lh_first == NULL)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: %s [-d] "
|
||||
|
@ -920,7 +1026,8 @@ int main(int argc, char * * argv)
|
|||
"-i <interface> [-i <interface2>] ...\n",
|
||||
argv[0]);
|
||||
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,
|
||||
"\n By default, socket will be open as %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 */
|
||||
s_ifacewatch = OpenAndConfInterfaceWatchSocket();
|
||||
/* 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)
|
||||
{
|
||||
syslog(LOG_ERR, "Cannot open socket for receiving SSDP messages, exiting");
|
||||
|
@ -968,7 +1075,7 @@ int main(int argc, char * * argv)
|
|||
}
|
||||
#ifdef ENABLE_IPV6
|
||||
if(ipv6) {
|
||||
s_ssdp6 = OpenAndConfSSDPReceiveSocket(n_if_addr, if_addr, 1);
|
||||
s_ssdp6 = OpenAndConfSSDPReceiveSocket(1);
|
||||
if(s_ssdp6 < 0)
|
||||
{
|
||||
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 */
|
||||
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 */
|
||||
quit:
|
||||
|
@ -1209,6 +1317,18 @@ quit:
|
|||
close(s_ifacewatch);
|
||||
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)
|
||||
syslog(LOG_ERR, "unlink(%s): %m", pidfilename);
|
||||
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
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2014 Thomas Bernard
|
||||
|
@ -18,6 +18,9 @@
|
|||
|
||||
#include "openssdpsocket.h"
|
||||
#include "upnputils.h"
|
||||
#include "minissdpdtypes.h"
|
||||
|
||||
extern struct lan_addr_list lan_addrs;
|
||||
|
||||
/* SSDP ip/port */
|
||||
#define SSDP_PORT (1900)
|
||||
|
@ -26,44 +29,6 @@
|
|||
#define LL_SSDP_MCAST_ADDR ("FF02::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
|
||||
* @param s the socket
|
||||
|
@ -71,12 +36,11 @@ GetIfAddrIPv4(const char * ifaddr)
|
|||
* @param ipv6 IPv6 or IPv4
|
||||
* return -1 on error, 0 on success */
|
||||
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 */
|
||||
#ifdef ENABLE_IPV6
|
||||
struct ipv6_mreq mr;
|
||||
unsigned int ifindex;
|
||||
#else /* ENABLE_IPV6 */
|
||||
(void)ipv6;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
|
@ -86,17 +50,16 @@ AddDropMulticastMembership(int s, const char * ifaddr, int ipv6, int drop)
|
|||
#ifdef ENABLE_IPV6
|
||||
if(ipv6)
|
||||
{
|
||||
ifindex = if_nametoindex(ifaddr);
|
||||
memset(&mr, 0, sizeof(mr));
|
||||
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,
|
||||
&mr, sizeof(struct ipv6_mreq)) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "setsockopt(udp, %s)(%s, %s): %m",
|
||||
drop ? "IPV6_LEAVE_GROUP" : "IPV6_JOIN_GROUP",
|
||||
LL_SSDP_MCAST_ADDR,
|
||||
ifaddr);
|
||||
lan_addr->ifname);
|
||||
return -1;
|
||||
}
|
||||
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",
|
||||
drop ? "IPV6_LEAVE_GROUP" : "IPV6_JOIN_GROUP",
|
||||
SL_SSDP_MCAST_ADDR,
|
||||
ifaddr);
|
||||
lan_addr->ifname);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -115,11 +78,11 @@ AddDropMulticastMembership(int s, const char * ifaddr, int ipv6, int drop)
|
|||
#endif /* ENABLE_IPV6 */
|
||||
/* setting up imr structure */
|
||||
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)
|
||||
{
|
||||
syslog(LOG_ERR, "no IPv4 address for interface %s",
|
||||
ifaddr);
|
||||
lan_addr->ifname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -128,7 +91,7 @@ AddDropMulticastMembership(int s, const char * ifaddr, int ipv6, int drop)
|
|||
{
|
||||
syslog(LOG_ERR, "setsockopt(udp, %s)(%s): %m",
|
||||
drop ? "IP_DROP_MEMBERSHIP" : "IP_ADD_MEMBERSHIP",
|
||||
ifaddr);
|
||||
lan_addr->ifname);
|
||||
return -1;
|
||||
}
|
||||
#ifdef ENABLE_IPV6
|
||||
|
@ -139,9 +102,7 @@ AddDropMulticastMembership(int s, const char * ifaddr, int ipv6, int drop)
|
|||
}
|
||||
|
||||
int
|
||||
OpenAndConfSSDPReceiveSocket(int n_listen_addr,
|
||||
const char * * listen_addr,
|
||||
int ipv6)
|
||||
OpenAndConfSSDPReceiveSocket(int ipv6)
|
||||
{
|
||||
int s;
|
||||
int opt = 1;
|
||||
|
@ -151,6 +112,7 @@ OpenAndConfSSDPReceiveSocket(int n_listen_addr,
|
|||
struct sockaddr_in sockname;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
socklen_t sockname_len;
|
||||
struct lan_addr_s * lan_addr;
|
||||
|
||||
#ifndef ENABLE_IPV6
|
||||
if(ipv6) {
|
||||
|
@ -246,14 +208,13 @@ OpenAndConfSSDPReceiveSocket(int n_listen_addr,
|
|||
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, listen_addr[n_listen_addr], ipv6, 0) < 0)
|
||||
if(AddDropMulticastMembership(s, lan_addr, ipv6, 0) < 0)
|
||||
{
|
||||
syslog(LOG_WARNING, "Failed to add IPv%d multicast membership for interface %s.",
|
||||
ipv6 ? 6 : 4,
|
||||
listen_addr[n_listen_addr] );
|
||||
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
|
||||
* 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
|
||||
* in the LICENCE file provided within the distribution */
|
||||
#ifndef OPENSSDPSOCKET_H_INCLUDED
|
||||
#define OPENSSDPSOCKET_H_INCLUDED
|
||||
|
||||
#include "minissdpdtypes.h"
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @return socket
|
||||
*/
|
||||
int
|
||||
OpenAndConfSSDPReceiveSocket(int n_if_addr,
|
||||
const char * * if_addr,
|
||||
int ipv6);
|
||||
OpenAndConfSSDPReceiveSocket(int ipv6);
|
||||
|
||||
/**
|
||||
* Add or Drop the multicast membership for SSDP on the interface
|
||||
* @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 drop 0 to add, 1 to drop
|
||||
* return -1 on error, 0 on success */
|
||||
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
|
||||
|
||||
|
|
|
@ -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
|
||||
* 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
|
||||
* in the LICENCE file provided within the distribution */
|
||||
|
||||
|
@ -21,6 +21,10 @@
|
|||
#endif
|
||||
|
||||
#include "upnputils.h"
|
||||
#include "getroute.h"
|
||||
#include "minissdpdtypes.h"
|
||||
|
||||
extern struct lan_addr_list lan_addrs;
|
||||
|
||||
int
|
||||
sockaddr_to_string(const struct sockaddr * addr, char * str, size_t size)
|
||||
|
@ -85,3 +89,84 @@ set_non_blocking(int fd)
|
|||
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
|
||||
* 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
|
||||
* 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
|
||||
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
|
||||
|
||||
|
|
Loading…
Reference in New Issue