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:
Thomas Bernard 2012-06-24 01:41:47 +02:00
parent 635222fd02
commit 779a71bb6c
6 changed files with 314 additions and 11 deletions

View File

@ -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

View File

@ -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

16
miniupnpd/getroute.h Normal file
View File

@ -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

162
miniupnpd/linux/getroute.c Normal file
View File

@ -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;
}

View File

@ -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 */

78
miniupnpd/testgetroute.c Normal file
View File

@ -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;
}