miniupnpc: distinguish between not connected IGD and connected to a private IP

fixes #732
This commit is contained in:
Thomas Bernard 2024-05-08 17:37:17 +02:00
parent 2edbc62c50
commit c0a50ce33e
No known key found for this signature in database
GPG Key ID: DB511043A31ACAAF
8 changed files with 60 additions and 33 deletions

View File

@ -6,7 +6,7 @@ project (miniupnpc
HOMEPAGE_URL https://miniupnp.tuxfamily.org/
LANGUAGES C)
set (MINIUPNPC_API_VERSION 17)
set (MINIUPNPC_API_VERSION 18)
option (UPNPC_BUILD_STATIC "Build static library" TRUE)
option (UPNPC_BUILD_SHARED "Build shared library" TRUE)

View File

@ -3,6 +3,9 @@ miniUPnP client Changelog.
2024/05/08:
upnpc.c: Add -f option to upnpc program (delete multiple port redirections)
UPNP_GetValidIGD(): distinguish between not connected and connected to a
"private" network (with a reserved IP address).
Increments API_VERSION to 18
VERSION 2.2.7 : released 2024/03/20

View File

@ -84,7 +84,7 @@ ifneq (, $(findstring sun, $(OS))$(findstring solaris, $(OS)))
endif
# APIVERSION is used to build SONAME
APIVERSION = 17
APIVERSION = 18
SRCS = $(wildcard $(SRCDIR)/*.c)

View File

@ -2,6 +2,11 @@ $Id: apiversions.txt,v 1.9 2016/01/24 17:24:36 nanard Exp $
Differences in API between miniUPnPc versions
API version 18
change UPNP_GetValidIGD() prototype and return values
updated macro :
#define MINIUPNPC_API_VERSION 18
API version 17
change struct UPNPDev
move getHTTPResponse() to miniwget_private.h

View File

@ -1,9 +1,9 @@
/* $Id: miniupnpc.h,v 1.63 2024/01/04 00:45:17 nanard Exp $ */
/* $Id: miniupnpc.h,v 1.64 2024/03/19 23:26:06 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
* Copyright (c) 2005-2024 Thomas Bernard
* This software is subjects to the conditions detailed
* in the LICENCE file provided within this distribution */
#ifndef MINIUPNPC_H_INCLUDED
@ -20,8 +20,8 @@
#define UPNPDISCOVER_MEMORY_ERROR (-102)
/* versions : */
#define MINIUPNPC_VERSION "2.2.6"
#define MINIUPNPC_API_VERSION 17
#define MINIUPNPC_VERSION "2.2.7"
#define MINIUPNPC_API_VERSION 18
/* Source port:
Using "1" as an alias for 1900 for backwards compatibility
@ -108,9 +108,11 @@ struct UPNPUrls {
* 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
* 2 = A valid connected IGD has been found but its
* IP address is reserved (non routable)
* 3 = 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
* 4 = 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
@ -119,8 +121,9 @@ struct UPNPUrls {
MINIUPNP_LIBSPEC int
UPNP_GetValidIGD(struct UPNPDev * devlist,
struct UPNPUrls * urls,
struct IGDdatas * data,
char * lanaddr, int lanaddrlen);
struct IGDdatas * data,
char * lanaddr, int lanaddrlen,
char * wanaddr, int wanaddrlen);
/* UPNP_GetIGDFromUrl()
* Used when skipping the discovery process.

View File

@ -38,7 +38,7 @@ 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);"
.IP "int UPNP_GetValidIGD(struct UPNPDev * devlist, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen, char * wanaddr, int wanaddrlen);"
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.

View File

@ -3,7 +3,7 @@
* Project : miniupnp
* Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
* Author : Thomas BERNARD
* copyright (c) 2005-2021 Thomas Bernard
* copyright (c) 2005-2024 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENSE file. */
#include <stdlib.h>
@ -534,9 +534,11 @@ UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data)
* -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
* 2 = A valid connected IGD has been found but its
* IP address is reserved (non routable)
* 3 = 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
* 4 = 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
@ -545,11 +547,13 @@ UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data)
MINIUPNP_LIBSPEC int
UPNP_GetValidIGD(struct UPNPDev * devlist,
struct UPNPUrls * urls,
struct IGDdatas * data,
char * lanaddr, int lanaddrlen)
struct IGDdatas * data,
char * lanaddr, int lanaddrlen,
char * wanaddr, int wanaddrlen)
{
struct xml_desc {
char lanaddr[40];
char wanaddr[40];
char * xml;
int size;
int is_igd;
@ -557,8 +561,8 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
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 state = -1; /* state 1 : IGD connected. State 2 : connected with reserved IP.
* State 3 : IGD. State 4 : anything */
int status_code = -1;
if(!devlist)
@ -602,7 +606,7 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
}
}
/* iterate the list to find a device depending on state */
for(state = 1; state <= 3; state++)
for(state = 1; state <= 4; state++)
{
for(dev = devlist, i = 0; dev; dev = dev->pNext, i++)
{
@ -611,14 +615,14 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
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 )
if(desc[i].is_igd || state >= 4 )
{
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)
/* in state 3 and 4 we don't test if device is connected ! */
if(state >= 3)
goto free_and_return;
is_connected = UPNPIGD_IsConnected(urls, data);
#ifdef DEBUG
@ -626,9 +630,11 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
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))
if(is_connected) {
if(state >= 2)
goto free_and_return;
if(UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, desc[i].wanaddr) == 0
&& !addr_is_reserved(desc[i].wanaddr))
goto free_and_return;
}
FreeUPNPUrls(urls);
@ -647,9 +653,11 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
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))
if(is_connected) {
if(state >= 2)
goto free_and_return;
if(UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, desc[i].wanaddr) == 0
&& !addr_is_reserved(desc[i].wanaddr))
goto free_and_return;
}
FreeUPNPUrls(urls);
@ -661,8 +669,12 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
}
state = 0;
free_and_return:
if (lanaddr != NULL && state >= 1 && state <= 3 && i < ndev)
strncpy(lanaddr, desc[i].lanaddr, lanaddrlen);
if (state >= 1 && state <= 4 && i < ndev) {
if (lanaddr != NULL)
strncpy(lanaddr, desc[i].lanaddr, lanaddrlen);
if (wanaddr != NULL)
strncpy(wanaddr, desc[i].wanaddr, wanaddrlen);
}
for(i = 0; i < ndev; i++)
free(desc[i].xml);
free(desc);

