Merge branch 'master' into local_port

Conflicts:
	miniupnpc/miniupnpc.c
	miniupnpc/miniupnpc.h
	miniupnpc/miniupnpcmodule.c
	miniupnpc/upnpc.c
This commit is contained in:
Thomas Bernard 2015-10-08 17:42:45 +02:00
commit d4af610c51
87 changed files with 2668 additions and 1193 deletions

46
.travis.yml Normal file
View File

@ -0,0 +1,46 @@
language: c
os:
- linux
- osx
addons:
apt:
packages:
# packages list: https://github.com/travis-ci/apt-package-whitelist/blob/master/ubuntu-precise
- iptables-dev
- libevent-dev
- libnfnetlink-dev
# container-based builds
sudo: false
env:
- 'PROJECT=minissdpd'
- 'PROJECT=miniupnpc'
- 'PROJECT=miniupnpc-async'
- 'PROJECT=miniupnpc-libevent'
- 'PROJECT=miniupnpd'
matrix:
exclude:
- os: osx
env: PROJECT=miniupnpd
compiler:
- gcc
- clang
before_install:
- 'if [ "$TRAVIS_OS_NAME" = "osx" -a "$PROJECT" = "miniupnpc-libevent" ]; then brew update > /dev/null && brew install libevent; fi'
script:
- 'cd $TRAVIS_BUILD_DIR && cd $PROJECT'
- 'MAKEFILE=Makefile && if [ -f Makefile.linux -a "$TRAVIS_OS_NAME" = "linux" ]; then MAKEFILE=Makefile.linux; elif [ -f Makefile.macosx -a "$TRAVIS_OS_NAME" = "osx" ]; then MAKEFILE=Makefile.macosx; fi'
- 'if [ "$MAKEFILE" = "Makefile.macosx" ]; then make -f $MAKEFILE depend; fi'
- 'make -f $MAKEFILE -j3'
- 'if [ "$PROJECT" = "miniupnpc" -o "$PROJECT" = "minissdpd" -o "$PROJECT" = "miniupnpd" ]; then make -f $MAKEFILE check; fi'
- 'if [ "$PROJECT" = "miniupnpc" ]; then INSTALLPREFIX="$HOME/_pythonmodule" make -f $MAKEFILE pythonmodule; fi'
after_success:
- 'INSTALLPREFIX="$HOME/$PROJECT" make -f $MAKEFILE install'

3
README
View File

@ -4,6 +4,7 @@ Main author : Thomas BERNARD
Web site : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
Github : https://github.com/miniupnp/miniupnp/
Freecode : http://freecode.com/projects/miniupnp
Travis CI : https://travis-ci.org/miniupnp/miniupnp
miniupnpc/ : MiniUPnP client - an UPnP IGD control point
miniupnpd/ : MiniUPnP daemon - an implementation of a UPnP IGD
@ -53,3 +54,5 @@ Thanks to :
* Yonetani Tomokazu
* Markus Stenberg
* Tomofumi Hayashi
* Konstantin Tokarev
* Mike Tzou

6
appveyor.yml Normal file
View File

@ -0,0 +1,6 @@
install:
- set PATH=%PATH%;C:\MinGW\bin
build_script:
- cmd: 'cd miniupnpc'
- cmd: 'mingw32make.bat'

View File

@ -4,3 +4,5 @@ testcodelength
testminissdpd
listifaces
Makefile.bak
validateminissdpd
validatecodelength

View File

@ -1,4 +1,19 @@
$Id: Changelog.txt,v 1.39 2014/12/05 13:42:59 nanard Exp $
$Id: Changelog.txt,v 1.43 2015/08/06 14:05:49 nanard Exp $
2015/08/06:
disable multicast loop
add -f command line option to filter for a specific device type
VERSION 1.4:
2015/08/06:
added command 0 (version)
2015/07/21:
set multicast TTL to 2 by default and configurable
2015/05/27:
support larger buffer size (useful for type 3 requests)
VERSION 1.3:

View File

@ -1,4 +1,4 @@
# $Id: Makefile,v 1.23 2014/12/06 10:54:01 nanard Exp $
# $Id: Makefile,v 1.25 2015/08/06 10:17:52 nanard Exp $
# MiniUPnP project
# author: Thomas Bernard
# website: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
@ -18,7 +18,7 @@ CFLAGS += -W -Wstrict-prototypes
CFLAGS += -fno-strict-aliasing -fno-common
CFLAGS += -D_GNU_SOURCE
CFLAGS += -ansi
CC = gcc
CC ?= gcc
RM = rm -f
INSTALL = install
OS = $(shell uname -s)
@ -43,10 +43,12 @@ SBININSTALLDIR = $(INSTALLPREFIX)/sbin
MANINSTALLDIR = $(INSTALLPREFIX)/share/man
.PHONY: all clean install depend
.PHONY: all clean install depend check test
all: $(EXECUTABLES)
test: check
clean:
$(RM) $(ALLOBJS) $(EXECUTABLES)
@ -60,6 +62,16 @@ ifneq ($(OS), Darwin)
$(INSTALL) minissdpd.init.d.script $(PREFIX)/etc/init.d/minissdpd
endif
check: validateminissdpd validatecodelength
validateminissdpd: testminissdpd minissdpd
./testminissdpd.sh
touch $@
validatecodelength: testcodelength
./testcodelength
touch $@
minissdpd: $(MINISSDPDOBJS)
testminissdpd: $(TESTMINISSDPDOBJS)

View File

@ -1,20 +1,45 @@
protocol :
* MiniSSDPd - SSDP daemon
(c) Thomas Bernard
http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
https://github.com/miniupnp/miniupnp/
MiniSSDPd is a daemon that :
1 - keeps track of all UPnP devices announcing themselves on the network.
its database can be queried by local processes using a protocol based on
a unix socket. That enables local processes to quickly discover UPnP devices
without broadcasting SSDP message and waiting several seconds for a response.
2 - keeps a database of local UPnP devices hosted on the machine and
answering SSDP searchs on their behalf. It enables to run several UPnP devices,
like an IGD and a MediaServer, on the same machine.
to build, use GNU Make.
* protocol :
Connect to the unix socket.
Sent request, answer response.
Sent request, get response.
close unix socket connection.
Request format :
* Request format :
1st byte : request type
1 - type
2 - USN (unique id)
3 - everything
4 - submit service (see below)
0 - version
1 - type
2 - USN (unique id)
3 - everything
4 - submit service (see below)
n bytes : string length : 1 byte if < 128 else the upper bit indicate that
one additional byte should be read, etc. (see codelength.h)
n bytes = string
Response format :
request type 0 (version) :
n bytes string length
n bytes = version string
request type 1 / 2 / 3 :
1st byte : number of services/devices
For each service/device :
URL :

View File

@ -6,6 +6,7 @@ fermeture de la connexion.
format de requete :
1 octet : type de la requete
0 - version
1 - type
2 - USN (id unique)
3 - tout

View File

@ -1 +1 @@
1.3
1.4

View File

@ -1,4 +1,4 @@
/* $Id: asyncsendto.c,v 1.6 2014/05/19 14:26:56 nanard Exp $ */
/* $Id: asyncsendto.c,v 1.7 2015/09/03 18:19:20 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2014 Thomas Bernard
@ -11,10 +11,12 @@
#include <sys/queue.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <syslog.h>
#include <errno.h>
#include <sys/uio.h>
#include <netinet/in.h>
#include <inttypes.h>
#include "asyncsendto.h"
#include "upnputils.h"

View File

@ -1,7 +1,7 @@
/* $Id: codelength.h,v 1.3 2011/07/30 13:10:05 nanard Exp $ */
/* $Id: codelength.h,v 1.5 2015/07/09 12:40:18 nanard Exp $ */
/* Project : miniupnp
* Author : Thomas BERNARD
* copyright (c) 2005-2011 Thomas Bernard
* copyright (c) 2005-2015 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENCE file. */
#ifndef CODELENGTH_H_INCLUDED
@ -10,10 +10,30 @@
/* Encode length by using 7bit per Byte :
* Most significant bit of each byte specifies that the
* following byte is part of the code */
/* n : unsigned
* p : unsigned char *
*/
#define DECODELENGTH(n, p) n = 0; \
do { n = (n << 7) | (*p & 0x7f); } \
while((*(p++)&0x80) && (n<(1<<25)));
/* n : unsigned
* READ : function/macro to read one byte (unsigned char)
*/
#define DECODELENGTH_READ(n, READ) \
n = 0; \
do { \
unsigned char c; \
READ(c); \
n = (n << 7) | (c & 0x07f); \
if(!(c&0x80)) break; \
} while(n<(1<<25));
/* n : unsigned
* p : unsigned char *
* p_limit : unsigned char *
*/
#define DECODELENGTH_CHECKLIMIT(n, p, p_limit) \
n = 0; \
do { \
@ -21,11 +41,14 @@
n = (n << 7) | (*(p) & 0x7f); \
} while((*((p)++)&0x80) && (n<(1<<25)));
/* n : unsigned
* p : unsigned char *
*/
#define CODELENGTH(n, p) if(n>=268435456) *(p++) = (n >> 28) | 0x80; \
if(n>=2097152) *(p++) = (n >> 21) | 0x80; \
if(n>=16384) *(p++) = (n >> 14) | 0x80; \
if(n>=128) *(p++) = (n >> 7) | 0x80; \
*(p++) = n & 0x7f;
#endif
#endif /* CODELENGTH_H_INCLUDED */

View File

@ -1,12 +1,14 @@
/* $Id: config.h,v 1.6 2012/09/27 15:40:29 nanard Exp $ */
/* $Id: config.h,v 1.9 2015/08/06 13:16:58 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2011 Thomas Bernard
* (c) 2006-2015 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
#ifndef CONFIG_H_INCLUDED
#define CONFIG_H_INCLUDED
#define MINISSDPD_VERSION "1.4"
/* use BSD daemon() ? */
#define USE_DAEMON
@ -19,6 +21,9 @@
/* Maximum number of network interface we can listen on */
#define MAX_IF_ADDR 8
/* The size of unix socket response buffer */
#define RESPONSE_BUFFER_SIZE (1024 * 4)
/* Uncomment the following line in order to make minissdpd
* listen on 1.2.3.4:1900 instead of *:1900
* Note : it prevents broadcast packets to be received,

View File

@ -1,4 +1,4 @@
/* $Id: getifaddr.c,v 1.23 2014/05/06 14:40:53 nanard Exp $ */
/* $Id: getifaddr.c,v 1.24 2015/07/09 12:27:26 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2014 Thomas Bernard
@ -47,6 +47,7 @@ getifaddr(const char * ifname, char * buf, int len,
return -1;
}
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
ifr.ifr_name[IFNAMSIZ-1] = '\0';
if(ioctl(s, SIOCGIFFLAGS, &ifr, &ifrlen) < 0)
{
syslog(LOG_DEBUG, "ioctl(s, SIOCGIFFLAGS, ...): %m");

View File

@ -172,7 +172,7 @@ get_src_for_route_to(const struct sockaddr * dst,
if(src_len && src) {
if(*src_len < RTA_PAYLOAD(rta)) {
syslog(LOG_WARNING, "cannot copy src: %u<%lu",
(unsigned)*src_len, RTA_PAYLOAD(rta));
(unsigned)*src_len, (unsigned long)RTA_PAYLOAD(rta));
goto error;
}
*src_len = RTA_PAYLOAD(rta);

View File

@ -1,4 +1,4 @@
/* $Id: ifacewatch.c,v 1.15 2014/11/28 16:30:37 nanard Exp $ */
/* $Id: ifacewatch.c,v 1.16 2015/09/03 18:31:25 nanard Exp $ */
/* MiniUPnP project
* (c) 2011-2012 Thomas Bernard
* website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
@ -25,6 +25,7 @@
#endif
#endif /* __linux__ */
#include <syslog.h>
#include <inttypes.h>
#include "openssdpsocket.h"
#include "upnputils.h"

View File

