Merge branch 'master' into randomize_url

This commit is contained in:
Thomas Bernard 2017-05-26 17:30:18 +02:00
commit 11fcf5a008
18 changed files with 456 additions and 198 deletions

2
README
View File

@ -11,7 +11,7 @@ miniupnpc/ : MiniUPnP client - an UPnP IGD control point
miniupnpd/ : MiniUPnP daemon - an implementation of a UPnP IGD miniupnpd/ : MiniUPnP daemon - an implementation of a UPnP IGD
+ NAT-PMP / PCP gateway + NAT-PMP / PCP gateway
minissdpd/ : SSDP managing daemon. Designed to work with miniupnpc, minissdpd/ : SSDP managing daemon. Designed to work with miniupnpc,
miniupnpd, minidlna, etc. miniupnpd, ReadyMedia (formerly MiniDLNA), etc.
miniupnpc-async/ : Proof of concept for a UPnP IGD control point using miniupnpc-async/ : Proof of concept for a UPnP IGD control point using
asynchronous (non blocking) sockets. asynchronous (non blocking) sockets.
miniupnpc-libevent/ : UPnP IGD control point using libevent2 miniupnpc-libevent/ : UPnP IGD control point using libevent2

View File

@ -1,10 +1,10 @@
#!/bin/sh #!/bin/sh
# $Id: testminissdpd.sh,v 1.2 2015/09/03 18:31:25 nanard Exp $ # $Id: testminissdpd.sh,v 1.8 2017/04/21 11:57:59 nanard Exp $
# (c) 2016 Thomas Bernard # (c) 2017 Thomas Bernard
OS=`uname -s` OS=`uname -s`
IF=lo IF=lo
if [ "$OS" = "Darwin" ] || [ "$OS" = "SunOS" ] ; then if [ "$OS" = "Darwin" ] || [ "$OS" = "OpenBSD" ] || [ "$OS" = "SunOS" ] || [ "$OS" = "FreeBSD" ] ; then
IF=lo0 IF=lo0
fi fi
# if set, 1st argument is network interface # if set, 1st argument is network interface

View File

@ -5,7 +5,7 @@ Pod::Spec.new do |spec|
spec.authors = "The MiniUPnP Authors" spec.authors = "The MiniUPnP Authors"
spec.license = { type: "BSD", file: "miniupnpc/LICENSE" } spec.license = { type: "BSD", file: "miniupnpc/LICENSE" }
spec.version = "2.0.0.0" spec.version = "2.0.0.2"
spec.source = { spec.source = {
git: 'https://github.com/cpp-ethereum-ios/miniupnp.git', git: 'https://github.com/cpp-ethereum-ios/miniupnp.git',
tag: "v#{spec.version}" tag: "v#{spec.version}"
@ -36,12 +36,13 @@ Pod::Spec.new do |spec|
CC=`xcrun -sdk $PLATFORM -find cc` \ CC=`xcrun -sdk $PLATFORM -find cc` \
CFLAGS="-arch $ARCH -isysroot $SDKPATH" \ CFLAGS="-arch $ARCH -isysroot $SDKPATH" \
LIBTOOL=`xcrun -sdk $PLATFORM -find libtool` \ LIBTOOL=`xcrun -sdk $PLATFORM -find libtool` \
LDFLAGS="-arch $ARCH" LDFLAGS="-arch $ARCH -headerpad_max_install_names"
} }
create_universal_library() { create_universal_library() {
lipo -create -output build-ios/libminiupnpc.dylib \ lipo -create -output libminiupnpc.dylib \
build-ios/{armv7,arm64,i386,x86_64}/usr/lib/libminiupnpc.dylib build-ios/{armv7,arm64,i386,x86_64}/usr/lib/libminiupnpc.dylib
install_name_tool -id "@rpath/libminiupnpc.dylib" libminiupnpc.dylib
} }
cd miniupnpc cd miniupnpc
@ -49,5 +50,5 @@ Pod::Spec.new do |spec|
CMD CMD
spec.source_files = "miniupnpc/build-ios/armv7/usr/include/**/*.h" spec.source_files = "miniupnpc/build-ios/armv7/usr/include/**/*.h"
spec.ios.vendored_libraries = "miniupnpc/build-ios/libminiupnpc.dylib" spec.ios.vendored_libraries = "miniupnpc/libminiupnpc.dylib"
end end

View File

@ -1,13 +1,15 @@
# $Id: Makefile,v 1.9 2014/11/04 22:25:00 nanard Exp $ # $Id: Makefile,v 1.12 2017/05/26 11:01:37 nanard Exp $
# MiniUPnP Project # MiniUPnP Project
# http://miniupnp.free.fr/ # http://miniupnp.free.fr/
# (c) 2005-2014 Thomas Bernard # (c) 2005-2017 Thomas Bernard
# to install use : # to install use :
# $ PREFIX=/tmp/dummylocation make install # $ PREFIX=/tmp/dummylocation make install
# or # or
# $ INSTALLPREFIX=/usr/local make install # $ INSTALLPREFIX=/usr/local make install
# or # or
# make install (will go to /usr/bin, /usr/lib, etc...) # make install (will go to /usr/bin, /usr/lib, etc...)
OS = $(shell uname -s)
CC ?= gcc CC ?= gcc
#AR = gar #AR = gar
CFLAGS = -O0 -g -DDEBUG CFLAGS = -O0 -g -DDEBUG
@ -16,10 +18,15 @@ CFLAGS += -fPIC
CFLAGS += -ansi CFLAGS += -ansi
CFLAGS += -Wall -W CFLAGS += -Wall -W
CFLAGS += -D_BSD_SOURCE CFLAGS += -D_BSD_SOURCE
ifneq ($(OS), FreeBSD)
ifneq ($(OS), Darwin)
#CFLAGS += -D_POSIX_C_SOURCE=200112L
CFLAGS += -D_XOPEN_SOURCE=600
endif
endif
CFLAGS += -DUPNPC_USE_SELECT CFLAGS += -DUPNPC_USE_SELECT
INSTALL = install INSTALL = install
OS = $(shell uname -s)
#following libs are needed on Solaris #following libs are needed on Solaris
ifeq ($(OS), SunOS) ifeq ($(OS), SunOS)
LDLIBS += -lsocket -lnsl -lresolv LDLIBS += -lsocket -lnsl -lresolv

View File