View File

@ -604,6 +604,7 @@ int main(int argc, char ** argv)
int commandargc = 0;
struct UPNPDev * devlist = 0;
char lanaddr[64] = "unset"; /* my ip address on the LAN */
char wanaddr[64] = "unsed"; /* up address of the IGD on the WAN */
int i;
const char * rootdescurl = 0;
const char * multicastif = 0;
@ -727,17 +728,20 @@ int main(int argc, char ** argv)
}
i = 1;
if( (rootdescurl && UPNP_GetIGDFromUrl(rootdescurl, &urls, &data, lanaddr, sizeof(lanaddr)))
|| (i = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr))))
|| (i = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr), wanaddr, sizeof(wanaddr))))
{
switch(i) {
case 1:
printf("Found valid IGD : %s\n", urls.controlURL);
break;
case 2:
printf("Found an IGD with a reserved IP address (%s) : %s\n", wanaddr, urls.controlURL);
break;
case 3:
printf("Found a (not connected?) IGD : %s\n", urls.controlURL);
if (ignore) printf("Trying to continue anyway\n");
break;
case 3:
case 4:
printf("UPnP device found. Is it an IGD ? : %s\n", urls.controlURL);
if (ignore) printf("Trying to continue anyway\n");
break;
@ -745,7 +749,7 @@ int main(int argc, char ** argv)
printf("Found device (igd ?) : %s\n", urls.controlURL);
if (ignore) printf("Trying to continue anyway\n");
}
if(i==1 || ignore) {
if(i==1 || i==2 || ignore) {
printf("Local LAN ip address : %s\n", lanaddr);
#if 0