@ -1,4 +1,4 @@
/* $Id: minissdpd.c,v 1.45 2015/02/08 08:51:54 nanard Exp $ */
/* $Id: minissdpd.c,v 1.50 2015/08/06 14:05:49 nanard Exp $ */
/* MiniUPnP project
* (c) 2007-2015 Thomas Bernard
* website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
@ -27,8 +27,10 @@
/* unix sockets */
#include <sys/un.h>
/* for getpwnam() and getgrnam() */
#if 0
#include <pwd.h>
#include <grp.h>
#endif
#include "getifaddr.h"
#include "upnputils.h"
@ -490,7 +492,8 @@ containsForbiddenChars(const unsigned char * p, int len)
* 1 : a device was added. */
static int
ParseSSDPPacket(int s, const char * p, ssize_t n,
const struct sockaddr * addr)
const struct sockaddr * addr,
const char * searched_device)
{
const char * linestart;
const char * lineend;
@ -646,6 +649,10 @@ ParseSSDPPacket(int s, const char * p, ssize_t n,
case METHOD_NOTIFY:
if(nts==NTS_SSDP_ALIVE || nts==NTS_SSDP_UPDATE) {
if(headers[HEADER_NT].p && headers[HEADER_USN].p && headers[HEADER_LOCATION].p) {
/* filter if needed */
if(searched_device &&
0 != memcmp(headers[HEADER_NT].p, searched_device, headers[HEADER_NT].l))
break;
r = updateDevice(headers, time(NULL) + lifetime);
} else {
syslog(LOG_WARNING, "missing header nt=%p usn=%p location=%p",
@ -726,8 +733,8 @@ void processRequest(struct reqelem * req)
const unsigned char * p;
int type;
struct device * d = devlist;
unsigned char rbuf[4096];
unsigned char * rp = rbuf+1;
unsigned char rbuf[RESPONSE_BUFFER_SIZE];
unsigned char * rp;
unsigned char nrep = 0;
time_t t;
struct service * newserv = NULL;
@ -749,19 +756,31 @@ void processRequest(struct reqelem * req)
p = buf + 1;
DECODELENGTH_CHECKLIMIT(l, p, buf + n);
if(p+l > buf+n) {
syslog(LOG_WARNING, "bad request (length encoding)");
syslog(LOG_WARNING, "bad request (length encoding l=%u n=%u)",
l, (unsigned)n);
goto error;
}
if(l == 0 && type != 3) {
if(l == 0 && type != 3 && type != 0) {
syslog(LOG_WARNING, "bad request (length=0)");
goto error;
}
syslog(LOG_INFO, "(s=%d) request type=%d str='%.*s'",
req->socket, type, l, p);
switch(type) {
case 0: /* version */
rp = rbuf;
CODELENGTH((sizeof(MINISSDPD_VERSION) - 1), rp);
memcpy(rp, MINISSDPD_VERSION, sizeof(MINISSDPD_VERSION) - 1);
rp += (sizeof(MINISSDPD_VERSION) - 1);
if(write_or_buffer(req, rbuf, rp - rbuf) < 0) {
syslog(LOG_ERR, "(s=%d) write: %m", req->socket);
goto error;
}
break;
case 1: /* request by type */
case 2: /* request by USN (unique id) */
case 3: /* everything */
rp = rbuf+1;
while(d && (nrep < 255)) {
if(d->t < t) {
syslog(LOG_INFO, "outdated device");
@ -915,7 +934,7 @@ void processRequest(struct reqelem * req)
serv = serv->entries.le_next) {
if(0 == strcmp(newserv->usn, serv->usn)
&& 0 == strcmp(newserv->st, serv->st)) {
syslog(LOG_INFO, "Service allready in the list. Updating...");
syslog(LOG_INFO, "Service already in the list. Updating...");
free(newserv->st);
free(newserv->usn);
free(serv->server);
@ -979,13 +998,14 @@ sigterm(int sig)
#define UPNP_MCAST_LL_ADDR "FF02::C" /* link-local */
#define UPNP_MCAST_SL_ADDR "FF05::C" /* site-local */
/* send the M-SEARCH request for all devices */
void ssdpDiscoverAll(int s, int ipv6)
/* send the M-SEARCH request for devices
* either all devices (third argument is NULL or "*") or a specific one */
static void ssdpDiscover(int s, int ipv6, const char * search)
{
static const char MSearchMsgFmt[] =
"M-SEARCH * HTTP/1.1\r\n"
"HOST: %s:" XSTR(PORT) "\r\n"
"ST: ssdp:all\r\n"
"ST: %s\r\n"
"MAN: \"ssdp:discover\"\r\n"
"MX: %u\r\n"
"\r\n";
@ -1000,7 +1020,8 @@ void ssdpDiscoverAll(int s, int ipv6)
MSearchMsgFmt,
ipv6 ?
(linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]")
: UPNP_MCAST_ADDR, mx);
: UPNP_MCAST_ADDR,
(search ? search : "ssdp:all"), mx);
memset(&sockudp_w, 0, sizeof(struct sockaddr_storage));
if(ipv6) {
struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w;
@ -1062,6 +1083,8 @@ int main(int argc, char * * argv)
struct sockaddr_in6 sendername6;
socklen_t sendername6_len;
#endif /* ENABLE_IPV6 */
unsigned char ttl = 2; /* UDA says it should default to 2 */
const char * searched_device = NULL; /* if not NULL, search/filter a specific device type */
LIST_INIT(&reqlisthead);
LIST_INIT(&servicelisthead);
@ -1069,28 +1092,40 @@ int main(int argc, char * * argv)
/* process command line */
for(i=1; i<argc; i++)
{
if(0==strcmp(argv[i], "-i")) {
lan_addr = malloc(sizeof(struct lan_addr_s));
if(lan_addr == NULL) {
fprintf(stderr, "malloc(%d) FAILED\n", (int)sizeof(struct lan_addr_s));
break;
}
if(parselanaddr(lan_addr, argv[++i]) != 0) {
fprintf(stderr, "can't parse \"%s\" as a valid address or interface name\n", argv[i]);
free(lan_addr);
} else {
LIST_INSERT_HEAD(&lan_addrs, lan_addr, list);
}
} else if(0==strcmp(argv[i], "-d"))
if(0==strcmp(argv[i], "-d"))
debug_flag = 1;
else if(0==strcmp(argv[i], "-s"))
sockpath = argv[++i];
else if(0==strcmp(argv[i], "-p"))
pidfilename = argv[++i];
#ifdef ENABLE_IPV6
else if(0==strcmp(argv[i], "-6"))
ipv6 = 1;
#endif /* ENABLE_IPV6 */
else {
if((i + 1) >= argc) {
fprintf(stderr, "option %s needs an argument.\n", argv[i]);
break;
}
if(0==strcmp(argv[i], "-i")) {
lan_addr = malloc(sizeof(struct lan_addr_s));
if(lan_addr == NULL) {
fprintf(stderr, "malloc(%d) FAILED\n", (int)sizeof(struct lan_addr_s));
break;
}
if(parselanaddr(lan_addr, argv[++i]) != 0) {
fprintf(stderr, "can't parse \"%s\" as a valid address or interface name\n", argv[i]);
free(lan_addr);
} else {
LIST_INSERT_HEAD(&lan_addrs, lan_addr, list);
}
} else if(0==strcmp(argv[i], "-s"))
sockpath = argv[++i];
else if(0==strcmp(argv[i], "-p"))
pidfilename = argv[++i];
else if(0==strcmp(argv[i], "-t"))
ttl = (unsigned char)atoi(argv[++i]);
else if(0==strcmp(argv[i], "-f"))
searched_device = argv[++i];
else
fprintf(stderr, "unknown commandline option %s.\n", argv[i]);
}
}
if(lan_addrs.lh_first == NULL)
{
@ -1099,7 +1134,8 @@ int main(int argc, char * * argv)
#ifdef ENABLE_IPV6
"[-6] "
#endif /* ENABLE_IPV6 */
"[-s socket] [-p pidfile] "
"[-s socket] [-p pidfile] [-t TTL] "
"-f device "
"-i <interface> [-i <interface2>] ...\n",
argv[0]);
fprintf(stderr,
@ -1143,7 +1179,7 @@ int main(int argc, char * * argv)
/* open route/interface config changes socket */
s_ifacewatch = OpenAndConfInterfaceWatchSocket();
/* open UDP socket(s) for receiving SSDP packets */
s_ssdp = OpenAndConfSSDPReceiveSocket(0);
s_ssdp = OpenAndConfSSDPReceiveSocket(0, ttl);
if(s_ssdp < 0)
{
syslog(LOG_ERR, "Cannot open socket for receiving SSDP messages, exiting");
@ -1152,7 +1188,7 @@ int main(int argc, char * * argv)
}
#ifdef ENABLE_IPV6
if(ipv6) {
s_ssdp6 = OpenAndConfSSDPReceiveSocket(1);
s_ssdp6 = OpenAndConfSSDPReceiveSocket(1, ttl);
if(s_ssdp6 < 0)
{
syslog(LOG_ERR, "Cannot open socket for receiving SSDP messages (IPv6), exiting");
@ -1219,9 +1255,9 @@ int main(int argc, char * * argv)
/* send M-SEARCH ssdp:all Requests */
if(s_ssdp >= 0)
ssdpDiscoverAll(s_ssdp, 0);
ssdpDiscover(s_ssdp, 0, searched_device);
if(s_ssdp6 >= 0)
ssdpDiscoverAll(s_ssdp6, 1);
ssdpDiscover(s_ssdp6, 1, searched_device);
/* Main loop */
while(!quitting) {
@ -1287,7 +1323,7 @@ int main(int argc, char * * argv)
/* Parse and process the packet received */
/*printf("%.*s", n, buf);*/
i = ParseSSDPPacket(s_ssdp6, buf, n,
(struct sockaddr *)&sendername6);
(struct sockaddr *)&sendername6, searched_device);
syslog(LOG_DEBUG, "** i=%d deltadev=%d **", i, deltadev);
if(i==0 || (i*deltadev < 0))
{
@ -1321,7 +1357,7 @@ int main(int argc, char * * argv)
/* Parse and process the packet received */
/*printf("%.*s", n, buf);*/
i = ParseSSDPPacket(s_ssdp, buf, n,
(struct sockaddr *)&sendername);
(struct sockaddr *)&sendername, searched_device);
syslog(LOG_DEBUG, "** i=%d deltadev=%d **", i, deltadev);
if(i==0 || (i*deltadev < 0))
{

View File

@ -8,7 +8,7 @@ MINISSDPD=/usr/sbin/minissdpd
PIDFILE=/var/run/minissdpd.pid
# get default interface
IF=`route | grep default |awk -- '{ print $8 }'`
ARGS="-i `ifconfig $IF|grep 'inet adr'|sed 's/.\+inet adr:\([0-9.]\+\).\+/\1/'`"
ARGS="-i $IF"
test -f $MINISSDPD || exit 0

View File

@ -1,7 +1,7 @@
/* $Id: openssdpsocket.c,v 1.15 2014/11/28 16:20:58 nanard Exp $ */
/* $Id: openssdpsocket.c,v 1.17 2015/08/06 14:05:37 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2014 Thomas Bernard
* (c) 2006-2015 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
@ -102,10 +102,11 @@ AddDropMulticastMembership(int s, struct lan_addr_s * lan_addr, int ipv6, int dr
}
int
OpenAndConfSSDPReceiveSocket(int ipv6)
OpenAndConfSSDPReceiveSocket(int ipv6, unsigned char ttl)
{
int s;
int opt = 1;
unsigned char loopchar = 0;
#ifdef ENABLE_IPV6
struct sockaddr_storage sockname;
#else /* ENABLE_IPV6 */
@ -192,10 +193,20 @@ OpenAndConfSSDPReceiveSocket(int ipv6)
}
else
#endif /* SSDP_LISTEN_ON_SPECIFIC_ADDR */
sockname.sin_addr.s_addr = htonl(INADDR_ANY);
sockname.sin_addr.s_addr = htonl(INADDR_ANY);
sockname_len = sizeof(struct sockaddr_in);
#endif /* ENABLE_IPV6 */
if(setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loopchar, sizeof(loopchar)) < 0)
{
syslog(LOG_WARNING, "setsockopt(IP_MULTICAST_LOOP): %m");
}
if(setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0)
{
syslog(LOG_WARNING, "setsockopt(IP_MULTICAST_TTL): %m");
}
if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0)
{
syslog(LOG_WARNING, "setsockopt(SO_REUSEADDR): %m");

View File

@ -1,7 +1,7 @@
/* $Id: openssdpsocket.h,v 1.6 2014/11/28 16:20:58 nanard Exp $ */
/* $Id: openssdpsocket.h,v 1.7 2015/07/21 15:39:38 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2014 Thomas Bernard
* (c) 2006-2015 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
#ifndef OPENSSDPSOCKET_H_INCLUDED
@ -13,10 +13,11 @@
* Open a socket and configure it for receiving SSDP packets
*
* @param ipv6 open INET6 or INET socket
* @param ttl multicast TTL
* @return socket
*/
int
OpenAndConfSSDPReceiveSocket(int ipv6);
OpenAndConfSSDPReceiveSocket(int ipv6, unsigned char ttl);
/**
* Add or Drop the multicast membership for SSDP on the interface

View File

@ -1,10 +1,11 @@
/* $Id: testminissdpd.c,v 1.8 2014/02/28 18:38:21 nanard Exp $ */
/* $Id: testminissdpd.c,v 1.12 2015/08/06 13:16:59 nanard Exp $ */
/* Project : miniupnp
* website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* Author : Thomas BERNARD
* copyright (c) 2005-2014 Thomas Bernard
* copyright (c) 2005-2015 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENCE file. */
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
@ -17,6 +18,19 @@
do { n = (n << 7) | (*p & 0x7f); } \
while(*(p++)&0x80);
void printversion(const unsigned char * resp, int n)
{
int l;
const unsigned char * p;
p = resp;
DECODELENGTH(l, p);
if(resp + n < p + l) {
printf("get version error\n");
}
printf("MiniSSDPd version : %.*s\n", l, p);
}
void printresponse(const unsigned char * resp, int n)
{
int i, l;
@ -24,10 +38,22 @@ void printresponse(const unsigned char * resp, int n)
const unsigned char * p;
if(n == 0)
return;
for(i=0; i<n; i++)
printf("%02x ", resp[i]);
printf("\n");
nresp = resp[0];
/* first, hexdump the response : */
for(i = 0; i < n; i += 16) {
printf("%06x | ", i);
for(l = i; l < n && l < (i + 16); l++)
printf("%02x ", resp[l]);
while(l < (i + 16)) {
printf(" ");
l++;
}
printf("| ");
for(l = i; l < n && l < (i + 16); l++)
putchar((resp[l] >= ' ' && resp[l] < 128) ? resp[l] : '.');
putchar('\n');
}
/* now parse and display all devices of response */
nresp = resp[0]; /* 1st byte : number of devices in response */
p = resp + 1;
for(i = 0; i < (int)nresp; i++) {
if(p >= resp + n)
@ -36,7 +62,7 @@ void printresponse(const unsigned char * resp, int n)
DECODELENGTH(l, p);
if(p + l > resp + n)
goto error;
printf("%d - %.*s\n", i, l, p);
printf("%d - %.*s\n", i, l, p); /* URL */
p += l;
if(p >= resp + n)
goto error;
@ -44,7 +70,7 @@ void printresponse(const unsigned char * resp, int n)
DECODELENGTH(l, p);
if(p + l > resp + n)
goto error;
printf(" %.*s\n", l, p);
printf(" %.*s\n", l, p); /* ST */
p += l;
if(p >= resp + n)
goto error;
@ -52,7 +78,7 @@ void printresponse(const unsigned char * resp, int n)
DECODELENGTH(l, p);
if(p + l > resp + n)
goto error;
printf(" %.*s\n", l, p);
printf(" %.*s\n", l, p); /* USN */
p += l;
}
return;
@ -61,7 +87,7 @@ error:
}
#define SENDCOMMAND(command, size) write(s, command, size); \
printf("Command written type=%u\n", (unsigned)command[0]);
printf("Command written type=%u\n", (unsigned char)command[0]);
int connect_unix_socket(const char * sockpath)
{
@ -72,11 +98,11 @@ int connect_unix_socket(const char * sockpath)
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, sockpath, sizeof(addr.sun_path));
if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) {
fprintf(stderr, "connecting to %s\n", addr.sun_path);
fprintf(stderr, "connecting to %s : ", addr.sun_path);
perror("connect");
exit(1);
}
printf("Connected.\n");
printf("Connected to %s\n", addr.sun_path);
return s;
}
@ -84,16 +110,24 @@ int connect_unix_socket(const char * sockpath)
int
main(int argc, char * * argv)
{
char command0[] = { 0x00, 0x00 };
char command1[] = "\x01\x00urn:schemas-upnp-org:device:InternetGatewayDevice";
char command2[] = "\x02\x00uuid:fc4ec57e-b051-11db-88f8-0060085db3f6::upnp:rootdevice";
char command3[] = { 0x03, 0x00 };
/* old versions of minissdpd would reject a command with
* a zero length string argument */
char command3compat[] = "\x03\x00ssdp:all";
char command4[] = "\x04\x00test:test:test";
char bad_command[] = { 0xff, 0xff };
char overflow[] = { 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
int s;
int i;
unsigned char buf[16*1024];
void * tmp;
unsigned char * resp = NULL;
size_t respsize = 0;
unsigned char buf[4096];
ssize_t n;
int total = 0;
const char * sockpath = "/var/run/minissdpd.sock";
for(i=0; i<argc-1; i++) {
@ -102,10 +136,22 @@ main(int argc, char * * argv)
}
command1[1] = sizeof(command1) - 3;
command2[1] = sizeof(command2) - 3;
command3compat[1] = sizeof(command3compat) - 3;
command4[1] = sizeof(command4) - 3;
s = connect_unix_socket(sockpath);
SENDCOMMAND(command1, sizeof(command1) - 1);
n = SENDCOMMAND(command0, sizeof(command0));
n = read(s, buf, sizeof(buf));
printf("Response received %d bytes\n", (int)n);
if(n > 0) {
printversion(buf, n);
} else {
printf("Command 0 (get version) not supported\n");
close(s);
s = connect_unix_socket(sockpath);
}
n = SENDCOMMAND(command1, sizeof(command1) - 1);
n = read(s, buf, sizeof(buf));
printf("Response received %d bytes\n", (int)n);
printresponse(buf, n);
@ -114,7 +160,7 @@ main(int argc, char * * argv)
s = connect_unix_socket(sockpath);
}
SENDCOMMAND(command2, sizeof(command2) - 1);
n = SENDCOMMAND(command2, sizeof(command2) - 1);
n = read(s, buf, sizeof(buf));
printf("Response received %d bytes\n", (int)n);
printresponse(buf, n);
@ -123,7 +169,51 @@ main(int argc, char * * argv)
s = connect_unix_socket(sockpath);
}
SENDCOMMAND(command3, sizeof(command3));
buf[0] = 0; /* Slight hack for printing num devices when 0 */
n = SENDCOMMAND(command3, sizeof(command3));
n = read(s, buf, sizeof(buf));
if(n == 0) {
printf("command3 failed, testing compatible one\n");
close(s);
s = connect_unix_socket(sockpath);
n = SENDCOMMAND(command3compat, sizeof(command3compat) - 1);
n = read(s, buf, sizeof(buf));
}
printf("Response received %d bytes\n", (int)n);
printf("Number of devices %d\n", (int)buf[0]);
while(n > 0) {
tmp = realloc(resp, respsize + n);
if(tmp == NULL) {
fprintf(stderr, "memory allocation error\n");
break;
}
resp = tmp;
respsize += n;
if (n > 0) {
memcpy(resp + total, buf, n);
total += n;
}
if (n < (ssize_t)sizeof(buf)) {
break;
}
n = read(s, buf, sizeof(buf));
printf("response received %d bytes\n", (int)n);
}
if(resp != NULL) {
printresponse(resp, total);
free(resp);
resp = NULL;
}
if(n == 0) {
close(s);
s = connect_unix_socket(sockpath);
}
n = SENDCOMMAND(command4, sizeof(command4));
/* no response for request type 4 */
n = SENDCOMMAND(bad_command, sizeof(bad_command));
n = read(s, buf, sizeof(buf));
printf("Response received %d bytes\n", (int)n);
printresponse(buf, n);
@ -132,18 +222,7 @@ main(int argc, char * * argv)
s = connect_unix_socket(sockpath);
}
SENDCOMMAND(command4, sizeof(command4));
SENDCOMMAND(bad_command, sizeof(bad_command));
n = read(s, buf, sizeof(buf));
printf("Response received %d bytes\n", (int)n);
printresponse(buf, n);
if(n == 0) {
close(s);
s = connect_unix_socket(sockpath);
}
SENDCOMMAND(overflow, sizeof(overflow));
n = SENDCOMMAND(overflow, sizeof(overflow));
n = read(s, buf, sizeof(buf));
printf("Response received %d bytes\n", (int)n);
printresponse(buf, n);
@ -151,4 +230,3 @@ main(int argc, char * * argv)
close(s);
return 0;
}

14
minissdpd/testminissdpd.sh Executable file
View File

@ -0,0 +1,14 @@
#!/bin/sh
# $Id: testminissdpd.sh,v 1.2 2015/09/03 18:31:25 nanard Exp $
# (c) 2015 Thomas Bernard
OS=`uname -s`
IF=lo
if [ "$OS" = "Darwin" ] ; then
IF=lo0
fi
SOCKET=`mktemp -t minissdpdsocketXXXXXX`
PID="${SOCKET}.pid"
./minissdpd -s $SOCKET -p $PID -i $IF || exit 1
./testminissdpd -s $SOCKET || exit 2
kill `cat $PID`

View File

@ -8,7 +8,7 @@
# $ INSTALLPREFIX=/usr/local make install
# or
# make install (will go to /usr/bin, /usr/lib, etc...)
CC = gcc
CC ?= gcc
#AR = gar
CFLAGS = -O0 -g -DDEBUG
#CFLAGS = -O
@ -71,7 +71,8 @@ install: $(LIBRARY) $(SHAREDLIBRARY)
$(INSTALL) -d $(INSTALLDIRLIB)
$(INSTALL) -m 644 $(LIBRARY) $(INSTALLDIRLIB)
$(INSTALL) -m 644 $(SHAREDLIBRARY) $(INSTALLDIRLIB)/$(SONAME)
$(INSTALL) -m 755 upnpc-shared $(INSTALLDIRBIN)/upnpc
$(INSTALL) -d $(INSTALLDIRBIN)
$(INSTALL) -m 755 $(EXECUTABLES) $(INSTALLDIRBIN)
ln -fs $(SONAME) $(INSTALLDIRLIB)/$(SHAREDLIBRARY)
cleaninstall:
@ -94,8 +95,8 @@ upnpc-static: upnpc.o $(LIBRARY)
upnpc-shared: upnpc.o $(SHAREDLIBRARY)
$(CC) -o $@ $^
#testasync: testasync.o libminiupnpc-async.a
testasync: testasync.o -lminiupnpc-async
testasync: testasync.o libminiupnpc-async.a
#testasync: testasync.o -lminiupnpc-async
# DO NOT DELETE THIS LINE -- make depend depends on it.

View File

@ -1,8 +1,8 @@
/* $Id: igd_desc_parse.c,v 1.16 2014/11/17 17:19:13 nanard Exp $ */
/* $Id: igd_desc_parse.c,v 1.17 2015/09/15 13:30:04 nanard Exp $ */
/* Project : miniupnp
* http://miniupnp.free.fr/
* Author : Thomas Bernard
* Copyright (c) 2005-2014 Thomas Bernard
* Copyright (c) 2005-2015 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. */
@ -15,7 +15,9 @@
void IGDstartelt(void * d, const char * name, int l)
{
struct IGDdatas * datas = (struct IGDdatas *)d;
memcpy( datas->cureltname, name, l);
if(l >= MINIUPNPC_URL_MAXSIZE)
l = MINIUPNPC_URL_MAXSIZE-1;
memcpy(datas->cureltname, name, l);
datas->cureltname[l] = '\0';
datas->level++;
if( (l==7) && !memcmp(name, "service", l) ) {

View File

@ -1,7 +1,7 @@
/* $Id: upnpreplyparse.c,v 1.18 2014/11/05 05:36:08 nanard Exp $ */
/* $Id: upnpreplyparse.c,v 1.19 2015/07/15 10:29:11 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2014 Thomas Bernard
* (c) 2006-2015 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
@ -40,6 +40,15 @@ NameValueParserEndElt(void * d, const char * name, int l)
/* standard case. Limited to n chars strings */
l = data->cdatalen;
nv = malloc(sizeof(struct NameValue));
if(nv == NULL)
{
/* malloc error */
#ifdef DEBUG
fprintf(stderr, "%s: error allocating memory",
"NameValueParserEndElt");
#endif /* DEBUG */
return;
}
if(l>=(int)sizeof(nv->value))
l = sizeof(nv->value) - 1;
strncpy(nv->name, data->curelt, 64);
@ -72,6 +81,10 @@ NameValueParserGetData(void * d, const char * datas, int l)
if(!data->portListing)
{
/* malloc error */
#ifdef DEBUG
fprintf(stderr, "%s: error allocating memory",
"NameValueParserGetData");
#endif /* DEBUG */
return;
}
memcpy(data->portListing, datas, l);
@ -180,5 +193,5 @@ DisplayNameValueList(char * buffer, int bufsize)
}
ClearNameValueList(&pdata);
}
#endif
#endif /* DEBUG */

View File

@ -1,6 +1,7 @@
# $Id: Makefile,v 1.7 2014/11/28 13:14:19 nanard Exp $
OS = $(shell uname -s)
PKG_CONFIG ?= pkg-config
CFLAGS = -O0 -g -DDEBUG
# libevent debug
@ -10,18 +11,25 @@ CFLAGS += -fPIC
CFLAGS += -ansi
CFLAGS += -Wall -W
CFLAGS += -D_BSD_SOURCE
ifneq ($(OS), Darwin)
ifneq ($(OS), FreeBSD)
CFLAGS += -D_POSIX_C_SOURCE=200112L
CFLAGS += -I/usr/local/include
endif
endif
#CFLAGS += -I/usr/local/include
CFLAGS += $(shell $(PKG_CONFIG) --cflags libevent)
#CFLAGS += -DENABLE_UPNP_EVENTS
LDFLAGS = -levent
LDFLAGS += -L/usr/local/lib
#LDLIBS = -levent
LDLIBS = $(shell $(PKG_CONFIG) --libs-only-l libevent)
#LDFLAGS += -L/usr/local/lib
LDFLAGS += $(shell $(PKG_CONFIG) --libs-only-L libevent)
ifeq ($(OS), Darwin)
CFLAGS += -D_DARWIN_C_SOURCE
CFLAGS += -I/opt/local/include
LDFLAGS += -L/opt/local/lib
#CFLAGS += -I/opt/local/include
#LDFLAGS += -L/opt/local/lib
endif
LIB = libminiupnpc-ev.a
@ -43,6 +51,7 @@ all: $(EXECUTABLE)
clean:
$(RM) $(OBJS)
$(RM) $(EXECUTABLE)
$(RM) $(LIB)
upnpc-libevent: upnpc-libevent.o $(LIB)

View File

@ -1,8 +1,8 @@
/* $Id: igd_desc_parse.c,v 1.16 2014/11/17 17:19:13 nanard Exp $ */
/* $Id: igd_desc_parse.c,v 1.17 2015/09/15 13:30:04 nanard Exp $ */
/* Project : miniupnp
* http://miniupnp.free.fr/
* Author : Thomas Bernard
* Copyright (c) 2005-2014 Thomas Bernard
* Copyright (c) 2005-2015 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. */
@ -15,7 +15,9 @@
void IGDstartelt(void * d, const char * name, int l)
{
struct IGDdatas * datas = (struct IGDdatas *)d;
memcpy( datas->cureltname, name, l);
if(l >= MINIUPNPC_URL_MAXSIZE)
l = MINIUPNPC_URL_MAXSIZE-1;
memcpy(datas->cureltname, name, l);
datas->cureltname[l] = '\0';
datas->level++;
if( (l==7) && !memcmp(name, "service", l) ) {

View File

@ -1,4 +1,4 @@
/* $Id: miniupnpc-libevent.c,v 1.25 2015/02/05 17:56:38 nanard Exp $ */
/* $Id: miniupnpc-libevent.c,v 1.27 2015/07/22 13:51:09 nanard Exp $ */
/* miniupnpc-libevent
* Copyright (c) 2008-2014, Thomas BERNARD <miniupnp@free.fr>
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
@ -651,6 +651,14 @@ static int upnpc_send_soap_request(upnpc_device_t * p, const char * url,
}
#ifdef ENABLE_UPNP_EVENTS
#define EVHTTP_REQ_NOTIFY ((EVHTTP_REQ_MAX) << 1)
#define EVHTTP_REQ_SUBSCRIBE ((EVHTTP_REQ_NOTIFY) << 1)
static const struct evhttp_extended_methods ext_methods[] = {
{"NOTIFY", EVHTTP_REQ_NOTIFY, EVHTTP_METHOD_HAS_BODY},
{"SUBSCRIBE", EVHTTP_REQ_SUBSCRIBE, EVHTTP_METHOD_HAS_BODY},
{NULL, 0, 0}
};
void upnpc_event_conn_req(struct evhttp_request * req, void * data)
{
size_t len;
@ -721,11 +729,18 @@ int upnpc_init(upnpc_t * p, struct event_base * base, const char * multicastif,
p->ready_cb = ready_cb;
p->soap_cb = soap_cb;
p->cb_data = cb_data;
p->ttl = 2;
/* open the socket for SSDP */
p->ssdp_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(p->ssdp_socket < 0) {
return UPNPC_ERR_SOCKET_FAILED;
}
/* set multicast TTL */
if(setsockopt(p->ssdp_socket, IPPROTO_IP, IP_MULTICAST_TTL, &p->ttl, sizeof(p->ttl) < 0))
{
/* not a fatal error */
debug_printf("setsockopt(%d, ..., IP_MULTICAST_TTL, ...) FAILED\n", p->ssdp_socket);
}
/* set REUSEADDR */
#ifdef _WIN32
if(setsockopt(p->ssdp_socket, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt)) < 0) {
@ -887,6 +902,7 @@ int upnpc_event_subscribe(upnpc_device_t * p)
debug_printf("evhttp_new() FAILED\n");
return -1;
}
evhttp_set_extended_methods(p->parent->http_server, ext_methods);
evhttp_set_allowed_methods(p->parent->http_server, EVHTTP_REQ_NOTIFY);
evhttp_set_cb(p->parent->http_server, "/evt_conn", upnpc_event_conn_req, p);
if(evhttp_bind_socket(p->parent->http_server, p->parent->local_address, p->parent->local_port) < 0) {
@ -905,6 +921,7 @@ int upnpc_event_subscribe(upnpc_device_t * p)
if(p->soap_conn == NULL) {
p->soap_conn = evhttp_connection_base_new(p->parent->base, NULL, hostname, port);
}
evhttp_connection_set_extended_methods(p->soap_conn, ext_methods);
req = evhttp_request_new(upnpc_subscribe_response, p);
headers = evhttp_request_get_output_headers(req);
/*buffer = evhttp_request_get_output_buffer(req);*/

View File

@ -1,6 +1,6 @@
/* $Id: miniupnpc-libevent.h,v 1.11 2014/12/02 13:33:42 nanard Exp $ */
/* $Id: miniupnpc-libevent.h,v 1.13 2015/07/22 13:48:37 nanard Exp $ */
/* miniupnpc-libevent
* Copyright (c) 2008-2014, Thomas BERNARD <miniupnp@free.fr>
* Copyright (c) 2008-2015, Thomas BERNARD <miniupnp@free.fr>
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
*
* Permission to use, copy, modify, and/or distribute this software for any
@ -88,6 +88,7 @@ struct upnpc {
#endif /* ENABLE_UPNP_EVENTS */
char * local_address;
uint16_t local_port;
unsigned char ttl;
};
int upnpc_init(upnpc_t * p, struct event_base * base, const char * multicastif,

View File

@ -1,7 +1,7 @@
/* $Id: upnpreplyparse.c,v 1.18 2014/11/05 05:36:08 nanard Exp $ */
/* $Id: upnpreplyparse.c,v 1.19 2015/07/15 10:29:11 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2014 Thomas Bernard
* (c) 2006-2015 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
@ -40,6 +40,15 @@ NameValueParserEndElt(void * d, const char * name, int l)
/* standard case. Limited to n chars strings */
l = data->cdatalen;
nv = malloc(sizeof(struct NameValue));
if(nv == NULL)
{
/* malloc error */
#ifdef DEBUG
fprintf(stderr, "%s: error allocating memory",
"NameValueParserEndElt");
#endif /* DEBUG */
return;
}
if(l>=(int)sizeof(nv->value))
l = sizeof(nv->value) - 1;
strncpy(nv->name, data->curelt, 64);
@ -72,6 +81,10 @@ NameValueParserGetData(void * d, const char * datas, int l)
if(!data->portListing)
{
/* malloc error */
#ifdef DEBUG
fprintf(stderr, "%s: error allocating memory",
"NameValueParserGetData");
#endif /* DEBUG */
return;
}
memcpy(data->portListing, datas, l);
@ -180,5 +193,5 @@ DisplayNameValueList(char * buffer, int bufsize)
}
ClearNameValueList(&pdata);
}
#endif
#endif /* DEBUG */

View File

@ -2,7 +2,7 @@ cmake_minimum_required (VERSION 2.6)
project (miniupnpc C)
set (MINIUPNPC_VERSION 1.9)
set (MINIUPNPC_API_VERSION 12)
set (MINIUPNPC_API_VERSION 14)
if (NOT CMAKE_BUILD_TYPE)
if (WIN32)
@ -70,9 +70,11 @@ set (MINIUPNPC_SOURCES
miniupnpc.c
minixml.c
minisoap.c
minissdpc.c
miniwget.c
upnpc.c
upnpcommands.c
upnpdev.c
upnpreplyparse.c
upnperrors.c
connecthostport.c
@ -164,9 +166,10 @@ install (FILES
igd_desc_parse.h
upnpreplyparse.h
upnperrors.h
upnpdev.h
miniupnpctypes.h
portlistingparse.h
declspec.h
miniupnpc_declspec.h
DESTINATION include/miniupnpc
)

View File

@ -1,6 +1,38 @@
$Id: Changelog.txt,v 1.203 2015/04/27 15:50:19 nanard Exp $
$Id: Changelog.txt,v 1.215 2015/10/01 09:26:11 nanard Exp $
miniUPnP client Changelog.
2015/09/15:
Fix buffer overflow in igd_desc_parse.c/IGDstartelt()
Discovered by Aleksandar Nikolic of Cisco Talos
2015/08/28:
move ssdpDiscoverDevices() to minissdpc.c
2015/08/27:
avoid unix socket leak in getDevicesFromMiniSSDPD()
2015/08/16:
Also accept "Up" as ConnectionStatus value
2015/07/23:
split getDevicesFromMiniSSDPD
add ttl argument to upnpDiscover() functions
increments API_VERSION to 14
2015/07/22:
Read USN from SSDP messages.
2015/07/15:
Check malloc/calloc
2015/06/16:
update getDevicesFromMiniSSDPD() to process longer minissdpd
responses
2015/05/22:
add searchalltypes param to upnpDiscoverDevices()
increments API_VERSION to 13
2015/04/30:
upnpc: output version on the terminal

View File

@ -1,4 +1,4 @@
# $Id: Makefile,v 1.120 2015/01/07 09:07:32 nanard Exp $
# $Id: Makefile,v 1.126 2015/08/28 12:14:18 nanard Exp $
# MiniUPnP Project
# http://miniupnp.free.fr/
# http://miniupnp.tuxfamily.org/
@ -35,8 +35,15 @@ CFLAGS += -W -Wstrict-prototypes
CFLAGS += -fno-common
CFLAGS += -DMINIUPNPC_SET_SOCKET_TIMEOUT
CFLAGS += -DMINIUPNPC_GET_SRC_ADDR
CFLAGS += -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200112L
CFLAGS += -ansi
CFLAGS += -D_BSD_SOURCE
CFLAGS += -D_DEFAULT_SOURCE
ifneq ($(OS), FreeBSD)
ifneq ($(OS), Darwin)
#CFLAGS += -D_POSIX_C_SOURCE=200112L
CFLAGS += -D_XOPEN_SOURCE=600
endif
endif
#CFLAGS += -ansi
# -DNO_GETADDRINFO
INSTALL = install
SH = /bin/sh
@ -46,29 +53,32 @@ JAVA = java
#JNAERATOR = jnaerator-0.9.8-shaded.jar
#JNAERATORARGS = -library miniupnpc
#JNAERATOR = jnaerator-0.10-shaded.jar
JNAERATOR = jnaerator-0.11-shaded.jar
#JNAERATOR = jnaerator-0.11-shaded.jar
# https://repo1.maven.org/maven2/com/nativelibs4java/jnaerator/0.12/jnaerator-0.12-shaded.jar
JNAERATOR = jnaerator-0.12-shaded.jar
JNAERATORARGS = -mode StandaloneJar -runtime JNAerator -library miniupnpc
JNAERATORBASEURL = http://jnaerator.googlecode.com/files/
#JNAERATORBASEURL = http://jnaerator.googlecode.com/files/
JNAERATORBASEURL = https://repo1.maven.org/maven2/com/nativelibs4java/jnaerator/0.12
ifeq (SunOS, $(OS))
LDFLAGS=-lsocket -lnsl -lresolv
endif
# APIVERSION is used to build SONAME
APIVERSION = 12
APIVERSION = 14
SRCS = igd_desc_parse.c miniupnpc.c minixml.c minisoap.c miniwget.c \
upnpc.c upnpcommands.c upnpreplyparse.c testminixml.c \
minixmlvalid.c testupnpreplyparse.c minissdpc.c \
upnperrors.c testigddescparse.c testminiwget.c \
connecthostport.c portlistingparse.c receivedata.c \
testportlistingparse.c miniupnpcmodule.c \
upnpdev.c testportlistingparse.c miniupnpcmodule.c \
minihttptestserver.c \
listdevices.c
LIBOBJS = miniwget.o minixml.o igd_desc_parse.o minisoap.o \
miniupnpc.o upnpreplyparse.o upnpcommands.o upnperrors.o \
connecthostport.o portlistingparse.o receivedata.o
connecthostport.o portlistingparse.o receivedata.o upnpdev.o
ifneq ($(OS), AmigaOS)
CFLAGS := -fPIC $(CFLAGS)
@ -81,7 +91,8 @@ OBJS = $(patsubst %.c,%.o,$(SRCS))
HEADERS = miniupnpc.h miniwget.h upnpcommands.h igd_desc_parse.h \
upnpreplyparse.h upnperrors.h miniupnpctypes.h \
portlistingparse.h \
declspec.h
upnpdev.h \
miniupnpc_declspec.h
# library names
LIBRARY = libminiupnpc.a
@ -292,7 +303,7 @@ jnaerator-%.jar:
jar: $(SHAREDLIBRARY) $(JNAERATOR)
$(JAVA) -jar $(JNAERATOR) $(JNAERATORARGS) \
miniupnpc.h declspec.h upnpcommands.h upnpreplyparse.h \
miniupnpc.h miniupnpc_declspec.h upnpcommands.h upnpreplyparse.h \
igd_desc_parse.h miniwget.h upnperrors.h $(SHAREDLIBRARY) \
-package fr.free.miniupnp -o . -jar java/miniupnpc_$(JARSUFFIX).jar -v
@ -325,33 +336,40 @@ minihttptestserver: minihttptestserver.o
# DO NOT DELETE THIS LINE -- make depend depends on it.
igd_desc_parse.o: igd_desc_parse.h
miniupnpc.o: miniupnpc.h declspec.h igd_desc_parse.h minissdpc.h miniwget.h
miniupnpc.o: minisoap.h minixml.h upnpcommands.h upnpreplyparse.h
miniupnpc.o: portlistingparse.h miniupnpctypes.h connecthostport.h
miniupnpc.o: receivedata.h
miniupnpc.o: miniupnpc.h miniupnpc_declspec.h igd_desc_parse.h upnpdev.h
miniupnpc.o: minissdpc.h miniwget.h minisoap.h minixml.h upnpcommands.h
miniupnpc.o: upnpreplyparse.h portlistingparse.h miniupnpctypes.h
miniupnpc.o: connecthostport.h
minixml.o: minixml.h
minisoap.o: minisoap.h miniupnpcstrings.h
miniwget.o: miniupnpcstrings.h miniwget.h declspec.h connecthostport.h
miniwget.o: receivedata.h
upnpc.o: miniwget.h declspec.h miniupnpc.h igd_desc_parse.h upnpcommands.h
upnpc.o: upnpreplyparse.h portlistingparse.h miniupnpctypes.h upnperrors.h
upnpcommands.o: upnpcommands.h upnpreplyparse.h portlistingparse.h declspec.h
upnpcommands.o: miniupnpctypes.h miniupnpc.h igd_desc_parse.h
miniwget.o: miniupnpcstrings.h miniwget.h miniupnpc_declspec.h
miniwget.o: connecthostport.h receivedata.h
upnpc.o: miniwget.h miniupnpc_declspec.h miniupnpc.h igd_desc_parse.h
upnpc.o: upnpdev.h upnpcommands.h upnpreplyparse.h portlistingparse.h
upnpc.o: miniupnpctypes.h upnperrors.h miniupnpcstrings.h
upnpcommands.o: upnpcommands.h upnpreplyparse.h portlistingparse.h
upnpcommands.o: miniupnpc_declspec.h miniupnpctypes.h miniupnpc.h
upnpcommands.o: igd_desc_parse.h upnpdev.h
upnpreplyparse.o: upnpreplyparse.h minixml.h
testminixml.o: minixml.h igd_desc_parse.h
minixmlvalid.o: minixml.h
testupnpreplyparse.o: upnpreplyparse.h
minissdpc.o: minissdpc.h miniupnpc.h declspec.h igd_desc_parse.h codelength.h
upnperrors.o: upnperrors.h declspec.h upnpcommands.h upnpreplyparse.h
upnperrors.o: portlistingparse.h miniupnpctypes.h miniupnpc.h
upnperrors.o: igd_desc_parse.h
testigddescparse.o: igd_desc_parse.h minixml.h miniupnpc.h declspec.h
testminiwget.o: miniwget.h declspec.h
minissdpc.o: minissdpc.h miniupnpc_declspec.h upnpdev.h miniupnpc.h
minissdpc.o: igd_desc_parse.h receivedata.h codelength.h
upnperrors.o: upnperrors.h miniupnpc_declspec.h upnpcommands.h
upnperrors.o: upnpreplyparse.h portlistingparse.h miniupnpctypes.h
upnperrors.o: miniupnpc.h igd_desc_parse.h upnpdev.h
testigddescparse.o: igd_desc_parse.h minixml.h miniupnpc.h
testigddescparse.o: miniupnpc_declspec.h upnpdev.h
testminiwget.o: miniwget.h miniupnpc_declspec.h
connecthostport.o: connecthostport.h
portlistingparse.o: portlistingparse.h declspec.h miniupnpctypes.h minixml.h
portlistingparse.o: portlistingparse.h miniupnpc_declspec.h miniupnpctypes.h
portlistingparse.o: minixml.h
receivedata.o: receivedata.h
testportlistingparse.o: portlistingparse.h declspec.h miniupnpctypes.h
miniupnpcmodule.o: miniupnpc.h declspec.h igd_desc_parse.h upnpcommands.h
miniupnpcmodule.o: upnpreplyparse.h portlistingparse.h miniupnpctypes.h
miniupnpcmodule.o: upnperrors.h
listdevices.o: miniupnpc.h declspec.h igd_desc_parse.h
upnpdev.o: upnpdev.h miniupnpc_declspec.h
testportlistingparse.o: portlistingparse.h miniupnpc_declspec.h
testportlistingparse.o: miniupnpctypes.h
miniupnpcmodule.o: miniupnpc.h miniupnpc_declspec.h igd_desc_parse.h
miniupnpcmodule.o: upnpdev.h upnpcommands.h upnpreplyparse.h
miniupnpcmodule.o: portlistingparse.h miniupnpctypes.h upnperrors.h
listdevices.o: miniupnpc.h miniupnpc_declspec.h igd_desc_parse.h upnpdev.h

View File

@ -1,7 +1,7 @@
# $Id: Makefile.mingw,v 1.18 2014/01/17 09:04:01 nanard Exp $
# $Id: Makefile.mingw,v 1.21 2015/09/18 12:45:16 nanard Exp $
# Miniupnp project.
# http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
# (c) 2005-2014 Thomas Bernard
# (c) 2005-2015 Thomas Bernard
# This Makefile is made for MinGW
#
CC = gcc
@ -12,8 +12,10 @@ LDLIBS = -lws2_32 -liphlpapi
# -liphlpapi is needed for GetBestRoute() and GetIpAddrTable()
PYTHON=\utils\python25\python
OBJS=miniwget.o minixml.o igd_desc_parse.o minisoap.o \
minissdpc.o \
miniupnpc.o upnpreplyparse.o upnpcommands.o upnperrors.o \
connecthostport.o portlistingparse.o receivedata.o
connecthostport.o portlistingparse.o receivedata.o \
upnpdev.o
OBJSDLL=$(addprefix dll/, $(OBJS))
all: init upnpc-static upnpc-shared testminixml libminiupnpc.a miniupnpc.dll
@ -71,9 +73,10 @@ wingenminiupnpcstrings.o: wingenminiupnpcstrings.c
miniupnpcstrings.h: miniupnpcstrings.h.in wingenminiupnpcstrings
wingenminiupnpcstrings $< $@
minixml.o: minixml.c minixml.h miniupnpcstrings.h
minixml.o: minixml.c minixml.h
upnpc.o: upnpc.c miniwget.h minisoap.h miniupnpc.h igd_desc_parse.h upnpreplyparse.h upnpcommands.h upnperrors.h
upnpc.o: upnpc.c miniwget.h minisoap.h miniupnpc.h igd_desc_parse.h
upnpc.o: upnpreplyparse.h upnpcommands.h upnperrors.h miniupnpcstrings.h
miniwget.o: miniwget.c miniwget.h miniupnpcstrings.h connecthostport.h
@ -89,3 +92,7 @@ upnpreplyparse.o: upnpreplyparse.c upnpreplyparse.h minixml.h
upnpcommands.o: upnpcommands.c upnpcommands.h upnpreplyparse.h miniupnpc.h portlistingparse.h
minissdpc.o: minissdpc.c minissdpc.h receivedata.h
upnpdev.o: upnpdev.c upnpdev.h

View File

@ -1,7 +1,21 @@
$Id: apiversions.txt,v 1.3 2014/01/31 13:14:32 nanard Exp $
$Id: apiversions.txt,v 1.7 2015/07/23 20:40:08 nanard Exp $
Differences in API between miniUPnPc versions
API version 14
miniupnpc.h
add ttl argument to upnpDiscover() upnpDiscoverAll() upnpDiscoverDevice()
upnpDiscoverDevices()
getDevicesFromMiniSSDPD() :
connectToMiniSSDPD() / disconnectFromMiniSSDPD()
requestDevicesFromMiniSSDPD() / receiveDevicesFromMiniSSDPD()
API version 13
miniupnpc.h:
add searchalltype param to upnpDiscoverDevices() function
updated macro :
#define MINIUPNPC_API_VERSION 13
API version 12
miniupnpc.h :
add upnpDiscoverAll() / upnpDiscoverDevice() / upnpDiscoverDevices()

View File

@ -1,7 +1,7 @@
/* $Id: codelength.h,v 1.3 2011/07/30 13:10:05 nanard Exp $ */
/* Project : miniupnp
* Author : Thomas BERNARD
* copyright (c) 2005-2011 Thomas Bernard
* copyright (c) 2005-2015 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENCE file. */
#ifndef CODELENGTH_H_INCLUDED
@ -10,10 +10,30 @@
/* Encode length by using 7bit per Byte :
* Most significant bit of each byte specifies that the
* following byte is part of the code */
/* n : unsigned
* p : unsigned char *
*/
#define DECODELENGTH(n, p) n = 0; \
do { n = (n << 7) | (*p & 0x7f); } \
while((*(p++)&0x80) && (n<(1<<25)));
/* n : unsigned
* READ : function/macro to read one byte (unsigned char)
*/
#define DECODELENGTH_READ(n, READ) \
n = 0; \
do { \
unsigned char c; \
READ(c); \
n = (n << 7) | (c & 0x07f); \
if(!(c&0x80)) break; \
} while(n<(1<<25));
/* n : unsigned
* p : unsigned char *
* p_limit : unsigned char *
*/
#define DECODELENGTH_CHECKLIMIT(n, p, p_limit) \
n = 0; \
do { \
@ -21,11 +41,14 @@
n = (n << 7) | (*(p) & 0x7f); \
} while((*((p)++)&0x80) && (n<(1<<25)));
/* n : unsigned
* p : unsigned char *
*/
#define CODELENGTH(n, p) if(n>=268435456) *(p++) = (n >> 28) | 0x80; \
if(n>=2097152) *(p++) = (n >> 21) | 0x80; \
if(n>=16384) *(p++) = (n >> 14) | 0x80; \
if(n>=128) *(p++) = (n >> 7) | 0x80; \
*(p++) = n & 0x7f;
#endif
#endif /* CODELENGTH_H_INCLUDED */

View File

@ -23,6 +23,10 @@
#define socklen_t int
#else /* #ifdef _WIN32 */
#include <unistd.h>
#include <sys/types.h>
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
#include <sys/time.h>
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
#include <sys/param.h>
#include <sys/select.h>
#include <errno.h>
@ -33,7 +37,6 @@
* during the connect() call */
#define MINIUPNPC_IGNORE_EINTR
#ifndef USE_GETHOSTBYNAME
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#endif /* #ifndef USE_GETHOSTBYNAME */

View File

@ -1,8 +1,8 @@
/* $Id: igd_desc_parse.c,v 1.16 2014/11/17 17:19:13 nanard Exp $ */
/* $Id: igd_desc_parse.c,v 1.17 2015/09/15 13:30:04 nanard Exp $ */
/* Project : miniupnp
* http://miniupnp.free.fr/
* Author : Thomas Bernard
* Copyright (c) 2005-2014 Thomas Bernard
* Copyright (c) 2005-2015 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. */
@ -15,7 +15,9 @@
void IGDstartelt(void * d, const char * name, int l)
{
struct IGDdatas * datas = (struct IGDdatas *)d;
memcpy( datas->cureltname, name, l);
if(l >= MINIUPNPC_URL_MAXSIZE)
l = MINIUPNPC_URL_MAXSIZE-1;
memcpy(datas->cureltname, name, l);
datas->cureltname[l] = '\0';
datas->level++;
if( (l==7) && !memcmp(name, "service", l) ) {

View File

@ -29,7 +29,7 @@ public class JavaBridgeTest {
return;
}
devlist = miniupnpc.upnpDiscover(UPNP_DELAY, (String) null, (String) null, 0, 0, IntBuffer.allocate(1));
devlist = miniupnpc.upnpDiscover(UPNP_DELAY, (String) null, (String) null, 0, 0, (byte)2, IntBuffer.allocate(1));
if (devlist != null) {
System.out.println("List of UPNP devices found on the network :");
for (UPNPDev device = devlist; device != null; device = device.pNext) {

View File

@ -1,34 +1,63 @@
/* $Id: listdevices.c,v 1.2 2014/11/17 09:50:56 nanard Exp $ */
/* $Id: listdevices.c,v 1.6 2015/07/23 20:40:08 nanard Exp $ */
/* Project : miniupnp
* Author : Thomas Bernard
* Copyright (c) 2013-2014 Thomas Bernard
* Copyright (c) 2013-2015 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifdef _WIN32
#include <winsock2.h>
#endif /* _WIN32 */
#include "miniupnpc.h"
int main(int argc, char * * argv)
{
const char * searched_device = NULL;
const char * * searched_devices = NULL;
const char * multicastif = 0;
const char * minissdpdpath = 0;
int ipv6 = 0;
unsigned char ttl = 2;
int error = 0;
struct UPNPDev * devlist = 0;
struct UPNPDev * dev;
int i;
#ifdef _WIN32
WSADATA wsaData;
int nResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if(nResult != NO_ERROR)
{
fprintf(stderr, "WSAStartup() failed.\n");
return -1;
}
#endif
for(i = 1; i < argc; i++) {
if(strcmp(argv[i], "-6") == 0)
ipv6 = 1;
else if(strcmp(argv[i], "-d") == 0) {
if(++i >= argc) {
fprintf(stderr, "-d option needs one argument\n");
fprintf(stderr, "%s option needs one argument\n", "-d");
return 1;
}
searched_device = argv[i];
} else if(strcmp(argv[i], "-t") == 0) {
if(++i >= argc) {
fprintf(stderr, "%s option needs one argument\n", "-t");
return 1;
}
ttl = (unsigned char)atoi(argv[i]);
} else if(strcmp(argv[i], "-l") == 0) {
if(++i >= argc) {
fprintf(stderr, "-l option needs at least one argument\n");
return 1;
}
searched_devices = (const char * *)(argv + i);
break;
} else if(strcmp(argv[i], "-m") == 0) {
if(++i >= argc) {
fprintf(stderr, "-m option needs one argument\n");
@ -36,11 +65,13 @@ int main(int argc, char * * argv)
}
multicastif = argv[i];
} else {
printf("usage : %s [options]\n", argv[0]);
printf("usage : %s [options] [-l <device1> <device2> ...]\n", argv[0]);
printf("options :\n");
printf(" -6 : use IPv6\n");
printf(" -d <device string> : search only for this type of device\n");
printf(" -m address/ifname : network interface to use for multicast\n");
printf(" -d <device string> : search only for this type of device\n");
printf(" -l <device1> <device2> ... : search only for theses types of device\n");
printf(" -t ttl : set multicast TTL. Default value is 2.\n");
printf(" -h : this help\n");
return 1;
}
@ -50,15 +81,24 @@ int main(int argc, char * * argv)
printf("searching UPnP device type %s\n", searched_device);
devlist = upnpDiscoverDevice(searched_device,
2000, multicastif, minissdpdpath,
0/*sameport*/, ipv6, &error);
0/*localport*/, ipv6, ttl, &error);
} else if(searched_devices) {
printf("searching UPnP device types :\n");
for(i = 0; searched_devices[i]; i++)
printf("\t%s\n", searched_devices[i]);
devlist = upnpDiscoverDevices(searched_devices,
2000, multicastif, minissdpdpath,
0/*localport*/, ipv6, ttl, &error, 1);
} else {
printf("searching all UPnP devices\n");
devlist = upnpDiscoverAll(2000, multicastif, minissdpdpath,
0/*sameport*/, ipv6, &error);
0/*localport*/, ipv6, ttl, &error);
}
if(devlist) {
for(dev = devlist; dev != NULL; dev = dev->pNext) {
printf("%-48s\t%s\n", dev->st, dev->descURL);
for(dev = devlist, i = 1; dev != NULL; dev = dev->pNext, i++) {
printf("%3d: %-48s\n", i, dev->st);
printf(" %s\n", dev->descURL);
printf(" %s\n", dev->usn);
}
freeUPNPDevlist(devlist);
} else {

View File

@ -1,4 +1,4 @@
/* $Id: minihttptestserver.c,v 1.17 2015/02/06 10:31:19 nanard Exp $ */
/* $Id: minihttptestserver.c,v 1.18 2015/07/15 12:41:15 nanard Exp $ */
/* Project : miniUPnP
* Author : Thomas Bernard
* Copyright (c) 2011-2015 Thomas Bernard
@ -104,6 +104,8 @@ char * build_chunked_response(int content_length, int * response_len)
/* allocate to have some margin */
buffer_length = 256 + content_length + (content_length >> 4);
response_buffer = malloc(buffer_length);
if(response_buffer == NULL)
return NULL;
*response_len = snprintf(response_buffer, buffer_length,
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
@ -112,6 +114,10 @@ char * build_chunked_response(int content_length, int * response_len)
/* build the content */
content_buffer = malloc(content_length);
if(content_buffer == NULL) {
free(response_buffer);
return NULL;
}
build_content(content_buffer, content_length);
/* chunk it */
@ -578,12 +584,16 @@ int main(int argc, char * * argv) {
if(f) {
char * buffer;
buffer = malloc(16*1024);
build_content(buffer, 16*1024);
i = fwrite(buffer, 1, 16*1024, f);
if(i != 16*1024) {
fprintf(stderr, "error writing to file %s : %dbytes written (out of %d)\n", expected_file_name, i, 16*1024);
if(buffer == NULL) {
fprintf(stderr, "memory allocation error\n");
} else {
build_content(buffer, 16*1024);
i = fwrite(buffer, 1, 16*1024, f);
if(i != 16*1024) {
fprintf(stderr, "error writing to file %s : %dbytes written (out of %d)\n", expected_file_name, i, 16*1024);
}
free(buffer);
}
free(buffer);
fclose(f);
} else {
fprintf(stderr, "error opening file %s for writing\n", expected_file_name);

View File

@ -1,67 +1,194 @@
/* $Id: minissdpc.c,v 1.15 2012/01/21 13:30:31 nanard Exp $ */
/* $Id: minissdpc.c,v 1.28 2015/09/18 13:05:39 nanard Exp $ */
/* Project : miniupnp
* Web : http://miniupnp.free.fr/
* Author : Thomas BERNARD
* copyright (c) 2005-2014 Thomas Bernard
* copyright (c) 2005-2015 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENCE file. */
/*#include <syslog.h>*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#if defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <io.h>
#include <iphlpapi.h>
#include <winsock.h>
#define snprintf _snprintf
#if !defined(_MSC_VER)
#include <stdint.h>
#endif
#else /* !defined(_MSC_VER) */
typedef unsigned short uint16_t;
#endif /* !defined(_MSC_VER) */
#ifndef strncasecmp
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
#define strncasecmp _memicmp
#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
#define strncasecmp memicmp
#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
#endif /* #ifndef strncasecmp */
#endif /* _WIN32 */
#if defined(__amigaos__) || defined(__amigaos4__)
#include <sys/socket.h>
#endif
#endif /* defined(__amigaos__) || defined(__amigaos4__) */
#if defined(__amigaos__)
#define uint16_t unsigned short
#endif
#endif /* defined(__amigaos__) */
/* Hack */
#define UNIX_PATH_LEN 108
struct sockaddr_un {
uint16_t sun_family;
char sun_path[UNIX_PATH_LEN];
};
#else
#else /* defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__) */
#include <strings.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <net/if.h>
#define closesocket close
#endif
#ifdef _WIN32
#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError());
#else
#define PRINT_SOCKET_ERROR(x) perror(x)
#endif
#if !defined(__DragonFly__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__APPLE__) && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__sun) && !defined(__GNU__) && !defined(__FreeBSD_kernel__)
#define HAS_IP_MREQN
#endif
#if defined(HAS_IP_MREQN) && defined(NEED_STRUCT_IP_MREQN)
/* Several versions of glibc don't define this structure,
* define it here and compile with CFLAGS NEED_STRUCT_IP_MREQN */
struct ip_mreqn
{
struct in_addr imr_multiaddr; /* IP multicast address of group */
struct in_addr imr_address; /* local IP address of interface */
int imr_ifindex; /* Interface index */
};
#endif
#if defined(__amigaos__) || defined(__amigaos4__)
/* Amiga OS specific stuff */
#define TIMEVAL struct timeval
#endif
#include "minissdpc.h"
#include "miniupnpc.h"
#include "receivedata.h"
#if !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__))
#include "codelength.h"
struct UPNPDev *
getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath)
getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath, int * error)
{
struct UPNPDev * tmp;
struct UPNPDev * devlist = NULL;
unsigned char buffer[4*1024]; /* is that enough ? */
ssize_t n;
unsigned char * p;
unsigned char * url;
unsigned int i;
unsigned int urlsize, stsize, usnsize, l;
int s;
int res;
s = connectToMiniSSDPD(socketpath);
if (s < 0) {
if (error)
*error = s;
return NULL;
}
res = requestDevicesFromMiniSSDPD(s, devtype);
if (res < 0) {
if (error)
*error = res;
} else {
devlist = receiveDevicesFromMiniSSDPD(s, error);
}
disconnectFromMiniSSDPD(s);
return devlist;
}
/* macros used to read from unix socket */
#define READ_BYTE_BUFFER(c) \
if((int)bufferindex >= n) { \
n = read(s, buffer, sizeof(buffer)); \
if(n<=0) break; \
bufferindex = 0; \
} \
c = buffer[bufferindex++];
#ifndef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif /* MIN */
#define READ_COPY_BUFFER(dst, len) \
for(l = len, p = (unsigned char *)dst; l > 0; ) { \
unsigned int lcopy; \
if((int)bufferindex >= n) { \
n = read(s, buffer, sizeof(buffer)); \
if(n<=0) break; \
bufferindex = 0; \
} \
lcopy = MIN(l, (n - bufferindex)); \
memcpy(p, buffer + bufferindex, lcopy); \
l -= lcopy; \
p += lcopy; \
bufferindex += lcopy; \
}
#define READ_DISCARD_BUFFER(len) \
for(l = len; l > 0; ) { \
unsigned int lcopy; \
if(bufferindex >= n) { \
n = read(s, buffer, sizeof(buffer)); \
if(n<=0) break; \
bufferindex = 0; \
} \
lcopy = MIN(l, (n - bufferindex)); \
l -= lcopy; \
bufferindex += lcopy; \
}
int
connectToMiniSSDPD(const char * socketpath)
{
int s;
struct sockaddr_un addr;
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
struct timeval timeout;
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
s = socket(AF_UNIX, SOCK_STREAM, 0);
if(s < 0)
{
/*syslog(LOG_ERR, "socket(unix): %m");*/
perror("socket(unix)");
return NULL;
return MINISSDPC_SOCKET_ERROR;
}
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
/* setting a 3 seconds timeout */
timeout.tv_sec = 3;
timeout.tv_usec = 0;
if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0)
{
perror("setsockopt");
}
timeout.tv_sec = 3;
timeout.tv_usec = 0;
if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0)
{
perror("setsockopt");
}
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
if(!socketpath)
socketpath = "/var/run/minissdpd.sock";
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, socketpath, sizeof(addr.sun_path));
/* TODO : check if we need to handle the EINTR */
@ -69,8 +196,26 @@ getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath)
{
/*syslog(LOG_WARNING, "connect(\"%s\"): %m", socketpath);*/
close(s);
return NULL;
return MINISSDPC_SOCKET_ERROR;
}
return s;
}
int
disconnectFromMiniSSDPD(int s)
{
if (close(s) < 0)
return MINISSDPC_SOCKET_ERROR;
return MINISSDPC_SUCCESS;
}
int
requestDevicesFromMiniSSDPD(int s, const char * devtype)
{
unsigned char buffer[256];
unsigned char * p;
unsigned int stsize, l;
stsize = strlen(devtype);
if(stsize == 8 && 0 == memcmp(devtype, "ssdp:all", 8))
{
@ -85,8 +230,11 @@ getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath)
if(p + stsize > buffer + sizeof(buffer))
{
/* devtype is too long ! */
close(s);
return NULL;
#ifdef DEBUG
fprintf(stderr, "devtype is too long ! stsize=%u sizeof(buffer)=%u\n",
stsize, (unsigned)sizeof(buffer));
#endif /* DEBUG */
return MINISSDPC_INVALID_INPUT;
}
memcpy(p, devtype, stsize);
p += stsize;
@ -94,48 +242,603 @@ getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath)
{
/*syslog(LOG_ERR, "write(): %m");*/
perror("minissdpc.c: write()");
close(s);
return NULL;
return MINISSDPC_SOCKET_ERROR;
}
return MINISSDPC_SUCCESS;
}
struct UPNPDev *
receiveDevicesFromMiniSSDPD(int s, int * error)
{
struct UPNPDev * tmp;
struct UPNPDev * devlist = NULL;
unsigned char buffer[256];
ssize_t n;
unsigned char * p;
unsigned char * url;
unsigned char * st;
unsigned int bufferindex;
unsigned int i, ndev;
unsigned int urlsize, stsize, usnsize, l;
n = read(s, buffer, sizeof(buffer));
if(n<=0)
{
perror("minissdpc.c: read()");
close(s);
if (error)
*error = MINISSDPC_SOCKET_ERROR;
return NULL;
}
p = buffer + 1;
for(i = 0; i < buffer[0]; i++)
ndev = buffer[0];
bufferindex = 1;
for(i = 0; i < ndev; i++)
{
if(p+2>=buffer+sizeof(buffer))
break;
DECODELENGTH(urlsize, p);
if(p+urlsize+2>=buffer+sizeof(buffer))
break;
url = p;
p += urlsize;
DECODELENGTH(stsize, p);
if(p+stsize+2>=buffer+sizeof(buffer))
break;
tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize);
DECODELENGTH_READ(urlsize, READ_BYTE_BUFFER);
if(n<=0) {
if (error)
*error = MINISSDPC_INVALID_SERVER_REPLY;
return devlist;
}
#ifdef DEBUG
printf(" urlsize=%u", urlsize);
#endif /* DEBUG */
url = malloc(urlsize);
if(url == NULL) {
if (error)
*error = MINISSDPC_MEMORY_ERROR;
return devlist;
}
READ_COPY_BUFFER(url, urlsize);
if(n<=0) {
if (error)
*error = MINISSDPC_INVALID_SERVER_REPLY;
goto free_url_and_return;
}
DECODELENGTH_READ(stsize, READ_BYTE_BUFFER);
if(n<=0) {
if (error)
*error = MINISSDPC_INVALID_SERVER_REPLY;
goto free_url_and_return;
}
#ifdef DEBUG
printf(" stsize=%u", stsize);
#endif /* DEBUG */
st = malloc(stsize);
if (st == NULL) {
if (error)
*error = MINISSDPC_MEMORY_ERROR;
goto free_url_and_return;
}
READ_COPY_BUFFER(st, stsize);
if(n<=0) {
if (error)
*error = MINISSDPC_INVALID_SERVER_REPLY;
goto free_url_and_st_and_return;
}
DECODELENGTH_READ(usnsize, READ_BYTE_BUFFER);
if(n<=0) {
if (error)
*error = MINISSDPC_INVALID_SERVER_REPLY;
goto free_url_and_st_and_return;
}
#ifdef DEBUG
printf(" usnsize=%u\n", usnsize);
#endif /* DEBUG */
tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize);
if(tmp == NULL) {
if (error)
*error = MINISSDPC_MEMORY_ERROR;
goto free_url_and_st_and_return;
}
tmp->pNext = devlist;
tmp->descURL = tmp->buffer;
tmp->st = tmp->buffer + 1 + urlsize;
memcpy(tmp->buffer, url, urlsize);
tmp->buffer[urlsize] = '\0';
memcpy(tmp->buffer + urlsize + 1, p, stsize);
p += stsize;
memcpy(tmp->st, st, stsize);
tmp->buffer[urlsize+1+stsize] = '\0';
free(url);
free(st);
url = NULL;
st = NULL;
tmp->usn = tmp->buffer + 1 + urlsize + 1 + stsize;
READ_COPY_BUFFER(tmp->usn, usnsize);
if(n<=0) {
if (error)
*error = MINISSDPC_INVALID_SERVER_REPLY;
goto free_tmp_and_return;
}
tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0';
tmp->scope_id = 0; /* default value. scope_id is not available with MiniSSDPd */
devlist = tmp;
/* added for compatibility with recent versions of MiniSSDPd
* >= 2007/12/19 */
DECODELENGTH(usnsize, p);
p += usnsize;
if(p>buffer + sizeof(buffer))
break;
}
close(s);
if (error)
*error = MINISSDPC_SUCCESS;
return devlist;
free_url_and_st_and_return:
free(st);
free_url_and_return:
free(url);
return devlist;
free_tmp_and_return:
free(tmp);
return devlist;
}
#endif /* !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) */
/* parseMSEARCHReply()
* the last 4 arguments are filled during the parsing :
* - location/locationsize : "location:" field of the SSDP reply packet
* - st/stsize : "st:" field of the SSDP reply packet.
* The strings are NOT null terminated */
static void
parseMSEARCHReply(const char * reply, int size,
const char * * location, int * locationsize,
const char * * st, int * stsize,
const char * * usn, int * usnsize)
{
int a, b, i;
i = 0;
a = i; /* start of the line */
b = 0; /* end of the "header" (position of the colon) */
while(i<size)
{
switch(reply[i])
{
case ':':
if(b==0)
{
b = i; /* end of the "header" */
/*for(j=a; j<b; j++)
{
putchar(reply[j]);
}
*/
}
break;
case '\x0a':
case '\x0d':
if(b!=0)
{
/*for(j=b+1; j<i; j++)
{
putchar(reply[j]);
}
putchar('\n');*/
/* skip the colon and white spaces */
do { b++; } while(reply[b]==' ');
if(0==strncasecmp(reply+a, "location", 8))
{
*location = reply+b;
*locationsize = i-b;
}
else if(0==strncasecmp(reply+a, "st", 2))
{
*st = reply+b;
*stsize = i-b;
}
else if(0==strncasecmp(reply+a, "usn", 3))
{
*usn = reply+b;
*usnsize = i-b;
}
b = 0;
}
a = i+1;
break;
default:
break;
}
i++;
}
}
/* port upnp discover : SSDP protocol */
#define PORT 1900
#define XSTR(s) STR(s)
#define STR(s) #s
#define UPNP_MCAST_ADDR "239.255.255.250"
/* for IPv6 */
#define UPNP_MCAST_LL_ADDR "FF02::C" /* link-local */
#define UPNP_MCAST_SL_ADDR "FF05::C" /* site-local */
/* direct discovery if minissdpd responses are not sufficient */
/* ssdpDiscoverDevices() :
* return a chained list of all devices found or NULL if
* no devices was found.
* It is up to the caller to free the chained list
* delay is in millisecond (poll).
* UDA v1.1 says :
* The TTL for the IP packet SHOULD default to 2 and
* SHOULD be configurable. */
struct UPNPDev *
ssdpDiscoverDevices(const char * const deviceTypes[],
int delay, const char * multicastif,
int localport,
int ipv6, unsigned char ttl,
int * error,
int searchalltypes)
{
struct UPNPDev * tmp;
struct UPNPDev * devlist = 0;
unsigned int scope_id = 0;
int opt = 1;
static const char MSearchMsgFmt[] =
"M-SEARCH * HTTP/1.1\r\n"
"HOST: %s:" XSTR(PORT) "\r\n"
"ST: %s\r\n"
"MAN: \"ssdp:discover\"\r\n"
"MX: %u\r\n"
"\r\n";
int deviceIndex;
char bufr[1536]; /* reception and emission buffer */
int sudp;
int n;
struct sockaddr_storage sockudp_r;
unsigned int mx;
#ifdef NO_GETADDRINFO
struct sockaddr_storage sockudp_w;
#else
int rv;
struct addrinfo hints, *servinfo, *p;
#endif
#ifdef _WIN32
MIB_IPFORWARDROW ip_forward;
unsigned long _ttl = (unsigned long)ttl;
#endif
int linklocal = 1;
if(error)
*error = MINISSDPC_UNKNOWN_ERROR;
if(localport==UPNP_LOCAL_PORT_SAME)
localport = PORT;
#ifdef _WIN32
sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, IPPROTO_UDP);
#else
sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0);
#endif
if(sudp < 0)
{
if(error)
*error = MINISSDPC_SOCKET_ERROR;
PRINT_SOCKET_ERROR("socket");
return NULL;
}
/* reception */
memset(&sockudp_r, 0, sizeof(struct sockaddr_storage));
if(ipv6) {
struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_r;
p->sin6_family = AF_INET6;
if(localport > 0 && localport < 65536)
p->sin6_port = htons((unsigned short)localport);
p->sin6_addr = in6addr_any; /* in6addr_any is not available with MinGW32 3.4.2 */
} else {
struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_r;
p->sin_family = AF_INET;
if(localport > 0 && localport < 65536)
p->sin_port = htons((unsigned short)localport);
p->sin_addr.s_addr = INADDR_ANY;
}
#ifdef _WIN32
/* This code could help us to use the right Network interface for
* SSDP multicast traffic */
/* Get IP associated with the index given in the ip_forward struct
* in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */
if(!ipv6
&& (GetBestRoute(inet_addr("223.255.255.255"), 0, &ip_forward) == NO_ERROR)) {
DWORD dwRetVal = 0;
PMIB_IPADDRTABLE pIPAddrTable;
DWORD dwSize = 0;
#ifdef DEBUG
IN_ADDR IPAddr;
#endif
int i;
#ifdef DEBUG
printf("ifIndex=%lu nextHop=%lx \n", ip_forward.dwForwardIfIndex, ip_forward.dwForwardNextHop);
#endif
pIPAddrTable = (MIB_IPADDRTABLE *) malloc(sizeof (MIB_IPADDRTABLE));
if(pIPAddrTable) {
if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
free(pIPAddrTable);
pIPAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize);
}
}
if(pIPAddrTable) {
dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 );
if (dwRetVal == NO_ERROR) {
#ifdef DEBUG
printf("\tNum Entries: %ld\n", pIPAddrTable->dwNumEntries);
#endif
for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) {
#ifdef DEBUG
printf("\n\tInterface Index[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwIndex);
IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr;
printf("\tIP Address[%d]: \t%s\n", i, inet_ntoa(IPAddr) );
IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwMask;
printf("\tSubnet Mask[%d]: \t%s\n", i, inet_ntoa(IPAddr) );
IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwBCastAddr;
printf("\tBroadCast[%d]: \t%s (%ld)\n", i, inet_ntoa(IPAddr), pIPAddrTable->table[i].dwBCastAddr);
printf("\tReassembly size[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwReasmSize);
printf("\tType and State[%d]:", i);
printf("\n");
#endif
if (pIPAddrTable->table[i].dwIndex == ip_forward.dwForwardIfIndex) {
/* Set the address of this interface to be used */
struct in_addr mc_if;
memset(&mc_if, 0, sizeof(mc_if));
mc_if.s_addr = pIPAddrTable->table[i].dwAddr;
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) {
PRINT_SOCKET_ERROR("setsockopt");
}
((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = pIPAddrTable->table[i].dwAddr;
#ifndef DEBUG
break;
#endif
}
}
}
free(pIPAddrTable);
pIPAddrTable = NULL;
}
}
#endif /* _WIN32 */
#ifdef _WIN32
if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0)
#else
if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0)
#endif
{
if(error)
*error = MINISSDPC_SOCKET_ERROR;
PRINT_SOCKET_ERROR("setsockopt(SO_REUSEADDR,...)");
return NULL;
}
#ifdef _WIN32
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, (const char *)&_ttl, sizeof(_ttl)) < 0)
#else /* _WIN32 */
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0)
#endif /* _WIN32 */
{
/* not a fatal error */
PRINT_SOCKET_ERROR("setsockopt(IP_MULTICAST_TTL,...)");
}
if(multicastif)
{
if(ipv6) {
#if !defined(_WIN32)
/* according to MSDN, if_nametoindex() is supported since
* MS Windows Vista and MS Windows Server 2008.
* http://msdn.microsoft.com/en-us/library/bb408409%28v=vs.85%29.aspx */
unsigned int ifindex = if_nametoindex(multicastif); /* eth0, etc. */
if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)) < 0)
{
PRINT_SOCKET_ERROR("setsockopt");
}
#else
#ifdef DEBUG
printf("Setting of multicast interface not supported in IPv6 under Windows.\n");
#endif
#endif
} else {
struct in_addr mc_if;
mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */
if(mc_if.s_addr != INADDR_NONE)
{
((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr;
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0)
{
PRINT_SOCKET_ERROR("setsockopt");
}
} else {
#ifdef HAS_IP_MREQN
/* was not an ip address, try with an interface name */
struct ip_mreqn reqn; /* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */
memset(&reqn, 0, sizeof(struct ip_mreqn));
reqn.imr_ifindex = if_nametoindex(multicastif);
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0)
{
PRINT_SOCKET_ERROR("setsockopt");
}
#else
#ifdef DEBUG
printf("Setting of multicast interface not supported with interface name.\n");
#endif
#endif
}
}
}
/* Before sending the packed, we first "bind" in order to be able
* to receive the response */
if (bind(sudp, (const struct sockaddr *)&sockudp_r,
ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) != 0)
{
if(error)
*error = MINISSDPC_SOCKET_ERROR;
PRINT_SOCKET_ERROR("bind");
closesocket(sudp);
return NULL;
}
if(error)
*error = MINISSDPC_SUCCESS;
/* Calculating maximum response time in seconds */
mx = ((unsigned int)delay) / 1000u;
if(mx == 0) {
mx = 1;
delay = 1000;
}
/* receiving SSDP response packet */
for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) {
/* sending the SSDP M-SEARCH packet */
n = snprintf(bufr, sizeof(bufr),
MSearchMsgFmt,
ipv6 ?
(linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]")
: UPNP_MCAST_ADDR,
deviceTypes[deviceIndex], mx);
#ifdef DEBUG
/*printf("Sending %s", bufr);*/
printf("Sending M-SEARCH request to %s with ST: %s\n",
ipv6 ?
(linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]")
: UPNP_MCAST_ADDR,
deviceTypes[deviceIndex]);
#endif
#ifdef NO_GETADDRINFO
/* the following code is not using getaddrinfo */
/* emission */
memset(&sockudp_w, 0, sizeof(struct sockaddr_storage));
if(ipv6) {
struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w;
p->sin6_family = AF_INET6;
p->sin6_port = htons(PORT);
inet_pton(AF_INET6,
linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR,
&(p->sin6_addr));
} else {
struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w;
p->sin_family = AF_INET;
p->sin_port = htons(PORT);
p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);
}
n = sendto(sudp, bufr, n, 0, &sockudp_w,
ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
if (n < 0) {
if(error)
*error = MINISSDPC_SOCKET_ERROR;
PRINT_SOCKET_ERROR("sendto");
break;
}
#else /* #ifdef NO_GETADDRINFO */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; /* AF_INET6 or AF_INET */
hints.ai_socktype = SOCK_DGRAM;
/*hints.ai_flags = */
if ((rv = getaddrinfo(ipv6
? (linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR)
: UPNP_MCAST_ADDR,
XSTR(PORT), &hints, &servinfo)) != 0) {
if(error)
*error = MINISSDPC_SOCKET_ERROR;
#ifdef _WIN32
fprintf(stderr, "getaddrinfo() failed: %d\n", rv);
#else
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
#endif
break;
}
for(p = servinfo; p; p = p->ai_next) {
n = sendto(sudp, bufr, n, 0, p->ai_addr, p->ai_addrlen);
if (n < 0) {
#ifdef DEBUG
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
if (getnameinfo(p->ai_addr, p->ai_addrlen, hbuf, sizeof(hbuf), sbuf,
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
fprintf(stderr, "host:%s port:%s\n", hbuf, sbuf);
}
#endif
PRINT_SOCKET_ERROR("sendto");
continue;
}
}
freeaddrinfo(servinfo);
if(n < 0) {
if(error)
*error = MINISSDPC_SOCKET_ERROR;
break;
}
#endif /* #ifdef NO_GETADDRINFO */
/* Waiting for SSDP REPLY packet to M-SEARCH
* if searchalltypes is set, enter the loop only
* when the last deviceType is reached */
if(!searchalltypes || !deviceTypes[deviceIndex + 1]) do {
n = receivedata(sudp, bufr, sizeof(bufr), delay, &scope_id);
if (n < 0) {
/* error */
if(error)
*error = MINISSDPC_SOCKET_ERROR;
goto error;
} else if (n == 0) {
/* no data or Time Out */
#ifdef DEBUG
printf("NODATA or TIMEOUT\n");
#endif /* DEBUG */
if (devlist && !searchalltypes) {
/* found some devices, stop now*/
if(error)
*error = MINISSDPC_SUCCESS;
goto error;
}
} else {
const char * descURL=NULL;
int urlsize=0;
const char * st=NULL;
int stsize=0;
const char * usn=NULL;
int usnsize=0;
parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize, &usn, &usnsize);
if(st&&descURL) {
#ifdef DEBUG
printf("M-SEARCH Reply:\n ST: %.*s\n USN: %.*s\n Location: %.*s\n",
stsize, st, usnsize, (usn?usn:""), urlsize, descURL);
#endif /* DEBUG */
for(tmp=devlist; tmp; tmp = tmp->pNext) {
if(memcmp(tmp->descURL, descURL, urlsize) == 0 &&
tmp->descURL[urlsize] == '\0' &&
memcmp(tmp->st, st, stsize) == 0 &&
tmp->st[stsize] == '\0' &&
(usnsize == 0 || memcmp(tmp->usn, usn, usnsize) == 0) &&
tmp->usn[usnsize] == '\0')
break;
}
/* at the exit of the loop above, tmp is null if
* no duplicate device was found */
if(tmp)
continue;
tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize);
if(!tmp) {
/* memory allocation error */
if(error)
*error = MINISSDPC_MEMORY_ERROR;
goto error;
}
tmp->pNext = devlist;
tmp->descURL = tmp->buffer;
tmp->st = tmp->buffer + 1 + urlsize;
tmp->usn = tmp->st + 1 + stsize;
memcpy(tmp->buffer, descURL, urlsize);
tmp->buffer[urlsize] = '\0';
memcpy(tmp->st, st, stsize);
tmp->buffer[urlsize+1+stsize] = '\0';
if(usn != NULL)
memcpy(tmp->usn, usn, usnsize);
tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0';
tmp->scope_id = scope_id;
devlist = tmp;
}
}
} while(n > 0);
if(ipv6) {
/* switch linklocal flag */
if(linklocal) {
linklocal = 0;
--deviceIndex;
} else {
linklocal = 1;
}
}
}
error:
closesocket(sudp);
return devlist;
}

