miniupnpd: IPv6 address used for LOCATION:
in UPNP_STRICT mode, the literal IPv6 address in "location:" of SSDP messages is now the source address used to send the message. For linux only at the moment Also added testgetroute
This commit is contained in:
parent
635222fd02
commit
779a71bb6c
|
@ -1,4 +1,8 @@
|
|||
$Id: Changelog.txt,v 1.289 2012/06/08 18:16:30 nanard Exp $
|
||||
$Id: Changelog.txt,v 1.290 2012/06/23 23:34:41 nanard Exp $
|
||||
|
||||
2012/06/23:
|
||||
in UPNP_STRICT mode, the literal IPv6 address in "location:" of SSDP
|
||||
messages is the source address used to send the message
|
||||
|
||||
2012/06/08:
|
||||
Disable -ansi CFLAGS in Makefile.linux because recent iptables headers
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# $Id: Makefile.linux,v 1.72 2012/06/08 18:16:30 nanard Exp $
|
||||
# $Id: Makefile.linux,v 1.74 2012/06/23 23:33:57 nanard Exp $
|
||||
# MiniUPnP project
|
||||
# (c) 2006-2012 Thomas Bernard
|
||||
# http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
|
@ -47,7 +47,7 @@ BASEOBJS = miniupnpd.o upnphttp.o upnpdescgen.o upnpsoap.o \
|
|||
upnpevents.o upnputils.o getconnstatus.o \
|
||||
upnppinhole.o
|
||||
|
||||
LNXOBJS = linux/getifstats.o linux/ifacewatcher.o
|
||||
LNXOBJS = linux/getifstats.o linux/ifacewatcher.o linux/getroute.o
|
||||
NETFILTEROBJS = netfilter/iptcrdr.o netfilter/iptpinhole.o
|
||||
|
||||
ALLOBJS = $(BASEOBJS) $(LNXOBJS) $(NETFILTEROBJS)
|
||||
|
@ -114,10 +114,13 @@ endif # ($(TESTIP6TC), 1)
|
|||
endif # ($(TEST), 1)
|
||||
endif # ifdef IPTABLESPATH
|
||||
|
||||
LIBS += -lnfnetlink
|
||||
|
||||
TESTUPNPDESCGENOBJS = testupnpdescgen.o upnpdescgen.o
|
||||
|
||||
EXECUTABLES = miniupnpd testupnpdescgen testgetifstats \
|
||||
testupnppermissions miniupnpdctl testgetifaddr
|
||||
testupnppermissions miniupnpdctl testgetifaddr \
|
||||
testgetroute
|
||||
|
||||
.PHONY: all clean install depend genuuid
|
||||
|
||||
|
@ -128,6 +131,7 @@ clean:
|
|||
$(RM) $(EXECUTABLES)
|
||||
$(RM) testupnpdescgen.o testgetifstats.o
|
||||
$(RM) testupnppermissions.o testgetifaddr.o
|
||||
$(RM) testgetroute.o
|
||||
$(RM) miniupnpdctl.o
|
||||
|
||||
install: miniupnpd genuuid
|
||||
|
@ -162,6 +166,8 @@ testupnppermissions: testupnppermissions.o upnppermissions.o
|
|||
|
||||
testgetifaddr: testgetifaddr.o getifaddr.o
|
||||
|
||||
testgetroute: testgetroute.o linux/getroute.o upnputils.o -lnfnetlink
|
||||
|
||||
miniupnpdctl: miniupnpdctl.o
|
||||
|
||||
config.h: genconfig.sh VERSION
|
||||
|
@ -174,10 +180,11 @@ depend: config.h
|
|||
|
||||
# DO NOT DELETE
|
||||
|
||||
miniupnpd.o: config.h upnpglobalvars.h upnppermissions.h miniupnpdtypes.h
|
||||
miniupnpd.o: upnphttp.h upnpdescgen.h miniupnpdpath.h getifaddr.h upnpsoap.h
|
||||
miniupnpd.o: options.h minissdp.h upnpredirect.h upnppinhole.h daemonize.h
|
||||
miniupnpd.o: upnpevents.h natpmp.h commonrdr.h upnputils.h ifacewatcher.h
|
||||
miniupnpd.o: config.h macros.h upnpglobalvars.h upnppermissions.h
|
||||
miniupnpd.o: miniupnpdtypes.h upnphttp.h upnpdescgen.h miniupnpdpath.h
|
||||
miniupnpd.o: getifaddr.h upnpsoap.h options.h minissdp.h upnpredirect.h
|
||||
miniupnpd.o: upnppinhole.h daemonize.h upnpevents.h natpmp.h commonrdr.h
|
||||
miniupnpd.o: upnputils.h ifacewatcher.h
|
||||
upnphttp.o: config.h upnphttp.h upnpdescgen.h miniupnpdpath.h upnpsoap.h
|
||||
upnphttp.o: upnpevents.h upnputils.h
|
||||
upnpdescgen.o: config.h getifaddr.h upnpredirect.h upnpdescgen.h
|
||||
|
@ -201,9 +208,9 @@ options.o: miniupnpdtypes.h
|
|||
upnppermissions.o: config.h upnppermissions.h
|
||||
minissdp.o: config.h upnpdescstrings.h miniupnpdpath.h upnphttp.h
|
||||
minissdp.o: upnpglobalvars.h upnppermissions.h miniupnpdtypes.h minissdp.h
|
||||
minissdp.o: upnputils.h codelength.h
|
||||
minissdp.o: upnputils.h getroute.h codelength.h
|
||||
natpmp.o: macros.h config.h natpmp.h upnpglobalvars.h upnppermissions.h
|
||||
natpmp.o: miniupnpdtypes.h getifaddr.h upnpredirect.h commonrdr.h
|
||||
natpmp.o: miniupnpdtypes.h getifaddr.h upnpredirect.h commonrdr.h upnputils.h
|
||||
upnpevents.o: config.h upnpevents.h miniupnpdpath.h upnpglobalvars.h
|
||||
upnpevents.o: upnppermissions.h miniupnpdtypes.h upnpdescgen.h upnputils.h
|
||||
upnputils.o: config.h upnputils.h
|
||||
|
@ -215,6 +222,7 @@ linux/getifstats.o: config.h getifstats.h
|
|||
linux/ifacewatcher.o: config.h ifacewatcher.h config.h minissdp.h
|
||||
linux/ifacewatcher.o: miniupnpdtypes.h getifaddr.h upnpglobalvars.h
|
||||
linux/ifacewatcher.o: upnppermissions.h natpmp.h
|
||||
linux/getroute.o: getroute.h upnputils.h
|
||||
netfilter/iptcrdr.o: macros.h config.h netfilter/iptcrdr.h commonrdr.h
|
||||
netfilter/iptcrdr.o: config.h upnpglobalvars.h upnppermissions.h
|
||||
netfilter/iptcrdr.o: miniupnpdtypes.h
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
/* $Id: getroute.h,v 1.1 2012/06/23 22:59:07 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2012 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
|
||||
#ifndef __GETROUTE_H__
|
||||
#define __GETROUTE_H__
|
||||
|
||||
int
|
||||
get_src_for_route_to(const struct sockaddr * dst,
|
||||
void * src, size_t * src_len);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
/* $Id: getroute.c,v 1.2 2012/06/23 23:34:42 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2012 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>
|
||||
/*#include <linux/in_route.h>*/
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <libnfnetlink/libnfnetlink.h>
|
||||
|
||||
#include "../getroute.h"
|
||||
#include "../upnputils.h"
|
||||
|
||||
int
|
||||
get_src_for_route_to(const struct sockaddr * dst,
|
||||
void * src, size_t * src_len)
|
||||
{
|
||||
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);
|
||||
|
||||
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");
|
||||
return -1;
|
||||
}
|
||||
|
||||
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 < 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));
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
/* $Id: minissdp.c,v 1.36 2012/05/27 22:16:26 nanard Exp $ */
|
||||
/* $Id: minissdp.c,v 1.38 2012/06/23 23:34:41 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2012 Thomas Bernard
|
||||
|
@ -14,6 +14,7 @@
|
|||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "upnpdescstrings.h"
|
||||
#include "miniupnpdpath.h"
|
||||
|
@ -21,6 +22,7 @@
|
|||
#include "upnpglobalvars.h"
|
||||
#include "minissdp.h"
|
||||
#include "upnputils.h"
|
||||
#include "getroute.h"
|
||||
#include "codelength.h"
|
||||
|
||||
/* SSDP ip/port */
|
||||
|
@ -525,6 +527,9 @@ ProcessSSDPData(int s, const char *bufr, int n,
|
|||
int st_len = 0;
|
||||
char sender_str[64];
|
||||
const char * announced_host = NULL;
|
||||
#ifdef UPNP_STRICT
|
||||
char announced_host_buf[64];
|
||||
#endif
|
||||
|
||||
/* get the string representation of the sender address */
|
||||
sockaddr_to_string(sender, sender_str, sizeof(sender_str));
|
||||
|
@ -586,7 +591,37 @@ ProcessSSDPData(int s, const char *bufr, int n,
|
|||
else
|
||||
{
|
||||
/* IPv6 address with brackets */
|
||||
#ifdef UPNP_STRICT
|
||||
struct in6_addr addr6;
|
||||
size_t addr6_len = sizeof(addr6);
|
||||
/* retrieve the IPv6 address which
|
||||
* will be used locally to reach sender */
|
||||
memset(&addr6, 0, sizeof(addr6));
|
||||
if(get_src_for_route_to (sender, &addr6, &addr6_len) < 0) {
|
||||
syslog(LOG_WARNING, "get_src_for_route_to() failed, using %s", ipv6_addr_for_http_with_brackets);
|
||||
announced_host = ipv6_addr_for_http_with_brackets;
|
||||
} else {
|
||||
if(inet_ntop(AF_INET6, &addr6,
|
||||
announced_host_buf+1,
|
||||
sizeof(announced_host_buf) - 2)) {
|
||||
announced_host_buf[0] = '[';
|
||||
i = strlen(announced_host_buf);
|
||||
if(i < sizeof(announced_host_buf) - 1) {
|
||||
announced_host_buf[i] = ']';
|
||||
announced_host_buf[i+1] = '\0';
|
||||
} else {
|
||||
syslog(LOG_NOTICE, "cannot suffix %s with ']'",
|
||||
announced_host_buf);
|
||||
}
|
||||
announced_host = announced_host_buf;
|
||||
} else {
|
||||
syslog(LOG_NOTICE, "inet_ntop() failed %m");
|
||||
announced_host = ipv6_addr_for_http_with_brackets;
|
||||
}
|
||||
}
|
||||
#else
|
||||
announced_host = ipv6_addr_for_http_with_brackets;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
/* Responds to request with a device as ST header */
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
/* $Id: testgetroute.c,v 1.2 2012/06/23 23:32:32 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2012 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 <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "getroute.h"
|
||||
#include "upnputils.h"
|
||||
|
||||
#ifndef LOG_PERROR
|
||||
/* solaris does not define LOG_PERROR */
|
||||
#define LOG_PERROR 0
|
||||
#endif
|
||||
|
||||
int
|
||||
main(int argc, char ** argv)
|
||||
{
|
||||
struct sockaddr_in dst4;
|
||||
struct sockaddr_in6 dst6;
|
||||
struct sockaddr * dst;
|
||||
void * src;
|
||||
size_t src_len;
|
||||
int r;
|
||||
|
||||
memset(&dst4, 0, sizeof(dst4));
|
||||
memset(&dst6, 0, sizeof(dst6));
|
||||
dst = NULL;
|
||||
if(argc < 2) {
|
||||
fprintf(stderr, "usage: %s <ip address>\n", argv[0]);
|
||||
fprintf(stderr, "both v4 and v6 IP addresses are supported.\n");
|
||||
return 1;
|
||||
}
|
||||
openlog("testgetroute", LOG_CONS|LOG_PERROR, LOG_USER);
|
||||
r = inet_pton (AF_INET, argv[1], &dst4.sin_addr);
|
||||
if(r < 0) {
|
||||
syslog(LOG_ERR, "inet_pton(AF_INET, %s) : %m", argv[1]);
|
||||
return 2;
|
||||
}
|
||||
if (r == 0) {
|
||||
r = inet_pton (AF_INET6, argv[1], &dst6.sin6_addr);
|
||||
if(r < 0) {
|
||||
syslog(LOG_ERR, "inet_pton(AF_INET6, %s) : %m", argv[1]);
|
||||
return 2;
|
||||
}
|
||||
if(r > 0) {
|
||||
dst6.sin6_family = AF_INET6;
|
||||
dst = (struct sockaddr *)&dst6;
|
||||
src = &dst6.sin6_addr;
|
||||
src_len = sizeof(dst6.sin6_addr);
|
||||
}
|
||||
} else {
|
||||
dst4.sin_family = AF_INET;
|
||||
dst = (struct sockaddr *)&dst4;
|
||||
src = &dst4.sin_addr;
|
||||
src_len = sizeof(dst4.sin_addr);
|
||||
}
|
||||
|
||||
if (dst) {
|
||||
r = get_src_for_route_to (dst, src, &src_len);
|
||||
syslog(LOG_DEBUG, "get_src_for_route_to() returned %d", r);
|
||||
if(r >= 0) {
|
||||
char src_str[128];
|
||||
sockaddr_to_string(dst, src_str, sizeof(src_str));
|
||||
syslog(LOG_DEBUG, "src=%s", src_str);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue