miniupnpc-2.2.6/Makefile010064400017500000024000000302311454537750100143570ustar00nanardstaff# $Id: Makefile,v 1.150 2023/06/15 22:55:24 nanard Exp $ # MiniUPnP Project # http://miniupnp.free.fr/ # https://miniupnp.tuxfamily.org/ # https://github.com/miniupnp/miniupnp # (c) 2005-2023 Thomas Bernard # to install use : # $ make DESTDIR=/tmp/dummylocation install # or # $ INSTALLPREFIX=/usr/local make install # or # $ make install (default INSTALLPREFIX is /usr) OS = $(shell $(CC) -dumpmachine) VERSION = $(shell cat VERSION) ifneq (, $(findstring darwin, $(OS))) JARSUFFIX=mac LIBTOOL ?= $(shell which libtool) endif ifneq (, $(findstring linux, $(OS))) JARSUFFIX=linux endif ifneq (, $(findstring mingw, $(OS))$(findstring cygwin, $(OS))$(findstring msys, $(OS))) JARSUFFIX=win32 endif HAVE_IPV6 ?= yes export HAVE_IPV6 # directories INCDIR = include SRCDIR = src BUILD = build CC ?= gcc #AR = gar #CFLAGS = -O -g # to debug : ASANFLAGS = -fsanitize=address -fsanitize=undefined -fsanitize=leak #CFLAGS = -g -ggdb -O0 $(ASANFLAGS) -fno-omit-frame-pointer #CPPFLAGS += -DDEBUG #LDFLAGS += $(ASANFLAGS) CFLAGS ?= -O CFLAGS += -Wall CFLAGS += -W -Wstrict-prototypes CFLAGS += -fno-common CPPFLAGS += -I$(BUILD) CPPFLAGS += -DMINIUPNPC_SET_SOCKET_TIMEOUT CPPFLAGS += -DMINIUPNPC_GET_SRC_ADDR CPPFLAGS += -D_BSD_SOURCE CPPFLAGS += -D_DEFAULT_SOURCE ifneq (, $(findstring netbsd, $(OS))) CPPFLAGS += -D_NETBSD_SOURCE endif ifeq (, $(findstring freebsd, $(OS))$(findstring darwin, $(OS))) #CPPFLAGS += -D_POSIX_C_SOURCE=200112L CPPFLAGS += -D_XOPEN_SOURCE=600 endif #CFLAGS += -ansi #CPPFLAGS += -DNO_GETADDRINFO DEPFLAGS = -MM -MG MKDIR = mkdir -p INSTALL = install SH = /bin/sh JAVA = java # see http://code.google.com/p/jnaerator/ #JNAERATOR = jnaerator-0.9.7.jar #JNAERATOR = jnaerator-0.9.8-shaded.jar #JNAERATORARGS = -library miniupnpc #JNAERATOR = jnaerator-0.10-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 = https://repo1.maven.org/maven2/com/nativelibs4java/jnaerator/0.12 ifneq (, $(findstring sun, $(OS))$(findstring solaris, $(OS))) LDLIBS=-lsocket -lnsl -lresolv CPPFLAGS += -D__EXTENSIONS__ CFLAGS += -std=c99 endif # APIVERSION is used to build SONAME APIVERSION = 17 SRCS = $(wildcard $(SRCDIR)/*.c) LIBOBJS = $(addprefix $(BUILD)/,miniwget.o minixml.o igd_desc_parse.o minisoap.o \ miniupnpc.o upnpreplyparse.o upnpcommands.o upnperrors.o \ connecthostport.o portlistingparse.o receivedata.o upnpdev.o \ addr_is_reserved.o) BUILDINCLUDES = $(addprefix $(BUILD)/, miniupnpcstrings.h) OBJS = $(patsubst $(SRCDIR)/%.c,$(BUILD)/%.o,$(SRCS)) DEPS = $(patsubst $(SRCDIR)/%.c,$(BUILD)/%.d,$(SRCS)) # HEADERS to install CPPFLAGS += -I$(INCDIR) HEADERS = $(wildcard $(INCDIR)/*.h) # library names LIBRARY = $(BUILD)/libminiupnpc.a ifneq (, $(findstring darwin, $(OS))) SHAREDLIBRARY = $(BUILD)/libminiupnpc.dylib SONAME = $(notdir $(basename $(SHAREDLIBRARY))).$(APIVERSION).dylib CPPFLAGS += -D_DARWIN_C_SOURCE else ifeq ($(JARSUFFIX), win32) SHAREDLIBRARY = $(BUILD)/miniupnpc.dll else # Linux/BSD/etc. SHAREDLIBRARY = $(BUILD)/libminiupnpc.so SONAME = $(notdir $(SHAREDLIBRARY)).$(APIVERSION) endif endif EXECUTABLES = $(addprefix $(BUILD)/, upnpc-static upnp-listdevices-static) EXECUTABLES_ADDTESTS = $(addprefix $(BUILD)/, testminixml minixmlvalid \ testupnpreplyparse testigddescparse testminiwget testportlistingparse) TESTMINIXMLOBJS = $(addprefix $(BUILD)/, minixml.o igd_desc_parse.o testminixml.o) TESTMINIWGETOBJS = $(addprefix $(BUILD)/, miniwget.o testminiwget.o connecthostport.o receivedata.o) TESTUPNPREPLYPARSE = $(addprefix $(BUILD)/, testupnpreplyparse.o minixml.o upnpreplyparse.o) TESTPORTLISTINGPARSE = $(addprefix $(BUILD)/, testportlistingparse.o minixml.o portlistingparse.o) TESTADDR_IS_RESERVED = $(addprefix $(BUILD)/, testaddr_is_reserved.o addr_is_reserved.o) TESTIGDDESCPARSE = $(addprefix $(BUILD)/, testigddescparse.o igd_desc_parse.o minixml.o \ miniupnpc.o miniwget.o upnpcommands.o upnpreplyparse.o \ minisoap.o connecthostport.o receivedata.o \ portlistingparse.o addr_is_reserved.o) ifeq (, $(findstring amiga, $(OS))) ifeq (, $(findstring mingw, $(OS))$(findstring cygwin, $(OS))$(findstring msys, $(OS))) CFLAGS += -fPIC endif EXECUTABLES += $(BUILD)/upnpc-shared $(BUILD)/upnp-listdevices-shared TESTMINIWGETOBJS += $(BUILD)/minissdpc.o TESTIGDDESCPARSE += $(BUILD)/minissdpc.o LIBOBJS += $(BUILD)/minissdpc.o endif LIBDIR ?= lib # install directories ifeq ($(strip $(PREFIX)),) INSTALLPREFIX ?= /usr else INSTALLPREFIX ?= $(PREFIX) endif INSTALLDIRINC = $(INSTALLPREFIX)/include/miniupnpc INSTALLDIRLIB = $(INSTALLPREFIX)/$(LIBDIR) INSTALLDIRBIN = $(INSTALLPREFIX)/bin INSTALLDIRMAN = $(INSTALLPREFIX)/share/man PKGCONFIGDIR = $(INSTALLDIRLIB)/pkgconfig FILESTOINSTALL = $(LIBRARY) $(EXECUTABLES) ifeq (, $(findstring amiga, $(OS))) FILESTOINSTALL += $(SHAREDLIBRARY) $(BUILD)/miniupnpc.pc endif .PHONY: install clean depend all check test everything \ installpythonmodule updateversion all: $(LIBRARY) $(EXECUTABLES) test: check check: validateminixml validateminiwget validateupnpreplyparse \ validateportlistingparse validateigddescparse validateaddr_is_reserved everything: all $(EXECUTABLES_ADDTESTS) pythonmodule: $(LIBRARY) $(SRCDIR)/miniupnpcmodule.c setup.py MAKE=$(MAKE) python setup.py build touch $@ installpythonmodule: pythonmodule MAKE=$(MAKE) python setup.py install pythonmodule3: $(LIBRARY) $(SRCDIR)/miniupnpcmodule.c setup.py MAKE=$(MAKE) python3 setup.py build touch $@ installpythonmodule3: pythonmodule3 MAKE=$(MAKE) python3 setup.py install validateminixml: $(BUILD)/minixmlvalid @echo "minixml validation test" ./$< touch $@ validateminiwget: testminiwget.sh $(BUILD)/testminiwget $(BUILD)/minihttptestserver @echo "miniwget validation test" ./$< touch $@ validateupnpreplyparse: testupnpreplyparse.sh $(BUILD)/testupnpreplyparse @echo "upnpreplyparse validation test" ./$< touch $@ validateportlistingparse: $(BUILD)/testportlistingparse @echo "portlistingparse validation test" ./$< touch $@ validateigddescparse: $(BUILD)/testigddescparse @echo "igd desc parse validation test" ./$< testdesc/new_LiveBox_desc.xml testdesc/new_LiveBox_desc.values ./$< testdesc/linksys_WAG200G_desc.xml testdesc/linksys_WAG200G_desc.values touch $@ validateaddr_is_reserved: $(BUILD)/testaddr_is_reserved @echo "addr_is_reserved() validation test" ./$< touch $@ clean: $(RM) $(LIBRARY) $(SHAREDLIBRARY) $(EXECUTABLES) $(OBJS) $(BUILDINCLUDES) $(RM) $(EXECUTABLES_ADDTESTS) # clean python stuff $(RM) pythonmodule pythonmodule3 $(RM) validateminixml validateminiwget validateupnpreplyparse $(RM) validateigddescparse $(RM) minihttptestserver $(RM) testaddr_is_reserved $(RM) -r build/ dist/ #python setup.py clean # clean jnaerator stuff $(RM) _jnaerator.* java/miniupnpc_$(OS).jar distclean: clean $(RM) $(JNAERATOR) java/*.jar java/*.class out.errors.txt updateversion: include/miniupnpc.h cp $< $<.bak sed 's/\(.*MINIUPNPC_API_VERSION\s\+\)[0-9]\+/\1$(APIVERSION)/' < $<.bak > $< install: updateversion $(FILESTOINSTALL) $(INSTALL) -d $(DESTDIR)$(INSTALLDIRINC) $(INSTALL) -m 644 $(HEADERS) $(DESTDIR)$(INSTALLDIRINC) $(INSTALL) -d $(DESTDIR)$(INSTALLDIRLIB) $(INSTALL) -m 644 $(LIBRARY) $(DESTDIR)$(INSTALLDIRLIB) ifeq (, $(findstring amiga, $(OS))) $(INSTALL) -m 644 $(SHAREDLIBRARY) $(DESTDIR)$(INSTALLDIRLIB)/$(SONAME) ln -fs $(SONAME) $(DESTDIR)$(INSTALLDIRLIB)/$(notdir $(SHAREDLIBRARY)) $(INSTALL) -d $(DESTDIR)$(PKGCONFIGDIR) $(INSTALL) -m 644 $(BUILD)/miniupnpc.pc $(DESTDIR)$(PKGCONFIGDIR) endif $(INSTALL) -d $(DESTDIR)$(INSTALLDIRBIN) ifneq (, $(findstring amiga, $(OS))) $(INSTALL) -m 755 $(BUILD)/upnpc-static $(DESTDIR)$(INSTALLDIRBIN)/upnpc $(INSTALL) -m 755 $(BUILD)/upnp-listdevices-static $(DESTDIR)$(INSTALLDIRBIN)/upnp-listdevices else $(INSTALL) -m 755 $(BUILD)/upnpc-shared $(DESTDIR)$(INSTALLDIRBIN)/upnpc $(INSTALL) -m 755 $(BUILD)/upnp-listdevices-shared $(DESTDIR)$(INSTALLDIRBIN)/upnp-listdevices endif $(INSTALL) -m 755 external-ip.sh $(DESTDIR)$(INSTALLDIRBIN)/external-ip ifeq (, $(findstring amiga, $(OS))) $(INSTALL) -d $(DESTDIR)$(INSTALLDIRMAN)/man3 $(INSTALL) -m 644 man3/miniupnpc.3 $(DESTDIR)$(INSTALLDIRMAN)/man3/miniupnpc.3 ifneq (, $(findstring linux, $(OS))) gzip -f $(DESTDIR)$(INSTALLDIRMAN)/man3/miniupnpc.3 endif endif install-static: updateversion $(FILESTOINSTALL) $(INSTALL) -d $(DESTDIR)$(INSTALLDIRINC) $(INSTALL) -m 644 $(HEADERS) $(DESTDIR)$(INSTALLDIRINC) $(INSTALL) -d $(DESTDIR)$(INSTALLDIRLIB) $(INSTALL) -m 644 $(LIBRARY) $(DESTDIR)$(INSTALLDIRLIB) $(INSTALL) -d $(DESTDIR)$(INSTALLDIRBIN) $(INSTALL) -m 755 external-ip.sh $(DESTDIR)$(INSTALLDIRBIN)/external-ip cleaninstall: $(RM) -r $(DESTDIR)$(INSTALLDIRINC) $(RM) $(DESTDIR)$(INSTALLDIRLIB)/$(LIBRARY) $(RM) $(DESTDIR)$(INSTALLDIRLIB)/$(SHAREDLIBRARY) $(BUILD)/miniupnpc.pc: VERSION @$(MKDIR) $(@D) $(RM) $@ echo "prefix=$(INSTALLPREFIX)" >> $@ echo "exec_prefix=\$${prefix}" >> $@ echo "libdir=\$${exec_prefix}/$(LIBDIR)" >> $@ echo "includedir=\$${prefix}/include" >> $@ echo "" >> $@ echo "Name: miniUPnPc" >> $@ echo "Description: UPnP IGD client lightweight library" >> $@ echo "URL: https://miniupnp.tuxfamily.org/" >> $@ echo "Version: $(VERSION)" >> $@ echo "Libs: -L\$${libdir} -lminiupnpc" >> $@ echo "Cflags: -I\$${includedir}" >> $@ depend: $(DEPS) $(LIBRARY): $(LIBOBJS) ifneq (, $(findstring darwin, $(OS))) $(LIBTOOL) -static -o $@ $? else $(AR) crs $@ $? endif $(SHAREDLIBRARY): $(LIBOBJS) ifneq (, $(findstring darwin, $(OS))) # $(CC) -dynamiclib $(LDFLAGS) -Wl,-install_name,$(SONAME) -o $@ $^ $(CC) -dynamiclib $(LDFLAGS) -Wl,-install_name,$(INSTALLDIRLIB)/$(SONAME) -o $@ $^ else $(CC) -shared $(LDFLAGS) -Wl,-soname,$(SONAME) -o $@ $^ endif $(BUILD)/%.o: $(SRCDIR)/%.c $(BUILD)/%.d $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< $(DEPS): $(BUILDINCLUDES) $(BUILD)/%.d: $(SRCDIR)/%.c @$(MKDIR) $(@D) $(CC) $(CPPFLAGS) $(DEPFLAGS) -MT $@ -o $@ $< $(BUILD)/upnpc-static: $(BUILD)/upnpc.o $(LIBRARY) $(CC) $(LDFLAGS) -o $@ $^ $(LOADLIBES) $(LDLIBS) $(BUILD)/upnpc-shared: $(BUILD)/upnpc.o $(SHAREDLIBRARY) $(CC) $(LDFLAGS) -o $@ $^ $(LOADLIBES) $(LDLIBS) $(BUILD)/upnp-listdevices-static: $(BUILD)/listdevices.o $(LIBRARY) $(CC) $(LDFLAGS) -o $@ $^ $(LOADLIBES) $(LDLIBS) $(BUILD)/upnp-listdevices-shared: $(BUILD)/listdevices.o $(SHAREDLIBRARY) $(CC) $(LDFLAGS) -o $@ $^ $(LOADLIBES) $(LDLIBS) $(BUILD)/testminixml: $(TESTMINIXMLOBJS) $(BUILD)/testminiwget: $(TESTMINIWGETOBJS) $(BUILD)/minixmlvalid: $(addprefix $(BUILD)/, minixml.o minixmlvalid.o) $(BUILD)/testupnpreplyparse: $(TESTUPNPREPLYPARSE) $(BUILD)/testigddescparse: $(TESTIGDDESCPARSE) $(BUILD)/testportlistingparse: $(TESTPORTLISTINGPARSE) $(BUILD)/testaddr_is_reserved: $(TESTADDR_IS_RESERVED) $(BUILD)/miniupnpcstrings.h: miniupnpcstrings.h.in updateminiupnpcstrings.sh VERSION @$(MKDIR) $(@D) $(SH) updateminiupnpcstrings.sh $@ $< # ftp tool supplied with OpenBSD can download files from http. jnaerator-%.jar: wget $(JNAERATORBASEURL)/$@ || \ curl -o $@ $(JNAERATORBASEURL)/$@ || \ ftp $(JNAERATORBASEURL)/$@ jar: $(SHAREDLIBRARY) $(JNAERATOR) $(JAVA) -jar $(JNAERATOR) $(JNAERATORARGS) \ 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 mvn_install: mvn install:install-file -Dfile=java/miniupnpc_$(JARSUFFIX).jar \ -DgroupId=com.github \ -DartifactId=miniupnp \ -Dversion=$(VERSION) \ -Dpackaging=jar \ -Dclassifier=$(JARSUFFIX) \ -DgeneratePom=true \ -DcreateChecksum=true # make .deb packages deb: /usr/share/pyshared/stdeb all (python setup.py --command-packages=stdeb.command bdist_deb) # install .deb packages ideb: (sudo dpkg -i deb_dist/*.deb) /usr/share/pyshared/stdeb: /usr/share/doc/python-all-dev (sudo apt-get install python-stdeb) /usr/share/doc/python-all-dev: (sudo apt-get install python-all-dev) minihttptestserver: minihttptestserver.o print-%: @echo "$* = $($*)" ifneq ($(MAKECMDGOALS),clean) -include $(DEPS) endif miniupnpc-2.2.6/include/igd_desc_parse.h010064400017500000024000000031351243532726300174450ustar00nanardstaff/* $Id: igd_desc_parse.h,v 1.12 2014/11/17 17:19:13 nanard Exp $ */ /* Project : miniupnp * http://miniupnp.free.fr/ * Author : Thomas Bernard * Copyright (c) 2005-2014 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. * */ #ifndef IGD_DESC_PARSE_H_INCLUDED #define IGD_DESC_PARSE_H_INCLUDED /* Structure to store the result of the parsing of UPnP * descriptions of Internet Gateway Devices */ #define MINIUPNPC_URL_MAXSIZE (128) struct IGDdatas_service { char controlurl[MINIUPNPC_URL_MAXSIZE]; char eventsuburl[MINIUPNPC_URL_MAXSIZE]; char scpdurl[MINIUPNPC_URL_MAXSIZE]; char servicetype[MINIUPNPC_URL_MAXSIZE]; /*char devicetype[MINIUPNPC_URL_MAXSIZE];*/ }; struct IGDdatas { char cureltname[MINIUPNPC_URL_MAXSIZE]; char urlbase[MINIUPNPC_URL_MAXSIZE]; char presentationurl[MINIUPNPC_URL_MAXSIZE]; int level; /*int state;*/ /* "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */ struct IGDdatas_service CIF; /* "urn:schemas-upnp-org:service:WANIPConnection:1" * "urn:schemas-upnp-org:service:WANPPPConnection:1" */ struct IGDdatas_service first; /* if both WANIPConnection and WANPPPConnection are present */ struct IGDdatas_service second; /* "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1" */ struct IGDdatas_service IPv6FC; /* tmp */ struct IGDdatas_service tmp; }; void IGDstartelt(void *, const char *, int); void IGDendelt(void *, const char *, int); void IGDdata(void *, const char *, int); #ifdef DEBUG void printIGD(struct IGDdatas *); #endif /* DEBUG */ #endif /* IGD_DESC_PARSE_H_INCLUDED */ miniupnpc-2.2.6/include/miniupnpc.h010064400017500000024000000120321454537753600165240ustar00nanardstaff/* $Id: miniupnpc.h,v 1.62 2023/06/11 23:25:46 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * Project: miniupnp * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * Author: Thomas Bernard * Copyright (c) 2005-2022 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 "miniupnpc_declspec.h" #include "igd_desc_parse.h" #include "upnpdev.h" /* error codes : */ #define UPNPDISCOVER_SUCCESS (0) #define UPNPDISCOVER_UNKNOWN_ERROR (-1) #define UPNPDISCOVER_SOCKET_ERROR (-101) #define UPNPDISCOVER_MEMORY_ERROR (-102) /* versions : */ #define MINIUPNPC_VERSION "2.2.6" #define MINIUPNPC_API_VERSION 17 /* Source port: Using "1" as an alias for 1900 for backwards compatibility (presuming one would have used that for the "sameport" parameter) */ #define UPNP_LOCAL_PORT_ANY 0 #define UPNP_LOCAL_PORT_SAME 1 #ifdef __cplusplus extern "C" { #endif /* Structures definitions : */ struct UPNParg { const char * elt; const char * val; }; char * simpleUPnPcommand(int, const char *, const char *, const char *, struct UPNParg *, int *); /* upnpDiscover() * discover UPnP devices on the network. * The discovered devices are returned as a chained list. * It is up to the caller to free the list with freeUPNPDevlist(). * delay (in millisecond) is the maximum time for waiting any device * response. * If available, device list will be obtained from MiniSSDPd. * Default path for minissdpd socket will be used if minissdpdsock argument * is NULL. * If multicastif is not NULL, it will be used instead of the default * multicast interface for sending SSDP discover packets. * 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. * "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, unsigned char ttl, int * error); MINIUPNP_LIBSPEC struct UPNPDev * upnpDiscoverAll(int delay, const char * multicastif, const char * minissdpdsock, int localport, 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, 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, unsigned char ttl, int * error, int searchalltypes); /* parserootdesc() : * parse root XML description of a UPnP device and fill the IGDdatas * structure. */ MINIUPNP_LIBSPEC void parserootdesc(const char *, int, struct IGDdatas *); /* structure used to get fast access to urls * controlURL: controlURL of the WANIPConnection * ipcondescURL: url of the description of the WANIPConnection * controlURL_CIF: controlURL of the WANCommonInterfaceConfig * controlURL_6FC: controlURL of the WANIPv6FirewallControl */ struct UPNPUrls { char * controlURL; char * ipcondescURL; char * controlURL_CIF; char * controlURL_6FC; char * rootdescURL; }; /* UPNP_GetValidIGD() : * return values : * 0 = NO IGD found * 1 = A valid connected IGD has been found * 2 = A valid IGD has been found but it reported as * not connected * 3 = an UPnP device has been found but was not recognized as an IGD * * In any non zero return case, the urls and data structures * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to * free allocated memory. */ MINIUPNP_LIBSPEC int UPNP_GetValidIGD(struct UPNPDev * devlist, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen); /* UPNP_GetIGDFromUrl() * Used when skipping the discovery process. * When succeding, urls, data, and lanaddr arguments are set. * return value : * 0 - Not ok * 1 - OK */ MINIUPNP_LIBSPEC int UPNP_GetIGDFromUrl(const char * rootdescurl, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen); MINIUPNP_LIBSPEC void GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *, const char *, unsigned int); MINIUPNP_LIBSPEC void FreeUPNPUrls(struct UPNPUrls *); /* return 0 or 1 */ MINIUPNP_LIBSPEC int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *); #ifdef __cplusplus } #endif #endif miniupnpc-2.2.6/include/miniupnpc_declspec.h010064400017500000024000000010601255344242200203450ustar00nanardstaff#ifndef MINIUPNPC_DECLSPEC_H_INCLUDED #define MINIUPNPC_DECLSPEC_H_INCLUDED #if defined(_WIN32) && !defined(MINIUPNP_STATICLIB) /* for windows dll */ #ifdef MINIUPNP_EXPORTS #define MINIUPNP_LIBSPEC __declspec(dllexport) #else #define MINIUPNP_LIBSPEC __declspec(dllimport) #endif #else #if defined(__GNUC__) && __GNUC__ >= 4 /* fix dynlib for OS X 10.9.2 and Apple LLVM version 5.0 */ #define MINIUPNP_LIBSPEC __attribute__ ((visibility ("default"))) #else #define MINIUPNP_LIBSPEC #endif #endif #endif /* MINIUPNPC_DECLSPEC_H_INCLUDED */ miniupnpc-2.2.6/include/miniupnpctypes.h010064400017500000024000000012421412470240300175640ustar00nanardstaff/* $Id: miniupnpctypes.h,v 1.3 2021/08/21 09:50:00 nanard Exp $ */ /* Miniupnp project : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org * Author : Thomas Bernard * Copyright (c) 2021 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided within this distribution */ #ifndef MINIUPNPCTYPES_H_INCLUDED #define MINIUPNPCTYPES_H_INCLUDED /* Use unsigned long long when available : * strtoull is C99 */ #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L #define UNSIGNED_INTEGER unsigned long long #define STRTOUI strtoull #else #define UNSIGNED_INTEGER unsigned int #define STRTOUI strtoul #endif #endif miniupnpc-2.2.6/include/miniwget.h010064400017500000024000000012621326165065200163330ustar00nanardstaff/* $Id: miniwget.h,v 1.13 2018/04/06 10:53:15 nanard Exp $ */ /* Project : miniupnp * Author : Thomas Bernard * Copyright (c) 2005-2016 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 "miniupnpc_declspec.h" #ifdef __cplusplus extern "C" { #endif MINIUPNP_LIBSPEC void * miniwget(const char *, int *, unsigned int, int *); MINIUPNP_LIBSPEC void * miniwget_getaddr(const char *, int *, char *, int, unsigned int, int *); int parseURL(const char *, char *, unsigned short *, char * *, unsigned int *); #ifdef __cplusplus } #endif #endif miniupnpc-2.2.6/include/portlistingparse.h010064400017500000024000000034461255344400000201160ustar00nanardstaff/* $Id: portlistingparse.h,v 1.11 2015/07/21 13:16:55 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (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 "miniupnpc_declspec.h" /* for the definition of UNSIGNED_INTEGER */ #include "miniupnpctypes.h" #ifdef __cplusplus extern "C" { #endif /* sample of PortMappingEntry : 202.233.2.1 2345 TCP 2345 192.168.1.137 1 dooom 345 */ typedef enum { PortMappingEltNone, PortMappingEntry, NewRemoteHost, NewExternalPort, NewProtocol, NewInternalPort, NewInternalClient, NewEnabled, NewDescription, NewLeaseTime } portMappingElt; struct PortMapping { struct PortMapping * l_next; /* list next element */ UNSIGNED_INTEGER leaseTime; unsigned short externalPort; unsigned short internalPort; char remoteHost[64]; char internalClient[64]; char description[64]; char protocol[4]; unsigned char enabled; }; struct PortMappingParserData { struct PortMapping * l_head; /* list head */ portMappingElt curelt; }; MINIUPNP_LIBSPEC void ParsePortListing(const char * buffer, int bufsize, struct PortMappingParserData * pdata); MINIUPNP_LIBSPEC void FreePortListing(struct PortMappingParserData * pdata); #ifdef __cplusplus } #endif #endif miniupnpc-2.2.6/include/upnpcommands.h010064400017500000024000000324161343001453300172070ustar00nanardstaff/* $Id: upnpcommands.h,v 1.33 2019/02/10 12:29:25 nanard Exp $ */ /* Miniupnp project : http://miniupnp.free.fr/ * Author : Thomas Bernard * Copyright (c) 2005-2018 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided within this distribution */ #ifndef UPNPCOMMANDS_H_INCLUDED #define UPNPCOMMANDS_H_INCLUDED #include "miniupnpc_declspec.h" #include "miniupnpctypes.h" /* MiniUPnPc return codes : */ #define UPNPCOMMAND_SUCCESS (0) #define UPNPCOMMAND_UNKNOWN_ERROR (-1) #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" { #endif struct PortMappingParserData; MINIUPNP_LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalBytesSent(const char * controlURL, const char * servicetype); MINIUPNP_LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalBytesReceived(const char * controlURL, const char * servicetype); MINIUPNP_LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalPacketsSent(const char * controlURL, const char * servicetype); MINIUPNP_LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalPacketsReceived(const char * controlURL, const char * servicetype); /* UPNP_GetStatusInfo() * status and lastconnerror are 64 byte buffers * Return values : * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR * or a UPnP Error code */ MINIUPNP_LIBSPEC int UPNP_GetStatusInfo(const char * controlURL, const char * servicetype, char * status, unsigned int * uptime, char * lastconnerror); /* UPNP_GetConnectionTypeInfo() * argument connectionType is a 64 character buffer * Return Values : * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR * or a UPnP Error code */ MINIUPNP_LIBSPEC int UPNP_GetConnectionTypeInfo(const char * controlURL, const char * servicetype, char * connectionType); /* UPNP_GetExternalIPAddress() call the corresponding UPNP method. * if the third arg is not null the value is copied to it. * at least 16 bytes must be available * * Return values : * 0 : SUCCESS * NON ZERO : ERROR Either an UPnP error code or an unknown error. * * possible UPnP Errors : * 402 Invalid Args - See UPnP Device Architecture section on Control. * 501 Action Failed - See UPnP Device Architecture section on Control. */ MINIUPNP_LIBSPEC int UPNP_GetExternalIPAddress(const char * controlURL, const char * servicetype, char * extIpAdd); /* UPNP_GetLinkLayerMaxBitRates() * call WANCommonInterfaceConfig:1#GetCommonLinkProperties * * return values : * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR * or a UPnP Error Code. */ MINIUPNP_LIBSPEC int UPNP_GetLinkLayerMaxBitRates(const char* controlURL, const char* servicetype, unsigned int * bitrateDown, unsigned int * bitrateUp); /* UPNP_AddPortMapping() * if desc is NULL, it will be defaulted to "libminiupnpc" * remoteHost is usually NULL because IGD don't support it. * * Return values : * 0 : SUCCESS * NON ZERO : ERROR. Either an UPnP error code or an unknown error. * * List of possible UPnP errors for AddPortMapping : * errorCode errorDescription (short) - Description (long) * 402 Invalid Args - See UPnP Device Architecture section on Control. * 501 Action Failed - See UPnP Device Architecture section on Control. * 606 Action not authorized - The action requested REQUIRES authorization and * the sender was not authorized. * 715 WildCardNotPermittedInSrcIP - The source IP address cannot be * wild-carded * 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded * 718 ConflictInMappingEntry - The port mapping entry specified conflicts * with a mapping assigned previously to another client * 724 SamePortValuesRequired - Internal and External port values * must be the same * 725 OnlyPermanentLeasesSupported - The NAT implementation only supports * permanent lease times on port mappings * 726 RemoteHostOnlySupportsWildcard - RemoteHost must be a wildcard * and cannot be a specific IP address or DNS name * 727 ExternalPortOnlySupportsWildcard - ExternalPort must be a wildcard and * cannot be a specific port value * 728 NoPortMapsAvailable - There are not enough free ports available to * complete port mapping. * 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed * due to conflict with other mechanisms. * 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded */ MINIUPNP_LIBSPEC int UPNP_AddPortMapping(const char * controlURL, const char * servicetype, const char * extPort, const char * inPort, const char * inClient, const char * desc, const char * proto, const char * remoteHost, const char * leaseDuration); /* UPNP_AddAnyPortMapping() * if desc is NULL, it will be defaulted to "libminiupnpc" * remoteHost is usually NULL because IGD don't support it. * * Return values : * 0 : SUCCESS * NON ZERO : ERROR. Either an UPnP error code or an unknown error. * * List of possible UPnP errors for AddPortMapping : * errorCode errorDescription (short) - Description (long) * 402 Invalid Args - See UPnP Device Architecture section on Control. * 501 Action Failed - See UPnP Device Architecture section on Control. * 606 Action not authorized - The action requested REQUIRES authorization and * the sender was not authorized. * 715 WildCardNotPermittedInSrcIP - The source IP address cannot be * wild-carded * 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded * 728 NoPortMapsAvailable - There are not enough free ports available to * complete port mapping. * 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed * due to conflict with other mechanisms. * 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded */ MINIUPNP_LIBSPEC int UPNP_AddAnyPortMapping(const char * controlURL, const char * servicetype, const char * extPort, const char * inPort, const char * inClient, const char * desc, const char * proto, const char * remoteHost, const char * leaseDuration, char * reservedPort); /* UPNP_DeletePortMapping() * Use same argument values as what was used for AddPortMapping(). * remoteHost is usually NULL because IGD don't support it. * Return Values : * 0 : SUCCESS * NON ZERO : error. Either an UPnP error code or an undefined error. * * List of possible UPnP errors for DeletePortMapping : * 402 Invalid Args - See UPnP Device Architecture section on Control. * 606 Action not authorized - The action requested REQUIRES authorization * and the sender was not authorized. * 714 NoSuchEntryInArray - The specified value does not exist in the array */ MINIUPNP_LIBSPEC int UPNP_DeletePortMapping(const char * controlURL, const char * servicetype, const char * extPort, const char * proto, const char * remoteHost); /* UPNP_DeletePortRangeMapping() * Use same argument values as what was used for AddPortMapping(). * remoteHost is usually NULL because IGD don't support it. * Return Values : * 0 : SUCCESS * NON ZERO : error. Either an UPnP error code or an undefined error. * * List of possible UPnP errors for DeletePortMapping : * 606 Action not authorized - The action requested REQUIRES authorization * and the sender was not authorized. * 730 PortMappingNotFound - This error message is returned if no port * mapping is found in the specified range. * 733 InconsistentParameters - NewStartPort and NewEndPort values are not consistent. */ MINIUPNP_LIBSPEC int UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype, const char * extPortStart, const char * extPortEnd, const char * proto, const char * manage); /* UPNP_GetPortMappingNumberOfEntries() * not supported by all routers */ MINIUPNP_LIBSPEC int UPNP_GetPortMappingNumberOfEntries(const char * controlURL, const char * servicetype, unsigned int * numEntries); /* UPNP_GetSpecificPortMappingEntry() * retrieves an existing port mapping * params : * in extPort * in proto * in remoteHost * out intClient (16 bytes) * out intPort (6 bytes) * out desc (80 bytes) * out enabled (4 bytes) * out leaseDuration (16 bytes) * * return value : * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR * or a UPnP Error Code. * * List of possible UPnP errors for _GetSpecificPortMappingEntry : * 402 Invalid Args - See UPnP Device Architecture section on Control. * 501 Action Failed - See UPnP Device Architecture section on Control. * 606 Action not authorized - The action requested REQUIRES authorization * and the sender was not authorized. * 714 NoSuchEntryInArray - The specified value does not exist in the array. */ MINIUPNP_LIBSPEC int UPNP_GetSpecificPortMappingEntry(const char * controlURL, const char * servicetype, const char * extPort, const char * proto, const char * remoteHost, char * intClient, char * intPort, char * desc, char * enabled, char * leaseDuration); /* UPNP_GetGenericPortMappingEntry() * params : * in index * out extPort (6 bytes) * out intClient (16 bytes) * out intPort (6 bytes) * out protocol (4 bytes) * out desc (80 bytes) * out enabled (4 bytes) * out rHost (64 bytes) * out duration (16 bytes) * * return value : * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR * or a UPnP Error Code. * * Possible UPNP Error codes : * 402 Invalid Args - See UPnP Device Architecture section on Control. * 606 Action not authorized - The action requested REQUIRES authorization * and the sender was not authorized. * 713 SpecifiedArrayIndexInvalid - The specified array index is out of bounds */ MINIUPNP_LIBSPEC int UPNP_GetGenericPortMappingEntry(const char * controlURL, const char * servicetype, const char * index, char * extPort, char * intClient, char * intPort, char * protocol, char * desc, char * enabled, char * rHost, char * duration); /* UPNP_GetListOfPortMappings() Available in IGD v2 * * * Possible UPNP Error codes : * 606 Action not Authorized * 730 PortMappingNotFound - no port mapping is found in the specified range. * 733 InconsistantParameters - NewStartPort and NewEndPort values are not * consistent. */ MINIUPNP_LIBSPEC int UPNP_GetListOfPortMappings(const char * controlURL, const char * servicetype, const char * startPort, const char * endPort, const char * protocol, const char * numberOfPorts, struct PortMappingParserData * data); /* IGD:2, functions for service WANIPv6FirewallControl:1 */ MINIUPNP_LIBSPEC int UPNP_GetFirewallStatus(const char * controlURL, const char * servicetype, int * firewallEnabled, int * inboundPinholeAllowed); MINIUPNP_LIBSPEC int UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype, const char * remoteHost, const char * remotePort, const char * intClient, const char * intPort, const char * proto, int * opTimeout); MINIUPNP_LIBSPEC int UPNP_AddPinhole(const char * controlURL, const char * servicetype, const char * remoteHost, const char * remotePort, const char * intClient, const char * intPort, const char * proto, const char * leaseTime, char * uniqueID); MINIUPNP_LIBSPEC int UPNP_UpdatePinhole(const char * controlURL, const char * servicetype, const char * uniqueID, const char * leaseTime); MINIUPNP_LIBSPEC int UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID); MINIUPNP_LIBSPEC int UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype, const char * uniqueID, int * isWorking); MINIUPNP_LIBSPEC int UPNP_GetPinholePackets(const char * controlURL, const char * servicetype, const char * uniqueID, int * packets); #ifdef __cplusplus } #endif #endif miniupnpc-2.2.6/include/upnpdev.h010064400017500000024000000016661412470240400161710ustar00nanardstaff/* $Id: upnpdev.h,v 1.4 2021/08/21 09:45:01 nanard Exp $ */ /* Project : miniupnp * Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * Author : Thomas BERNARD * copyright (c) 2005-2021 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; char * usn; unsigned int scope_id; #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 flexible array member */ char buffer[]; #elif defined(__GNUC__) char buffer[0]; #else /* Fallback to a hack */ char buffer[1]; #endif }; /* freeUPNPDevlist() * free list returned by upnpDiscover() */ MINIUPNP_LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist); #ifdef __cplusplus } #endif #endif /* UPNPDEV_H_INCLUDED */ miniupnpc-2.2.6/include/upnperrors.h010064400017500000024000000011601255344400000167130ustar00nanardstaff/* $Id: upnperrors.h,v 1.6 2015/07/21 13:16:55 nanard Exp $ */ /* (c) 2007-2015 Thomas Bernard * All rights reserved. * MiniUPnP Project. * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * This software is subjet to the conditions detailed in the * provided LICENCE file. */ #ifndef UPNPERRORS_H_INCLUDED #define UPNPERRORS_H_INCLUDED #include "miniupnpc_declspec.h" #ifdef __cplusplus extern "C" { #endif /* strupnperror() * Return a string description of the UPnP error code * or NULL for undefinded errors */ MINIUPNP_LIBSPEC const char * strupnperror(int err); #ifdef __cplusplus } #endif #endif miniupnpc-2.2.6/include/upnpreplyparse.h010064400017500000024000000025211242347260200175740ustar00nanardstaff/* $Id: upnpreplyparse.h,v 1.19 2014/10/27 16:33:19 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2013 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ #ifndef UPNPREPLYPARSE_H_INCLUDED #define UPNPREPLYPARSE_H_INCLUDED #ifdef __cplusplus extern "C" { #endif struct NameValue { struct NameValue * l_next; char name[64]; char value[128]; }; struct NameValueParserData { struct NameValue * l_head; char curelt[64]; char * portListing; int portListingLength; int topelt; const char * cdata; int cdatalen; }; /* ParseNameValue() */ void ParseNameValue(const char * buffer, int bufsize, struct NameValueParserData * data); /* ClearNameValueList() */ void ClearNameValueList(struct NameValueParserData * pdata); /* GetValueFromNameValueList() */ char * GetValueFromNameValueList(struct NameValueParserData * pdata, const char * Name); #if 0 /* GetValueFromNameValueListIgnoreNS() */ char * GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata, const char * Name); #endif /* DisplayNameValueList() */ #ifdef DEBUG void DisplayNameValueList(char * buffer, int bufsize); #endif #ifdef __cplusplus } #endif #endif miniupnpc-2.2.6/src/igd_desc_parse.c010064400017500000024000000110161257653522500166060ustar00nanardstaff/* $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-2015 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. */ #include "igd_desc_parse.h" #include #include /* Start element handler : * update nesting level counter and copy element name */ void IGDstartelt(void * d, const char * name, int l) { struct IGDdatas * datas = (struct IGDdatas *)d; 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) ) { datas->tmp.controlurl[0] = '\0'; datas->tmp.eventsuburl[0] = '\0'; datas->tmp.scpdurl[0] = '\0'; datas->tmp.servicetype[0] = '\0'; } } #define COMPARE(str, cstr) (0==memcmp(str, cstr, sizeof(cstr) - 1)) /* End element handler : * update nesting level counter and update parser state if * service element is parsed */ void IGDendelt(void * d, const char * name, int l) { struct IGDdatas * datas = (struct IGDdatas *)d; datas->level--; /*printf("endelt %2d %.*s\n", datas->level, l, name);*/ if( (l==7) && !memcmp(name, "service", l) ) { if(COMPARE(datas->tmp.servicetype, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:")) { memcpy(&datas->CIF, &datas->tmp, sizeof(struct IGDdatas_service)); } else if(COMPARE(datas->tmp.servicetype, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:")) { memcpy(&datas->IPv6FC, &datas->tmp, sizeof(struct IGDdatas_service)); } else if(COMPARE(datas->tmp.servicetype, "urn:schemas-upnp-org:service:WANIPConnection:") || COMPARE(datas->tmp.servicetype, "urn:schemas-upnp-org:service:WANPPPConnection:") ) { if(datas->first.servicetype[0] == '\0') { memcpy(&datas->first, &datas->tmp, sizeof(struct IGDdatas_service)); } else { memcpy(&datas->second, &datas->tmp, sizeof(struct IGDdatas_service)); } } } } /* Data handler : * copy data depending on the current element name and state */ void IGDdata(void * d, const char * data, int l) { struct IGDdatas * datas = (struct IGDdatas *)d; char * dstmember = 0; /*printf("%2d %s : %.*s\n", datas->level, datas->cureltname, l, data); */ if( !strcmp(datas->cureltname, "URLBase") ) dstmember = datas->urlbase; else if( !strcmp(datas->cureltname, "presentationURL") ) dstmember = datas->presentationurl; else if( !strcmp(datas->cureltname, "serviceType") ) dstmember = datas->tmp.servicetype; else if( !strcmp(datas->cureltname, "controlURL") ) dstmember = datas->tmp.controlurl; else if( !strcmp(datas->cureltname, "eventSubURL") ) dstmember = datas->tmp.eventsuburl; else if( !strcmp(datas->cureltname, "SCPDURL") ) dstmember = datas->tmp.scpdurl; /* else if( !strcmp(datas->cureltname, "deviceType") ) dstmember = datas->devicetype_tmp;*/ if(dstmember) { if(l>=MINIUPNPC_URL_MAXSIZE) l = MINIUPNPC_URL_MAXSIZE-1; memcpy(dstmember, data, l); dstmember[l] = '\0'; } } #ifdef DEBUG void printIGD(struct IGDdatas * d) { printf("urlbase = '%s'\n", d->urlbase); printf("WAN Device (Common interface config) :\n"); /*printf(" deviceType = '%s'\n", d->CIF.devicetype);*/ printf(" serviceType = '%s'\n", d->CIF.servicetype); printf(" controlURL = '%s'\n", d->CIF.controlurl); printf(" eventSubURL = '%s'\n", d->CIF.eventsuburl); printf(" SCPDURL = '%s'\n", d->CIF.scpdurl); printf("primary WAN Connection Device (IP or PPP Connection):\n"); /*printf(" deviceType = '%s'\n", d->first.devicetype);*/ printf(" servicetype = '%s'\n", d->first.servicetype); printf(" controlURL = '%s'\n", d->first.controlurl); printf(" eventSubURL = '%s'\n", d->first.eventsuburl); printf(" SCPDURL = '%s'\n", d->first.scpdurl); printf("secondary WAN Connection Device (IP or PPP Connection):\n"); /*printf(" deviceType = '%s'\n", d->second.devicetype);*/ printf(" servicetype = '%s'\n", d->second.servicetype); printf(" controlURL = '%s'\n", d->second.controlurl); printf(" eventSubURL = '%s'\n", d->second.eventsuburl); printf(" SCPDURL = '%s'\n", d->second.scpdurl); printf("WAN IPv6 Firewall Control :\n"); /*printf(" deviceType = '%s'\n", d->IPv6FC.devicetype);*/ printf(" servicetype = '%s'\n", d->IPv6FC.servicetype); printf(" controlURL = '%s'\n", d->IPv6FC.controlurl); printf(" eventSubURL = '%s'\n", d->IPv6FC.eventsuburl); printf(" SCPDURL = '%s'\n", d->IPv6FC.scpdurl); } #endif /* DEBUG */ miniupnpc-2.2.6/src/miniwget.c010064400017500000024000000407621454537750100155070ustar00nanardstaff/* $Id: miniwget.c,v 1.85 2023/06/15 21:47:50 nanard Exp $ */ /* Project : miniupnp * Website : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * Author : Thomas Bernard * Copyright (c) 2005-2023 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. */ #include #include #include #include #ifdef _WIN32 #include #include #include #define MAXHOSTNAMELEN 64 #include "win32_snprintf.h" #define socklen_t int #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 */ #else /* #ifdef _WIN32 */ #include #include #if defined(__amigaos__) && !defined(__amigaos4__) #define socklen_t int #else /* #if defined(__amigaos__) && !defined(__amigaos4__) */ #include #endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */ #include #include #include #include #include #define closesocket close #include #endif /* #else _WIN32 */ #ifdef __GNU__ #define MAXHOSTNAMELEN 64 #endif /* __GNU__ */ #ifndef MIN #define MIN(x,y) (((x)<(y))?(x):(y)) #endif /* MIN */ #include "miniupnpcstrings.h" #include "miniwget.h" #include "connecthostport.h" #include "receivedata.h" #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif /* * Read a HTTP response from a socket. * Process Content-Length and Transfer-encoding headers. * return a pointer to the content buffer, which length is saved * to the length parameter. */ void * getHTTPResponse(SOCKET s, int * size, int * status_code) { char buf[2048]; int n; int endofheaders = 0; int chunked = 0; int content_length = -1; unsigned int chunksize = 0; unsigned int bytestocopy = 0; /* buffers : */ char * header_buf; unsigned int header_buf_len = 2048; unsigned int header_buf_used = 0; char * content_buf; unsigned int content_buf_len = 2048; unsigned int content_buf_used = 0; char chunksize_buf[32]; unsigned int chunksize_buf_index; #ifdef DEBUG char * reason_phrase = NULL; int reason_phrase_len = 0; #endif if(status_code) *status_code = -1; 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; while((n = receivedata(s, buf, sizeof(buf), 5000, NULL)) > 0) { if(endofheaders == 0) { int i; int linestart=0; int colon=0; int valuestart=0; if(header_buf_used + n > header_buf_len) { char * tmp = realloc(header_buf, header_buf_used + n); if(tmp == NULL) { /* memory allocation error */ free(header_buf); free(content_buf); *size = -1; return NULL; } header_buf = tmp; header_buf_len = header_buf_used + n; } memcpy(header_buf + header_buf_used, buf, n); header_buf_used += n; /* search for CR LF CR LF (end of headers) * recognize also LF LF */ i = 0; while(i < ((int)header_buf_used-1) && (endofheaders == 0)) { if(header_buf[i] == '\r') { i++; if(header_buf[i] == '\n') { i++; if(i < (int)header_buf_used && header_buf[i] == '\r') { i++; if(i < (int)header_buf_used && header_buf[i] == '\n') { endofheaders = i+1; } } } } else if(header_buf[i] == '\n') { i++; if(header_buf[i] == '\n') { endofheaders = i+1; } } i++; } if(endofheaders == 0) continue; /* parse header lines */ for(i = 0; i < endofheaders - 1; i++) { if(linestart > 0 && colon <= linestart && header_buf[i]==':') { colon = i; while(i < (endofheaders-1) && (header_buf[i+1] == ' ' || header_buf[i+1] == '\t')) i++; valuestart = i + 1; } /* detecting end of line */ else if(header_buf[i]=='\r' || header_buf[i]=='\n') { if(linestart == 0 && status_code) { /* Status line * HTTP-Version SP Status-Code SP Reason-Phrase CRLF */ int sp; for(sp = 0; sp < i - 1; sp++) if(header_buf[sp] == ' ') { if(*status_code < 0) { if (header_buf[sp+1] >= '1' && header_buf[sp+1] <= '9') *status_code = atoi(header_buf + sp + 1); } else { #ifdef DEBUG reason_phrase = header_buf + sp + 1; reason_phrase_len = i - sp - 1; #endif break; } } #ifdef DEBUG printf("HTTP status code = %d, Reason phrase = %.*s\n", *status_code, reason_phrase_len, reason_phrase); #endif } else if(colon > linestart && valuestart > colon) { #ifdef DEBUG printf("header='%.*s', value='%.*s'\n", colon-linestart, header_buf+linestart, i-valuestart, header_buf+valuestart); #endif if(0==strncasecmp(header_buf+linestart, "content-length", colon-linestart)) { content_length = atoi(header_buf+valuestart); #ifdef DEBUG printf("Content-Length: %d\n", content_length); #endif } else if(0==strncasecmp(header_buf+linestart, "transfer-encoding", colon-linestart) && 0==strncasecmp(header_buf+valuestart, "chunked", 7)) { #ifdef DEBUG printf("chunked transfer-encoding!\n"); #endif chunked = 1; } } while((i < (int)header_buf_used) && (header_buf[i]=='\r' || header_buf[i] == '\n')) i++; linestart = i; colon = linestart; valuestart = 0; } } /* copy the remaining of the received data back to buf */ n = header_buf_used - endofheaders; memcpy(buf, header_buf + endofheaders, n); /* if(headers) */ } /* if we get there, endofheaders != 0. * In the other case, there was a continue above */ /* content */ if(chunked) { int i = 0; while(i < n) { if(chunksize == 0) { /* reading chunk size */ if(chunksize_buf_index == 0) { /* skipping any leading CR LF */ if(buf[i] == '\r') i++; if(i= '0' && chunksize_buf[j] <= '9') chunksize = (chunksize << 4) + (chunksize_buf[j] - '0'); else chunksize = (chunksize << 4) + ((chunksize_buf[j] | 32) - 'a' + 10); } chunksize_buf[0] = '\0'; chunksize_buf_index = 0; i++; } else { /* not finished to get chunksize */ continue; } #ifdef DEBUG printf("chunksize = %u (%x)\n", chunksize, chunksize); #endif if(chunksize == 0) { #ifdef DEBUG printf("end of HTTP content - %d %d\n", i, n); /*printf("'%.*s'\n", n-i, buf+i);*/ #endif goto end_of_stream; } } /* it is guaranteed that (n >= i) */ bytestocopy = (chunksize < (unsigned int)(n - i))?chunksize:(unsigned int)(n - i); if((content_buf_used + bytestocopy) > content_buf_len) { char * tmp; if((content_length >= 0) && ((unsigned int)content_length >= (content_buf_used + bytestocopy))) { content_buf_len = content_length; } else { content_buf_len = content_buf_used + bytestocopy; } tmp = realloc(content_buf, content_buf_len); if(tmp == NULL) { /* memory allocation error */ free(content_buf); free(header_buf); *size = -1; return NULL; } content_buf = tmp; } memcpy(content_buf + content_buf_used, buf + i, bytestocopy); content_buf_used += bytestocopy; i += bytestocopy; chunksize -= bytestocopy; } } else { /* not chunked */ if(content_length > 0 && (content_buf_used + n) > (unsigned int)content_length) { /* skipping additional bytes */ n = content_length - content_buf_used; } if(content_buf_used + n > content_buf_len) { char * tmp; if(content_length >= 0 && (unsigned int)content_length >= (content_buf_used + n)) { content_buf_len = content_length; } else { content_buf_len = content_buf_used + n; } tmp = realloc(content_buf, content_buf_len); if(tmp == NULL) { /* memory allocation error */ free(content_buf); free(header_buf); *size = -1; return NULL; } content_buf = tmp; } memcpy(content_buf + content_buf_used, buf, n); content_buf_used += n; } /* use the Content-Length header value if available */ if(content_length > 0 && content_buf_used >= (unsigned int)content_length) { #ifdef DEBUG printf("End of HTTP content\n"); #endif break; } } end_of_stream: free(header_buf); *size = content_buf_used; if(content_buf_used == 0) { free(content_buf); content_buf = NULL; } return content_buf; } /* miniwget3() : * do all the work. * Return NULL if something failed. */ static void * miniwget3(const char * host, unsigned short port, const char * path, int * size, char * addr_str, int addr_str_len, const char * httpversion, unsigned int scope_id, int * status_code) { char buf[2048]; SOCKET s; int n; int len; int sent; void * content; *size = 0; s = connecthostport(host, port, scope_id); if(ISINVALID(s)) return NULL; /* get address for caller ! */ if(addr_str) { struct sockaddr_storage saddr; socklen_t saddrlen; saddrlen = sizeof(saddr); if(getsockname(s, (struct sockaddr *)&saddr, &saddrlen) < 0) { perror("getsockname"); } else { #if defined(__amigaos__) && !defined(__amigaos4__) /* using INT WINAPI WSAAddressToStringA(LPSOCKADDR, DWORD, LPWSAPROTOCOL_INFOA, LPSTR, LPDWORD); * But his function make a string with the port : nn.nn.nn.nn:port */ /* if(WSAAddressToStringA((SOCKADDR *)&saddr, sizeof(saddr), NULL, addr_str, (DWORD *)&addr_str_len)) { printf("WSAAddressToStringA() failed : %d\n", WSAGetLastError()); }*/ /* the following code is only compatible with ip v4 addresses */ strncpy(addr_str, inet_ntoa(((struct sockaddr_in *)&saddr)->sin_addr), addr_str_len); #else #if 0 if(saddr.sa_family == AF_INET6) { inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)&saddr)->sin6_addr), addr_str, addr_str_len); } else { inet_ntop(AF_INET, &(((struct sockaddr_in *)&saddr)->sin_addr), addr_str, addr_str_len); } #endif /* getnameinfo return ip v6 address with the scope identifier * such as : 2a01:e35:8b2b:7330::%4281128194 */ n = getnameinfo((const struct sockaddr *)&saddr, saddrlen, addr_str, addr_str_len, NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV); if(n != 0) { #ifdef _WIN32 fprintf(stderr, "getnameinfo() failed : %d\n", n); #else fprintf(stderr, "getnameinfo() failed : %s\n", gai_strerror(n)); #endif } #endif } #ifdef DEBUG printf("address miniwget : %s\n", addr_str); #endif } len = snprintf(buf, sizeof(buf), "GET %s HTTP/%s\r\n" "Host: %s:%d\r\n" "Connection: Close\r\n" "User-Agent: " OS_STRING " " UPNP_VERSION_STRING " MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n" "\r\n", path, httpversion, host, port); if ((unsigned int)len >= sizeof(buf)) { closesocket(s); return NULL; } sent = 0; /* sending the HTTP request */ while(sent < len) { n = send(s, buf+sent, len-sent, 0); if(n < 0) { perror("send"); closesocket(s); return NULL; } else { sent += n; } } content = getHTTPResponse(s, size, status_code); closesocket(s); return content; } /* miniwget2() : * Call miniwget3(); retry with HTTP/1.1 if 1.0 fails. */ static void * miniwget2(const char * host, unsigned short port, const char * path, int * size, char * addr_str, int addr_str_len, unsigned int scope_id, int * status_code) { char * respbuffer; #if 1 respbuffer = miniwget3(host, port, path, size, addr_str, addr_str_len, "1.1", scope_id, status_code); #else respbuffer = miniwget3(host, port, path, size, addr_str, addr_str_len, "1.0", scope_id, status_code); if (*size == 0) { #ifdef DEBUG printf("Retrying with HTTP/1.1\n"); #endif free(respbuffer); respbuffer = miniwget3(host, port, path, size, addr_str, addr_str_len, "1.1", scope_id, status_code); } #endif return respbuffer; } /* parseURL() * arguments : * url : source string not modified * hostname : hostname destination string (size of MAXHOSTNAMELEN+1) * port : port (destination) * path : pointer to the path part of the URL * * Return values : * 0 - Failure * 1 - Success */ int parseURL(const char * url, char * hostname, unsigned short * port, char * * path, unsigned int * scope_id) { char * p1, *p2, *p3; if(!url) return 0; p1 = strstr(url, "://"); if(!p1) return 0; p1 += 3; if( (url[0]!='h') || (url[1]!='t') ||(url[2]!='t') || (url[3]!='p')) return 0; memset(hostname, 0, MAXHOSTNAMELEN + 1); if(*p1 == '[') { /* IP v6 : http://[2a00:1450:8002::6a]/path/abc */ char * scope; scope = strchr(p1, '%'); p2 = strchr(p1, ']'); if(p2 && scope && scope < p2 && scope_id) { /* parse scope */ #ifdef IF_NAMESIZE char tmp[IF_NAMESIZE]; int l; scope++; /* "%25" is just '%' in URL encoding */ if(scope[0] == '2' && scope[1] == '5') scope += 2; /* skip "25" */ l = p2 - scope; if(l >= IF_NAMESIZE) l = IF_NAMESIZE - 1; memcpy(tmp, scope, l); tmp[l] = '\0'; *scope_id = if_nametoindex(tmp); if(*scope_id == 0) { *scope_id = (unsigned int)strtoul(tmp, NULL, 10); } #else /* under windows, scope is numerical */ char tmp[8]; size_t l; scope++; /* "%25" is just '%' in URL encoding */ if(scope[0] == '2' && scope[1] == '5') scope += 2; /* skip "25" */ l = p2 - scope; if(l >= sizeof(tmp)) l = sizeof(tmp) - 1; memcpy(tmp, scope, l); tmp[l] = '\0'; *scope_id = (unsigned int)strtoul(tmp, NULL, 10); #endif } p3 = strchr(p1, '/'); if(p2 && p3) { p2++; strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1))); if(*p2 == ':') { *port = 0; p2++; while( (*p2 >= '0') && (*p2 <= '9')) { *port *= 10; *port += (unsigned short)(*p2 - '0'); p2++; } } else { *port = 80; } *path = p3; return 1; } } p2 = strchr(p1, ':'); p3 = strchr(p1, '/'); if(!p3) return 0; if(!p2 || (p2>p3)) { strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p3-p1))); *port = 80; } else { strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1))); *port = 0; p2++; while( (*p2 >= '0') && (*p2 <= '9')) { *port *= 10; *port += (unsigned short)(*p2 - '0'); p2++; } } *path = p3; return 1; } void * miniwget(const char * url, int * size, unsigned int scope_id, int * status_code) { unsigned short port; char * path; /* protocol://host:port/chemin */ char hostname[MAXHOSTNAMELEN+1]; *size = 0; if(!parseURL(url, hostname, &port, &path, &scope_id)) return NULL; #ifdef DEBUG printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n", hostname, port, path, scope_id); #endif return miniwget2(hostname, port, path, size, 0, 0, scope_id, status_code); } void * miniwget_getaddr(const char * url, int * size, char * addr, int addrlen, unsigned int scope_id, int * status_code) { unsigned short port; char * path; /* protocol://host:port/path */ char hostname[MAXHOSTNAMELEN+1]; *size = 0; if(addr) addr[0] = '\0'; if(!parseURL(url, hostname, &port, &path, &scope_id)) return NULL; #ifdef DEBUG printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n", hostname, port, path, scope_id); #endif return miniwget2(hostname, port, path, size, addr, addrlen, scope_id, status_code); } miniupnpc-2.2.6/src/minixml.c010064400017500000024000000132321321374133400153170ustar00nanardstaff/* $Id: minixml.c,v 1.12 2017/12/12 11:17:40 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * minixml.c : the minimum size a xml parser can be ! */ /* Project : miniupnp * webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * Author : Thomas Bernard Copyright (c) 2005-2017, Thomas BERNARD All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 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. */ #include #include "minixml.h" /* parseatt : used to parse the argument list * return 0 (false) in case of success and -1 (true) if the end * of the xmlbuffer is reached. */ static int parseatt(struct xmlparser * p) { const char * attname; int attnamelen; const char * attvalue; int attvaluelen; while(p->xml < p->xmlend) { if(*p->xml=='/' || *p->xml=='>') return 0; if( !IS_WHITE_SPACE(*p->xml) ) { char sep; attname = p->xml; attnamelen = 0; while(*p->xml!='=' && !IS_WHITE_SPACE(*p->xml) ) { attnamelen++; p->xml++; if(p->xml >= p->xmlend) return -1; } while(*(p->xml++) != '=') { if(p->xml >= p->xmlend) return -1; } while(IS_WHITE_SPACE(*p->xml)) { p->xml++; if(p->xml >= p->xmlend) return -1; } sep = *p->xml; if(sep=='\'' || sep=='\"') { p->xml++; if(p->xml >= p->xmlend) return -1; attvalue = p->xml; attvaluelen = 0; while(*p->xml != sep) { attvaluelen++; p->xml++; if(p->xml >= p->xmlend) return -1; } } else { attvalue = p->xml; attvaluelen = 0; while( !IS_WHITE_SPACE(*p->xml) && *p->xml != '>' && *p->xml != '/') { attvaluelen++; p->xml++; if(p->xml >= p->xmlend) return -1; } } /*printf("%.*s='%.*s'\n", attnamelen, attname, attvaluelen, attvalue);*/ if(p->attfunc) p->attfunc(p->data, attname, attnamelen, attvalue, attvaluelen); } p->xml++; } return -1; } /* parseelt parse the xml stream and * call the callback functions when needed... */ static void parseelt(struct xmlparser * p) { int i; const char * elementname; while(p->xml < (p->xmlend - 1)) { if((p->xml + 4) <= p->xmlend && (0 == memcmp(p->xml, "", 3) != 0); p->xml += 3; } else if((p->xml)[0]=='<' && (p->xml)[1]!='?') { i = 0; elementname = ++p->xml; while( !IS_WHITE_SPACE(*p->xml) && (*p->xml!='>') && (*p->xml!='/') ) { i++; p->xml++; if (p->xml >= p->xmlend) return; /* to ignore namespace : */ if(*p->xml==':') { i = 0; elementname = ++p->xml; } } if(i>0) { if(p->starteltfunc) p->starteltfunc(p->data, elementname, i); if(parseatt(p)) return; if(*p->xml!='/') { const char * data; i = 0; data = ++p->xml; if (p->xml >= p->xmlend) return; while( IS_WHITE_SPACE(*p->xml) ) { i++; p->xml++; if (p->xml >= p->xmlend) return; } /* CDATA are at least 9 + 3 characters long : */ if((p->xmlend >= (p->xml + (9 + 3))) && (memcmp(p->xml, "xml += 9; data = p->xml; i = 0; while(memcmp(p->xml, "]]>", 3) != 0) { i++; p->xml++; if ((p->xml + 3) >= p->xmlend) return; } if(i>0 && p->datafunc) p->datafunc(p->data, data, i); while(*p->xml!='<') { p->xml++; if (p->xml >= p->xmlend) return; } } else { while(*p->xml!='<') { i++; p->xml++; if ((p->xml + 1) >= p->xmlend) return; } if(i>0 && p->datafunc && *(p->xml + 1) == '/') p->datafunc(p->data, data, i); } } } else if(*p->xml == '/') { i = 0; elementname = ++p->xml; if (p->xml >= p->xmlend) return; while((*p->xml != '>')) { i++; p->xml++; if (p->xml >= p->xmlend) return; } if(p->endeltfunc) p->endeltfunc(p->data, elementname, i); p->xml++; } } else { p->xml++; } } } /* the parser must be initialized before calling this function */ void parsexml(struct xmlparser * parser) { parser->xml = parser->xmlstart; parser->xmlend = parser->xmlstart + parser->xmlsize; parseelt(parser); } miniupnpc-2.2.6/src/minixml.h010064400017500000024000000022331343001453300153160ustar00nanardstaff/* $Id: minixml.h,v 1.8 2019/02/10 12:29:25 nanard Exp $ */ /* minimal xml parser * * Project : miniupnp * Website : http://miniupnp.free.fr/ * Author : Thomas Bernard * Copyright (c) 2005 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. * */ #ifndef MINIXML_H_INCLUDED #define MINIXML_H_INCLUDED #define IS_WHITE_SPACE(c) ((c)==' ' || (c)=='\t' || (c)=='\r' || (c)=='\n') /* if a callback function pointer is set to NULL, * the function is not called */ struct xmlparser { const char *xmlstart; const char *xmlend; const char *xml; /* pointer to current character */ int xmlsize; void * data; void (*starteltfunc) (void *, const char *, int); void (*endeltfunc) (void *, const char *, int); void (*datafunc) (void *, const char *, int); void (*attfunc) (void *, const char *, int, const char *, int); }; /* parsexml() * the xmlparser structure must be initialized before the call * the following structure members have to be initialized : * xmlstart, xmlsize, data, *func * xml is for internal usage, xmlend is computed automatically */ void parsexml(struct xmlparser *); #endif miniupnpc-2.2.6/src/upnpc.c010064400017500000024000000710661454537750100150120ustar00nanardstaff/* $Id: upnpc.c,v 1.137 2024/01/04 00:42:50 nanard Exp $ */ /* Project : miniupnp * Author : Thomas Bernard * Copyright (c) 2005-2024 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. */ #include #include #include #include #ifdef _WIN32 #include #include "win32_snprintf.h" #else /* for IPPROTO_TCP / IPPROTO_UDP */ #include #endif #include #include "miniwget.h" #include "miniupnpc.h" #include "upnpcommands.h" #include "portlistingparse.h" #include "upnperrors.h" #include "miniupnpcstrings.h" /* protofix() checks if protocol is "UDP" or "TCP" * returns NULL if not */ const char * protofix(const char * proto) { static const char proto_tcp[4] = { 'T', 'C', 'P', 0}; static const char proto_udp[4] = { 'U', 'D', 'P', 0}; int i, b; for(i=0, b=1; i<4; i++) b = b && ( (proto[i] == proto_tcp[i]) || (proto[i] == (proto_tcp[i] | 32)) ); if(b) return proto_tcp; for(i=0, b=1; i<4; i++) b = b && ( (proto[i] == proto_udp[i]) || (proto[i] == (proto_udp[i] | 32)) ); if(b) return proto_udp; return 0; } /* is_int() checks if parameter is an integer or not * 1 for integer * 0 for not an integer */ int is_int(char const* s) { if(s == NULL) return 0; while(*s) { /* #define isdigit(c) ((c) >= '0' && (c) <= '9') */ if(!isdigit(*s)) return 0; s++; } return 1; } static void DisplayInfos(struct UPNPUrls * urls, struct IGDdatas * data) { char externalIPAddress[40]; char connectionType[64]; char status[64]; char lastconnerr[64]; unsigned int uptime = 0; unsigned int brUp, brDown; time_t timenow, timestarted; int r; if(UPNP_GetConnectionTypeInfo(urls->controlURL, data->first.servicetype, connectionType) != UPNPCOMMAND_SUCCESS) printf("GetConnectionTypeInfo failed.\n"); else printf("Connection Type : %s\n", connectionType); if(UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype, status, &uptime, lastconnerr) != UPNPCOMMAND_SUCCESS) printf("GetStatusInfo failed.\n"); else printf("Status : %s, uptime=%us, LastConnectionError : %s\n", status, uptime, lastconnerr); if(uptime > 0) { timenow = time(NULL); timestarted = timenow - uptime; printf(" Time started : %s", ctime(×tarted)); } if(UPNP_GetLinkLayerMaxBitRates(urls->controlURL_CIF, data->CIF.servicetype, &brDown, &brUp) != UPNPCOMMAND_SUCCESS) { printf("GetLinkLayerMaxBitRates failed.\n"); } else { printf("MaxBitRateDown : %u bps", brDown); if(brDown >= 1000000) { printf(" (%u.%u Mbps)", brDown / 1000000, (brDown / 100000) % 10); } else if(brDown >= 1000) { printf(" (%u Kbps)", brDown / 1000); } printf(" MaxBitRateUp %u bps", brUp); if(brUp >= 1000000) { printf(" (%u.%u Mbps)", brUp / 1000000, (brUp / 100000) % 10); } else if(brUp >= 1000) { printf(" (%u Kbps)", brUp / 1000); } printf("\n"); } r = UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, externalIPAddress); if(r != UPNPCOMMAND_SUCCESS) { printf("GetExternalIPAddress failed. (errorcode=%d)\n", r); } else if(!externalIPAddress[0]) { printf("GetExternalIPAddress failed. (empty string)\n"); } else { printf("ExternalIPAddress = %s\n", externalIPAddress); } } static void GetConnectionStatus(struct UPNPUrls * urls, struct IGDdatas * data) { unsigned int bytessent, bytesreceived, packetsreceived, packetssent; DisplayInfos(urls, data); bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->CIF.servicetype); bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->CIF.servicetype); packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->CIF.servicetype); packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->CIF.servicetype); printf("Bytes: Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived); printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived); } static void ListRedirections(struct UPNPUrls * urls, struct IGDdatas * data) { int r; unsigned short i = 0; char index[6]; char intClient[40]; char intPort[6]; char extPort[6]; char protocol[4]; char desc[80]; char enabled[6]; char rHost[64]; char duration[16]; /*unsigned int num=0; UPNP_GetPortMappingNumberOfEntries(urls->controlURL, data->servicetype, &num); printf("PortMappingNumberOfEntries : %u\n", num);*/ printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n"); do { snprintf(index, 6, "%hu", i); rHost[0] = '\0'; enabled[0] = '\0'; duration[0] = '\0'; desc[0] = '\0'; extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0'; r = UPNP_GetGenericPortMappingEntry(urls->controlURL, data->first.servicetype, index, extPort, intClient, intPort, protocol, desc, enabled, rHost, duration); if(r==0) /* printf("%02hu - %s %s->%s:%s\tenabled=%s leaseDuration=%s\n" " desc='%s' rHost='%s'\n", i, protocol, extPort, intClient, intPort, enabled, duration, desc, rHost); */ printf("%2hu %s %5s->%s:%-5s '%s' '%s' %s\n", i, protocol, extPort, intClient, intPort, desc, rHost, duration); else printf("GetGenericPortMappingEntry() returned %d (%s)\n", r, strupnperror(r)); } while(r == 0 && i++ < 65535); } static void NewListRedirections(struct UPNPUrls * urls, struct IGDdatas * data) { int r; int i = 0; struct PortMappingParserData pdata; struct PortMapping * pm; memset(&pdata, 0, sizeof(struct PortMappingParserData)); r = UPNP_GetListOfPortMappings(urls->controlURL, data->first.servicetype, "1", "65535", "TCP", "1000", &pdata); if(r == UPNPCOMMAND_SUCCESS) { printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n"); for(pm = pdata.l_head; pm != NULL; pm = pm->l_next) { printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n", i, pm->protocol, pm->externalPort, pm->internalClient, pm->internalPort, pm->description, pm->remoteHost, (unsigned)pm->leaseTime); i++; } FreePortListing(&pdata); } else { printf("GetListOfPortMappings() returned %d (%s)\n", r, strupnperror(r)); } r = UPNP_GetListOfPortMappings(urls->controlURL, data->first.servicetype, "1", "65535", "UDP", "1000", &pdata); if(r == UPNPCOMMAND_SUCCESS) { for(pm = pdata.l_head; pm != NULL; pm = pm->l_next) { printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n", i, pm->protocol, pm->externalPort, pm->internalClient, pm->internalPort, pm->description, pm->remoteHost, (unsigned)pm->leaseTime); i++; } FreePortListing(&pdata); } else { printf("GetListOfPortMappings() returned %d (%s)\n", r, strupnperror(r)); } } /* Test function * 1 - get connection type * 2 - get extenal ip address * 3 - Add port mapping * 4 - get this port mapping from the IGD */ static int SetRedirectAndTest(struct UPNPUrls * urls, struct IGDdatas * data, const char * iaddr, const char * iport, const char * eport, const char * proto, const char * leaseDuration, const char * remoteHost, const char * description, int addAny) { char externalIPAddress[40]; char intClient[40]; char intPort[6]; char reservedPort[6]; char duration[16]; int r; if(!iaddr || !iport || !eport || !proto) { fprintf(stderr, "Wrong arguments\n"); return -1; } proto = protofix(proto); if(!proto) { fprintf(stderr, "invalid protocol\n"); return -1; } r = UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, externalIPAddress); if(r!=UPNPCOMMAND_SUCCESS) printf("GetExternalIPAddress failed.\n"); else printf("ExternalIPAddress = %s\n", externalIPAddress); if (addAny) { r = UPNP_AddAnyPortMapping(urls->controlURL, data->first.servicetype, eport, iport, iaddr, description, proto, remoteHost, leaseDuration, reservedPort); if(r==UPNPCOMMAND_SUCCESS) eport = reservedPort; else printf("AddAnyPortMapping(%s, %s, %s) failed with code %d (%s)\n", eport, iport, iaddr, r, strupnperror(r)); } else { r = UPNP_AddPortMapping(urls->controlURL, data->first.servicetype, eport, iport, iaddr, description, proto, remoteHost, leaseDuration); if(r!=UPNPCOMMAND_SUCCESS) { printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", eport, iport, iaddr, r, strupnperror(r)); return -2; } } r = UPNP_GetSpecificPortMappingEntry(urls->controlURL, data->first.servicetype, eport, proto, remoteHost, intClient, intPort, NULL/*desc*/, NULL/*enabled*/, duration); if(r!=UPNPCOMMAND_SUCCESS) { printf("GetSpecificPortMappingEntry() failed with code %d (%s)\n", r, strupnperror(r)); return -2; } else { printf("InternalIP:Port = %s:%s\n", intClient, intPort); printf("external %s:%s %s is redirected to internal %s:%s (duration=%s)\n", externalIPAddress, eport, proto, intClient, intPort, duration); } return 0; } static int RemoveRedirect(struct UPNPUrls * urls, struct IGDdatas * data, const char * eport, const char * proto, const char * remoteHost) { int r; if(!proto || !eport) { fprintf(stderr, "invalid arguments\n"); return -1; } proto = protofix(proto); if(!proto) { fprintf(stderr, "protocol invalid\n"); return -1; } r = UPNP_DeletePortMapping(urls->controlURL, data->first.servicetype, eport, proto, remoteHost); if(r!=UPNPCOMMAND_SUCCESS) { printf("UPNP_DeletePortMapping() failed with code : %d\n", r); return -2; }else { printf("UPNP_DeletePortMapping() returned : %d\n", r); } return 0; } static int RemoveRedirectRange(struct UPNPUrls * urls, struct IGDdatas * data, const char * ePortStart, char const * ePortEnd, const char * proto, const char * manage) { int r; if (!manage) manage = "0"; if(!proto || !ePortStart || !ePortEnd) { fprintf(stderr, "invalid arguments\n"); return -1; } proto = protofix(proto); if(!proto) { fprintf(stderr, "protocol invalid\n"); return -1; } r = UPNP_DeletePortMappingRange(urls->controlURL, data->first.servicetype, ePortStart, ePortEnd, proto, manage); if(r!=UPNPCOMMAND_SUCCESS) { printf("UPNP_DeletePortMappingRange() failed with code : %d\n", r); return -2; }else { printf("UPNP_DeletePortMappingRange() returned : %d\n", r); } return 0; } /* IGD:2, functions for service WANIPv6FirewallControl:1 */ static void GetFirewallStatus(struct UPNPUrls * urls, struct IGDdatas * data) { unsigned int bytessent, bytesreceived, packetsreceived, packetssent; int firewallEnabled = 0, inboundPinholeAllowed = 0; UPNP_GetFirewallStatus(urls->controlURL_6FC, data->IPv6FC.servicetype, &firewallEnabled, &inboundPinholeAllowed); printf("FirewallEnabled: %d & Inbound Pinhole Allowed: %d\n", firewallEnabled, inboundPinholeAllowed); printf("GetFirewallStatus:\n Firewall Enabled: %s\n Inbound Pinhole Allowed: %s\n", (firewallEnabled)? "Yes":"No", (inboundPinholeAllowed)? "Yes":"No"); bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->CIF.servicetype); bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->CIF.servicetype); packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->CIF.servicetype); packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->CIF.servicetype); printf("Bytes: Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived); printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived); } /* Test function * 1 - Add pinhole * 2 - Check if pinhole is working from the IGD side */ static void SetPinholeAndTest(struct UPNPUrls * urls, struct IGDdatas * data, const char * remoteaddr, const char * eport, const char * intaddr, const char * iport, const char * proto, const char * lease_time) { char uniqueID[8]; /*int isWorking = 0;*/ int r; char proto_tmp[8]; if(!intaddr || !remoteaddr || !iport || !eport || !proto || !lease_time) { fprintf(stderr, "Wrong arguments\n"); return; } if(atoi(proto) == 0) { const char * protocol; protocol = protofix(proto); if(protocol && (strcmp("TCP", protocol) == 0)) { snprintf(proto_tmp, sizeof(proto_tmp), "%d", IPPROTO_TCP); proto = proto_tmp; } else if(protocol && (strcmp("UDP", protocol) == 0)) { snprintf(proto_tmp, sizeof(proto_tmp), "%d", IPPROTO_UDP); proto = proto_tmp; } else { fprintf(stderr, "invalid protocol\n"); return; } } r = UPNP_AddPinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, lease_time, uniqueID); if(r!=UPNPCOMMAND_SUCCESS) printf("AddPinhole([%s]:%s -> [%s]:%s) failed with code %d (%s)\n", remoteaddr, eport, intaddr, iport, r, strupnperror(r)); else { printf("AddPinhole: ([%s]:%s -> [%s]:%s) / Pinhole ID = %s\n", remoteaddr, eport, intaddr, iport, uniqueID); /*r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->servicetype_6FC, uniqueID, &isWorking); if(r!=UPNPCOMMAND_SUCCESS) printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r)); printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");*/ } } /* Test function * 1 - Check if pinhole is working from the IGD side * 2 - Update pinhole */ static void GetPinholeAndUpdate(struct UPNPUrls * urls, struct IGDdatas * data, const char * uniqueID, const char * lease_time) { int isWorking = 0; int r; if(!uniqueID || !lease_time) { fprintf(stderr, "Wrong arguments\n"); return; } /* CheckPinholeWorking is an Optional Action, error 602 should be * returned if it is not implemented */ r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking); if(r==UPNPCOMMAND_SUCCESS) printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No"); else printf("CheckPinholeWorking(%s) failed with code %d (%s)\n", uniqueID, r, strupnperror(r)); /* 702 FirewallDisabled Firewall is disabled and this action is disabled * 703 InboundPinholeNotAllowed Creation of inbound pinholes by UPnP CPs * are not allowed and this action is disabled * 704 NoSuchEntry There is no pinhole with the specified UniqueID. * 709 NoTrafficReceived No traffic corresponding to this pinhole has * been received by the gateway. */ if(isWorking || (r!=702 && r!=703 && r!=704)) { r = UPNP_UpdatePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, lease_time); printf("UpdatePinhole: Pinhole ID = %s with Lease Time: %s\n", uniqueID, lease_time); if(r!=UPNPCOMMAND_SUCCESS) printf("UpdatePinhole: ID (%s) failed with code %d (%s)\n", uniqueID, r, strupnperror(r)); } } /* Test function * Get pinhole timeout */ static void GetPinholeOutboundTimeout(struct UPNPUrls * urls, struct IGDdatas * data, const char * remoteaddr, const char * eport, const char * intaddr, const char * iport, const char * proto) { int timeout = 0; int r; if(!intaddr || !remoteaddr || !iport || !eport || !proto) { fprintf(stderr, "Wrong arguments\n"); return; } r = UPNP_GetOutboundPinholeTimeout(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, &timeout); if(r!=UPNPCOMMAND_SUCCESS) printf("GetOutboundPinholeTimeout([%s]:%s -> [%s]:%s) failed with code %d (%s)\n", intaddr, iport, remoteaddr, eport, r, strupnperror(r)); else printf("GetOutboundPinholeTimeout: ([%s]:%s -> [%s]:%s) / Timeout = %d\n", intaddr, iport, remoteaddr, eport, timeout); } static void GetPinholePackets(struct UPNPUrls * urls, struct IGDdatas * data, const char * uniqueID) { int r, pinholePackets = 0; if(!uniqueID) { fprintf(stderr, "invalid arguments\n"); return; } r = UPNP_GetPinholePackets(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &pinholePackets); if(r!=UPNPCOMMAND_SUCCESS) printf("GetPinholePackets() failed with code %d (%s)\n", r, strupnperror(r)); else printf("GetPinholePackets: Pinhole ID = %s / PinholePackets = %d\n", uniqueID, pinholePackets); } static void CheckPinhole(struct UPNPUrls * urls, struct IGDdatas * data, const char * uniqueID) { int r, isWorking = 0; if(!uniqueID) { fprintf(stderr, "invalid arguments\n"); return; } r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking); if(r!=UPNPCOMMAND_SUCCESS) printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r)); else printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No"); } static void RemovePinhole(struct UPNPUrls * urls, struct IGDdatas * data, const char * uniqueID) { int r; if(!uniqueID) { fprintf(stderr, "invalid arguments\n"); return; } r = UPNP_DeletePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID); printf("UPNP_DeletePinhole() returned : %d\n", r); } /* sample upnp client program */ int main(int argc, char ** argv) { char command = 0; char ** commandargv = 0; int commandargc = 0; struct UPNPDev * devlist = 0; char lanaddr[64] = "unset"; /* my ip address on the LAN */ int i; const char * rootdescurl = 0; const char * multicastif = 0; const char * minissdpdpath = 0; int localport = UPNP_LOCAL_PORT_ANY; int retcode = 0; int error = 0; int ipv6 = 0; int ignore = 0; unsigned char ttl = 2; /* defaulting to 2 */ const char * description = 0; #ifdef _WIN32 WSADATA wsaData; int nResult = WSAStartup(MAKEWORD(2,2), &wsaData); if(nResult != NO_ERROR) { fprintf(stderr, "WSAStartup() failed.\n"); return -1; } #endif printf("upnpc : miniupnpc library test client, version %s.\n", MINIUPNPC_VERSION_STRING); printf(" (c) 2005-2024 Thomas Bernard.\n"); printf("Go to http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/\n" "for more information.\n"); /* command line processing */ for(i=1; i65535 || (localport >1 && localport < 1024)) { fprintf(stderr, "Invalid localport '%s'\n", argv[i]); localport = UPNP_LOCAL_PORT_ANY; break; } } else if(argv[i][1] == 'p') minissdpdpath = argv[++i]; else if(argv[i][1] == '6') ipv6 = 1; else if(argv[i][1] == 'e') description = argv[++i]; else if(argv[i][1] == 't') ttl = (unsigned char)atoi(argv[++i]); else if(argv[i][1] == 'i') ignore = 1; else { command = argv[i][1]; i++; commandargv = argv + i; commandargc = argc - i; break; } } else { fprintf(stderr, "option '%s' invalid\n", argv[i]); } } if(!command || (command == 'a' && commandargc<4) || (command == 'd' && argc<2) || (command == 'r' && argc<2) || (command == 'A' && commandargc<6) || (command == 'U' && commandargc<2) || (command == 'D' && commandargc<1)) { fprintf(stderr, "Usage :\t%s [options] -a ip port external_port protocol [duration] [remote host]\n\t\tAdd port mapping\n", argv[0]); fprintf(stderr, " \t%s [options] -r port1 [external_port1] protocol1 [port2 [external_port2] protocol2] [...]\n\t\tAdd multiple port mappings to the current host\n", argv[0]); fprintf(stderr, " \t%s [options] -d external_port protocol [remote host]\n\t\tDelete port redirection\n", argv[0]); fprintf(stderr, " \t%s [options] -s\n\t\tGet Connection status\n", argv[0]); fprintf(stderr, " \t%s [options] -l\n\t\tList redirections\n", argv[0]); fprintf(stderr, " \t%s [options] -L\n\t\tList redirections (using GetListOfPortMappings (for IGD:2 only)\n", argv[0]); fprintf(stderr, " \t%s [options] -n ip port external_port protocol [duration] [remote host]\n\t\tAdd (any) port mapping allowing IGD to use alternative external_port (for IGD:2 only)\n", argv[0]); fprintf(stderr, " \t%s [options] -N external_port_start external_port_end protocol [manage]\n\t\tDelete range of port mappings (for IGD:2 only)\n", argv[0]); fprintf(stderr, " \t%s [options] -A remote_ip remote_port internal_ip internal_port protocol lease_time\n\t\tAdd Pinhole (for IGD:2 only)\n", argv[0]); fprintf(stderr, " \t%s [options] -U uniqueID new_lease_time\n\t\tUpdate Pinhole (for IGD:2 only)\n", argv[0]); fprintf(stderr, " \t%s [options] -C uniqueID\n\t\tCheck if Pinhole is Working (for IGD:2 only)\n", argv[0]); fprintf(stderr, " \t%s [options] -K uniqueID\n\t\tGet Number of packets going through the rule (for IGD:2 only)\n", argv[0]); fprintf(stderr, " \t%s [options] -D uniqueID\n\t\tDelete Pinhole (for IGD:2 only)\n", argv[0]); fprintf(stderr, " \t%s [options] -S\n\t\tGet Firewall status (for IGD:2 only)\n", argv[0]); fprintf(stderr, " \t%s [options] -G remote_ip remote_port internal_ip internal_port protocol\n\t\tGet Outbound Pinhole Timeout (for IGD:2 only)\n", argv[0]); fprintf(stderr, " \t%s [options] -P\n\t\tGet Presentation URL\n", argv[0]); fprintf(stderr, "\nprotocol is UDP or TCP\n"); fprintf(stderr, "@ can be used in option -a, -n, -A and -G to represent local LAN address.\n"); fprintf(stderr, "Options:\n"); fprintf(stderr, " -e description : set description for port mapping.\n"); fprintf(stderr, " -6 : use IPv6 instead of IPv4.\n"); fprintf(stderr, " -u URL : bypass discovery process by providing the XML root description URL.\n"); fprintf(stderr, " -m address/interface : provide IPv4 address or interface name (IPv4 or IPv6) 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"); fprintf(stderr, " -i : ignore errors and try to use also disconnected IGD or non-IGD device.\n"); return 1; } if( rootdescurl || (devlist = upnpDiscover(2000, multicastif, minissdpdpath, localport, ipv6, ttl, &error))) { struct UPNPDev * device; struct UPNPUrls urls; struct IGDdatas data; if(devlist) { printf("List of UPNP devices found on the network :\n"); for(device = devlist; device; device = device->pNext) { printf(" desc: %s\n st: %s\n\n", device->descURL, device->st); } } else if(!rootdescurl) { printf("upnpDiscover() error code=%d\n", error); } i = 1; if( (rootdescurl && UPNP_GetIGDFromUrl(rootdescurl, &urls, &data, lanaddr, sizeof(lanaddr))) || (i = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)))) { switch(i) { case 1: printf("Found valid IGD : %s\n", urls.controlURL); break; case 2: printf("Found a (not connected?) IGD : %s\n", urls.controlURL); if (ignore) printf("Trying to continue anyway\n"); break; case 3: printf("UPnP device found. Is it an IGD ? : %s\n", urls.controlURL); if (ignore) printf("Trying to continue anyway\n"); break; default: printf("Found device (igd ?) : %s\n", urls.controlURL); if (ignore) printf("Trying to continue anyway\n"); } if(i==1 || ignore) { printf("Local LAN ip address : %s\n", lanaddr); #if 0 printf("getting \"%s\"\n", urls.ipcondescURL); descXML = miniwget(urls.ipcondescURL, &descXMLsize); if(descXML) { /*fwrite(descXML, 1, descXMLsize, stdout);*/ free(descXML); descXML = NULL; } #endif /* replace '@' with the local LAN ip address */ if ((command == 'a' || command == 'n') && 0 == strcmp(commandargv[0], "@")) commandargv[0] = lanaddr; else if ((command == 'A' || command == 'G') && 0 == strcmp(commandargv[2], "@")) commandargv[2] = lanaddr; switch(command) { case 'l': DisplayInfos(&urls, &data); ListRedirections(&urls, &data); break; case 'L': NewListRedirections(&urls, &data); break; case 'a': if (SetRedirectAndTest(&urls, &data, commandargv[0], commandargv[1], commandargv[2], commandargv[3], (commandargc > 4) && is_int(commandargv[4]) ? commandargv[4] : "0", (commandargc > 4) && !is_int(commandargv[4]) ? commandargv[4] : (commandargc > 5) ? commandargv[5] : NULL, description, 0) < 0) retcode = 2; break; case 'd': if (RemoveRedirect(&urls, &data, commandargv[0], commandargv[1], commandargc > 2 ? commandargv[2] : NULL) < 0) retcode = 2; break; case 'n': /* aNy */ if (SetRedirectAndTest(&urls, &data, commandargv[0], commandargv[1], commandargv[2], commandargv[3], (commandargc > 4) && is_int(commandargv[4]) ? commandargv[4] : "0", (commandargc > 4) && !is_int(commandargv[4]) ? commandargv[4] : (commandargc > 5) ? commandargv[5] : NULL, description, 1) < 0) retcode = 2; break; case 'N': if (commandargc < 3) fprintf(stderr, "too few arguments\n"); if (RemoveRedirectRange(&urls, &data, commandargv[0], commandargv[1], commandargv[2], commandargc > 3 ? commandargv[3] : NULL) < 0) retcode = 2; break; case 's': GetConnectionStatus(&urls, &data); break; case 'r': i = 0; while(i */ if (SetRedirectAndTest(&urls, &data, lanaddr, commandargv[i], commandargv[i+1], commandargv[i+2], "0", NULL, description, 0) < 0) retcode = 2; i+=3; /* 3 parameters parsed */ } else { /* 2nd parameter not an integer : */ if (SetRedirectAndTest(&urls, &data, lanaddr, commandargv[i], commandargv[i], commandargv[i+1], "0", NULL, description, 0) < 0) retcode = 2; i+=2; /* 2 parameters parsed */ } } break; case 'A': SetPinholeAndTest(&urls, &data, commandargv[0], commandargv[1], commandargv[2], commandargv[3], commandargv[4], commandargv[5]); break; case 'U': GetPinholeAndUpdate(&urls, &data, commandargv[0], commandargv[1]); break; case 'C': for(i=0; i #include #include #include "minixml.h" #include "igd_desc_parse.h" /* ---------------------------------------------------------------------- */ void printeltname1(void * d, const char * name, int l) { int i; (void)d; printf("element "); for(i=0;i #include #ifdef _WIN32 #include #include #include "win32_snprintf.h" #else #include #include #include #endif #include "minisoap.h" #include "miniupnpcstrings.h" /* only for malloc */ #include /* httpWrite sends the headers and the body to the socket * and returns the number of bytes sent */ static int httpWrite(SOCKET fd, const char * body, int bodysize, const char * headers, int headerssize) { int n = 0; /*n = write(fd, headers, headerssize);*/ /*if(bodysize>0) n += write(fd, body, bodysize);*/ /* Note : my old linksys router only took into account * soap request that are sent into only one packet */ char * p; /* TODO: AVOID MALLOC, we could use writev() for that */ p = malloc(headerssize+bodysize); if(!p) return -1; memcpy(p, headers, headerssize); memcpy(p+headerssize, body, bodysize); /*n = write(fd, p, headerssize+bodysize);*/ n = send(fd, p, headerssize+bodysize, 0); if(n<0) { PRINT_SOCKET_ERROR("send"); } /* disable send on the socket */ /* draytek routers don't seem to like that... */ #if 0 #ifdef _WIN32 if(shutdown(fd, SD_SEND)<0) { #else if(shutdown(fd, SHUT_WR)<0) { /*SD_SEND*/ #endif PRINT_SOCKET_ERROR("shutdown"); } #endif free(p); return n; } /* self explanatory */ int soapPostSubmit(SOCKET fd, const char * url, const char * host, unsigned short port, const char * action, const char * body, const char * httpversion) { char headerbuf[512]; int headerssize; char portstr[8]; int bodysize = (int)strlen(body); /* We are not using keep-alive HTTP connections. * HTTP/1.1 needs the header Connection: close to do that. * This is the default with HTTP/1.0 * Using HTTP/1.1 means we need to support chunked transfer-encoding : * When using HTTP/1.1, the router "BiPAC 7404VNOX" always use chunked * transfer encoding. */ /* Connection: Close is normally there only in HTTP/1.1 but who knows */ portstr[0] = '\0'; if(port != 80) snprintf(portstr, sizeof(portstr), ":%hu", port); headerssize = snprintf(headerbuf, sizeof(headerbuf), "POST %s HTTP/%s\r\n" "Host: %s%s\r\n" "User-Agent: " OS_STRING " " UPNP_VERSION_STRING " MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n" "Content-Length: %d\r\n" #if (UPNP_VERSION_MAJOR == 1) && (UPNP_VERSION_MINOR == 0) "Content-Type: text/xml\r\n" #else "Content-Type: text/xml; charset=\"utf-8\"\r\n" #endif "SOAPAction: \"%s\"\r\n" "Connection: Close\r\n" "Cache-Control: no-cache\r\n" /* ??? */ "Pragma: no-cache\r\n" "\r\n", url, httpversion, host, portstr, bodysize, action); if ((unsigned int)headerssize >= sizeof(headerbuf)) return -1; #ifdef DEBUG /*printf("SOAP request : headersize=%d bodysize=%d\n", headerssize, bodysize); */ printf("SOAP request : POST %s HTTP/%s - Host: %s%s\n", url, httpversion, host, portstr); printf("SOAPAction: \"%s\" - Content-Length: %d\n", action, bodysize); printf("Headers :\n%s", headerbuf); printf("Body :\n%s\n", body); #endif return httpWrite(fd, body, bodysize, headerbuf, headerssize); } miniupnpc-2.2.6/src/minisoap.h010064400017500000024000000010341326165065200154700ustar00nanardstaff/* $Id: minisoap.h,v 1.6 2018/04/06 10:53:13 nanard Exp $ */ /* Project : miniupnp * Author : Thomas Bernard * Copyright (c) 2005-2018 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. */ #ifndef MINISOAP_H_INCLUDED #define MINISOAP_H_INCLUDED #include "miniupnpc_socketdef.h" /*int httpWrite(int, const char *, int, const char *);*/ int soapPostSubmit(SOCKET, const char *, const char *, unsigned short, const char *, const char *, const char *); #endif miniupnpc-2.2.6/src/miniupnpc.c010064400017500000024000000475611401754661000156630ustar00nanardstaff/* $Id: miniupnpc.c,v 1.159 2021/03/02 23:36:32 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * Project : miniupnp * Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * Author : Thomas BERNARD * copyright (c) 2005-2021 Thomas Bernard * This software is subjet to the conditions detailed in the * provided LICENSE file. */ #include #include #include #ifdef _WIN32 /* Win32 Specific includes and defines */ #include #include #include #include #include "win32_snprintf.h" #define strdup _strdup #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 */ #define MAXHOSTNAMELEN 64 #else /* #ifdef _WIN32 */ /* Standard POSIX includes */ #include #if defined(__amigaos__) && !defined(__amigaos4__) /* Amiga OS 3 specific stuff */ #define socklen_t int #else #include #endif #include #include #include #include #include #include #include #if !defined(__amigaos__) && !defined(__amigaos4__) #include #endif #include #include #define closesocket close #endif /* #else _WIN32 */ #ifdef __GNU__ #define MAXHOSTNAMELEN 64 #endif #include "miniupnpc.h" #include "minissdpc.h" #include "miniwget.h" #include "miniwget_private.h" #include "minisoap.h" #include "minixml.h" #include "upnpcommands.h" #include "connecthostport.h" #include "addr_is_reserved.h" /* compare the beginning of a string with a constant string */ #define COMPARE(str, cstr) (0==strncmp(str, cstr, sizeof(cstr) - 1)) #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif #define SOAPPREFIX "s" #define SERVICEPREFIX "u" #define SERVICEPREFIX2 'u' /* root description parsing */ MINIUPNP_LIBSPEC void parserootdesc(const char * buffer, int bufsize, struct IGDdatas * data) { struct xmlparser parser; /* xmlparser object */ parser.xmlstart = buffer; parser.xmlsize = bufsize; parser.data = data; parser.starteltfunc = IGDstartelt; parser.endeltfunc = IGDendelt; parser.datafunc = IGDdata; parser.attfunc = 0; parsexml(&parser); #ifdef DEBUG printIGD(data); #endif } /* simpleUPnPcommand2 : * not so simple ! * return values : * pointer - OK * NULL - error */ static char * simpleUPnPcommand2(SOCKET s, const char * url, const char * service, const char * action, struct UPNParg * args, int * bufsize, const char * httpversion) { char hostname[MAXHOSTNAMELEN+1]; unsigned short port = 0; char * path; char soapact[128]; char soapbody[2048]; int soapbodylen; char * buf; int n; int status_code; *bufsize = 0; snprintf(soapact, sizeof(soapact), "%s#%s", service, action); if(args==NULL) { soapbodylen = snprintf(soapbody, sizeof(soapbody), "\r\n" "<" SOAPPREFIX ":Envelope " "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" " SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" "<" SOAPPREFIX ":Body>" "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">" "" "" "\r\n", action, service, action); if ((unsigned int)soapbodylen >= sizeof(soapbody)) return NULL; } else { char * p; const char * pe, * pv; const char * const pend = soapbody + sizeof(soapbody); soapbodylen = snprintf(soapbody, sizeof(soapbody), "\r\n" "<" SOAPPREFIX ":Envelope " "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" " SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" "<" SOAPPREFIX ":Body>" "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">", action, service); if ((unsigned int)soapbodylen >= sizeof(soapbody)) return NULL; p = soapbody + soapbodylen; while(args->elt) { if(p >= pend) /* check for space to write next byte */ return NULL; *(p++) = '<'; pe = args->elt; while(p < pend && *pe) *(p++) = *(pe++); if(p >= pend) /* check for space to write next byte */ return NULL; *(p++) = '>'; if((pv = args->val)) { while(p < pend && *pv) *(p++) = *(pv++); } if((p+2) > pend) /* check for space to write next 2 bytes */ return NULL; *(p++) = '<'; *(p++) = '/'; pe = args->elt; while(p < pend && *pe) *(p++) = *(pe++); if(p >= pend) /* check for space to write next byte */ return NULL; *(p++) = '>'; args++; } if((p+4) > pend) /* check for space to write next 4 bytes */ return NULL; *(p++) = '<'; *(p++) = '/'; *(p++) = SERVICEPREFIX2; *(p++) = ':'; pe = action; while(p < pend && *pe) *(p++) = *(pe++); strncpy(p, ">\r\n", pend - p); if(soapbody[sizeof(soapbody)-1]) /* strncpy pads buffer with 0s, so if it doesn't end in 0, could not fit full string */ return NULL; } if(!parseURL(url, hostname, &port, &path, NULL)) return NULL; if(ISINVALID(s)) { s = connecthostport(hostname, port, 0); if(ISINVALID(s)) { /* failed to connect */ return NULL; } } n = soapPostSubmit(s, path, hostname, port, soapact, soapbody, httpversion); if(n<=0) { #ifdef DEBUG printf("Error sending SOAP request\n"); #endif closesocket(s); return NULL; } buf = getHTTPResponse(s, bufsize, &status_code); #ifdef DEBUG if(*bufsize > 0 && buf) { printf("HTTP %d SOAP Response :\n%.*s\n", status_code, *bufsize, buf); } else { printf("HTTP %d, empty SOAP response. size=%d\n", status_code, *bufsize); } #endif closesocket(s); return buf; } /* simpleUPnPcommand : * not so simple ! * return values : * pointer - OK * NULL - error */ char * simpleUPnPcommand(int s, const char * url, const char * service, const char * action, struct UPNParg * args, int * bufsize) { char * buf; #if 1 buf = simpleUPnPcommand2((SOCKET)s, url, service, action, args, bufsize, "1.1"); #else buf = simpleUPnPcommand2((SOCKET)s, url, service, action, args, bufsize, "1.0"); if (!buf || *bufsize == 0) { #if DEBUG printf("Error or no result from SOAP request; retrying with HTTP/1.1\n"); #endif buf = simpleUPnPcommand2((SOCKET)s, url, service, action, args, bufsize, "1.1"); } #endif return buf; } /* 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). * 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, unsigned char ttl, int * error, int searchalltypes) { struct UPNPDev * tmp; struct UPNPDev * devlist = 0; #if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) int deviceIndex; #endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */ 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"; if(minissdpdsock[0] != '\0') { 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(!strstr(tmp->st, "rootdevice")) { if(error) *error = UPNPDISCOVER_SUCCESS; return devlist; } } #else /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */ (void)minissdpdsock; /* unused */ #endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */ /* direct discovery if minissdpd responses are not sufficient */ { 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; } } return devlist; } /* upnpDiscover() Discover IGD device */ MINIUPNP_LIBSPEC struct UPNPDev * upnpDiscover(int delay, const char * multicastif, const char * minissdpdsock, int localport, int ipv6, unsigned char ttl, int * error) { static const char * const deviceList[] = { #if 0 "urn:schemas-upnp-org:device:InternetGatewayDevice:2", "urn:schemas-upnp-org:service:WANIPConnection:2", #endif "urn:schemas-upnp-org:device:InternetGatewayDevice:1", "urn:schemas-upnp-org:service:WANIPConnection:1", "urn:schemas-upnp-org:service:WANPPPConnection:1", "upnp:rootdevice", /*"ssdp:all",*/ 0 }; return upnpDiscoverDevices(deviceList, delay, multicastif, minissdpdsock, localport, 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, unsigned char ttl, int * error) { static const char * const deviceList[] = { /*"upnp:rootdevice",*/ "ssdp:all", 0 }; return upnpDiscoverDevices(deviceList, delay, multicastif, minissdpdsock, localport, 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, unsigned char ttl, int * error) { const char * const deviceList[] = { device, 0 }; return upnpDiscoverDevices(deviceList, delay, multicastif, minissdpdsock, localport, ipv6, ttl, error, 0); } static char * build_absolute_url(const char * baseurl, const char * descURL, const char * url, unsigned int scope_id) { size_t l, n; char * s; const char * base; char * p; #if defined(IF_NAMESIZE) && !defined(_WIN32) char ifname[IF_NAMESIZE]; #else /* defined(IF_NAMESIZE) && !defined(_WIN32) */ char scope_str[8]; #endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */ if( (url[0] == 'h') &&(url[1] == 't') &&(url[2] == 't') &&(url[3] == 'p') &&(url[4] == ':') &&(url[5] == '/') &&(url[6] == '/')) return strdup(url); base = (baseurl[0] == '\0') ? descURL : baseurl; n = strlen(base); if(n > 7) { p = strchr(base + 7, '/'); if(p) n = p - base; } l = n + strlen(url) + 1; if(url[0] != '/') l++; if(scope_id != 0) { #if defined(IF_NAMESIZE) && !defined(_WIN32) if(if_indextoname(scope_id, ifname)) { l += 3 + strlen(ifname); /* 3 == strlen(%25) */ } #else /* defined(IF_NAMESIZE) && !defined(_WIN32) */ /* under windows, scope is numerical */ l += 3 + snprintf(scope_str, sizeof(scope_str), "%u", scope_id); #endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */ } s = malloc(l); if(s == NULL) return NULL; memcpy(s, base, n); if(scope_id != 0) { s[n] = '\0'; if(n > 13 && 0 == memcmp(s, "http://[fe80:", 13)) { /* this is a linklocal IPv6 address */ p = strchr(s, ']'); if(p) { /* insert %25 into URL */ #if defined(IF_NAMESIZE) && !defined(_WIN32) memmove(p + 3 + strlen(ifname), p, strlen(p) + 1); memcpy(p, "%25", 3); memcpy(p + 3, ifname, strlen(ifname)); n += 3 + strlen(ifname); #else /* defined(IF_NAMESIZE) && !defined(_WIN32) */ memmove(p + 3 + strlen(scope_str), p, strlen(p) + 1); memcpy(p, "%25", 3); memcpy(p + 3, scope_str, strlen(scope_str)); n += 3 + strlen(scope_str); #endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */ } } } if(url[0] != '/') s[n++] = '/'; memcpy(s + n, url, l - n); return s; } /* Prepare the Urls for usage... */ MINIUPNP_LIBSPEC void GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data, const char * descURL, unsigned int scope_id) { /* strdup descURL */ urls->rootdescURL = strdup(descURL); /* get description of WANIPConnection */ urls->ipcondescURL = build_absolute_url(data->urlbase, descURL, data->first.scpdurl, scope_id); urls->controlURL = build_absolute_url(data->urlbase, descURL, data->first.controlurl, scope_id); urls->controlURL_CIF = build_absolute_url(data->urlbase, descURL, data->CIF.controlurl, scope_id); urls->controlURL_6FC = build_absolute_url(data->urlbase, descURL, data->IPv6FC.controlurl, scope_id); #ifdef DEBUG printf("urls->ipcondescURL='%s'\n", urls->ipcondescURL); printf("urls->controlURL='%s'\n", urls->controlURL); printf("urls->controlURL_CIF='%s'\n", urls->controlURL_CIF); printf("urls->controlURL_6FC='%s'\n", urls->controlURL_6FC); #endif } MINIUPNP_LIBSPEC void FreeUPNPUrls(struct UPNPUrls * urls) { if(!urls) return; free(urls->controlURL); urls->controlURL = 0; free(urls->ipcondescURL); urls->ipcondescURL = 0; free(urls->controlURL_CIF); urls->controlURL_CIF = 0; free(urls->controlURL_6FC); urls->controlURL_6FC = 0; free(urls->rootdescURL); urls->rootdescURL = 0; } int UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data) { char status[64]; unsigned int uptime; status[0] = '\0'; 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; } /* UPNP_GetValidIGD() : * return values : * -1 = Internal error * 0 = NO IGD found * 1 = A valid connected IGD has been found * 2 = A valid IGD has been found but it reported as * not connected * 3 = an UPnP device has been found but was not recognized as an IGD * * In any positive non zero return case, the urls and data structures * passed as parameters are set. Don't forget to call FreeUPNPUrls(urls) to * free allocated memory. */ MINIUPNP_LIBSPEC int UPNP_GetValidIGD(struct UPNPDev * devlist, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen) { struct xml_desc { char lanaddr[40]; char * xml; int size; int is_igd; } * desc = NULL; struct UPNPDev * dev; int ndev = 0; int i; int state = -1; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */ char extIpAddr[16]; int status_code = -1; if(!devlist) { #ifdef DEBUG printf("Empty devlist\n"); #endif return 0; } /* counting total number of devices in the list */ for(dev = devlist; dev; dev = dev->pNext) ndev++; /* ndev is always > 0 */ desc = calloc(ndev, sizeof(struct xml_desc)); if(!desc) return -1; /* memory allocation error */ /* Step 1 : downloading descriptions and testing type */ for(dev = devlist, i = 0; dev; dev = dev->pNext, i++) { /* we should choose an internet gateway device. * with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */ desc[i].xml = miniwget_getaddr(dev->descURL, &(desc[i].size), desc[i].lanaddr, sizeof(desc[i].lanaddr), dev->scope_id, &status_code); #ifdef DEBUG if(!desc[i].xml) { printf("error getting XML description %s\n", dev->descURL); } #endif if(desc[i].xml) { memset(data, 0, sizeof(struct IGDdatas)); memset(urls, 0, sizeof(struct UPNPUrls)); parserootdesc(desc[i].xml, desc[i].size, data); if(COMPARE(data->CIF.servicetype, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:")) { desc[i].is_igd = 1; } } } /* iterate the list to find a device depending on state */ for(state = 1; state <= 3; state++) { for(dev = devlist, i = 0; dev; dev = dev->pNext, i++) { if(desc[i].xml) { memset(data, 0, sizeof(struct IGDdatas)); memset(urls, 0, sizeof(struct UPNPUrls)); parserootdesc(desc[i].xml, desc[i].size, data); if(desc[i].is_igd || state >= 3 ) { int is_connected; GetUPNPUrls(urls, data, dev->descURL, dev->scope_id); /* in state 2 and 3 we don't test if device is connected ! */ if(state >= 2) goto free_and_return; is_connected = UPNPIGD_IsConnected(urls, data); #ifdef DEBUG printf("UPNPIGD_IsConnected(%s) = %d\n", urls->controlURL, is_connected); #endif /* checks that status is connected AND there is a external IP address assigned */ if(is_connected && (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) { if(!addr_is_reserved(extIpAddr)) goto free_and_return; } FreeUPNPUrls(urls); if(data->second.servicetype[0] != '\0') { #ifdef DEBUG printf("We tried %s, now we try %s !\n", data->first.servicetype, data->second.servicetype); #endif /* swaping WANPPPConnection and WANIPConnection ! */ memcpy(&data->tmp, &data->first, sizeof(struct IGDdatas_service)); memcpy(&data->first, &data->second, sizeof(struct IGDdatas_service)); memcpy(&data->second, &data->tmp, sizeof(struct IGDdatas_service)); GetUPNPUrls(urls, data, dev->descURL, dev->scope_id); is_connected = UPNPIGD_IsConnected(urls, data); #ifdef DEBUG printf("UPNPIGD_IsConnected(%s) = %d\n", urls->controlURL, is_connected); #endif if(is_connected && (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) { if(!addr_is_reserved(extIpAddr)) goto free_and_return; } FreeUPNPUrls(urls); } } memset(data, 0, sizeof(struct IGDdatas)); } } } state = 0; free_and_return: if (lanaddr != NULL && state >= 1 && state <= 3 && i < ndev) strncpy(lanaddr, desc[i].lanaddr, lanaddrlen); for(i = 0; i < ndev; i++) free(desc[i].xml); free(desc); return state; } /* UPNP_GetIGDFromUrl() * Used when skipping the discovery process. * return value : * 0 - Not ok * 1 - OK */ int UPNP_GetIGDFromUrl(const char * rootdescurl, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen) { char * descXML; int descXMLsize = 0; descXML = miniwget_getaddr(rootdescurl, &descXMLsize, lanaddr, lanaddrlen, 0, NULL); if(descXML) { memset(data, 0, sizeof(struct IGDdatas)); memset(urls, 0, sizeof(struct UPNPUrls)); parserootdesc(descXML, descXMLsize, data); free(descXML); GetUPNPUrls(urls, data, rootdescurl, 0); return 1; } else { return 0; } } miniupnpc-2.2.6/README010064400017500000024000000066121437357071700136100ustar00nanardstaffProject: miniupnp Project web page: http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ github: https://github.com/miniupnp/miniupnp Author: Thomas Bernard Copyright (c) 2005-2023 Thomas Bernard This software is subject to the conditions detailed in the LICENSE file provided within this distribution. * miniUPnP Client - miniUPnPc * To compile, simply run 'gmake' (could be 'make' on your system). Under win32, to compile with MinGW, type "mingw32make.bat". MS Visual C solution and project files are supplied in the msvc/ subdirectory. The miniupnpc library is available as a static library or as a DLL : define MINIUPNP_STATICLIB if you want to link against the static library. The compilation is known to work under linux, FreeBSD, OpenBSD, MacOS X, AmigaOS and cygwin. The official AmigaOS4.1 SDK was used for AmigaOS4 and GeekGadgets for AmigaOS3. upx (http://upx.sourceforge.net) is used to compress the win32 .exe files. To install the library and headers on the system use : > su > make install > exit alternatively, to install into a specific location, use : > INSTALLPREFIX=/usr/local make install upnpc.c is a sample client using the libminiupnpc. To use the libminiupnpc in your application, link it with libminiupnpc.a (or .so) and use the following functions found in miniupnpc.h, upnpcommands.h and miniwget.h : - upnpDiscover() - UPNP_GetValidIGD() - miniwget() - parserootdesc() - GetUPNPUrls() - UPNP_* (calling UPNP methods) Note : use #include etc... for the includes and -lminiupnpc for the link Discovery process is speeded up when MiniSSDPd is running on the machine. * Python module * you can build a python module with 'make pythonmodule' and install it with 'make installpythonmodule'. setup.py (and setupmingw32.py) are included in the distribution. Feel free to contact me if you have any problem : e-mail : miniupnp@free.fr If you are using libminiupnpc in your application, please send me an email ! For any question, you can use the web forum : https://miniupnp.tuxfamily.org/forum/ Bugs should be reported on GitHub : https://github.com/miniupnp/miniupnp/issues * Linux firewall configuration for UPnP clients * Due to how UPnP protocol is designed, unicast responses to UPnP multicast client requests are not tracked by Linux netfilter. And therefore netfilter executes default action for them (which is in most cases DROP response packet). To workaround this limitation, custom ipset hash table can be used. It is supported since Linux kernel >= 2.6.39. Rules for IPv4: $ ipset create upnp hash:ip,port timeout 3 $ iptables -A OUTPUT -d 239.255.255.250/32 -p udp -m udp --dport 1900 -j SET --add-set upnp src,src --exist $ iptables -A INPUT -p udp -m set --match-set upnp dst,dst -j ACCEPT $ iptables -A INPUT -d 239.255.255.250/32 -p udp -m udp --dport 1900 -j ACCEPT Rules for IPv6: $ ipset create upnp6 hash:ip,port timeout 3 family inet6 $ ip6tables -A OUTPUT -d ff02::c/128 -p udp -m udp --dport 1900 -j SET --add-set upnp6 src,src --exist $ ip6tables -A OUTPUT -d ff05::c/128 -p udp -m udp --dport 1900 -j SET --add-set upnp6 src,src --exist $ ip6tables -A INPUT -p udp -m set --match-set upnp6 dst,dst -j ACCEPT $ ip6tables -A INPUT -d ff02::c/128 -p udp -m udp --dport 1900 -j ACCEPT $ ip6tables -A INPUT -d ff05::c/128 -p udp -m udp --dport 1900 -j ACCEPT Detailed description is available on: https://serverfault.com/a/911286 https://unix.stackexchange.com/a/444804 miniupnpc-2.2.6/LICENSE010064400017500000024000000027671437357071700137440ustar00nanardstaffBSD 3-Clause License Copyright (c) 2005-2023, Thomas BERNARD All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 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. miniupnpc-2.2.6/src/upnpcommands.c010064400017500000024000001045331346201452000163470ustar00nanardstaff/* $Id: upnpcommands.c,v 1.51 2019/04/23 11:45:15 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * Project : miniupnp * Author : Thomas Bernard * Copyright (c) 2005-2018 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. * */ #include #include #include #include "upnpcommands.h" #include "miniupnpc.h" #include "portlistingparse.h" #include "upnpreplyparse.h" static UNSIGNED_INTEGER my_atoui(const char * s) { return s ? ((UNSIGNED_INTEGER)STRTOUI(s, NULL, 0)) : 0; } /* * */ MINIUPNP_LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalBytesSent(const char * controlURL, const char * servicetype) { struct NameValueParserData pdata; char * buffer; int bufsize; unsigned int r = 0; char * p; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetTotalBytesSent", 0, &bufsize))) { return (UNSIGNED_INTEGER)UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); /*DisplayNameValueList(buffer, bufsize);*/ free(buffer); p = GetValueFromNameValueList(&pdata, "NewTotalBytesSent"); r = my_atoui(p); ClearNameValueList(&pdata); return r; } /* * */ MINIUPNP_LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalBytesReceived(const char * controlURL, const char * servicetype) { struct NameValueParserData pdata; char * buffer; int bufsize; unsigned int r = 0; char * p; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetTotalBytesReceived", 0, &bufsize))) { return (UNSIGNED_INTEGER)UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); /*DisplayNameValueList(buffer, bufsize);*/ free(buffer); p = GetValueFromNameValueList(&pdata, "NewTotalBytesReceived"); r = my_atoui(p); ClearNameValueList(&pdata); return r; } /* * */ MINIUPNP_LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalPacketsSent(const char * controlURL, const char * servicetype) { struct NameValueParserData pdata; char * buffer; int bufsize; unsigned int r = 0; char * p; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetTotalPacketsSent", 0, &bufsize))) { return (UNSIGNED_INTEGER)UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); /*DisplayNameValueList(buffer, bufsize);*/ free(buffer); p = GetValueFromNameValueList(&pdata, "NewTotalPacketsSent"); r = my_atoui(p); ClearNameValueList(&pdata); return r; } /* * */ MINIUPNP_LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalPacketsReceived(const char * controlURL, const char * servicetype) { struct NameValueParserData pdata; char * buffer; int bufsize; unsigned int r = 0; char * p; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetTotalPacketsReceived", 0, &bufsize))) { return (UNSIGNED_INTEGER)UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); /*DisplayNameValueList(buffer, bufsize);*/ free(buffer); p = GetValueFromNameValueList(&pdata, "NewTotalPacketsReceived"); r = my_atoui(p); ClearNameValueList(&pdata); return r; } /* UPNP_GetStatusInfo() call the corresponding UPNP method * returns the current status and uptime */ MINIUPNP_LIBSPEC int UPNP_GetStatusInfo(const char * controlURL, const char * servicetype, char * status, unsigned int * uptime, char * lastconnerror) { struct NameValueParserData pdata; char * buffer; int bufsize; char * p; char * up; char * err; int ret = UPNPCOMMAND_UNKNOWN_ERROR; if(!status && !uptime) return UPNPCOMMAND_INVALID_ARGS; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetStatusInfo", 0, &bufsize))) { return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); /*DisplayNameValueList(buffer, bufsize);*/ free(buffer); up = GetValueFromNameValueList(&pdata, "NewUptime"); p = GetValueFromNameValueList(&pdata, "NewConnectionStatus"); err = GetValueFromNameValueList(&pdata, "NewLastConnectionError"); if(p && up) ret = UPNPCOMMAND_SUCCESS; if(status) { if(p){ strncpy(status, p, 64 ); status[63] = '\0'; }else status[0]= '\0'; } if(uptime) { if(up) sscanf(up,"%u",uptime); else *uptime = 0; } if(lastconnerror) { if(err) { strncpy(lastconnerror, err, 64 ); lastconnerror[63] = '\0'; } else lastconnerror[0] = '\0'; } p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &ret); } ClearNameValueList(&pdata); return ret; } /* UPNP_GetConnectionTypeInfo() call the corresponding UPNP method * returns the connection type */ MINIUPNP_LIBSPEC int UPNP_GetConnectionTypeInfo(const char * controlURL, const char * servicetype, char * connectionType) { struct NameValueParserData pdata; char * buffer; int bufsize; char * p; int ret = UPNPCOMMAND_UNKNOWN_ERROR; if(!connectionType) return UPNPCOMMAND_INVALID_ARGS; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetConnectionTypeInfo", 0, &bufsize))) { return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); free(buffer); p = GetValueFromNameValueList(&pdata, "NewConnectionType"); /*p = GetValueFromNameValueList(&pdata, "NewPossibleConnectionTypes");*/ /* PossibleConnectionTypes will have several values.... */ if(p) { strncpy(connectionType, p, 64 ); connectionType[63] = '\0'; ret = UPNPCOMMAND_SUCCESS; } else connectionType[0] = '\0'; p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &ret); } ClearNameValueList(&pdata); return ret; } /* UPNP_GetLinkLayerMaxBitRate() call the corresponding UPNP method. * Returns 2 values: Downloadlink bandwidth and Uplink bandwidth. * One of the values can be null * Note : GetLinkLayerMaxBitRates belongs to WANPPPConnection:1 only * We can use the GetCommonLinkProperties from WANCommonInterfaceConfig:1 */ MINIUPNP_LIBSPEC int UPNP_GetLinkLayerMaxBitRates(const char * controlURL, const char * servicetype, unsigned int * bitrateDown, unsigned int * bitrateUp) { struct NameValueParserData pdata; char * buffer; int bufsize; int ret = UPNPCOMMAND_UNKNOWN_ERROR; char * down; char * up; char * p; if(!bitrateDown && !bitrateUp) return UPNPCOMMAND_INVALID_ARGS; /* shouldn't we use GetCommonLinkProperties ? */ if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetCommonLinkProperties", 0, &bufsize))) { /*"GetLinkLayerMaxBitRates", 0, &bufsize);*/ return UPNPCOMMAND_HTTP_ERROR; } /*DisplayNameValueList(buffer, bufsize);*/ ParseNameValue(buffer, bufsize, &pdata); free(buffer); /*down = GetValueFromNameValueList(&pdata, "NewDownstreamMaxBitRate");*/ /*up = GetValueFromNameValueList(&pdata, "NewUpstreamMaxBitRate");*/ down = GetValueFromNameValueList(&pdata, "NewLayer1DownstreamMaxBitRate"); up = GetValueFromNameValueList(&pdata, "NewLayer1UpstreamMaxBitRate"); /*GetValueFromNameValueList(&pdata, "NewWANAccessType");*/ /*GetValueFromNameValueList(&pdata, "NewPhysicalLinkStatus");*/ if(down && up) ret = UPNPCOMMAND_SUCCESS; if(bitrateDown) { if(down) sscanf(down,"%u",bitrateDown); else *bitrateDown = 0; } if(bitrateUp) { if(up) sscanf(up,"%u",bitrateUp); else *bitrateUp = 0; } p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &ret); } ClearNameValueList(&pdata); return ret; } /* UPNP_GetExternalIPAddress() call the corresponding UPNP method. * if the third arg is not null the value is copied to it. * at least 16 bytes must be available * * Return values : * 0 : SUCCESS * NON ZERO : ERROR Either an UPnP error code or an unknown error. * * 402 Invalid Args - See UPnP Device Architecture section on Control. * 501 Action Failed - See UPnP Device Architecture section on Control. */ MINIUPNP_LIBSPEC int UPNP_GetExternalIPAddress(const char * controlURL, const char * servicetype, char * extIpAdd) { struct NameValueParserData pdata; char * buffer; int bufsize; char * p; int ret = UPNPCOMMAND_UNKNOWN_ERROR; if(!extIpAdd || !controlURL || !servicetype) return UPNPCOMMAND_INVALID_ARGS; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetExternalIPAddress", 0, &bufsize))) { return UPNPCOMMAND_HTTP_ERROR; } /*DisplayNameValueList(buffer, bufsize);*/ ParseNameValue(buffer, bufsize, &pdata); free(buffer); /*printf("external ip = %s\n", GetValueFromNameValueList(&pdata, "NewExternalIPAddress") );*/ p = GetValueFromNameValueList(&pdata, "NewExternalIPAddress"); if(p) { strncpy(extIpAdd, p, 16 ); extIpAdd[15] = '\0'; ret = UPNPCOMMAND_SUCCESS; } else extIpAdd[0] = '\0'; p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &ret); } ClearNameValueList(&pdata); return ret; } MINIUPNP_LIBSPEC int UPNP_AddPortMapping(const char * controlURL, const char * servicetype, const char * extPort, const char * inPort, const char * inClient, const char * desc, const char * proto, const char * remoteHost, const char * leaseDuration) { struct UPNParg * AddPortMappingArgs; char * buffer; int bufsize; struct NameValueParserData pdata; const char * resVal; int ret; if(!inPort || !inClient || !proto || !extPort) 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"; AddPortMappingArgs[1].val = extPort; AddPortMappingArgs[2].elt = "NewProtocol"; AddPortMappingArgs[2].val = proto; AddPortMappingArgs[3].elt = "NewInternalPort"; AddPortMappingArgs[3].val = inPort; AddPortMappingArgs[4].elt = "NewInternalClient"; AddPortMappingArgs[4].val = inClient; AddPortMappingArgs[5].elt = "NewEnabled"; AddPortMappingArgs[5].val = "1"; AddPortMappingArgs[6].elt = "NewPortMappingDescription"; AddPortMappingArgs[6].val = desc?desc:"libminiupnpc"; AddPortMappingArgs[7].elt = "NewLeaseDuration"; AddPortMappingArgs[7].val = leaseDuration?leaseDuration:"0"; buffer = simpleUPnPcommand(-1, controlURL, servicetype, "AddPortMapping", AddPortMappingArgs, &bufsize); free(AddPortMappingArgs); if(!buffer) { return UPNPCOMMAND_HTTP_ERROR; } /*DisplayNameValueList(buffer, bufsize);*/ /*buffer[bufsize] = '\0';*/ /*puts(buffer);*/ ParseNameValue(buffer, bufsize, &pdata); free(buffer); resVal = GetValueFromNameValueList(&pdata, "errorCode"); if(resVal) { /*printf("AddPortMapping errorCode = '%s'\n", resVal); */ ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(resVal, "%d", &ret); } else { ret = UPNPCOMMAND_SUCCESS; } ClearNameValueList(&pdata); return ret; } MINIUPNP_LIBSPEC int UPNP_AddAnyPortMapping(const char * controlURL, const char * servicetype, const char * extPort, const char * inPort, const char * inClient, const char * desc, const char * proto, const char * remoteHost, const char * leaseDuration, char * reservedPort) { struct UPNParg * AddPortMappingArgs; char * buffer; int bufsize; struct NameValueParserData pdata; const char * resVal; int ret; if(!inPort || !inClient || !proto || !extPort) 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"; AddPortMappingArgs[1].val = extPort; AddPortMappingArgs[2].elt = "NewProtocol"; AddPortMappingArgs[2].val = proto; AddPortMappingArgs[3].elt = "NewInternalPort"; AddPortMappingArgs[3].val = inPort; AddPortMappingArgs[4].elt = "NewInternalClient"; AddPortMappingArgs[4].val = inClient; AddPortMappingArgs[5].elt = "NewEnabled"; AddPortMappingArgs[5].val = "1"; AddPortMappingArgs[6].elt = "NewPortMappingDescription"; AddPortMappingArgs[6].val = desc?desc:"libminiupnpc"; AddPortMappingArgs[7].elt = "NewLeaseDuration"; AddPortMappingArgs[7].val = leaseDuration?leaseDuration:"0"; buffer = simpleUPnPcommand(-1, controlURL, servicetype, "AddAnyPortMapping", AddPortMappingArgs, &bufsize); free(AddPortMappingArgs); if(!buffer) { return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); free(buffer); resVal = GetValueFromNameValueList(&pdata, "errorCode"); if(resVal) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(resVal, "%d", &ret); } else { char *p; p = GetValueFromNameValueList(&pdata, "NewReservedPort"); if(p) { strncpy(reservedPort, p, 6); reservedPort[5] = '\0'; ret = UPNPCOMMAND_SUCCESS; } else { ret = UPNPCOMMAND_INVALID_RESPONSE; } } ClearNameValueList(&pdata); return ret; } MINIUPNP_LIBSPEC int UPNP_DeletePortMapping(const char * controlURL, const char * servicetype, const char * extPort, const char * proto, const char * remoteHost) { /*struct NameValueParserData pdata;*/ struct UPNParg * DeletePortMappingArgs; char * buffer; int bufsize; struct NameValueParserData pdata; const char * resVal; int ret; if(!extPort || !proto) 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"; DeletePortMappingArgs[1].val = extPort; DeletePortMappingArgs[2].elt = "NewProtocol"; DeletePortMappingArgs[2].val = proto; buffer = simpleUPnPcommand(-1, controlURL, servicetype, "DeletePortMapping", DeletePortMappingArgs, &bufsize); free(DeletePortMappingArgs); if(!buffer) { return UPNPCOMMAND_HTTP_ERROR; } /*DisplayNameValueList(buffer, bufsize);*/ ParseNameValue(buffer, bufsize, &pdata); free(buffer); resVal = GetValueFromNameValueList(&pdata, "errorCode"); if(resVal) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(resVal, "%d", &ret); } else { ret = UPNPCOMMAND_SUCCESS; } ClearNameValueList(&pdata); return ret; } MINIUPNP_LIBSPEC int UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype, const char * extPortStart, const char * extPortEnd, const char * proto, const char * manage) { struct UPNParg * DeletePortMappingArgs; char * buffer; int bufsize; struct NameValueParserData pdata; const char * resVal; int ret; if(!extPortStart || !extPortEnd || !proto || !manage) 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"; DeletePortMappingArgs[1].val = extPortEnd; DeletePortMappingArgs[2].elt = "NewProtocol"; DeletePortMappingArgs[2].val = proto; DeletePortMappingArgs[3].elt = "NewManage"; DeletePortMappingArgs[3].val = manage; buffer = simpleUPnPcommand(-1, controlURL, servicetype, "DeletePortMappingRange", DeletePortMappingArgs, &bufsize); free(DeletePortMappingArgs); if(!buffer) { return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); free(buffer); resVal = GetValueFromNameValueList(&pdata, "errorCode"); if(resVal) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(resVal, "%d", &ret); } else { ret = UPNPCOMMAND_SUCCESS; } ClearNameValueList(&pdata); return ret; } MINIUPNP_LIBSPEC int UPNP_GetGenericPortMappingEntry(const char * controlURL, const char * servicetype, const char * index, char * extPort, char * intClient, char * intPort, char * protocol, char * desc, char * enabled, char * rHost, char * duration) { struct NameValueParserData pdata; struct UPNParg * GetPortMappingArgs; char * buffer; int bufsize; char * p; int r = UPNPCOMMAND_UNKNOWN_ERROR; if(!index) return UPNPCOMMAND_INVALID_ARGS; 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; buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetGenericPortMappingEntry", GetPortMappingArgs, &bufsize); free(GetPortMappingArgs); if(!buffer) { return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); free(buffer); p = GetValueFromNameValueList(&pdata, "NewRemoteHost"); if(p && rHost) { strncpy(rHost, p, 64); rHost[63] = '\0'; } p = GetValueFromNameValueList(&pdata, "NewExternalPort"); if(p && extPort) { strncpy(extPort, p, 6); extPort[5] = '\0'; r = UPNPCOMMAND_SUCCESS; } p = GetValueFromNameValueList(&pdata, "NewProtocol"); if(p && protocol) { strncpy(protocol, p, 4); protocol[3] = '\0'; } p = GetValueFromNameValueList(&pdata, "NewInternalClient"); if(p) { strncpy(intClient, p, 16); intClient[15] = '\0'; r = 0; } p = GetValueFromNameValueList(&pdata, "NewInternalPort"); if(p) { strncpy(intPort, p, 6); intPort[5] = '\0'; } p = GetValueFromNameValueList(&pdata, "NewEnabled"); if(p && enabled) { strncpy(enabled, p, 4); enabled[3] = '\0'; } p = GetValueFromNameValueList(&pdata, "NewPortMappingDescription"); if(p && desc) { strncpy(desc, p, 80); desc[79] = '\0'; } p = GetValueFromNameValueList(&pdata, "NewLeaseDuration"); if(p && duration) { strncpy(duration, p, 16); duration[15] = '\0'; } p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { r = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &r); } ClearNameValueList(&pdata); return r; } MINIUPNP_LIBSPEC int UPNP_GetPortMappingNumberOfEntries(const char * controlURL, const char * servicetype, unsigned int * numEntries) { struct NameValueParserData pdata; char * buffer; int bufsize; char* p; int ret = UPNPCOMMAND_UNKNOWN_ERROR; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetPortMappingNumberOfEntries", 0, &bufsize))) { return UPNPCOMMAND_HTTP_ERROR; } #ifdef DEBUG DisplayNameValueList(buffer, bufsize); #endif ParseNameValue(buffer, bufsize, &pdata); free(buffer); p = GetValueFromNameValueList(&pdata, "NewPortMappingNumberOfEntries"); if(numEntries && p) { *numEntries = 0; sscanf(p, "%u", numEntries); ret = UPNPCOMMAND_SUCCESS; } p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &ret); } ClearNameValueList(&pdata); return ret; } /* UPNP_GetSpecificPortMappingEntry retrieves an existing port mapping * the result is returned in the intClient and intPort strings * please provide 16 and 6 bytes of data */ MINIUPNP_LIBSPEC int UPNP_GetSpecificPortMappingEntry(const char * controlURL, const char * servicetype, const char * extPort, const char * proto, const char * remoteHost, char * intClient, char * intPort, char * desc, char * enabled, char * leaseDuration) { struct NameValueParserData pdata; struct UPNParg * GetPortMappingArgs; char * buffer; int bufsize; char * p; int ret = UPNPCOMMAND_UNKNOWN_ERROR; if(!intPort || !intClient || !extPort || !proto) 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"; GetPortMappingArgs[1].val = extPort; GetPortMappingArgs[2].elt = "NewProtocol"; GetPortMappingArgs[2].val = proto; buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetSpecificPortMappingEntry", GetPortMappingArgs, &bufsize); free(GetPortMappingArgs); if(!buffer) { return UPNPCOMMAND_HTTP_ERROR; } /*DisplayNameValueList(buffer, bufsize);*/ ParseNameValue(buffer, bufsize, &pdata); free(buffer); p = GetValueFromNameValueList(&pdata, "NewInternalClient"); if(p) { strncpy(intClient, p, 16); intClient[15] = '\0'; ret = UPNPCOMMAND_SUCCESS; } else intClient[0] = '\0'; p = GetValueFromNameValueList(&pdata, "NewInternalPort"); if(p) { strncpy(intPort, p, 6); intPort[5] = '\0'; } else intPort[0] = '\0'; p = GetValueFromNameValueList(&pdata, "NewEnabled"); if(p && enabled) { strncpy(enabled, p, 4); enabled[3] = '\0'; } p = GetValueFromNameValueList(&pdata, "NewPortMappingDescription"); if(p && desc) { strncpy(desc, p, 80); desc[79] = '\0'; } p = GetValueFromNameValueList(&pdata, "NewLeaseDuration"); if(p && leaseDuration) { strncpy(leaseDuration, p, 16); leaseDuration[15] = '\0'; } p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &ret); } ClearNameValueList(&pdata); return ret; } /* UPNP_GetListOfPortMappings() * * Possible UPNP Error codes : * 606 Action not Authorized * 730 PortMappingNotFound - no port mapping is found in the specified range. * 733 InconsistantParameters - NewStartPort and NewEndPort values are not * consistent. */ MINIUPNP_LIBSPEC int UPNP_GetListOfPortMappings(const char * controlURL, const char * servicetype, const char * startPort, const char * endPort, const char * protocol, const char * numberOfPorts, struct PortMappingParserData * data) { struct NameValueParserData pdata; struct UPNParg * GetListOfPortMappingsArgs; const char * p; char * buffer; int bufsize; int ret = UPNPCOMMAND_UNKNOWN_ERROR; if(!startPort || !endPort || !protocol) 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"; GetListOfPortMappingsArgs[1].val = endPort; GetListOfPortMappingsArgs[2].elt = "NewProtocol"; GetListOfPortMappingsArgs[2].val = protocol; GetListOfPortMappingsArgs[3].elt = "NewManage"; GetListOfPortMappingsArgs[3].val = "1"; GetListOfPortMappingsArgs[4].elt = "NewNumberOfPorts"; GetListOfPortMappingsArgs[4].val = numberOfPorts?numberOfPorts:"1000"; buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetListOfPortMappings", GetListOfPortMappingsArgs, &bufsize); free(GetListOfPortMappingsArgs); if(!buffer) { return UPNPCOMMAND_HTTP_ERROR; } /*DisplayNameValueList(buffer, bufsize);*/ ParseNameValue(buffer, bufsize, &pdata); free(buffer); /*p = GetValueFromNameValueList(&pdata, "NewPortListing");*/ /*if(p) { printf("NewPortListing : %s\n", p); }*/ /*printf("NewPortListing(%d chars) : %s\n", pdata.portListingLength, pdata.portListing);*/ if(pdata.portListing) { /*struct PortMapping * pm; int i = 0;*/ ParsePortListing(pdata.portListing, pdata.portListingLength, data); ret = UPNPCOMMAND_SUCCESS; /* for(pm = data->head.lh_first; pm != NULL; pm = pm->entries.le_next) { printf("%2d %s %5hu->%s:%-5hu '%s' '%s'\n", i, pm->protocol, pm->externalPort, pm->internalClient, pm->internalPort, pm->description, pm->remoteHost); i++; } */ /*FreePortListing(&data);*/ } p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &ret); } ClearNameValueList(&pdata); /*printf("%.*s", bufsize, buffer);*/ return ret; } /* IGD:2, functions for service WANIPv6FirewallControl:1 */ MINIUPNP_LIBSPEC int UPNP_GetFirewallStatus(const char * controlURL, const char * servicetype, int * firewallEnabled, int * inboundPinholeAllowed) { struct NameValueParserData pdata; char * buffer; int bufsize; char * fe, *ipa, *p; int ret = UPNPCOMMAND_UNKNOWN_ERROR; if(!firewallEnabled || !inboundPinholeAllowed) return UPNPCOMMAND_INVALID_ARGS; buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetFirewallStatus", 0, &bufsize); if(!buffer) { return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); free(buffer); fe = GetValueFromNameValueList(&pdata, "FirewallEnabled"); ipa = GetValueFromNameValueList(&pdata, "InboundPinholeAllowed"); if(ipa && fe) ret = UPNPCOMMAND_SUCCESS; if(fe) *firewallEnabled = my_atoui(fe); /*else *firewallEnabled = 0;*/ if(ipa) *inboundPinholeAllowed = my_atoui(ipa); /*else *inboundPinholeAllowed = 0;*/ p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &ret); } ClearNameValueList(&pdata); return ret; } MINIUPNP_LIBSPEC int UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype, const char * remoteHost, const char * remotePort, const char * intClient, const char * intPort, const char * proto, int * opTimeout) { struct UPNParg * GetOutboundPinholeTimeoutArgs; char * buffer; int bufsize; struct NameValueParserData pdata; const char * resVal; int ret; if(!intPort || !intClient || !proto || !remotePort || !remoteHost) 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"; GetOutboundPinholeTimeoutArgs[1].val = remotePort; GetOutboundPinholeTimeoutArgs[2].elt = "Protocol"; GetOutboundPinholeTimeoutArgs[2].val = proto; GetOutboundPinholeTimeoutArgs[3].elt = "InternalPort"; GetOutboundPinholeTimeoutArgs[3].val = intPort; GetOutboundPinholeTimeoutArgs[4].elt = "InternalClient"; GetOutboundPinholeTimeoutArgs[4].val = intClient; buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetOutboundPinholeTimeout", GetOutboundPinholeTimeoutArgs, &bufsize); free(GetOutboundPinholeTimeoutArgs); if(!buffer) return UPNPCOMMAND_HTTP_ERROR; ParseNameValue(buffer, bufsize, &pdata); free(buffer); resVal = GetValueFromNameValueList(&pdata, "errorCode"); if(resVal) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(resVal, "%d", &ret); } else { const char * p = GetValueFromNameValueList(&pdata, "OutboundPinholeTimeout"); if(p) *opTimeout = my_atoui(p); ret = UPNPCOMMAND_SUCCESS; } ClearNameValueList(&pdata); return ret; } MINIUPNP_LIBSPEC int UPNP_AddPinhole(const char * controlURL, const char * servicetype, const char * remoteHost, const char * remotePort, const char * intClient, const char * intPort, const char * proto, const char * leaseTime, char * uniqueID) { struct UPNParg * AddPinholeArgs; char * buffer; int bufsize; struct NameValueParserData pdata; const char * resVal; char * p; int ret; if(!intPort || !intClient || !proto || !remoteHost || !remotePort || !leaseTime) 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) { AddPinholeArgs[0].elt = "RemoteHost"; AddPinholeArgs[0].val = ""; } else { AddPinholeArgs[0].elt = "RemoteHost"; AddPinholeArgs[0].val = remoteHost; } AddPinholeArgs[1].elt = "RemotePort"; AddPinholeArgs[1].val = remotePort; AddPinholeArgs[2].elt = "Protocol"; AddPinholeArgs[2].val = proto; AddPinholeArgs[3].elt = "InternalPort"; AddPinholeArgs[3].val = intPort; if(strncmp(intClient, "empty", 5)==0) { AddPinholeArgs[4].elt = "InternalClient"; AddPinholeArgs[4].val = ""; } else { AddPinholeArgs[4].elt = "InternalClient"; AddPinholeArgs[4].val = intClient; } AddPinholeArgs[5].elt = "LeaseTime"; AddPinholeArgs[5].val = leaseTime; buffer = simpleUPnPcommand(-1, controlURL, servicetype, "AddPinhole", AddPinholeArgs, &bufsize); free(AddPinholeArgs); if(!buffer) return UPNPCOMMAND_HTTP_ERROR; ParseNameValue(buffer, bufsize, &pdata); free(buffer); p = GetValueFromNameValueList(&pdata, "UniqueID"); if(p) { strncpy(uniqueID, p, 8); uniqueID[7] = '\0'; } resVal = GetValueFromNameValueList(&pdata, "errorCode"); if(resVal) { /*printf("AddPortMapping errorCode = '%s'\n", resVal);*/ ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(resVal, "%d", &ret); } else { ret = UPNPCOMMAND_SUCCESS; } ClearNameValueList(&pdata); return ret; } MINIUPNP_LIBSPEC int UPNP_UpdatePinhole(const char * controlURL, const char * servicetype, const char * uniqueID, const char * leaseTime) { struct UPNParg * UpdatePinholeArgs; char * buffer; int bufsize; struct NameValueParserData pdata; const char * resVal; int ret; if(!uniqueID || !leaseTime) 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"; UpdatePinholeArgs[1].val = leaseTime; buffer = simpleUPnPcommand(-1, controlURL, servicetype, "UpdatePinhole", UpdatePinholeArgs, &bufsize); free(UpdatePinholeArgs); if(!buffer) return UPNPCOMMAND_HTTP_ERROR; ParseNameValue(buffer, bufsize, &pdata); free(buffer); resVal = GetValueFromNameValueList(&pdata, "errorCode"); if(resVal) { /*printf("AddPortMapping errorCode = '%s'\n", resVal); */ ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(resVal, "%d", &ret); } else { ret = UPNPCOMMAND_SUCCESS; } ClearNameValueList(&pdata); return ret; } MINIUPNP_LIBSPEC int UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID) { /*struct NameValueParserData pdata;*/ struct UPNParg * DeletePinholeArgs; char * buffer; int bufsize; struct NameValueParserData pdata; const char * resVal; int ret; if(!uniqueID) 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, "DeletePinhole", DeletePinholeArgs, &bufsize); free(DeletePinholeArgs); if(!buffer) return UPNPCOMMAND_HTTP_ERROR; /*DisplayNameValueList(buffer, bufsize);*/ ParseNameValue(buffer, bufsize, &pdata); free(buffer); resVal = GetValueFromNameValueList(&pdata, "errorCode"); if(resVal) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(resVal, "%d", &ret); } else { ret = UPNPCOMMAND_SUCCESS; } ClearNameValueList(&pdata); return ret; } MINIUPNP_LIBSPEC int UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype, const char * uniqueID, int * isWorking) { struct NameValueParserData pdata; struct UPNParg * CheckPinholeWorkingArgs; char * buffer; int bufsize; char * p; int ret = UPNPCOMMAND_UNKNOWN_ERROR; if(!uniqueID) 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, "CheckPinholeWorking", CheckPinholeWorkingArgs, &bufsize); free(CheckPinholeWorkingArgs); if(!buffer) { return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); free(buffer); p = GetValueFromNameValueList(&pdata, "IsWorking"); if(p) { *isWorking=my_atoui(p); ret = UPNPCOMMAND_SUCCESS; } else *isWorking = 0; p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &ret); } ClearNameValueList(&pdata); return ret; } MINIUPNP_LIBSPEC int UPNP_GetPinholePackets(const char * controlURL, const char * servicetype, const char * uniqueID, int * packets) { struct NameValueParserData pdata; struct UPNParg * GetPinholePacketsArgs; char * buffer; int bufsize; char * p; int ret = UPNPCOMMAND_UNKNOWN_ERROR; if(!uniqueID) 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, "GetPinholePackets", GetPinholePacketsArgs, &bufsize); free(GetPinholePacketsArgs); if(!buffer) return UPNPCOMMAND_HTTP_ERROR; ParseNameValue(buffer, bufsize, &pdata); free(buffer); p = GetValueFromNameValueList(&pdata, "PinholePackets"); if(p) { *packets=my_atoui(p); ret = UPNPCOMMAND_SUCCESS; } p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &ret); } ClearNameValueList(&pdata); return ret; } miniupnpc-2.2.6/src/upnpreplyparse.c010064400017500000024000000106551345264716300167530ustar00nanardstaff/* $Id: upnpreplyparse.c,v 1.21 2019/04/08 13:30:51 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2019 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ #include #include #include #include "upnpreplyparse.h" #include "minixml.h" static void NameValueParserStartElt(void * d, const char * name, int l) { struct NameValueParserData * data = (struct NameValueParserData *)d; data->topelt = 1; if(l>63) l = 63; memcpy(data->curelt, name, l); data->curelt[l] = '\0'; data->cdata = NULL; data->cdatalen = 0; } static void NameValueParserEndElt(void * d, const char * name, int namelen) { struct NameValueParserData * data = (struct NameValueParserData *)d; struct NameValue * nv; (void)name; (void)namelen; if(!data->topelt) return; if(strcmp(data->curelt, "NewPortListing") != 0) { 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); nv->name[63] = '\0'; if(data->cdata != NULL) { memcpy(nv->value, data->cdata, l); nv->value[l] = '\0'; } else { nv->value[0] = '\0'; } nv->l_next = data->l_head; /* insert in list */ data->l_head = nv; } data->cdata = NULL; data->cdatalen = 0; data->topelt = 0; } static void NameValueParserGetData(void * d, const char * datas, int l) { struct NameValueParserData * data = (struct NameValueParserData *)d; if(strcmp(data->curelt, "NewPortListing") == 0) { /* specific case for NewPortListing which is a XML Document */ free(data->portListing); data->portListing = malloc(l + 1); if(!data->portListing) { /* malloc error */ #ifdef DEBUG fprintf(stderr, "%s: error allocating memory", "NameValueParserGetData"); #endif /* DEBUG */ return; } memcpy(data->portListing, datas, l); data->portListing[l] = '\0'; data->portListingLength = l; } else { /* standard case. */ data->cdata = datas; data->cdatalen = l; } } void ParseNameValue(const char * buffer, int bufsize, struct NameValueParserData * data) { struct xmlparser parser; memset(data, 0, sizeof(struct NameValueParserData)); /* init xmlparser object */ parser.xmlstart = buffer; parser.xmlsize = bufsize; parser.data = data; parser.starteltfunc = NameValueParserStartElt; parser.endeltfunc = NameValueParserEndElt; parser.datafunc = NameValueParserGetData; parser.attfunc = 0; parsexml(&parser); } void ClearNameValueList(struct NameValueParserData * pdata) { struct NameValue * nv; if(pdata->portListing) { free(pdata->portListing); pdata->portListing = NULL; pdata->portListingLength = 0; } while((nv = pdata->l_head) != NULL) { pdata->l_head = nv->l_next; free(nv); } } char * GetValueFromNameValueList(struct NameValueParserData * pdata, const char * Name) { struct NameValue * nv; char * p = NULL; for(nv = pdata->l_head; (nv != NULL) && (p == NULL); nv = nv->l_next) { if(strcmp(nv->name, Name) == 0) p = nv->value; } return p; } #if 0 /* useless now that minixml ignores namespaces by itself */ char * GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata, const char * Name) { struct NameValue * nv; char * p = NULL; char * pname; for(nv = pdata->head.lh_first; (nv != NULL) && (p == NULL); nv = nv->entries.le_next) { pname = strrchr(nv->name, ':'); if(pname) pname++; else pname = nv->name; if(strcmp(pname, Name)==0) p = nv->value; } return p; } #endif /* debug all-in-one function * do parsing then display to stdout */ #ifdef DEBUG void DisplayNameValueList(char * buffer, int bufsize) { struct NameValueParserData pdata; struct NameValue * nv; ParseNameValue(buffer, bufsize, &pdata); for(nv = pdata.l_head; nv != NULL; nv = nv->l_next) { printf("%s = %s\n", nv->name, nv->value); } ClearNameValueList(&pdata); } #endif /* DEBUG */ miniupnpc-2.2.6/Makefile.mingw010064400017500000024000000125011432271534100154660ustar00nanardstaff# $Id: Makefile.mingw,v 1.35 2022/10/16 05:28:15 nanard Exp $ # Miniupnp project. # http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ # (c) 2005-2020 Thomas Bernard # This Makefile is made for MinGW # # To cross compile on a *nix machine : # make -f Makefile.mingw DLLWRAP=mingw32-dllwrap CC=mingw32-gcc AR=mingw32-ar WINDRES=mingw32-windres # SRCDIR = src INCDIR = include CC ?= gcc SETUP_COMPILER_FLAG?= DLLWRAP = dllwrap WINDRES = windres SH = /bin/sh ZIP = zip ifeq ($(OS),Windows_NT) RM = del else RM = rm -f endif CFLAGS ?= -Os CFLAGS += -Wall CFLAGS += -W -Wstrict-prototypes CPPFLAGS += -DNDEBUG -D_WIN32_WINNT=0x501 CPPFLAGS += -Iinclude CPPFLAGS += -I. # -liphlpapi is needed for GetBestRoute() and GetIpAddrTable() LDLIBS = -lws2_32 -liphlpapi 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 \ upnpdev.o addr_is_reserved.o OBJSDLL=$(addprefix dll-, $(OBJS)) winres.o BINARIES=upnpc-static.exe upnpc-shared.exe \ listdevices-static.exe listdevices-shared.exe \ miniupnpc.dll libminiupnpc.a \ testminixml.exe ifneq ($(GITHUB_SHA),) COMMITREF=$(GITHUB_SHA) else ifneq ($(CI_COMMIT_SHORT_SHA),) COMMITREF=$(CI_COMMIT_SHORT_SHA) else COMMITREF=$(shell git rev-parse --short HEAD) endif endif DISTFILE:=$(shell echo "miniupnpc-bin-win32-`cat VERSION`-$(COMMITREF).zip") LIBDIR ?= lib # install directories ifeq ($(strip $(PREFIX)),) INSTALLPREFIX ?= /usr else INSTALLPREFIX ?= $(PREFIX) endif .PHONY: all dist clean all: $(BINARIES) dist: $(DISTFILE) clean: $(RM) miniupnpcstrings.h $(RM) *.o $(RM) *.exe $(RM) miniupnpc.dll miniupnpc.lib miniupnpc.dll.def $(RM) libminiupnpc.a $(RM) $(DISTFILE) $(DISTFILE): $(BINARIES) $(ZIP) $@ *.exe *.dll *.lib *.def *.a LICENSE README Changelog.txt libminiupnpc.a: $(OBJS) $(AR) cr $@ $? pythonmodule: libminiupnpc.a $(PYTHON) setupmingw32.py build $(SETUP_COMPILER_FLAG) $(PYTHON) setupmingw32.py install --skip-build $(PYTHON) setupmingw32.py bdist_wheel --skip-build miniupnpc.dll: miniupnpc.def $(OBJSDLL) $(DLLWRAP) -k --driver-name $(CC) \ --def miniupnpc.def \ --output-def miniupnpc.dll.def \ --implib miniupnpc.lib -o $@ \ $(OBJSDLL) $(LDLIBS) miniupnpc.lib: miniupnpc.dll %.o: $(SRCDIR)/%.c $(CC) $(CFLAGS) $(CPPFLAGS) -DMINIUPNP_STATICLIB -c -o $@ $< dll-%.o: $(SRCDIR)/%.c $(CC) $(CFLAGS) $(CPPFLAGS) -DMINIUPNP_EXPORTS -c -o $@ $< %-shared.o: $(SRCDIR)/%.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< # --enable-stdcall-fixup %-static.exe: %.o libminiupnpc.a $(CC) -static -o $@ $^ $(LDLIBS) %-shared.exe: %-shared.o miniupnpc.lib $(CC) -o $@ $^ $(LDLIBS) # To make miniupnpcstrings.h from miniupnpcstrings.h.in we either # use a custom executable (if running make under windows) or use # sed (if cross compiling from another platform). ifeq ($(OS),Windows_NT) wingenminiupnpcstrings.exe: wingenminiupnpcstrings.c $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $^ miniupnpcstrings.h: miniupnpcstrings.h.in wingenminiupnpcstrings.exe VERSION .\wingenminiupnpcstrings.exe $< $@ rc_version.h rc_version.h: miniupnpcstrings.h else miniupnpcstrings.h: miniupnpcstrings.h.in VERSION sed 's|OS_STRING ".*"|OS_STRING "Windows/Mingw32"|' $< | \ sed 's|MINIUPNPC_VERSION_STRING ".*"|MINIUPNPC_VERSION_STRING "$(shell cat VERSION)"|' > $@ rc_version.h: VERSION echo "#define LIBMINIUPNPC_DOTTED_VERSION \"$(shell cat VERSION)\"" > $@.tmp echo "#define LIBMINIUPNPC_MAJOR_VERSION $(shell cat VERSION|cut -d. -f1)" >> $@.tmp echo "#define LIBMINIUPNPC_MINOR_VERSION $(shell cat VERSION|cut -d. -f2)" >> $@.tmp echo "#define LIBMINIUPNPC_MICRO_VERSION $(shell cat VERSION|cut -d. -f3)" >> $@.tmp mv $@.tmp $@ endif miniupnpc.pc: VERSION $(RM) $@ echo "prefix=$(INSTALLPREFIX)" >> $@ echo "exec_prefix=\$${prefix}" >> $@ echo "libdir=\$${exec_prefix}/$(LIBDIR)" >> $@ echo "includedir=\$${prefix}/include" >> $@ echo "" >> $@ echo "Name: miniUPnPc" >> $@ echo "Description: UPnP IGD client lightweight library" >> $@ echo "Version: $(shell cat VERSION)" >> $@ echo "Libs: -L\$${libdir} -lminiupnpc" >> $@ echo "Cflags: -I\$${includedir}" >> $@ winres.o: miniupnpc.rc rc_version.h $(WINDRES) -D INTERNAL_NAME=\\\"miniupnpc.dll\\0\\\" -i $< -o $@ testminixml.exe: testminixml.o minixml.o igd_desc_parse.o $(CC) -static -o $@ $^ minixml.o: $(SRCDIR)/minixml.c $(SRCDIR)/minixml.h upnpc.o: include/miniwget.h $(SRCDIR)/minisoap.h include/miniupnpc.h include/igd_desc_parse.h upnpc.o: include/upnpreplyparse.h include/upnpcommands.h include/upnperrors.h miniupnpcstrings.h miniwget.o: $(SRCDIR)/miniwget.c include/miniwget.h miniupnpcstrings.h $(SRCDIR)/connecthostport.h minisoap.o: $(SRCDIR)/minisoap.c $(SRCDIR)/minisoap.h miniupnpcstrings.h miniupnpc.o: $(SRCDIR)/miniupnpc.c include/miniupnpc.h $(SRCDIR)/minisoap.h \ include/miniwget.h $(SRCDIR)/minixml.h $(SRCDIR)/addr_is_reserved.h igd_desc_parse.o: $(SRCDIR)/igd_desc_parse.c include/igd_desc_parse.h upnpreplyparse.o: $(SRCDIR)/upnpreplyparse.c include/upnpreplyparse.h $(SRCDIR)/minixml.h upnpcommands.o: $(SRCDIR)/upnpcommands.c include/upnpcommands.h include/upnpreplyparse.h \ include/miniupnpc.h include/portlistingparse.h minissdpc.o: $(SRCDIR)/minissdpc.c $(SRCDIR)/minissdpc.h $(SRCDIR)/receivedata.h upnpdev.o: $(SRCDIR)/upnpdev.c include/upnpdev.h miniupnpc-2.2.6/Changelog.txt010064400017500000024000000454551454537750100153650ustar00nanardstaff$Id: Changelog.txt,v 1.261 2024/01/04 00:35:54 nanard Exp $ miniUPnP client Changelog. 2024/01/04: includes charset="utf-8" in Content-Type fix memory allocation error in minissdpc.c 2023/06/15: Make User-Agent compliant. listdevices => upnp-listdevices VERSION 2.2.5 : released 2023/06/12 2023/06/05: GetListOfPortMappings NewStartPort 0 => 1 2023/05/30: CheckPinholeWorking is optional add 60x errors from UPnP Device Architecture 2023/01/04: cmake: install binaries, man pages and external-ip.sh VERSION 2.2.4 : released 2022/10/21 2022/02/20: upnpc: use of @ to replace local lan address 2021/11/09: python module : Allow to specify the root description url VERSION 2.2.3 : released 2021/09/28 2021/08/13: Change directory structure : include/ and src/ directories. VERSION 2.2.2 : released 2021/03/03 2021/01/15: miniupnpcmodule.c: throw an exception in UPnP_discover() 2020/12/30: Fix usage of IP_MULTICAST_IF with struct ip_mreqn VERSION 2.2.1 : released 2020/12/20 2020/11/30: Add miniupnpc.rc for .dll description VERSION 2.2.0 : released 2020/11/09 2020/09/24: Check properly for reserved IP addresses 2020/09/23: prevent infinite loop in upnpDiscover() 2020/02/16: Add Haiku support 2019/10/22: testminiwget.sh can use either "ip addr" or "ifconfig -a 2019/10/13: fix UPNP_GetValidIGD() when several devices are found which are reachable from != local address 2019/08/24: Allow Remote Host on upnpc command line fix error 708 description in strupnperror() 2019/04/05: Fix memory leak in upnpreplyparse.c with NewPortListing element 2019/03/10: connecthostport.c: Code simplification, error trace fix 2019/01/23: set timeout for select() in connecthostport() 2018/10/31: miniupnpcmodule.c: check return of WSAStartup() 2018/07/14: Fix and improve MSVC project : Add Dll configurations improve genminiupnpcstrings.vbs 2018/06/18: Fixes for windows 64-bits. VERSION 2.1 : released 2018/05/07 2018/05/07: CMake Modernize and cleanup CMakeLists.txt Update MS Visual Studio projects 2018/04/30: listdevices: show devices sorted by XML desc URL 2018/04/26: Small fix in miniupnpcmodule.c (python module) Support cross compiling in Makefile.mingw 2018/04/06: Use SOCKET type instead of int (for Win64 compilation) Increments API_VERSION to 17 2018/02/22: Disable usage of MiniSSDPd when using -m option 2017/12/11: Fix buffer over run in minixml.c Fix uninitialized variable access in upnpreplyparse.c 2017/05/05: Fix CVE-2017-8798 Thanks to tin/Team OSTStrom 2016/11/11: check strlen before memcmp in XML parsing portlistingparse.c fix build under SOLARIS and CYGWIN 2016/10/11: Add python 3 compatibility to IGD test VERSION 2.0 : released 2016/04/19 2016/01/24: change miniwget to return HTTP status code increments API_VERSION to 16 2016/01/22: Improve UPNPIGD_IsConnected() to check if WAN address is not private. parse HTTP response status line in miniwget.c 2015/10/26: snprintf() overflow check. check overflow in simpleUPnPcommand2() 2015/10/25: fix compilation with old macs fix compilation with mingw32 (for Appveyor) fix python module for python <= 2.3 2015/10/08: Change sameport to localport see https://github.com/miniupnp/miniupnp/pull/120 increments API_VERSION to 15 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 2015/04/27: _BSD_SOURCE is deprecated in favor of _DEFAULT_SOURCE fix CMakeLists.txt COMPILE_DEFINITIONS fix getDevicesFromMiniSSDPD() not setting scope_id improve -r command of upnpc command line tool 2014/11/17: search all : upnpDiscoverDevices() / upnpDiscoverAll() functions listdevices executable increment API_VERSION to 12 validate igd_desc_parse 2014/11/13: increment API_VERSION to 11 2014/11/05: simplified function GetUPNPUrls() 2014/09/11: use remoteHost arg of DeletePortMapping 2014/09/06: Fix python3 build 2014/07/01: Fix parsing of IGD2 root descriptions 2014/06/10: rename LIBSPEC to MINIUPNP_LIBSPEC 2014/05/15: Add support for IGD2 AddAnyPortMapping and DeletePortMappingRange 2014/02/05: handle EINPROGRESS after connect() 2014/02/03: minixml now handle XML comments VERSION 1.9 : released 2014/01/31 2014/01/31: added argument remoteHost to UPNP_GetSpecificPortMappingEntry() increment API_VERSION to 10 2013/12/09: --help and -h arguments in upnpc.c 2013/10/07: fixed potential buffer overrun in miniwget.c Modified UPNP_GetValidIGD() to check for ExternalIpAddress 2013/08/01: define MAXHOSTNAMELEN if not already done 2013/06/06: update upnpreplyparse to allow larger values (128 chars instead of 64) 2013/05/14: Update upnpreplyparse to take into account "empty" elements validate upnpreplyparse.c code with "make check" 2013/05/03: Fix Solaris build thanks to Maciej MaÅ‚ecki 2013/04/27: Fix testminiwget.sh for BSD 2013/03/23: Fixed Makefile for *BSD 2013/03/11: Update Makefile to use JNAerator version 0.11 2013/02/11: Fix testminiwget.sh for use with dash Use $(DESTDIR) in Makefile VERSION 1.8 : released 2013/02/06 2012/10/16: fix testminiwget with no IPv6 support 2012/09/27: Rename all include guards to not clash with C99 (7.1.3 Reserved identifiers). 2012/08/30: Added -e option to upnpc program (set description for port mappings) 2012/08/29: Python 3 support (thanks to Christopher Foo) 2012/08/11: Fix a memory link in UPNP_GetValidIGD() Try to handle scope id in link local IPv6 URL under MS Windows 2012/07/20: Disable HAS_IP_MREQN on DragonFly BSD 2012/06/28: GetUPNPUrls() now inserts scope into link-local IPv6 addresses 2012/06/23: More error return checks in upnpc.c #define MINIUPNPC_GET_SRC_ADDR enables receivedata() to get scope_id parseURL() now parses IPv6 addresses scope new parameter for miniwget() : IPv6 address scope increment API_VERSION to 9 2012/06/20: fixed CMakeLists.txt 2012/05/29 Improvements in testminiwget.sh VERSION 1.7 : released 2012/05/24 2012/05/01: Cleanup settings of CFLAGS in Makefile Fix signed/unsigned integer comparaisons 2012/04/20: Allow to specify protocol with TCP or UDP for -A option 2012/04/09: Only try to fetch XML description once in UPNP_GetValidIGD() Added -ansi flag to compilation, and fixed C++ comments to ANSI C comments. 2012/04/05: minor improvements to minihttptestserver.c 2012/03/15: upnperrors.c returns valid error string for unrecognized error codes 2012/03/08: make minihttptestserver listen on loopback interface instead of 0.0.0.0 2012/01/25: Maven installation thanks to Alexey Kuznetsov 2012/01/21: Replace WIN32 macro by _WIN32 2012/01/19: Fixes in java wrappers thanks to Alexey Kuznetsov : https://github.com/axet/miniupnp/tree/fix-javatest/miniupnpc Make and install .deb packages (python) thanks to Alexey Kuznetsov : https://github.com/axet/miniupnp/tree/feature-debbuild/miniupnpc 2012/01/07: The multicast interface can now be specified by name with IPv4. 2012/01/02: Install man page 2011/11/25: added header to Port Mappings list in upnpc.c 2011/10/09: Makefile : make clean now removes jnaerator generated files. MINIUPNPC_VERSION in miniupnpc.h (updated by make) 2011/09/12: added rootdescURL to UPNPUrls structure. VERSION 1.6 : released 2011/07/25 2011/07/25: Update doc for version 1.6 release 2011/06/18: Fix for windows in miniwget.c 2011/06/04: display remote host in port mapping listing 2011/06/03: Fix in make install : there were missing headers 2011/05/26: Fix the socket leak in miniwget thanks to Richard Marsh. Permit to add leaseduration in -a command. Display lease duration. 2011/05/15: Try both LinkLocal and SiteLocal multicast address for SSDP in IPv6 2011/05/09: add a test in testminiwget.sh. more error checking in miniwget.c 2011/05/06: Adding some tool to test and validate miniwget.c simplified and debugged miniwget.c 2011/04/11: moving ReceiveData() to a receivedata.c file. parsing presentation url adding IGD v2 WANIPv6FirewallControl commands 2011/04/10: update of miniupnpcmodule.c comments in miniwget.c, update in testminiwget Adding errors codes from IGD v2 new functions in upnpc.c for IGD v2 2011/04/09: Support for litteral ip v6 address in miniwget 2011/04/08: Adding support for urn:schemas-upnp-org:service:WANIPv6FirewallControl:1 Updating APIVERSION Supporting IPV6 in upnpDiscover() Adding a -6 option to upnpc command line tool 2011/03/18: miniwget/parseURL() : return an error when url param is null. fixing GetListOfPortMappings() 2011/03/14: upnpDiscover() now reporting an error code. improvements in comments. 2011/03/11: adding miniupnpcstrings.h.cmake and CMakeLists.txt files. 2011/02/15: Implementation of GetListOfPortMappings() 2011/02/07: updates to minixml to support character data starting with spaces minixml now support CDATA upnpreplyparse treats specificaly change in simpleUPnPcommand to return the buffer (simplification) 2011/02/06: Added leaseDuration argument to AddPortMapping() Starting to implement GetListOfPortMappings() 2011/01/11: updating wingenminiupnpcstrings.c 2011/01/04: improving updateminiupnpcstrings.sh VERSION 1.5 : released 2011/01/01 2010/12/21: use NO_GETADDRINFO macro to disable the use of getaddrinfo/freeaddrinfo 2010/12/11: Improvements on getHTTPResponse() code. 2010/12/09: new code for miniwget that handle Chunked transfer encoding using getHTTPResponse() in SOAP call code Adding MANIFEST.in for 'python setup.py bdist_rpm' 2010/11/25: changes to minissdpc.c to compile under Win32. see http://miniupnp.tuxfamily.org/forum/viewtopic.php?t=729 2010/09/17: Various improvement to Makefile from MichaÅ‚ Górny 2010/08/05: Adding the script "external-ip.sh" from Reuben Hawkins 2010/06/09: update to python module to match modification made on 2010/04/05 update to Java test code to match modification made on 2010/04/05 all UPNP_* function now return an error if the SOAP request failed at HTTP level. 2010/04/17: Using GetBestRoute() under win32 in order to find the right interface to use. 2010/04/12: Retrying with HTTP/1.1 if HTTP/1.0 failed. see http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=1703 2010/04/07: avoid returning duplicates in upnpDiscover() 2010/04/05: Create a connecthostport.h/.c with connecthostport() function and use it in miniwget and miniupnpc. Use getnameinfo() instead of inet_ntop or inet_ntoa Work to make miniupnpc IPV6 compatible... Add java test code. Big changes in order to support device having both WANIPConnection and WANPPPConnection. 2010/04/04: Use getaddrinfo() instead of gethostbyname() in miniwget. 2010/01/06: #define _DARWIN_C_SOURCE for Mac OS X 2009/12/19: Improve MinGW32 build 2009/12/11: adding a MSVC9 project to build the static library and executable 2009/12/10: Fixing some compilation stuff for Windows/MinGW 2009/12/07: adaptations in Makefile and updateminiupnpcstring.sh for AmigaOS some fixes for Windows when using virtual ethernet adapters (it is the case with VMWare installed). 2009/12/04: some fixes for AmigaOS compilation Changed HTTP version to HTTP/1.0 for Soap too (to prevent chunked transfer encoding) 2009/12/03: updating printIDG and testigddescparse.c for debug. modifications to compile under AmigaOS adding a testminiwget program Changed miniwget to advertise itself as HTTP/1.0 to prevent chunked transfer encoding 2009/11/26: fixing updateminiupnpcstrings.sh to take into account which command that does not return an error code. VERSION 1.4 : released 2009/10/30 2009/10/16: using Py_BEGIN_ALLOW_THREADS and Py_END_ALLOW_THREADS in python module. 2009/10/10: Some fixes for compilation under Solaris compilation fixes : http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=1464 2009/09/21: fixing the code to ignore EINTR during connect() calls. 2009/08/07: Set socket timeout for connect() Some cleanup in miniwget.c 2009/08/04: remove multiple redirections with -d in upnpc.c Print textual error code in upnpc.c Ignore EINTR during the connect() and poll() calls. 2009/07/29: fix in updateminiupnpcstrings.sh if OS name contains "/" Sending a correct value for MX: field in SSDP request 2009/07/20: Change the Makefile to compile under Mac OS X Fixed a stackoverflow in getDevicesFromMiniSSDPD() 2009/07/09: Compile under Haiku generate miniupnpcstrings.h.in from miniupnpcstrings.h 2009/06/04: patching to compile under CygWin and cross compile for minGW VERSION 1.3 : 2009/04/17: updating python module Use strtoull() when using C99 2009/02/28: Fixed miniwget.c for compiling under sun 2008/12/18: cleanup in Makefile (thanks to Paul de Weerd) minissdpc.c : win32 compatibility miniupnpc.c : changed xmlns prefix from 'm' to 'u' Removed NDEBUG (using DEBUG) 2008/10/14: Added the ExternalHost argument to DeletePortMapping() 2008/10/11: Added the ExternalHost argument to AddPortMapping() Put a correct User-Agent: header in HTTP requests. VERSION 1.2 : 2008/10/07: Update docs 2008/09/25: Integrated sameport patch from Dario Meloni : Added a "sameport" argument to upnpDiscover(). 2008/07/18: small modif to make Clang happy :) 2008/07/17: #define SOAPPREFIX "s" in miniupnpc.c in order to remove SOAP-ENV... 2008/07/14: include declspec.h in installation (to /usr/include/miniupnpc) VERSION 1.1 : 2008/07/04: standard options for install/ln instead of gnu-specific stuff. 2008/07/03: now builds a .dll and .lib with win32. (mingw32) 2008/04/28: make install now install the binary of the upnpc tool 2008/04/27: added testupnpigd.py added error strings for miniupnpc "internal" errors improved python module error/exception reporting. 2008/04/23: Completely rewrite igd_desc_parse.c in order to be compatible with Linksys WAG200G Added testigddescparse updated python module VERSION 1.0 : 2008/02/21: put some #ifdef DEBUG around DisplayNameValueList() 2008/02/18: Improved error reporting in upnpcommands.c UPNP_GetStatusInfo() returns LastConnectionError 2008/02/16: better error handling in minisoap.c improving display of "valid IGD found" in upnpc.c 2008/02/03: Fixing UPNP_GetValidIGD() improved make install :) 2007/12/22: Adding upnperrors.c/h to provide a strupnperror() function used to translate UPnP error codes to string. 2007/12/19: Fixing getDevicesFromMiniSSDPD() improved error reporting of UPnP functions 2007/12/18: It is now possible to specify a different location for MiniSSDPd socket. working with MiniSSDPd is now more efficient. python module improved. 2007/12/16: improving error reporting 2007/12/13: Try to improve compatibility by using HTTP/1.0 instead of 1.1 and XML a bit different for SOAP. 2007/11/25: fixed select() call for linux 2007/11/15: Added -fPIC to CFLAG for better shared library code. 2007/11/02: Fixed a potential socket leak in miniwget2() 2007/10/16: added a parameter to upnpDiscover() in order to allow the use of another interface than the default multicast interface. 2007/10/12: Fixed the creation of symbolic link in Makefile 2007/10/08: Added man page 2007/10/02: fixed memory bug in GetUPNPUrls() 2007/10/01: fixes in the Makefile Added UPNP_GetIGDFromUrl() and adapted the sample program accordingly. Added SONAME in the shared library to please debian :) fixed MS Windows compilation (minissdpd is not available under MS Windows). 2007/09/25: small change to Makefile to be able to install in a different location (default is /usr) 2007/09/24: now compiling both shared and static library 2007/09/19: Cosmetic changes on upnpc.c 2007/09/02: adapting to new miniSSDPd (release version ?) 2007/08/31: Usage of miniSSDPd to skip discovery process. 2007/08/27: fixed python module to allow compilation with Python older than Python 2.4 2007/06/12: Added a python module. 2007/05/19: Fixed compilation under MinGW 2007/05/15: fixed a memory leak in AddPortMapping() Added testupnpreplyparse executable to check the parsing of upnp soap messages minixml now ignore namespace prefixes. 2007/04/26: upnpc now displays external ip address with -s or -l 2007/04/11: changed MINIUPNPC_URL_MAXSIZE to 128 to accommodate the "BT Voyager 210" 2007/03/19: cleanup in miniwget.c 2007/03/01: Small typo fix... 2007/01/30: Now parsing the HTTP header from SOAP responses in order to get content-length value. 2007/01/29: Fixed the Soap Query to speedup the HTTP request. added some Win32 DLL stuff... 2007/01/27: Fixed some WIN32 compatibility issues 2006/12/14: Added UPNPIGD_IsConnected() function in miniupnp.c/.h Added UPNP_GetValidIGD() in miniupnp.c/.h cleaned upnpc.c main(). now using UPNP_GetValidIGD() 2006/12/07: Version 1.0-RC1 released 2006/12/03: Minor changes to compile under SunOS/Solaris 2006/11/30: made a minixml parser validator program updated minixml to handle attributes correctly 2006/11/22: Added a -r option to the upnpc sample thanks to Alexander Hubmann. 2006/11/19: Cleanup code to make it more ANSI C compliant 2006/11/10: detect and display local lan address. 2006/11/04: Packets and Bytes Sent/Received are now unsigned int. 2006/11/01: Bug fix thanks to Giuseppe D'Angelo 2006/10/31: C++ compatibility for .h files. Added a way to get ip Address on the LAN used to reach the IGD. 2006/10/25: Added M-SEARCH to the services in the discovery process. 2006/10/22: updated the Makefile to use makedepend, added a "make install" update Makefile 2006/10/20: fixing the description url parsing thanks to patch sent by Wayne Dawe. Fixed/translated some comments. Implemented a better discover process, first looking for IGD then for root devices (as some devices only reply to M-SEARCH for root devices). 2006/09/02: added freeUPNPDevlist() function. 2006/08/04: More command line arguments checking 2006/08/01: Added the .bat file to compile under Win32 with minGW32 2006/07/31: Fixed the rootdesc parser (igd_desc_parse.c) 2006/07/20: parseMSEARCHReply() is now returning the ST: line as well starting changes to detect several UPnP devices on the network 2006/07/19: using GetCommonLinkProperties to get down/upload bitrate miniupnpc-2.2.6/src/minixmlvalid.c010064400017500000024000000070561255150331100163410ustar00nanardstaff/* $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 : * validation program for the minixml parser * * (c) 2006-2011 Thomas Bernard */ #include #include #include #include "minixml.h" /* xml event structure */ struct event { enum { ELTSTART, ELTEND, ATT, CHARDATA } type; const char * data; int len; }; struct eventlist { int n; struct event * events; }; /* compare 2 xml event lists * return 0 if the two lists are equals */ int evtlistcmp(struct eventlist * a, struct eventlist * b) { int i; struct event * ae, * be; if(a->n != b->n) { printf("event number not matching : %d != %d\n", a->n, b->n); /*return 1;*/ } for(i=0; in; i++) { ae = a->events + i; be = b->events + i; if( (ae->type != be->type) ||(ae->len != be->len) ||memcmp(ae->data, be->data, ae->len)) { printf("Found a difference : %d '%.*s' != %d '%.*s'\n", ae->type, ae->len, ae->data, be->type, be->len, be->data); return 1; } } return 0; } /* Test data */ static const char xmldata[] = "\n" " " "character data" " \n \t" "" "\nstuff !\n ]]> \n\n" " \tchardata1 chardata2 " ""; static const struct event evtref[] = { {ELTSTART, "xmlroot", 7}, {ELTSTART, "elt1", 4}, /* attributes */ {CHARDATA, "character data", 14}, {ELTEND, "elt1", 4}, {ELTSTART, "elt1b", 5}, {ELTSTART, "elt1", 4}, {CHARDATA, " stuff !\n ", 16}, {ELTEND, "elt1", 4}, {ELTSTART, "elt2a", 5}, {ELTSTART, "elt2b", 5}, {CHARDATA, "chardata1", 9}, {ELTEND, "elt2b", 5}, {ELTSTART, "elt2b", 5}, {CHARDATA, " chardata2 ", 11}, {ELTEND, "elt2b", 5}, {ELTEND, "elt2a", 5}, {ELTEND, "xmlroot", 7} }; void startelt(void * data, const char * p, int l) { struct eventlist * evtlist = data; struct event * evt; evt = evtlist->events + evtlist->n; /*printf("startelt : %.*s\n", l, p);*/ evt->type = ELTSTART; evt->data = p; evt->len = l; evtlist->n++; } void endelt(void * data, const char * p, int l) { struct eventlist * evtlist = data; struct event * evt; evt = evtlist->events + evtlist->n; /*printf("endelt : %.*s\n", l, p);*/ evt->type = ELTEND; evt->data = p; evt->len = l; evtlist->n++; } void chardata(void * data, const char * p, int l) { struct eventlist * evtlist = data; struct event * evt; evt = evtlist->events + evtlist->n; /*printf("chardata : '%.*s'\n", l, p);*/ evt->type = CHARDATA; evt->data = p; evt->len = l; evtlist->n++; } int testxmlparser(const char * xml, int size) { int r; struct eventlist evtlist; struct eventlist evtlistref; 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; parser.data = &evtlist; parser.starteltfunc = startelt; parser.endeltfunc = endelt; parser.datafunc = chardata; parsexml(&parser); printf("%d events\n", evtlist.n); /* compare */ evtlistref.n = sizeof(evtref)/sizeof(struct event); evtlistref.events = (struct event *)evtref; r = evtlistcmp(&evtlistref, &evtlist); free(evtlist.events); return r; } int main(int argc, char * * argv) { int r; (void)argc; (void)argv; r = testxmlparser(xmldata, sizeof(xmldata)-1); if(r) printf("minixml validation test failed\n"); return r; } miniupnpc-2.2.6/mingw32make.bat010064400017500000024000000003241131314053500155140ustar00nanardstaff@mingw32-make -f Makefile.mingw %1 @if errorlevel 1 goto end @if not exist upnpc-static.exe goto end @strip upnpc-static.exe @upx --best upnpc-static.exe @strip upnpc-shared.exe @upx --best upnpc-shared.exe :end miniupnpc-2.2.6/src/testupnpreplyparse.c010064400017500000024000000044771321374133400176460ustar00nanardstaff/* $Id: testupnpreplyparse.c,v 1.5 2017/12/12 11:18:46 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2017 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ #include #include #include #include "upnpreplyparse.h" int test_parsing(const char * buf, int len, FILE * f) { char line[1024]; struct NameValueParserData pdata; int ok = 1; ParseNameValue(buf, len, &pdata); /* check result */ if(f != NULL) { while(fgets(line, sizeof(line), f)) { char * value; char * equal; char * parsedvalue; int l; l = strlen(line); while((l > 0) && ((line[l-1] == '\r') || (line[l-1] == '\n'))) line[--l] = '\0'; /* skip empty lines */ if(l == 0) continue; equal = strchr(line, '='); if(equal == NULL) { fprintf(stderr, "Warning, line does not contain '=' : %s\n", line); continue; } *equal = '\0'; value = equal + 1; parsedvalue = GetValueFromNameValueList(&pdata, line); if((parsedvalue == NULL) || (strcmp(parsedvalue, value) != 0)) { fprintf(stderr, "Element <%s> : expecting value '%s', got '%s'\n", line, value, parsedvalue ? parsedvalue : ""); ok = 0; } } } ClearNameValueList(&pdata); return ok; } int main(int argc, char * * argv) { FILE * f; char * buffer; long l; int ok; if(argc<2) { fprintf(stderr, "Usage: %s file.xml [file.namevalues]\n", argv[0]); return 1; } f = fopen(argv[1], "r"); if(!f) { fprintf(stderr, "Error : can not open file %s\n", argv[1]); return 2; } if(fseek(f, 0, SEEK_END) < 0) { perror("fseek"); return 1; } l = (int)ftell(f); if(l < 0) { perror("ftell"); return 1; } if(fseek(f, 0, SEEK_SET) < 0) { perror("fseek"); return 1; } buffer = malloc(l + 1); if(buffer == NULL) { fprintf(stderr, "Error: failed to allocate %ld bytes\n", l+1); return 1; } l = fread(buffer, 1, l, f); fclose(f); f = NULL; buffer[l] = '\0'; if(argc > 2) { f = fopen(argv[2], "r"); if(!f) { fprintf(stderr, "Error : can not open file %s\n", argv[2]); return 2; } } #ifdef DEBUG DisplayNameValueList(buffer, l); #endif ok = test_parsing(buffer, l, f); if(f) { fclose(f); } free(buffer); return ok ? 0 : 3; } miniupnpc-2.2.6/src/miniupnpcmodule.c010064400017500000024000000516651417311724100170660ustar00nanardstaff/* $Id: miniupnpcmodule.c,v 1.38 2021/11/09 18:46:49 nanard Exp $*/ /* vim: tabstop=4 shiftwidth=4 noexpandtab * Project : miniupnp * Author : Thomas BERNARD * website : https://miniupnp.tuxfamily.org/ * copyright (c) 2007-2021 Thomas Bernard * This software is subjet to the conditions detailed in the * provided LICENCE file. */ #include #define MINIUPNP_STATICLIB #include #include "miniupnpc.h" #include "upnpcommands.h" #include "upnperrors.h" #ifdef _WIN32 #include #endif /* for compatibility with Python < 2.4 */ #ifndef Py_RETURN_NONE #define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None #endif #ifndef Py_RETURN_TRUE #define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True #endif #ifndef Py_RETURN_FALSE #define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False #endif /* for compatibility with Python < 3.0 */ #ifndef PyVarObject_HEAD_INIT #define PyVarObject_HEAD_INIT(type, size) \ PyObject_HEAD_INIT(type) size, #endif #ifndef Py_TYPE #define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) #endif typedef struct { PyObject_HEAD /* Type-specific fields go here. */ struct UPNPDev * devlist; struct UPNPUrls urls; struct IGDdatas data; unsigned int discoverdelay; /* value passed to upnpDiscover() */ unsigned int localport; /* value passed to upnpDiscover() */ char lanaddr[40]; /* our ip address on the LAN */ char * multicastif; char * minissdpdsocket; } UPnPObject; static PyMemberDef UPnP_members[] = { {"lanaddr", T_STRING_INPLACE, offsetof(UPnPObject, lanaddr), READONLY, "ip address on the LAN" }, {"discoverdelay", T_UINT, offsetof(UPnPObject, discoverdelay), 0/*READWRITE*/, "value in ms used to wait for SSDP responses" }, {"localport", T_UINT, offsetof(UPnPObject, localport), 0/*READWRITE*/, "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" }, /* T_STRING is always readonly :( */ {"multicastif", T_STRING, offsetof(UPnPObject, multicastif), 0, "IP of the network interface to be used for multicast operations" }, {"minissdpdsocket", T_STRING, offsetof(UPnPObject, minissdpdsocket), 0, "path of the MiniSSDPd unix socket" }, {NULL} }; static int UPnP_init(UPnPObject *self, PyObject *args, PyObject *kwds) { char* multicastif = NULL; char* minissdpdsocket = NULL; static char *kwlist[] = { "multicastif", "minissdpdsocket", "discoverdelay", "localport", NULL }; if(!PyArg_ParseTupleAndKeywords(args, kwds, "|zzII", kwlist, &multicastif, &minissdpdsocket, &self->discoverdelay, &self->localport)) return -1; if(self->localport>1 && (self->localport>65534||self->localport<1024)) { PyErr_SetString(PyExc_Exception, "Invalid localport value"); return -1; } if(multicastif) self->multicastif = strdup(multicastif); if(minissdpdsocket) self->minissdpdsocket = strdup(minissdpdsocket); return 0; } static void UPnPObject_dealloc(UPnPObject *self) { freeUPNPDevlist(self->devlist); FreeUPNPUrls(&self->urls); free(self->multicastif); free(self->minissdpdsocket); Py_TYPE(self)->tp_free((PyObject*)self); } static PyObject * UPnP_discover(UPnPObject *self) { int error = 0; PyObject *res = NULL; if(self->devlist) { freeUPNPDevlist(self->devlist); self->devlist = 0; } Py_BEGIN_ALLOW_THREADS self->devlist = upnpDiscover((int)self->discoverdelay/*timeout in ms*/, self->multicastif, self->minissdpdsocket, (int)self->localport, 0/*ip v6*/, 2/* TTL */, &error); Py_END_ALLOW_THREADS /* Py_RETURN_NONE ??? */ if (self->devlist != NULL) { struct UPNPDev * dev; int i = 0; for(dev = self->devlist; dev; dev = dev->pNext) i++; res = Py_BuildValue("i", i); return res; } else { PyErr_SetString(PyExc_Exception, strupnperror(error)); return NULL; } } static PyObject * UPnP_selectigd(UPnPObject *self, PyObject *args) { const char * rootDescUrl = NULL; int r; if(!PyArg_ParseTuple(args, "|z", &rootDescUrl)) return NULL; Py_BEGIN_ALLOW_THREADS if (rootDescUrl == NULL) { r = UPNP_GetValidIGD(self->devlist, &self->urls, &self->data, self->lanaddr, sizeof(self->lanaddr)); } else { r = UPNP_GetIGDFromUrl(rootDescUrl, &self->urls, &self->data, self->lanaddr, sizeof(self->lanaddr)); } Py_END_ALLOW_THREADS if(r) { return Py_BuildValue("s", self->urls.controlURL); } else { /* TODO: have our own exception type ! */ PyErr_SetString(PyExc_Exception, "No UPnP device discovered"); return NULL; } } static PyObject * UPnP_totalbytesent(UPnPObject *self) { UNSIGNED_INTEGER i; Py_BEGIN_ALLOW_THREADS i = UPNP_GetTotalBytesSent(self->urls.controlURL_CIF, self->data.CIF.servicetype); Py_END_ALLOW_THREADS #if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3) return Py_BuildValue("I", i); #else return Py_BuildValue("i", (int)i); #endif } static PyObject * UPnP_totalbytereceived(UPnPObject *self) { UNSIGNED_INTEGER i; Py_BEGIN_ALLOW_THREADS i = UPNP_GetTotalBytesReceived(self->urls.controlURL_CIF, self->data.CIF.servicetype); Py_END_ALLOW_THREADS #if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3) return Py_BuildValue("I", i); #else return Py_BuildValue("i", (int)i); #endif } static PyObject * UPnP_totalpacketsent(UPnPObject *self) { UNSIGNED_INTEGER i; Py_BEGIN_ALLOW_THREADS i = UPNP_GetTotalPacketsSent(self->urls.controlURL_CIF, self->data.CIF.servicetype); Py_END_ALLOW_THREADS #if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3) return Py_BuildValue("I", i); #else return Py_BuildValue("i", (int)i); #endif } static PyObject * UPnP_totalpacketreceived(UPnPObject *self) { UNSIGNED_INTEGER i; Py_BEGIN_ALLOW_THREADS i = UPNP_GetTotalPacketsReceived(self->urls.controlURL_CIF, self->data.CIF.servicetype); Py_END_ALLOW_THREADS #if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3) return Py_BuildValue("I", i); #else return Py_BuildValue("i", (int)i); #endif } static PyObject * UPnP_statusinfo(UPnPObject *self) { char status[64]; char lastconnerror[64]; unsigned int uptime = 0; int r; status[0] = '\0'; lastconnerror[0] = '\0'; Py_BEGIN_ALLOW_THREADS r = UPNP_GetStatusInfo(self->urls.controlURL, self->data.first.servicetype, status, &uptime, lastconnerror); Py_END_ALLOW_THREADS if(r==UPNPCOMMAND_SUCCESS) { #if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3) return Py_BuildValue("(s,I,s)", status, uptime, lastconnerror); #else return Py_BuildValue("(s,i,s)", status, (int)uptime, lastconnerror); #endif } else { /* TODO: have our own exception type ! */ PyErr_SetString(PyExc_Exception, strupnperror(r)); return NULL; } } static PyObject * UPnP_connectiontype(UPnPObject *self) { char connectionType[64]; int r; connectionType[0] = '\0'; Py_BEGIN_ALLOW_THREADS r = UPNP_GetConnectionTypeInfo(self->urls.controlURL, self->data.first.servicetype, connectionType); Py_END_ALLOW_THREADS if(r==UPNPCOMMAND_SUCCESS) { return Py_BuildValue("s", connectionType); } else { /* TODO: have our own exception type ! */ PyErr_SetString(PyExc_Exception, strupnperror(r)); return NULL; } } static PyObject * UPnP_externalipaddress(UPnPObject *self) { char externalIPAddress[40]; int r; externalIPAddress[0] = '\0'; Py_BEGIN_ALLOW_THREADS r = UPNP_GetExternalIPAddress(self->urls.controlURL, self->data.first.servicetype, externalIPAddress); Py_END_ALLOW_THREADS if(r==UPNPCOMMAND_SUCCESS) { return Py_BuildValue("s", externalIPAddress); } else { /* TODO: have our own exception type ! */ PyErr_SetString(PyExc_Exception, strupnperror(r)); return NULL; } } /* AddPortMapping(externalPort, protocol, internalHost, internalPort, desc, * remoteHost, leaseDuration) * protocol is 'UDP' or 'TCP' */ static PyObject * UPnP_addportmapping(UPnPObject *self, PyObject *args) { char extPort[6]; unsigned short ePort; char inPort[6]; unsigned short iPort; const char * proto; const char * host; const char * desc; const char * remoteHost; unsigned int intLeaseDuration = 0; char strLeaseDuration[12]; int r; #if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3) if (!PyArg_ParseTuple(args, "HssHzz|I", &ePort, &proto, &host, &iPort, &desc, &remoteHost, &intLeaseDuration)) #else if (!PyArg_ParseTuple(args, "HssHzz|i", &ePort, &proto, &host, &iPort, &desc, &remoteHost, (int *)&intLeaseDuration)) #endif return NULL; Py_BEGIN_ALLOW_THREADS sprintf(extPort, "%hu", ePort); sprintf(inPort, "%hu", iPort); sprintf(strLeaseDuration, "%u", intLeaseDuration); r = UPNP_AddPortMapping(self->urls.controlURL, self->data.first.servicetype, extPort, inPort, host, desc, proto, remoteHost, strLeaseDuration); Py_END_ALLOW_THREADS if(r==UPNPCOMMAND_SUCCESS) { Py_RETURN_TRUE; } else { // TODO: RAISE an Exception. See upnpcommands.h for errors codes. // upnperrors.c //Py_RETURN_FALSE; /* TODO: have our own exception type ! */ PyErr_SetString(PyExc_Exception, strupnperror(r)); return NULL; } } /* AddAnyPortMapping(externalPort, protocol, internalHost, internalPort, desc, * remoteHost) * protocol is 'UDP' or 'TCP' */ static PyObject * UPnP_addanyportmapping(UPnPObject *self, PyObject *args) { char extPort[6]; unsigned short ePort; char inPort[6]; unsigned short iPort; char reservedPort[6]; const char * proto; const char * host; const char * desc; const char * remoteHost; const char * leaseDuration = "0"; int r; if (!PyArg_ParseTuple(args, "HssHzz", &ePort, &proto, &host, &iPort, &desc, &remoteHost)) return NULL; Py_BEGIN_ALLOW_THREADS sprintf(extPort, "%hu", ePort); sprintf(inPort, "%hu", iPort); r = UPNP_AddAnyPortMapping(self->urls.controlURL, self->data.first.servicetype, extPort, inPort, host, desc, proto, remoteHost, leaseDuration, reservedPort); Py_END_ALLOW_THREADS if(r==UPNPCOMMAND_SUCCESS) { return Py_BuildValue("i", atoi(reservedPort)); } else { /* TODO: have our own exception type ! */ PyErr_SetString(PyExc_Exception, strupnperror(r)); return NULL; } } /* DeletePortMapping(extPort, proto, removeHost='') * proto = 'UDP', 'TCP' */ static PyObject * UPnP_deleteportmapping(UPnPObject *self, PyObject *args) { char extPort[6]; unsigned short ePort; const char * proto; const char * remoteHost = ""; int r; if(!PyArg_ParseTuple(args, "Hs|z", &ePort, &proto, &remoteHost)) return NULL; Py_BEGIN_ALLOW_THREADS sprintf(extPort, "%hu", ePort); r = UPNP_DeletePortMapping(self->urls.controlURL, self->data.first.servicetype, extPort, proto, remoteHost); Py_END_ALLOW_THREADS if(r==UPNPCOMMAND_SUCCESS) { Py_RETURN_TRUE; } else { /* TODO: have our own exception type ! */ PyErr_SetString(PyExc_Exception, strupnperror(r)); return NULL; } } /* DeletePortMappingRange(extPort, proto, removeHost='') * proto = 'UDP', 'TCP' */ static PyObject * UPnP_deleteportmappingrange(UPnPObject *self, PyObject *args) { char extPortStart[6]; unsigned short ePortStart; char extPortEnd[6]; unsigned short ePortEnd; const char * proto; unsigned char manage; char manageStr[6]; int r; if(!PyArg_ParseTuple(args, "HHsb", &ePortStart, &ePortEnd, &proto, &manage)) return NULL; Py_BEGIN_ALLOW_THREADS sprintf(extPortStart, "%hu", ePortStart); sprintf(extPortEnd, "%hu", ePortEnd); sprintf(manageStr, "%hu", (unsigned short)manage); r = UPNP_DeletePortMappingRange(self->urls.controlURL, self->data.first.servicetype, extPortStart, extPortEnd, proto, manageStr); Py_END_ALLOW_THREADS if(r==UPNPCOMMAND_SUCCESS) { Py_RETURN_TRUE; } else { /* TODO: have our own exception type ! */ PyErr_SetString(PyExc_Exception, strupnperror(r)); return NULL; } } static PyObject * UPnP_getportmappingnumberofentries(UPnPObject *self) { unsigned int n = 0; int r; Py_BEGIN_ALLOW_THREADS r = UPNP_GetPortMappingNumberOfEntries(self->urls.controlURL, self->data.first.servicetype, &n); Py_END_ALLOW_THREADS if(r==UPNPCOMMAND_SUCCESS) { #if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3) return Py_BuildValue("I", n); #else return Py_BuildValue("i", (int)n); #endif } else { /* TODO: have our own exception type ! */ PyErr_SetString(PyExc_Exception, strupnperror(r)); return NULL; } } /* GetSpecificPortMapping(ePort, proto, remoteHost='') * proto = 'UDP' or 'TCP' */ static PyObject * UPnP_getspecificportmapping(UPnPObject *self, PyObject *args) { char extPort[6]; unsigned short ePort; const char * proto; const char * remoteHost = ""; char intClient[40]; char intPort[6]; unsigned short iPort; char desc[80]; char enabled[4]; char leaseDuration[16]; if(!PyArg_ParseTuple(args, "Hs|z", &ePort, &proto, &remoteHost)) return NULL; extPort[0] = '\0'; intClient[0] = '\0'; intPort[0] = '\0'; desc[0] = '\0'; enabled[0] = '\0'; leaseDuration[0] = '\0'; Py_BEGIN_ALLOW_THREADS sprintf(extPort, "%hu", ePort); UPNP_GetSpecificPortMappingEntry(self->urls.controlURL, self->data.first.servicetype, extPort, proto, remoteHost, intClient, intPort, desc, enabled, leaseDuration); Py_END_ALLOW_THREADS if(intClient[0]) { iPort = (unsigned short)atoi(intPort); return Py_BuildValue("(s,H,s,O,i)", intClient, iPort, desc, PyBool_FromLong(atoi(enabled)), atoi(leaseDuration)); } else { Py_RETURN_NONE; } } /* GetGenericPortMapping(index) */ static PyObject * UPnP_getgenericportmapping(UPnPObject *self, PyObject *args) { int i, r; char index[8]; char intClient[40]; char intPort[6]; unsigned short iPort; char extPort[6]; unsigned short ePort; char protocol[4]; char desc[80]; char enabled[6]; char rHost[64]; char duration[16]; /* lease duration */ unsigned int dur; if(!PyArg_ParseTuple(args, "i", &i)) return NULL; Py_BEGIN_ALLOW_THREADS snprintf(index, sizeof(index), "%d", i); rHost[0] = '\0'; enabled[0] = '\0'; duration[0] = '\0'; desc[0] = '\0'; extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0'; r = UPNP_GetGenericPortMappingEntry(self->urls.controlURL, self->data.first.servicetype, index, extPort, intClient, intPort, protocol, desc, enabled, rHost, duration); Py_END_ALLOW_THREADS if(r==UPNPCOMMAND_SUCCESS) { ePort = (unsigned short)atoi(extPort); iPort = (unsigned short)atoi(intPort); dur = (unsigned int)strtoul(duration, 0, 0); #if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3) return Py_BuildValue("(H,s,(s,H),s,s,s,I)", ePort, protocol, intClient, iPort, desc, enabled, rHost, dur); #else return Py_BuildValue("(i,s,(s,i),s,s,s,i)", (int)ePort, protocol, intClient, (int)iPort, desc, enabled, rHost, (int)dur); #endif } else { Py_RETURN_NONE; } } /* miniupnpc.UPnP object Method Table */ static PyMethodDef UPnP_methods[] = { {"discover", (PyCFunction)UPnP_discover, METH_NOARGS, "discover UPnP IGD devices on the network" }, {"selectigd", (PyCFunction)UPnP_selectigd, METH_VARARGS, "select a valid UPnP IGD among discovered devices" }, {"totalbytesent", (PyCFunction)UPnP_totalbytesent, METH_NOARGS, "return the total number of bytes sent by UPnP IGD" }, {"totalbytereceived", (PyCFunction)UPnP_totalbytereceived, METH_NOARGS, "return the total number of bytes received by UPnP IGD" }, {"totalpacketsent", (PyCFunction)UPnP_totalpacketsent, METH_NOARGS, "return the total number of packets sent by UPnP IGD" }, {"totalpacketreceived", (PyCFunction)UPnP_totalpacketreceived, METH_NOARGS, "return the total number of packets received by UPnP IGD" }, {"statusinfo", (PyCFunction)UPnP_statusinfo, METH_NOARGS, "return status and uptime" }, {"connectiontype", (PyCFunction)UPnP_connectiontype, METH_NOARGS, "return IGD WAN connection type" }, {"externalipaddress", (PyCFunction)UPnP_externalipaddress, METH_NOARGS, "return external IP address" }, {"addportmapping", (PyCFunction)UPnP_addportmapping, METH_VARARGS, "add a port mapping" }, {"addanyportmapping", (PyCFunction)UPnP_addanyportmapping, METH_VARARGS, "add a port mapping, IGD to select alternative if necessary" }, {"deleteportmapping", (PyCFunction)UPnP_deleteportmapping, METH_VARARGS, "delete a port mapping" }, {"deleteportmappingrange", (PyCFunction)UPnP_deleteportmappingrange, METH_VARARGS, "delete a range of port mappings" }, {"getportmappingnumberofentries", (PyCFunction)UPnP_getportmappingnumberofentries, METH_NOARGS, "-- non standard --" }, {"getspecificportmapping", (PyCFunction)UPnP_getspecificportmapping, METH_VARARGS, "get details about a specific port mapping entry" }, {"getgenericportmapping", (PyCFunction)UPnP_getgenericportmapping, METH_VARARGS, "get all details about the port mapping at index" }, {NULL} /* Sentinel */ }; static PyTypeObject UPnPType = { PyVarObject_HEAD_INIT(NULL, 0) /*ob_size*/ "miniupnpc.UPnP", /*tp_name*/ sizeof(UPnPObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ (destructor)UPnPObject_dealloc,/*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash */ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ "UPnP objects", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ UPnP_methods, /* tp_methods */ UPnP_members, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)UPnP_init, /* tp_init */ 0, /* tp_alloc */ #ifndef _WIN32 PyType_GenericNew,/*UPnP_new,*/ /* tp_new */ #else 0, /* tp_new */ #endif 0, /* tp_free */ }; /* module methods */ static PyMethodDef miniupnpc_methods[] = { {NULL} /* Sentinel */ }; #if PY_MAJOR_VERSION >= 3 static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "miniupnpc", /* m_name */ "miniupnpc module.", /* m_doc */ -1, /* m_size */ miniupnpc_methods, /* m_methods */ NULL, /* m_reload */ NULL, /* m_traverse */ NULL, /* m_clear */ NULL, /* m_free */ }; #endif #ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ #define PyMODINIT_FUNC void #endif PyMODINIT_FUNC #if PY_MAJOR_VERSION >= 3 PyInit_miniupnpc(void) #else initminiupnpc(void) #endif { PyObject* m; #ifdef _WIN32 /* initialize Winsock. */ WSADATA wsaData; int nResult = WSAStartup(MAKEWORD(2,2), &wsaData); if (nResult != 0) { /* error code could be WSASYSNOTREADY WSASYSNOTREADY * WSASYSNOTREADY WSASYSNOTREADY WSASYSNOTREADY */ #if PY_MAJOR_VERSION >= 3 return 0; #else return; #endif } UPnPType.tp_new = PyType_GenericNew; #endif if (PyType_Ready(&UPnPType) < 0) #if PY_MAJOR_VERSION >= 3 return 0; #else return; #endif #if PY_MAJOR_VERSION >= 3 m = PyModule_Create(&moduledef); #else m = Py_InitModule3("miniupnpc", miniupnpc_methods, "miniupnpc module."); #endif Py_INCREF(&UPnPType); PyModule_AddObject(m, "UPnP", (PyObject *)&UPnPType); #if PY_MAJOR_VERSION >= 3 return m; #endif } miniupnpc-2.2.6/pymoduletest.py010064400017500000024000000056131417311724100160230ustar00nanardstaff#! /usr/bin/env python # vim: tabstop=2 shiftwidth=2 expandtab # MiniUPnP project # Author : Thomas Bernard # Python 3 # This Sample code is public domain. # website : https://miniupnp.tuxfamily.org/ # import the python miniupnpc module import miniupnpc import sys try: import argparse parser = argparse.ArgumentParser() parser.add_argument('-m', '--multicastif') parser.add_argument('-p', '--minissdpdsocket') parser.add_argument('-d', '--discoverdelay', type=int, default=200) parser.add_argument('-z', '--localport', type=int, default=0) # create the object u = miniupnpc.UPnP(**vars(parser.parse_args())) except: print('argparse not available') i = 1 multicastif = None minissdpdsocket = None discoverdelay = 200 localport = 0 while i < len(sys.argv): print(sys.argv[i]) if sys.argv[i] == '-m' or sys.argv[i] == '--multicastif': multicastif = sys.argv[i+1] elif sys.argv[i] == '-p' or sys.argv[i] == '--minissdpdsocket': minissdpdsocket = sys.argv[i+1] elif sys.argv[i] == '-d' or sys.argv[i] == '--discoverdelay': discoverdelay = int(sys.argv[i+1]) elif sys.argv[i] == '-z' or sys.argv[i] == '--localport': localport = int(sys.argv[i+1]) else: raise Exception('invalid argument %s' % sys.argv[i]) i += 2 # create the object u = miniupnpc.UPnP(multicastif, minissdpdsocket, discoverdelay, localport) print('inital(default) values :') print(' discoverdelay', u.discoverdelay) print(' lanaddr', u.lanaddr) print(' multicastif', u.multicastif) print(' minissdpdsocket', u.minissdpdsocket) #u.minissdpdsocket = '../minissdpd/minissdpd.sock' # discovery process, it usually takes several seconds (2 seconds or more) print('Discovering... delay=%ums' % u.discoverdelay) print('%d device(s) detected' % u.discover()) # select an igd try: u.selectigd() except Exception as e: print('Exception :', e) sys.exit(1) # it is also possible to pass the root description URL to u.selectigd() : # u.selectigd('http://192.168.1.254:5678/desc/root') # display information about the IGD and the internet connection print('local ip address :', u.lanaddr) print('external ip address :', u.externalipaddress()) print( u.statusinfo(), u.connectiontype()) print('total bytes : sent', u.totalbytesent(), 'received', u.totalbytereceived()) print('total packets : sent', u.totalpacketsent(), 'received', u.totalpacketreceived()) #print u.addportmapping(64000, 'TCP', # '192.168.1.166', 63000, 'port mapping test', '') #print u.deleteportmapping(64000, 'TCP') port = 0 proto = 'UDP' # list the redirections : i = 0 while True: p = u.getgenericportmapping(i) if p==None: break print(i, p) (port, proto, (ihost,iport), desc, c, d, e) = p #print port, desc i = i + 1 print(u.getspecificportmapping(port, proto)) try: print(u.getportmappingnumberofentries()) except Exception as e: print('GetPortMappingNumberOfEntries() is not supported :', e) miniupnpc-2.2.6/setup.py010064400017500000024000000021751412470240300144210ustar00nanardstaff#! /usr/bin/env python # vim: tabstop=8 shiftwidth=8 expandtab # $Id: setup.py,v 1.15 2021/09/28 21:10:11 nanard Exp $ # the MiniUPnP Project (c) 2007-2021 Thomas Bernard # https://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/ # # python script to build the miniupnpc module under unix # # Uses MAKE environment variable (defaulting to 'make') from setuptools import setup, Extension from setuptools.command import build_ext import subprocess import os EXT = ['build/libminiupnpc.a'] class make_then_build_ext(build_ext.build_ext): def run(self): subprocess.check_call([os.environ.get('MAKE', 'make')] + EXT) build_ext.build_ext.run(self) setup(name="miniupnpc", version=open('VERSION').read().strip(), author='Thomas BERNARD', author_email='miniupnp@free.fr', license=open('LICENSE').read(), url='http://miniupnp.free.fr/', description='miniUPnP client', cmdclass={'build_ext': make_then_build_ext}, ext_modules=[ Extension(name="miniupnpc", sources=["src/miniupnpcmodule.c"], include_dirs=['include'], extra_objects=EXT) ]) miniupnpc-2.2.6/setupmingw32.py010064400017500000024000000023021412470240300156200ustar00nanardstaff#! /usr/bin/env python # vim: tabstop=8 shiftwidth=8 expandtab # $Id: setupmingw32.py,v 1.14 2021/09/28 21:10:11 nanard Exp $ # the MiniUPnP Project (c) 2007-2021 Thomas Bernard # https://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/ # # python script to build the miniupnpc module under windows (using mingw32) # import sys if (sys.version_info.major * 10 + sys.version_info.minor) >= 35: compat_lib = ["legacy_stdio_definitions"] else: compat_lib = [] try: from setuptools import setup, Extension except ImportError: from distutils.core import setup, Extension from distutils import sysconfig sysconfig.get_config_vars()["OPT"] = '' sysconfig.get_config_vars()["CFLAGS"] = '' setup(name="miniupnpc", version=open('VERSION').read().strip(), author='Thomas BERNARD', author_email='miniupnp@free.fr', license=open('LICENSE').read(), url='http://miniupnp.free.fr/', description='miniUPnP client', ext_modules=[ Extension(name="miniupnpc", sources=["src/miniupnpcmodule.c"], libraries=["ws2_32", "iphlpapi"] + compat_lib, include_dirs=['include'], extra_objects=["miniupnpc.lib"]) ]) miniupnpc-2.2.6/src/minissdpc.h010064400017500000024000000031401343001453300156300ustar00nanardstaff/* $Id: minissdpc.h,v 1.8 2019/02/10 12:29:23 nanard Exp $ */ /* Project: miniupnp * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * Author: 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 #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 s); MINIUPNP_LIBSPEC int requestDevicesFromMiniSSDPD(int s, const char * devtype); MINIUPNP_LIBSPEC struct UPNPDev * receiveDevicesFromMiniSSDPD(int s, 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 miniupnpc-2.2.6/src/minissdpc.c010064400017500000024000000702441454537750100156530ustar00nanardstaff/* $Id: minissdpc.c,v 1.50 2024/01/04 00:35:53 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * Project : miniupnp * Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * Author : Thomas BERNARD * copyright (c) 2005-2021 Thomas Bernard * This software is subjet to the conditions detailed in the * provided LICENCE file. */ #include #include #include #include #include #if defined (__NetBSD__) #include #endif #if defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__) #ifdef _WIN32 #include #include #include #include #include "win32_snprintf.h" #if !defined(_MSC_VER) #include #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 */ #if defined(WINAPI_FAMILY) && defined(WINAPI_FAMILY_PARTITION) #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP #define in6addr_any in6addr_any_init static const IN6_ADDR in6addr_any_init = {0}; #endif #endif #endif /* _WIN32 */ #if defined(__amigaos__) || defined(__amigaos4__) #include #endif /* defined(__amigaos__) || defined(__amigaos4__) */ #if defined(__amigaos__) #define uint16_t unsigned short #endif /* defined(__amigaos__) */ /* Hack */ #define UNIX_PATH_LEN 108 struct sockaddr_un { uint16_t sun_family; char sun_path[UNIX_PATH_LEN]; }; #else /* defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__) */ #include #include #include #include #include #include #include #include #include #include #define closesocket close #endif #include "miniupnpc_socketdef.h" #if !defined(__DragonFly__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__APPLE__) && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__sun) && !defined(__GNU__) && !defined(__FreeBSD_kernel__) && !defined(__HAIKU__) #define HAS_IP_MREQN #endif #ifndef _WIN32 #include #if defined(__sun) || defined(__HAIKU__) #include #endif #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, int * error) { struct UPNPDev * devlist = NULL; 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; #if defined(MINIUPNPC_SET_SOCKET_TIMEOUT) && !defined(__sun) 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 MINISSDPC_SOCKET_ERROR; } #if defined(MINIUPNPC_SET_SOCKET_TIMEOUT) && !defined(__sun) /* setting a 3 seconds timeout */ /* not supported for AF_UNIX sockets under Solaris */ timeout.tv_sec = 3; timeout.tv_usec = 0; if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0) { perror("setsockopt SO_RCVTIMEO unix"); } timeout.tv_sec = 3; timeout.tv_usec = 0; if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0) { perror("setsockopt SO_SNDTIMEO unix"); } #endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ if(!socketpath) socketpath = "/var/run/minissdpd.sock"; memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, socketpath, sizeof(addr.sun_path)); /* TODO : check if we need to handle the EINTR */ if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) { /*syslog(LOG_WARNING, "connect(\"%s\"): %m", socketpath);*/ close(s); 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)) { buffer[0] = 3; /* request type 3 : everything */ } else { buffer[0] = 1; /* request type 1 : request devices/services by type */ } p = buffer + 1; l = stsize; CODELENGTH(l, p); if(p + stsize > buffer + sizeof(buffer)) { /* devtype is too long ! */ #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; if(write(s, buffer, p - buffer) < 0) { /*syslog(LOG_ERR, "write(): %m");*/ perror("minissdpc.c: write()"); 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()"); if (error) *error = MINISSDPC_SOCKET_ERROR; return NULL; } ndev = buffer[0]; bufferindex = 1; for(i = 0; i < ndev; i++) { 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+3); 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->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; } 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. * - usn/usnsize : "usn:" filed 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= 0x0600 // _WIN32_WINNT_VISTA ULONGLONG ts = GetTickCount64(); #else DWORD ts = GetTickCount(); #endif tv->tv_sec = (long)(ts / 1000); tv->tv_usec = (ts % 1000) * 1000; return 0; /* success */ #elif defined(CLOCK_MONOTONIC_FAST) || defined(CLOCK_MONOTONIC) #if defined(__APPLE__) #if defined(__clang__) if (__builtin_available(macOS 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *)) { #else /* !defined(__clang__) */ if (clock_gettime != NULL) { #endif /* defined(__clang__) */ #endif /* defined(__APPLE__) */ struct timespec ts; int ret_code = clock_gettime(UPNP_CLOCKID, &ts); if (ret_code == 0) { tv->tv_sec = ts.tv_sec; tv->tv_usec = ts.tv_nsec / 1000; } return ret_code; #if defined(__APPLE__) } else { /* fall-back for earlier Apple platforms */ return gettimeofday(tv, NULL); } #endif /* defined(__APPLE__) */ #else return gettimeofday(tv, NULL); #endif } /* port upnp discover : SSDP protocol */ #define SSDP_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 = NULL; unsigned int scope_id = 0; int opt = 1; static const char MSearchMsgFmt[] = "M-SEARCH * HTTP/1.1\r\n" "HOST: %s:" XSTR(SSDP_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 */ SOCKET 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; #endif #ifdef _WIN32 unsigned long _ttl = (unsigned long)ttl; #endif int linklocal = 1; int sentok; if(error) *error = MINISSDPC_UNKNOWN_ERROR; if(localport==UPNP_LOCAL_PORT_SAME) localport = SSDP_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(ISINVALID(sudp)) { 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) { DWORD ifbestidx; #if _WIN32_WINNT >= 0x0600 // _WIN32_WINNT_VISTA // While we don't need IPv6 support, the IPv4 only funciton is not available in UWP apps. SOCKADDR_IN destAddr; memset(&destAddr, 0, sizeof(destAddr)); destAddr.sin_family = AF_INET; destAddr.sin_addr.s_addr = inet_addr("223.255.255.255"); destAddr.sin_port = 0; if (GetBestInterfaceEx((struct sockaddr *)&destAddr, &ifbestidx) == NO_ERROR) { #else if (GetBestInterface(inet_addr("223.255.255.255"), &ifbestidx) == NO_ERROR) { #endif DWORD dwRetVal = NO_ERROR; PIP_ADAPTER_ADDRESSES pAddresses = NULL; ULONG outBufLen = 15360; int Iterations; PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL; for (Iterations = 0; Iterations < 3; Iterations++) { pAddresses = (IP_ADAPTER_ADDRESSES *) HeapAlloc(GetProcessHeap(), 0, outBufLen); if (pAddresses == NULL) { break; } dwRetVal = GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &outBufLen); if (dwRetVal != ERROR_BUFFER_OVERFLOW) { break; } HeapFree(GetProcessHeap(), 0, pAddresses); pAddresses = NULL; } if (dwRetVal == NO_ERROR) { pCurrAddresses = pAddresses; while (pCurrAddresses) { #ifdef DEBUG int i; PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL; PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL; printf("\tIfIndex (IPv4 interface): %u\n", pCurrAddresses->IfIndex); printf("\tAdapter name: %s\n", pCurrAddresses->AdapterName); pUnicast = pCurrAddresses->FirstUnicastAddress; if (pUnicast != NULL) { for (i = 0; pUnicast != NULL; i++) { printf("\tIP Address[%d]: \t%s\n", i, inet_ntoa(((PSOCKADDR_IN)pUnicast->Address.lpSockaddr)->sin_addr) ); pUnicast = pUnicast->Next; } printf("\tNumber of Unicast Addresses: %d\n", i); } pAnycast = pCurrAddresses->FirstAnycastAddress; if (pAnycast) { for (i = 0; pAnycast != NULL; i++) { printf("\tAnycast Address[%d]: \t%s\n", i, inet_ntoa(((PSOCKADDR_IN)pAnycast->Address.lpSockaddr)->sin_addr) ); pAnycast = pAnycast->Next; } printf("\tNumber of Anycast Addresses: %d\n", i); } pMulticast = pCurrAddresses->FirstMulticastAddress; if (pMulticast) { for (i = 0; pMulticast != NULL; i++) { printf("\tMulticast Address[%d]: \t%s\n", i, inet_ntoa(((PSOCKADDR_IN)pMulticast->Address.lpSockaddr)->sin_addr) ); pMulticast = pMulticast->Next; } } printf("\n"); #endif pUnicast = pCurrAddresses->FirstUnicastAddress; if (pCurrAddresses->IfIndex == ifbestidx && pUnicast != NULL) { SOCKADDR_IN *ipv4 = (SOCKADDR_IN *)(pUnicast->Address.lpSockaddr); /* 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 = ipv4->sin_addr.s_addr; 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 = ipv4->sin_addr.s_addr; #ifndef DEBUG break; #endif } pCurrAddresses = pCurrAddresses->Next; } } if (pAddresses != NULL) { HeapFree(GetProcessHeap(), 0, pAddresses); pAddresses = 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,...)"); goto error; } if(ipv6) { #ifdef _WIN32 DWORD mcastHops = ttl; if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (const char *)&mcastHops, sizeof(mcastHops)) < 0) #else /* _WIN32 */ int mcastHops = ttl; if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &mcastHops, sizeof(mcastHops)) < 0) #endif /* _WIN32 */ { PRINT_SOCKET_ERROR("setsockopt(IPV6_MULTICAST_HOPS,...)"); } } else { #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 && multicastif[0] != '\0') { 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(ifindex == 0) { if(error) *error = MINISSDPC_INVALID_INPUT; fprintf(stderr, "Invalid multicast interface name %s\n", multicastif); goto error; } if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)) < 0) { PRINT_SOCKET_ERROR("setsockopt IPV6_MULTICAST_IF"); } #else #ifdef DEBUG printf("Setting of multicast interface not supported in IPv6 under Windows.\n"); #endif #endif } else { struct in_addr mc_if; #if defined(_WIN32) #if _WIN32_WINNT >= 0x0600 // _WIN32_WINNT_VISTA InetPtonA(AF_INET, multicastif, &mc_if); #else mc_if.s_addr = inet_addr(multicastif); /* old Windows SDK do not support InetPtoA() */ #endif #else /* was : mc_if.s_addr = inet_addr(multicastif); */ /* ex: 192.168.x.x */ if (inet_pton(AF_INET, multicastif, &mc_if.s_addr) <= 0) { mc_if.s_addr = INADDR_NONE; } #endif 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 IP_MULTICAST_IF"); } } else { /* was not an ip address, try with an interface name */ #ifndef _WIN32 #ifdef HAS_IP_MREQN struct ip_mreqn reqn; /* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */ #endif struct ifreq ifr; int ifrlen = sizeof(ifr); strncpy(ifr.ifr_name, multicastif, IFNAMSIZ); ifr.ifr_name[IFNAMSIZ-1] = '\0'; if(ioctl(sudp, SIOCGIFADDR, &ifr, &ifrlen) < 0) { PRINT_SOCKET_ERROR("ioctl(...SIOCGIFADDR...)"); goto error; } mc_if.s_addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr; #ifdef HAS_IP_MREQN memset(&reqn, 0, sizeof(struct ip_mreqn)); reqn.imr_address.s_addr = mc_if.s_addr; reqn.imr_ifindex = if_nametoindex(multicastif); if(reqn.imr_ifindex == 0) { if(error) *error = MINISSDPC_INVALID_INPUT; fprintf(stderr, "Invalid multicast ip address / interface name %s\n", multicastif); goto error; } if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0) { PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF"); } #else if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) { PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF"); } #endif #else /* _WIN32 */ #ifdef DEBUG printf("Setting of multicast interface not supported with interface name.\n"); #endif #endif /* #ifdef HAS_IP_MREQN / !defined(_WIN32) */ } } } /* 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++) { sentok = 0; /* 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); if ((unsigned int)n >= sizeof(bufr)) { if(error) *error = MINISSDPC_MEMORY_ERROR; goto error; } #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(SSDP_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(SSDP_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"); } else { sentok = 1; } #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(SSDP_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; } else { struct addrinfo *p; for(p = servinfo; p; p = p->ai_next) { n = sendto(sudp, bufr, n, 0, p->ai_addr, MSC_CAST_INT p->ai_addrlen); if (n < 0) { #ifdef DEBUG char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; if (getnameinfo(p->ai_addr, (socklen_t)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; } else { sentok = 1; } } freeaddrinfo(servinfo); } if(!sentok) { if(error) *error = MINISSDPC_SOCKET_ERROR; } #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((sentok && !searchalltypes) || !deviceTypes[deviceIndex + 1]) { struct timeval start = {0, 0}, current = {0, 0}; upnp_gettimeofday(&start); 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(strncmp(tmp->descURL, descURL, urlsize) == 0 && tmp->descURL[urlsize] == '\0' && strncmp(tmp->st, st, stsize) == 0 && tmp->st[stsize] == '\0' && (usnsize == 0 || strncmp(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+3); 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; } if (upnp_gettimeofday(¤t) >= 0) { /* exit the loop if delay is reached */ long interval = (current.tv_sec - start.tv_sec) * 1000; interval += (current.tv_usec - start.tv_usec) / 1000; if (interval > (long)delay) break; } } } while(n > 0); } if(ipv6) { /* switch linklocal flag */ if(linklocal) { linklocal = 0; --deviceIndex; } else { linklocal = 1; } } } error: closesocket(sudp); return devlist; } miniupnpc-2.2.6/man3/miniupnpc.3010064400017500000024000000055001323543256400156400ustar00nanardstaff.TH MINIUPNPC 3 .SH NAME miniupnpc \- UPnP client library .SH SYNOPSIS .SH DESCRIPTION The miniupnpc library implement the UPnP protocol defined to dialog with Internet Gateway Devices. It also has the ability to use data gathered by minissdpd(1) about UPnP devices up on the network in order to skip the long UPnP device discovery process. .PP At first, upnpDiscover(3) has to be used to discover UPnP IGD present on the network. Then UPNP_GetValidIGD(3) to select the right one. Alternatively, UPNP_GetIGDFromUrl(3) could be used to bypass discovery process if the root description url of the device to use is known. Then all the UPNP_* functions can be used, such as UPNP_GetConnectionTypeInfo(3), UPNP_AddPortMapping(3), etc... .SH "HEADER FILES" .IP miniupnpc.h That's the main header file for the miniupnpc library API. It contains all the functions and structures related to device discovery. .IP upnpcommands.h This header file contain the UPnP IGD methods that are accessible through the miniupnpc API. The name of the C functions are matching the UPnP methods names. ie: GetGenericPortMappingEntry is UPNP_GetGenericPortMappingEntry. .SH "API FUNCTIONS" .IP "struct UPNPDev * upnpDiscover(int delay, const char * multicastif, const char * minissdpdsock, int localport, int ipv6, int * error);" execute the discovery process. delay (in millisecond) is the maximum time for waiting any device response. If available, device list will be obtained from MiniSSDPd. Default path for minissdpd socket will be used if minissdpdsock argument is NULL. If multicastif is not NULL, it will be used instead of the default multicast interface for sending SSDP discover packets. 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. If ipv6 is not 0, IPv6 is used instead of IPv4 for the discovery process. .IP "void freeUPNPDevlist(struct UPNPDev * devlist);" free the list returned by upnpDiscover(). .IP "int UPNP_GetValidIGD(struct UPNPDev * devlist, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen);" browse the list of device returned by upnpDiscover(), find a live UPnP internet gateway device and fill structures passed as arguments with data used for UPNP methods invocation. .IP "int UPNP_GetIGDFromUrl(const char * rootdescurl, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen);" permit one to bypass the upnpDiscover() call if the xml root description URL of the UPnP IGD is known. Fill structures passed as arguments with data used for UPNP methods invocation. .IP "void GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *, const char *);" .IP "void FreeUPNPUrls(struct UPNPUrls *);" .SH "SEE ALSO" minissdpd(1) .SH BUGS miniupnpc-2.2.6/src/upnperrors.c010064400017500000024000000055541454537750100161030ustar00nanardstaff/* $Id: upnperrors.c,v 1.12 2023/06/26 23:19:28 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * Project : miniupnp * Author : Thomas BERNARD * copyright (c) 2007-2023 Thomas Bernard * All Right reserved. * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * This software is subjet to the conditions detailed in the * provided LICENCE file. */ #include #include "upnperrors.h" #include "upnpcommands.h" #include "miniupnpc.h" const char * strupnperror(int err) { const char * s = NULL; switch(err) { case UPNPCOMMAND_SUCCESS: s = "Success"; break; case UPNPCOMMAND_UNKNOWN_ERROR: s = "Miniupnpc Unknown Error"; break; case UPNPCOMMAND_INVALID_ARGS: s = "Miniupnpc Invalid Arguments"; break; case UPNPCOMMAND_INVALID_RESPONSE: s = "Miniupnpc Invalid response"; break; case UPNPCOMMAND_HTTP_ERROR: s = "Miniupnpc HTTP error"; break; case UPNPDISCOVER_SOCKET_ERROR: s = "Miniupnpc Socket error"; break; case UPNPDISCOVER_MEMORY_ERROR: case UPNPCOMMAND_MEM_ALLOC_ERROR: s = "Miniupnpc Memory allocation error"; break; case 401: s = "Invalid Action"; break; case 402: s = "Invalid Args"; break; case 501: s = "Action Failed"; break; case 600: s = "Argument Value Invalid"; break; case 601: s = "Argument Value Out of Range"; break; case 602: s = "Optional Action Not Implemented"; break; case 603: s = "Out of Memory"; break; case 604: s = "Human Intervention Required"; break; case 605: s = "String Argument Too Long"; break; case 606: s = "Action not authorized"; break; case 701: s = "PinholeSpaceExhausted"; break; case 702: s = "FirewallDisabled"; break; case 703: s = "InboundPinholeNotAllowed"; break; case 704: s = "NoSuchEntry"; break; case 705: s = "ProtocolNotSupported"; break; case 706: s = "InternalPortWildcardingNotAllowed"; break; case 707: s = "ProtocolWildcardingNotAllowed"; break; case 708: s = "InvalidLayer2Address"; break; case 709: s = "NoTrafficReceived"; break; case 713: s = "SpecifiedArrayIndexInvalid"; break; case 714: s = "NoSuchEntryInArray"; break; case 715: s = "WildCardNotPermittedInSrcIP"; break; case 716: s = "WildCardNotPermittedInExtPort"; break; case 718: s = "ConflictInMappingEntry"; break; case 724: s = "SamePortValuesRequired"; break; case 725: s = "OnlyPermanentLeasesSupported"; break; case 726: s = "RemoteHostOnlySupportsWildcard"; break; case 727: s = "ExternalPortOnlySupportsWildcard"; break; case 728: s = "NoPortMapsAvailable"; break; case 729: s = "ConflictWithOtherMechanisms"; break; case 730: s = "PortMappingNotFound"; break; case 731: s = "ReadOnly"; break; case 732: s = "WildCardNotPermittedInIntPort"; break; case 733: s = "InconsistentParameters"; break; default: s = "UnknownError"; break; } return s; } miniupnpc-2.2.6/src/testigddescparse.c010064400017500000024000000105501343002305400171700ustar00nanardstaff/* $Id: testigddescparse.c,v 1.11 2019/02/10 12:33:32 nanard Exp $ */ /* Project : miniupnp * http://miniupnp.free.fr/ * Author : Thomas Bernard * Copyright (c) 2008-2015 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. * */ #include #include #include #include "igd_desc_parse.h" #include "minixml.h" #include "miniupnpc.h" /* count number of differences */ int compare_service(struct IGDdatas_service * s, FILE * f) { int n = 0; char line[1024]; while(fgets(line, sizeof(line), f)) { char * value; char * equal; char * name; char * parsedvalue; int l; l = strlen(line); while((l > 0) && ((line[l-1] == '\r') || (line[l-1] == '\n') || (line[l-1] == ' '))) line[--l] = '\0'; if(l == 0) break; /* end on blank line */ if(line[0] == '#') continue; /* skip comments */ equal = strchr(line, '='); if(equal == NULL) { fprintf(stderr, "Warning, line does not contain '=' : %s\n", line); continue; } *equal = '\0'; name = line; while(*name == ' ' || *name == '\t') name++; l = strlen(name); while((l > 0) && (name[l-1] == ' ' || name[l-1] == '\t')) name[--l] = '\0'; value = equal + 1; while(*value == ' ' || *value == '\t') value++; if(strcmp(name, "controlurl") == 0) parsedvalue = s->controlurl; else if(strcmp(name, "eventsuburl") == 0) parsedvalue = s->eventsuburl; else if(strcmp(name, "scpdurl") == 0) parsedvalue = s->scpdurl; else if(strcmp(name, "servicetype") == 0) parsedvalue = s->servicetype; else { fprintf(stderr, "unknown field '%s'\n", name); continue; } if(0 != strcmp(parsedvalue, value)) { fprintf(stderr, "difference : '%s' != '%s'\n", parsedvalue, value); n++; } } return n; } int compare_igd(struct IGDdatas * p, FILE * f) { int n = 0; char line[1024]; struct IGDdatas_service * s; while(fgets(line, sizeof(line), f)) { char * colon; int l = (int)strlen(line); while((l > 0) && (line[l-1] == '\r' || (line[l-1] == '\n'))) line[--l] = '\0'; if(l == 0 || line[0] == '#') continue; /* skip blank lines and comments */ colon = strchr(line, ':'); if(colon == NULL) { fprintf(stderr, "Warning, no ':' : %s\n", line); continue; } s = NULL; *colon = '\0'; if(strcmp(line, "CIF") == 0) s = &p->CIF; else if(strcmp(line, "first") == 0) s = &p->first; else if(strcmp(line, "second") == 0) s = &p->second; else if(strcmp(line, "IPv6FC") == 0) s = &p->IPv6FC; else { s = NULL; fprintf(stderr, "*** unknown service '%s' ***\n", line); n++; continue; } n += compare_service(s, f); } if(n > 0) fprintf(stderr, "*** %d difference%s ***\n", n, (n > 1) ? "s" : ""); return n; } int test_igd_desc_parse(char * buffer, int len, FILE * f) { int n; struct IGDdatas igd; struct xmlparser parser; struct UPNPUrls urls; memset(&igd, 0, sizeof(struct IGDdatas)); memset(&parser, 0, sizeof(struct xmlparser)); parser.xmlstart = buffer; parser.xmlsize = len; parser.data = &igd; parser.starteltfunc = IGDstartelt; parser.endeltfunc = IGDendelt; parser.datafunc = IGDdata; parsexml(&parser); #ifdef DEBUG printIGD(&igd); #endif /* DEBUG */ GetUPNPUrls(&urls, &igd, "http://fake/desc/url/file.xml", 0); printf("ipcondescURL='%s'\n", urls.ipcondescURL); printf("controlURL='%s'\n", urls.controlURL); printf("controlURL_CIF='%s'\n", urls.controlURL_CIF); n = f ? compare_igd(&igd, f) : 0; FreeUPNPUrls(&urls); return n; } int main(int argc, char * * argv) { FILE * f; char * buffer; int len; int r; if(argc<2) { fprintf(stderr, "Usage: %s file.xml [file.values]\n", argv[0]); return 1; } f = fopen(argv[1], "rb"); if(!f) { fprintf(stderr, "Cannot open %s for reading.\n", argv[1]); return 1; } fseek(f, 0, SEEK_END); len = ftell(f); fseek(f, 0, SEEK_SET); buffer = malloc(len); if(!buffer) { fprintf(stderr, "Memory allocation error.\n"); fclose(f); return 1; } 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) { f = fopen(argv[2], "rb"); if(!f) { fprintf(stderr, "Cannot open %s for reading.\n", argv[2]); free(buffer); return 1; } } r = test_igd_desc_parse(buffer, len, f); free(buffer); if(f) fclose(f); return r; } miniupnpc-2.2.6/testupnpigd.py010075500017500000024000000046721365604170000156430ustar00nanardstaff#! /usr/bin/env python # $Id: testupnpigd.py,v 1.7 2020/04/06 10:23:02 nanard Exp $ # MiniUPnP project # Author : Thomas Bernard # This Sample code is public domain. # website : https://miniupnp.tuxfamily.org/ # import the python miniupnpc module import miniupnpc import socket try: from http.server import BaseHTTPRequestHandler, HTTPServer except ImportError: from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer # function definition def list_redirections(): i = 0 while True: p = u.getgenericportmapping(i) if p==None: break print(i, p) i = i + 1 #define the handler class for HTTP connections class handler_class(BaseHTTPRequestHandler): def do_GET(self): self.send_response(200) self.end_headers() self.wfile.write(b"OK MON GARS") # create the object u = miniupnpc.UPnP() #print 'inital(default) values :' #print ' discoverdelay', u.discoverdelay #print ' lanaddr', u.lanaddr #print ' multicastif', u.multicastif #print ' minissdpdsocket', u.minissdpdsocket u.discoverdelay = 200; try: print('Discovering... delay=%ums' % u.discoverdelay) ndevices = u.discover() print(ndevices, 'device(s) detected') # select an igd u.selectigd() # display information about the IGD and the internet connection print('local ip address :', u.lanaddr) externalipaddress = u.externalipaddress() print('external ip address :', externalipaddress) print(u.statusinfo(), u.connectiontype()) #instanciate a HTTPd object. The port is assigned by the system. httpd = HTTPServer((u.lanaddr, 0), handler_class) eport = httpd.server_port # find a free port for the redirection r = u.getspecificportmapping(eport, 'TCP') while r != None and eport < 65536: eport = eport + 1 r = u.getspecificportmapping(eport, 'TCP') print('trying to redirect %s port %u TCP => %s port %u TCP' % (externalipaddress, eport, u.lanaddr, httpd.server_port)) b = u.addportmapping(eport, 'TCP', u.lanaddr, httpd.server_port, 'UPnP IGD Tester port %u' % eport, '') if b: print('Success. Now waiting for some HTTP request on http://%s:%u' % (externalipaddress ,eport)) try: httpd.handle_request() httpd.server_close() except KeyboardInterrupt as details: print("CTRL-C exception!", details) b = u.deleteportmapping(eport, 'TCP') if b: print('Successfully deleted port mapping') else: print('Failed to remove port mapping') else: print('Failed') httpd.server_close() except Exception as e: print('Exception :', e) miniupnpc-2.2.6/miniupnpc.def010064400017500000024000000020271365604170000153720ustar00nanardstaffLIBRARY ; miniupnpc library miniupnpc EXPORTS ; miniupnpc upnpDiscover upnpDiscoverDevice upnpDiscoverDevices upnpDiscoverAll freeUPNPDevlist parserootdesc UPNP_GetValidIGD UPNP_GetIGDFromUrl GetUPNPUrls FreeUPNPUrls ; miniwget miniwget miniwget_getaddr ; upnpcommands UPNP_GetTotalBytesSent UPNP_GetTotalBytesReceived UPNP_GetTotalPacketsSent UPNP_GetTotalPacketsReceived UPNP_GetStatusInfo UPNP_GetConnectionTypeInfo UPNP_GetExternalIPAddress UPNP_GetLinkLayerMaxBitRates UPNP_AddPortMapping UPNP_AddAnyPortMapping UPNP_DeletePortMapping UPNP_DeletePortMappingRange UPNP_GetPortMappingNumberOfEntries UPNP_GetSpecificPortMappingEntry UPNP_GetGenericPortMappingEntry UPNP_GetListOfPortMappings UPNP_AddPinhole UPNP_CheckPinholeWorking UPNP_UpdatePinhole UPNP_GetPinholePackets UPNP_DeletePinhole UPNP_GetFirewallStatus UPNP_GetOutboundPinholeTimeout ; upnperrors strupnperror ; portlistingparse ParsePortListing FreePortListing miniupnpc-2.2.6/src/codelength.h010064400017500000024000000030251255150331000157540ustar00nanardstaff/* $Id: codelength.h,v 1.5 2015/07/09 12:40:18 nanard Exp $ */ /* Project : miniupnp * Author : 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 #define CODELENGTH_H_INCLUDED /* 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 { \ if((p) >= (p_limit)) break; \ 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 /* CODELENGTH_H_INCLUDED */ miniupnpc-2.2.6/miniupnpcstrings.h.in010064400017500000024000000014511454537750100171130ustar00nanardstaff/* $Id: miniupnpcstrings.h.in,v 1.7 2023/07/05 22:43:50 nanard Exp $ */ /* Project: miniupnp * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * Author: Thomas Bernard * Copyright (c) 2005-2014 Thomas Bernard * This software is subjects to the conditions detailed * in the LICENCE file provided within this distribution */ #ifndef MINIUPNPCSTRINGS_H_INCLUDED #define MINIUPNPCSTRINGS_H_INCLUDED #define OS_STRING "OS/version" #define MINIUPNPC_VERSION_STRING "version" #if 0 /* according to "UPnP Device Architecture 1.0" */ #define UPNP_VERSION_MAJOR 1 #define UPNP_VERSION_MINOR 0 #define UPNP_VERSION_STRING "UPnP/1.0" #else /* according to "UPnP Device Architecture 1.1" */ #define UPNP_VERSION_MAJOR 1 #define UPNP_VERSION_MINOR 1 #define UPNP_VERSION_STRING "UPnP/1.1" #endif #endif miniupnpc-2.2.6/updateminiupnpcstrings.sh010075500017500000024000000034611432271534100200710ustar00nanardstaff#! /bin/sh # $Id: updateminiupnpcstrings.sh,v 1.10 2022/10/16 05:28:15 nanard Exp $ # project miniupnp : http://miniupnp.free.fr/ # (c) 2009-2021 Thomas Bernard FILE=miniupnpcstrings.h TEMPLATE_FILE=${FILE}.in if [ -n "$1" ] ; then FILE="$1" fi if [ -n "$2" ] ; then TEMPLATE_FILE="$2" fi TMPFILE=`mktemp -t miniupnpcstringsXXXXXX` if [ ! -f "$TMPFILE" ] ; then echo "mktemp failure" exit 1 fi # detecting the OS name and version OS_NAME=`uname -s` OS_VERSION=`uname -r` if [ -f /etc/debian_version ]; then OS_NAME=Debian OS_VERSION=`cat /etc/debian_version` fi # use lsb_release (Linux Standard Base) when available LSB_RELEASE=`which lsb_release` if [ 0 -eq $? -a -x "${LSB_RELEASE}" ]; then # On NixOS, lsb_release returns strings such as "NixOS" (with quotes), # so we need to stript them with the following xargs trick: OS_NAME=`${LSB_RELEASE} -i -s | xargs echo` OS_VERSION=`${LSB_RELEASE} -r -s | xargs echo` case $OS_NAME in Debian) #OS_VERSION=`${LSB_RELEASE} -c -s` ;; Ubuntu) #OS_VERSION=`${LSB_RELEASE} -c -s` ;; esac fi # on AmigaOS 3, uname -r returns "unknown", so we use uname -v if [ "$OS_NAME" = "AmigaOS" ]; then if [ "$OS_VERSION" = "unknown" ]; then OS_VERSION=`uname -v` fi fi echo "Detected OS [$OS_NAME] version [$OS_VERSION]" MINIUPNPC_VERSION=`cat VERSION` echo "MiniUPnPc version [${MINIUPNPC_VERSION}]" EXPR="s|OS_STRING \".*\"|OS_STRING \"${OS_NAME}/${OS_VERSION}\"|" #echo $EXPR test -f ${FILE}.in echo "setting OS_STRING macro value to ${OS_NAME}/${OS_VERSION} in $FILE." sed -e "$EXPR" < $TEMPLATE_FILE > $TMPFILE EXPR="s|MINIUPNPC_VERSION_STRING \".*\"|MINIUPNPC_VERSION_STRING \"${MINIUPNPC_VERSION}\"|" echo "setting MINIUPNPC_VERSION_STRING macro value to ${MINIUPNPC_VERSION} in $FILE." sed -e "$EXPR" < $TMPFILE > $FILE rm $TMPFILE && echo "$TMPFILE deleted" miniupnpc-2.2.6/VERSION010064400017500000024000000000061454537751500137710ustar00nanardstaff2.2.6 miniupnpc-2.2.6/src/testminiwget.c010064400017500000024000000030141323023101700163510ustar00nanardstaff/* $Id: testminiwget.c,v 1.7 2018/01/16 01:01:05 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * Project : miniupnp * Author : Thomas Bernard * Copyright (c) 2005-2018 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. * */ #include #include #include "miniwget.h" /** * This program uses the miniwget / miniwget_getaddr function * from miniwget.c in order to retrieve a web ressource using * a GET HTTP method, and store it in a file. */ int main(int argc, char * * argv) { void * data; int size, writtensize; FILE *f; char addr[64]; int status_code = -1; if(argc < 3) { fprintf(stderr, "Usage:\t%s url file\n", argv[0]); fprintf(stderr, "Example:\t%s http://www.google.com/ out.html\n", argv[0]); return 1; } data = miniwget_getaddr(argv[1], &size, addr, sizeof(addr), 0, &status_code); if(!data || (status_code != 200)) { if(data) free(data); fprintf(stderr, "Error %d fetching %s\n", status_code, argv[1]); return 1; } printf("local address : %s\n", addr); printf("got %d bytes\n", size); f = fopen(argv[2], "wb"); if(!f) { fprintf(stderr, "Cannot open file %s for writing\n", argv[2]); free(data); return 1; } writtensize = fwrite(data, 1, size, f); if(writtensize != size) { fprintf(stderr, "Could only write %d bytes out of %d to %s\n", writtensize, size, argv[2]); } else { printf("%d bytes written to %s\n", writtensize, argv[2]); } fclose(f); free(data); return 0; } miniupnpc-2.2.6/msvc/miniupnpc.sln010064400017500000024000000027031131024352600163740ustar00nanardstaff Microsoft Visual Studio Solution File, Format Version 10.00 # Visual C++ Express 2008 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "miniupnpc", "miniupnpc.vcproj", "{D28CE435-CB33-4BAE-8A52-C6EF915956F5}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "upnpc-static", "upnpc-static.vcproj", "{469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}" ProjectSection(ProjectDependencies) = postProject {D28CE435-CB33-4BAE-8A52-C6EF915956F5} = {D28CE435-CB33-4BAE-8A52-C6EF915956F5} EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Debug|Win32.ActiveCfg = Debug|Win32 {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Debug|Win32.Build.0 = Debug|Win32 {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Release|Win32.ActiveCfg = Release|Win32 {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Release|Win32.Build.0 = Release|Win32 {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Debug|Win32.ActiveCfg = Debug|Win32 {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Debug|Win32.Build.0 = Debug|Win32 {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Release|Win32.ActiveCfg = Release|Win32 {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal miniupnpc-2.2.6/msvc/miniupnpc.vcproj010064400017500000024000000120301260022317500170760ustar00nanardstaff miniupnpc-2.2.6/msvc/upnpc-static.vcproj010064400017500000024000000076471242146516100175340ustar00nanardstaff miniupnpc-2.2.6/wingenminiupnpcstrings.c010064400017500000024000000070071412470240400176770ustar00nanardstaff/* $Id: wingenminiupnpcstrings.c,v 1.6 2021/08/21 09:43:40 nanard Exp $ */ /* Project: miniupnp * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * Author: Thomas Bernard * Copyright (c) 2005-2021 Thomas Bernard * This software is subjects to the conditions detailed * in the LICENSE file provided within this distribution */ #include #include /* This program display the Windows version and is used to * generate the miniupnpcstrings.h * wingenminiupnpcstrings miniupnpcstrings.h.in miniupnpcstrings.h */ int main(int argc, char * * argv) { char buffer[256]; OSVERSIONINFO osvi; FILE * fin; FILE * fout; int n; char miniupnpcVersion[32]; /* dwMajorVersion : The major version number of the operating system. For more information, see Remarks. dwMinorVersion : The minor version number of the operating system. For more information, see Remarks. dwBuildNumber : The build number of the operating system. dwPlatformId The operating system platform. This member can be the following value. szCSDVersion A null-terminated string, such as "Service Pack 3", that indicates the latest Service Pack installed on the system. If no Service Pack has been installed, the string is empty. */ ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osvi); printf("Windows %lu.%lu Build %lu %s\n", osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber, (const char *)&(osvi.szCSDVersion)); fin = fopen("VERSION", "r"); fgets(miniupnpcVersion, sizeof(miniupnpcVersion), fin); fclose(fin); for(n = 0; n < (int)sizeof(miniupnpcVersion); n++) { if(miniupnpcVersion[n] < ' ') miniupnpcVersion[n] = '\0'; } printf("MiniUPnPc version %s\n", miniupnpcVersion); if(argc >= 3) { fin = fopen(argv[1], "r"); if(!fin) { fprintf(stderr, "Cannot open %s for reading.\n", argv[1]); return 1; } fout = fopen(argv[2], "w"); if(!fout) { fprintf(stderr, "Cannot open %s for writing.\n", argv[2]); fclose(fin); return 1; } n = 0; while(fgets(buffer, sizeof(buffer), fin)) { if(0 == memcmp(buffer, "#define OS_STRING \"OS/version\"", 30)) { sprintf(buffer, "#define OS_STRING \"MSWindows/%ld.%ld.%ld\"\n", osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber); } else if(0 == memcmp(buffer, "#define MINIUPNPC_VERSION_STRING \"version\"", 42)) { sprintf(buffer, "#define MINIUPNPC_VERSION_STRING \"%s\"\n", miniupnpcVersion); } /*fputs(buffer, stdout);*/ fputs(buffer, fout); n++; } fclose(fin); fclose(fout); printf("%d lines written to %s.\n", n, argv[2]); } if(argc >= 4) { fout = fopen(argv[3], "w"); if(fout == NULL) { fprintf(stderr, "Cannot open %s for writing.\n", argv[2]); return 1; } else { char * cur, * next; fprintf(fout, "#define LIBMINIUPNPC_DOTTED_VERSION \"%s\"\n", miniupnpcVersion); next = strchr(miniupnpcVersion, '.'); if (next && *next) { *next = '\0'; next++; } fprintf(fout, "#define LIBMINIUPNPC_MAJOR_VERSION %s\n", miniupnpcVersion); cur = next; next = strchr(cur, '.'); if (next && *next) { *next = '\0'; next++; } fprintf(fout, "#define LIBMINIUPNPC_MINOR_VERSION %s\n", cur); cur = next; next = strchr(cur, '.'); if (next && *next) { *next = '\0'; next++; } fprintf(fout, "#define LIBMINIUPNPC_MICRO_VERSION %s\n", cur); fclose(fout); printf("%s written\n", argv[3]); } } return 0; } miniupnpc-2.2.6/src/connecthostport.c010064400017500000024000000166101375231574600171150ustar00nanardstaff/* $Id: connecthostport.c,v 1.24 2020/11/09 19:26:53 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * Project : miniupnp * Author : Thomas Bernard * Copyright (c) 2010-2020 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. */ /* use getaddrinfo() or gethostbyname() * uncomment the following line in order to use gethostbyname() */ #ifdef NO_GETADDRINFO #define USE_GETHOSTBYNAME #endif #include #include #ifdef _WIN32 #include #include #include #define MAXHOSTNAMELEN 64 #include "win32_snprintf.h" #define herror #define socklen_t int #else /* #ifdef _WIN32 */ #include #include #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT #include #endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ #include #include #include #define closesocket close #include #include /* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions * during the connect() call */ #define MINIUPNPC_IGNORE_EINTR #include #include #endif /* #else _WIN32 */ #if defined(__amigaos__) || defined(__amigaos4__) #define herror(A) printf("%s\n", A) #endif #include "connecthostport.h" #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif /* connecthostport() * return a socket connected (TCP) to the host and port * or -1 in case of error */ SOCKET connecthostport(const char * host, unsigned short port, unsigned int scope_id) { SOCKET s; int n; #ifdef USE_GETHOSTBYNAME struct sockaddr_in dest; struct hostent *hp; #else /* #ifdef USE_GETHOSTBYNAME */ char tmp_host[MAXHOSTNAMELEN+1]; char port_str[8]; struct addrinfo *ai, *p; struct addrinfo hints; #endif /* #ifdef USE_GETHOSTBYNAME */ #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT struct timeval timeout; #endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ #ifdef USE_GETHOSTBYNAME hp = gethostbyname(host); if(hp == NULL) { herror(host); return INVALID_SOCKET; } memcpy(&dest.sin_addr, hp->h_addr, sizeof(dest.sin_addr)); memset(dest.sin_zero, 0, sizeof(dest.sin_zero)); s = socket(PF_INET, SOCK_STREAM, 0); if(ISINVALID(s)) { PRINT_SOCKET_ERROR("socket"); return INVALID_SOCKET; } #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT /* setting a 3 seconds timeout for the connect() call */ timeout.tv_sec = 3; timeout.tv_usec = 0; if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0) { PRINT_SOCKET_ERROR("setsockopt SO_RCVTIMEO"); } timeout.tv_sec = 3; timeout.tv_usec = 0; if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0) { PRINT_SOCKET_ERROR("setsockopt SO_SNDTIMEO"); } #endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ dest.sin_family = AF_INET; dest.sin_port = htons(port); n = connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr_in)); #ifdef MINIUPNPC_IGNORE_EINTR /* EINTR The system call was interrupted by a signal that was caught * EINPROGRESS The socket is nonblocking and the connection cannot * be completed immediately. */ while(n < 0 && (errno == EINTR || errno == EINPROGRESS)) { socklen_t len; fd_set wset; int err; FD_ZERO(&wset); FD_SET(s, &wset); #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT timeout.tv_sec = 3; timeout.tv_usec = 0; n = select(s + 1, NULL, &wset, NULL, &timeout); #else n = select(s + 1, NULL, &wset, NULL, NULL); #endif if(n == -1 && errno == EINTR) continue; #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT if(n == 0) { errno = ETIMEDOUT; n = -1; break; } #endif /*len = 0;*/ /*n = getpeername(s, NULL, &len);*/ len = sizeof(err); if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { PRINT_SOCKET_ERROR("getsockopt"); closesocket(s); return INVALID_SOCKET; } if(err != 0) { errno = err; n = -1; } } #endif /* #ifdef MINIUPNPC_IGNORE_EINTR */ if(n<0) { PRINT_SOCKET_ERROR("connect"); closesocket(s); return INVALID_SOCKET; } #else /* #ifdef USE_GETHOSTBYNAME */ /* use getaddrinfo() instead of gethostbyname() */ memset(&hints, 0, sizeof(hints)); /* hints.ai_flags = AI_ADDRCONFIG; */ #ifdef AI_NUMERICSERV hints.ai_flags = AI_NUMERICSERV; #endif hints.ai_socktype = SOCK_STREAM; hints.ai_family = AF_UNSPEC; /* AF_INET, AF_INET6 or AF_UNSPEC */ /* hints.ai_protocol = IPPROTO_TCP; */ snprintf(port_str, sizeof(port_str), "%hu", port); if(host[0] == '[') { /* literal ip v6 address */ int i, j; for(i = 0, j = 1; host[j] && (host[j] != ']') && i < MAXHOSTNAMELEN; i++, j++) { tmp_host[i] = host[j]; if(0 == strncmp(host+j, "%25", 3)) /* %25 is just url encoding for '%' */ j+=2; /* skip "25" */ } tmp_host[i] = '\0'; } else { strncpy(tmp_host, host, MAXHOSTNAMELEN); } tmp_host[MAXHOSTNAMELEN] = '\0'; n = getaddrinfo(tmp_host, port_str, &hints, &ai); if(n != 0) { #ifdef _WIN32 fprintf(stderr, "getaddrinfo() error : %d\n", n); #else fprintf(stderr, "getaddrinfo() error : %s\n", gai_strerror(n)); #endif return INVALID_SOCKET; } s = INVALID_SOCKET; for(p = ai; p; p = p->ai_next) { if(!ISINVALID(s)) closesocket(s); #ifdef DEBUG printf("ai_family=%d ai_socktype=%d ai_protocol=%d (PF_INET=%d, PF_INET6=%d)\n", p->ai_family, p->ai_socktype, p->ai_protocol, PF_INET, PF_INET6); #endif s = socket(p->ai_family, p->ai_socktype, p->ai_protocol); if(ISINVALID(s)) continue; if(p->ai_addr->sa_family == AF_INET6 && scope_id > 0) { struct sockaddr_in6 * addr6 = (struct sockaddr_in6 *)p->ai_addr; addr6->sin6_scope_id = scope_id; } #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT /* setting a 3 seconds timeout for the connect() call */ timeout.tv_sec = 3; timeout.tv_usec = 0; if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0) { PRINT_SOCKET_ERROR("setsockopt"); } timeout.tv_sec = 3; timeout.tv_usec = 0; if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0) { PRINT_SOCKET_ERROR("setsockopt"); } #endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ n = connect(s, p->ai_addr, MSC_CAST_INT p->ai_addrlen); #ifdef MINIUPNPC_IGNORE_EINTR /* EINTR The system call was interrupted by a signal that was caught * EINPROGRESS The socket is nonblocking and the connection cannot * be completed immediately. */ while(n < 0 && (errno == EINTR || errno == EINPROGRESS)) { socklen_t len; fd_set wset; int err; FD_ZERO(&wset); FD_SET(s, &wset); #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT timeout.tv_sec = 3; timeout.tv_usec = 0; n = select(s + 1, NULL, &wset, NULL, &timeout); #else n = select(s + 1, NULL, &wset, NULL, NULL); #endif if(n == -1 && errno == EINTR) continue; #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT if(n == 0) { errno = ETIMEDOUT; n = -1; break; } #endif /*len = 0;*/ /*n = getpeername(s, NULL, &len);*/ len = sizeof(err); if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { PRINT_SOCKET_ERROR("getsockopt"); closesocket(s); freeaddrinfo(ai); return INVALID_SOCKET; } if(err != 0) { errno = err; n = -1; } } #endif /* #ifdef MINIUPNPC_IGNORE_EINTR */ if(n >= 0) /* connect() was successful */ break; } freeaddrinfo(ai); if(ISINVALID(s)) { PRINT_SOCKET_ERROR("socket"); return INVALID_SOCKET; } if(n < 0) { PRINT_SOCKET_ERROR("connect"); closesocket(s); return INVALID_SOCKET; } #endif /* #ifdef USE_GETHOSTBYNAME */ return s; } miniupnpc-2.2.6/src/connecthostport.h010064400017500000024000000012031326165065200171030ustar00nanardstaff/* $Id: connecthostport.h,v 1.4 2018/04/06 10:53:13 nanard Exp $ */ /* Project: miniupnp * http://miniupnp.free.fr/ * Author: Thomas Bernard * Copyright (c) 2010-2018 Thomas Bernard * This software is subjects to the conditions detailed * in the LICENCE file provided within this distribution */ #ifndef CONNECTHOSTPORT_H_INCLUDED #define CONNECTHOSTPORT_H_INCLUDED #include "miniupnpc_socketdef.h" /* connecthostport() * return a socket connected (TCP) to the host and port * or INVALID_SOCKET in case of error */ SOCKET connecthostport(const char * host, unsigned short port, unsigned int scope_id); #endif miniupnpc-2.2.6/java/JavaBridgeTest.java010064400017500000024000000114661257653522700173550ustar00nanardstaffimport java.nio.ByteBuffer; import java.nio.IntBuffer; import fr.free.miniupnp.*; /** * * @author syuu */ public class JavaBridgeTest { public static void main(String[] args) { int UPNP_DELAY = 2000; MiniupnpcLibrary miniupnpc = MiniupnpcLibrary.INSTANCE; UPNPDev devlist = null; UPNPUrls urls = new UPNPUrls(); IGDdatas data = new IGDdatas(); ByteBuffer lanaddr = ByteBuffer.allocate(16); ByteBuffer intClient = ByteBuffer.allocate(16); ByteBuffer intPort = ByteBuffer.allocate(6); ByteBuffer desc = ByteBuffer.allocate(80); ByteBuffer enabled = ByteBuffer.allocate(4); ByteBuffer leaseDuration = ByteBuffer.allocate(16); int ret; int i; if(args.length < 2) { System.err.println("Usage : java [...] JavaBridgeTest port protocol"); System.out.println(" port is numeric, protocol is TCP or UDP"); return; } 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) { System.out.println("desc: " + device.descURL.getString(0) + " st: " + device.st.getString(0)); } if ((i = miniupnpc.UPNP_GetValidIGD(devlist, urls, data, lanaddr, 16)) != 0) { switch (i) { case 1: System.out.println("Found valid IGD : " + urls.controlURL.getString(0)); break; case 2: System.out.println("Found a (not connected?) IGD : " + urls.controlURL.getString(0)); System.out.println("Trying to continue anyway"); break; case 3: System.out.println("UPnP device found. Is it an IGD ? : " + urls.controlURL.getString(0)); System.out.println("Trying to continue anyway"); break; default: System.out.println("Found device (igd ?) : " + urls.controlURL.getString(0)); System.out.println("Trying to continue anyway"); } System.out.println("Local LAN ip address : " + new String(lanaddr.array())); ByteBuffer externalAddress = ByteBuffer.allocate(16); miniupnpc.UPNP_GetExternalIPAddress(urls.controlURL.getString(0), new String(data.first.servicetype), externalAddress); System.out.println("ExternalIPAddress = " + new String(externalAddress.array())); ret = miniupnpc.UPNP_AddPortMapping( urls.controlURL.getString(0), // controlURL new String(data.first.servicetype), // servicetype args[0], // external Port args[0], // internal Port new String(lanaddr.array()), // internal client "added via miniupnpc/JAVA !", // description args[1], // protocol UDP or TCP null, // remote host (useless) "0"); // leaseDuration if (ret != MiniupnpcLibrary.UPNPCOMMAND_SUCCESS) System.out.println("AddPortMapping() failed with code " + ret); ret = miniupnpc.UPNP_GetSpecificPortMappingEntry( urls.controlURL.getString(0), new String(data.first.servicetype), args[0], args[1], null, intClient, intPort, desc, enabled, leaseDuration); if (ret != MiniupnpcLibrary.UPNPCOMMAND_SUCCESS) System.out.println("GetSpecificPortMappingEntry() failed with code " + ret); System.out.println("InternalIP:Port = " + new String(intClient.array()) + ":" + new String(intPort.array()) + " (" + new String(desc.array()) + ")"); ret = miniupnpc.UPNP_DeletePortMapping( urls.controlURL.getString(0), new String(data.first.servicetype), args[0], args[1], null); if (ret != MiniupnpcLibrary.UPNPCOMMAND_SUCCESS) System.out.println("DelPortMapping() failed with code " + ret); miniupnpc.FreeUPNPUrls(urls); } else { System.out.println("No valid UPNP Internet Gateway Device found."); } miniupnpc.freeUPNPDevlist(devlist); } else { System.out.println("No IGD UPnP Device found on the network !\n"); } } } miniupnpc-2.2.6/java/testjava.sh010075500017500000024000000002561170636161400160160ustar00nanardstaff#!/bin/bash JAVA=java JAVAC=javac CP=$(for i in *.jar; do echo -n $i:; done). $JAVAC -cp $CP JavaBridgeTest.java || exit 1 $JAVA -cp $CP JavaBridgeTest 12345 UDP || exit 1 miniupnpc-2.2.6/java/testjava.bat010075500017500000024000000003641210132026500161350ustar00nanardstaff@echo off set JAVA=java set JAVAC=javac REM notice the semicolon for Windows. Write once, run ... oh nevermind set CP=miniupnpc_win32.jar;. %JAVAC% -cp "%CP%" JavaBridgeTest.java || exit 1 %JAVA% -cp "%CP%" JavaBridgeTest 12345 UDP || exit 1 miniupnpc-2.2.6/external-ip.sh010075500017500000024000000002411317665377100155110ustar00nanardstaff#!/bin/sh # $Id: external-ip.sh,v 1.2 2017/11/02 15:33:09 nanard Exp $ # (c) 2010 Reuben Hawkins upnpc -s | sed -n -e 's/^ExternalIPAddress = \([0-9.]*\)$/\1/p' miniupnpc-2.2.6/MANIFEST.in010064400017500000024000000002621412470240300144400ustar00nanardstaffinclude README include VERSION include LICENSE include src/miniupnpcmodule.c include setup.py include Makefile include src/*.[ch] include include/*.h include *.h.in include *.sh miniupnpc-2.2.6/src/portlistingparse.c010064400017500000024000000075531364006264600172720ustar00nanardstaff/* $Id: portlistingparse.c,v 1.11 2020/03/22 22:43:44 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2011-2020 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ #include #include #ifdef DEBUG #include #endif /* DEBUG */ #include "portlistingparse.h" #include "minixml.h" #if defined(__HAIKU__) /* rename our private function because Haiku already defines a atoui() function */ #define atoui atoui2 #endif /* list of the elements */ static const struct { const portMappingElt code; const char * const str; } elements[] = { { PortMappingEntry, "PortMappingEntry"}, { NewRemoteHost, "NewRemoteHost"}, { NewExternalPort, "NewExternalPort"}, { NewProtocol, "NewProtocol"}, { NewInternalPort, "NewInternalPort"}, { NewInternalClient, "NewInternalClient"}, { NewEnabled, "NewEnabled"}, { NewDescription, "NewDescription"}, { NewLeaseTime, "NewLeaseTime"}, { PortMappingEltNone, NULL} }; /* Helper function */ static UNSIGNED_INTEGER atoui(const char * p, int l) { UNSIGNED_INTEGER r = 0; while(l > 0 && *p) { if(*p >= '0' && *p <= '9') r = r*10 + (*p - '0'); else break; p++; l--; } return r; } /* Start element handler */ static void startelt(void * d, const char * name, int l) { int i; struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; pdata->curelt = PortMappingEltNone; for(i = 0; elements[i].str; i++) { if(strlen(elements[i].str) == (size_t)l && memcmp(name, elements[i].str, l) == 0) { pdata->curelt = elements[i].code; break; } } if(pdata->curelt == PortMappingEntry) { 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; } } /* End element handler */ static void endelt(void * d, const char * name, int l) { struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; (void)name; (void)l; pdata->curelt = PortMappingEltNone; } /* Data handler */ static void data(void * d, const char * data, int l) { struct PortMapping * pm; struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; pm = pdata->l_head; if(!pm) return; if(l > 63) l = 63; switch(pdata->curelt) { case NewRemoteHost: memcpy(pm->remoteHost, data, l); pm->remoteHost[l] = '\0'; break; case NewExternalPort: pm->externalPort = (unsigned short)atoui(data, l); break; case NewProtocol: if(l > 3) l = 3; memcpy(pm->protocol, data, l); pm->protocol[l] = '\0'; break; case NewInternalPort: pm->internalPort = (unsigned short)atoui(data, l); break; case NewInternalClient: memcpy(pm->internalClient, data, l); pm->internalClient[l] = '\0'; break; case NewEnabled: pm->enabled = (unsigned char)atoui(data, l); break; case NewDescription: memcpy(pm->description, data, l); pm->description[l] = '\0'; break; case NewLeaseTime: pm->leaseTime = atoui(data, l); break; default: break; } } /* Parse the PortMappingList XML document for IGD version 2 */ void ParsePortListing(const char * buffer, int bufsize, struct PortMappingParserData * pdata) { struct xmlparser parser; memset(pdata, 0, sizeof(struct PortMappingParserData)); /* init xmlparser */ parser.xmlstart = buffer; parser.xmlsize = bufsize; parser.data = pdata; parser.starteltfunc = startelt; parser.endeltfunc = endelt; parser.datafunc = data; parser.attfunc = 0; parsexml(&parser); } void FreePortListing(struct PortMappingParserData * pdata) { struct PortMapping * pm; while((pm = pdata->l_head) != NULL) { /* remove from list */ pdata->l_head = pm->l_next; free(pm); } } miniupnpc-2.2.6/CMakeLists.txt010064400017500000024000000307751454537753600155040ustar00nanardstaffcmake_minimum_required(VERSION 3.12 FATAL_ERROR) project (miniupnpc VERSION 2.2.6 DESCRIPTION "UPnP IGD client lightweight library" HOMEPAGE_URL https://miniupnp.tuxfamily.org/ LANGUAGES C) set (MINIUPNPC_API_VERSION 17) option (UPNPC_BUILD_STATIC "Build static library" TRUE) option (UPNPC_BUILD_SHARED "Build shared library" TRUE) option (UPNPC_BUILD_TESTS "Build test executables" TRUE) option (UPNPC_BUILD_SAMPLE "Build sample executables" TRUE) option (NO_GETADDRINFO "Define NO_GETADDRINFO" FALSE) option (UPNPC_NO_INSTALL "Disable installation" FALSE) if (NOT UPNPC_BUILD_STATIC AND NOT UPNPC_BUILD_SHARED) message (FATAL "Both shared and static libraries are disabled!") endif () include(GNUInstallDirs) # Interface library for compile definitions, flags and option add_library(miniupnpc-private INTERFACE) if (NO_GETADDRINFO) target_compile_definitions(miniupnpc-private INTERFACE NO_GETADDRINFO) endif () if (NOT WIN32) target_compile_definitions(miniupnpc-private INTERFACE MINIUPNPC_SET_SOCKET_TIMEOUT _BSD_SOURCE _DEFAULT_SOURCE) if (NOT APPLE AND NOT CMAKE_SYSTEM_NAME MATCHES ".*BSD" AND NOT CMAKE_SYSTEM_NAME STREQUAL "SunOS") # add_definitions (-D_POSIX_C_SOURCE=200112L) target_compile_definitions(miniupnpc-private INTERFACE _XOPEN_SOURCE=600) endif () if (CMAKE_SYSTEM_NAME STREQUAL "NetBSD") target_compile_definitions(miniupnpc-private INTERFACE _NETBSD_SOURCE) endif () else () set (MINIUPNPC_TARGET_WINDOWS_VERSION "0x0501" CACHE STRING "Minimum target Windows version as hex string") # XP or higher for getnameinfo and friends if (MINIUPNPC_TARGET_WINDOWS_VERSION) target_compile_definitions(miniupnpc-private INTERFACE _WIN32_WINNT=${MINIUPNPC_TARGET_WINDOWS_VERSION}) endif () endif () if (APPLE) target_compile_definitions(miniupnpc-private INTERFACE _DARWIN_C_SOURCE) endif () # Set compiler specific build flags if (CMAKE_COMPILER_IS_GNUCC AND NOT CMAKE_SYSTEM_NAME STREQUAL "AmigaOS") set(CMAKE_POSITION_INDEPENDENT_CODE ON) target_compile_options(miniupnpc-private INTERFACE -Wall) endif () # Suppress noise warnings if (MSVC) target_compile_definitions(miniupnpc-private INTERFACE _CRT_SECURE_NO_WARNINGS _WINSOCK_DEPRECATED_NO_WARNINGS) endif() configure_file (${CMAKE_CURRENT_SOURCE_DIR}/miniupnpcstrings.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/miniupnpcstrings.h) target_include_directories(miniupnpc-private INTERFACE $) set (MINIUPNPC_SOURCES src/igd_desc_parse.c src/miniupnpc.c src/minixml.c src/minisoap.c src/minissdpc.c src/miniwget.c src/upnpcommands.c src/upnpdev.c src/upnpreplyparse.c src/upnperrors.c src/connecthostport.c src/portlistingparse.c src/receivedata.c src/addr_is_reserved.c ${CMAKE_CURRENT_BINARY_DIR}/miniupnpcstrings.h ) if (WIN32) target_link_libraries(miniupnpc-private INTERFACE ws2_32 iphlpapi) elseif (CMAKE_SYSTEM_NAME STREQUAL "SunOS") target_link_libraries(miniupnpc-private INTERFACE socket nsl resolv) find_library (SOCKET_LIBRARY NAMES socket) find_library (NSL_LIBRARY NAMES nsl) find_library (RESOLV_LIBRARY NAMES resolv) set (LDLIBS ${SOCKET_LIBRARY} ${NSL_LIBRARY} ${RESOLV_LIBRARY} ${LDLIBS}) elseif (HAIKU) target_link_libraries(miniupnpc-private INTERFACE network) find_library (SOCKET_LIBRARY NAMES network) find_library (NSL_LIBRARY NAMES network) find_library (RESOLV_LIBRARY NAMES network) set (LDLIBS ${SOCKET_LIBRARY} ${NSL_LIBRARY} ${RESOLV_LIBRARY} ${LDLIBS}) endif () if (UPNPC_BUILD_STATIC) add_library (libminiupnpc-static STATIC ${MINIUPNPC_SOURCES}) target_include_directories (libminiupnpc-static PUBLIC $ $) if (NOT UPNPC_BUILD_SHARED) add_library (miniupnpc::miniupnpc ALIAS libminiupnpc-static) endif() set_target_properties (libminiupnpc-static PROPERTIES EXPORT_NAME miniupnpc) if (WIN32 AND NOT MINGW) set_target_properties (libminiupnpc-static PROPERTIES OUTPUT_NAME "libminiupnpc") else() set_target_properties (libminiupnpc-static PROPERTIES OUTPUT_NAME "miniupnpc") endif() target_link_libraries (libminiupnpc-static PRIVATE miniupnpc-private) target_include_directories(libminiupnpc-static INTERFACE $) target_compile_definitions(libminiupnpc-static PUBLIC MINIUPNP_STATICLIB) if (NOT UPNPC_NO_INSTALL) install (TARGETS miniupnpc-private EXPORT miniupnpc-private) install (EXPORT miniupnpc-private DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/miniupnpc" NAMESPACE miniupnpc::) install (TARGETS libminiupnpc-static EXPORT libminiupnpc-static RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) install (EXPORT libminiupnpc-static DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/miniupnpc" NAMESPACE miniupnpc::) endif() if (UPNPC_BUILD_SAMPLE) add_executable (upnpc-static src/upnpc.c) target_link_libraries (upnpc-static PRIVATE libminiupnpc-static) target_include_directories(upnpc-static PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) if (NOT UPNPC_NO_INSTALL) install (TARGETS upnpc-static RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() endif () add_executable (upnp-listdevices-static src/listdevices.c) target_link_libraries (upnp-listdevices-static PRIVATE libminiupnpc-static) target_include_directories(upnp-listdevices-static PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) if (NOT UPNPC_NO_INSTALL) install (TARGETS upnp-listdevices-static RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() endif () if (UPNPC_BUILD_SHARED) add_library (libminiupnpc-shared SHARED ${MINIUPNPC_SOURCES}) target_include_directories (libminiupnpc-shared PUBLIC $ $) add_library (miniupnpc::miniupnpc ALIAS libminiupnpc-shared) set_target_properties (libminiupnpc-shared PROPERTIES EXPORT_NAME miniupnpc) set_target_properties (libminiupnpc-shared PROPERTIES OUTPUT_NAME "miniupnpc") set_target_properties (libminiupnpc-shared PROPERTIES VERSION ${PROJECT_VERSION}) set_target_properties (libminiupnpc-shared PROPERTIES SOVERSION ${MINIUPNPC_API_VERSION}) target_link_libraries (libminiupnpc-shared PRIVATE miniupnpc-private) target_compile_definitions(libminiupnpc-shared PRIVATE MINIUPNP_EXPORTS) target_include_directories(libminiupnpc-shared INTERFACE $) if (WIN32) target_link_libraries(libminiupnpc-shared INTERFACE ws2_32 iphlpapi) endif() if (NOT UPNPC_NO_INSTALL) install (TARGETS libminiupnpc-shared EXPORT libminiupnpc-shared RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) install (EXPORT libminiupnpc-shared DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/miniupnpc" NAMESPACE miniupnpc::) endif() if (UPNPC_BUILD_SAMPLE) add_executable (upnpc-shared src/upnpc.c) target_link_libraries (upnpc-shared PRIVATE libminiupnpc-shared) target_include_directories(upnpc-shared PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) if (NOT UPNPC_NO_INSTALL) install (TARGETS upnpc-shared RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() endif () add_executable (upnp-listdevices-shared src/listdevices.c) target_link_libraries (upnp-listdevices-shared PRIVATE libminiupnpc-shared) target_include_directories(upnp-listdevices-shared PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) if (NOT UPNPC_NO_INSTALL) install (TARGETS upnp-listdevices-shared RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() endif () if (UPNPC_BUILD_TESTS) add_library(miniupnpc-tests INTERFACE) target_link_libraries(miniupnpc-tests INTERFACE miniupnpc-private) target_compile_definitions(miniupnpc-tests INTERFACE MINIUPNP_STATICLIB) add_executable (testminixml src/testminixml.c src/minixml.c src/igd_desc_parse.c) target_include_directories (testminixml PRIVATE $) target_link_libraries (testminixml PRIVATE miniupnpc-tests) add_executable (minixmlvalid src/minixmlvalid.c src/minixml.c) target_link_libraries (minixmlvalid PRIVATE miniupnpc-tests) add_executable (testupnpreplyparse src/testupnpreplyparse.c src/minixml.c src/upnpreplyparse.c) target_include_directories (testupnpreplyparse PRIVATE $) target_link_libraries (testupnpreplyparse PRIVATE miniupnpc-tests) add_executable (testigddescparse src/testigddescparse.c src/igd_desc_parse.c src/minixml.c src/miniupnpc.c src/miniwget.c src/minissdpc.c src/upnpcommands.c src/upnpreplyparse.c src/minisoap.c src/connecthostport.c src/portlistingparse.c src/receivedata.c src/addr_is_reserved.c ) target_include_directories (testigddescparse PRIVATE $) target_link_libraries (testigddescparse PRIVATE miniupnpc-tests) add_executable (testminiwget src/testminiwget.c src/miniwget.c src/miniupnpc.c src/minisoap.c src/upnpcommands.c src/minissdpc.c src/upnpreplyparse.c src/minixml.c src/igd_desc_parse.c src/connecthostport.c src/portlistingparse.c src/receivedata.c src/addr_is_reserved.c ) target_include_directories (testminiwget PRIVATE $) target_link_libraries (testminiwget PRIVATE miniupnpc-tests) add_executable (testaddr_is_reserved src/testaddr_is_reserved.c src/addr_is_reserved.c ) target_link_libraries (testaddr_is_reserved PRIVATE miniupnpc-tests) add_executable (testportlistingparse src/testportlistingparse.c src/minixml.c src/portlistingparse.c) target_include_directories (testportlistingparse PRIVATE $) target_link_libraries (testportlistingparse PRIVATE miniupnpc-tests) if (NOT WIN32) add_executable (minihttptestserver src/minihttptestserver.c) endif() # set (UPNPC_INSTALL_TARGETS ${UPNPC_INSTALL_TARGETS} testminixml minixmlvalid testupnpreplyparse testigddescparse testminiwget) include(CTest) add_test(NAME validateminixml COMMAND minixmlvalid) add_test(NAME validateminiwget COMMAND ${CMAKE_SOURCE_DIR}/testminiwget.sh) if (NOT WIN32) set_property(TEST validateminiwget PROPERTY ENVIRONMENT TESTSERVER=${CMAKE_BINARY_DIR}/minihttptestserver TESTMINIWGET=${CMAKE_BINARY_DIR}/testminiwget) endif() add_test(NAME validateupnpreplyparse COMMAND ${CMAKE_SOURCE_DIR}/testupnpreplyparse.sh WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) set_property(TEST validateupnpreplyparse PROPERTY ENVIRONMENT TESTUPNPREPLYPARSE=${CMAKE_BINARY_DIR}/testupnpreplyparse) add_test(NAME validateportlistingparse COMMAND testportlistingparse) add_test(NAME validateigddescparse1 COMMAND testigddescparse new_LiveBox_desc.xml new_LiveBox_desc.values WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/testdesc) add_test(NAME validateigddescparse2 COMMAND testigddescparse linksys_WAG200G_desc.xml linksys_WAG200G_desc.values WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/testdesc) add_test(NAME validateaddr_is_reserved COMMAND testaddr_is_reserved) endif () configure_file(miniupnpc.pc.in miniupnpc.pc @ONLY) if (NOT UPNPC_NO_INSTALL) install (FILES include/miniupnpc.h include/miniwget.h include/upnpcommands.h include/igd_desc_parse.h include/upnpreplyparse.h include/upnperrors.h include/upnpdev.h include/miniupnpctypes.h include/portlistingparse.h include/miniupnpc_declspec.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/miniupnpc ) install(FILES miniupnpc-config.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/miniupnpc ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/miniupnpc.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig ) install(FILES man3/miniupnpc.3 DESTINATION ${CMAKE_INSTALL_MANDIR}/man3 ) install(FILES external-ip.sh TYPE BIN ) endif() # vim: ts=2:sw=2:expandtab miniupnpc-2.2.6/miniupnpcstrings.h.cmake010064400017500000024000000007541454537750100175720ustar00nanardstaff#ifndef MINIUPNPCSTRINGS_H_INCLUDED #define MINIUPNPCSTRINGS_H_INCLUDED #define OS_STRING "${CMAKE_SYSTEM_NAME}" #define MINIUPNPC_VERSION_STRING "${MINIUPNPC_VERSION}" #if 0 /* according to "UPnP Device Architecture 1.0" */ #define UPNP_VERSION_MAJOR 1 #define UPNP_VERSION_MINOR 0 #define UPNP_VERSION_STRING "UPnP/1.0" #else /* according to "UPnP Device Architecture 1.1" */ #define UPNP_VERSION_MAJOR 1 #define UPNP_VERSION_MINOR 1 #define UPNP_VERSION_STRING "UPnP/1.1" #endif #endif miniupnpc-2.2.6/miniupnpc-config.cmake010064400017500000024000000004621376227073600171730ustar00nanardstaffif(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/libminiupnpc-shared.cmake" OR MINIUPNPC_USE_STATIC_LIBS) include("${CMAKE_CURRENT_LIST_DIR}/miniupnpc-private.cmake") include("${CMAKE_CURRENT_LIST_DIR}/libminiupnpc-static.cmake") else() include("${CMAKE_CURRENT_LIST_DIR}/libminiupnpc-shared.cmake") endif() miniupnpc-2.2.6/src/receivedata.c010064400017500000024000000060431401754661000161230ustar00nanardstaff/* $Id: receivedata.c,v 1.10 2021/03/02 23:33:07 nanard Exp $ */ /* Project : miniupnp * Website : http://miniupnp.free.fr/ * Author : Thomas Bernard * Copyright (c) 2011-2021 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. */ #include #include #ifdef _WIN32 #include #include #else /* _WIN32 */ #include #if defined(__amigaos__) && !defined(__amigaos4__) #define socklen_t int #else /* #if defined(__amigaos__) && !defined(__amigaos4__) */ #include #endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */ #include #include #if !defined(__amigaos__) && !defined(__amigaos4__) #include #endif /* !defined(__amigaos__) && !defined(__amigaos4__) */ #include #define MINIUPNPC_IGNORE_EINTR #endif /* _WIN32 */ #include "receivedata.h" int receivedata(SOCKET socket, char * data, int length, int timeout, unsigned int * scope_id) { #ifdef MINIUPNPC_GET_SRC_ADDR struct sockaddr_storage src_addr; socklen_t src_addr_len = sizeof(src_addr); #endif /* MINIUPNPC_GET_SRC_ADDR */ int n; #if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) /* using poll */ struct pollfd fds[1]; /* for the poll */ #ifdef MINIUPNPC_IGNORE_EINTR do { #endif /* MINIUPNPC_IGNORE_EINTR */ fds[0].fd = socket; fds[0].events = POLLIN; n = poll(fds, 1, timeout); #ifdef MINIUPNPC_IGNORE_EINTR } while(n < 0 && errno == EINTR); #endif /* MINIUPNPC_IGNORE_EINTR */ if(n < 0) { PRINT_SOCKET_ERROR("poll"); return -1; } else if(n == 0) { /* timeout */ return 0; } #else /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */ /* using select under _WIN32 and amigaos */ fd_set socketSet; TIMEVAL timeval; FD_ZERO(&socketSet); FD_SET(socket, &socketSet); timeval.tv_sec = timeout / 1000; timeval.tv_usec = (timeout % 1000) * 1000; n = select(FD_SETSIZE, &socketSet, NULL, NULL, &timeval); if(n < 0) { PRINT_SOCKET_ERROR("select"); return -1; } else if(n == 0) { return 0; } #endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */ #ifdef MINIUPNPC_GET_SRC_ADDR memset(&src_addr, 0, sizeof(src_addr)); n = recvfrom(socket, data, length, 0, (struct sockaddr *)&src_addr, &src_addr_len); #else /* MINIUPNPC_GET_SRC_ADDR */ n = recv(socket, data, length, 0); #endif /* MINIUPNPC_GET_SRC_ADDR */ if(n<0) { PRINT_SOCKET_ERROR("recv"); } #ifdef MINIUPNPC_GET_SRC_ADDR if (src_addr.ss_family == AF_INET6) { const struct sockaddr_in6 * src_addr6 = (struct sockaddr_in6 *)&src_addr; #ifdef DEBUG printf("scope_id=%u\n", src_addr6->sin6_scope_id); #endif /* DEBUG */ if(scope_id) *scope_id = src_addr6->sin6_scope_id; } else { if(scope_id) *scope_id = 0; } #else /* MINIUPNPC_GET_SRC_ADDR */ if(scope_id) *scope_id = 0; #endif /* MINIUPNPC_GET_SRC_ADDR */ return n; } miniupnpc-2.2.6/src/receivedata.h010064400017500000024000000013551326165065200161330ustar00nanardstaff/* $Id: receivedata.h,v 1.5 2018/04/06 10:53:15 nanard Exp $ */ /* Project: miniupnp * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * Author: Thomas Bernard * Copyright (c) 2011-2018 Thomas Bernard * This software is subjects to the conditions detailed * in the LICENCE file provided within this distribution */ #ifndef RECEIVEDATA_H_INCLUDED #define RECEIVEDATA_H_INCLUDED #include "miniupnpc_socketdef.h" /* Reads data from the specified socket. * Returns the number of bytes read if successful, zero if no bytes were * read or if we timed out. Returns negative if there was an error. */ int receivedata(SOCKET socket, char * data, int length, int timeout, unsigned int * scope_id); #endif miniupnpc-2.2.6/src/minihttptestserver.c010064400017500000024000000373601366427612300176460ustar00nanardstaff/* $Id: minihttptestserver.c,v 1.25 2020/05/29 21:14:22 nanard Exp $ */ /* Project : miniUPnP * Author : Thomas Bernard * Copyright (c) 2011-2018 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. * */ #include #include #include #include #include #include #include #include #include #include #include #include #ifndef INADDR_LOOPBACK #define INADDR_LOOPBACK 0x7f000001 #endif #define CRAP_LENGTH (2048) static int server(unsigned short port, const char * expected_file_name, int ipv6); volatile sig_atomic_t quit = 0; volatile sig_atomic_t child_to_wait_for = 0; /** * signal handler for SIGCHLD (child status has changed) */ void handle_signal_chld(int sig) { (void)sig; /* printf("handle_signal_chld(%d)\n", sig); */ ++child_to_wait_for; } /** * signal handler for SIGINT (CRTL C) */ void handle_signal_int(int sig) { (void)sig; /* printf("handle_signal_int(%d)\n", sig); */ quit = 1; } /** * build a text/plain content of the specified length */ void build_content(char * p, size_t n) { char line_buffer[80]; int k; int i = 0; while(n > 0) { k = snprintf(line_buffer, sizeof(line_buffer), "%04d_ABCDEFGHIJKL_This_line_is_64_bytes_long_ABCDEFGHIJKL_%04d\r\n", i, i); if(k != 64) { fprintf(stderr, "snprintf() returned %d in build_content()\n", k); } ++i; if(n >= 64) { memcpy(p, line_buffer, 64); p += 64; n -= 64; } else { memcpy(p, line_buffer, n); p += n; n = 0; } } } /** * build crappy content */ void build_crap(char * p, size_t n) { static const char crap[] = "_CRAP_\r\n"; size_t i; while(n > 0) { i = sizeof(crap) - 1; if(i > n) i = n; memcpy(p, crap, i); p += i; n -= i; } } /** * build chunked response. * return a malloc'ed buffer */ char * build_chunked_response(size_t content_length, size_t * response_len) { char * response_buffer; char * content_buffer; size_t buffer_length; size_t i; unsigned int n; /* 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" "Transfer-Encoding: chunked\r\n" "\r\n"); /* 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 */ i = 0; while(i < content_length) { n = (rand() % 199) + 1; if(i + n > content_length) { n = content_length - i; } /* TODO : check buffer size ! */ *response_len += snprintf(response_buffer + *response_len, buffer_length - *response_len, "%x\r\n", n); memcpy(response_buffer + *response_len, content_buffer + i, n); *response_len += n; i += n; response_buffer[(*response_len)++] = '\r'; response_buffer[(*response_len)++] = '\n'; } /* the last chunk : "0\r\n" a empty body and then * the final "\r\n" */ memcpy(response_buffer + *response_len, "0\r\n\r\n", 5); *response_len += 5; free(content_buffer); printf("resp_length=%lu buffer_length=%lu content_length=%lu\n", *response_len, buffer_length, content_length); return response_buffer; } /* favicon.ico generator */ #ifdef OLD_HEADER #define FAVICON_LENGTH (6 + 16 + 12 + 8 + 32 * 4) #else #define FAVICON_LENGTH (6 + 16 + 40 + 8 + 32 * 4) #endif void build_favicon_content(unsigned char * p, size_t n) { int i; if(n < FAVICON_LENGTH) return; /* header : 6 bytes */ *p++ = 0; *p++ = 0; *p++ = 1; /* type : ICO */ *p++ = 0; *p++ = 1; /* number of images in file */ *p++ = 0; /* image directory (1 entry) : 16 bytes */ *p++ = 16; /* width */ *p++ = 16; /* height */ *p++ = 2; /* number of colors in the palette. 0 = no palette */ *p++ = 0; /* reserved */ *p++ = 1; /* color planes */ *p++ = 0; /* " */ *p++ = 1; /* bpp */ *p++ = 0; /* " */ #ifdef OLD_HEADER *p++ = 12 + 8 + 32 * 4; /* bmp size */ #else *p++ = 40 + 8 + 32 * 4; /* bmp size */ #endif *p++ = 0; /* " */ *p++ = 0; /* " */ *p++ = 0; /* " */ *p++ = 6 + 16; /* bmp offset */ *p++ = 0; /* " */ *p++ = 0; /* " */ *p++ = 0; /* " */ /* BMP */ #ifdef OLD_HEADER /* BITMAPCOREHEADER */ *p++ = 12; /* size of this header */ *p++ = 0; /* " */ *p++ = 0; /* " */ *p++ = 0; /* " */ *p++ = 16; /* width */ *p++ = 0; /* " */ *p++ = 16 * 2; /* height x 2 ! */ *p++ = 0; /* " */ *p++ = 1; /* color planes */ *p++ = 0; /* " */ *p++ = 1; /* bpp */ *p++ = 0; /* " */ #else /* BITMAPINFOHEADER */ *p++ = 40; /* size of this header */ *p++ = 0; /* " */ *p++ = 0; /* " */ *p++ = 0; /* " */ *p++ = 16; /* width */ *p++ = 0; /* " */ *p++ = 0; /* " */ *p++ = 0; /* " */ *p++ = 16 * 2; /* height x 2 ! */ *p++ = 0; /* " */ *p++ = 0; /* " */ *p++ = 0; /* " */ *p++ = 1; /* color planes */ *p++ = 0; /* " */ *p++ = 1; /* bpp */ *p++ = 0; /* " */ /* compression method, image size, ppm x, ppm y */ /* colors in the palette ? */ /* important colors */ for(i = 4 * 6; i > 0; --i) *p++ = 0; #endif /* palette */ *p++ = 0; /* b */ *p++ = 0; /* g */ *p++ = 0; /* r */ *p++ = 0; /* reserved */ *p++ = 255; /* b */ *p++ = 255; /* g */ *p++ = 255; /* r */ *p++ = 0; /* reserved */ /* pixel data */ for(i = 16; i > 0; --i) { if(i & 1) { *p++ = 0125; *p++ = 0125; } else { *p++ = 0252; *p++ = 0252; } *p++ = 0; *p++ = 0; } /* Opacity MASK */ for(i = 16 * 4; i > 0; --i) { *p++ = 0; } } enum modes { MODE_INVALID, MODE_CHUNKED, MODE_ADDCRAP, MODE_NORMAL, MODE_FAVICON, MODE_MALFORMED }; const struct { const enum modes mode; const char * text; } modes_array[] = { {MODE_CHUNKED, "chunked"}, {MODE_ADDCRAP, "addcrap"}, {MODE_NORMAL, "normal"}, {MODE_FAVICON, "favicon.ico"}, {MODE_MALFORMED, "malformed"}, {MODE_INVALID, NULL} }; /** * write the response with random behaviour ! */ void send_response(int c, const char * buffer, size_t len) { ssize_t n; while(len > 0) { n = (rand() % 99) + 1; if((size_t)n > len) n = len; n = write(c, buffer, n); if(n < 0) { if(errno != EINTR) { perror("write"); return; } /* if errno == EINTR, try again */ } else { len -= n; buffer += n; usleep(10000); /* 10ms */ } } } /** * handle the HTTP connection */ void handle_http_connection(int c) { char request_buffer[2048]; size_t request_len = 0; int headers_found = 0; ssize_t n, m; size_t i; char request_method[16]; char request_uri[256]; char http_version[16]; char * p; char * response_buffer; size_t response_len; enum modes mode; size_t content_length = 16*1024; /* read the request */ while(request_len < sizeof(request_buffer) && !headers_found) { n = read(c, request_buffer + request_len, sizeof(request_buffer) - request_len); if(n < 0) { if(errno == EINTR) continue; perror("read"); return; } else if(n==0) { /* remote host closed the connection */ break; } else { request_len += n; for(i = 0; i < request_len - 3; i++) { if(0 == memcmp(request_buffer + i, "\r\n\r\n", 4)) { /* found the end of headers */ headers_found = 1; break; } } } } if(!headers_found) { /* error */ printf("no HTTP header found in the request\n"); return; } printf("headers :\n%.*s", (int)request_len, request_buffer); /* the request have been received, now parse the request line */ p = request_buffer; for(i = 0; i < sizeof(request_method) - 1; i++) { if(*p == ' ' || *p == '\r') break; request_method[i] = *p; ++p; } request_method[i] = '\0'; while(*p == ' ') p++; for(i = 0; i < (int)sizeof(request_uri) - 1; i++) { if(*p == ' ' || *p == '\r') break; request_uri[i] = *p; ++p; } request_uri[i] = '\0'; while(*p == ' ') p++; for(i = 0; i < (int)sizeof(http_version) - 1; i++) { if(*p == ' ' || *p == '\r') break; http_version[i] = *p; ++p; } http_version[i] = '\0'; printf("Method = %s, URI = %s, %s\n", request_method, request_uri, http_version); /* check if the request method is allowed */ if(0 != strcmp(request_method, "GET")) { const char response405[] = "HTTP/1.1 405 Method Not Allowed\r\n" "Allow: GET\r\n\r\n"; const char * pc; /* 405 Method Not Allowed */ /* The response MUST include an Allow header containing a list * of valid methods for the requested resource. */ n = sizeof(response405) - 1; pc = response405; while(n > 0) { m = write(c, pc, n); if(m<0) { if(errno != EINTR) { perror("write"); return; } } else { n -= m; pc += m; } } return; } mode = MODE_INVALID; /* use the request URI to know what to do */ for(i = 0; modes_array[i].mode != MODE_INVALID; i++) { if(strstr(request_uri, modes_array[i].text)) { mode = modes_array[i].mode; /* found */ break; } } switch(mode) { case MODE_MALFORMED: response_len = 2048; response_buffer = malloc(response_len); if(!response_buffer) break; n = snprintf(response_buffer, response_len, "HTTP/1.1 \r\n" "\r\n" /*"0000\r\n"*/); for (i = n; i < response_len; i++) { response_buffer[i] = ' '; } response_len = n; break; case MODE_CHUNKED: response_buffer = build_chunked_response(content_length, &response_len); break; case MODE_ADDCRAP: response_len = content_length+256; response_buffer = malloc(response_len); if(!response_buffer) break; n = snprintf(response_buffer, response_len, "HTTP/1.1 200 OK\r\n" "Server: minihttptestserver\r\n" "Content-Type: text/plain\r\n" "Content-Length: %lu\r\n" "\r\n", content_length); response_len = content_length+n+CRAP_LENGTH; p = realloc(response_buffer, response_len); if(p == NULL) { /* error 500 */ free(response_buffer); response_buffer = NULL; break; } response_buffer = p; build_content(response_buffer + n, content_length); build_crap(response_buffer + n + content_length, CRAP_LENGTH); break; case MODE_FAVICON: content_length = FAVICON_LENGTH; response_len = content_length + 256; response_buffer = malloc(response_len); if(!response_buffer) break; n = snprintf(response_buffer, response_len, "HTTP/1.1 200 OK\r\n" "Server: minihttptestserver\r\n" "Content-Type: image/vnd.microsoft.icon\r\n" "Content-Length: %lu\r\n" "\r\n", content_length); /* image/x-icon */ build_favicon_content((unsigned char *)(response_buffer + n), content_length); response_len = content_length + n; break; default: response_len = content_length+256; response_buffer = malloc(response_len); if(!response_buffer) break; n = snprintf(response_buffer, response_len, "HTTP/1.1 200 OK\r\n" "Server: minihttptestserver\r\n" "Content-Type: text/plain\r\n" "\r\n"); response_len = content_length+n; p = realloc(response_buffer, response_len); if(p == NULL) { /* Error 500 */ free(response_buffer); response_buffer = NULL; break; } response_buffer = p; build_content(response_buffer + n, response_len - n); } if(response_buffer) { send_response(c, response_buffer, response_len); free(response_buffer); } else { /* Error 500 */ } } /** */ int main(int argc, char * * argv) { int ipv6 = 0; int r, i; unsigned short port = 0; const char * expected_file_name = NULL; for(i = 1; i < argc; i++) { if(argv[i][0] == '-') { switch(argv[i][1]) { case '6': ipv6 = 1; break; case 'e': /* write expected file ! */ expected_file_name = argv[++i]; break; case 'p': /* port */ if(++i < argc) { port = (unsigned short)atoi(argv[i]); } break; default: fprintf(stderr, "unknown command line switch '%s'\n", argv[i]); } } else { fprintf(stderr, "unknown command line argument '%s'\n", argv[i]); } } srand(time(NULL)); r = server(port, expected_file_name, ipv6); if(r != 0) { printf("*** ERROR ***\n"); } return r; } static int server(unsigned short port, const char * expected_file_name, int ipv6) { int s, c; int i; struct sockaddr_storage server_addr; socklen_t server_addrlen; struct sockaddr_storage client_addr; socklen_t client_addrlen; pid_t pid; int child = 0; int status; struct sigaction sa; memset(&sa, 0, sizeof(struct sigaction)); /*signal(SIGCHLD, handle_signal_chld);*/ sa.sa_handler = handle_signal_chld; if(sigaction(SIGCHLD, &sa, NULL) < 0) { perror("sigaction"); return 1; } /*signal(SIGINT, handle_signal_int);*/ sa.sa_handler = handle_signal_int; if(sigaction(SIGINT, &sa, NULL) < 0) { perror("sigaction"); return 1; } s = socket(ipv6 ? AF_INET6 : AF_INET, SOCK_STREAM, 0); if(s < 0) { perror("socket"); return 1; } memset(&server_addr, 0, sizeof(struct sockaddr_storage)); memset(&client_addr, 0, sizeof(struct sockaddr_storage)); if(ipv6) { struct sockaddr_in6 * addr = (struct sockaddr_in6 *)&server_addr; addr->sin6_family = AF_INET6; addr->sin6_port = htons(port); addr->sin6_addr = in6addr_loopback; } else { struct sockaddr_in * addr = (struct sockaddr_in *)&server_addr; addr->sin_family = AF_INET; addr->sin_port = htons(port); addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK); } if(bind(s, (struct sockaddr *)&server_addr, ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) < 0) { perror("bind"); return 1; } if(listen(s, 5) < 0) { perror("listen"); } if(port == 0) { server_addrlen = sizeof(struct sockaddr_storage); if(getsockname(s, (struct sockaddr *)&server_addr, &server_addrlen) < 0) { perror("getsockname"); return 1; } if(ipv6) { struct sockaddr_in6 * addr = (struct sockaddr_in6 *)&server_addr; port = ntohs(addr->sin6_port); } else { struct sockaddr_in * addr = (struct sockaddr_in *)&server_addr; port = ntohs(addr->sin_port); } printf("Listening on port %hu\n", port); fflush(stdout); } /* write expected file */ if(expected_file_name) { FILE * f; f = fopen(expected_file_name, "wb"); if(f) { char * buffer; buffer = malloc(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); } fclose(f); } else { fprintf(stderr, "error opening file %s for writing\n", expected_file_name); } } /* fork() loop */ while(!child && !quit) { while(child_to_wait_for > 0) { pid = wait(&status); if(pid < 0) { perror("wait"); } else { printf("child(%d) terminated with status %d\n", (int)pid, status); } --child_to_wait_for; } client_addrlen = sizeof(struct sockaddr_storage); c = accept(s, (struct sockaddr *)&client_addr, &client_addrlen); if(c < 0) { if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) continue; perror("accept"); return 1; } printf("accept...\n"); pid = fork(); if(pid < 0) { perror("fork"); return 1; } else if(pid == 0) { /* child */ child = 1; close(s); s = -1; handle_http_connection(c); } close(c); } if(s >= 0) { close(s); s = -1; } if(!child) { while(child_to_wait_for > 0) { pid = wait(&status); if(pid < 0) { perror("wait"); } else { printf("child(%d) terminated with status %d\n", (int)pid, status); } --child_to_wait_for; } printf("Bye...\n"); } return 0; } miniupnpc-2.2.6/testminiwget.sh010075500017500000024000000057641432460530200160020ustar00nanardstaff#!/bin/sh # $Id: testminiwget.sh,v 1.20 2022/10/21 21:09:42 nanard Exp $ # vim: tabstop=4 shiftwidth=4 noexpandtab # project miniupnp : http://miniupnp.free.fr/ # or https://miniupnp.tuxfamily.org/ # (c) 2011-2022 Thomas Bernard # # test program for miniwget.c # is usually invoked by "make check" # # This test program : # 1 - launches a local HTTP server (minihttptestserver) # 2 - uses testminiwget to retrieve data from this server # 3 - compares served and received data # 4 - kills the local HTTP server and exits # # The script was tested and works with ksh, bash # it should now also run with dash TMPD=`mktemp -d -t miniwgetXXXXXXXXXX` if [ -z "$TESTSERVER" ] ; then TESTSERVER=./build/minihttptestserver fi if [ -z "$TESTMINIWGET" ] ; then TESTMINIWGET=./build/testminiwget fi HTTPSERVEROUT="${TMPD}/httpserverout" EXPECTEDFILE="${TMPD}/expectedfile" DOWNLOADEDFILE="${TMPD}/downloadedfile" PORT= RET=0 IPCONFIG=$(which ifconfig) IP=$(which ip) if [ "$IP" ] ; then if ! $IP addr | grep inet6 ; then HAVE_IPV6=no fi else if [ -z "$IPCONFIG" ] ; then IPCONFIG="/sbin/ifconfig" fi if ! $IPCONFIG -a | grep inet6 ; then HAVE_IPV6=no fi fi case "$HAVE_IPV6" in n|no|0) ADDR=localhost SERVERARGS="" ;; *) ADDR="[::1]" SERVERARGS="-6" ;; esac if [ ! -x "$TESTSERVER" ] || [ ! -x "$TESTMINIWGET" ] ; then echo "Please build $TESTSERVER and $TESTMINIWGET" #make minihttptestserver #make testminiwget exit 1 fi # launching the test HTTP server $TESTSERVER $SERVERARGS -e $EXPECTEDFILE > $HTTPSERVEROUT & SERVERPID=$! while [ -z "$PORT" ]; do sleep 1 PORT=`cat $HTTPSERVEROUT | sed 's/Listening on port \([0-9]*\)/\1/' ` done if [ "$PORT" = "*** ERROR ***" ]; then echo "HTTP test server error" echo "Network config :" $IPCONFIG -a exit 2 fi echo "Test HTTP server is listening on $PORT" URL1="http://$ADDR:$PORT/index.html" URL2="http://$ADDR:$PORT/chunked" URL3="http://$ADDR:$PORT/addcrap" URL4="http://$ADDR:$PORT/malformed" echo "standard test ..." $TESTMINIWGET $URL1 "${DOWNLOADEDFILE}.1" if cmp $EXPECTEDFILE "${DOWNLOADEDFILE}.1" ; then echo "ok" else echo "standard test FAILED" RET=1 fi echo "chunked transfert encoding test ..." $TESTMINIWGET $URL2 "${DOWNLOADEDFILE}.2" if cmp $EXPECTEDFILE "${DOWNLOADEDFILE}.2" ; then echo "ok" else echo "chunked transfert encoding test FAILED" RET=1 fi echo "response too long test ..." $TESTMINIWGET $URL3 "${DOWNLOADEDFILE}.3" if cmp $EXPECTEDFILE "${DOWNLOADEDFILE}.3" ; then echo "ok" else echo "response too long test FAILED" RET=1 fi echo "malformed response test ..." $TESTMINIWGET $URL4 "${DOWNLOADEDFILE}.4" # kill the test HTTP server kill $SERVERPID wait $SERVERPID # remove temporary files (for success cases) if [ $RET -eq 0 ]; then rm -f "${DOWNLOADEDFILE}.1" rm -f "${DOWNLOADEDFILE}.2" rm -f "${DOWNLOADEDFILE}.3" rm -f $EXPECTEDFILE $HTTPSERVEROUT rmdir ${TMPD} else echo "at least one of the test FAILED" echo "directory ${TMPD} is left intact" fi exit $RET miniupnpc-2.2.6/apiversions.txt010064400017500000024000000117121326165065200160200ustar00nanardstaff$Id: apiversions.txt,v 1.10 2018/04/06 10:53:13 nanard Exp $ Differences in API between miniUPnPc versions API version 17 change struct UPNPDev move getHTTPResponse() to miniwget_private.h updated macro : #define MINIUPNPC_API_VERSION 17 API version 16 added "status_code" argument to getHTTPResponse(), miniwget() and miniwget_getaddr() updated macro : #define MINIUPNPC_API_VERSION 16 API version 15 changed "sameport" argument of upnpDiscover() upnpDiscoverAll() upnpDiscoverDevice() to "localport". When 0 or 1, behaviour is not changed, but it can take any other value between 2 and 65535 Existing programs should be compatible updated macro : #define MINIUPNPC_API_VERSION 15 API version 14 miniupnpc.h add ttl argument to upnpDiscover() upnpDiscoverAll() upnpDiscoverDevice() upnpDiscoverDevices() getDevicesFromMiniSSDPD() : connectToMiniSSDPD() / disconnectFromMiniSSDPD() requestDevicesFromMiniSSDPD() / receiveDevicesFromMiniSSDPD() updated macro : #define MINIUPNPC_API_VERSION 14 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() functions updated macros : #define MINIUPNPC_API_VERSION 12 API version 11 upnpreplyparse.h / portlistingparse.h : removed usage of sys/queue.h / bsdqueue.h miniupnpc.h: updated macros : #define MINIUPNPC_API_VERSION 11 ====================== miniUPnPc version 1.9 ====================== API version 10 upnpcommands.h: added argument remoteHost to UPNP_GetSpecificPortMappingEntry() miniupnpc.h: updated macros : #define MINIUPNPC_VERSION "1.9" #define MINIUPNPC_API_VERSION 10 ====================== miniUPnPc version 1.8 ====================== API version 9 miniupnpc.h: updated macros : #define MINIUPNPC_VERSION "1.8" #define MINIUPNPC_API_VERSION 9 added "unsigned int scope_id;" to struct UPNPDev added scope_id argument to GetUPNPUrls() ====================== miniUPnPc version 1.7 ====================== API version 8 miniupnpc.h : add new macros : #define MINIUPNPC_VERSION "1.7" #define MINIUPNPC_API_VERSION 8 add rootdescURL to struct UPNPUrls ====================== miniUPnPc version 1.6 ====================== API version 8 Adding support for IPv6. igd_desc_parse.h : struct IGDdatas_service : add char presentationurl[MINIUPNPC_URL_MAXSIZE]; struct IGDdatas : add struct IGDdatas_service IPv6FC; miniupnpc.h : new macros : #define UPNPDISCOVER_SUCCESS (0) #define UPNPDISCOVER_UNKNOWN_ERROR (-1) #define UPNPDISCOVER_SOCKET_ERROR (-101) #define UPNPDISCOVER_MEMORY_ERROR (-102) simpleUPnPcommand() prototype changed (but is normaly not used by API users) add arguments ipv6 and error to upnpDiscover() : struct UPNPDev * upnpDiscover(int delay, const char * multicastif, const char * minissdpdsock, int sameport, int ipv6, int * error); add controlURL_6FC member to struct UPNPUrls : struct UPNPUrls { char * controlURL; char * ipcondescURL; char * controlURL_CIF; char * controlURL_6FC; }; upnpcommands.h : add leaseDuration argument to UPNP_AddPortMapping() add desc, enabled and leaseDuration arguments to UPNP_GetSpecificPortMappingEntry() add UPNP_GetListOfPortMappings() function (IGDv2) add IGDv2 IPv6 related functions : UPNP_GetFirewallStatus() UPNP_GetOutboundPinholeTimeout() UPNP_AddPinhole() UPNP_UpdatePinhole() UPNP_DeletePinhole() UPNP_CheckPinholeWorking() UPNP_GetPinholePackets() ====================== miniUPnPc version 1.5 ====================== API version 5 new function : int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *); new macro in upnpcommands.h : #define UPNPCOMMAND_HTTP_ERROR ====================== miniUPnPc version 1.4 ====================== Same API as version 1.3 ====================== miniUPnPc version 1.3 ====================== API version 4 Use UNSIGNED_INTEGER type for UPNP_GetTotalBytesSent(), UPNP_GetTotalBytesReceived(), UPNP_GetTotalPacketsSent(), UPNP_GetTotalPacketsReceived() Add remoteHost argument to UPNP_AddPortMapping() and UPNP_DeletePortMapping() ====================== miniUPnPc version 1.2 ====================== API version 3 added sameport argument to upnpDiscover() struct UPNPDev * upnpDiscover(int delay, const char * multicastif, const char * minissdpdsock, int sameport); ====================== miniUPnPc Version 1.1 ====================== Same API as 1.0 ====================== miniUPnPc Version 1.0 ====================== API version 2 struct UPNPDev { struct UPNPDev * pNext; char * descURL; char * st; char buffer[2]; }; struct UPNPDev * upnpDiscover(int delay, const char * multicastif, const char * minissdpdsock); miniupnpc-2.2.6/testreplyparse/DeletePortMapping.namevalue010064400017500000024000000000631214451773100232610ustar00nanardstaffNewRemoteHost= NewExternalPort=123 NewProtocol=TCP miniupnpc-2.2.6/testreplyparse/DeletePortMapping.xml010064400017500000024000000005751214451773100221140ustar00nanardstaff 123 TCP miniupnpc-2.2.6/testreplyparse/GetExternalIPAddress.namevalue010064400017500000024000000000361214451773100236570ustar00nanardstaffNewExternalIPAddress=1.2.3.4 miniupnpc-2.2.6/testreplyparse/GetExternalIPAddress.xml010064400017500000024000000005371214451773100225100ustar00nanardstaff1.2.3.4 miniupnpc-2.2.6/testreplyparse/readme.txt010064400017500000024000000003151214451773100177750ustar00nanardstaffThis directory contains files used for validation of upnpreplyparse.c code. Each .xml file to parse should give the results which are in the .namevalue file. A .namevalue file contain name=value lines. miniupnpc-2.2.6/testupnpreplyparse.sh010075500017500000024000000004501432460530200172330ustar00nanardstaff#!/bin/sh if [ -z "$TESTUPNPREPLYPARSE" ] ; then TESTUPNPREPLYPARSE=./build/testupnpreplyparse fi for f in testreplyparse/*.xml ; do bf="`dirname $f`/`basename $f .xml`" if $TESTUPNPREPLYPARSE $f $bf.namevalue ; then echo "$f : passed" else echo "$f : FAILED" exit 1 fi done exit 0 miniupnpc-2.2.6/testreplyparse/SetDefaultConnectionService.namevalue010064400017500000024000000001571215417747400253120ustar00nanardstaffNewDefaultConnectionService=uuid:c6c05a33-f704-48df-9910-e099b3471d81:WANConnectionDevice:1,INVALID_SERVICE_ID miniupnpc-2.2.6/testreplyparse/SetDefaultConnectionService.xml010064400017500000024000000007071215417747400241360ustar00nanardstaffuuid:c6c05a33-f704-48df-9910-e099b3471d81:WANConnectionDevice:1,INVALID_SERVICE_ID miniupnpc-2.2.6/testreplyparse/GetSpecificPortMappingEntryReq.namevalue010064400017500000024000000000651227144321300257320ustar00nanardstaffNewProtocol=UDP NewExternalPort=12345 NewRemoteHost= miniupnpc-2.2.6/testreplyparse/GetSpecificPortMappingEntryReq.xml010064400017500000024000000006171227144321300245600ustar00nanardstaff 12345UDP miniupnpc-2.2.6/testreplyparse/GetSpecificPortMappingEntryResp.namevalue010064400017500000024000000001761227144321300261170ustar00nanardstaffNewInternalPort=12345 NewInternalClient=192.168.10.110 NewEnabled=1 NewPortMappingDescription=libminiupnpc NewLeaseDuration=0 miniupnpc-2.2.6/testreplyparse/GetSpecificPortMappingEntryResp.xml010064400017500000024000000010311227144321300247310ustar00nanardstaff12345192.168.10.1101libminiupnpc0 miniupnpc-2.2.6/src/listdevices.c010064400017500000024000000131041327254414400161630ustar00nanardstaff/* $Id: listdevices.c,v 1.8 2018/05/03 08:16:44 nanard Exp $ */ /* Project : miniupnp * Author : 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 #include #include #ifdef _WIN32 #include #endif /* _WIN32 */ #include "miniupnpc.h" struct upnp_dev_list { struct upnp_dev_list * next; char * descURL; struct UPNPDev * * array; size_t count; size_t allocated_count; }; #define ADD_DEVICE_COUNT_STEP 16 void add_device(struct upnp_dev_list * * list_head, struct UPNPDev * dev) { struct upnp_dev_list * elt; size_t i; if(dev == NULL) return; for(elt = *list_head; elt != NULL; elt = elt->next) { if(strcmp(elt->descURL, dev->descURL) == 0) { for(i = 0; i < elt->count; i++) { if (strcmp(elt->array[i]->st, dev->st) == 0 && strcmp(elt->array[i]->usn, dev->usn) == 0) { return; /* already found */ } } if(elt->count >= elt->allocated_count) { struct UPNPDev * * tmp; elt->allocated_count += ADD_DEVICE_COUNT_STEP; tmp = realloc(elt->array, elt->allocated_count * sizeof(struct UPNPDev *)); if(tmp == NULL) { fprintf(stderr, "Failed to realloc(%p, %lu)\n", elt->array, (unsigned long)(elt->allocated_count * sizeof(struct UPNPDev *))); return; } elt->array = tmp; } elt->array[elt->count++] = dev; return; } } elt = malloc(sizeof(struct upnp_dev_list)); if(elt == NULL) { fprintf(stderr, "Failed to malloc(%lu)\n", (unsigned long)sizeof(struct upnp_dev_list)); return; } elt->next = *list_head; elt->descURL = strdup(dev->descURL); if(elt->descURL == NULL) { fprintf(stderr, "Failed to strdup(%s)\n", dev->descURL); free(elt); return; } elt->allocated_count = ADD_DEVICE_COUNT_STEP; elt->array = malloc(ADD_DEVICE_COUNT_STEP * sizeof(struct UPNPDev *)); if(elt->array == NULL) { fprintf(stderr, "Failed to malloc(%lu)\n", (unsigned long)(ADD_DEVICE_COUNT_STEP * sizeof(struct UPNPDev *))); free(elt->descURL); free(elt); return; } elt->array[0] = dev; elt->count = 1; *list_head = elt; } void free_device(struct upnp_dev_list * elt) { free(elt->descURL); free(elt->array); free(elt); } 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; struct upnp_dev_list * sorted_list = NULL; struct upnp_dev_list * dev_array; 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, "%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"); return 1; } multicastif = argv[i]; } else { printf("usage : %s [options] [-l ...]\n", argv[0]); printf("options :\n"); printf(" -6 : use IPv6\n"); printf(" -m address/ifname : network interface to use for multicast\n"); printf(" -d : search only for this type of device\n"); printf(" -l ... : 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; } } if(searched_device) { printf("searching UPnP device type %s\n", searched_device); devlist = upnpDiscoverDevice(searched_device, 2000, multicastif, minissdpdpath, 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/*localport*/, ipv6, ttl, &error); } if(devlist) { 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); add_device(&sorted_list, dev); } putchar('\n'); for (dev_array = sorted_list; dev_array != NULL ; dev_array = dev_array->next) { printf("%s :\n", dev_array->descURL); for(i = 0; (unsigned)i < dev_array->count; i++) { printf("%2d: %s\n", i+1, dev_array->array[i]->st); printf(" %s\n", dev_array->array[i]->usn); } putchar('\n'); } freeUPNPDevlist(devlist); while(sorted_list != NULL) { dev_array = sorted_list; sorted_list = sorted_list->next; free_device(dev_array); } } else { printf("no device found.\n"); } return 0; } miniupnpc-2.2.6/testdesc/linksys_WAG200G_desc.values010064400017500000024000000006141243532717300214750ustar00nanardstaff# values for linksys_WAG200G_desc.xml CIF: servicetype = urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1 controlurl = /upnp/control/WANCommonIFC1 eventsuburl = /upnp/event/WANCommonIFC1 scpdurl = /cmnicfg.xml first: servicetype = urn:schemas-upnp-org:service:WANPPPConnection:1 controlurl = /upnp/control/WANPPPConn1 eventsuburl = /upnp/event/WANPPPConn1 scpdurl = /pppcfg.xml miniupnpc-2.2.6/testdesc/linksys_WAG200G_desc.xml010064400017500000024000000076201243532717300210020ustar00nanardstaff 1 0 http://192.168.1.1:49152 urn:schemas-upnp-org:device:InternetGatewayDevice:1 LINKSYS WAG200G Gateway LINKSYS http://www.linksys.com LINKSYS WAG200G Gateway Wireless-G ADSL Home Gateway WAG200G http://www.linksys.com 123456789 uuid:8ca2eb37-1dd2-11b2-86f1-001a709b5aa8 WAG200G urn:schemas-upnp-org:service:Layer3Forwarding:1 urn:upnp-org:serviceId:L3Forwarding1 /upnp/control/L3Forwarding1 /upnp/event/L3Forwarding1 /l3frwd.xml urn:schemas-upnp-org:device:WANDevice:1 WANDevice LINKSYS http://www.linksys.com/ Residential Gateway Internet Connection Sharing 1 http://www.linksys.com/ 0000001 uuid:8ca2eb36-1dd2-11b2-86f1-001a709b5aa8 WAG200G urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1 urn:upnp-org:serviceId:WANCommonIFC1 /upnp/control/WANCommonIFC1 /upnp/event/WANCommonIFC1 /cmnicfg.xml urn:schemas-upnp-org:device:WANConnectionDevice:1 WANConnectionDevice LINKSYS http://www.linksys.com/ Residential Gateway Internet Connection Sharing 1 http://www.linksys.com/ 0000001 uuid:8ca2eb37-1dd2-11b2-86f0-001a709b5aa8 WAG200G urn:schemas-upnp-org:service:WANEthernetLinkConfig:1 urn:upnp-org:serviceId:WANEthLinkC1 /upnp/control/WANEthLinkC1 /upnp/event/WANEthLinkC1 /wanelcfg.xml urn:schemas-upnp-org:service:WANPPPConnection:1 urn:upnp-org:serviceId:WANPPPConn1 /upnp/control/WANPPPConn1 /upnp/event/WANPPPConn1 /pppcfg.xml urn:schemas-upnp-org:device:LANDevice:1 LANDevice LINKSYS http://www.linksys.com/ Residential Gateway Residential Gateway 1 http://www.linksys.com/ 0000001 uuid:8ca2eb36-1dd2-11b2-86f0-001a709b5aa 8 WAG200G urn:schemas-upnp-org:service:LANHostConfigManagement:1 urn:upnp-org:serviceId:LANHostCfg1 /upnp/control/LANHostCfg1 /upnp/event/LANHostCfg1 /lanhostc.xml http://192.168.1.1/index.htm miniupnpc-2.2.6/testdesc/new_LiveBox_desc.values010064400017500000024000000012611243242652300211660ustar00nanardstaff# values for new_LiveBox_desc.xml CIF: servicetype = urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1 controlurl = /87895a19/upnp/control/WANCommonIFC1 eventsuburl = /87895a19/upnp/control/WANCommonIFC1 scpdurl = /87895a19/gateicfgSCPD.xml first: servicetype = urn:schemas-upnp-org:service:WANPPPConnection:2 controlurl = /87895a19/upnp/control/WANIPConn1 eventsuburl = /87895a19/upnp/control/WANIPConn1 scpdurl = /87895a19/gateconnSCPD_PPP.xml IPv6FC: servicetype = urn:schemas-upnp-org:service:WANIPv6FirewallControl:1 controlurl = /87895a19/upnp/control/WANIPv6FwCtrl1 eventsuburl = /87895a19/upnp/control/WANIPv6FwCtrl1 scpdurl = /87895a19/wanipv6fwctrlSCPD.xml miniupnpc-2.2.6/testdesc/new_LiveBox_desc.xml010064400017500000024000000110061243242652300204650ustar00nanardstaff 1 0 VEN_0129&DEV_0000&SUBSYS_03&REV_250417 GenericUmPass NetworkInfrastructure.Gateway Network.Gateway urn:schemas-upnp-org:device:InternetGatewayDevice:2 Orange Livebox Sagemcom http://www.sagemcom.com/ Residential Livebox,(DSL,WAN Ethernet) uuid:87895a19-50f9-3736-a87f-115c230155f8 Sagemcom,fr,SG30_sip-fr-4.28.35.1 3 LK14129DP441489 http://192.168.1.1 image/png 16 16 8 /87895a19/ligd.png urn:schemas-upnp-org:device:WANDevice:2 WANDevice Sagemcom http://www.sagemcom.com/ WAN Device on Sagemcom,fr,SG30_sip-fr-4.28.35.1 Residential Livebox,(DSL,WAN Ethernet) 3 http://www.sagemcom.com/ LK14129DP441489 http://192.168.1.1 uuid:e2397374-53d8-3fc6-8306-593ba1a34625 urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1 urn:upnp-org:serviceId:WANCommonIFC1 /87895a19/upnp/control/WANCommonIFC1 /87895a19/upnp/control/WANCommonIFC1 /87895a19/gateicfgSCPD.xml urn:schemas-upnp-org:device:WANConnectionDevice:2 WANConnectionDevice Sagemcom http://www.sagemcom.com/ WanConnectionDevice on Sagemcom,fr,SG30_sip-fr-4.28.35.1 Residential Livebox,(DSL,WAN Ethernet) 3 http://www.sagemcom.com/ LK14129DP441489 http://192.168.1.1 uuid:44598a08-288e-32c9-8a4d-d3c008ede331 urn:schemas-upnp-org:service:WANPPPConnection:2 urn:upnp-org:serviceId:WANIPConn1 /87895a19/upnp/control/WANIPConn1 /87895a19/upnp/control/WANIPConn1 /87895a19/gateconnSCPD_PPP.xml urn:schemas-upnp-org:service:WANIPv6FirewallControl:1 urn:upnp-org:serviceId:WANIPv6FwCtrl1 /87895a19/upnp/control/WANIPv6FwCtrl1 /87895a19/upnp/control/WANIPv6FwCtrl1 /87895a19/wanipv6fwctrlSCPD.xml miniupnpc-2.2.6/src/testportlistingparse.c010064400017500000024000000113701242513375400201610ustar00nanardstaff/* $Id: testportlistingparse.c,v 1.2 2014/11/01 10:37:32 nanard Exp $ */ /* Project : miniupnp * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * Author : Thomas Bernard * Copyright (c) 2014 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. * */ #include #include #include "portlistingparse.h" struct port_mapping { unsigned int leasetime; unsigned short externalport; unsigned short internalport; const char * remotehost; const char * client; const char * proto; const char * desc; unsigned char enabled; }; /* return the number of differences */ int test(const char * portListingXml, int portListingXmlLen, const struct port_mapping * ref, int count) { int i; int r = 0; struct PortMappingParserData data; struct PortMapping * pm; memset(&data, 0, sizeof(data)); ParsePortListing(portListingXml, portListingXmlLen, &data); for(i = 0, pm = data.l_head; (pm != NULL) && (i < count); i++, pm = pm->l_next) { printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n", i, pm->protocol, pm->externalPort, pm->internalClient, pm->internalPort, pm->description, pm->remoteHost, (unsigned)pm->leaseTime); if(0 != strcmp(pm->protocol, ref[i].proto)) { printf("protocol : '%s' != '%s'\n", pm->protocol, ref[i].proto); r++; } if(pm->externalPort != ref[i].externalport) { printf("externalPort : %hu != %hu\n", pm->externalPort, ref[i].externalport); r++; } if(0 != strcmp(pm->internalClient, ref[i].client)) { printf("client : '%s' != '%s'\n", pm->internalClient, ref[i].client); r++; } if(pm->internalPort != ref[i].internalport) { printf("internalPort : %hu != %hu\n", pm->internalPort, ref[i].internalport); r++; } if(0 != strcmp(pm->description, ref[i].desc)) { printf("description : '%s' != '%s'\n", pm->description, ref[i].desc); r++; } if(0 != strcmp(pm->remoteHost, ref[i].remotehost)) { printf("remoteHost : '%s' != '%s'\n", pm->remoteHost, ref[i].remotehost); r++; } if((unsigned)pm->leaseTime != ref[i].leasetime) { printf("leaseTime : %u != %u\n", (unsigned)pm->leaseTime, ref[i].leasetime); r++; } if(pm->enabled != ref[i].enabled) { printf("enabled : %d != %d\n", (int)pm->enabled, (int)ref[i].enabled); r++; } } if((i != count) || (pm != NULL)) { printf("count mismatch : i=%d count=%d pm=%p\n", i, count, pm); r++; } FreePortListing(&data); return r; } const char test_document[] = "\n" "\n" " \n" " \n" " 5002\n" " UDP\n" " 4001\n" " 192.168.1.123\n" " 1\n" " xxx\n" " 0\n" " \n" " \n" " 202.233.2.1\n" " 2345\n" " TCP\n" " 2349\n" " 192.168.1.137\n" " 1\n" " dooom\n" " 346\n" " \n" " \n" " 134.231.2.11\n" " 12345\n" " TCP\n" " 12345\n" " 192.168.1.137\n" " 1\n" " dooom A\n" " 347\n" " \n" ""; #define PORT_MAPPINGS_COUNT 3 const struct port_mapping port_mappings[PORT_MAPPINGS_COUNT] = { {347, 12345, 12345, "134.231.2.11", "192.168.1.137", "TCP", "dooom A", 1}, {346, 2345, 2349, "202.233.2.1", "192.168.1.137", "TCP", "dooom", 1}, {0, 5002, 4001, "", "192.168.1.123", "UDP", "xxx", 1} }; /* --- main --- */ int main(void) { int r; r = test(test_document, sizeof(test_document) - 1, port_mappings, PORT_MAPPINGS_COUNT); if(r == 0) { printf("test of portlistingparse OK\n"); return 0; } else { printf("test FAILED (%d differences counted)\n", r); return 1; } } miniupnpc-2.2.6/src/upnpdev.c010064400017500000024000000010711257005023300153150ustar00nanardstaff/* $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 #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; } } miniupnpc-2.2.6/src/miniupnpc_socketdef.h010064400017500000024000000017661401754661000177140ustar00nanardstaff/* $Id: miniupnpc_socketdef.h,v 1.4 2021/03/02 23:35:29 nanard Exp $ */ /* Miniupnp project : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * Author : Thomas Bernard * Copyright (c) 2018 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided within this distribution */ #ifndef MINIUPNPC_SOCKETDEF_H_INCLUDED #define MINIUPNPC_SOCKETDEF_H_INCLUDED #ifdef _WIN32 #define ISINVALID(s) (INVALID_SOCKET==(s)) #else #ifndef SOCKET #define SOCKET int #endif #ifndef SSIZE_T #define SSIZE_T ssize_t #endif #ifndef INVALID_SOCKET #define INVALID_SOCKET (-1) #endif #ifndef ISINVALID #define ISINVALID(s) ((s)<0) #endif #endif #ifdef _MSC_VER #define MSC_CAST_INT (int) #else #define MSC_CAST_INT #endif /* definition of PRINT_SOCKET_ERROR */ #ifdef _WIN32 #define PRINT_SOCKET_ERROR(x) fprintf(stderr, "Socket error: %s, %d\n", x, WSAGetLastError()); #else #define PRINT_SOCKET_ERROR(x) perror(x) #endif #endif /* MINIUPNPC_SOCKETDEF_H_INCLUDED */ miniupnpc-2.2.6/src/miniwget_private.h010064400017500000024000000007041326164452600172340ustar00nanardstaff/* $Id: miniwget_private.h,v 1.1 2018/04/06 10:17:58 nanard Exp $ */ /* Project : miniupnp * Author : Thomas Bernard * Copyright (c) 2018 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. * */ #ifndef MINIWGET_INTERNAL_H_INCLUDED #define MINIWGET_INTERNAL_H_INCLUDED #include "miniupnpc_socketdef.h" void * getHTTPResponse(SOCKET s, int * size, int * status_code); #endif miniupnpc-2.2.6/src/addr_is_reserved.h010064400017500000024000000010341373445056700171650ustar00nanardstaff/* $Id: addr_is_reserved.h,v 1.1 2020/09/28 21:11:19 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * Project: miniupnp * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * Author: Thomas Bernard * Copyright (c) 2005-2020 Thomas Bernard * This software is subjects to the conditions detailed * in the LICENCE file provided within this distribution */ #ifndef ADDR_IS_RESERVED_H_INCLUDED #define ADDR_IS_RESERVED_H_INCLUDED int addr_is_reserved(const char * addr_str); #endif /* ADDR_IS_RESERVED_H_INCLUDED */ miniupnpc-2.2.6/src/addr_is_reserved.c010064400017500000024000000055061404631667600171670ustar00nanardstaff/* $Id: addr_is_reserved.c,v 1.5 2021/05/10 20:53:02 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * Project : miniupnp * Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * Author : Thomas BERNARD * copyright (c) 2005-2021 Thomas Bernard * This software is subjet to the conditions detailed in the * provided LICENSE file. */ #ifdef _WIN32 /* Win32 Specific includes and defines */ #include #include #if !defined(_MSC_VER) #include #else /* !defined(_MSC_VER) */ typedef unsigned long uint32_t; #endif /* !defined(_MSC_VER) */ #else /* _WIN32 */ #include #include #include #include #endif /* _WIN32 */ /* List of IP address blocks which are private / reserved and therefore not suitable for public external IP addresses */ #define IP(a, b, c, d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) #define MSK(m) (32-(m)) static const struct { uint32_t address; uint32_t rmask; } reserved[] = { { IP( 0, 0, 0, 0), MSK( 8) }, /* RFC1122 "This host on this network" */ { IP( 10, 0, 0, 0), MSK( 8) }, /* RFC1918 Private-Use */ { IP(100, 64, 0, 0), MSK(10) }, /* RFC6598 Shared Address Space */ { IP(127, 0, 0, 0), MSK( 8) }, /* RFC1122 Loopback */ { IP(169, 254, 0, 0), MSK(16) }, /* RFC3927 Link-Local */ { IP(172, 16, 0, 0), MSK(12) }, /* RFC1918 Private-Use */ { IP(192, 0, 0, 0), MSK(24) }, /* RFC6890 IETF Protocol Assignments */ { IP(192, 0, 2, 0), MSK(24) }, /* RFC5737 Documentation (TEST-NET-1) */ { IP(192, 31, 196, 0), MSK(24) }, /* RFC7535 AS112-v4 */ { IP(192, 52, 193, 0), MSK(24) }, /* RFC7450 AMT */ { IP(192, 88, 99, 0), MSK(24) }, /* RFC7526 6to4 Relay Anycast */ { IP(192, 168, 0, 0), MSK(16) }, /* RFC1918 Private-Use */ { IP(192, 175, 48, 0), MSK(24) }, /* RFC7534 Direct Delegation AS112 Service */ { IP(198, 18, 0, 0), MSK(15) }, /* RFC2544 Benchmarking */ { IP(198, 51, 100, 0), MSK(24) }, /* RFC5737 Documentation (TEST-NET-2) */ { IP(203, 0, 113, 0), MSK(24) }, /* RFC5737 Documentation (TEST-NET-3) */ { IP(224, 0, 0, 0), MSK( 4) }, /* RFC1112 Multicast */ { IP(240, 0, 0, 0), MSK( 4) }, /* RFC1112 Reserved for Future Use + RFC919 Limited Broadcast */ }; #undef IP #undef MSK /** * @return 1 or 0 */ int addr_is_reserved(const char * addr_str) { uint32_t addr_n, address; size_t i; #if defined(_WIN32) && _WIN32_WINNT < 0x0600 // _WIN32_WINNT_VISTA addr_n = inet_addr(addr_str); if (addr_n == INADDR_NONE) return 1; #else /* was : addr_n = inet_addr(addr_str); */ if (inet_pton(AF_INET, addr_str, &addr_n) <= 0) { /* error */ return 1; } #endif address = ntohl(addr_n); for (i = 0; i < sizeof(reserved)/sizeof(reserved[0]); ++i) { if ((address >> reserved[i].rmask) == (reserved[i].address >> reserved[i].rmask)) return 1; } return 0; } miniupnpc-2.2.6/src/testaddr_is_reserved.c010064400017500000024000000022551374214454300200570ustar00nanardstaff/* $Id: testaddr_is_reserved.c,v 1.1 2020/10/15 22:12:51 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * Project : miniupnp * Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * Author : Thomas BERNARD * copyright (c) 2005-2020 Thomas Bernard * This software is subjet to the conditions detailed in the * provided LICENSE file. */ #include #include "addr_is_reserved.h" static const struct { const char * str; int expected_result; } tests[] = { { "0.0.0.0", 1 }, { "8.8.8.8", 0 }, { "192.168.1.1", 1 }, { "10.250.42.12", 1 }, { "11.250.42.12", 0 }, { "172.31.1.1", 1 }, { "172.32.1.1", 0 }, { "169.254.42.42", 1 }, { "192.0.0.11", 1 }, { "198.0.0.11", 0 }, { "198.18.0.11", 1 }, { "100.64.1.1", 1 }, { "100.127.1.1", 1 }, { "100.128.1.1", 0 }, { NULL, 0 } }; int main(int argc, char * * argv) { int i, result; (void)argc; (void)argv; for (i = 0; tests[i].str != NULL; i++) { result = addr_is_reserved(tests[i].str); printf("testing %s %d %d\n", tests[i].str, tests[i].expected_result, result); if (result != tests[i].expected_result) { fprintf(stderr, "*** FAILURE ***\n"); return 1; /* Failure */ } } return 0; /* success */ } miniupnpc-2.2.6/msvc/genminiupnpcstrings.vbs010064400017500000024000000060731376227254700205240ustar00nanardstaff' VBScript to generate miniupnpcstrings.h ' Copyright 2018 Thomas Bernard 'Set WshShell = CreateObject("WScript.Shell") Set FSO = CreateObject("Scripting.FileSystemObject") versionfile = "..\version" infile = "..\miniupnpcstrings.h.in" outfile = "..\miniupnpcstrings.h" outfilerc = "..\rc_version.h" On Error Resume Next 'Wscript.Echo revision Err.Clear Set f = FSO.OpenTextFile(versionfile, 1, False) ' 1 = Read If Err.Number = 0 Then version = f.ReadLine f.Close Else ' Exit error WScript.Quit 1 End If os_version = "0.0.0" strComputer = "." Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2") Set colOperatingSystems = objWMIService.ExecQuery ("Select * from Win32_OperatingSystem") For Each objOperatingSystem in colOperatingSystems 'Wscript.Echo objOperatingSystem.Caption & " -- " os_version = objOperatingSystem.Version Next 'Wscript.Echo os_version Dim array needWrite = True ' First Check if the file already contains the right versions Err.Clear Set f_in = FSO.OpenTextFile(outfile, 1, False) If Err.Number = 0 Then old_version = "" old_os_version = "" Do Until f_in.AtEndOfStream line = f_in.ReadLine If Len(line) > 0 Then array = Split(line, " ") If UBound(array) >= 2 And array(0) = "#define" Then If array(1) = "OS_STRING" Then old_os_version = Replace(array(2), Chr(34), "") ElseIf array(1) = "MINIUPNPC_VERSION_STRING" Then old_version = Replace(array(2), Chr(34), "") End if End if End If Loop f_in.Close If old_version = version And old_os_version = "MSWindows/" & os_version Then needWrite = False Else needWrite = True End If End If If Not needWrite Then ' check files dates Set fIn1 = FSO.GetFile(versionfile) Set fIn2 = FSO.GetFile(infile) Set fOut = FSO.GetFile(outfile) If DateDiff("s", fIn1.DateLastModified, fOut.DateLastModified) < 0 Then needWrite = True End If If DateDiff("s", fIn2.DateLastModified, fOut.DateLastModified) < 0 Then needWrite = True End If End If If Not needWrite Then ' nothing to do WScript.Quit 0 End if ' generate the file Err.Clear Set f_in = FSO.OpenTextFile(infile, 1, False) If Err.Number = 0 Then Set f_out = FSO.OpenTextFile(outfile, 2, True) ' 2 = Write Do Until f_in.AtEndOfStream line = f_in.ReadLine If Len(line) > 0 Then array = Split(line, " ") If UBound(array) >= 2 And array(0) = "#define" Then If array(1) = "OS_STRING" Then line = "#define OS_STRING " & Chr(34) & "MSWindows/" & os_version & Chr(34) ElseIf array(1) = "MINIUPNPC_VERSION_STRING" Then line = "#define MINIUPNPC_VERSION_STRING " & Chr(34) & version & Chr(34) End if End if End If f_out.WriteLine line Loop f_in.Close f_out.Close End If Set f_out = FSO.OpenTextFile(outfilerc, 2, True) ' 2 = Write f_out.WriteLine "#define LIBMINIUPNPC_DOTTED_VERSION " & Chr(34) & version & Chr(34) ver = Split(version, ".") f_out.WriteLine "#define LIBMINIUPNPC_MAJOR_VERSION " & ver(0) f_out.WriteLine "#define LIBMINIUPNPC_MINOR_VERSION " & ver(1) f_out.WriteLine "#define LIBMINIUPNPC_MICRO_VERSION " & ver(2) f_out.Close miniupnpc-2.2.6/msvc/miniupnpc.vcxproj010064400017500000024000000251231412470240400172750ustar00nanardstaff Debug Dll Win32 Debug Win32 Release Dll Win32 Release Win32 {D28CE435-CB33-4BAE-8A52-C6EF915956F5} miniupnpc Win32Proj StaticLibrary v140 Unicode true DynamicLibrary v140 Unicode true StaticLibrary v140 Unicode DynamicLibrary v140 Unicode <_ProjectFileVersion>14.0.25123.0 $(SolutionDir)$(Configuration)\ $(Configuration)\ $(SolutionDir)$(Configuration)\ $(Configuration)\ $(SolutionDir)$(Configuration)\ $(Configuration)\ $(SolutionDir)$(Configuration)\ $(Configuration)\ Disabled _CRT_SECURE_NO_WARNINGS;MINIUPNP_STATICLIB;DEBUG;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level3 EditAndContinue ..;..\include;%(AdditionalIncludeDirectories) genminiupnpcstrings.vbs INTERNAL_NAME="\"miniupnpc.dll\0\"";%(PreprocessorDefinitions) Disabled _CRT_SECURE_NO_WARNINGS;MINIUPNP_EXPORTS;DEBUG;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level3 EditAndContinue ..;..\include;%(AdditionalIncludeDirectories) genminiupnpcstrings.vbs ws2_32.lib;IPHlpApi.Lib;%(AdditionalDependencies) INTERNAL_NAME="\"miniupnpc.dll\0\"";%(PreprocessorDefinitions) MaxSpeed true _CRT_SECURE_NO_WARNINGS;MINIUPNP_STATICLIB;%(PreprocessorDefinitions) MultiThreadedDLL true Level3 ProgramDatabase ..;..\include;%(AdditionalIncludeDirectories) genminiupnpcstrings.vbs INTERNAL_NAME="\"miniupnpc.dll\0\"";%(PreprocessorDefinitions) MaxSpeed true _CRT_SECURE_NO_WARNINGS;MINIUPNP_EXPORTS;%(PreprocessorDefinitions) MultiThreadedDLL true Level3 ProgramDatabase ..;..\include;%(AdditionalIncludeDirectories) genminiupnpcstrings.vbs ws2_32.lib;IPHlpApi.Lib;%(AdditionalDependencies) INTERNAL_NAME="\"miniupnpc.dll\0\"";%(PreprocessorDefinitions) miniupnpc-2.2.6/msvc/miniupnpc.vcxproj.filters010064400017500000024000000113771412470240400207520ustar00nanardstaff {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hpp;hxx;hm;inl;inc;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav {508da401-2f8e-4fdb-9a43-95baa95a91e7} Fichiers sources Fichiers sources Fichiers sources Fichiers sources Fichiers sources Fichiers sources Fichiers sources Fichiers sources Fichiers sources Fichiers sources Fichiers sources Fichiers sources Fichiers sources Fichiers sources Fichiers d%27en-tête Fichiers d%27en-tête Fichiers d%27en-tête Fichiers d%27en-tête Fichiers d%27en-tête Fichiers d%27en-tête Fichiers d%27en-tête Fichiers d%27en-tête Fichiers d%27en-tête Fichiers d%27en-tête Fichiers d%27en-tête Fichiers d%27en-tête Fichiers d%27en-tête Fichiers d%27en-tête Fichiers d%27en-tête Fichiers d%27en-tête Fichiers d%27en-tête Fichiers d%27en-tête Fichiers d%27en-tête scripts Fichiers de ressources miniupnpc-2.2.6/msvc/miniupnpc_vs2010.sln010064400017500000024000000041051343001453400174050ustar00nanardstaff Microsoft Visual Studio Solution File, Format Version 11.00 # Visual C++ Express 2010 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "miniupnpc_vs2010", "miniupnpc_vs2010.vcxproj", "{D28CE435-CB33-4BAE-8A52-C6EF915956F5}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "upnpc-static_vs2010", "upnpc-static_vs2010.vcxproj", "{469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug Dll|Win32 = Debug Dll|Win32 Debug|Win32 = Debug|Win32 Release Dll|Win32 = Release Dll|Win32 Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Debug Dll|Win32.ActiveCfg = Debug Dll|Win32 {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Debug Dll|Win32.Build.0 = Debug Dll|Win32 {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Debug|Win32.ActiveCfg = Debug|Win32 {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Debug|Win32.Build.0 = Debug|Win32 {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Release Dll|Win32.ActiveCfg = Release Dll|Win32 {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Release Dll|Win32.Build.0 = Release Dll|Win32 {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Release|Win32.ActiveCfg = Release|Win32 {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Release|Win32.Build.0 = Release|Win32 {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Debug Dll|Win32.ActiveCfg = Debug Dll|Win32 {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Debug Dll|Win32.Build.0 = Debug Dll|Win32 {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Debug|Win32.ActiveCfg = Debug|Win32 {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Debug|Win32.Build.0 = Debug|Win32 {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Release Dll|Win32.ActiveCfg = Release Dll|Win32 {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Release Dll|Win32.Build.0 = Release Dll|Win32 {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Release|Win32.ActiveCfg = Release|Win32 {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal miniupnpc-2.2.6/msvc/miniupnpc_vs2010.vcxproj010064400017500000024000000257041412470240400203150ustar00nanardstaff Debug Dll Win32 Debug Win32 Release Dll Win32 Release Win32 {D28CE435-CB33-4BAE-8A52-C6EF915956F5} miniupnpc Win32Proj StaticLibrary Unicode true DynamicLibrary Unicode true StaticLibrary Unicode DynamicLibrary Unicode <_ProjectFileVersion>10.0.40219.1 $(SolutionDir)$(Configuration)\ $(SolutionDir)$(Configuration)\ $(Configuration)\ $(Configuration)\ $(SolutionDir)$(Configuration)\ $(SolutionDir)$(Configuration)\ $(Configuration)\ $(Configuration)\ miniupnpc miniupnpc miniupnpc miniupnpc Disabled _CRT_SECURE_NO_WARNINGS;MINIUPNP_STATICLIB;DEBUG;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level3 EditAndContinue ..;..\include;%(AdditionalIncludeDirectories) genminiupnpcstrings.vbs INTERNAL_NAME="\"miniupnpc.dll\0\"";%(PreprocessorDefinitions) Disabled _CRT_SECURE_NO_WARNINGS;MINIUPNP_EXPORTS;DEBUG;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level3 EditAndContinue ..;..\include;%(AdditionalIncludeDirectories) genminiupnpcstrings.vbs ws2_32.lib;IPHlpApi.Lib;%(AdditionalDependencies) INTERNAL_NAME="\"miniupnpc.dll\0\"";%(PreprocessorDefinitions) MaxSpeed true _CRT_SECURE_NO_WARNINGS;MINIUPNP_STATICLIB;%(PreprocessorDefinitions) MultiThreadedDLL true Level3 ProgramDatabase ..;..\include;%(AdditionalIncludeDirectories) genminiupnpcstrings.vbs INTERNAL_NAME="\"miniupnpc.dll\0\"";%(PreprocessorDefinitions) MaxSpeed true _CRT_SECURE_NO_WARNINGS;MINIUPNP_EXPORTS;%(PreprocessorDefinitions) MultiThreadedDLL true Level3 ProgramDatabase ..;..\include;%(AdditionalIncludeDirectories) genminiupnpcstrings.vbs ws2_32.lib;IPHlpApi.Lib;%(AdditionalDependencies) INTERNAL_NAME="\"miniupnpc.dll\0\"";%(PreprocessorDefinitions) miniupnpc-2.2.6/msvc/miniupnpc_vs2010.vcxproj.filters010064400017500000024000000100301401754661100217550ustar00nanardstaff sources sources sources sources sources sources sources sources sources sources sources sources sources sources headers headers headers headers headers headers headers headers headers headers headers headers headers headers headers headers headers headers headers Fichiers d%27en-tête Fichiers d%27en-tête {f2cbd46b-f63f-412e-80e5-b7c9048a1add} {2b3996de-1bc4-418b-8a83-a5f34fdf0df5} {45dbc39d-c3ca-4a75-adf0-76070e20415a} scripts Fichiers de ressources miniupnpc-2.2.6/msvc/miniupnpc_vs2015.sln010064400017500000024000000041571343001453400174210ustar00nanardstaff Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.25123.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "miniupnpc", "miniupnpc.vcxproj", "{D28CE435-CB33-4BAE-8A52-C6EF915956F5}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "upnpc-static", "upnpc-static.vcxproj", "{469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug Dll|Win32 = Debug Dll|Win32 Debug|Win32 = Debug|Win32 Release Dll|Win32 = Release Dll|Win32 Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Debug Dll|Win32.ActiveCfg = Debug Dll|Win32 {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Debug Dll|Win32.Build.0 = Debug Dll|Win32 {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Debug|Win32.ActiveCfg = Debug|Win32 {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Debug|Win32.Build.0 = Debug|Win32 {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Release Dll|Win32.ActiveCfg = Release Dll|Win32 {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Release Dll|Win32.Build.0 = Release Dll|Win32 {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Release|Win32.ActiveCfg = Release|Win32 {D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Release|Win32.Build.0 = Release|Win32 {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Debug Dll|Win32.ActiveCfg = Debug Dll|Win32 {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Debug Dll|Win32.Build.0 = Debug Dll|Win32 {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Debug|Win32.ActiveCfg = Debug|Win32 {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Debug|Win32.Build.0 = Debug|Win32 {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Release Dll|Win32.ActiveCfg = Release Dll|Win32 {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Release Dll|Win32.Build.0 = Release Dll|Win32 {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Release|Win32.ActiveCfg = Release|Win32 {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal miniupnpc-2.2.6/msvc/upnpc-static.vcxproj010064400017500000024000000224731432271534100177160ustar00nanardstaff Debug Dll Win32 Debug Win32 Release Dll Win32 Release Win32 {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1} upnpcstatic Win32Proj Application v140 Unicode true Application v140 Unicode true Application v140 Unicode Application v140 Unicode <_ProjectFileVersion>14.0.25123.0 $(SolutionDir)$(Configuration)\ $(Configuration)\ true $(SolutionDir)$(Configuration)\ $(Configuration)\ true upnpc-shared $(SolutionDir)$(Configuration)\ $(Configuration)\ false $(SolutionDir)$(Configuration)\ $(Configuration)\ false upnpc-shared Disabled _DEBUG;_CONSOLE;MINIUPNP_STATICLIB;DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level3 EditAndContinue ..;..\include ws2_32.lib;$(Configuration)\miniupnpc.lib;IPHlpApi.Lib;%(AdditionalDependencies) true Console MachineX86 Disabled _DEBUG;_CONSOLE;MINIUPNP_STATICLIB;DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level3 EditAndContinue ..;..\include ws2_32.lib;$(Configuration)\miniupnpc.lib;$(AdditionalDependencies) true Console MachineX86 MaxSpeed true NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;MINIUPNP_STATICLIB;%(PreprocessorDefinitions) MultiThreadedDLL true Level3 ProgramDatabase ..;..\include ws2_32.lib;$(Configuration)\miniupnpc.lib;IPHlpApi.Lib;%(AdditionalDependencies) true Console true true MachineX86 MaxSpeed true NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) MultiThreadedDLL true Level3 ProgramDatabase ..;..\include ws2_32.lib;$(Configuration)\miniupnpc.lib;IPHlpApi.Lib;%(AdditionalDependencies) true Console true true MachineX86 {d28ce435-cb33-4bae-8a52-c6ef915956f5} false miniupnpc-2.2.6/msvc/upnpc-static.vcxproj.filters010064400017500000024000000016661412470240400213620ustar00nanardstaff {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hpp;hxx;hm;inl;inc;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav Fichiers sources miniupnpc-2.2.6/msvc/upnpc-static_vs2010.vcxproj010064400017500000024000000234771412470240400207320ustar00nanardstaff Debug Dll Win32 Debug Win32 Release Dll Win32 Release Win32 {469E1CF6-08A2-4B7B-A2AA-5BDB089857C1} upnpcstatic Win32Proj Application Unicode true Application Unicode true Application Unicode Application Unicode <_ProjectFileVersion>10.0.40219.1 $(SolutionDir)$(Configuration)\ $(SolutionDir)$(Configuration)\ $(Configuration)\ $(Configuration)\ true true $(SolutionDir)$(Configuration)\ $(SolutionDir)$(Configuration)\ $(Configuration)\ $(Configuration)\ false false upnpc-static upnpc-static upnpc-static upnpc-static Disabled _DEBUG;_CONSOLE;MINIUPNP_STATICLIB;DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level3 EditAndContinue ..;..\include ws2_32.lib;IPHlpApi.Lib;$(Configuration)\miniupnpc.lib;%(AdditionalDependencies) true Console MachineX86 Disabled _DEBUG;_CONSOLE;DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level3 EditAndContinue ..;..\include ws2_32.lib;$(Configuration)\miniupnpc.lib;%(AdditionalDependencies) true Console MachineX86 MaxSpeed true NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;MINIUPNP_STATICLIB;%(PreprocessorDefinitions) MultiThreadedDLL true Level3 ProgramDatabase ..;..\include ws2_32.lib;IPHlpApi.Lib;$(Configuration)\miniupnpc.lib;%(AdditionalDependencies) true Console true true MachineX86 MaxSpeed true NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) MultiThreadedDLL true Level3 ProgramDatabase ..;..\include ws2_32.lib;$(Configuration)\miniupnpc.lib;%(AdditionalDependencies) true Console true true MachineX86 {d28ce435-cb33-4bae-8a52-c6ef915956f5} false miniupnpc-2.2.6/src/win32_snprintf.h010064400017500000024000000045671375231347600165610ustar00nanardstaff/* vim: tabstop=4 shiftwidth=4 noexpandtab * MiniUPnP project * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * (c) 2020 Pali Rohár * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ #ifndef WIN32_SNPRINTF_H #define WIN32_SNPRINTF_H #ifdef _WIN32 #include /* snprintf is supported by: * - Visual Studio 2015 or new * - mingw32 with iso c ext * - mingw-w64 with ansi stdio * - mingw-w64 6.0.0 or new with ucrt * - mingw-w64 8.0.0 or new with iso c ext */ #if ( \ (defined(_MSC_VER) && _MSC_VER < 1900) /* Visual Studio older than 2015 */ || \ (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) && defined(__NO_ISOCEXT)) /* mingw32 without iso c ext */ || \ (defined(__MINGW64_VERSION_MAJOR) && /* mingw-w64 not ... */ !( \ (defined (__USE_MINGW_ANSI_STDIO) && __USE_MINGW_ANSI_STDIO != 0)) /* ... with ansi stdio */ || \ (__MINGW64_VERSION_MAJOR >= 6 && defined(_UCRT)) /* ... at least 6.0.0 with ucrt */ || \ (__MINGW64_VERSION_MAJOR >= 8 && !defined(__NO_ISOCEXT)) /* ... at least 8.0.0 with iso c ext */ || \ 0) || \ 0) /* _scprintf is supported by: * - Visual Studio 2002 or new * - msvcr70.dll or new * - msvcrt.dll on Windows XP or new */ #if ( \ (defined(_MSC_VER) && _MSC_VER < 1300) /* Visual Studio older than 2002 */ || \ (defined(__MSVCRT_VERSION__) && __MSVCRT_VERSION__ < 0x700) /* msvcrt older than 7.0 */ || \ 0) #define CHECK_SCPRINTF 0 #define IF_SCPRINTF(expr) 0 #define ELSE_SCPRINTF(expr) expr #else #define CHECK_SCPRINTF 1 #define IF_SCPRINTF(expr) expr #define ELSE_SCPRINTF(expr) 0 #endif /* Emulation of snprintf for win32 */ #define snprintf(buf, size, fmt, ...) ( \ (((size) != 0 && (buf) != NULL) ? ( /* _snprintf does not work with NULL buffer */ \ _snprintf((buf), (size), (fmt), __VA_ARGS__), /* _snprintf returns -1 on overflow, so ignore its value */ \ (((char *)buf)[(size_t)(size)-1] = 0), /* _snprintf does not fill nul byte on overflow */ \ 0) : 0), \ (CHECK_SCPRINTF ? IF_SCPRINTF( \ _scprintf((fmt), __VA_ARGS__) /* calculate return value for snprintf via _scprintf */ \ ) : ELSE_SCPRINTF( \ ((size) != 0 && (buf) != NULL) ? \ strlen((buf)) /* return just length of buffer */ \ : \ 1 /* no buffer, impossible to calculate, return just non-zero number */ \ ) \ ) \ ) #endif #endif /* _WIN32 */ #endif /* WIN32_SNPRINTF_H */ miniupnpc-2.2.6/miniupnpc.rc010064400017500000024000000022341376227141200152430ustar00nanardstaff#include #include "rc_version.h" VS_VERSION_INFO VERSIONINFO FILEVERSION LIBMINIUPNPC_MAJOR_VERSION,LIBMINIUPNPC_MINOR_VERSION,LIBMINIUPNPC_MICRO_VERSION,0 PRODUCTVERSION LIBMINIUPNPC_MAJOR_VERSION,LIBMINIUPNPC_MINOR_VERSION,LIBMINIUPNPC_MICRO_VERSION,0 FILEFLAGSMASK VS_FFI_FILEFLAGSMASK #ifdef _DEBUG FILEFLAGS VS_FF_DEBUG #else FILEFLAGS 0 #endif FILEOS VOS__WINDOWS32 FILETYPE VFT_DLL FILESUBTYPE VFT2_UNKNOWN // not used BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "04090000" /* Lang = US English, Charset = ASCII */ BEGIN VALUE "FileDescription", "MiniUPnPc library\0" VALUE "FileVersion", LIBMINIUPNPC_DOTTED_VERSION "\0" VALUE "InternalName", INTERNAL_NAME VALUE "LegalCopyright", "Copyright (C) Thomas Bernard\0" VALUE "LegalTrademarks", "\0" VALUE "OriginalFilename", INTERNAL_NAME VALUE "ProductName", "MiniUPnPc\0" VALUE "ProductVersion", LIBMINIUPNPC_DOTTED_VERSION "\0" VALUE "Comments", "For more information visit https://miniupnp.tuxfamil.org/\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x0409, 0 /* US English, ASCII */ END END miniupnpc-2.2.6/miniupnpc.pc.in010064400017500000024000000010761432407705700156550ustar00nanardstaff# this template is filled-in by CMake `configure_file(... @ONLY)` # the `@....@` are filled in by CMake configure_file(), # from variables set in your CMakeLists.txt or by CMake itself # # Good tutoral for understanding .pc files: # https://people.freedesktop.org/~dbn/pkg-config-guide.html prefix="@CMAKE_INSTALL_PREFIX@" exec_prefix="${prefix}" libdir="${prefix}/lib" includedir="${prefix}/include" Name: @PROJECT_NAME@ Description: @PROJECT_DESCRIPTION@ URL: @PROJECT_HOMEPAGE_URL@ Version: @PROJECT_VERSION@ Libs: -L"${libdir}" -lminiupnpc Cflags: -I"${includedir}"