View File

@ -1,15 +1,58 @@
/* $Id: minissdpc.h,v 1.1 2007/08/31 15:15:33 nanard Exp $ */
/* $Id: minissdpc.h,v 1.6 2015/09/18 12:45:16 nanard Exp $ */
/* Project: miniupnp
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* Author: Thomas Bernard
* Copyright (c) 2005-2007 Thomas Bernard
* Copyright (c) 2005-2015 Thomas Bernard
* This software is subjects to the conditions detailed
* in the LICENCE file provided within this distribution */
#ifndef MINISSDPC_H_INCLUDED
#define MINISSDPC_H_INCLUDED
struct UPNPDev *
getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath);
#include "miniupnpc_declspec.h"
#include "upnpdev.h"
/* error codes : */
#define MINISSDPC_SUCCESS (0)
#define MINISSDPC_UNKNOWN_ERROR (-1)
#define MINISSDPC_SOCKET_ERROR (-101)
#define MINISSDPC_MEMORY_ERROR (-102)
#define MINISSDPC_INVALID_INPUT (-103)
#define MINISSDPC_INVALID_SERVER_REPLY (-104)
#ifdef __cplusplus
extern "C" {
#endif
#if !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__))
MINIUPNP_LIBSPEC struct UPNPDev *
getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath, int * error);
MINIUPNP_LIBSPEC int
connectToMiniSSDPD(const char * socketpath);
MINIUPNP_LIBSPEC int
disconnectFromMiniSSDPD(int fd);
MINIUPNP_LIBSPEC int
requestDevicesFromMiniSSDPD(int fd, const char * devtype);
MINIUPNP_LIBSPEC struct UPNPDev *
receiveDevicesFromMiniSSDPD(int fd, int * error);
#endif /* !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) */
MINIUPNP_LIBSPEC struct UPNPDev *
ssdpDiscoverDevices(const char * const deviceTypes[],
int delay, const char * multicastif,
int localport,
int ipv6, unsigned char ttl,
int * error,
int searchalltypes);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,26 +1,10 @@
/* $Id: miniupnpc.c,v 1.124 2014/12/01 09:25:11 nanard Exp $ */
/* $Id: miniupnpc.c,v 1.135 2015/07/23 20:40:08 nanard Exp $ */
/* Project : miniupnp
* Web : http://miniupnp.free.fr/
* Author : Thomas BERNARD
* copyright (c) 2005-2014 Thomas Bernard
* copyright (c) 2005-2015 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENSE file. */
#define __EXTENSIONS__ 1
#if !defined(__APPLE__) && !defined(__sun)
#if !defined(_XOPEN_SOURCE) && !defined(__OpenBSD__) && !defined(__NetBSD__)
#ifndef __cplusplus
#define _XOPEN_SOURCE 600
#endif
#endif
#ifndef __BSD_VISIBLE
#define __BSD_VISIBLE 1
#endif
#endif
#if !defined(__DragonFly__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__APPLE__) && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__sun) && !defined(__GNU__) && !defined(__FreeBSD_kernel__)
#define HAS_IP_MREQN
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@ -63,28 +47,11 @@
#include <errno.h>
#define closesocket close
#endif /* #else _WIN32 */
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
#include <sys/time.h>
#endif
#if defined(__amigaos__) || defined(__amigaos4__)
/* Amiga OS specific stuff */
#define TIMEVAL struct timeval
#endif
#ifdef __GNU__
#define MAXHOSTNAMELEN 64
#endif
#if defined(HAS_IP_MREQN) && defined(NEED_STRUCT_IP_MREQN)
/* Several versions of glibc don't define this structure, define it here and compile with CFLAGS NEED_STRUCT_IP_MREQN */
struct ip_mreqn
{
struct in_addr imr_multiaddr; /* IP multicast address of group */
struct in_addr imr_address; /* local IP address of interface */
int imr_ifindex; /* Interface index */
};
#endif
#include "miniupnpc.h"
#include "minissdpc.h"
#include "miniwget.h"
@ -92,17 +59,10 @@ struct ip_mreqn
#include "minixml.h"
#include "upnpcommands.h"
#include "connecthostport.h"
#include "receivedata.h"
/* compare the begining of a string with a constant string */
#define COMPARE(str, cstr) (0==memcmp(str, cstr, sizeof(cstr) - 1))
#ifdef _WIN32
#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError());
#else
#define PRINT_SOCKET_ERROR(x) perror(x)
#endif
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64
#endif
@ -266,451 +226,82 @@ char * simpleUPnPcommand(int s, const char * url, const char * service,
return buf;
}
/* parseMSEARCHReply()
* the last 4 arguments are filled during the parsing :
* - location/locationsize : "location:" field of the SSDP reply packet
* - st/stsize : "st:" field of the SSDP reply packet.
* The strings are NOT null terminated */
static void
parseMSEARCHReply(const char * reply, int size,
const char * * location, int * locationsize,
const char * * st, int * stsize)
{
int a, b, i;
i = 0;
a = i; /* start of the line */
b = 0; /* end of the "header" (position of the colon) */
while(i<size)
{
switch(reply[i])
{
case ':':
if(b==0)
{
b = i; /* end of the "header" */
/*for(j=a; j<b; j++)
{
putchar(reply[j]);
}
*/
}
break;
case '\x0a':
case '\x0d':
if(b!=0)
{
/*for(j=b+1; j<i; j++)
{
putchar(reply[j]);
}
putchar('\n');*/
/* skip the colon and white spaces */
do { b++; } while(reply[b]==' ');
if(0==strncasecmp(reply+a, "location", 8))
{
*location = reply+b;
*locationsize = i-b;
}
else if(0==strncasecmp(reply+a, "st", 2))
{
*st = reply+b;
*stsize = i-b;
}
b = 0;
}
a = i+1;
break;
default:
break;
}
i++;
}
}
/* port upnp discover : SSDP protocol */
#define PORT 1900
#define XSTR(s) STR(s)
#define STR(s) #s
#define UPNP_MCAST_ADDR "239.255.255.250"
/* for IPv6 */
#define UPNP_MCAST_LL_ADDR "FF02::C" /* link-local */
#define UPNP_MCAST_SL_ADDR "FF05::C" /* site-local */
/* upnpDiscoverDevices() :
* return a chained list of all devices found or NULL if
* no devices was found.
* It is up to the caller to free the chained list
* delay is in millisecond (poll) */
* delay is in millisecond (poll).
* UDA v1.1 says :
* The TTL for the IP packet SHOULD default to 2 and
* SHOULD be configurable. */
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscoverDevices(const char * const deviceTypes[],
int delay, const char * multicastif,
const char * minissdpdsock, int localport,
int ipv6,
int * error)
int ipv6, unsigned char ttl,
int * error,
int searchalltypes)
{
struct UPNPDev * tmp;
struct UPNPDev * devlist = 0;
unsigned int scope_id = 0;
int opt = 1;
static const char MSearchMsgFmt[] =
"M-SEARCH * HTTP/1.1\r\n"
"HOST: %s:" XSTR(PORT) "\r\n"
"ST: %s\r\n"
"MAN: \"ssdp:discover\"\r\n"
"MX: %u\r\n"
"\r\n";
#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
int deviceIndex;
char bufr[1536]; /* reception and emission buffer */
int sudp;
int n;
struct sockaddr_storage sockudp_r;
unsigned int mx;
#ifdef NO_GETADDRINFO
struct sockaddr_storage sockudp_w;
#else
int rv;
struct addrinfo hints, *servinfo, *p;
#endif
#ifdef _WIN32
MIB_IPFORWARDROW ip_forward;
#endif
int linklocal = 1;
#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
if(localport==UPNP_LOCAL_PORT_SAME)
localport = PORT;
if(error)
*error = UPNPDISCOVER_UNKNOWN_ERROR;
#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
/* first try to get infos from minissdpd ! */
if(!minissdpdsock)
minissdpdsock = "/var/run/minissdpd.sock";
for(deviceIndex = 0; !devlist && deviceTypes[deviceIndex]; deviceIndex++) {
devlist = getDevicesFromMiniSSDPD(deviceTypes[deviceIndex],
minissdpdsock);
for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) {
struct UPNPDev * minissdpd_devlist;
int only_rootdevice = 1;
minissdpd_devlist = getDevicesFromMiniSSDPD(deviceTypes[deviceIndex],
minissdpdsock, 0);
if(minissdpd_devlist) {
#ifdef DEBUG
printf("returned by MiniSSDPD: %s\t%s\n",
minissdpd_devlist->st, minissdpd_devlist->descURL);
#endif /* DEBUG */
if(!strstr(minissdpd_devlist->st, "rootdevice"))
only_rootdevice = 0;
for(tmp = minissdpd_devlist; tmp->pNext != NULL; tmp = tmp->pNext) {
#ifdef DEBUG
printf("returned by MiniSSDPD: %s\t%s\n",
tmp->pNext->st, tmp->pNext->descURL);
#endif /* DEBUG */
if(!strstr(tmp->st, "rootdevice"))
only_rootdevice = 0;
}
tmp->pNext = devlist;
devlist = minissdpd_devlist;
if(!searchalltypes && !only_rootdevice)
break;
}
}
for(tmp = devlist; tmp != NULL; tmp = tmp->pNext) {
/* We return what we have found if it was not only a rootdevice */
if(devlist && !strstr(deviceTypes[deviceIndex], "rootdevice")) {
if(!strstr(tmp->st, "rootdevice")) {
if(error)
*error = UPNPDISCOVER_SUCCESS;
return devlist;
}
}
#endif
/* fallback to direct discovery */
#ifdef _WIN32
sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, IPPROTO_UDP);
#else
sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0);
#endif
if(sudp < 0)
{
if(error)
*error = UPNPDISCOVER_SOCKET_ERROR;
PRINT_SOCKET_ERROR("socket");
return NULL;
}
/* reception */
memset(&sockudp_r, 0, sizeof(struct sockaddr_storage));
if(ipv6) {
struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_r;
p->sin6_family = AF_INET6;
if(localport)
p->sin6_port = htons(localport);
p->sin6_addr = in6addr_any; /* in6addr_any is not available with MinGW32 3.4.2 */
} else {
struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_r;
p->sin_family = AF_INET;
if(localport)
p->sin_port = htons(localport);
p->sin_addr.s_addr = INADDR_ANY;
}
#ifdef _WIN32
/* This code could help us to use the right Network interface for
* SSDP multicast traffic */
/* Get IP associated with the index given in the ip_forward struct
* in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */
if(!ipv6
&& (GetBestRoute(inet_addr("223.255.255.255"), 0, &ip_forward) == NO_ERROR)) {
DWORD dwRetVal = 0;
PMIB_IPADDRTABLE pIPAddrTable;
DWORD dwSize = 0;
#ifdef DEBUG
IN_ADDR IPAddr;
#endif
int i;
#ifdef DEBUG
printf("ifIndex=%lu nextHop=%lx \n", ip_forward.dwForwardIfIndex, ip_forward.dwForwardNextHop);
#endif
pIPAddrTable = (MIB_IPADDRTABLE *) malloc(sizeof (MIB_IPADDRTABLE));
if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
free(pIPAddrTable);
pIPAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize);
}
if(pIPAddrTable) {
dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 );
#ifdef DEBUG
printf("\tNum Entries: %ld\n", pIPAddrTable->dwNumEntries);
#endif
for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) {
#ifdef DEBUG
printf("\n\tInterface Index[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwIndex);
IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr;
printf("\tIP Address[%d]: \t%s\n", i, inet_ntoa(IPAddr) );
IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwMask;
printf("\tSubnet Mask[%d]: \t%s\n", i, inet_ntoa(IPAddr) );
IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwBCastAddr;
printf("\tBroadCast[%d]: \t%s (%ld)\n", i, inet_ntoa(IPAddr), pIPAddrTable->table[i].dwBCastAddr);
printf("\tReassembly size[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwReasmSize);
printf("\tType and State[%d]:", i);
printf("\n");
#endif
if (pIPAddrTable->table[i].dwIndex == ip_forward.dwForwardIfIndex) {
/* Set the address of this interface to be used */
struct in_addr mc_if;
memset(&mc_if, 0, sizeof(mc_if));
mc_if.s_addr = pIPAddrTable->table[i].dwAddr;
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) {
PRINT_SOCKET_ERROR("setsockopt");
}
((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = pIPAddrTable->table[i].dwAddr;
#ifndef DEBUG
break;
#endif
}
}
free(pIPAddrTable);
pIPAddrTable = NULL;
}
}
#endif
#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
#ifdef _WIN32
if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0)
#else
if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0)
#endif
/* direct discovery if minissdpd responses are not sufficient */
{
if(error)
*error = UPNPDISCOVER_SOCKET_ERROR;
PRINT_SOCKET_ERROR("setsockopt");
return NULL;
}
if(multicastif)
{
if(ipv6) {
#if !defined(_WIN32)
/* according to MSDN, if_nametoindex() is supported since
* MS Windows Vista and MS Windows Server 2008.
* http://msdn.microsoft.com/en-us/library/bb408409%28v=vs.85%29.aspx */
unsigned int ifindex = if_nametoindex(multicastif); /* eth0, etc. */
if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)) < 0)
{
PRINT_SOCKET_ERROR("setsockopt");
}
#else
#ifdef DEBUG
printf("Setting of multicast interface not supported in IPv6 under Windows.\n");
#endif
#endif
} else {
struct in_addr mc_if;
mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */
if(mc_if.s_addr != INADDR_NONE)
{
((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr;
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0)
{
PRINT_SOCKET_ERROR("setsockopt");
}
} else {
#ifdef HAS_IP_MREQN
/* was not an ip address, try with an interface name */
struct ip_mreqn reqn; /* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */
memset(&reqn, 0, sizeof(struct ip_mreqn));
reqn.imr_ifindex = if_nametoindex(multicastif);
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0)
{
PRINT_SOCKET_ERROR("setsockopt");
}
#else
#ifdef DEBUG
printf("Setting of multicast interface not supported with interface name.\n");
#endif
#endif
}
struct UPNPDev * discovered_devlist;
discovered_devlist = ssdpDiscoverDevices(deviceTypes, delay, multicastif, localport,
ipv6, ttl, error, searchalltypes);
if(devlist == NULL)
devlist = discovered_devlist;
else {
for(tmp = devlist; tmp->pNext != NULL; tmp = tmp->pNext);
tmp->pNext = discovered_devlist;
}
}
/* Before sending the packed, we first "bind" in order to be able
* to receive the response */
if (bind(sudp, (const struct sockaddr *)&sockudp_r,
ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) != 0)
{
if(error)
*error = UPNPDISCOVER_SOCKET_ERROR;
PRINT_SOCKET_ERROR("bind");
closesocket(sudp);
return NULL;
}
if(error)
*error = UPNPDISCOVER_SUCCESS;
/* Calculating maximum response time in seconds */
mx = ((unsigned int)delay) / 1000u;
if(mx == 0) {
mx = 1;
delay = 1000;
}
/* receiving SSDP response packet */
for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) {
/* sending the SSDP M-SEARCH packet */
n = snprintf(bufr, sizeof(bufr),
MSearchMsgFmt,
ipv6 ?
(linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]")
: UPNP_MCAST_ADDR,
deviceTypes[deviceIndex], mx);
#ifdef DEBUG
/*printf("Sending %s", bufr);*/
printf("Sending M-SEARCH request to %s with ST: %s\n",
ipv6 ?
(linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]")
: UPNP_MCAST_ADDR,
deviceTypes[deviceIndex]);
#endif
#ifdef NO_GETADDRINFO
/* the following code is not using getaddrinfo */
/* emission */
memset(&sockudp_w, 0, sizeof(struct sockaddr_storage));
if(ipv6) {
struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w;
p->sin6_family = AF_INET6;
p->sin6_port = htons(PORT);
inet_pton(AF_INET6,
linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR,
&(p->sin6_addr));
} else {
struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w;
p->sin_family = AF_INET;
p->sin_port = htons(PORT);
p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);
}
n = sendto(sudp, bufr, n, 0, &sockudp_w,
ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
if (n < 0) {
if(error)
*error = UPNPDISCOVER_SOCKET_ERROR;
PRINT_SOCKET_ERROR("sendto");
break;
}
#else /* #ifdef NO_GETADDRINFO */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; /* AF_INET6 or AF_INET */
hints.ai_socktype = SOCK_DGRAM;
/*hints.ai_flags = */
if ((rv = getaddrinfo(ipv6
? (linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR)
: UPNP_MCAST_ADDR,
XSTR(PORT), &hints, &servinfo)) != 0) {
if(error)
*error = UPNPDISCOVER_SOCKET_ERROR;
#ifdef _WIN32
fprintf(stderr, "getaddrinfo() failed: %d\n", rv);
#else
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
#endif
break;
}
for(p = servinfo; p; p = p->ai_next) {
n = sendto(sudp, bufr, n, 0, p->ai_addr, p->ai_addrlen);
if (n < 0) {
#ifdef DEBUG
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
if (getnameinfo(p->ai_addr, p->ai_addrlen, hbuf, sizeof(hbuf), sbuf,
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
fprintf(stderr, "host:%s port:%s\n", hbuf, sbuf);
}
#endif
PRINT_SOCKET_ERROR("sendto");
continue;
}
}
freeaddrinfo(servinfo);
if(n < 0) {
if(error)
*error = UPNPDISCOVER_SOCKET_ERROR;
break;
}
#endif /* #ifdef NO_GETADDRINFO */
/* Waiting for SSDP REPLY packet to M-SEARCH */
do {
n = receivedata(sudp, bufr, sizeof(bufr), delay, &scope_id);
if (n < 0) {
/* error */
if(error)
*error = UPNPDISCOVER_SOCKET_ERROR;
goto error;
} else if (n == 0) {
/* no data or Time Out */
if (devlist) {
/* found some devices, stop now*/
if(error)
*error = UPNPDISCOVER_SUCCESS;
goto error;
}
if(ipv6) {
/* switch linklocal flag */
if(linklocal) {
linklocal = 0;
--deviceIndex;
} else {
linklocal = 1;
}
}
} else {
const char * descURL=NULL;
int urlsize=0;
const char * st=NULL;
int stsize=0;
parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize);
if(st&&descURL) {
#ifdef DEBUG
printf("M-SEARCH Reply:\n ST: %.*s\n Location: %.*s\n",
stsize, st, urlsize, descURL);
#endif
for(tmp=devlist; tmp; tmp = tmp->pNext) {
if(memcmp(tmp->descURL, descURL, urlsize) == 0 &&
tmp->descURL[urlsize] == '\0' &&
memcmp(tmp->st, st, stsize) == 0 &&
tmp->st[stsize] == '\0')
break;
}
/* at the exit of the loop above, tmp is null if
* no duplicate device was found */
if(tmp)
continue;
tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize);
if(!tmp) {
/* memory allocation error */
if(error)
*error = UPNPDISCOVER_MEMORY_ERROR;
goto error;
}
tmp->pNext = devlist;
tmp->descURL = tmp->buffer;
tmp->st = tmp->buffer + 1 + urlsize;
memcpy(tmp->buffer, descURL, urlsize);
tmp->buffer[urlsize] = '\0';
memcpy(tmp->buffer + urlsize + 1, st, stsize);
tmp->buffer[urlsize+1+stsize] = '\0';
tmp->scope_id = scope_id;
devlist = tmp;
}
}
} while(n > 0);
}
error:
closesocket(sudp);
return devlist;
}
@ -718,7 +309,7 @@ error:
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscover(int delay, const char * multicastif,
const char * minissdpdsock, int localport,
int ipv6,
int ipv6, unsigned char ttl,
int * error)
{
static const char * const deviceList[] = {
@ -735,14 +326,14 @@ upnpDiscover(int delay, const char * multicastif,
};
return upnpDiscoverDevices(deviceList,
delay, multicastif, minissdpdsock, localport,
ipv6, error);
ipv6, ttl, error, 0);
}
/* upnpDiscoverAll() Discover all UPnP devices */
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscoverAll(int delay, const char * multicastif,
const char * minissdpdsock, int localport,
int ipv6,
int ipv6, unsigned char ttl,
int * error)
{
static const char * const deviceList[] = {
@ -752,14 +343,14 @@ upnpDiscoverAll(int delay, const char * multicastif,
};
return upnpDiscoverDevices(deviceList,
delay, multicastif, minissdpdsock, localport,
ipv6, error);
ipv6, ttl, error, 0);
}
/* upnpDiscoverDevice() Discover a specific device */
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscoverDevice(const char * device, int delay, const char * multicastif,
const char * minissdpdsock, int localport,
int ipv6,
int ipv6, unsigned char ttl,
int * error)
{
const char * const deviceList[] = {
@ -768,20 +359,7 @@ upnpDiscoverDevice(const char * device, int delay, const char * multicastif,
};
return upnpDiscoverDevices(deviceList,
delay, multicastif, minissdpdsock, localport,
ipv6, error);
}
/* freeUPNPDevlist() should be used to
* free the chained list returned by upnpDiscover() */
MINIUPNP_LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist)
{
struct UPNPDev * next;
while(devlist)
{
next = devlist->pNext;
free(devlist);
devlist = next;
}
ipv6, ttl, error, 0);
}
static char *
@ -909,9 +487,9 @@ UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data)
UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype,
status, &uptime, NULL);
if(0 == strcmp("Connected", status))
{
return 1;
}
else if(0 == strcmp("Up", status)) /* Also accept "Up" */
return 1;
else
return 0;
}