@ -1,6 +1,6 @@
/* $Id: miniupnpc-async.c,v 1.19 2014/11/07 12:05:40 nanard Exp $ */ /* $Id: miniupnpc-async.c,v 1.19 2014/11/07 12:05:40 nanard Exp $ */
/* miniupnpc-async /* miniupnpc-async
* Copyright (c) 2008-2014, Thomas BERNARD <miniupnp@free.fr> * Copyright (c) 2008-2017, Thomas BERNARD <miniupnp@free.fr>
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
@ -72,8 +72,8 @@ struct upnp_args {
/* private functions */ /* private functions */
static int upnpc_connect(upnpc_t * p, const char * url); static int upnpc_connect(upnpc_device_t * p, const char * url);
static int upnpc_send_request(upnpc_t * p); static int upnpc_send_request(upnpc_device_t * p);
/* parse_msearch_reply() /* parse_msearch_reply()
@ -83,8 +83,8 @@ static int upnpc_send_request(upnpc_t * p);
* The strings are NOT null terminated */ * The strings are NOT null terminated */
static void static void
parse_msearch_reply(const char * reply, int size, parse_msearch_reply(const char * reply, int size,
const char * * location, int * locationsize, const char * * location, unsigned int * locationsize,
const char * * st, int * stsize) const char * * st, unsigned int * stsize)
{ {
int a, b, i; int a, b, i;
i = 0; /* current character index */ i = 0; /* current character index */
@ -147,26 +147,26 @@ static int upnpc_send_ssdp_msearch(upnpc_t * p, const char * device, unsigned in
int err = SOCKET_ERROR; int err = SOCKET_ERROR;
if(err == EINTR || WOULDBLOCK(err)) { if(err == EINTR || WOULDBLOCK(err)) {
debug_printf("upnpc_send_ssdp_msearch: should try again"); debug_printf("upnpc_send_ssdp_msearch: should try again");
p->state = ESendSSDP; p->state = EUPnPSendSSDP;
return 0; return 0;
} }
PRINT_SOCKET_ERROR("sendto"); PRINT_SOCKET_ERROR("sendto");
return -1; return -1;
} }
p->state = EReceiveSSDP; p->state = EUPnPReceiveSSDP;
return 0; return 0;
} }
static int upnpc_set_root_desc_location(upnpc_t * p, const char * location, int locationsize) static int upnpc_set_root_desc_location(upnpc_device_t * d, const char * location, int locationsize)
{ {
char * tmp; char * tmp;
tmp = realloc(p->root_desc_location, locationsize + 1); tmp = realloc(d->root_desc_location, locationsize + 1);
if(tmp == 0) { if(tmp == 0) {
return -1; return -1;
} }
memcpy(tmp, location, locationsize); memcpy(tmp, location, locationsize);
tmp[locationsize] = '\0'; tmp[locationsize] = '\0';
p->root_desc_location = tmp; d->root_desc_location = tmp;
return 0; return 0;
} }
@ -181,23 +181,41 @@ static int upnpc_receive_and_parse_ssdp(upnpc_t * p)
debug_printf("empty packet received\n"); debug_printf("empty packet received\n");
} else { } else {
const char * location = NULL; const char * location = NULL;
int locationsize; unsigned int locationsize;
const char * st = NULL; const char * st = NULL;
int stsize; unsigned int stsize;
debug_printf("%.*s", n, bufr); debug_printf("%.*s", n, bufr);
parse_msearch_reply(bufr, n, &location, &locationsize, &st, &stsize); parse_msearch_reply(bufr, n, &location, &locationsize, &st, &stsize);
debug_printf("location = '%.*s'\n", locationsize, location); debug_printf("location = '%.*s'\n", locationsize, location);
debug_printf("st = '%.*s'\n", stsize, st); debug_printf("st = '%.*s'\n", stsize, st);
if(location != NULL) { if(location != NULL) {
if(upnpc_set_root_desc_location(p, location, locationsize) < 0) { upnpc_device_t * dev = p->device_list;
p->state = EError; while(dev != NULL) {
if(dev->root_desc_location != NULL
&& strlen(dev->root_desc_location) == locationsize
&& memcmp(dev->root_desc_location, location, locationsize) == 0) {
debug_printf("device already in list (location='%s')\n", dev->root_desc_location);
return -1; return -1;
} }
p->state = EGetDescConnect; dev = dev->next;
upnpc_connect(p, p->root_desc_location); }
dev = calloc(1, sizeof(upnpc_device_t));
if(dev == NULL) {
p->state = EUPnPError;
return -1;
}
if(upnpc_set_root_desc_location(dev, location, locationsize) < 0) {
free(dev);
p->state = EUPnPError;
return -1;
}
dev->next = p->device_list;
p->device_list = dev;
dev->state = EDevGetDescConnect;
upnpc_connect(dev, dev->root_desc_location);
} else { } else {
/* or do nothing ? */ /* or do nothing ? */
p->state = EError; p->state = EUPnPError;
} }
} }
return 0; return 0;
@ -298,7 +316,7 @@ parseURL(const char * url,
return 1; return 1;
} }
static int upnpc_connect(upnpc_t * p, const char * url) static int upnpc_connect(upnpc_device_t * p, const char * url)
{ {
int r; int r;
char hostname[MAXHOSTNAMELEN+1]; char hostname[MAXHOSTNAMELEN+1];
@ -308,19 +326,19 @@ static int upnpc_connect(upnpc_t * p, const char * url)
struct sockaddr_in addr; struct sockaddr_in addr;
socklen_t addrlen; socklen_t addrlen;
if(p->root_desc_location == 0) { /*if(p->root_desc_location == 0) {
p->state = EError; p->state = EError;
return -1; return -1;
} }*/
if(!parseURL(url/*p->root_desc_location*/, hostname, &port, if(!parseURL(url/*p->root_desc_location*/, hostname, &port,
&path, &scope_id)) { &path, &scope_id)) {
p->state = EError; p->state = EDevError;
return -1; return -1;
} }
p->http_socket = socket(PF_INET, SOCK_STREAM, 0); p->http_socket = socket(PF_INET, SOCK_STREAM, 0);
if(p->http_socket < 0) { if(p->http_socket < 0) {
PRINT_SOCKET_ERROR("socket"); PRINT_SOCKET_ERROR("socket");
p->state = EError; p->state = EDevError;
return -1; return -1;
} }
if(!set_non_blocking(p->http_socket)) { if(!set_non_blocking(p->http_socket)) {
@ -339,44 +357,44 @@ static int upnpc_connect(upnpc_t * p, const char * url)
return 0; return 0;
} else if(errno != EINTR) { } else if(errno != EINTR) {
PRINT_SOCKET_ERROR("connect"); PRINT_SOCKET_ERROR("connect");
p->state = EError; p->state = EDevError;
return -1; return -1;
} }
} }
} while(r < 0 && errno == EINTR); } while(r < 0 && errno == EINTR);
if(p->state == EGetDescConnect) { if(p->state == EDevGetDescConnect) {
p->state = EGetDescRequest; p->state = EDevGetDescRequest;
} else { } else {
p->state = ESoapRequest; p->state = EDevSoapRequest;
} }
upnpc_send_request(p); upnpc_send_request(p);
return 0; return 0;
} }
static int upnpc_complete_connect(upnpc_t * p) static int upnpc_complete_connect(upnpc_device_t * p)
{ {
socklen_t len; socklen_t len;
int err; int err;
len = sizeof(err); len = sizeof(err);
if(getsockopt(p->http_socket, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { if(getsockopt(p->http_socket, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
PRINT_SOCKET_ERROR("getsockopt"); PRINT_SOCKET_ERROR("getsockopt");
p->state = EError; p->state = EDevError;
return -1; return -1;
} }
if(err != 0) { if(err != 0) {
debug_printf("connect failed %d\n", err); debug_printf("connect failed %d\n", err);
p->state = EError; p->state = EDevError;
return -1; return -1;
} }
if(p->state == EGetDescConnect) if(p->state == EDevGetDescConnect)
p->state = EGetDescRequest; p->state = EDevGetDescRequest;
else else
p->state = ESoapRequest; p->state = EDevSoapRequest;
upnpc_send_request(p); upnpc_send_request(p);
return 0; return 0;
} }
static int upnpc_send_request(upnpc_t * p) static int upnpc_send_request(upnpc_device_t * p)
{ {
ssize_t n; ssize_t n;
static const char reqfmt[] = "GET %s HTTP/1.1\r\n" static const char reqfmt[] = "GET %s HTTP/1.1\r\n"
@ -384,6 +402,13 @@ static int upnpc_send_request(upnpc_t * p)
"Connection: Close\r\n" "Connection: Close\r\n"
"User-Agent: MiniUPnPc-async\r\n" "User-Agent: MiniUPnPc-async\r\n"
"\r\n"; "\r\n";
/* retrieve "our" IP address used to connect to the UPnP device */
p->selfaddrlen = sizeof(struct sockaddr_storage);
if(getsockname(p->http_socket, (struct sockaddr *)&p->selfaddr, &p->selfaddrlen) < 0) {
PRINT_SOCKET_ERROR("getsockname()");
}
if(p->http_request == NULL) { if(p->http_request == NULL) {
char hostname[MAXHOSTNAMELEN+1]; char hostname[MAXHOSTNAMELEN+1];
unsigned short port; unsigned short port;
@ -392,13 +417,13 @@ static int upnpc_send_request(upnpc_t * p)
int len; int len;
if(!parseURL(p->root_desc_location, hostname, &port, if(!parseURL(p->root_desc_location, hostname, &port,
&path, &scope_id)) { &path, &scope_id)) {
p->state = EError; p->state = EDevError;
return -1; return -1;
} }
len = snprintf(NULL, 0, reqfmt, path, hostname, port); len = snprintf(NULL, 0, reqfmt, path, hostname, port);
p->http_request = malloc(len + 1); p->http_request = malloc(len + 1);
if(p->http_request == NULL) { if(p->http_request == NULL) {
p->state = EError; p->state = EDevError;
return -1; return -1;
} }
p->http_request_len = snprintf(p->http_request, len + 1, p->http_request_len = snprintf(p->http_request, len + 1,
@ -409,7 +434,7 @@ static int upnpc_send_request(upnpc_t * p)
p->http_request_len - p->http_request_sent, 0/* flags */); p->http_request_len - p->http_request_sent, 0/* flags */);
if(n < 0) { if(n < 0) {
PRINT_SOCKET_ERROR("send"); PRINT_SOCKET_ERROR("send");
p->state = EError; p->state = EDevError;
return -1; return -1;
} else { } else {
debug_printf("sent %d bytes\n", (int)n); debug_printf("sent %d bytes\n", (int)n);
@ -426,10 +451,10 @@ static int upnpc_send_request(upnpc_t * p)
free(p->http_request); free(p->http_request);
p->http_request = NULL; p->http_request = NULL;
p->http_request_len = 0; p->http_request_len = 0;
if(p->state == EGetDescRequest) if(p->state == EDevGetDescRequest)
p->state = EGetDescResponse; p->state = EDevGetDescResponse;
else else
p->state = ESoapResponse; p->state = EDevSoapResponse;
free(p->http_response); free(p->http_response);
p->http_response = NULL; p->http_response = NULL;
p->http_response_received = 0; p->http_response_received = 0;
@ -440,7 +465,7 @@ static int upnpc_send_request(upnpc_t * p)
return 0; return 0;
} }
static int upnpc_parse_headers(upnpc_t * p) static int upnpc_parse_headers(upnpc_device_t * p)
{ {
/* search for CR LF CR LF (end of headers) /* search for CR LF CR LF (end of headers)
* recognize also LF LF */ * recognize also LF LF */
@ -547,7 +572,7 @@ static char * build_url_string(const char * urlbase, const char * root_desc_url,
return s; return s;
} }
static int upnpc_get_response(upnpc_t * p) static int upnpc_get_response(upnpc_device_t * p)
{ {
ssize_t n; ssize_t n;
ssize_t count; ssize_t count;
@ -566,7 +591,7 @@ static int upnpc_get_response(upnpc_t * p)
if(errno == EINTR || WOULDBLOCK(errno)) if(errno == EINTR || WOULDBLOCK(errno))
return 0; /* try again later */ return 0; /* try again later */
PRINT_SOCKET_ERROR("read"); PRINT_SOCKET_ERROR("read");
p->state = EError; p->state = EDevError;
return -1; return -1;
} else if(n == 0) { } else if(n == 0) {
/* receiving finished */ /* receiving finished */
@ -579,7 +604,7 @@ static int upnpc_get_response(upnpc_t * p)
} }
/* TODO : decode chunked transfer-encoding */ /* TODO : decode chunked transfer-encoding */
/* parse xml */ /* parse xml */
if(p->state == EGetDescResponse) { if(p->state == EDevGetDescResponse) {
struct IGDdatas igd; struct IGDdatas igd;
struct xmlparser parser; struct xmlparser parser;
memset(&igd, 0, sizeof(struct IGDdatas)); memset(&igd, 0, sizeof(struct IGDdatas));
@ -608,7 +633,7 @@ static int upnpc_get_response(upnpc_t * p)
p->http_response = NULL; p->http_response = NULL;
p->http_response_received = 0; p->http_response_received = 0;
p->http_response_end_of_headers = 0; p->http_response_end_of_headers = 0;
p->state = EReady; p->state = EDevReady;
} else { } else {
/* receiving in progress */ /* receiving in progress */
debug_printf("received %d bytes:\n%.*s\n", (int)n, (int)n, buffer); debug_printf("received %d bytes:\n%.*s\n", (int)n, (int)n, buffer);
@ -616,7 +641,7 @@ static int upnpc_get_response(upnpc_t * p)
p->http_response = malloc(n); p->http_response = malloc(n);
if(p->http_response == NULL) { if(p->http_response == NULL) {
debug_printf("failed to malloc %d bytes\n", (int)n); debug_printf("failed to malloc %d bytes\n", (int)n);
p->state = EError; p->state = EDevError;
return -1; return -1;
} }
p->http_response_received = n; p->http_response_received = n;
@ -625,7 +650,7 @@ static int upnpc_get_response(upnpc_t * p)
char * tmp = realloc(p->http_response, p->http_response_received + n); char * tmp = realloc(p->http_response, p->http_response_received + n);
if(tmp == NULL) { if(tmp == NULL) {
debug_printf("failed to realloc %d bytes\n", (int)(p->http_response_received + n)); debug_printf("failed to realloc %d bytes\n", (int)(p->http_response_received + n));
p->state = EError; p->state = EDevError;
return -1; return -1;
} }
p->http_response = tmp; p->http_response = tmp;
@ -643,7 +668,7 @@ static int upnpc_get_response(upnpc_t * p)
#define SERVICEPREFIX "u" #define SERVICEPREFIX "u"
#define SERVICEPREFIX2 'u' #define SERVICEPREFIX2 'u'
static int upnpc_build_soap_request(upnpc_t * p, const char * url, static int upnpc_build_soap_request(upnpc_device_t * p, const char * url,
const char * service, const char * service,
const char * action, const char * action,
const struct upnp_args * args, int arg_count) const struct upnp_args * args, int arg_count)
@ -689,7 +714,7 @@ static int upnpc_build_soap_request(upnpc_t * p, const char * url,
} }
args_xml = malloc(++l); args_xml = malloc(++l);
if(args_xml == NULL) { if(args_xml == NULL) {
p->state = EError; p->state = EDevError;
return -1; return -1;
} }
for(i = 0, n = 0; i < arg_count && n < l; i++) { for(i = 0, n = 0; i < arg_count && n < l; i++) {
@ -702,7 +727,7 @@ static int upnpc_build_soap_request(upnpc_t * p, const char * url,
body_len = snprintf(NULL, 0, fmt_soap, action, service, args_xml?args_xml:"", action); body_len = snprintf(NULL, 0, fmt_soap, action, service, args_xml?args_xml:"", action);
body = malloc(body_len + 1); body = malloc(body_len + 1);
if(body == NULL) { if(body == NULL) {
p->state = EError; p->state = EDevError;
free(args_xml); free(args_xml);
return -1; return -1;
} }
@ -712,7 +737,7 @@ static int upnpc_build_soap_request(upnpc_t * p, const char * url,
free(args_xml); free(args_xml);
args_xml = NULL; args_xml = NULL;
if(!parseURL(url, hostname, &port, &path, &scope_id)) { if(!parseURL(url, hostname, &port, &path, &scope_id)) {
p->state = EError; p->state = EDevError;
free(body); free(body);
return -1; return -1;
} }
@ -741,7 +766,7 @@ int upnpc_init(upnpc_t * p, const char * multicastif)
struct sockaddr_in addr; struct sockaddr_in addr;
if(!p) if(!p)
return UPNPC_ERR_INVALID_ARGS; return UPNPC_ERR_INVALID_ARGS;
p->state = EError; p->state = EUPnPError;
memset(p, 0, sizeof(upnpc_t)); /* clean everything */ memset(p, 0, sizeof(upnpc_t)); /* clean everything */
/* open the socket for SSDP */ /* open the socket for SSDP */
p->ssdp_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); p->ssdp_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
@ -782,57 +807,62 @@ int upnpc_init(upnpc_t * p, const char * multicastif)
return UPNPC_ERR_BIND_FAILED; return UPNPC_ERR_BIND_FAILED;
} }
p->state = EInit; p->state = EUPnPInit;
return UPNPC_OK; return UPNPC_OK;
} }
int upnpc_finalize(upnpc_t * p) int upnpc_finalize(upnpc_t * p)
{ {
if(!p) return UPNPC_ERR_INVALID_ARGS; if(!p) return UPNPC_ERR_INVALID_ARGS;
free(p->root_desc_location);
p->root_desc_location = NULL;
free(p->http_request);
p->http_request = NULL;
free(p->http_response);
p->http_response = NULL;
free(p->control_cif_url);
p->control_cif_url = NULL;
free(p->control_conn_url);
p->control_conn_url = NULL;
if(p->ssdp_socket >= 0) { if(p->ssdp_socket >= 0) {
close(p->ssdp_socket); close(p->ssdp_socket);
p->ssdp_socket = -1; p->ssdp_socket = -1;
} }
if(p->http_socket >= 0) { while(p->device_list) {
close(p->http_socket); upnpc_device_t * next = p->device_list->next;
p->http_socket = -1; free(p->device_list->root_desc_location);
p->device_list->root_desc_location = NULL;
free(p->device_list->http_request);
p->device_list->http_request = NULL;
free(p->device_list->http_response);
p->device_list->http_response = NULL;
free(p->device_list->control_cif_url);
p->device_list->control_cif_url = NULL;
free(p->device_list->control_conn_url);
p->device_list->control_conn_url = NULL;
if(p->device_list->http_socket >= 0) {
close(p->device_list->http_socket);
p->device_list->http_socket = -1;
} }
ClearNameValueList(&p->soap_response_data); ClearNameValueList(&p->device_list->soap_response_data);
p->state = EFinalized; free(p->device_list);
p->device_list = next;
}
p->state = EUPnPFinalized;
return UPNPC_OK; return UPNPC_OK;
} }
int upnpc_get_external_ip_address(upnpc_t * p) int upnpc_get_external_ip_address(upnpc_device_t * p)
{ {
upnpc_build_soap_request(p, p->control_conn_url, upnpc_build_soap_request(p, p->control_conn_url,
"urn:schemas-upnp-org:service:WANIPConnection:1", "urn:schemas-upnp-org:service:WANIPConnection:1",
"GetExternalIPAddress", NULL, 0); "GetExternalIPAddress", NULL, 0);
p->state = ESoapConnect; p->state = EDevSoapConnect;
upnpc_connect(p, p->control_conn_url); upnpc_connect(p, p->control_conn_url);
return 0; return 0;
} }
int upnpc_get_link_layer_max_rate(upnpc_t * p) int upnpc_get_link_layer_max_rate(upnpc_device_t * p)
{ {
upnpc_build_soap_request(p, p->control_cif_url, upnpc_build_soap_request(p, p->control_cif_url,
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1", "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
"GetCommonLinkProperties", NULL, 0); "GetCommonLinkProperties", NULL, 0);
p->state = ESoapConnect; p->state = EDevSoapConnect;
upnpc_connect(p, p->control_conn_url); upnpc_connect(p, p->control_conn_url);
return 0; return 0;
} }
int upnpc_add_port_mapping(upnpc_t * p, int upnpc_add_port_mapping(upnpc_device_t * p,
const char * remote_host, unsigned short ext_port, const char * remote_host, unsigned short ext_port,
unsigned short int_port, const char * int_client, unsigned short int_port, const char * int_client,
const char * proto, const char * description, const char * proto, const char * description,
@ -868,7 +898,7 @@ int upnpc_add_port_mapping(upnpc_t * p,
"urn:schemas-upnp-org:service:WANIPConnection:1", "urn:schemas-upnp-org:service:WANIPConnection:1",
"AddPortMapping", "AddPortMapping",
args, 8); args, 8);
p->state = ESoapConnect; p->state = EDevSoapConnect;
upnpc_connect(p, p->control_conn_url); upnpc_connect(p, p->control_conn_url);
return 0; return 0;
} }
@ -876,42 +906,69 @@ int upnpc_add_port_mapping(upnpc_t * p,
#ifdef UPNPC_USE_SELECT #ifdef UPNPC_USE_SELECT
int upnpc_select_fds(upnpc_t * p, int * nfds, fd_set * readfds, fd_set * writefds) int upnpc_select_fds(upnpc_t * p, int * nfds, fd_set * readfds, fd_set * writefds)
{ {
upnpc_device_t * d;
int n = 0; int n = 0;
if(!p) return UPNPC_ERR_INVALID_ARGS; if(!p) return UPNPC_ERR_INVALID_ARGS;
for(d = p->device_list; d != NULL; d = d->next) {
switch(d->state) {
case EDevGetDescConnect:
case EDevGetDescRequest:
case EDevSoapConnect:
case EDevSoapRequest:
FD_SET(d->http_socket, writefds);
if(*nfds < d->http_socket)
*nfds = d->http_socket;
n++;
break;
case EDevGetDescResponse:
case EDevSoapResponse:
FD_SET(d->http_socket, readfds);
if(*nfds < d->http_socket)
*nfds = d->http_socket;
n++;
break;
default:
break;
}
}
switch(p->state) { switch(p->state) {
case ESendSSDP: case EUPnPSendSSDP:
FD_SET(p->ssdp_socket, writefds); FD_SET(p->ssdp_socket, writefds);
if(*nfds < p->ssdp_socket) if(*nfds < p->ssdp_socket)
*nfds = p->ssdp_socket; *nfds = p->ssdp_socket;
n++; n++;
break; break;
case EReceiveSSDP: case EUPnPReceiveSSDP:
default:
/* still receive SSDP responses when processing Description, etc. */
FD_SET(p->ssdp_socket, readfds); FD_SET(p->ssdp_socket, readfds);
if(*nfds < p->ssdp_socket) if(*nfds < p->ssdp_socket)
*nfds = p->ssdp_socket; *nfds = p->ssdp_socket;
n++; n++;
break; break;
case EGetDescConnect:
case EGetDescRequest:
case ESoapConnect:
case ESoapRequest:
FD_SET(p->http_socket, writefds);
if(*nfds < p->http_socket)
*nfds = p->http_socket;
n++;
break;
case EGetDescResponse:
case ESoapResponse:
FD_SET(p->http_socket, readfds);
if(*nfds < p->http_socket)
*nfds = p->http_socket;
n++;
break;
default:
return 0;
} }
return n; return n;
} }
void upnpc_check_select_fds(upnpc_t * p, const fd_set * readfds, const fd_set * writefds)
{
upnpc_device_t * d;
p->socket_flags = 0;
if(FD_ISSET(p->ssdp_socket, readfds))
p->socket_flags = UPNPC_SSDP_READABLE;
if(FD_ISSET(p->ssdp_socket, writefds))
p->socket_flags = UPNPC_SSDP_WRITEABLE;
for(d = p->device_list; d != NULL; d = d->next) {
d->socket_flags = 0;
if(FD_ISSET(d->http_socket, readfds))
d->socket_flags = UPNPC_HTTP_READABLE;
if(FD_ISSET(d->http_socket, writefds))
d->socket_flags = UPNPC_HTTP_WRITEABLE;
}
}
#endif #endif
static const char * devices_to_search[] = { static const char * devices_to_search[] = {
@ -924,6 +981,7 @@ static const char * devices_to_search[] = {
int upnpc_process(upnpc_t * p) int upnpc_process(upnpc_t * p)
{ {
upnpc_device_t * d;
/* /*
1) Envoyer les paquets de discovery SSDP 1) Envoyer les paquets de discovery SSDP
2) Recevoir et traiter les reponses 2) Recevoir et traiter les reponses
@ -931,31 +989,51 @@ int upnpc_process(upnpc_t * p)
4) tester les etats 4) tester les etats
*/ */
if(!p) return UPNPC_ERR_INVALID_ARGS; if(!p) return UPNPC_ERR_INVALID_ARGS;
debug_printf("state=%d\n", (int)p->state); debug_printf("state=%d socket_flags=0x%04x\n", (int)p->state, p->socket_flags);
switch(p->state) {
case EInit: for(d = p->device_list; d != NULL; d = d->next) {
upnpc_send_ssdp_msearch(p, devices_to_search[0], 2); switch(d->state) {
case EDevGetDescConnect:
case EDevSoapConnect:
upnpc_complete_connect(d);
break; break;
case ESendSSDP: case EDevGetDescRequest:
upnpc_send_ssdp_msearch(p, devices_to_search[0], 2); case EDevSoapRequest:
upnpc_send_request(d);
break; break;
case EReceiveSSDP: case EDevGetDescResponse:
case EDevSoapResponse:
upnpc_get_response(d);
break;
default:
break;
}
}
/* all devices ready => ready */
if(p->device_list != NULL) {
d = p->device_list;
while(d && d->state == EDevReady) d = d->next;
p->state = (d == NULL) ? EUPnPReady : EUPnPProcessing;
}
if(p->socket_flags & UPNPC_SSDP_READABLE) {
upnpc_receive_and_parse_ssdp(p); upnpc_receive_and_parse_ssdp(p);
}
switch(p->state) {
case EUPnPInit:
upnpc_send_ssdp_msearch(p, devices_to_search[0], 2);
break;
case EUPnPSendSSDP:
upnpc_send_ssdp_msearch(p, devices_to_search[0], 2);
break;
case EUPnPReceiveSSDP:
/*upnpc_receive_and_parse_ssdp(p);*/
break; break;
/*case EGetDesc: /*case EGetDesc:
upnpc_connect(p); upnpc_connect(p);
break;*/ break;*/
case EGetDescConnect: case EUPnPReady:
case ESoapConnect: case EUPnPProcessing:
upnpc_complete_connect(p);
break;
case EGetDescRequest:
case ESoapRequest:
upnpc_send_request(p);
break;
case EGetDescResponse:
case ESoapResponse:
upnpc_get_response(p);
break; break;
default: default:
return UPNPC_ERR_UNKNOWN_STATE; return UPNPC_ERR_UNKNOWN_STATE;

View File

@ -1,6 +1,6 @@
/* $Id: miniupnpc-async.h,v 1.13 2014/11/07 11:25:52 nanard Exp $ */ /* $Id: miniupnpc-async.h,v 1.13 2014/11/07 11:25:52 nanard Exp $ */
/* miniupnpc-async /* miniupnpc-async
* Copyright (c) 2008-2014, Thomas BERNARD <miniupnp@free.fr> * Copyright (c) 2008-2017, Thomas BERNARD <miniupnp@free.fr>
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
@ -17,6 +17,9 @@
#ifndef MINIUPNPC_ASYNC_H_INCLUDED #ifndef MINIUPNPC_ASYNC_H_INCLUDED
#define MINIUPNPC_ASYNC_H_INCLUDED #define MINIUPNPC_ASYNC_H_INCLUDED
/* for struct sockaddr_storage */
#include <netinet/in.h>
#include "declspec.h" #include "declspec.h"
#include "upnpreplyparse.h" #include "upnpreplyparse.h"
@ -30,25 +33,30 @@ extern "C" {
#define UPNPC_ERR_BIND_FAILED (-3) #define UPNPC_ERR_BIND_FAILED (-3)
#define UPNPC_ERR_UNKNOWN_STATE (-4) #define UPNPC_ERR_UNKNOWN_STATE (-4)
typedef struct { #define UPNPC_SSDP_READABLE 0x0001
#define UPNPC_SSDP_WRITEABLE 0x0100
#define UPNPC_HTTP_READABLE 0x0002
#define UPNPC_HTTP_WRITEABLE 0x0200
typedef struct upnpc_device {
struct upnpc_device * next;
enum { enum {
EInit = 1, EDevInit = 1,
ESendSSDP, EDevGetDescConnect,
EReceiveSSDP, EDevGetDescRequest,
/*EGetDesc,*/ EDevGetDescResponse,
EGetDescConnect, EDevReady,
EGetDescRequest, EDevSoapConnect,
EGetDescResponse, EDevSoapRequest,
EReady, EDevSoapResponse,
ESoapConnect, EDevFinalized = 99,
ESoapRequest, EDevError = 1000
ESoapResponse,
EFinalized = 99,
EError = 1000
} state; } state;
int ssdp_socket;
char * root_desc_location; char * root_desc_location;
char * control_cif_url;
char * control_conn_url;
int http_socket; int http_socket;
int socket_flags; /* see UPNPC_*_READABLE, etc. */
char * http_request; char * http_request;
int http_request_len; int http_request_len;
int http_request_sent; int http_request_sent;
@ -58,20 +66,36 @@ typedef struct {
int http_response_content_length; int http_response_content_length;
int http_response_chunked; int http_response_chunked;
int http_response_code; int http_response_code;
char * control_cif_url;
char * control_conn_url;
struct NameValueParserData soap_response_data; struct NameValueParserData soap_response_data;
struct sockaddr_storage selfaddr;
socklen_t selfaddrlen;
} upnpc_device_t;
typedef struct {
enum {
EUPnPInit = 1,
EUPnPSendSSDP,
EUPnPReceiveSSDP,
EUPnPGetDesc,
EUPnPReady,
EUPnPProcessing,
EUPnPFinalized = 99,
EUPnPError = 1000
} state;
int socket_flags; /* see UPNPC_*_READABLE, etc. */
int ssdp_socket;
upnpc_device_t * device_list;
} upnpc_t; } upnpc_t;
int upnpc_init(upnpc_t * p, const char * multicastif); int upnpc_init(upnpc_t * p, const char * multicastif);
int upnpc_finalize(upnpc_t * p); int upnpc_finalize(upnpc_t * p);
int upnpc_get_external_ip_address(upnpc_t * p); int upnpc_get_external_ip_address(upnpc_device_t * p);
int upnpc_get_link_layer_max_rate(upnpc_t * p); int upnpc_get_link_layer_max_rate(upnpc_device_t * p);
int upnpc_add_port_mapping(upnpc_t * p, int upnpc_add_port_mapping(upnpc_device_t * p,
const char * remote_host, unsigned short ext_port, const char * remote_host, unsigned short ext_port,
unsigned short int_port, const char * int_client, unsigned short int_port, const char * int_client,
const char * proto, const char * description, const char * proto, const char * description,
@ -79,6 +103,7 @@ int upnpc_add_port_mapping(upnpc_t * p,
#ifdef UPNPC_USE_SELECT #ifdef UPNPC_USE_SELECT
int upnpc_select_fds(upnpc_t * p, int * nfds, fd_set * readfds, fd_set * writefds); int upnpc_select_fds(upnpc_t * p, int * nfds, fd_set * readfds, fd_set * writefds);
void upnpc_check_select_fds(upnpc_t * p, const fd_set * readfds, const fd_set * writefds);
#endif /* UPNPC_USE_SELECT */ #endif /* UPNPC_USE_SELECT */
int upnpc_process(upnpc_t * p); int upnpc_process(upnpc_t * p);

View File

@ -1,6 +1,6 @@
/* $Id: testasync.c,v 1.14 2014/11/07 12:07:38 nanard Exp $ */ /* $Id: testasync.c,v 1.14 2014/11/07 12:07:38 nanard Exp $ */
/* miniupnpc-async /* miniupnpc-async
* Copyright (c) 2008-2014, Thomas BERNARD <miniupnp@free.fr> * Copyright (c) 2008-2017, Thomas BERNARD <miniupnp@free.fr>
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
@ -17,6 +17,10 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <sys/select.h> #include <sys/select.h>
/* for getnameinfo() : */
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
/* compile with -DUPNPC_USE_SELECT to enable upnpc_select_fds() function */ /* compile with -DUPNPC_USE_SELECT to enable upnpc_select_fds() function */
#include "miniupnpc-async.h" #include "miniupnpc-async.h"
#include "upnpreplyparse.h" #include "upnpreplyparse.h"
@ -30,8 +34,10 @@ enum methods {
int main(int argc, char * * argv) int main(int argc, char * * argv)
{ {
char ip_address[64];
int r, n; int r, n;
upnpc_t upnp; upnpc_t upnp;
upnpc_device_t * device = NULL;
const char * multicastif = NULL; const char * multicastif = NULL;
enum methods next_method_to_call = EGetExternalIP; enum methods next_method_to_call = EGetExternalIP;
enum methods last_method = ENothing; enum methods last_method = ENothing;
@ -43,7 +49,7 @@ int main(int argc, char * * argv)
} }
r = upnpc_process(&upnp); r = upnpc_process(&upnp);
printf("upnpc_process returned %d\n", r); printf("upnpc_process returned %d\n", r);
while((upnp.state != EReady) && (upnp.state != EError)) { while(upnp.state != EUPnPError) {
int nfds; int nfds;
fd_set readfds; fd_set readfds;
fd_set writefds; fd_set writefds;
@ -68,26 +74,31 @@ int main(int argc, char * * argv)
perror("select"); perror("select");
return 1; return 1;
} }
upnpc_check_select_fds(&upnp, &readfds, &writefds);
r = upnpc_process(&upnp); r = upnpc_process(&upnp);
#if DEBUG #if DEBUG
printf("upnpc_process returned %d\n", r); printf("upnpc_process returned %d\n", r);
#endif /* DEBUG */ #endif /* DEBUG */
if(r < 0) if(r < 0)
break; break;
if(upnp.state == EReady) { if(upnp.state == EUPnPReady) {
char * p; char * p;
printf("Process UPnP IGD Method results : HTTP %d\n", upnp.http_response_code); if(device == NULL) {
if(upnp.http_response_code == 200) { /* select one device */
device = upnp.device_list; /* pick up the first one */
}
printf("Process UPnP IGD Method results : HTTP %d\n", device->http_response_code);
if(device->http_response_code == 200) {
switch(last_method) { switch(last_method) {
case EGetExternalIP: case EGetExternalIP:
p = GetValueFromNameValueList(&upnp.soap_response_data, "NewExternalIPAddress"); p = GetValueFromNameValueList(&device->soap_response_data, "NewExternalIPAddress");
printf("ExternalIPAddress = %s\n", p); printf("ExternalIPAddress = %s\n", p);
/* p = GetValueFromNameValueList(&pdata, "errorCode");*/ /* p = GetValueFromNameValueList(&pdata, "errorCode");*/
break; break;
case EGetRates: case EGetRates:
p = GetValueFromNameValueList(&upnp.soap_response_data, "NewLayer1DownstreamMaxBitRate"); p = GetValueFromNameValueList(&device->soap_response_data, "NewLayer1DownstreamMaxBitRate");
printf("DownStream MaxBitRate = %s\t", p); printf("DownStream MaxBitRate = %s\t", p);
p = GetValueFromNameValueList(&upnp.soap_response_data, "NewLayer1UpstreamMaxBitRate"); p = GetValueFromNameValueList(&device->soap_response_data, "NewLayer1UpstreamMaxBitRate");
printf("UpStream MaxBitRate = %s\n", p); printf("UpStream MaxBitRate = %s\n", p);
break; break;
case EAddPortMapping: case EAddPortMapping:
@ -98,10 +109,10 @@ int main(int argc, char * * argv)
} }
} else { } else {
printf("SOAP error :\n"); printf("SOAP error :\n");
printf(" faultcode='%s'\n", GetValueFromNameValueList(&upnp.soap_response_data, "faultcode")); printf(" faultcode='%s'\n", GetValueFromNameValueList(&device->soap_response_data, "faultcode"));
printf(" faultstring='%s'\n", GetValueFromNameValueList(&upnp.soap_response_data, "faultstring")); printf(" faultstring='%s'\n", GetValueFromNameValueList(&device->soap_response_data, "faultstring"));
printf(" errorCode=%s\n", GetValueFromNameValueList(&upnp.soap_response_data, "errorCode")); printf(" errorCode=%s\n", GetValueFromNameValueList(&device->soap_response_data, "errorCode"));
printf(" errorDescription='%s'\n", GetValueFromNameValueList(&upnp.soap_response_data, "errorDescription")); printf(" errorDescription='%s'\n", GetValueFromNameValueList(&device->soap_response_data, "errorDescription"));
} }
if(next_method_to_call == ENothing) if(next_method_to_call == ENothing)
break; break;
@ -110,19 +121,24 @@ int main(int argc, char * * argv)
switch(next_method_to_call) { switch(next_method_to_call) {
case EGetExternalIP: case EGetExternalIP:
printf("GetExternalIPAddress\n"); printf("GetExternalIPAddress\n");
upnpc_get_external_ip_address(&upnp); upnpc_get_external_ip_address(device);
next_method_to_call = EGetRates; next_method_to_call = EGetRates;
break; break;
case EGetRates: case EGetRates:
printf("GetCommonLinkProperties\n"); printf("GetCommonLinkProperties\n");
upnpc_get_link_layer_max_rate(&upnp); upnpc_get_link_layer_max_rate(device);
next_method_to_call = EAddPortMapping; next_method_to_call = EAddPortMapping;
break; break;
case EAddPortMapping: case EAddPortMapping:
if(getnameinfo((struct sockaddr *)&device->selfaddr, device->selfaddrlen,
ip_address, sizeof(ip_address), NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV) < 0) {
fprintf(stderr, "getnameinfo() failed\n");
}
printf("our IP address is %s\n", ip_address);
printf("AddPortMapping\n"); printf("AddPortMapping\n");
upnpc_add_port_mapping(&upnp, upnpc_add_port_mapping(device,
NULL /* remote_host */, 40002 /* ext_port */, NULL /* remote_host */, 40002 /* ext_port */,
42042 /* int_port */, "192.168.1.202" /* int_client */, 42042 /* int_port */, ip_address /* int_client */,
"TCP" /* proto */, "this is a test" /* description */, "TCP" /* proto */, "this is a test" /* description */,
0 /* lease duration */); 0 /* lease duration */);
next_method_to_call = ENothing; next_method_to_call = ENothing;

View File

@ -1,6 +1,9 @@
$Id: Changelog.txt,v 1.226 2016/12/16 08:57:19 nanard Exp $ $Id: Changelog.txt,v 1.226 2016/12/16 08:57:19 nanard Exp $
miniUPnP client Changelog. miniUPnP client Changelog.
2017/05/05:
Fix CVE-2017-8798 Thanks to tin/Team OSTStrom
2016/11/11: 2016/11/11:
check strlen before memcmp in XML parsing portlistingparse.c check strlen before memcmp in XML parsing portlistingparse.c
fix build under SOLARIS and CYGWIN fix build under SOLARIS and CYGWIN

View File

@ -2,7 +2,7 @@
/* Project : miniupnp /* Project : miniupnp
* Website : http://miniupnp.free.fr/ * Website : http://miniupnp.free.fr/
* Author : Thomas Bernard * Author : Thomas Bernard
* Copyright (c) 2005-2016 Thomas Bernard * Copyright (c) 2005-2017 Thomas Bernard
* This software is subject to the conditions detailed in the * This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. */ * LICENCE file provided in this distribution. */
@ -111,7 +111,7 @@ getHTTPResponse(int s, int * size, int * status_code)
chunksize_buf[0] = '\0'; chunksize_buf[0] = '\0';
chunksize_buf_index = 0; chunksize_buf_index = 0;
while((n = receivedata(s, buf, 2048, 5000, NULL)) > 0) while((n = receivedata(s, buf, sizeof(buf), 5000, NULL)) > 0)
{ {
if(endofheaders == 0) if(endofheaders == 0)
{ {
@ -284,11 +284,12 @@ getHTTPResponse(int s, int * size, int * status_code)
goto end_of_stream; goto end_of_stream;
} }
} }
bytestocopy = ((int)chunksize < (n - i))?chunksize:(unsigned int)(n - i); /* it is guaranteed that (n >= i) */
bytestocopy = (chunksize < (unsigned int)(n - i))?chunksize:(unsigned int)(n - i);
if((content_buf_used + bytestocopy) > content_buf_len) if((content_buf_used + bytestocopy) > content_buf_len)
{ {
char * tmp; char * tmp;
if(content_length >= (int)(content_buf_used + bytestocopy)) { if((content_length >= 0) && ((unsigned int)content_length >= (content_buf_used + bytestocopy))) {
content_buf_len = content_length; content_buf_len = content_length;
} else { } else {
content_buf_len = content_buf_used + bytestocopy; content_buf_len = content_buf_used + bytestocopy;
@ -313,14 +314,15 @@ getHTTPResponse(int s, int * size, int * status_code)
{ {
/* not chunked */ /* not chunked */
if(content_length > 0 if(content_length > 0
&& (int)(content_buf_used + n) > content_length) { && (content_buf_used + n) > (unsigned int)content_length) {
/* skipping additional bytes */ /* skipping additional bytes */
n = content_length - content_buf_used; n = content_length - content_buf_used;
} }
if(content_buf_used + n > content_buf_len) if(content_buf_used + n > content_buf_len)
{ {
char * tmp; char * tmp;
if(content_length >= (int)(content_buf_used + n)) { if(content_length >= 0
&& (unsigned int)content_length >= (content_buf_used + n)) {
content_buf_len = content_length; content_buf_len = content_length;
} else { } else {
content_buf_len = content_buf_used + n; content_buf_len = content_buf_used + n;
@ -340,7 +342,7 @@ getHTTPResponse(int s, int * size, int * status_code)
} }
} }
/* use the Content-Length header value if available */ /* use the Content-Length header value if available */
if(content_length > 0 && (int)content_buf_used >= content_length) if(content_length > 0 && content_buf_used >= (unsigned int)content_length)
{ {
#ifdef DEBUG #ifdef DEBUG
printf("End of HTTP content\n"); printf("End of HTTP content\n");

View File

@ -1,7 +1,7 @@
/* $Id: upnpc.c,v 1.114 2016/01/22 15:04:23 nanard Exp $ */ /* $Id: upnpc.c,v 1.117 2017/05/26 15:26:55 nanard Exp $ */
/* Project : miniupnp /* Project : miniupnp
* Author : Thomas Bernard * Author : Thomas Bernard
* Copyright (c) 2005-2016 Thomas Bernard * Copyright (c) 2005-2017 Thomas Bernard
* This software is subject to the conditions detailed in the * This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. */ * LICENCE file provided in this distribution. */
@ -578,8 +578,8 @@ int main(int argc, char ** argv)
} }
#endif #endif
printf("upnpc : miniupnpc library test client, version %s.\n", MINIUPNPC_VERSION_STRING); printf("upnpc : miniupnpc library test client, version %s.\n", MINIUPNPC_VERSION_STRING);
printf(" (c) 2005-2016 Thomas Bernard.\n"); printf(" (c) 2005-2017 Thomas Bernard.\n");
printf("Go to http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/\n" printf("Go to http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/\n"
"for more information.\n"); "for more information.\n");
/* command line processing */ /* command line processing */
for(i=1; i<argc; i++) for(i=1; i<argc; i++)

View File

@ -1,4 +1,8 @@
$Id: Changelog.txt,v 1.430 2016/12/16 09:14:40 nanard Exp $ $Id: Changelog.txt,v 1.432 2017/05/24 22:47:53 nanard Exp $
2017/05/24:
get SSDP packet receiving interface index and use it to check if the
packet is from a LAN
2017/03/13: 2017/03/13:
default to client address for AddPortMapping when <NewInternalClient> default to client address for AddPortMapping when <NewInternalClient>

View File

@ -1,7 +1,7 @@
MiniUPnP project. MiniUPnP project.
(c) 2006-2016 Thomas Bernard (c) 2006-2017 Thomas Bernard
Homepage : http://miniupnp.free.fr/ Homepage : http://miniupnp.free.fr/
Mirror: http://miniupnp.tuxfamily.org/ Mirror: https://miniupnp.tuxfamily.org/
github: https://github.com/miniupnp/miniupnp github: https://github.com/miniupnp/miniupnp
miniupnpd is still under active developpement. This documentation is miniupnpd is still under active developpement. This documentation is

View File

@ -1,5 +1,5 @@
MiniUPnPd MiniUPnPd
Copyright (c) 2006-2016, Thomas BERNARD Copyright (c) 2006-2017, Thomas BERNARD
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

View File

@ -1,6 +1,6 @@
MiniUPnP project MiniUPnP project
(c) 2006-2016 Thomas Bernard (c) 2006-2017 Thomas Bernard
webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ webpage: http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
github: https://github.com/miniupnp/miniupnp github: https://github.com/miniupnp/miniupnp
freecode: http://freecode.com/projects/miniupnp freecode: http://freecode.com/projects/miniupnp
contact: miniupnp@free.fr contact: miniupnp@free.fr
@ -31,7 +31,7 @@ Read the INSTALL file for instructions to compile, install and
configure miniupnpd on your system. configure miniupnpd on your system.
Report bugs to miniupnp@free.fr or on the web forum Report bugs to miniupnp@free.fr or on the web forum
http://miniupnp.tuxfamily.org/forum/ https://miniupnp.tuxfamily.org/forum/
or using https://github.com/miniupnp/miniupnp/issues or using https://github.com/miniupnp/miniupnp/issues
Thomas Bernard Thomas Bernard

View File

@ -1,4 +1,4 @@
/* $Id: minissdp.c,v 1.77 2015/08/26 07:36:52 nanard Exp $ */ /* $Id: minissdp.c,v 1.87 2017/05/24 22:33:33 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-2017 Thomas Bernard * (c) 2006-2017 Thomas Bernard
@ -16,6 +16,13 @@
#include <errno.h> #include <errno.h>
#include <syslog.h> #include <syslog.h>
#ifdef IP_RECVIF
#include <sys/types.h>
#include <sys/uio.h>
#include <net/if.h>
#include <net/if_dl.h>
#endif
#include "config.h" #include "config.h"
#if defined(ENABLE_IPV6) && defined(UPNP_STRICT) #if defined(ENABLE_IPV6) && defined(UPNP_STRICT)
#include <ifaddrs.h> #include <ifaddrs.h>
@ -153,7 +160,7 @@ OpenAndConfSSDPReceiveSocket(int ipv6)
struct sockaddr_storage sockname; struct sockaddr_storage sockname;
socklen_t sockname_len; socklen_t sockname_len;
struct lan_addr_s * lan_addr; struct lan_addr_s * lan_addr;
int j = 1; const int on = 1;
if( (s = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0)) < 0) if( (s = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0)) < 0)
{ {
@ -185,10 +192,36 @@ OpenAndConfSSDPReceiveSocket(int ipv6)
sockname_len = sizeof(struct sockaddr_in); sockname_len = sizeof(struct sockaddr_in);
} }
if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &j, sizeof(j)) < 0) if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
{ {
syslog(LOG_WARNING, "setsockopt(udp, SO_REUSEADDR): %m"); syslog(LOG_WARNING, "setsockopt(udp, SO_REUSEADDR): %m");
} }
#ifdef IP_RECVIF
/* BSD */
if(!ipv6) {
if(setsockopt(s, IPPROTO_IP, IP_RECVIF, &on, sizeof(on)) < 0)
{
syslog(LOG_WARNING, "setsockopt(udp, IP_RECVIF): %m");
}
}
#endif /* IP_RECVIF */
#ifdef IP_PKTINFO
/* Linux */
if(!ipv6) {
if(setsockopt(s, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)) < 0)
{
syslog(LOG_WARNING, "setsockopt(udp, IP_PKTINFO): %m");
}
}
#endif /* IP_PKTINFO */
#if defined(ENABLE_IPV6) && defined(IPV6_RECVPKTINFO)
if(ipv6) {
if(setsockopt(s, IPPROTO_IP, IPV6_RECVPKTINFO, &on, sizeof(on)) < 0)
{
syslog(LOG_WARNING, "setsockopt(udp, IPV6_RECVPKTINFO): %m");
}
}
#endif /* defined(ENABLE_IPV6) && defined(IPV6_RECVPKTINFO) */
if(!set_non_blocking(s)) if(!set_non_blocking(s))
{ {
@ -814,17 +847,53 @@ ProcessSSDPRequest(int s, unsigned short http_port)
{ {
int n; int n;
char bufr[1500]; char bufr[1500];
socklen_t len_r;
#ifdef ENABLE_IPV6 #ifdef ENABLE_IPV6
struct sockaddr_storage sendername; struct sockaddr_storage sendername;
len_r = sizeof(struct sockaddr_storage);
#else #else
struct sockaddr_in sendername; struct sockaddr_in sendername;
len_r = sizeof(struct sockaddr_in);
#endif #endif
int source_ifindex = -1;
#ifdef IP_PKTINFO
char cmbuf[CMSG_SPACE(sizeof(struct in_pktinfo))];
struct iovec iovec = {
.iov_base = bufr,
.iov_len = sizeof(bufr)
};
struct msghdr mh = {
.msg_name = &sendername,
.msg_namelen = sizeof(sendername),
.msg_iov = &iovec,
.msg_iovlen = 1,
.msg_control = cmbuf,
.msg_controllen = sizeof(cmbuf)
};
struct cmsghdr *cmptr;
#endif /* IP_PKTINFO */
#ifdef IP_RECVIF
char cmbuf[CMSG_SPACE(sizeof(struct sockaddr_dl))];
struct iovec iovec = {
.iov_base = bufr,
.iov_len = sizeof(bufr)
};
struct msghdr mh = {
.msg_name = &sendername,
.msg_namelen = sizeof(sendername),
.msg_iov = &iovec,
.msg_iovlen = 1,
.msg_control = cmbuf,
.msg_controllen = sizeof(cmbuf)
};
struct cmsghdr *cmptr;
#endif /* IP_RECVIF */
#if defined(IP_RECVIF) || defined(IP_PKTINFO)
n = recvmsg(s, &mh, 0);
#else
socklen_t len_r;
len_r = sizeof(sendername);
n = recvfrom(s, bufr, sizeof(bufr), 0, n = recvfrom(s, bufr, sizeof(bufr), 0,
(struct sockaddr *)&sendername, &len_r); (struct sockaddr *)&sendername, &len_r);
#endif /* defined(IP_RECVIF) || defined(IP_PKTINFO) */
if(n < 0) if(n < 0)
{ {
/* EAGAIN, EWOULDBLOCK, EINTR : silently ignore (try again next time) /* EAGAIN, EWOULDBLOCK, EINTR : silently ignore (try again next time)
@ -837,11 +906,45 @@ ProcessSSDPRequest(int s, unsigned short http_port)
} }
return; return;
} }
#if defined(IP_RECVIF) || defined(IP_PKTINFO)
for(cmptr = CMSG_FIRSTHDR(&mh); cmptr != NULL; cmptr = CMSG_NXTHDR(&mh, cmptr))
{
syslog(LOG_DEBUG, "level=%d type=%d", cmptr->cmsg_level, cmptr->cmsg_type);
#ifdef IP_PKTINFO
if(cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
{
struct in_pktinfo * pi; /* fields : ifindex, spec_dst, addr */
pi = (struct in_pktinfo *)CMSG_DATA(cmptr);
syslog(LOG_DEBUG, "ifindex = %u %s", pi->ipi_ifindex, inet_ntoa(pi->ipi_spec_dst));
source_ifindex = pi->ipi_ifindex;
}
#endif /* IP_PKTINFO */
#if defined(ENABLE_IPV6) && defined(IPV6_RECVPKTINFO)
if(cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == IPV6_RECVPKTINFO)
{
struct in6_pktinfo * pi6; /* fields : ifindex, addr */
pi6 = (struct in6_pktinfo *)CMSG_DATA(cmptr);
syslog(LOG_DEBUG, "ifindex = %u", pi6->ipi6_ifindex);
source_ifindex = pi6->ipi6_ifindex;
}
#endif /* defined(ENABLE_IPV6) && defined(IPV6_RECVPKTINFO) */
#ifdef IP_RECVIF
if(cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
{
struct sockaddr_dl *sdl; /* fields : len, family, index, type, nlen, alen, slen, data */
sdl = (struct sockaddr_dl *)CMSG_DATA(cmptr);
syslog(LOG_DEBUG, "sdl_index = %d %s", sdl->sdl_index, link_ntoa(sdl));
source_ifindex = sdl->sdl_index;
}
#endif /* IP_RECVIF */
}
#endif /* defined(IP_RECVIF) || defined(IP_PKTINFO) */
#ifdef ENABLE_HTTPS #ifdef ENABLE_HTTPS
ProcessSSDPData(s, bufr, n, (struct sockaddr *)&sendername, ProcessSSDPData(s, bufr, n, (struct sockaddr *)&sendername, source_ifindex,
http_port, https_port); http_port, https_port);
#else #else
ProcessSSDPData(s, bufr, n, (struct sockaddr *)&sendername, ProcessSSDPData(s, bufr, n, (struct sockaddr *)&sendername, source_ifindex,
http_port); http_port);
#endif #endif
@ -850,12 +953,12 @@ ProcessSSDPRequest(int s, unsigned short http_port)
#ifdef ENABLE_HTTPS #ifdef ENABLE_HTTPS
void void
ProcessSSDPData(int s, const char *bufr, int n, ProcessSSDPData(int s, const char *bufr, int n,
const struct sockaddr * sender, const struct sockaddr * sender, int source_if,
unsigned short http_port, unsigned short https_port) unsigned short http_port, unsigned short https_port)
#else #else
void void
ProcessSSDPData(int s, const char *bufr, int n, ProcessSSDPData(int s, const char *bufr, int n,
const struct sockaddr * sender, const struct sockaddr * sender, int source_if,
unsigned short http_port) unsigned short http_port)
#endif #endif
{ {
@ -889,10 +992,31 @@ ProcessSSDPData(int s, const char *bufr, int n,
/* get the string representation of the sender address */ /* get the string representation of the sender address */
sockaddr_to_string(sender, sender_str, sizeof(sender_str)); sockaddr_to_string(sender, sender_str, sizeof(sender_str));
lan_addr = get_lan_for_peer(sender); lan_addr = get_lan_for_peer(sender);
if(source_if >= 0)
{
if(lan_addr != NULL)
{
if(lan_addr->index != (unsigned)source_if)
{
syslog(LOG_WARNING, "interface index not matching %u != %d", lan_addr->index, source_if);
}
}
else
{
/* use the interface index */
for(lan_addr = lan_addrs.lh_first;
lan_addr != NULL;
lan_addr = lan_addr->list.le_next)
{
if(lan_addr->index == (unsigned)source_if)
break;
}
}
}
if(lan_addr == NULL) if(lan_addr == NULL)
{ {
syslog(LOG_WARNING, "SSDP packet sender %s not from a LAN, ignoring", syslog(LOG_WARNING, "SSDP packet sender %s (if_index=%d) not from a LAN, ignoring",
sender_str); sender_str, source_if);
return; return;
} }

View File

@ -1,7 +1,7 @@
/* $Id: minissdp.h,v 1.12 2014/04/09 07:20:59 nanard Exp $ */ /* $Id: minissdp.h,v 1.12 2014/04/09 07:20:59 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-2017 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 MINISSDP_H_INCLUDED #ifndef MINISSDP_H_INCLUDED
@ -39,12 +39,12 @@ ProcessSSDPRequest(int s, unsigned short http_port);
#ifdef ENABLE_HTTPS #ifdef ENABLE_HTTPS
void void
ProcessSSDPData(int s, const char *bufr, int n, ProcessSSDPData(int s, const char *bufr, int n,
const struct sockaddr * sendername, const struct sockaddr * sendername, int source_if,
unsigned short http_port, unsigned short https_port); unsigned short http_port, unsigned short https_port);
#else #else
void void
ProcessSSDPData(int s, const char *bufr, int n, ProcessSSDPData(int s, const char *bufr, int n,
const struct sockaddr * sendername, const struct sockaddr * sendername, int source_if,
unsigned short http_port); unsigned short http_port);
#endif #endif

View File

@ -631,7 +631,7 @@ static int nfqueue_cb(
/* printf("pkt found %s\n",dd);*/ /* printf("pkt found %s\n",dd);*/
ProcessSSDPData (sudp, dd, size - x, ProcessSSDPData (sudp, dd, size - x,
&sendername, (unsigned short) 5555); &sendername, -1, (unsigned short) 5555);
} }
} }
} }
@ -984,7 +984,6 @@ parselanaddr(struct lan_addr_s * lan_addr, const char * str)
} }
} }
#endif #endif
#ifdef ENABLE_IPV6
if(lan_addr->ifname[0] != '\0') if(lan_addr->ifname[0] != '\0')
{ {
lan_addr->index = if_nametoindex(lan_addr->ifname); lan_addr->index = if_nametoindex(lan_addr->ifname);
@ -992,6 +991,7 @@ parselanaddr(struct lan_addr_s * lan_addr, const char * str)
fprintf(stderr, "Cannot get index for network interface %s", fprintf(stderr, "Cannot get index for network interface %s",
lan_addr->ifname); lan_addr->ifname);
} }
#ifdef ENABLE_IPV6
else else
{ {
fprintf(stderr, fprintf(stderr,

View File

@ -16,9 +16,7 @@
* with ascii representation and mask */ * with ascii representation and mask */
struct lan_addr_s { struct lan_addr_s {
char ifname[IFNAMSIZ]; /* example: eth0 */ char ifname[IFNAMSIZ]; /* example: eth0 */
#ifdef ENABLE_IPV6
unsigned int index; /* use if_nametoindex() */ unsigned int index; /* use if_nametoindex() */
#endif
char str[16]; /* example: 192.168.0.1 */ char str[16]; /* example: 192.168.0.1 */
struct in_addr addr, mask; /* ip/mask */ struct in_addr addr, mask; /* ip/mask */
#ifdef MULTIPLE_EXTERNAL_IP #ifdef MULTIPLE_EXTERNAL_IP