mirror of
https://github.com/status-im/miniupnp.git
synced 2025-02-24 11:48:14 +00:00
Merge branch 'master' into local_port
Conflicts: miniupnpc/miniupnpc.c miniupnpc/miniupnpc.h miniupnpc/miniupnpcmodule.c miniupnpc/upnpc.c
This commit is contained in:
commit
d4af610c51
46
.travis.yml
Normal file
46
.travis.yml
Normal 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
3
README
@ -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
6
appveyor.yml
Normal file
@ -0,0 +1,6 @@
|
||||
install:
|
||||
- set PATH=%PATH%;C:\MinGW\bin
|
||||
|
||||
build_script:
|
||||
- cmd: 'cd miniupnpc'
|
||||
- cmd: 'mingw32make.bat'
|
2
minissdpd/.gitignore
vendored
2
minissdpd/.gitignore
vendored
@ -4,3 +4,5 @@ testcodelength
|
||||
testminissdpd
|
||||
listifaces
|
||||
Makefile.bak
|
||||
validateminissdpd
|
||||
validatecodelength
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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 :
|
||||
|
@ -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
|
||||
|
@ -1 +1 @@
|
||||
1.3
|
||||
1.4
|
||||
|
@ -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"
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
|
@ -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"
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -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
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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
14
minissdpd/testminissdpd.sh
Executable 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`
|
@ -6,9 +6,9 @@
|
||||
# $ PREFIX=/tmp/dummylocation make install
|
||||
# or
|
||||
# $ INSTALLPREFIX=/usr/local make install
|
||||
# or
|
||||
# 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.
|
||||
|
||||
|
@ -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) ) {
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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) ) {
|
||||
|
@ -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);*/
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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
|
||||
)
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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) ) {
|
||||
|
@ -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) {
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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 ??? */
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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" {
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
>
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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"] = ''
|
||||
|
@ -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) {
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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
23
miniupnpc/upnpdev.c
Normal 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
36
miniupnpc/upnpdev.h
Normal 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 */
|
@ -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" {
|
||||
|
@ -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 */
|
||||
|
||||
|
3
miniupnpd/.gitignore
vendored
3
miniupnpd/.gitignore
vendored
@ -14,3 +14,6 @@ testportinuse
|
||||
netfilter/testiptcrdr
|
||||
netfilter/testiptcrdr_dscp
|
||||
netfilter/testiptcrdr_peer
|
||||
testdescs
|
||||
validateupnppermissions
|
||||
validategetifaddr
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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"
|
||||
|
@ -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 */
|
||||
|
@ -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}
|
||||
|
@ -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");
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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 */
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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, ×tamp) >= 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) {
|
||||
@ -1412,6 +1603,10 @@ init(int argc, char * * argv, struct runtime_vars * v)
|
||||
syslog(LOG_ERR, "MiniUPnPd is already running. EXITING");
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef TOMATO
|
||||
syslog(LOG_NOTICE, "version " MINIUPNPD_VERSION " started");
|
||||
#endif /* TOMATO */
|
||||
|
||||
set_startup_time(GETFLAG(SYSUPTIMEMASK));
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
×tamp, 0, 0);
|
||||
NULL/*×tamp*/, 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
29
miniupnpd/testgetifaddr.sh
Executable 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
|
@ -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;
|
||||
}
|
||||
|
||||
|
56
miniupnpd/testupnppermissions.sh
Executable file
56
miniupnpd/testupnppermissions.sh
Executable 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
|
@ -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>");
|
||||
|
@ -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) */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user