View File

@ -1,15 +1,16 @@
/* $Id: miniupnpc.h,v 1.39 2014/12/20 09:13:51 nanard Exp $ */
/* $Id: miniupnpc.h,v 1.44 2015/07/23 20:40:10 nanard Exp $ */
/* Project: miniupnp
* http://miniupnp.free.fr/
* Author: Thomas Bernard
* Copyright (c) 2005-2014 Thomas Bernard
* Copyright (c) 2005-2015 Thomas Bernard
* This software is subjects to the conditions detailed
* in the LICENCE file provided within this distribution */
#ifndef MINIUPNPC_H_INCLUDED
#define MINIUPNPC_H_INCLUDED
#include "declspec.h"
#include "miniupnpc_declspec.h"
#include "igd_desc_parse.h"
#include "upnpdev.h"
/* error codes : */
#define UPNPDISCOVER_SUCCESS (0)
@ -19,7 +20,7 @@
/* versions : */
#define MINIUPNPC_VERSION "1.9"
#define MINIUPNPC_API_VERSION 12
#define MINIUPNPC_API_VERSION 14
/* Source port:
Using "1" as an alias for 1900 for backwards compatability
@ -39,14 +40,6 @@ simpleUPnPcommand(int, const char *, const char *,
const char *, struct UPNParg *,
int *);
struct UPNPDev {
struct UPNPDev * pNext;
char * descURL;
char * st;
unsigned int scope_id;
char buffer[2];
};
/* upnpDiscover()
* discover UPnP devices on the network.
* The discovered devices are returned as a chained list.
@ -61,35 +54,35 @@ struct UPNPDev {
* If localport is set to UPNP_LOCAL_PORT_SAME(1) SSDP packets will be sent
* from the source port 1900 (same as destination port), if set to
* UPNP_LOCAL_PORT_ANY(0) system assign a source port, any other value will
* be attempted as the source port */
* be attempted as the source port.
* "searchalltypes" parameter is useful when searching several types,
* if 0, the discovery will stop with the first type returning results.
* TTL should default to 2. */
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscover(int delay, const char * multicastif,
const char * minissdpdsock, int localport,
int ipv6,
int ipv6, unsigned char ttl,
int * error);
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscoverAll(int delay, const char * multicastif,
const char * minissdpdsock, int localport,
int ipv6,
int ipv6, unsigned char ttl,
int * error);
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscoverDevice(const char * device, int delay, const char * multicastif,
const char * minissdpdsock, int localport,
int ipv6,
int ipv6, unsigned char ttl,
int * error);
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscoverDevices(const char * const deviceTypes[],
int delay, const char * multicastif,
const char * minissdpdsock, int localport,
int ipv6,
int * error);
/* freeUPNPDevlist()
* free list returned by upnpDiscover() */
MINIUPNP_LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist);
int ipv6, unsigned char ttl,
int * error,
int searchalltypes);
/* parserootdesc() :
* parse root XML description of a UPnP device and fill the IGDdatas

View File

@ -1,5 +1,5 @@
#ifndef DECLSPEC_H_INCLUDED
#define DECLSPEC_H_INCLUDED
#ifndef MINIUPNPC_DECLSPEC_H_INCLUDED
#define MINIUPNPC_DECLSPEC_H_INCLUDED
#if defined(_WIN32) && !defined(MINIUPNP_STATICLIB)
/* for windows dll */
@ -17,5 +17,5 @@
#endif
#endif
#endif
#endif /* MINIUPNPC_DECLSPEC_H_INCLUDED */

View File

@ -131,6 +131,7 @@ UPnP_discover(UPnPObject *self)
self->minissdpdsocket,
(int)self->localport,
0/*ip v6*/,
2/* TTL */,
0/*error */);
Py_END_ALLOW_THREADS
/* Py_RETURN_NONE ??? */

View File

@ -1,4 +1,4 @@
/* $Id: miniwget.c,v 1.68 2015/02/06 10:26:57 nanard Exp $ */
/* $Id: miniwget.c,v 1.70 2015/07/15 12:41:13 nanard Exp $ */
/* Project : miniupnp
* Website : http://miniupnp.free.fr/
* Author : Thomas Bernard
@ -85,7 +85,24 @@ getHTTPResponse(int s, int * size)
unsigned int chunksize_buf_index;
header_buf = malloc(header_buf_len);
if(header_buf == NULL)
{
#ifdef DEBUG
fprintf(stderr, "%s: Memory allocation error\n", "getHTTPResponse");
#endif /* DEBUG */
*size = -1;
return NULL;
}
content_buf = malloc(content_buf_len);
if(content_buf == NULL)
{
free(header_buf);
#ifdef DEBUG
fprintf(stderr, "%s: Memory allocation error\n", "getHTTPResponse");
#endif /* DEBUG */
*size = -1;
return NULL;
}
chunksize_buf[0] = '\0';
chunksize_buf_index = 0;

View File

