diff --git a/miniupnpd/Changelog.txt b/miniupnpd/Changelog.txt index b7c048d..892ed1d 100644 --- a/miniupnpd/Changelog.txt +++ b/miniupnpd/Changelog.txt @@ -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 diff --git a/miniupnpd/Makefile.linux b/miniupnpd/Makefile.linux index a999763..d93eeb1 100644 --- a/miniupnpd/Makefile.linux +++ b/miniupnpd/Makefile.linux @@ -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 diff --git a/miniupnpd/getroute.h b/miniupnpd/getroute.h new file mode 100644 index 0000000..fcf77a4 --- /dev/null +++ b/miniupnpd/getroute.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 + diff --git a/miniupnpd/linux/getroute.c b/miniupnpd/linux/getroute.c new file mode 100644 index 0000000..e2ae399 --- /dev/null +++ b/miniupnpd/linux/getroute.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +/*#include */ +#include +#include +#include + +#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; +} + diff --git a/miniupnpd/minissdp.c b/miniupnpd/minissdp.c index f3dd4a2..0d57c52 100644 --- a/miniupnpd/minissdp.c +++ b/miniupnpd/minissdp.c @@ -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 #include #include + #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 */ diff --git a/miniupnpd/testgetroute.c b/miniupnpd/testgetroute.c new file mode 100644 index 0000000..bd81324 --- /dev/null +++ b/miniupnpd/testgetroute.c @@ -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 +#include +#include +#include +#include +#include +#include + +#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 \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; +} +