@ -1,14 +1,14 @@
/* $Id: miniwget.h,v 1.7 2012/06/23 22:35:59 nanard Exp $ */
/* Project : miniupnp
* Author : Thomas Bernard
* Copyright (c) 2005-2012 Thomas Bernard
* Copyright (c) 2005-2015 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution.
* */
#ifndef MINIWGET_H_INCLUDED
#define MINIWGET_H_INCLUDED
#include "declspec.h"
#include "miniupnpc_declspec.h"
#ifdef __cplusplus
extern "C" {

View File

@ -1,4 +1,4 @@
/* $Id: minixmlvalid.c,v 1.6 2012/05/01 16:24:07 nanard Exp $ */
/* $Id: minixmlvalid.c,v 1.7 2015/07/15 12:41:15 nanard Exp $ */
/* MiniUPnP Project
* http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/
* minixmlvalid.c :
@ -128,6 +128,11 @@ int testxmlparser(const char * xml, int size)
struct xmlparser parser;
evtlist.n = 0;
evtlist.events = malloc(sizeof(struct event)*100);
if(evtlist.events == NULL)
{
fprintf(stderr, "Memory allocation error.\n");
return -1;
}
memset(&parser, 0, sizeof(parser));
parser.xmlstart = xml;
parser.xmlsize = size;

View File

@ -160,6 +160,10 @@
RelativePath="..\minisoap.c"
>
</File>
<File
RelativePath="..\minissdpc.c"
>
</File>
<File
RelativePath="..\miniupnpc.c"
>
@ -184,6 +188,10 @@
RelativePath="..\upnpcommands.c"
>
</File>
<File
RelativePath="..\upnpdev.c"
>
</File>
<File
RelativePath="..\upnperrors.c"
>
@ -214,6 +222,10 @@
RelativePath="..\minisoap.h"
>
</File>
<File
RelativePath="..\minissdpc.h"
>
</File>
<File
RelativePath="..\miniupnpc.h"
>
@ -246,6 +258,10 @@
RelativePath="..\upnpcommands.h"
>
</File>
<File
RelativePath="..\upnpdev.h"
>
</File>
<File
RelativePath="..\upnperrors.h"
>

View File

@ -1,11 +1,14 @@
/* $Id: portlistingparse.c,v 1.7 2014/11/01 10:37:32 nanard Exp $ */
/* $Id: portlistingparse.c,v 1.9 2015/07/15 12:41:13 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2011 Thomas Bernard
* (c) 2011-2015 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
#include <string.h>
#include <stdlib.h>
#ifdef DEBUG
#include <stdio.h>
#endif /* DEBUG */
#include "portlistingparse.h"
#include "minixml.h"
@ -62,6 +65,15 @@ startelt(void * d, const char * name, int l)
{
struct PortMapping * pm;
pm = calloc(1, sizeof(struct PortMapping));
if(pm == NULL)
{
/* malloc error */
#ifdef DEBUG
fprintf(stderr, "%s: error allocating memory",
"startelt");
#endif /* DEBUG */
return;
}
pm->l_next = pdata->l_head; /* insert in list */
pdata->l_head = pm;
}

View File

@ -1,13 +1,13 @@
/* $Id: portlistingparse.h,v 1.10 2014/11/01 10:37:32 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2011-2012 Thomas Bernard
* (c) 2011-2015 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
#ifndef PORTLISTINGPARSE_H_INCLUDED
#define PORTLISTINGPARSE_H_INCLUDED
#include "declspec.h"
#include "miniupnpc_declspec.h"
/* for the definition of UNSIGNED_INTEGER */
#include "miniupnpctypes.h"

View File

@ -6,7 +6,7 @@
# python script to build the miniupnpc module under unix
#
# replace libminiupnpc.a by libminiupnpc.so for shared library usage
from distutils.core import setup, Extension
from setuptools import setup, Extension
from distutils import sysconfig
sysconfig.get_config_vars()["OPT"] = ''
sysconfig.get_config_vars()["CFLAGS"] = ''

View File

@ -141,7 +141,7 @@ int main(int argc, char * * argv)
FILE * f;
char * buffer;
int len;
int r = 0;
int r;
if(argc<2) {
fprintf(stderr, "Usage: %s file.xml [file.values]\n", argv[0]);
return 1;
@ -160,7 +160,14 @@ int main(int argc, char * * argv)
fclose(f);
return 1;
}
fread(buffer, 1, len, f);
r = (int)fread(buffer, 1, len, f);
if(r != len) {
fprintf(stderr, "Failed to read file %s. %d out of %d bytes.\n",
argv[1], r, len);
fclose(f);
free(buffer);
return 1;
}
fclose(f);
f = NULL;
if(argc > 2) {

View File

@ -1,7 +1,7 @@
#!/bin/sh
# $Id: testminiwget.sh,v 1.10 2013/11/13 15:08:08 nanard Exp $
# $Id: testminiwget.sh,v 1.13 2015/09/03 17:57:44 nanard Exp $
# project miniupnp : http://miniupnp.free.fr/
# (c) 2011-2012 Thomas Bernard
# (c) 2011-2015 Thomas Bernard
#
# test program for miniwget.c
# is usually invoked by "make check"
@ -15,7 +15,7 @@
# The script was tested and works with ksh, bash
# it should now also run with dash
TMPD=`mktemp -d miniwgetXXXXXXXXXX`
TMPD=`mktemp -d -t miniwgetXXXXXXXXXX`
HTTPSERVEROUT="${TMPD}/httpserverout"
EXPECTEDFILE="${TMPD}/expectedfile"
DOWNLOADEDFILE="${TMPD}/downloadedfile"

View File

@ -1,4 +1,4 @@
/* $Id: upnpc.c,v 1.108 2014/12/20 09:13:16 nanard Exp $ */
/* $Id: upnpc.c,v 1.111 2015/07/23 20:40:10 nanard Exp $ */
/* Project : miniupnp
* Author : Thomas Bernard
* Copyright (c) 2005-2015 Thomas Bernard
@ -547,6 +547,7 @@ int main(int argc, char ** argv)
int retcode = 0;
int error = 0;
int ipv6 = 0;
unsigned char ttl = 2; /* defaulting to 2 */
const char * description = 0;
#ifdef _WIN32
@ -559,7 +560,7 @@ int main(int argc, char ** argv)
}
#endif
printf("upnpc : miniupnpc library test client, version %s.\n", MINIUPNPC_VERSION_STRING);
printf(" (c) 2005-2014 Thomas Bernard.\n");
printf(" (c) 2005-2015 Thomas Bernard.\n");
printf("Go to http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/\n"
"for more information.\n");
/* command line processing */
@ -592,6 +593,8 @@ int main(int argc, char ** argv)
ipv6 = 1;
else if(argv[i][1] == 'e')
description = argv[++i];
else if(argv[i][1] == 't')
ttl = (unsigned char)atoi(argv[++i]);
else
{
command = argv[i][1];
@ -639,12 +642,13 @@ int main(int argc, char ** argv)
fprintf(stderr, " -m address/interface : provide ip address (ip v4) or interface name (ip v4 or v6) to use for sending SSDP multicast packets.\n");
fprintf(stderr, " -z localport : SSDP packets local (source) port (1024-65535).\n");
fprintf(stderr, " -p path : use this path for MiniSSDPd socket.\n");
fprintf(stderr, " -t ttl : set multicast TTL. Default value is 2.\n");
return 1;
}
if( rootdescurl
|| (devlist = upnpDiscover(2000, multicastif, minissdpdpath,
localport, ipv6, &error)))
localport, ipv6, ttl, &error)))
{
struct UPNPDev * device;
struct UPNPUrls urls;

View File

@ -1,4 +1,4 @@
/* $Id: upnpcommands.c,v 1.45 2015/02/06 10:37:00 nanard Exp $ */
/* $Id: upnpcommands.c,v 1.46 2015/07/15 12:19:00 nanard Exp $ */
/* Project : miniupnp
* Author : Thomas Bernard
* Copyright (c) 2005-2015 Thomas Bernard
@ -354,6 +354,8 @@ UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
return UPNPCOMMAND_INVALID_ARGS;
AddPortMappingArgs = calloc(9, sizeof(struct UPNParg));
if(AddPortMappingArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
AddPortMappingArgs[0].elt = "NewRemoteHost";
AddPortMappingArgs[0].val = remoteHost;
AddPortMappingArgs[1].elt = "NewExternalPort";
@ -416,6 +418,8 @@ UPNP_AddAnyPortMapping(const char * controlURL, const char * servicetype,
return UPNPCOMMAND_INVALID_ARGS;
AddPortMappingArgs = calloc(9, sizeof(struct UPNParg));
if(AddPortMappingArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
AddPortMappingArgs[0].elt = "NewRemoteHost";
AddPortMappingArgs[0].val = remoteHost;
AddPortMappingArgs[1].elt = "NewExternalPort";
@ -478,6 +482,8 @@ UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
return UPNPCOMMAND_INVALID_ARGS;
DeletePortMappingArgs = calloc(4, sizeof(struct UPNParg));
if(DeletePortMappingArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
DeletePortMappingArgs[0].elt = "NewRemoteHost";
DeletePortMappingArgs[0].val = remoteHost;
DeletePortMappingArgs[1].elt = "NewExternalPort";
@ -522,6 +528,8 @@ UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype,
return UPNPCOMMAND_INVALID_ARGS;
DeletePortMappingArgs = calloc(5, sizeof(struct UPNParg));
if(DeletePortMappingArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
DeletePortMappingArgs[0].elt = "NewStartPort";
DeletePortMappingArgs[0].val = extPortStart;
DeletePortMappingArgs[1].elt = "NewEndPort";
@ -575,6 +583,8 @@ UPNP_GetGenericPortMappingEntry(const char * controlURL,
intClient[0] = '\0';
intPort[0] = '\0';
GetPortMappingArgs = calloc(2, sizeof(struct UPNParg));
if(GetPortMappingArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
GetPortMappingArgs[0].elt = "NewPortMappingIndex";
GetPortMappingArgs[0].val = index;
if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
@ -710,6 +720,8 @@ UPNP_GetSpecificPortMappingEntry(const char * controlURL,
return UPNPCOMMAND_INVALID_ARGS;
GetPortMappingArgs = calloc(4, sizeof(struct UPNParg));
if(GetPortMappingArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
GetPortMappingArgs[0].elt = "NewRemoteHost";
GetPortMappingArgs[0].val = remoteHost;
GetPortMappingArgs[1].elt = "NewExternalPort";
@ -799,6 +811,8 @@ UPNP_GetListOfPortMappings(const char * controlURL,
return UPNPCOMMAND_INVALID_ARGS;
GetListOfPortMappingsArgs = calloc(6, sizeof(struct UPNParg));
if(GetListOfPortMappingsArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
GetListOfPortMappingsArgs[0].elt = "NewStartPort";
GetListOfPortMappingsArgs[0].val = startPort;
GetListOfPortMappingsArgs[1].elt = "NewEndPort";
@ -926,6 +940,8 @@ UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype
return UPNPCOMMAND_INVALID_ARGS;
GetOutboundPinholeTimeoutArgs = calloc(6, sizeof(struct UPNParg));
if(GetOutboundPinholeTimeoutArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
GetOutboundPinholeTimeoutArgs[0].elt = "RemoteHost";
GetOutboundPinholeTimeoutArgs[0].val = remoteHost;
GetOutboundPinholeTimeoutArgs[1].elt = "RemotePort";
@ -982,6 +998,8 @@ UPNP_AddPinhole(const char * controlURL, const char * servicetype,
return UPNPCOMMAND_INVALID_ARGS;
AddPinholeArgs = calloc(7, sizeof(struct UPNParg));
if(AddPinholeArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
/* RemoteHost can be wilcarded */
if(strncmp(remoteHost, "empty", 5)==0)
{
@ -1055,6 +1073,8 @@ UPNP_UpdatePinhole(const char * controlURL, const char * servicetype,
return UPNPCOMMAND_INVALID_ARGS;
UpdatePinholeArgs = calloc(3, sizeof(struct UPNParg));
if(UpdatePinholeArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
UpdatePinholeArgs[0].elt = "UniqueID";
UpdatePinholeArgs[0].val = uniqueID;
UpdatePinholeArgs[1].elt = "NewLeaseTime";
@ -1096,6 +1116,8 @@ UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char
return UPNPCOMMAND_INVALID_ARGS;
DeletePinholeArgs = calloc(2, sizeof(struct UPNParg));
if(DeletePinholeArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
DeletePinholeArgs[0].elt = "UniqueID";
DeletePinholeArgs[0].val = uniqueID;
buffer = simpleUPnPcommand(-1, controlURL, servicetype,
@ -1135,6 +1157,8 @@ UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype,
return UPNPCOMMAND_INVALID_ARGS;
CheckPinholeWorkingArgs = calloc(4, sizeof(struct UPNParg));
if(CheckPinholeWorkingArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
CheckPinholeWorkingArgs[0].elt = "UniqueID";
CheckPinholeWorkingArgs[0].val = uniqueID;
buffer = simpleUPnPcommand(-1, controlURL, servicetype,
@ -1180,6 +1204,8 @@ UPNP_GetPinholePackets(const char * controlURL, const char * servicetype,
return UPNPCOMMAND_INVALID_ARGS;
GetPinholePacketsArgs = calloc(4, sizeof(struct UPNParg));
if(GetPinholePacketsArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
GetPinholePacketsArgs[0].elt = "UniqueID";
GetPinholePacketsArgs[0].val = uniqueID;
buffer = simpleUPnPcommand(-1, controlURL, servicetype,

View File

@ -1,7 +1,7 @@
/* $Id: upnpcommands.h,v 1.27 2014/02/17 15:38:26 nanard Exp $ */
/* $Id: upnpcommands.h,v 1.30 2015/07/15 12:21:28 nanard Exp $ */
/* Miniupnp project : http://miniupnp.free.fr/
* Author : Thomas Bernard
* Copyright (c) 2005-2014 Thomas Bernard
* Copyright (c) 2005-2015 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided within this distribution */
#ifndef UPNPCOMMANDS_H_INCLUDED
@ -9,7 +9,7 @@
#include "upnpreplyparse.h"
#include "portlistingparse.h"
#include "declspec.h"
#include "miniupnpc_declspec.h"
#include "miniupnpctypes.h"
/* MiniUPnPc return codes : */
@ -18,6 +18,7 @@
#define UPNPCOMMAND_INVALID_ARGS (-2)
#define UPNPCOMMAND_HTTP_ERROR (-3)
#define UPNPCOMMAND_INVALID_RESPONSE (-4)
#define UPNPCOMMAND_MEM_ALLOC_ERROR (-5)
#ifdef __cplusplus
extern "C" {

23
miniupnpc/upnpdev.c Normal file
View File

@ -0,0 +1,23 @@
/* $Id: upnpdev.c,v 1.1 2015/08/28 12:14:19 nanard Exp $ */
/* Project : miniupnp
* Web : http://miniupnp.free.fr/
* Author : Thomas BERNARD
* copyright (c) 2005-2015 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENSE file. */
#include <stdlib.h>
#include "upnpdev.h"
/* freeUPNPDevlist() should be used to
* free the chained list returned by upnpDiscover() */
void freeUPNPDevlist(struct UPNPDev * devlist)
{
struct UPNPDev * next;
while(devlist)
{
next = devlist->pNext;
free(devlist);
devlist = next;
}
}

36
miniupnpc/upnpdev.h Normal file
View File

@ -0,0 +1,36 @@
/* $Id: upnpdev.h,v 1.1 2015/08/28 12:14:19 nanard Exp $ */
/* Project : miniupnp
* Web : http://miniupnp.free.fr/
* Author : Thomas BERNARD
* copyright (c) 2005-2015 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENSE file. */
#ifndef UPNPDEV_H_INCLUDED
#define UPNPDEV_H_INCLUDED
#include "miniupnpc_declspec.h"
#ifdef __cplusplus
extern "C" {
#endif
struct UPNPDev {
struct UPNPDev * pNext;
char * descURL;
char * st;
unsigned int scope_id;
char * usn;
char buffer[3];
};
/* freeUPNPDevlist()
* free list returned by upnpDiscover() */
MINIUPNP_LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist);
#ifdef __cplusplus
}
#endif
#endif /* UPNPDEV_H_INCLUDED */

View File

@ -1,5 +1,5 @@
/* $Id: upnperrors.h,v 1.2 2008/07/02 23:31:15 nanard Exp $ */
/* (c) 2007 Thomas Bernard
/* (c) 2007-2015 Thomas Bernard
* All rights reserved.
* MiniUPnP Project.
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
@ -8,7 +8,7 @@
#ifndef UPNPERRORS_H_INCLUDED
#define UPNPERRORS_H_INCLUDED
#include "declspec.h"
#include "miniupnpc_declspec.h"
#ifdef __cplusplus
extern "C" {

View File

@ -1,7 +1,7 @@
/* $Id: upnpreplyparse.c,v 1.17 2014/11/04 22:25:48 nanard Exp $ */
/* $Id: upnpreplyparse.c,v 1.19 2015/07/15 10:29:11 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2014 Thomas Bernard
* (c) 2006-2015 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
@ -40,6 +40,15 @@ NameValueParserEndElt(void * d, const char * name, int l)
/* standard case. Limited to n chars strings */
l = data->cdatalen;
nv = malloc(sizeof(struct NameValue));
if(nv == NULL)
{
/* malloc error */
#ifdef DEBUG
fprintf(stderr, "%s: error allocating memory",
"NameValueParserEndElt");
#endif /* DEBUG */
return;
}
if(l>=(int)sizeof(nv->value))
l = sizeof(nv->value) - 1;
strncpy(nv->name, data->curelt, 64);
@ -72,6 +81,10 @@ NameValueParserGetData(void * d, const char * datas, int l)
if(!data->portListing)
{
/* malloc error */
#ifdef DEBUG
fprintf(stderr, "%s: error allocating memory",
"NameValueParserGetData");
#endif /* DEBUG */
return;
}
memcpy(data->portListing, datas, l);
@ -180,5 +193,5 @@ DisplayNameValueList(char * buffer, int bufsize)
}
ClearNameValueList(&pdata);
}
#endif
#endif /* DEBUG */

View File

@ -14,3 +14,6 @@ testportinuse
netfilter/testiptcrdr
netfilter/testiptcrdr_dscp
netfilter/testiptcrdr_peer
testdescs
validateupnppermissions
validategetifaddr

View File

@ -1,4 +1,15 @@
$Id: Changelog.txt,v 1.398 2015/04/26 14:43:27 nanard Exp $
$Id: Changelog.txt,v 1.403 2015/09/22 10:10:52 nanard Exp $
2015/09/22:
cleanup UPNP_VERSION macro / add UPNP_VERSION_MAJOR, UPNP_VERSION_MINOR
Dont use packed structs anymore to read/write PCP messages
2015/09/15:
use name server from query in SOAP responses
2015/08/25:
better bind socket to right interface(s),
using struct ip_mreqn, SO_BINDTODEVICE
2015/04/30:
Adding linux/nftables support

View File

@ -167,6 +167,7 @@ clean:
$(RM) testgetroute.o testasyncsendto.o
$(RM) testportinuse.o
$(RM) miniupnpdctl.o
$(RM) validateupnppermissions validategetifaddr
install: miniupnpd miniupnpd.8 miniupnpd.conf genuuid \
netfilter/iptables_init.sh netfilter/iptables_removeall.sh \
@ -197,6 +198,16 @@ else
sed -i -e "s/^uuid=[-0-9a-f]*/uuid=`($(STAGING_DIR_HOST)/bin/genuuid||$(STAGING_DIR_HOST)/bin/uuidgen||$(STAGING_DIR_HOST)/bin/uuid) 2>/dev/null`/" miniupnpd.conf
endif
check: validateupnppermissions validategetifaddr
validateupnppermissions: testupnppermissions testupnppermissions.sh
./testupnppermissions.sh
touch $@
validategetifaddr: testgetifaddr testgetifaddr.sh
./testgetifaddr.sh
touch $@
miniupnpd: $(BASEOBJS) $(LNXOBJS) $(NETFILTEROBJS)
testupnpdescgen: $(TESTUPNPDESCGENOBJS)

View File

@ -1,4 +1,4 @@
/* $Id: asyncsendto.c,v 1.6 2014/05/19 14:26:56 nanard Exp $ */
/* $Id: asyncsendto.c,v 1.7 2015/09/03 18:19:20 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2014 Thomas Bernard
@ -11,10 +11,12 @@
#include <sys/queue.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <syslog.h>
#include <errno.h>
#include <sys/uio.h>
#include <netinet/in.h>
#include <inttypes.h>
#include "asyncsendto.h"
#include "upnputils.h"

View File

@ -1,7 +1,7 @@
/* $Id: codelength.h,v 1.3 2011/07/30 13:10:05 nanard Exp $ */
/* $Id: codelength.h,v 1.5 2015/07/09 12:40:18 nanard Exp $ */
/* Project : miniupnp
* Author : Thomas BERNARD
* copyright (c) 2005-2011 Thomas Bernard
* copyright (c) 2005-2015 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENCE file. */
#ifndef CODELENGTH_H_INCLUDED
@ -10,10 +10,30 @@
/* Encode length by using 7bit per Byte :
* Most significant bit of each byte specifies that the
* following byte is part of the code */
/* n : unsigned
* p : unsigned char *
*/
#define DECODELENGTH(n, p) n = 0; \
do { n = (n << 7) | (*p & 0x7f); } \
while((*(p++)&0x80) && (n<(1<<25)));
/* n : unsigned
* READ : function/macro to read one byte (unsigned char)
*/
#define DECODELENGTH_READ(n, READ) \
n = 0; \
do { \
unsigned char c; \
READ(c); \
n = (n << 7) | (c & 0x07f); \
if(!(c&0x80)) break; \
} while(n<(1<<25));
/* n : unsigned
* p : unsigned char *
* p_limit : unsigned char *
*/
#define DECODELENGTH_CHECKLIMIT(n, p, p_limit) \
n = 0; \
do { \
@ -21,11 +41,14 @@
n = (n << 7) | (*(p) & 0x7f); \
} while((*((p)++)&0x80) && (n<(1<<25)));
/* n : unsigned
* p : unsigned char *
*/
#define CODELENGTH(n, p) if(n>=268435456) *(p++) = (n >> 28) | 0x80; \
if(n>=2097152) *(p++) = (n >> 21) | 0x80; \
if(n>=16384) *(p++) = (n >> 14) | 0x80; \
if(n>=128) *(p++) = (n >> 7) | 0x80; \
*(p++) = n & 0x7f;
#endif
#endif /* CODELENGTH_H_INCLUDED */

View File

@ -1,8 +1,8 @@
#! /bin/sh
# $Id: genconfig.sh,v 1.78 2014/12/10 09:34:42 nanard Exp $
# $Id: genconfig.sh,v 1.81 2015/07/16 15:00:21 nanard Exp $
# miniupnp daemon
# http://miniupnp.free.fr or http://miniupnp.tuxfamily.org/
# (c) 2006-2014 Thomas Bernard
# (c) 2006-2015 Thomas Bernard
# This software is subject to the conditions detailed in the
# LICENCE file provided within the distribution
@ -36,13 +36,11 @@ done
RM="rm -f"
MV="mv"
CONFIGFILE="config.h.tmp"
CONFIGFILE=`mktemp tmp.config.h.XXXXXXXXXX`
CONFIGFILE_FINAL="config.h"
CONFIGMACRO="CONFIG_H_INCLUDED"
# version reported in XML descriptions
#UPNP_VERSION=20070827
UPNP_VERSION=`date +"%Y%m%d"`
MINIUPNPD_DATE=`date +"%Y%m%d"`
# Facility to syslog
LOG_MINIUPNPD="LOG_DAEMON"
@ -73,14 +71,15 @@ fi
# Tomato USB special case
if [ -f ../shared/tomato_version ]; then
OS_NAME=Tomato
OS_VERSION="Tomato $(cat ../shared/tomato_version)"
TOMATO_VER=`cat ../shared/tomato_version | cut -d' ' -f2,3`
OS_VERSION="Tomato $TOMATO_VER"
fi
${RM} ${CONFIGFILE}
echo "/* MiniUPnP Project" >> ${CONFIGFILE}
echo " * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/" >> ${CONFIGFILE}
echo " * (c) 2006-2014 Thomas Bernard" >> ${CONFIGFILE}
echo " * (c) 2006-2015 Thomas Bernard" >> ${CONFIGFILE}
echo " * generated by $0 on `date`" >> ${CONFIGFILE}
echo " * using command line options $* */" >> ${CONFIGFILE}
echo "#ifndef $CONFIGMACRO" >> ${CONFIGFILE}
@ -89,8 +88,26 @@ echo "" >> ${CONFIGFILE}
echo "#include <inttypes.h>" >> ${CONFIGFILE}
echo "" >> ${CONFIGFILE}
echo "#define MINIUPNPD_VERSION \"`cat VERSION`\"" >> ${CONFIGFILE}
echo "#define MINIUPNPD_DATE \"$MINIUPNPD_DATE\"" >> ${CONFIGFILE}
echo "" >> ${CONFIGFILE}
cat >> ${CONFIGFILE} <<EOF
#ifndef XSTR
#define XSTR(s) STR(s)
#define STR(s) #s
#endif /* XSTR */
EOF
echo "" >> ${CONFIGFILE}
cat >> ${CONFIGFILE} <<EOF
/* UPnP version reported in XML descriptions
* 1.0 / 1.1 / 2.0 depending on which UDA (UPnP Device Architecture) Version */
#define UPNP_VERSION_MAJOR 2
#define UPNP_VERSION_MINOR 0
#define UPNP_VERSION_MAJOR_STR XSTR(UPNP_VERSION_MAJOR)
#define UPNP_VERSION_MINOR_STR XSTR(UPNP_VERSION_MINOR)
EOF
echo "" >> ${CONFIGFILE}
echo "#define UPNP_VERSION \"$UPNP_VERSION\"" >> ${CONFIGFILE}
# OS Specific stuff
case $OS_NAME in
@ -124,6 +141,7 @@ case $OS_NAME in
if [ $VER -ge 700049 ]; then
echo "#define PFRULE_INOUT_COUNTS" >> ${CONFIGFILE}
fi
HAVE_IP_MREQN=1
# new way to see which one to use PF or IPF.
# see http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=957
if [ -f /etc/rc.subr ] && [ -f /etc/rc.conf ] ; then
@ -212,6 +230,10 @@ case $OS_NAME in
KERNVERC=`echo $OS_VERSION | awk -F. '{print $3}'`
KERNVERD=`echo $OS_VERSION | awk -F. '{print $4}'`
#echo "$KERNVERA.$KERNVERB.$KERNVERC.$KERNVERD"
# from the 2.4 version, struct ip_mreqn instead of struct ip_mreq
if [ \( $KERNVERA -ge 3 \) -o \( $KERNVERA -eq 2 -a $KERNVERB -ge 4 \) ]; then
HAVE_IP_MREQN=1
fi
# Debian GNU/Linux special case
if [ -f /etc/debian_version ]; then
OS_NAME=Debian
@ -265,7 +287,9 @@ case $OS_NAME in
OS_NAME=UPnP
OS_URL=http://tomatousb.org/
echo "" >> ${CONFIGFILE}
echo "#include <tomato_config.h>" >> ${CONFIGFILE}
echo "#ifndef TOMATO" >> ${CONFIGFILE}
echo "#define TOMATO" >> ${CONFIGFILE}
echo "#endif" >> ${CONFIGFILE}
echo "" >> ${CONFIGFILE}
echo "#ifdef LINUX26" >> ${CONFIGFILE}
echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE}
@ -431,6 +455,11 @@ else
fi
echo "" >> ${CONFIGFILE}
if [ -n "$HAVE_IP_MREQN" ]; then
echo "#define HAVE_IP_MREQN" >> ${CONFIGFILE}
echo "" >> ${CONFIGFILE}
fi
echo "/* Enable the support of IGD v2 specification." >> ${CONFIGFILE}
echo " * This is not fully tested yet and can cause incompatibilities with some" >> ${CONFIGFILE}
echo " * control points, so enable with care. */" >> ${CONFIGFILE}

View File

@ -47,6 +47,7 @@ getifaddr(const char * ifname, char * buf, int len,
return -1;
}
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
ifr.ifr_name[IFNAMSIZ-1] = '\0';
if(ioctl(s, SIOCGIFFLAGS, &ifr, &ifrlen) < 0)
{
syslog(LOG_DEBUG, "ioctl(s, SIOCGIFFLAGS, ...): %m");

View File

@ -1,4 +1,4 @@
/* $Id: ipfwaux.h,v 1.3 2011/02/20 23:43:41 nanard Exp $ */
/* $Id: ipfwaux.h,v 1.6 2015/09/04 14:20:58 nanard Exp $ */
/*
* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
@ -10,6 +10,8 @@
#define IPFWAUX_H
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip_fw.h>

View File

@ -9,6 +9,7 @@
*/
#include "../config.h"
#include "../macros.h"
#include <sys/param.h>
#include <sys/types.h>
@ -327,6 +328,13 @@ int add_filter_rule2(
int proto,
const char * desc)
{
UNUSED(ifname);
UNUSED(rhost);
UNUSED(iaddr);
UNUSED(eport);
UNUSED(iport);
UNUSED(proto);
UNUSED(desc);
return 0; /* nothing to do, always success */
}
@ -335,6 +343,9 @@ int delete_filter_rule(
unsigned short eport,
int proto)
{
UNUSED(ifname);
UNUSED(eport);
UNUSED(proto);
return 0; /* nothing to do, always success */
}

View File

@ -107,7 +107,7 @@ getifstats(const char * ifname, struct ifdata * data)
}
fclose(f);
} else {
syslog(LOG_WARNING, "cannot read %s file : %m", fname);
syslog(LOG_INFO, "cannot read %s file : %m", fname);
}
#ifdef GET_WIRELESS_STATS
if(data->baudrate == BAUDRATE_DEFAULT) {

View File

@ -1,7 +1,7 @@
/* $Id: macros.h,v 1.1 2012/04/30 20:37:56 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2012 Thomas Bernard
* (c) 2012-2015 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
@ -10,5 +10,36 @@
#define UNUSED(arg) (void)(arg)
#endif
#include <stdint.h>
#define INLINE static inline
/* theses macros are designed to read/write unsigned short/long int
* from an unsigned char array in network order (big endian).
* Avoid pointer casting, so avoid accessing unaligned memory, which
* can crash with some cpu's */
INLINE uint32_t readnu32(const uint8_t * p)
{
return (p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]);
}
#define READNU32(p) readnu32(p)
INLINE uint16_t readnu16(const uint8_t * p)
{
return (p[0] << 8 | p[1]);
}
#define READNU16(p) readnu16(p)
INLINE void writenu32(uint8_t * p, uint32_t n)
{
p[0] = (n & 0xff000000) >> 24;
p[1] = (n & 0xff0000) >> 16;
p[2] = (n & 0xff00) >> 8;
p[3] = n & 0xff;
}
#define WRITENU32(p, n) writenu32(p, n)
INLINE void writenu16(uint8_t * p, uint16_t n)
{
p[0] = (n & 0xff00) >> 8;
p[1] = n & 0xff;
}
#define WRITENU16(p, n) writenu16(p, n)
#endif /* MACROS_H_INCLUDED */

View File

@ -1,4 +1,4 @@
/* $Id: minissdp.c,v 1.73 2015/01/17 11:26:05 nanard Exp $ */
/* $Id: minissdp.c,v 1.77 2015/08/26 07:36:52 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2015 Thomas Bernard
@ -44,20 +44,42 @@
#endif
/* AddMulticastMembership()
* param s socket
* param ifaddr ip v4 address
* param s socket
* param lan_addr lan address
*/
static int
AddMulticastMembership(int s, in_addr_t ifaddr)
AddMulticastMembership(int s, struct lan_addr_s * lan_addr)
{
#ifndef HAVE_IP_MREQN
/* The ip_mreqn structure appeared in Linux 2.4. */
struct ip_mreq imr; /* Ip multicast membership */
#else /* HAVE_IP_MREQN */
struct ip_mreqn imr; /* Ip multicast membership */
#endif /* HAVE_IP_MREQN */
/* setting up imr structure */
imr.imr_multiaddr.s_addr = inet_addr(SSDP_MCAST_ADDR);
/*imr.imr_interface.s_addr = htonl(INADDR_ANY);*/
imr.imr_interface.s_addr = ifaddr; /*inet_addr(ifaddr);*/
#ifndef HAVE_IP_MREQN
imr.imr_interface.s_addr = lan_addr->addr.s_addr;
#else /* HAVE_IP_MREQN */
imr.imr_address.s_addr = lan_addr->addr.s_addr;
#ifndef MULTIPLE_EXTERNAL_IP
#ifdef ENABLE_IPV6
imr.imr_ifindex = lan_addr->index;
#else /* ENABLE_IPV6 */
imr.imr_ifindex = if_nametoindex(lan_addr->ifname);
#endif /* ENABLE_IPV6 */
#else /* MULTIPLE_EXTERNAL_IP */
imr.imr_ifindex = 0;
#endif /* MULTIPLE_EXTERNAL_IP */
#endif /* HAVE_IP_MREQN */
#ifndef HAVE_IP_MREQN
if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&imr, sizeof(struct ip_mreq)) < 0)
#else /* HAVE_IP_MREQN */
if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&imr, sizeof(struct ip_mreqn)) < 0)
#endif /* HAVE_IP_MREQN */
{
syslog(LOG_ERR, "setsockopt(udp, IP_ADD_MEMBERSHIP): %m");
return -1;
@ -155,6 +177,20 @@ OpenAndConfSSDPReceiveSocket(int ipv6)
"OpenAndConfSSDPReceiveSocket");
}
#if defined(SO_BINDTODEVICE) && !defined(MULTIPLE_EXTERNAL_IP)
/* One and only one LAN interface */
if(lan_addrs.lh_first != NULL && lan_addrs.lh_first->list.le_next == NULL
&& strlen(lan_addrs.lh_first->ifname) > 0)
{
if(setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE,
lan_addrs.lh_first->ifname,
strlen(lan_addrs.lh_first->ifname)) < 0)
syslog(LOG_WARNING, "%s: setsockopt(udp%s, SO_BINDTODEVICE, %s): %m",
"OpenAndConfSSDPReceiveSocket", ipv6 ? "6" : "",
lan_addrs.lh_first->ifname);
}
#endif /* defined(SO_BINDTODEVICE) && !defined(MULTIPLE_EXTERNAL_IP) */
if(bind(s, (struct sockaddr *)&sockname, sockname_len) < 0)
{
syslog(LOG_ERR, "%s: bind(udp%s): %m",
@ -181,11 +217,11 @@ OpenAndConfSSDPReceiveSocket(int ipv6)
{
for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next)
{
if(AddMulticastMembership(s, lan_addr->addr.s_addr) < 0)
if(AddMulticastMembership(s, lan_addr) < 0)
{
syslog(LOG_WARNING,
"Failed to add multicast membership for interface %s",
lan_addr->str ? lan_addr->str : "NULL");
strlen(lan_addr->str) ? lan_addr->str : "NULL");
}
}
}
@ -499,7 +535,7 @@ static struct {
{"urn:schemas-upnp-org:service:Layer3Forwarding:", 1, uuidvalue_igd},
#endif
#ifdef ENABLE_6FC_SERVICE
{"url:schemas-upnp-org:service:WANIPv6FirewallControl:", 1, uuidvalue_wcd},
{"urn:schemas-upnp-org:service:WANIPv6FirewallControl:", 1, uuidvalue_wcd},
#endif
/* we might want to support urn:schemas-wifialliance-org:device:WFADevice:1
* urn:schemas-wifialliance-org:device:WFADevice:1
@ -1237,6 +1273,7 @@ SubmitServicesToMiniSSDPD(const char * host, unsigned short port) {
}
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, minissdpdsocketpath, sizeof(addr.sun_path));
addr.sun_path[sizeof(addr.sun_path) - 1] = '\0';
if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) {
syslog(LOG_ERR, "connect(\"%s\"): %m", minissdpdsocketpath);
close(s);

View File

@ -1,4 +1,4 @@
/* $Id: miniupnpd.c,v 1.206 2015/01/17 11:26:04 nanard Exp $ */
/* $Id: miniupnpd.c,v 1.210 2015/08/26 07:32:32 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2015 Thomas Bernard
@ -49,6 +49,9 @@
#include <sys/un.h>
#endif
#ifdef TOMATO
#include <sys/stat.h>
#endif /* TOMATO */
#include "macros.h"
#include "upnpglobalvars.h"
#include "upnphttp.h"
@ -92,7 +95,7 @@ struct ctlelem {
int socket;
LIST_ENTRY(ctlelem) entries;
};
#endif
#endif /* USE_MINIUPNPDCTL */
#ifdef ENABLE_NFQUEUE
/* globals */
@ -103,12 +106,187 @@ static struct sockaddr_in ssdp;
static int nfqueue_cb( struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *data) ;
int identify_ip_protocol (char *payload);
int get_udp_dst_port (char *payload);
#endif
#endif /* ENABLE_NFQUEUE */
/* variables used by signals */
static volatile sig_atomic_t quitting = 0;
volatile sig_atomic_t should_send_public_address_change_notif = 0;
#ifdef TOMATO
#if 1
/* Tomato specific code */
static volatile sig_atomic_t gotusr2 = 0;
static void
sigusr2(int sig)
{
gotusr2 = 1;
}
static void
tomato_save(const char *fname)
{
unsigned short eport;
unsigned short iport;
unsigned int leaseduration;
unsigned int timestamp;
char proto[4];
char iaddr[32];
char desc[64];
char rhost[32];
int n;
FILE *f;
int t;
char tmp[128];
strcpy(tmp, "/etc/upnp/saveXXXXXX");
if ((t = mkstemp(tmp)) != -1)
{
if ((f = fdopen(t, "w")) != NULL)
{
n = 0;
while (upnp_get_redirection_infos_by_index(n, &eport, proto, &iport, iaddr, sizeof(iaddr), desc, sizeof(desc), rhost, sizeof(rhost), &leaseduration) == 0)
{
timestamp = (leaseduration > 0) ? time(NULL) + leaseduration : 0;
fprintf(f, "%s %u %s %u [%s] %u\n", proto, eport, iaddr, iport, desc, timestamp);
++n;
}
fclose(f);
rename(tmp, fname);
}
else
{
close(t);
}
unlink(tmp);
}
}
static void
tomato_load(void)
{
FILE *f;
char s[256];
unsigned short eport;
unsigned short iport;
unsigned int leaseduration;
unsigned int timestamp;
time_t current_time;
char proto[4];
char iaddr[32];
char *rhost;
char *a, *b;
if ((f = fopen("/etc/upnp/data", "r")) != NULL)
{
current_time = time(NULL);
s[sizeof(s) - 1] = 0;
while (fgets(s, sizeof(s) - 1, f)) {
if (sscanf(s, "%3s %hu %31s %hu [%*s] %u", proto, &eport, iaddr, &iport, &timestamp) >= 4)
{
if (((a = strchr(s, '[')) != NULL) && ((b = strrchr(a, ']')) != NULL))
{
if (timestamp > 0)
{
if (timestamp > current_time)
leaseduration = current_time - timestamp;
else
continue;
}
else
{
leaseduration = 0; /* default value */
}
*b = 0;
rhost = NULL;
upnp_redirect(rhost, eport, iaddr, iport, proto, a + 1, leaseduration);
}
}
}
fclose(f);
}
#ifdef ENABLE_NATPMP
#if 0
ScanNATPMPforExpiration();
#endif
#endif /* ENABLE_NATPMP */
unlink("/etc/upnp/load");
}
static void
tomato_delete(void)
{
FILE *f;
char s[128];
unsigned short eport;
unsigned short iport;
unsigned int leaseduration;
char proto[4];
char iaddr[32];
char desc[64];
char rhost[32];
int n;
if ((f = fopen("/etc/upnp/delete", "r")) != NULL)
{
s[sizeof(s) - 1] = 0;
while (fgets(s, sizeof(s) - 1, f))
{
if (sscanf(s, "%3s %hu", proto, &eport) == 2)
{
if (proto[0] == '*')
{
n = upnp_get_portmapping_number_of_entries();
while (--n >= 0)
{
if (upnp_get_redirection_infos_by_index(n, &eport, proto, &iport, iaddr, sizeof(iaddr), desc, sizeof(desc), rhost, sizeof(rhost), &leaseduration) == 0)
{
upnp_delete_redirection(eport, proto);
}
}
break;
}
else
{
upnp_delete_redirection(eport, proto);
}
}
}
fclose(f);
unlink("/etc/upnp/delete");
}
}
static void
tomato_helper(void)
{
struct stat st;
if (stat("/etc/upnp/delete", &st) == 0)
{
tomato_delete();
}
if (stat("/etc/upnp/load", &st) == 0)
{
tomato_load();
}
if (stat("/etc/upnp/save", &st) == 0)
{
tomato_save("/etc/upnp/data");
unlink("/etc/upnp/save");
}
if (stat("/etc/upnp/info", &st) == 0)
{
tomato_save("/etc/upnp/data.info");
unlink("/etc/upnp/info");
}
}
#endif /* 1 (tomato) */
#endif /* TOMATO */
/* OpenAndConfHTTPSocket() :
* setup the socket used to handle incoming HTTP connections. */
static int
@ -192,6 +370,19 @@ OpenAndConfHTTPSocket(unsigned short * port)
listenname_len = sizeof(struct sockaddr_in);
#endif
#if defined(SO_BINDTODEVICE) && !defined(MULTIPLE_EXTERNAL_IP)
/* One and only one LAN interface */
if(lan_addrs.lh_first != NULL && lan_addrs.lh_first->list.le_next == NULL
&& strlen(lan_addrs.lh_first->ifname) > 0)
{
if(setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE,
lan_addrs.lh_first->ifname,
strlen(lan_addrs.lh_first->ifname)) < 0)
syslog(LOG_WARNING, "setsockopt(http, SO_BINDTODEVICE, %s): %m",
lan_addrs.lh_first->ifname);
}
#endif /* defined(SO_BINDTODEVICE) && !defined(MULTIPLE_EXTERNAL_IP) */
#ifdef ENABLE_IPV6
if(bind(s,
ipv6 ? (struct sockaddr *)&listenname6 : (struct sockaddr *)&listenname4,
@ -991,7 +1182,7 @@ init(int argc, char * * argv, struct runtime_vars * v)
strncpy(model_url, ary_options[i].value, MODEL_URL_MAX_LEN);
model_url[MODEL_URL_MAX_LEN-1] = '\0';
break;
#endif
#endif /* ENABLE_MANUFACTURER_INFO_CONFIGURATION */
#ifdef USE_NETFILTER
case UPNPFORWARDCHAIN:
miniupnpd_forward_chain = ary_options[i].value;
@ -999,7 +1190,7 @@ init(int argc, char * * argv, struct runtime_vars * v)
case UPNPNATCHAIN:
miniupnpd_nat_chain = ary_options[i].value;
break;
#endif
#endif /* USE_NETFILTER */
case UPNPNOTIFY_INTERVAL:
v->notify_interval = atoi(ary_options[i].value);
break;
@ -1012,7 +1203,7 @@ init(int argc, char * * argv, struct runtime_vars * v)
if(strcmp(ary_options[i].value, "yes") == 0)
SETFLAG(LOGPACKETSMASK); /*logpackets = 1;*/
break;
#endif
#endif /* defined(USE_PF) || defined(USE_IPF) */
case UPNPUUID:
strncpy(uuidvalue_igd+5, ary_options[i].value,
strlen(uuidvalue_igd+5) + 1);
@ -1042,7 +1233,7 @@ init(int argc, char * * argv, struct runtime_vars * v)
case UPNPTAG:
tag = ary_options[i].value;
break;
#endif
#endif /* USE_PF */
#ifdef ENABLE_NATPMP
case UPNPENABLENATPMP:
if(strcmp(ary_options[i].value, "yes") == 0)
@ -1052,7 +1243,7 @@ init(int argc, char * * argv, struct runtime_vars * v)
SETFLAG(ENABLENATPMPMASK);
/*enablenatpmp = atoi(ary_options[i].value);*/
break;
#endif
#endif /* ENABLE_NATPMP */
#ifdef ENABLE_PCP
case UPNPPCPMINLIFETIME:
min_lifetime = atoi(ary_options[i].value);
@ -1070,13 +1261,13 @@ init(int argc, char * * argv, struct runtime_vars * v)
if(strcmp(ary_options[i].value, "yes") == 0)
SETFLAG(PCP_ALLOWTHIRDPARTYMASK);
break;
#endif
#endif /* ENABLE_PCP */
#ifdef PF_ENABLE_FILTER_RULES
case UPNPQUICKRULES:
if(strcmp(ary_options[i].value, "no") == 0)
SETFLAG(PFNOQUICKRULESMASK);
break;
#endif
#endif /* PF_ENABLE_FILTER_RULES */
case UPNPENABLE:
if(strcmp(ary_options[i].value, "yes") != 0)
CLEARFLAG(ENABLEUPNPMASK);
@ -1089,7 +1280,7 @@ init(int argc, char * * argv, struct runtime_vars * v)
case UPNPLEASEFILE:
lease_file = ary_options[i].value;
break;
#endif
#endif /* ENABLE_LEASEFILE */
case UPNPMINISSDPDSOCKET:
minissdpdsocketpath = ary_options[i].value;
break;
@ -1105,7 +1296,7 @@ init(int argc, char * * argv, struct runtime_vars * v)
fprintf(stderr, "Check your configuration file.\n");
return 1;
}
#endif
#endif /* ENABLE_PCP */
}
#endif /* DISABLE_CONFIG_FILE */
@ -1157,7 +1348,7 @@ init(int argc, char * * argv, struct runtime_vars * v)
fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
friendly_name[FRIENDLY_NAME_MAX_LEN-1] = '\0';
break;
#endif
#endif /* ENABLE_MANUFACTURER_INFO_CONFIGURATION */
case 's':
if(i+1 < argc)
strncpy(serialnumber, argv[++i], SERIALNUMBER_MAX_LEN);
@ -1177,7 +1368,7 @@ init(int argc, char * * argv, struct runtime_vars * v)
/*enablenatpmp = 1;*/
SETFLAG(ENABLENATPMPMASK);
break;
#endif
#endif /* ENABLE_NATPMP */
case 'U':
/*sysuptime = 1;*/
SETFLAG(SYSUPTIMEMASK);
@ -1190,7 +1381,7 @@ init(int argc, char * * argv, struct runtime_vars * v)
/*logpackets = 1;*/
SETFLAG(LOGPACKETSMASK);
break;
#endif
#endif /* defined(USE_PF) || defined(USE_IPF) */
case 'S':
SETFLAG(SECUREMODEMASK);
break;
@ -1213,7 +1404,7 @@ init(int argc, char * * argv, struct runtime_vars * v)
else
fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
break;
#endif
#endif /* USE_PF */
case 'p':
if(i+1 < argc)
v->port = atoi(argv[++i]);
@ -1227,7 +1418,7 @@ init(int argc, char * * argv, struct runtime_vars * v)
else
fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
break;
#endif
#endif /* ENABLE_HTTPS */
#ifdef ENABLE_NFQUEUE
case 'Q':
if(i+1<argc)
@ -1249,7 +1440,7 @@ init(int argc, char * * argv, struct runtime_vars * v)
fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
}
break;
#endif
#endif /* ENABLE_NFQUEUE */
case 'P':
if(i+1 < argc)
pidfilename = argv[++i];
@ -1290,7 +1481,7 @@ init(int argc, char * * argv, struct runtime_vars * v)
fprintf(stderr, "can't parse \"%s\" as a valid "
#ifndef ENABLE_IPV6
"LAN address or "
#endif
#endif /* #ifndef ENABLE_IPV6 */
"interface name\n", argv[i]);
free(lan_addr);
break;
@ -1306,7 +1497,7 @@ init(int argc, char * * argv, struct runtime_vars * v)
}
else
fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
#else
#else /* #ifndef MULTIPLE_EXTERNAL_IP */
if(i+2 < argc)
{
char *val=calloc((strlen(argv[i+1]) + strlen(argv[i+2]) + 1), sizeof(char));
@ -1345,7 +1536,7 @@ init(int argc, char * * argv, struct runtime_vars * v)
}
else
fprintf(stderr, "Option -%c takes two arguments.\n", argv[i][1]);
#endif
#endif /* #ifndef MULTIPLE_EXTERNAL_IP */
break;
case 'A':
if(i+1 < argc) {
@ -1413,6 +1604,10 @@ init(int argc, char * * argv, struct runtime_vars * v)
return 1;
}
#ifdef TOMATO
syslog(LOG_NOTICE, "version " MINIUPNPD_VERSION " started");
#endif /* TOMATO */
set_startup_time(GETFLAG(SYSUPTIMEMASK));
/* presentation url */
@ -1442,8 +1637,14 @@ init(int argc, char * * argv, struct runtime_vars * v)
syslog(LOG_ERR, "Failed to set %s handler. EXITING", "SIGINT");
return 1;
}
#ifdef TOMATO
sa.sa_handler = sigusr2;
sigaction(SIGUSR2, &sa, NULL);
if(signal(SIGPIPE, SIG_IGN) == SIG_ERR)
#else /* TOMATO */
sa.sa_handler = SIG_IGN;
if(sigaction(SIGPIPE, &sa, NULL) < 0)
#endif /* TOMATO */
{
syslog(LOG_ERR, "Failed to ignore SIGPIPE signals");
}
@ -1477,6 +1678,10 @@ init(int argc, char * * argv, struct runtime_vars * v)
reload_from_lease_file();
#endif
#ifdef TOMATO
tomato_load();
#endif /* TOMATO */
return 0;
print_usage:
fprintf(stderr, "Usage:\n\t"
@ -1810,6 +2015,10 @@ main(int argc, char * * argv)
}
#endif
#ifdef TOMATO
tomato_helper();
#endif
/* main loop */
while(!quitting)
{
@ -2064,6 +2273,14 @@ main(int argc, char * * argv)
if(select(max_fd+1, &readset, &writeset, 0, &timeout) < 0)
{
if(quitting) goto shutdown;
#ifdef TOMATO
if (gotusr2)
{
gotusr2 = 0;
tomato_helper();
continue;
}
#endif /* TOMATO */
if(errno == EINTR) continue; /* interrupted by a signal, start again */
syslog(LOG_ERR, "select(all): %m");
syslog(LOG_ERR, "Failed to select open sockets. EXITING");
@ -2349,6 +2566,9 @@ shutdown:
/* try to send pending packets */
finalize_sendto();
#ifdef TOMATO
tomato_save("/etc/upnp/data");
#endif /* TOMATO */
/* close out open sockets */
while(upnphttphead.lh_first != NULL)
{

View File

@ -1,4 +1,4 @@
/* $Id: natpmp.c,v 1.51 2015/02/08 09:18:15 nanard Exp $ */
/* $Id: natpmp.c,v 1.52 2015/05/27 12:43:14 nanard Exp $ */
/* MiniUPnP project
* (c) 2007-2015 Thomas Bernard
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
@ -29,36 +29,6 @@
#ifdef ENABLE_NATPMP
#define INLINE static inline
/* theses macros are designed to read/write unsigned short/long int
* from an unsigned char array in network order (big endian).
* Avoid pointer casting, so avoid accessing unaligned memory, which
* can crash with some cpu's */
INLINE uint32_t readnu32(const uint8_t * p)
{
return (p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]);
}
#define READNU32(p) readnu32(p)
INLINE uint16_t readnu16(const uint8_t * p)
{
return (p[0] << 8 | p[1]);
}
#define READNU16(p) readnu16(p)
INLINE void writenu32(uint8_t * p, uint32_t n)
{
p[0] = (n & 0xff000000) >> 24;
p[1] = (n & 0xff0000) >> 16;
p[2] = (n & 0xff00) >> 8;
p[3] = n & 0xff;
}
#define WRITENU32(p, n) writenu32(p, n)
INLINE void writenu16(uint8_t * p, uint16_t n)
{
p[0] = (n & 0xff00) >> 8;
p[1] = n & 0xff;
}
#define WRITENU16(p, n) writenu16(p, n)
int OpenAndConfNATPMPSocket(in_addr_t addr)
{
int snatpmp;
@ -394,7 +364,7 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len,
if(r==0) {
if(strcmp(senderaddrstr, iaddr_old)==0
&& iport==iport_old) {
/* redirection allready existing */
/* redirection already existing */
syslog(LOG_INFO, "port %hu %s already redirected to %s:%hu, replacing",
eport, (proto==IPPROTO_TCP)?"tcp":"udp", iaddr_old, iport_old);
/* remove and then add again */
@ -513,5 +483,4 @@ void SendNATPMPPublicAddressChangeNotification(int * sockets, int n_sockets)
}
}
#endif
#endif /* ENABLE_NATPMP */

View File

@ -29,6 +29,8 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PCP_MSG_STRUCT_H_INCLUDED
#define PCP_MSG_STRUCT_H_INCLUDED
#define PCP_OPCODE_ANNOUNCE 0
#define PCP_OPCODE_MAP 1
@ -135,14 +137,8 @@ typedef enum pcp_options {
} pcp_options_t;
#ifdef _WIN32
#pragma warning (push)
#pragma warning (disable:4200)
#endif /* _WIN32 */
#pragma pack(push, 1)
/* PCP common request header*/
#if 0
typedef struct pcp_request {
uint8_t ver;
uint8_t r_opcode;
@ -152,8 +148,11 @@ typedef struct pcp_request {
by the ipv4 mapped ipv6 */
uint8_t next_data[0];
} pcp_request_t;
#endif
#define PCP_COMMON_REQUEST_SIZE (24)
/* PCP common response header*/
#if 0
typedef struct pcp_response {
uint8_t ver;
uint8_t r_opcode; /* R indicates Request (0) or Response (1)
@ -166,16 +165,22 @@ typedef struct pcp_response {
uint32_t reserved1[3];/* For requests that were successfully parsed this must be sent as 0 */
uint8_t next_data[0];
} pcp_response_t;
#endif
#define PCP_COMMON_RESPONSE_SIZE (24)
#if 0
typedef struct pcp_options_hdr {
uint8_t code; /* Most significant bit indicates if this option is mandatory (0) or optional (1) */
uint8_t reserved; /* MUST be set to 0 on transmission and MUST be ignored on reception */
uint16_t len; /* indicates the length of the enclosed data in octets (see RFC) */
uint8_t next_data[0]; /* */
} pcp_options_hdr_t;
#endif
#define PCP_OPTION_HDR_SIZE (4)
/* same for both request and response */
#if 0
typedef struct pcp_map_v2 {
uint32_t nonce[3];
uint8_t protocol; /* 6 = TCP, 17 = UDP, 0 = 'all protocols' */
@ -186,7 +191,10 @@ typedef struct pcp_map_v2 {
* ipv4 will be represented by the ipv4 mapped ipv6 */
uint8_t next_data[0];
} pcp_map_v2_t;
#endif
#define PCP_MAP_V2_SIZE (36)
#if 0
/* same for both request and response */
typedef struct pcp_map_v1 {
uint8_t protocol;
@ -197,8 +205,11 @@ typedef struct pcp_map_v1 {
by the ipv4 mapped ipv6 */
uint8_t next_data[0];
} pcp_map_v1_t;
#endif
#define PCP_MAP_V1_SIZE (24)
/* same for both request and response */
#if 0
typedef struct pcp_peer_v1 {
uint8_t protocol;
uint8_t reserved[3];
@ -211,8 +222,11 @@ typedef struct pcp_peer_v1 {
struct in6_addr peer_ip;
uint8_t next_data[0];
} pcp_peer_v1_t;
#endif
#define PCP_PEER_V1_SIZE (44)
/* same for both request and response */
#if 0
typedef struct pcp_peer_v2 {
uint32_t nonce[3];
uint8_t protocol;
@ -226,30 +240,41 @@ typedef struct pcp_peer_v2 {
struct in6_addr peer_ip;
uint8_t next_data[0];
} pcp_peer_v2_t;
#endif
#define PCP_PEER_V2_SIZE (56)
#ifdef PCP_SADSCP
#if 0
typedef struct pcp_sadscp_req {
uint32_t nonce[3];
uint8_t tolerance_fields;
uint8_t app_name_length;
char app_name[0];
} pcp_sadscp_req_t;
#endif
#define PCP_SADSCP_REQ_SIZE (14)
#if 0
typedef struct pcp_sadscp_resp {
uint32_t nonce[3];
#define PCP_SADSCP_MASK ((1<<6)-1)
uint8_t a_r_dscp_value;
uint8_t reserved[3];
} pcp_sadscp_resp_t;
#endif
#define PCP_SADSCP_MASK ((1<<6)-1)
#endif /* PCP_SADSCP */
#if 0
typedef struct pcp_prefer_fail_option {
uint8_t option;
uint8_t reserved;
uint16_t len;
uint8_t next_data[0];
} pcp_prefer_fail_option_t;
#endif
#define PCP_PREFER_FAIL_OPTION_SIZE (4)
#if 0
typedef struct pcp_3rd_party_option{
uint8_t option;
uint8_t reserved;
@ -257,22 +282,28 @@ typedef struct pcp_3rd_party_option{
struct in6_addr ip;
uint8_t next_data[0];
} pcp_3rd_party_option_t;
#endif
#define PCP_3RD_PARTY_OPTION_SIZE (20)
#ifdef PCP_FLOWP
#if 0
typedef struct pcp_flow_priority_option{
uint8_t option;
uint8_t reserved;
uint16_t len;
uint8_t dscp_up;
uint8_t dscp_down;
#define PCP_DSCP_MASK ((1<<6)-1)
uint8_t reserved2;
/* most significant bit is used for response */
uint8_t response_bit;
uint8_t next_data[0];
} pcp_flow_priority_option_t;
#endif
#define PCP_DSCP_MASK ((1<<6)-1)
#define PCP_FLOW_PRIORITY_OPTION_SIZE (8)
#endif
#if 0
typedef struct pcp_filter_option {
uint8_t option;
uint8_t reserved1;
@ -282,9 +313,7 @@ typedef struct pcp_filter_option {
uint16_t peer_port;
struct in6_addr peer_ip;
}pcp_filter_option_t;
#endif
#define PCP_FILTER_OPTION_SIZE (24)
#pragma pack(pop)
#ifdef _WIN32
#pragma warning (pop)
#endif /* _WIN32 */
#endif /* PCP_MSG_STRUCT_H_INCLUDED */

View File

@ -1,4 +1,4 @@
/* $Id: pcpserver.c,v 1.38 2014/10/27 16:35:13 nanard Exp $ */
/* $Id: pcpserver.c,v 1.39 2015/06/22 07:28:21 nanard Exp $ */
/* MiniUPnP project
* Website : http://miniupnp.free.fr/
* Author : Peter Tatrai
@ -153,6 +153,36 @@ typedef struct pcp_info {
char desc[64];
} pcp_info_t;
/* getPCPOpCodeStr()
* return a string representation of the PCP OpCode
* can be used for debug output */
static const char * getPCPOpCodeStr(uint8_t opcode)
{
switch(opcode) {
case PCP_OPCODE_ANNOUNCE:
return "ANNOUNCE";
case PCP_OPCODE_MAP:
return "MAP";
case PCP_OPCODE_PEER:
return "PEER";
#ifdef PCP_SADSCP
case PCP_OPCODE_SADSCP:
return "SADSCP";
#endif /* PCP_SADSCP */
default:
return "UNKNOWN";
}
}
/* useful to copy ext_ip only if needed, as request and response
* buffers are same */
static void copyIPv6IfDifferent(void * dest, const void * src)
{
if(dest != src) {
memcpy(dest, src, sizeof(struct in6_addr));
}
}
#ifdef PCP_SADSCP
int get_dscp_value(pcp_info_t *pcp_msg_info) {
@ -207,16 +237,16 @@ int get_dscp_value(pcp_info_t *pcp_msg_info) {
* result code is assigned to pcp_msg_info->result_code to indicate
* what kind of error occurred
*/
static int parseCommonRequestHeader(const pcp_request_t *common_req, pcp_info_t *pcp_msg_info)
static int parseCommonRequestHeader(const uint8_t *common_req, pcp_info_t *pcp_msg_info)
{
pcp_msg_info->version = common_req->ver ;
pcp_msg_info->opcode = common_req->r_opcode & 0x7f;
pcp_msg_info->lifetime = ntohl(common_req->req_lifetime);
pcp_msg_info->int_ip = &common_req->ip;
pcp_msg_info->mapped_ip = &common_req->ip;
pcp_msg_info->version = common_req[0] ;
pcp_msg_info->opcode = common_req[1] & 0x7f;
pcp_msg_info->lifetime = READNU32(common_req + 4);
pcp_msg_info->int_ip = (struct in6_addr *)(common_req + 8);
pcp_msg_info->mapped_ip = (struct in6_addr *)(common_req + 8);
if ( (common_req->ver > this_server_info.server_version) ) {
if ( (pcp_msg_info->version > this_server_info.server_version) ) {
pcp_msg_info->result_code = PCP_ERR_UNSUPP_VERSION;
return 1;
}
@ -233,102 +263,87 @@ static int parseCommonRequestHeader(const pcp_request_t *common_req, pcp_info_t
}
#ifdef DEBUG
static void printMAPOpcodeVersion1(const pcp_map_v1_t *map_buf)
static void printMAPOpcodeVersion1(const uint8_t *buf)
{
char map_addr[INET6_ADDRSTRLEN];
syslog(LOG_DEBUG, "PCP MAP: v1 Opcode specific information. \n");
syslog(LOG_DEBUG, "MAP protocol: \t\t %d\n",map_buf->protocol );
syslog(LOG_DEBUG, "MAP int port: \t\t %d\n", ntohs(map_buf->int_port) );
syslog(LOG_DEBUG, "MAP ext port: \t\t %d\n", ntohs(map_buf->ext_port) );
syslog(LOG_DEBUG, "MAP protocol: \t\t %d\n", (int)buf[0] );
syslog(LOG_DEBUG, "MAP int port: \t\t %d\n", (int)READNU16(buf+4));
syslog(LOG_DEBUG, "MAP ext port: \t\t %d\n", (int)READNU16(buf+6));
syslog(LOG_DEBUG, "MAP Ext IP: \t\t %s\n", inet_ntop(AF_INET6,
&map_buf->ext_ip, map_addr, INET6_ADDRSTRLEN));
buf+8, map_addr, INET6_ADDRSTRLEN));
}
static void printMAPOpcodeVersion2(const pcp_map_v2_t *map_buf)
static void printMAPOpcodeVersion2(const uint8_t *buf)
{
char map_addr[INET6_ADDRSTRLEN];
syslog(LOG_DEBUG, "PCP MAP: v2 Opcode specific information.");
syslog(LOG_DEBUG, "MAP nonce: \t%08x%08x%08x",
map_buf->nonce[0], map_buf->nonce[1], map_buf->nonce[2]);
syslog(LOG_DEBUG, "MAP protocol:\t%d", map_buf->protocol);
syslog(LOG_DEBUG, "MAP int port:\t%d", ntohs(map_buf->int_port));
syslog(LOG_DEBUG, "MAP ext port:\t%d", ntohs(map_buf->ext_port));
READNU32(buf), READNU32(buf+4), READNU32(buf+8));
syslog(LOG_DEBUG, "MAP protocol:\t%d", (int)buf[12]);
syslog(LOG_DEBUG, "MAP int port:\t%d", (int)READNU16(buf+16));
syslog(LOG_DEBUG, "MAP ext port:\t%d", (int)READNU16(buf+18));
syslog(LOG_DEBUG, "MAP Ext IP: \t%s", inet_ntop(AF_INET6,
&map_buf->ext_ip, map_addr, INET6_ADDRSTRLEN));
buf+20, map_addr, INET6_ADDRSTRLEN));
}
#endif /* DEBUG */
static int parsePCPMAP_version1(const pcp_map_v1_t *map_v1,
static void parsePCPMAP_version1(const uint8_t *map_v1,
pcp_info_t *pcp_msg_info)
{
pcp_msg_info->is_map_op = 1;
pcp_msg_info->protocol = map_v1->protocol;
pcp_msg_info->int_port = ntohs(map_v1->int_port);
pcp_msg_info->ext_port = ntohs(map_v1->ext_port);
pcp_msg_info->protocol = map_v1[0];
pcp_msg_info->int_port = READNU16(map_v1 + 4);
pcp_msg_info->ext_port = READNU16(map_v1 + 6);
pcp_msg_info->ext_ip = &(map_v1->ext_ip);
if (pcp_msg_info->protocol == 0 && pcp_msg_info->int_port !=0 ){
syslog(LOG_ERR, "PCP MAP: Protocol was ZERO, but internal port has non-ZERO value.");
pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST;
return 1;
}
return 0;
pcp_msg_info->ext_ip = (struct in6_addr *)(map_v1 + 8);
}
static int parsePCPMAP_version2(const pcp_map_v2_t *map_v2,
static void parsePCPMAP_version2(const uint8_t *map_v2,
pcp_info_t *pcp_msg_info)
{
pcp_msg_info->is_map_op = 1;
memcpy(pcp_msg_info->nonce, map_v2->nonce, 12);
pcp_msg_info->protocol = map_v2->protocol;
pcp_msg_info->int_port = ntohs(map_v2->int_port);
pcp_msg_info->ext_port = ntohs(map_v2->ext_port);
memcpy(pcp_msg_info->nonce, map_v2, 12);
pcp_msg_info->protocol = map_v2[12];
pcp_msg_info->int_port = READNU16(map_v2 + 16);
pcp_msg_info->ext_port = READNU16(map_v2 + 18);
pcp_msg_info->ext_ip = &(map_v2->ext_ip);
if (pcp_msg_info->protocol == 0 && pcp_msg_info->int_port !=0 ) {
syslog(LOG_ERR, "PCP MAP: Protocol was ZERO, but internal port has non-ZERO value.");
pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST;
return PCP_ERR_MALFORMED_REQUEST;
}
return 0;
pcp_msg_info->ext_ip = (struct in6_addr *)(map_v2 + 20);
}
#ifdef PCP_PEER
#ifdef DEBUG
static void printPEEROpcodeVersion1(pcp_peer_v1_t *peer_buf)
static void printPEEROpcodeVersion1(const uint8_t *buf)
{
char ext_addr[INET6_ADDRSTRLEN];
char peer_addr[INET6_ADDRSTRLEN];
syslog(LOG_DEBUG, "PCP PEER: v1 Opcode specific information. \n");
syslog(LOG_DEBUG, "Protocol: \t\t %d\n",peer_buf->protocol );
syslog(LOG_DEBUG, "Internal port: \t\t %d\n", ntohs(peer_buf->int_port) );
syslog(LOG_DEBUG, "External IP: \t\t %s\n", inet_ntop(AF_INET6, &peer_buf->ext_ip,
syslog(LOG_DEBUG, "Protocol: \t\t %d\n", (int)buf[0]);
syslog(LOG_DEBUG, "Internal port: \t\t %d\n", READNU16(buf + 4));
syslog(LOG_DEBUG, "External IP: \t\t %s\n", inet_ntop(AF_INET6, buf + 8,
ext_addr,INET6_ADDRSTRLEN));
syslog(LOG_DEBUG, "External port port: \t\t %d\n", ntohs(peer_buf->ext_port) );
syslog(LOG_DEBUG, "PEER IP: \t\t %s\n", inet_ntop(AF_INET6, &peer_buf->peer_ip,
syslog(LOG_DEBUG, "External port port: \t\t %d\n", READNU16(buf + 6));
syslog(LOG_DEBUG, "PEER IP: \t\t %s\n", inet_ntop(AF_INET6, buf + 28,
peer_addr,INET6_ADDRSTRLEN));
syslog(LOG_DEBUG, "PEER port port: \t\t %d\n", ntohs(peer_buf->peer_port) );
syslog(LOG_DEBUG, "PEER port port: \t\t %d\n", READNU16(buf + 24));
}
static void printPEEROpcodeVersion2(pcp_peer_v2_t *peer_buf)
static void printPEEROpcodeVersion2(const uint8_t *buf)
{
char ext_addr[INET6_ADDRSTRLEN];
char peer_addr[INET6_ADDRSTRLEN];
syslog(LOG_DEBUG, "PCP PEER: v2 Opcode specific information.");
syslog(LOG_DEBUG, "nonce: \t%08x%08x%08x",
peer_buf->nonce[0], peer_buf->nonce[1], peer_buf->nonce[2]);
syslog(LOG_DEBUG, "Protocol: \t%d",peer_buf->protocol );
syslog(LOG_DEBUG, "Internal port:\t%d", ntohs(peer_buf->int_port) );
syslog(LOG_DEBUG, "External IP: \t%s", inet_ntop(AF_INET6, &peer_buf->ext_ip,
ext_addr,INET6_ADDRSTRLEN));
syslog(LOG_DEBUG, "External port:\t%d", ntohs(peer_buf->ext_port) );
syslog(LOG_DEBUG, "PEER IP: \t%s", inet_ntop(AF_INET6, &peer_buf->peer_ip,
peer_addr,INET6_ADDRSTRLEN));
syslog(LOG_DEBUG, "PEER port: \t%d", ntohs(peer_buf->peer_port) );
READNU32(buf), READNU32(buf+4), READNU32(buf+8));
syslog(LOG_DEBUG, "Protocol: \t%d", buf[12]);
syslog(LOG_DEBUG, "Internal port:\t%d", READNU16(buf + 16));
syslog(LOG_DEBUG, "External IP: \t%s", inet_ntop(AF_INET6, buf + 20,
ext_addr, INET6_ADDRSTRLEN));
syslog(LOG_DEBUG, "External port:\t%d", READNU16(buf + 18));
syslog(LOG_DEBUG, "PEER IP: \t%s", inet_ntop(AF_INET6, buf + 40,
peer_addr, INET6_ADDRSTRLEN));
syslog(LOG_DEBUG, "PEER port: \t%d", READNU16(buf + 36));
}
#endif /* DEBUG */
@ -336,158 +351,122 @@ static void printPEEROpcodeVersion2(pcp_peer_v2_t *peer_buf)
* Function extracting information from peer_buf to pcp_msg_info
* @return : when no problem occurred 0 is returned, 1 otherwise
*/
static int parsePCPPEER_version1(pcp_peer_v1_t *peer_buf, \
static void parsePCPPEER_version1(const uint8_t *buf,
pcp_info_t *pcp_msg_info)
{
pcp_msg_info->is_peer_op = 1;
pcp_msg_info->protocol = peer_buf->protocol;
pcp_msg_info->int_port = ntohs(peer_buf->int_port);
pcp_msg_info->ext_port = ntohs(peer_buf->ext_port);
pcp_msg_info->peer_port = ntohs(peer_buf->peer_port);
pcp_msg_info->protocol = buf[0];
pcp_msg_info->int_port = READNU16(buf + 4);
pcp_msg_info->ext_port = READNU16(buf + 6);
pcp_msg_info->peer_port = READNU16(buf + 24);
pcp_msg_info->ext_ip = &peer_buf->ext_ip;
pcp_msg_info->peer_ip = &peer_buf->peer_ip;
if (pcp_msg_info->protocol == 0 && pcp_msg_info->int_port !=0 ){
syslog(LOG_ERR, "PCP PEER: protocol was ZERO, but internal port has non-ZERO value.");
pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST;
return 1;
}
return 0;
pcp_msg_info->ext_ip = (struct in6_addr *)(buf + 8);
pcp_msg_info->peer_ip = (struct in6_addr *)(buf + 28);
}
/*
* Function extracting information from peer_buf to pcp_msg_info
* @return : when no problem occurred 0 is returned, 1 otherwise
*/
static int parsePCPPEER_version2(pcp_peer_v2_t *peer_buf, \
pcp_info_t *pcp_msg_info)
static void parsePCPPEER_version2(const uint8_t *buf, pcp_info_t *pcp_msg_info)
{
pcp_msg_info->is_peer_op = 1;
memcpy(pcp_msg_info->nonce, peer_buf->nonce, 12);
pcp_msg_info->protocol = peer_buf->protocol;
pcp_msg_info->int_port = ntohs(peer_buf->int_port);
pcp_msg_info->ext_port = ntohs(peer_buf->ext_port);
pcp_msg_info->peer_port = ntohs(peer_buf->peer_port);
memcpy(pcp_msg_info->nonce, buf, 12);
pcp_msg_info->protocol = buf[12];
pcp_msg_info->int_port = READNU16(buf + 16);
pcp_msg_info->ext_port = READNU16(buf + 18);
pcp_msg_info->peer_port = READNU16(buf + 36);
pcp_msg_info->ext_ip = &peer_buf->ext_ip;
pcp_msg_info->peer_ip = &peer_buf->peer_ip;
if (pcp_msg_info->protocol == 0 && pcp_msg_info->int_port !=0 ){
syslog(LOG_ERR, "PCP PEER: protocol was ZERO, but internal port has non-ZERO value.");
pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST;
return 1;
}
return 0;
pcp_msg_info->ext_ip = (struct in6_addr *)(buf + 20);
pcp_msg_info->peer_ip = (struct in6_addr *)(buf + 40);
}
#endif /* PCP_PEER */
#ifdef PCP_SADSCP
#ifdef DEBUG
static void printSADSCPOpcode(pcp_sadscp_req_t *sadscp) {
static void printSADSCPOpcode(const uint8_t *buf)
{
unsigned char sadscp_tol;
sadscp_tol = sadscp->tolerance_fields;
sadscp_tol = buf[12]; /* tolerance_fields */
syslog(LOG_DEBUG, "PCP SADSCP: Opcode specific information.\n");
syslog(LOG_DEBUG, "Delay tolerance %d \n", (sadscp_tol>>6)&3 );
syslog(LOG_DEBUG, "Delay tolerance %d \n", (sadscp_tol>>6)&3);
syslog(LOG_DEBUG, "Loss tolerance %d \n", (sadscp_tol>>4)&3);
syslog(LOG_DEBUG, "Jitter tolerance %d \n", (sadscp_tol>>2)&3);
syslog(LOG_DEBUG, "RRR %d \n", sadscp_tol&3);
syslog(LOG_DEBUG, "AppName Length %d \n", sadscp->app_name_length);
if (sadscp->app_name) {
syslog(LOG_DEBUG, "Application name %.*s \n", sadscp->app_name_length,
sadscp->app_name);
}
syslog(LOG_DEBUG, "AppName Length %d \n", buf[13]);
syslog(LOG_DEBUG, "Application name %.*s \n", buf[13], buf + 14);
}
#endif //DEBUG
static int parseSADSCP(pcp_sadscp_req_t *sadscp, pcp_info_t *pcp_msg_info) {
static int parseSADSCP(const uint8_t *buf, pcp_info_t *pcp_msg_info)
{
pcp_msg_info->delay_tolerance = (buf[12]>>6)&3;
pcp_msg_info->loss_tolerance = (buf[12]>>4)&3;
pcp_msg_info->jitter_tolerance = (buf[12]>>2)&3;
pcp_msg_info->delay_tolerance = (sadscp->tolerance_fields>>6)&3;
pcp_msg_info->loss_tolerance = (sadscp->tolerance_fields>>4)&3;
pcp_msg_info->jitter_tolerance = (sadscp->tolerance_fields>>2)&3;
if (pcp_msg_info->delay_tolerance == 3 ) {
pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST;
return 1;
}
if ( pcp_msg_info->loss_tolerance == 3 ) {
pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST;
return 1;
}
if ( pcp_msg_info->jitter_tolerance == 3 ) {
if (pcp_msg_info->delay_tolerance == 3 ||
pcp_msg_info->loss_tolerance == 3 ||
pcp_msg_info->jitter_tolerance == 3 ) {
pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST;
return 1;
}
pcp_msg_info->app_name = sadscp->app_name;
pcp_msg_info->app_name_len = sadscp->app_name_length;
pcp_msg_info->app_name = (const char *)(buf + 14);
pcp_msg_info->app_name_len = buf[13];
return 0;
}
#endif
#endif /* PCP_SADSCP */
static int parsePCPOption(void* pcp_buf, int remain, pcp_info_t *pcp_msg_info)
static int parsePCPOption(uint8_t* pcp_buf, int remain, pcp_info_t *pcp_msg_info)
{
#ifdef DEBUG
char third_addr[INET6_ADDRSTRLEN];
#endif
#endif /* DEBUG */
unsigned short option_length;
pcp_3rd_party_option_t* opt_3rd;
#ifdef PCP_FLOWP
pcp_flow_priority_option_t* opt_flp;
#endif
pcp_filter_option_t* opt_filter;
pcp_prefer_fail_option_t* opt_prefail;
pcp_options_hdr_t* opt_hdr;
opt_hdr = (pcp_options_hdr_t*)pcp_buf;
/* Do centralized option sanity checks here. */
if (remain < (int)sizeof(*opt_hdr)) {
if (remain < (int)PCP_OPTION_HDR_SIZE) {
pcp_msg_info->result_code = PCP_ERR_MALFORMED_OPTION;
return 0;
}
option_length = ntohs(opt_hdr->len) + 4;
option_length = READNU16(pcp_buf + 2) + 4; /* len */
if (remain < option_length) {
pcp_msg_info->result_code = PCP_ERR_MALFORMED_OPTION;
return 0;
}
switch (opt_hdr->code) {
switch (pcp_buf[0]) { /* code */
case PCP_OPTION_3RD_PARTY:
opt_3rd = (pcp_3rd_party_option_t*)pcp_buf;
if ( option_length != sizeof(*opt_3rd) ) {
if (option_length != PCP_3RD_PARTY_OPTION_SIZE) {
pcp_msg_info->result_code = PCP_ERR_MALFORMED_OPTION;
return 0;
}
#ifdef DEBUG
syslog(LOG_DEBUG, "PCP OPTION: \t Third party \n");
syslog(LOG_DEBUG, "PCP OPTION: \t Third party\n");
syslog(LOG_DEBUG, "Third PARTY IP: \t %s\n", inet_ntop(AF_INET6,
&(opt_3rd->ip), third_addr, INET6_ADDRSTRLEN));
pcp_buf + 4, third_addr, INET6_ADDRSTRLEN));
#endif
if (pcp_msg_info->thirdp_ip ) {
syslog(LOG_ERR, "PCP: THIRD PARTY OPTION was already present. \n");
pcp_msg_info->result_code = PCP_ERR_MALFORMED_OPTION;
return 0;
}
else {
pcp_msg_info->thirdp_ip = &opt_3rd->ip;
pcp_msg_info->mapped_ip = &opt_3rd->ip;
} else {
pcp_msg_info->thirdp_ip = (struct in6_addr *)(pcp_buf + 4);
pcp_msg_info->mapped_ip = (struct in6_addr *)(pcp_buf + 4);
}
break;
case PCP_OPTION_PREF_FAIL:
opt_prefail = (pcp_prefer_fail_option_t*)pcp_buf;
if ( option_length != sizeof(*opt_prefail) ) {
if (option_length != PCP_PREFER_FAIL_OPTION_SIZE) {
pcp_msg_info->result_code = PCP_ERR_MALFORMED_OPTION;
return 0;
}
@ -499,19 +478,16 @@ static int parsePCPOption(void* pcp_buf, int remain, pcp_info_t *pcp_msg_info)
pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST;
}
if (pcp_msg_info->pfailure_present != 0 ) {
syslog(LOG_DEBUG, "PCP: PREFER FAILURE OPTION was already present. \n");
syslog(LOG_DEBUG, "PCP: PREFER FAILURE OPTION was already present.\n");
pcp_msg_info->result_code = PCP_ERR_MALFORMED_OPTION;
}
else {
} else {
pcp_msg_info->pfailure_present = 1;
}
break;
case PCP_OPTION_FILTER:
/* TODO fully implement filter */
opt_filter = (pcp_filter_option_t*)pcp_buf;
if ( option_length != sizeof(*opt_filter) ) {
if (option_length != PCP_FILTER_OPTION_SIZE) {
pcp_msg_info->result_code = PCP_ERR_MALFORMED_OPTION;
return 0;
}
@ -531,28 +507,26 @@ static int parsePCPOption(void* pcp_buf, int remain, pcp_info_t *pcp_msg_info)
#ifdef DEBUG
syslog(LOG_DEBUG, "PCP OPTION: \t Flow priority\n");
#endif
opt_flp = (pcp_flow_priority_option_t*)pcp_buf;
if ( option_length != sizeof (*flp) ) {
syslog(LOG_ERR, "PCP: Error processing DSCP. sizeof %d and remaining %d . flow len %d \n",
(int)sizeof(pcp_flow_priority_option_t), remain, opt_flp->len);
if (option_length != PCP_FLOW_PRIORITY_OPTION_SIZE) {
syslog(LOG_ERR, "PCP: Error processing DSCP. sizeof %d and remaining %d. flow len %d \n",
PCP_FLOW_PRIORITY_OPTION_SIZE, remain, READNU16(pcp_buf + 2));
pcp_msg_info->result_code = PCP_ERR_MALFORMED_OPTION;
return 0;
}
#ifdef DEBUG
syslog(LOG_DEBUG, "DSCP UP: \t %d \n", opt_flp->dscp_up);
syslog(LOG_DEBUG, "DSCP DOWN: \t %d \n", opt_flp->dscp_down);
syslog(LOG_DEBUG, "DSCP UP: \t %d\n", pcp_buf[4]);
syslog(LOG_DEBUG, "DSCP DOWN: \t %d\n", pcp_buf[5]);
#endif
pcp_msg_info->dscp_up = opt_flp->dscp_up;
pcp_msg_info->dscp_down = opt_flp->dscp_down;
pcp_msg_info->dscp_up = pcp_buf[4];
pcp_msg_info->dscp_down = pcp_buf[5];
pcp_msg_info->flowp_present = 1;
break;
#endif
default:
if (opt_hdr->code < 128) {
syslog(LOG_ERR, "PCP: Unrecognized mandatory PCP OPTION: %d \n", opt_hdr->code);
if (pcp_buf[0] < 128) {
syslog(LOG_ERR, "PCP: Unrecognized mandatory PCP OPTION: %d \n", (int)pcp_buf[0]);
/* Mandatory to understand */
pcp_msg_info->result_code = PCP_ERR_UNSUPP_OPTION;
remain = 0;
@ -576,6 +550,9 @@ static void parsePCPOptions(void* pcp_buf, int remain, pcp_info_t *pcp_msg_info)
remain -= option_length;
pcp_buf += option_length;
}
if (remain > 0) {
syslog(LOG_WARNING, "%s: remain=%d", "parsePCPOptions", remain);
}
}
@ -770,7 +747,7 @@ static int CreatePCPPeer_NAT(pcp_info_t *pcp_msg_info)
pcp_msg_info->peer_port,
pcp_msg_info->desc);
pcp_msg_info->result_code = PCP_ERR_NO_RESOURCES;
return;
return PCP_ERR_NO_RESOURCES;
}
}
#endif
@ -967,7 +944,7 @@ static int CreatePCPMap_NAT(pcp_info_t *pcp_msg_info)
pcp_msg_info->protocol,
iaddr_old, sizeof(iaddr_old),
&iport_old, 0, 0, 0, 0,
&timestamp, 0, 0);
NULL/*&timestamp*/, 0, 0);
if(r==0) {
if((strcmp(pcp_msg_info->mapped_str, iaddr_old)!=0)
@ -1114,9 +1091,14 @@ static void DeletePCPMap(pcp_info_t *pcp_msg_info)
index++)
if(0 == strcmp(iaddr2, pcp_msg_info->mapped_str)
&& (proto2==proto)
&& 0 == strcmp(desc, pcp_msg_info->desc)
&& ((iport2==iport) || (iport==0))) {
if (!pcp_msg_info->is_fw) {
if(0 != strcmp(desc, pcp_msg_info->desc)) {
/* nonce does not match */
pcp_msg_info->result_code = PCP_ERR_NOT_AUTHORIZED;
syslog(LOG_ERR, "Unauthorized to remove PCP mapping internal port %hu, protocol %s",
iport, (pcp_msg_info->protocol == IPPROTO_TCP)?"TCP":"UDP");
return;
} else if (!pcp_msg_info->is_fw) {
r = _upnp_delete_redir(eport2, proto2);
} else {
#ifdef ENABLE_UPNPPINHOLE
@ -1175,6 +1157,8 @@ static int ValidatePCPMsg(pcp_info_t *pcp_msg_info)
/* protocol zero means 'all protocols' : internal port MUST be zero */
if (pcp_msg_info->protocol == 0 && pcp_msg_info->int_port != 0) {
syslog(LOG_ERR, "PCP %s: Protocol was ZERO, but internal port "
"has non-ZERO value.", getPCPOpCodeStr(pcp_msg_info->opcode));
pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST;
return 0;
}
@ -1203,7 +1187,7 @@ static int ValidatePCPMsg(pcp_info_t *pcp_msg_info)
case PCP_OPCODE_PEER:
snprintf(pcp_msg_info->desc, sizeof(pcp_msg_info->desc),
"PCP %s %08x%08x%08x",
pcp_msg_info->opcode == PCP_OPCODE_MAP ? "MAP":"PEER",
getPCPOpCodeStr(pcp_msg_info->opcode),
pcp_msg_info->nonce[0],
pcp_msg_info->nonce[1], pcp_msg_info->nonce[2]);
break;
@ -1219,17 +1203,8 @@ static int processPCPRequest(void * req, int req_size, pcp_info_t *pcp_msg_info)
{
int remainingSize;
const pcp_map_v1_t* map_v1;
const pcp_map_v2_t* map_v2;
#ifdef PCP_PEER
pcp_peer_v1_t* peer_v1;
pcp_peer_v2_t* peer_v2;
#endif
#ifdef PCP_SADSCP
pcp_sadscp_req_t* sadscp;
#endif
/* start with PCP_SUCCESS as result code, if everything is OK value will be unchanged */
/* start with PCP_SUCCESS as result code,
* if everything is OK value will be unchanged */
pcp_msg_info->result_code = PCP_SUCCESS;
remainingSize = req_size;
@ -1253,33 +1228,30 @@ static int processPCPRequest(void * req, int req_size, pcp_info_t *pcp_msg_info)
}
/* first parse request header */
if (parseCommonRequestHeader((pcp_request_t*)req, pcp_msg_info) ) {
if (parseCommonRequestHeader(req, pcp_msg_info) ) {
return 1;
}
remainingSize -= sizeof(pcp_request_t);
req += sizeof(pcp_request_t);
remainingSize -= PCP_COMMON_REQUEST_SIZE;
req += PCP_COMMON_REQUEST_SIZE;
if (pcp_msg_info->version == 1) {
/* legacy PCP version 1 support */
switch (pcp_msg_info->opcode) {
case PCP_OPCODE_MAP:
remainingSize -= sizeof(pcp_map_v1_t);
remainingSize -= PCP_MAP_V1_SIZE;
if (remainingSize < 0) {
pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST;
return pcp_msg_info->result_code;
}
map_v1 = (pcp_map_v1_t*)req;
#ifdef DEBUG
printMAPOpcodeVersion1(map_v1);
printMAPOpcodeVersion1(req);
#endif /* DEBUG */
if ( parsePCPMAP_version1(map_v1, pcp_msg_info) ) {
return pcp_msg_info->result_code;
}
parsePCPMAP_version1(req, pcp_msg_info);
req += sizeof(pcp_map_v1_t);
req += PCP_MAP_V1_SIZE;
parsePCPOptions(req, remainingSize, pcp_msg_info);
if (ValidatePCPMsg(pcp_msg_info)) {
@ -1290,29 +1262,25 @@ static int processPCPRequest(void * req, int req_size, pcp_info_t *pcp_msg_info)
}
} else {
syslog(LOG_ERR, "PCP: Invalid PCP v1 MAP message.");
return pcp_msg_info->result_code;
}
break;
#ifdef PCP_PEER
case PCP_OPCODE_PEER:
remainingSize -= sizeof(pcp_peer_v1_t);
remainingSize -= PCP_PEER_V1_SIZE;
if (remainingSize < 0) {
pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST;
return pcp_msg_info->result_code;
}
peer_v1 = (pcp_peer_v1_t*)req;
#ifdef DEBUG
printPEEROpcodeVersion1(peer_v1);
printPEEROpcodeVersion1(req);
#endif /* DEBUG */
if ( parsePCPPEER_version1(peer_v1, pcp_msg_info) ) {
return pcp_msg_info->result_code;
}
parsePCPPEER_version1(req, pcp_msg_info);
req += sizeof(pcp_peer_v1_t);
req += PCP_PEER_V1_SIZE;
parsePCPOptions(req, remainingSize, pcp_msg_info);
@ -1324,6 +1292,7 @@ static int processPCPRequest(void * req, int req_size, pcp_info_t *pcp_msg_info)
}
} else {
syslog(LOG_ERR, "PCP: Invalid PCP v1 PEER message.");
return pcp_msg_info->result_code;
}
@ -1344,22 +1313,17 @@ static int processPCPRequest(void * req, int req_size, pcp_info_t *pcp_msg_info)
break;
case PCP_OPCODE_MAP:
remainingSize -= sizeof(pcp_map_v2_t);
remainingSize -= PCP_MAP_V2_SIZE;
if (remainingSize < 0) {
pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST;
return pcp_msg_info->result_code;
}
map_v2 = (pcp_map_v2_t*)req;
#ifdef DEBUG
printMAPOpcodeVersion2(map_v2);
printMAPOpcodeVersion2(req);
#endif /* DEBUG */
if (parsePCPMAP_version2(map_v2, pcp_msg_info) ) {
return pcp_msg_info->result_code;
}
req += sizeof(pcp_map_v2_t);
parsePCPMAP_version2(req, pcp_msg_info);
req += PCP_MAP_V2_SIZE;
parsePCPOptions(req, remainingSize, pcp_msg_info);
@ -1371,6 +1335,7 @@ static int processPCPRequest(void * req, int req_size, pcp_info_t *pcp_msg_info)
}
} else {
syslog(LOG_ERR, "PCP: Invalid PCP v2 MAP message.");
return pcp_msg_info->result_code;
}
@ -1379,18 +1344,17 @@ static int processPCPRequest(void * req, int req_size, pcp_info_t *pcp_msg_info)
#ifdef PCP_PEER
case PCP_OPCODE_PEER:
remainingSize -= sizeof(pcp_peer_v2_t);
remainingSize -= PCP_PEER_V2_SIZE;
if (remainingSize < 0) {
pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST;
return pcp_msg_info->result_code;
}
peer_v2 = (pcp_peer_v2_t*)req;
#ifdef DEBUG
printPEEROpcodeVersion2(peer_v2);
printPEEROpcodeVersion2(req);
#endif /* DEBUG */
parsePCPPEER_version2(peer_v2, pcp_msg_info);
req += sizeof(pcp_peer_v2_t);
parsePCPPEER_version2(req, pcp_msg_info);
req += PCP_PEER_V2_SIZE;
if (pcp_msg_info->result_code != 0) {
return pcp_msg_info->result_code;
@ -1413,25 +1377,27 @@ static int processPCPRequest(void * req, int req_size, pcp_info_t *pcp_msg_info)
#ifdef PCP_SADSCP
case PCP_OPCODE_SADSCP:
remainingSize -= sizeof(pcp_sadscp_req_t);
remainingSize -= PCP_SADSCP_REQ_SIZE;
if (remainingSize < 0) {
pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST;
return pcp_msg_info->result_code;
}
sadscp = (pcp_sadscp_req_t*)req;
req += sizeof(pcp_sadscp_req_t);
if (sadscp->app_name_length > remainingSize) {
remainingSize -= ((uint8_t *)req)[13]; /* app_name_length */
if (remainingSize < 0) {
pcp_msg_info->result_code = PCP_ERR_MALFORMED_OPTION;
return pcp_msg_info->result_code;
}
#ifdef DEBUG
printSADSCPOpcode(sadscp);
printSADSCPOpcode(req);
#endif
if (parseSADSCP(sadscp, pcp_msg_info)) {
parseSADSCP(req, pcp_msg_info);
req += PCP_SADSCP_REQ_SIZE;
if (pcp_msg_info->result_code != 0) {
return pcp_msg_info->result_code;
}
req += pcp_msg_info->app_name_len;
get_dscp_value(pcp_msg_info);
@ -1452,22 +1418,18 @@ static int processPCPRequest(void * req, int req_size, pcp_info_t *pcp_msg_info)
static void createPCPResponse(unsigned char *response, pcp_info_t *pcp_msg_info)
{
pcp_response_t *resp = (pcp_response_t*)response;
resp->reserved = 0;
resp->reserved1[0]=0;
resp->reserved1[1]=0;
resp->reserved1[2]=0;
response[2] = 0; /* reserved */
memset(response + 12, 0, 12); /* reserved */
if (pcp_msg_info->result_code == PCP_ERR_UNSUPP_VERSION ) {
/* highest supported version */
resp->ver = this_server_info.server_version;
response[0] = this_server_info.server_version;
} else {
resp->ver = pcp_msg_info->version;
response[0] = pcp_msg_info->version;
}
resp->r_opcode |= 0x80;
resp->result_code = pcp_msg_info->result_code;
resp->epochtime = htonl(time(NULL) - startup_time);
response[1] |= 0x80; /* r_opcode */
response[3] = pcp_msg_info->result_code;
WRITENU32(response + 8, time(NULL) - startup_time); /* epochtime */
switch (pcp_msg_info->result_code) {
/*long lifetime errors*/
case PCP_ERR_UNSUPP_VERSION:
@ -1480,61 +1442,60 @@ static void createPCPResponse(unsigned char *response, pcp_info_t *pcp_msg_info)
case PCP_ERR_ADDRESS_MISMATCH:
case PCP_ERR_CANNOT_PROVIDE_EXTERNAL:
case PCP_ERR_EXCESSIVE_REMOTE_PEERS:
resp->lifetime = 0;
WRITENU32(response + 4, 0); /* lifetime */
break;
case PCP_ERR_NETWORK_FAILURE:
case PCP_ERR_NO_RESOURCES:
case PCP_ERR_USER_EX_QUOTA:
resp->lifetime = htonl(30);
WRITENU32(response + 4, 30); /* lifetime */
break;
case PCP_SUCCESS:
default:
resp->lifetime = htonl(pcp_msg_info->lifetime);
WRITENU32(response + 4, pcp_msg_info->lifetime); /* lifetime */
break;
}
if (resp->r_opcode == 0x81) { /* MAP response */
if (resp->ver == 1 ) {
pcp_map_v1_t *mapr = (pcp_map_v1_t *)resp->next_data;
mapr->ext_ip = *pcp_msg_info->ext_ip;
mapr->ext_port = htons(pcp_msg_info->ext_port);
mapr->int_port = htons(pcp_msg_info->int_port);
if (response[1] == 0x81) { /* MAP response */
if (response[0] == 1) { /* version */
WRITENU16(response + PCP_COMMON_RESPONSE_SIZE + 4, pcp_msg_info->int_port);
WRITENU16(response + PCP_COMMON_RESPONSE_SIZE + 6, pcp_msg_info->ext_port);
copyIPv6IfDifferent(response + PCP_COMMON_RESPONSE_SIZE + 8,
pcp_msg_info->ext_ip);
}
else if (resp->ver == 2 ) {
pcp_map_v2_t *mapr = (pcp_map_v2_t *)resp->next_data;
mapr->ext_ip = *pcp_msg_info->ext_ip;
mapr->ext_port = htons(pcp_msg_info->ext_port);
mapr->int_port = htons(pcp_msg_info->int_port);
else if (response[0] == 2) {
WRITENU16(response + PCP_COMMON_RESPONSE_SIZE + 16, pcp_msg_info->int_port);
WRITENU16(response + PCP_COMMON_RESPONSE_SIZE + 18, pcp_msg_info->ext_port);
copyIPv6IfDifferent(response + PCP_COMMON_RESPONSE_SIZE + 20,
pcp_msg_info->ext_ip);
}
}
#ifdef PCP_PEER
else if (resp->r_opcode == 0x82) { /* PEER response */
if (resp->ver == 1 ){
pcp_peer_v1_t* peer_resp = (pcp_peer_v1_t*)resp->next_data;
peer_resp->ext_port = htons(pcp_msg_info->ext_port);
peer_resp->int_port = htons(pcp_msg_info->int_port);
peer_resp->peer_port = htons(pcp_msg_info->peer_port);
peer_resp->ext_ip = *pcp_msg_info->ext_ip;
else if (response[1] == 0x82) { /* PEER response */
if (response[0] == 1) {
WRITENU16(response + PCP_COMMON_RESPONSE_SIZE + 4, pcp_msg_info->int_port);
WRITENU16(response + PCP_COMMON_RESPONSE_SIZE + 6, pcp_msg_info->ext_port);
WRITENU16(response + PCP_COMMON_RESPONSE_SIZE + 24, pcp_msg_info->peer_port);
copyIPv6IfDifferent(response + PCP_COMMON_RESPONSE_SIZE + 8,
pcp_msg_info->ext_ip);
}
else if (resp->ver == 2 ){
pcp_peer_v2_t* peer_resp = (pcp_peer_v2_t*)resp->next_data;
peer_resp->ext_port = htons(pcp_msg_info->ext_port);
peer_resp->int_port = htons(pcp_msg_info->int_port);
peer_resp->peer_port = htons(pcp_msg_info->peer_port);
peer_resp->ext_ip = *pcp_msg_info->ext_ip;
else if (response[0] == 2) {
WRITENU16(response + PCP_COMMON_RESPONSE_SIZE + 16, pcp_msg_info->int_port);
WRITENU16(response + PCP_COMMON_RESPONSE_SIZE + 18, pcp_msg_info->ext_port);
WRITENU16(response + PCP_COMMON_RESPONSE_SIZE + 36, pcp_msg_info->peer_port);
copyIPv6IfDifferent(response + PCP_COMMON_RESPONSE_SIZE + 20,
pcp_msg_info->ext_ip);
}
}
#endif /* PCP_PEER */
#ifdef PCP_SADSCP
else if (resp->r_opcode == 0x83) { /*SADSCP response*/
pcp_sadscp_resp_t *sadscp_resp = (pcp_sadscp_resp_t*)resp->next_data;
sadscp_resp->a_r_dscp_value = pcp_msg_info->matched_name<<7;
sadscp_resp->a_r_dscp_value &= ~(1<<6);
sadscp_resp->a_r_dscp_value |= (pcp_msg_info->sadscp_dscp & PCP_SADSCP_MASK);
memset(sadscp_resp->reserved, 0, sizeof(sadscp_resp->reserved));
else if (response[1] == 0x83) { /*SADSCP response*/
response[PCP_COMMON_RESPONSE_SIZE + 12]
= ((pcp_msg_info->matched_name<<7) & ~(1<<6)) |
(pcp_msg_info->sadscp_dscp & PCP_SADSCP_MASK);
memset(response + PCP_COMMON_RESPONSE_SIZE + 13, 0, 3);
}
#endif /* PCP_SADSCP */
}

29
miniupnpd/testgetifaddr.sh Executable file
View File

@ -0,0 +1,29 @@
#!/bin/sh
# $Id: testgetifaddr.sh,v 1.2 2015/09/22 14:48:09 nanard Exp $
OS=`uname -s`
case $OS in
OpenBSD)
NS="`which netstat`" || exit 1
IFCONFIG="`which ifconfig`" || exit 1
EXTIF="`$NS -r -f inet | grep 'default' | awk '{ print $NF }' `" || exit 1
EXTIP="`$IFCONFIG $EXTIF | awk '/inet / { print $2 }' `"
;;
*)
IP="`which ip`" || exit 1
EXTIF="`LC_ALL=C $IP -4 route | grep 'default' | sed -e 's/.*dev[[:space:]]*//' -e 's/[[:space:]].*//'`" || exit 1
EXTIP="`LC_ALL=C $IP -4 addr show $EXTIF | awk '/inet/ { print $2 }' | cut -d "/" -f 1`"
;;
esac
#echo "Interface : $EXTIF IP address : $EXTIP"
RES=`./testgetifaddr $EXTIF | head -n1 | sed 's/Interface .* has IP address \(.*\)\./\1/'` || exit 1
if [ "$RES" = "$EXTIP" ] ; then
echo "testgetifaddr test OK"
exit 0
else
echo "testgetifaddr test FAILED : $EXTIP != $RES"
exit 1
fi

View File

@ -1,5 +1,5 @@
/* $Id: testupnppermissions.c,v 1.3 2009/09/14 15:24:46 nanard Exp $ */
/* (c) 2007-2009 Thomas Bernard
/* (c) 2007-2015 Thomas Bernard
* MiniUPnP Project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
*/
@ -35,7 +35,7 @@ print_upnpperm(const struct upnpperm * p)
int main(int argc, char * * argv)
{
int i, r;
int i, r, ret;
struct upnpperm p;
if(argc < 2) {
fprintf(stderr, "Usage: %s \"permission line\" [...]\n", argv[0]);
@ -43,8 +43,7 @@ int main(int argc, char * * argv)
return 1;
}
openlog("testupnppermissions", LOG_PERROR, LOG_USER);
/* for(i=0; i<argc; i++)
printf("%2d '%s'\n", i, argv[i]); */
ret = 0;
for(i=1; i<argc; i++) {
printf("%2d '%s'\n", i, argv[i]);
memset(&p, 0, sizeof(struct upnpperm));
@ -54,9 +53,10 @@ int main(int argc, char * * argv)
print_upnpperm(&p);
} else {
printf("Permission read failed, please check its correctness\n");
ret++;
}
putchar('\n');
}
return 0;
return ret;
}

View File

@ -0,0 +1,56 @@
#!/bin/bash
# $Id: testupnppermissions.sh,v 1.2 2015/09/22 15:12:14 nanard Exp $
# Array are not available with POSIX sh
# bash / ksh
RULE[1]="allow 1-20000 11.12.13.14/22 1234"
RULEA[1]="allow 1-20000 0b0c0d0e/fffffc00 1234-1234"
RULEB[1]="allow 1-20000 11.12.13.14/255.255.252.0 1234-1234"
RULE[2]="deny 55 21.22.23.24/17 555-559"
RULEA[2]="deny 55-55 15161718/ffff8000 555-559"
RULEB[2]="deny 55-55 21.22.23.24/255.255.128.0 555-559"
i=1
s=1
./testupnppermissions "${RULE[@]}" | while read l;
do
if [ -z "$l" ]; then i=$(($i+1)); s=1; else
#echo "$i $s : checking '$l'"
case $s in
1)
if [ "$i '${RULE[$i]}'" != "$l" ] ; then
exit $s
fi;;
2)
if [ "Permission read successfully" = "$l" ] ; then
s=$(($s+1))
elif [ "perm rule added : ${RULEA[$i]}" != "$l" ] ; then
exit $s
fi;;
3)
if [ "Permission read successfully" != "$l" ] ; then
exit $s
fi;;
4)
if [ "${RULEB[$i]}" != "$l" ] ; then
exit $s
fi;;
*)
echo "$i $s : $l"
exit $s
;;
esac
s=$(($s+1))
fi
done
# retrieve return status from subshell
r=$?
if [ $r -eq 0 ] ; then
echo "testupnppermissions tests OK"
else
echo "testupnppermissions tests FAILED"
fi
exit $r

View File

@ -1,7 +1,7 @@
/* $Id: upnpdescgen.c,v 1.77 2014/03/10 11:04:53 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2014 Thomas Bernard
* (c) 2006-2015 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
@ -140,8 +140,8 @@ static const struct XMLElt rootDesc[] =
#else
{"device", INITHELPER(5,12)},
#endif
{"/major", "1"},
{"/minor", "0"},
{"/major", UPNP_VERSION_MAJOR_STR},
{"/minor", UPNP_VERSION_MINOR_STR},
/* 5 */
{"/deviceType", DEVICE_TYPE_IGD},
/* urn:schemas-upnp-org:device:InternetGatewayDevice:1 or 2 */
@ -976,7 +976,8 @@ genServiceDesc(int * len, const struct serviceDesc * s)
str = strcat_char(str, len, &tmplen, '>');
str = strcat_str(str, len, &tmplen,
"<specVersion><major>1</major><minor>0</minor></specVersion>");
"<specVersion><major>" UPNP_VERSION_MAJOR_STR "</major>"
"<minor>" UPNP_VERSION_MINOR_STR "</minor></specVersion>");
i = 0;
str = strcat_str(str, len, &tmplen, "<actionList>");

View File

@ -22,7 +22,7 @@
#define WANDEV_MANUFACTURERURL "http://miniupnp.free.fr/"
#define WANDEV_MODELNAME "WAN Device"
#define WANDEV_MODELDESCRIPTION "WAN Device"
#define WANDEV_MODELNUMBER UPNP_VERSION
#define WANDEV_MODELNUMBER MINIUPNPD_DATE
#define WANDEV_MODELURL "http://miniupnp.free.fr/"
#define WANDEV_UPC "000000000000"
/* UPC is 12 digit (barcode) */
@ -32,7 +32,7 @@
#define WANCDEV_MANUFACTURERURL WANDEV_MANUFACTURERURL
#define WANCDEV_MODELNAME "MiniUPnPd"
#define WANCDEV_MODELDESCRIPTION "MiniUPnP daemon"
#define WANCDEV_MODELNUMBER UPNP_VERSION
#define WANCDEV_MODELNUMBER MINIUPNPD_DATE
#define WANCDEV_MODELURL "http://miniupnp.free.fr/"
#define WANCDEV_UPC "000000000000"
/* UPC is 12 digit (barcode) */

View File

@ -901,7 +901,7 @@ Process_upnphttp(struct upnphttp * h)
}
else if(n==0)
{
syslog(LOG_WARNING, "HTTP Connection closed unexpectedly");
syslog(LOG_WARNING, "HTTP Connection from %s closed unexpectedly", inet_ntoa(h->clientaddr));
h->state = EToDelete;
}
else
@ -971,7 +971,7 @@ Process_upnphttp(struct upnphttp * h)
}
else if(n==0)
{
syslog(LOG_WARNING, "HTTP Connection closed inexpectedly");
syslog(LOG_WARNING, "HTTP Connection from %s closed unexpectedly", inet_ntoa(h->clientaddr));
h->state = EToDelete;
}
else

View File

@ -1,7 +1,7 @@
/* $Id: upnphttp.h,v 1.40 2014/12/09 16:41:21 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2014 Thomas Bernard
* (c) 2006-2015 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
@ -20,10 +20,12 @@
#if 0
/* according to "UPnP Device Architecture 1.0" */
#define UPNP_VERSION_STRING "UPnP/1.0"
#else
/* according to "UPnP Device Architecture 1.1" */
#define UPNP_VERSION_STRING "UPnP/1.1"
/* according to "UPnP Device Architecture 2.0" */
#define UPNP_VERSION_STRING "UPnP/2.0"
#endif
#define UPNP_VERSION_STRING "UPnP/" UPNP_VERSION_MAJOR_STR "." UPNP_VERSION_MINOR_STR
/* server: HTTP header returned in all HTTP responses : */
#define MINIUPNPD_SERVER_STRING OS_VERSION " " UPNP_VERSION_STRING " MiniUPnPd/" MINIUPNPD_VERSION

View File

@ -1,7 +1,7 @@
/* $Id: upnpreplyparse.c,v 1.18 2014/11/05 05:36:08 nanard Exp $ */
/* $Id: upnpreplyparse.c,v 1.19 2015/07/15 10:29:11 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2014 Thomas Bernard
* (c) 2006-2015 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
@ -40,6 +40,15 @@ NameValueParserEndElt(void * d, const char * name, int l)
/* standard case. Limited to n chars strings */
l = data->cdatalen;
nv = malloc(sizeof(struct NameValue));
if(nv == NULL)
{
/* malloc error */
#ifdef DEBUG
fprintf(stderr, "%s: error allocating memory",
"NameValueParserEndElt");
#endif /* DEBUG */
return;
}
if(l>=(int)sizeof(nv->value))
l = sizeof(nv->value) - 1;
strncpy(nv->name, data->curelt, 64);
@ -72,6 +81,10 @@ NameValueParserGetData(void * d, const char * datas, int l)
if(!data->portListing)
{
/* malloc error */
#ifdef DEBUG
fprintf(stderr, "%s: error allocating memory",
"NameValueParserGetData");
#endif /* DEBUG */
return;
}
memcpy(data->portListing, datas, l);
@ -180,5 +193,5 @@ DisplayNameValueList(char * buffer, int bufsize)
}
ClearNameValueList(&pdata);
}
#endif
#endif /* DEBUG */

View File

@ -65,21 +65,32 @@ BuildSendAndCloseSoapResp(struct upnphttp * h,
}
static void
GetConnectionTypeInfo(struct upnphttp * h, const char * action)
GetConnectionTypeInfo(struct upnphttp * h, const char * action, const char * ns)
{
#if 0
static const char resp[] =
"<u:GetConnectionTypeInfoResponse "
"xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
"<NewConnectionType>IP_Routed</NewConnectionType>"
"<NewPossibleConnectionTypes>IP_Routed</NewPossibleConnectionTypes>"
"</u:GetConnectionTypeInfoResponse>";
UNUSED(action);
#endif
static const char resp[] =
"<u:%sResponse "
"xmlns:u=\"%s\">"
"<NewConnectionType>IP_Routed</NewConnectionType>"
"<NewPossibleConnectionTypes>IP_Routed</NewPossibleConnectionTypes>"
"</u:%sResponse>";
char body[512];
int bodylen;
BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
bodylen = snprintf(body, sizeof(body), resp,
action, ns, action);
BuildSendAndCloseSoapResp(h, body, bodylen);
}
static void
GetTotalBytesSent(struct upnphttp * h, const char * action)
GetTotalBytesSent(struct upnphttp * h, const char * action, const char * ns)
{
int r;
@ -95,13 +106,13 @@ GetTotalBytesSent(struct upnphttp * h, const char * action)
r = getifstats(ext_if_name, &data);
bodylen = snprintf(body, sizeof(body), resp,
action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
action, ns, /* was "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */
r<0?0:data.obytes, action);
BuildSendAndCloseSoapResp(h, body, bodylen);
}
static void
GetTotalBytesReceived(struct upnphttp * h, const char * action)
GetTotalBytesReceived(struct upnphttp * h, const char * action, const char * ns)
{
int r;
@ -117,13 +128,13 @@ GetTotalBytesReceived(struct upnphttp * h, const char * action)
r = getifstats(ext_if_name, &data);
bodylen = snprintf(body, sizeof(body), resp,
action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
action, ns, /* was "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */
r<0?0:data.ibytes, action);
BuildSendAndCloseSoapResp(h, body, bodylen);
}
static void
GetTotalPacketsSent(struct upnphttp * h, const char * action)
GetTotalPacketsSent(struct upnphttp * h, const char * action, const char * ns)
{
int r;
@ -139,13 +150,13 @@ GetTotalPacketsSent(struct upnphttp * h, const char * action)
r = getifstats(ext_if_name, &data);
bodylen = snprintf(body, sizeof(body), resp,
action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
action, ns,/*"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",*/
r<0?0:data.opackets, action);
BuildSendAndCloseSoapResp(h, body, bodylen);
}
static void
GetTotalPacketsReceived(struct upnphttp * h, const char * action)
GetTotalPacketsReceived(struct upnphttp * h, const char * action, const char * ns)
{
int r;
@ -161,13 +172,13 @@ GetTotalPacketsReceived(struct upnphttp * h, const char * action)
r = getifstats(ext_if_name, &data);
bodylen = snprintf(body, sizeof(body), resp,
action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
action, ns, /* was "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */
r<0?0:data.ipackets, action);
BuildSendAndCloseSoapResp(h, body, bodylen);
}
static void
GetCommonLinkProperties(struct upnphttp * h, const char * action)
GetCommonLinkProperties(struct upnphttp * h, const char * action, const char * ns)
{
/* WANAccessType : set depending on the hardware :
* DSL, POTS (plain old Telephone service), Cable, Ethernet */
@ -200,7 +211,7 @@ GetCommonLinkProperties(struct upnphttp * h, const char * action)
status = "Down";
}
bodylen = snprintf(body, sizeof(body), resp,
action, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
action, ns, /* was "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */
wan_access_type,
upstream_bitrate, downstream_bitrate,
status, action);
@ -208,7 +219,7 @@ GetCommonLinkProperties(struct upnphttp * h, const char * action)
}
static void
GetStatusInfo(struct upnphttp * h, const char * action)
GetStatusInfo(struct upnphttp * h, const char * action, const char * ns)
{
static const char resp[] =
"<u:%sResponse "
@ -229,14 +240,15 @@ GetStatusInfo(struct upnphttp * h, const char * action)
status = get_wan_connection_status_str(ext_if_name);
uptime = (time(NULL) - startup_time);
bodylen = snprintf(body, sizeof(body), resp,
action, SERVICE_TYPE_WANIPC,
action, ns, /*SERVICE_TYPE_WANIPC,*/
status, (long)uptime, action);
BuildSendAndCloseSoapResp(h, body, bodylen);
}
static void
GetNATRSIPStatus(struct upnphttp * h, const char * action)
GetNATRSIPStatus(struct upnphttp * h, const char * action, const char * ns)
{
#if 0
static const char resp[] =
"<u:GetNATRSIPStatusResponse "
"xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
@ -244,6 +256,15 @@ GetNATRSIPStatus(struct upnphttp * h, const char * action)
"<NewNATEnabled>1</NewNATEnabled>"
"</u:GetNATRSIPStatusResponse>";
UNUSED(action);
#endif
static const char resp[] =
"<u:%sResponse "
"xmlns:u=\"%s\">"
"<NewRSIPAvailable>0</NewRSIPAvailable>"
"<NewNATEnabled>1</NewNATEnabled>"
"</u:%sResponse>";
char body[512];
int bodylen;
/* 2.2.9. RSIPAvailable
* This variable indicates if Realm-specific IP (RSIP) is available
* as a feature on the InternetGatewayDevice. RSIP is being defined
@ -252,11 +273,14 @@ GetNATRSIPStatus(struct upnphttp * h, const char * action)
* applications that otherwise break if NAT is introduced
* (e.g. IPsec-based VPNs).
* A gateway that does not support RSIP should set this variable to 0. */
BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
bodylen = snprintf(body, sizeof(body), resp,
action, ns, /*SERVICE_TYPE_WANIPC,*/
action);
BuildSendAndCloseSoapResp(h, body, bodylen);
}
static void
GetExternalIPAddress(struct upnphttp * h, const char * action)
GetExternalIPAddress(struct upnphttp * h, const char * action, const char * ns)
{
static const char resp[] =
"<u:%sResponse "
@ -274,6 +298,7 @@ GetExternalIPAddress(struct upnphttp * h, const char * action)
if(use_ext_ip_addr)
{
strncpy(ext_ip_addr, use_ext_ip_addr, INET_ADDRSTRLEN);
ext_ip_addr[INET_ADDRSTRLEN - 1] = '\0';
}
else if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN, NULL, NULL) < 0)
{
@ -295,7 +320,7 @@ GetExternalIPAddress(struct upnphttp * h, const char * action)
}
#endif
bodylen = snprintf(body, sizeof(body), resp,
action, SERVICE_TYPE_WANIPC,
action, ns, /*SERVICE_TYPE_WANIPC,*/
ext_ip_addr, action);
BuildSendAndCloseSoapResp(h, body, bodylen);
}
@ -303,14 +328,19 @@ GetExternalIPAddress(struct upnphttp * h, const char * action)
/* AddPortMapping method of WANIPConnection Service
* Ignored argument : NewEnabled */
static void
AddPortMapping(struct upnphttp * h, const char * action)
AddPortMapping(struct upnphttp * h, const char * action, const char * ns)
{
int r;
static const char resp[] =
/*static const char resp[] =
"<u:AddPortMappingResponse "
"xmlns:u=\"" SERVICE_TYPE_WANIPC "\"/>";
"xmlns:u=\"" SERVICE_TYPE_WANIPC "\"/>";*/
static const char resp[] =
"<u:%sResponse "
"xmlns:u=\"%s\"/>";
char body[512];
int bodylen;
struct NameValueParserData data;
char * int_ip, * int_port, * ext_port, * protocol, * desc;
char * leaseduration_str;
@ -450,7 +480,9 @@ AddPortMapping(struct upnphttp * h, const char * action)
switch(r)
{
case 0: /* success */
BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
bodylen = snprintf(body, sizeof(body), resp,
action, ns/*SERVICE_TYPE_WANIPC*/);
BuildSendAndCloseSoapResp(h, body, bodylen);
break;
case -2: /* already redirected */
case -3: /* not permitted */
@ -463,7 +495,7 @@ AddPortMapping(struct upnphttp * h, const char * action)
/* AddAnyPortMapping was added in WANIPConnection v2 */
static void
AddAnyPortMapping(struct upnphttp * h, const char * action)
AddAnyPortMapping(struct upnphttp * h, const char * action, const char * ns)
{
int r;
static const char resp[] =
@ -573,7 +605,7 @@ AddAnyPortMapping(struct upnphttp * h, const char * action)
{
case 0: /* success */
bodylen = snprintf(body, sizeof(body), resp,
action, SERVICE_TYPE_WANIPC,
action, ns, /*SERVICE_TYPE_WANIPC,*/
eport, action);
BuildSendAndCloseSoapResp(h, body, bodylen);
break;
@ -589,7 +621,7 @@ AddAnyPortMapping(struct upnphttp * h, const char * action)
}
static void
GetSpecificPortMappingEntry(struct upnphttp * h, const char * action)
GetSpecificPortMappingEntry(struct upnphttp * h, const char * action, const char * ns)
{
int r;
@ -661,7 +693,7 @@ GetSpecificPortMappingEntry(struct upnphttp * h, const char * action)
r_host ? r_host : "NULL", ext_port, protocol, int_ip,
(unsigned int)iport, desc);
bodylen = snprintf(body, sizeof(body), resp,
action, SERVICE_TYPE_WANIPC,
action, ns/*SERVICE_TYPE_WANIPC*/,
(unsigned int)iport, int_ip, desc, leaseduration,
action);
BuildSendAndCloseSoapResp(h, body, bodylen);
@ -671,15 +703,21 @@ GetSpecificPortMappingEntry(struct upnphttp * h, const char * action)
}
static void
DeletePortMapping(struct upnphttp * h, const char * action)
DeletePortMapping(struct upnphttp * h, const char * action, const char * ns)
{
int r;
static const char resp[] =
/*static const char resp[] =
"<u:DeletePortMappingResponse "
"xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
"</u:DeletePortMappingResponse>";
"</u:DeletePortMappingResponse>";*/
static const char resp[] =
"<u:%sResponse "
"xmlns:u=\"%s\">"
"</u:%sResponse>";
char body[512];
int bodylen;
struct NameValueParserData data;
const char * ext_port, * protocol;
unsigned short eport;
@ -757,7 +795,9 @@ DeletePortMapping(struct upnphttp * h, const char * action)
}
else
{
BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
bodylen = snprintf(body, sizeof(body), resp,
action, ns, action);
BuildSendAndCloseSoapResp(h, body, bodylen);
}
ClearNameValueList(&data);
@ -765,13 +805,19 @@ DeletePortMapping(struct upnphttp * h, const char * action)
/* DeletePortMappingRange was added in IGD spec v2 */
static void
DeletePortMappingRange(struct upnphttp * h, const char * action)
DeletePortMappingRange(struct upnphttp * h, const char * action, const char * ns)
{
int r = -1;
static const char resp[] =
/*static const char resp[] =
"<u:DeletePortMappingRangeResponse "
"xmlns:u=\"" SERVICE_TYPE_WANIPC "\">"
"</u:DeletePortMappingRangeResponse>";
"</u:DeletePortMappingRangeResponse>";*/
static const char resp[] =
"<u:%sResponse "
"xmlns:u=\"%s\">"
"</u:%sResponse>";
char body[512];
int bodylen;
struct NameValueParserData data;
const char * protocol;
const char * startport_s, * endport_s;
@ -779,7 +825,6 @@ DeletePortMappingRange(struct upnphttp * h, const char * action)
/*int manage;*/
unsigned short * port_list;
unsigned int i, number = 0;
UNUSED(action);
ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
startport_s = GetValueFromNameValueList(&data, "NewStartPort");
@ -815,6 +860,7 @@ DeletePortMappingRange(struct upnphttp * h, const char * action)
{
SoapError(h, 730, "PortMappingNotFound");
ClearNameValueList(&data);
free(port_list);
return;
}
@ -825,13 +871,15 @@ DeletePortMappingRange(struct upnphttp * h, const char * action)
action, port_list[i], protocol, r < 0 ? "failed" : "ok");
}
free(port_list);
BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
bodylen = snprintf(body, sizeof(body), resp,
action, ns, action);
BuildSendAndCloseSoapResp(h, body, bodylen);
ClearNameValueList(&data);
}
static void
GetGenericPortMappingEntry(struct upnphttp * h, const char * action)
GetGenericPortMappingEntry(struct upnphttp * h, const char * action, const char * ns)
{
int r;
@ -902,7 +950,7 @@ GetGenericPortMappingEntry(struct upnphttp * h, const char * action)
int bodylen;
char body[2048];
bodylen = snprintf(body, sizeof(body), resp,
action, SERVICE_TYPE_WANIPC, rhost,
action, ns, /*SERVICE_TYPE_WANIPC,*/ rhost,
(unsigned int)eport, protocol, (unsigned int)iport, iaddr, desc,
leaseduration, action);
BuildSendAndCloseSoapResp(h, body, bodylen);
@ -913,7 +961,7 @@ GetGenericPortMappingEntry(struct upnphttp * h, const char * action)
/* GetListOfPortMappings was added in the IGD v2 specification */
static void
GetListOfPortMappings(struct upnphttp * h, const char * action)
GetListOfPortMappings(struct upnphttp * h, const char * action, const char * ns)
{
static const char resp_start[] =
"<u:%sResponse "
@ -1017,7 +1065,7 @@ http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd">
return;
}
bodylen = snprintf(body, bodyalloc, resp_start,
action, SERVICE_TYPE_WANIPC);
action, ns/*SERVICE_TYPE_WANIPC*/);
if(bodylen < 0)
{
SoapError(h, 501, "ActionFailed");
@ -1091,12 +1139,18 @@ http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd">
#ifdef ENABLE_L3F_SERVICE
static void
SetDefaultConnectionService(struct upnphttp * h, const char * action)
SetDefaultConnectionService(struct upnphttp * h, const char * action, const char * ns)
{
static const char resp[] =
/*static const char resp[] =
"<u:SetDefaultConnectionServiceResponse "
"xmlns:u=\"urn:schemas-upnp-org:service:Layer3Forwarding:1\">"
"</u:SetDefaultConnectionServiceResponse>";
"</u:SetDefaultConnectionServiceResponse>";*/
static const char resp[] =
"<u:%sResponse "
"xmlns:u=\"%s\">"
"</u:%sResponse>";
char body[512];
int bodylen;
struct NameValueParserData data;
char * p;
ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
@ -1116,7 +1170,9 @@ SetDefaultConnectionService(struct upnphttp * h, const char * action)
#endif
{
syslog(LOG_INFO, "%s(%s) : Ignored", action, p);
BuildSendAndCloseSoapResp(h, resp, sizeof(resp)-1);
bodylen = snprintf(body, sizeof(body), resp,
action, ns, action);
BuildSendAndCloseSoapResp(h, body, bodylen);
}
} else {
/* missing argument */
@ -1126,11 +1182,11 @@ SetDefaultConnectionService(struct upnphttp * h, const char * action)
}
static void
GetDefaultConnectionService(struct upnphttp * h, const char * action)
GetDefaultConnectionService(struct upnphttp * h, const char * action, const char * ns)
{
static const char resp[] =
"<u:%sResponse "
"xmlns:u=\"urn:schemas-upnp-org:service:Layer3Forwarding:1\">"
"xmlns:u=\"%s\">"
"<NewDefaultConnectionService>%s:WANConnectionDevice:1,"
SERVICE_ID_WANIPC "</NewDefaultConnectionService>"
"</u:%sResponse>";
@ -1140,21 +1196,23 @@ GetDefaultConnectionService(struct upnphttp * h, const char * action)
char body[1024];
int bodylen;
/* namespace : urn:schemas-upnp-org:service:Layer3Forwarding:1 */
bodylen = snprintf(body, sizeof(body), resp,
action, uuidvalue_wcd, action);
action, ns, uuidvalue_wcd, action);
BuildSendAndCloseSoapResp(h, body, bodylen);
}
#endif
/* Added for compliance with WANIPConnection v2 */
static void
SetConnectionType(struct upnphttp * h, const char * action)
SetConnectionType(struct upnphttp * h, const char * action, const char * ns)
{
#ifdef UPNP_STRICT
const char * connection_type;
#endif /* UPNP_STRICT */
struct NameValueParserData data;
UNUSED(action);
UNUSED(ns);
ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
#ifdef UPNP_STRICT
@ -1173,17 +1231,19 @@ SetConnectionType(struct upnphttp * h, const char * action)
/* Added for compliance with WANIPConnection v2 */
static void
RequestConnection(struct upnphttp * h, const char * action)
RequestConnection(struct upnphttp * h, const char * action, const char * ns)
{
UNUSED(action);
UNUSED(ns);
SoapError(h, 606, "Action not authorized");
}
/* Added for compliance with WANIPConnection v2 */
static void
ForceTermination(struct upnphttp * h, const char * action)
ForceTermination(struct upnphttp * h, const char * action, const char * ns)
{
UNUSED(action);
UNUSED(ns);
SoapError(h, 606, "Action not authorized");
}
@ -1196,7 +1256,7 @@ QueryStateVariable remains useful as a limited test tool but may not be
part of some future versions of UPnP.
*/
static void
QueryStateVariable(struct upnphttp * h, const char * action)
QueryStateVariable(struct upnphttp * h, const char * action, const char * ns)
{
static const char resp[] =
"<u:%sResponse "
@ -1226,7 +1286,7 @@ QueryStateVariable(struct upnphttp * h, const char * action)
status = get_wan_connection_status_str(ext_if_name);
bodylen = snprintf(body, sizeof(body), resp,
action, "urn:schemas-upnp-org:control-1-0",
action, ns,/*"urn:schemas-upnp-org:control-1-0",*/
status, action);
BuildSendAndCloseSoapResp(h, body, bodylen);
}
@ -1249,7 +1309,7 @@ QueryStateVariable(struct upnphttp * h, const char * action)
snprintf(strn, sizeof(strn), "%i",
upnp_get_portmapping_number_of_entries());
bodylen = snprintf(body, sizeof(body), resp,
action, "urn:schemas-upnp-org:control-1-0",
action, ns,/*"urn:schemas-upnp-org:control-1-0",*/
strn, action);
BuildSendAndCloseSoapResp(h, body, bodylen);
}
@ -1268,7 +1328,7 @@ QueryStateVariable(struct upnphttp * h, const char * action)
#endif
/* WANIPv6FirewallControl actions */
static void
GetFirewallStatus(struct upnphttp * h, const char * action)
GetFirewallStatus(struct upnphttp * h, const char * action, const char * ns)
{
static const char resp[] =
"<u:%sResponse "
@ -1281,7 +1341,7 @@ GetFirewallStatus(struct upnphttp * h, const char * action)
int bodylen;
bodylen = snprintf(body, sizeof(body), resp,
action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
action, ns, /*"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",*/
GETFLAG(IPV6FCFWDISABLEDMASK) ? 0 : 1,
GETFLAG(IPV6FCINBOUNDDISALLOWEDMASK) ? 0 : 1,
action);
@ -2011,7 +2071,7 @@ GetAssignedRoles(struct upnphttp * h, const char * action)
static const struct
{
const char * methodName;
void (*methodImpl)(struct upnphttp *, const char *);
void (*methodImpl)(struct upnphttp *, const char *, const char *);
}
soapMethods[] =
{
@ -2068,11 +2128,15 @@ ExecuteSoapAction(struct upnphttp * h, const char * action, int n)
char * p;
char * p2;
int i, len, methodlen;
char namespace[256];
/* SoapAction example :
* urn:schemas-upnp-org:service:WANIPConnection:1#GetStatusInfo */
p = strchr(action, '#');
if(p && (p - action) < n) {
for(i = 0; i < ((int)sizeof(namespace) - 1) && (action + i) < p; i++)
namespace[i] = action[i];
namespace[i] = '\0';
p++;
p2 = strchr(p, '"');
if(p2 && (p2 - action) <= n)
@ -2088,7 +2152,7 @@ ExecuteSoapAction(struct upnphttp * h, const char * action, int n)
syslog(LOG_DEBUG, "Remote Call of SoapMethod '%s'",
soapMethods[i].methodName);
#endif /* DEBUG */
soapMethods[i].methodImpl(h, soapMethods[i].methodName);
soapMethods[i].methodImpl(h, soapMethods[i].methodName, namespace);
return;
}
}