Created
August 3, 2021 22:05
-
-
Save Darkshadow2/a676844c6036a7beaaad343f56ab0116 to your computer and use it in GitHub Desktop.
miniupnp - patch to get MS clients to see a V2 as a V1 UPNP server
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/miniupnpd/upnpdescgen.c b/miniupnpd/upnpdescgen.c | |
index 46110f2..4020a09 100644 | |
--- a/miniupnpd/upnpdescgen.c | |
+++ b/miniupnpd/upnpdescgen.c | |
@@ -317,6 +317,147 @@ static const struct XMLElt rootDesc[] = | |
{0, 0} | |
}; | |
+#ifdef IGD_V2 | |
+static const struct XMLElt ms_rootDesc[] = | |
+{ | |
+/* 0 */ | |
+ {root_device, INITHELPER(1,2)}, | |
+ {"specVersion", INITHELPER(3,2)}, | |
+#if defined(ENABLE_L3F_SERVICE) || defined(HAS_DUMMY_SERVICE) | |
+ {"device", INITHELPER(5,13)}, | |
+#else | |
+ {"device", INITHELPER(5,12)}, | |
+#endif | |
+ {"/major", UPNP_VERSION_MAJOR_STR}, | |
+ {"/minor", UPNP_VERSION_MINOR_STR}, | |
+/* 5 */ | |
+ {"/deviceType", DEVICE_TYPE_IGD}, | |
+ /* urn:schemas-upnp-org:device:InternetGatewayDevice:1 or 2 */ | |
+#ifdef ENABLE_MANUFACTURER_INFO_CONFIGURATION | |
+ {"/friendlyName", friendly_name/*ROOTDEV_FRIENDLYNAME*/}, /* required */ | |
+ {"/manufacturer", manufacturer_name/*ROOTDEV_MANUFACTURER*/}, /* required */ | |
+/* 8 */ | |
+ {"/manufacturerURL", manufacturer_url/*ROOTDEV_MANUFACTURERURL*/}, /* optional */ | |
+ {"/modelDescription", model_description/*ROOTDEV_MODELDESCRIPTION*/}, /* recommended */ | |
+ {"/modelName", model_name/*ROOTDEV_MODELNAME*/}, /* required */ | |
+ {"/modelNumber", modelnumber}, | |
+ {"/modelURL", model_url/*ROOTDEV_MODELURL*/}, | |
+#else | |
+ {"/friendlyName", ROOTDEV_FRIENDLYNAME}, /* required */ | |
+ {"/manufacturer", ROOTDEV_MANUFACTURER}, /* required */ | |
+/* 8 */ | |
+ {"/manufacturerURL", ROOTDEV_MANUFACTURERURL}, /* optional */ | |
+ {"/modelDescription", ROOTDEV_MODELDESCRIPTION}, /* recommended */ | |
+ {"/modelName", ROOTDEV_MODELNAME}, /* required */ | |
+ {"/modelNumber", modelnumber}, | |
+ {"/modelURL", ROOTDEV_MODELURL}, | |
+#endif | |
+ {"/serialNumber", serialnumber}, | |
+ {"/UDN", uuidvalue_igd}, /* required */ | |
+ /* see if /UPC is needed. */ | |
+#define MS_SERVICES_OFFSET 58 | |
+#if defined(ENABLE_L3F_SERVICE) || defined(HAS_DUMMY_SERVICE) | |
+ /* here we defining Services for the root device : | |
+ * L3F and DUMMY */ | |
+#ifdef ENABLE_L3F_SERVICE | |
+#define MS_NSERVICES1 1 | |
+#else | |
+#define MS_NSERVICES1 0 | |
+#endif | |
+#ifdef HAS_DUMMY_SERVICE | |
+#define MS_NSERVICES2 1 | |
+#else | |
+#define MS_NSERVICES2 0 | |
+#endif | |
+#define MS_NSERVICES (MS_NSERVICES1+MS_NSERVICES2) | |
+ {"serviceList", INITHELPER(MS_SERVICES_OFFSET,MS_NSERVICES)}, | |
+ {"deviceList", INITHELPER(18,1)}, | |
+ {"/presentationURL", presentationurl}, /* recommended */ | |
+#else | |
+ {"deviceList", INITHELPER(18,1)}, | |
+ {"/presentationURL", presentationurl}, /* recommended */ | |
+ {0,0}, | |
+#endif | |
+/* 18 */ | |
+ {"device", INITHELPER(19,13)}, | |
+/* 19 */ | |
+ {"/deviceType", DEVICE_TYPE_WAN}, /* required */ | |
+ /* urn:schemas-upnp-org:device:WANDevice:1 or 2 */ | |
+ {"/friendlyName", WANDEV_FRIENDLYNAME}, | |
+ {"/manufacturer", WANDEV_MANUFACTURER}, | |
+ {"/manufacturerURL", WANDEV_MANUFACTURERURL}, | |
+ {"/modelDescription" , WANDEV_MODELDESCRIPTION}, | |
+ {"/modelName", WANDEV_MODELNAME}, | |
+ {"/modelNumber", WANDEV_MODELNUMBER}, | |
+ {"/modelURL", WANDEV_MODELURL}, | |
+ {"/serialNumber", serialnumber}, | |
+ {"/UDN", uuidvalue_wan}, | |
+ {"/UPC", WANDEV_UPC}, /* UPC (=12 digit barcode) is optional */ | |
+/* 30 */ | |
+ {"serviceList", INITHELPER(32,1)}, | |
+ {"deviceList", INITHELPER(38,1)}, | |
+/* 32 */ | |
+ {"service", INITHELPER(33,5)}, | |
+/* 33 */ | |
+ {"/serviceType", | |
+ "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1"}, | |
+ /*{"/serviceId", "urn:upnp-org:serviceId:WANCommonInterfaceConfig"}, */ | |
+ {"/serviceId", "urn:upnp-org:serviceId:WANCommonIFC1"}, /* required */ | |
+ {"/SCPDURL", WANCFG_PATH}, | |
+ {"/controlURL", WANCFG_CONTROLURL}, | |
+ {"/eventSubURL", WANCFG_EVENTURL}, | |
+/* 38 */ | |
+ {"device", INITHELPER(39,12)}, | |
+/* 39 */ | |
+ {"/deviceType", DEVICE_TYPE_WANC}, | |
+ /* urn:schemas-upnp-org:device:WANConnectionDevice:1 or 2 */ | |
+ {"/friendlyName", WANCDEV_FRIENDLYNAME}, | |
+ {"/manufacturer", WANCDEV_MANUFACTURER}, | |
+ {"/manufacturerURL", WANCDEV_MANUFACTURERURL}, | |
+ {"/modelDescription", WANCDEV_MODELDESCRIPTION}, | |
+ {"/modelName", WANCDEV_MODELNAME}, | |
+ {"/modelNumber", WANCDEV_MODELNUMBER}, | |
+ {"/modelURL", WANCDEV_MODELURL}, | |
+ {"/serialNumber", serialnumber}, | |
+ {"/UDN", uuidvalue_wcd}, | |
+ {"/UPC", WANCDEV_UPC}, /* UPC (=12 digit Barcode) is optional */ | |
+ {"serviceList", INITHELPER(51,1)}, | |
+/* 51 */ | |
+ {"service", INITHELPER(53,5)}, | |
+ {"service", INITHELPER(58,5)}, | |
+/* 53 */ | |
+ {"/serviceType", SERVICE_TYPE_WANIPC}, | |
+ /* urn:schemas-upnp-org:service:WANIPConnection:2 for v2 */ | |
+ {"/serviceId", SERVICE_ID_WANIPC}, | |
+ /* urn:upnp-org:serviceId:WANIPConn1 or 2 */ | |
+ {"/SCPDURL", WANIPC_PATH}, | |
+ {"/controlURL", WANIPC_CONTROLURL}, | |
+ {"/eventSubURL", WANIPC_EVENTURL}, | |
+/* 58 / 63 = SERVICES_OFFSET*/ | |
+#if defined(HAS_DUMMY_SERVICE) || defined(ENABLE_L3F_SERVICE) | |
+ {"service", INITHELPER(MS_SERVICES_OFFSET+2,5)}, | |
+ {"service", INITHELPER(MS_SERVICES_OFFSET+7,5)}, | |
+#endif | |
+#ifdef HAS_DUMMY_SERVICE | |
+/* 60 / 65 = SERVICES_OFFSET+2 */ | |
+ {"/serviceType", "urn:schemas-dummy-com:service:Dummy:1"}, | |
+ {"/serviceId", "urn:dummy-com:serviceId:dummy1"}, | |
+ {"/SCPDURL", DUMMY_PATH}, | |
+ {"/controlURL", "/dummy"}, | |
+ {"/eventSubURL", "/dummy"}, | |
+#endif | |
+#ifdef ENABLE_L3F_SERVICE | |
+/* 60 / 65 = SERVICES_OFFSET+2 */ | |
+ {"/serviceType", "urn:schemas-upnp-org:service:Layer3Forwarding:1"}, | |
+ {"/serviceId", "urn:upnp-org:serviceId:L3Forwarding1"}, | |
+ {"/SCPDURL", L3F_PATH}, | |
+ {"/controlURL", L3F_CONTROLURL}, /* The Layer3Forwarding service is only */ | |
+ {"/eventSubURL", L3F_EVENTURL}, /* recommended, not mandatory */ | |
+#endif | |
+ {0, 0} | |
+}; | |
+#endif | |
+ | |
/* WANIPCn.xml */ | |
/* see UPnP_IGD_WANIPConnection 1.0.pdf | |
static struct XMLElt scpdWANIPCn[] = | |
@@ -491,6 +632,31 @@ static const struct action WANIPCnActions[] = | |
}; | |
/* R=Required, O=Optional */ | |
+#ifdef IGD_V2 | |
+static const struct action ms_WANIPCnActions[] = | |
+{ | |
+ {"SetConnectionType", SetConnectionTypeArgs}, /* R */ | |
+ {"GetConnectionTypeInfo", GetConnectionTypeInfoArgs}, /* R */ | |
+ {"RequestConnection", 0}, /* R */ | |
+ /*{"RequestTermination", 0},*/ /* O */ | |
+ {"ForceTermination", 0}, /* R */ | |
+ /*{"SetAutoDisconnectTime", 0},*/ /* O */ | |
+ /*{"SetIdleDisconnectTime", 0},*/ /* O */ | |
+ /*{"SetWarnDisconnectDelay", 0}, */ /* O */ | |
+ {"GetStatusInfo", GetStatusInfoArgs}, /* R */ | |
+ /*GetAutoDisconnectTime*/ /* O */ | |
+ /*GetIdleDisconnectTime*/ /* O */ | |
+ /*GetWarnDisconnectDelay*/ /* O */ | |
+ {"GetNATRSIPStatus", GetNATRSIPStatusArgs}, /* R */ | |
+ {"GetGenericPortMappingEntry", GetGenericPortMappingEntryArgs}, /* R */ | |
+ {"GetSpecificPortMappingEntry", GetSpecificPortMappingEntryArgs}, /* R */ | |
+ {"AddPortMapping", AddPortMappingArgs}, /* R */ | |
+ {"DeletePortMapping", DeletePortMappingArgs}, /* R */ | |
+ {"GetExternalIPAddress", GetExternalIPAddressArgs}, /* R */ | |
+ {0, 0} | |
+}; | |
+#endif | |
+ | |
/* ignore "warning: missing initializer" */ | |
#pragma GCC diagnostic ignored "-Wmissing-field-initializers" | |
@@ -551,9 +717,56 @@ static const struct stateVar WANIPCnVars[] = | |
{0, 0} | |
}; | |
+#ifdef IGD_V2 | |
+static const struct stateVar ms_WANIPCnVars[] = | |
+{ | |
+ {"ConnectionType", 0, 1, 0, 15}, /* required */ | |
+ {"PossibleConnectionTypes", 0|0x80, 0, 14, 15}, | |
+ /* Required | |
+ * Allowed values : Unconfigured / IP_Routed / IP_Bridged */ | |
+ {"ConnectionStatus", 0|0x80, 3, 18, | |
+ CONNECTIONSTATUS_MAGICALVALUE }, /* required */ | |
+ /* Allowed Values : Unconfigured / Connecting(opt) / Connected | |
+ * PendingDisconnect(opt) / Disconnecting (opt) | |
+ * Disconnected */ | |
+ {"Uptime", 3, 0}, /* Required */ | |
+ {"LastConnectionError", 0, 6, 25}, /* required : */ | |
+ /* Allowed Values : ERROR_NONE(req) / ERROR_COMMAND_ABORTED(opt) | |
+ * ERROR_NOT_ENABLED_FOR_INTERNET(opt) | |
+ * ERROR_USER_DISCONNECT(opt) | |
+ * ERROR_ISP_DISCONNECT(opt) | |
+ * ERROR_IDLE_DISCONNECT(opt) | |
+ * ERROR_FORCED_DISCONNECT(opt) | |
+ * ERROR_NO_CARRIER(opt) | |
+ * ERROR_IP_CONFIGURATION(opt) | |
+ * ERROR_UNKNOWN(opt) */ | |
+ {"RSIPAvailable", 1, 4}, /* required */ | |
+ {"NATEnabled", 1, 5}, /* required */ | |
+ {"ExternalIPAddress", 0|0x80, 0, 0, | |
+ EXTERNALIPADDRESS_MAGICALVALUE}, /* required. Default : empty string */ | |
+ {"PortMappingNumberOfEntries", 2|0x80, 0, 0, | |
+ PORTMAPPINGNUMBEROFENTRIES_MAGICALVALUE}, /* required >= 0 */ | |
+ {"PortMappingEnabled", 1, 0}, /* Required */ | |
+ /* 10 */ | |
+ {"PortMappingLeaseDuration", 3, 2, 1}, /* required */ | |
+ {"RemoteHost", 0, 0}, /* required. Default : empty string */ | |
+ {"ExternalPort", 2, 0}, /* required */ | |
+ {"InternalPort", 2, 0, 3}, /* required */ | |
+ {"PortMappingProtocol", 0, 0, 11}, /* required allowedValues: TCP/UDP */ | |
+ {"InternalClient", 0, 0}, /* required */ | |
+ {"PortMappingDescription", 0, 0}, /* required default: empty string */ | |
+ {0, 0} | |
+}; | |
+#endif | |
+ | |
static const struct serviceDesc scpdWANIPCn = | |
{ WANIPCnActions, WANIPCnVars }; | |
+#ifdef IGD_V2 | |
+static const struct serviceDesc ms_scpdWANIPCn = | |
+{ ms_WANIPCnActions, ms_WANIPCnVars }; | |
+#endif | |
+ | |
/* WANCfg.xml */ | |
/* See UPnP_IGD_WANCommonInterfaceConfig 1.0.pdf */ | |
@@ -887,7 +1100,7 @@ strcat_int(char * str, int * len, int * tmplen, int i) | |
* This way, the progam stack usage is kept low */ | |
static char * | |
genXML(char * str, int * len, int * tmplen, | |
- const struct XMLElt * p) | |
+ const struct XMLElt * p, int is_ms) | |
{ | |
#define GENXML_STACK_SIZE 16 | |
unsigned short i, j; | |
@@ -928,7 +1141,7 @@ genXML(char * str, int * len, int * tmplen, | |
str = strcat_str(str, len, tmplen, p[i].data); | |
#ifdef IGD_V2 | |
/* checking a single 'u' saves us 4 strcmp() calls most of the time */ | |
- if (GETFLAG(FORCEIGDDESCV1MASK) && (p[i].data[0] == 'u')) | |
+ if ((GETFLAG(FORCEIGDDESCV1MASK) || is_ms) && (p[i].data[0] == 'u')) | |
{ | |
if ((strcmp(p[i].data, DEVICE_TYPE_IGD) == 0) || | |
(strcmp(p[i].data, DEVICE_TYPE_WAN) == 0) || | |
@@ -936,6 +1149,10 @@ genXML(char * str, int * len, int * tmplen, | |
(strcmp(p[i].data, SERVICE_TYPE_WANIPC) == 0) ) | |
{ | |
str[*len - 1] = '1'; /* Change the version number to 1 */ | |
+#ifdef DEBUG | |
+ if ( is_ms ) | |
+ syslog(LOG_DEBUG, "downgraded IGD version for MS client"); | |
+#endif | |
} | |
} | |
#endif | |
@@ -1007,6 +1224,9 @@ genRootDesc(int * len) | |
{ | |
char * str; | |
int tmplen; | |
+#ifdef IGD_V2 | |
+ int is_ms = *len; | |
+#endif | |
tmplen = 2048; | |
str = (char *)malloc(tmplen); | |
if(str == NULL) | |
@@ -1014,7 +1234,12 @@ genRootDesc(int * len) | |
* len = strlen(xmlver); | |
/*strcpy(str, xmlver); */ | |
memcpy(str, xmlver, *len + 1); | |
- str = genXML(str, len, &tmplen, rootDesc); | |
+#ifdef IGD_V2 | |
+ if ( is_ms ) | |
+ str = genXML(str, len, &tmplen, ms_rootDesc, 1); | |
+ else | |
+#endif | |
+ str = genXML(str, len, &tmplen, rootDesc, 0); | |
str[*len] = '\0'; | |
return str; | |
} | |
@@ -1081,11 +1306,15 @@ genServiceDesc(int * len, const struct serviceDesc * s) | |
if(plen >= (11+15) && 0 == memcmp(p + 11, "NumberOfEntries", 15)) { | |
/* PortMappingNumberOfEntries */ | |
#ifdef IGD_V2 | |
+ if(s != &ms_scpdWANIPCn ){ | |
if(0 == memcmp(acts[i].name, "GetListOfPortMappings", 22)) { | |
str = strcat_str(str, len, &tmplen, "NumberOfPorts"); | |
} else { | |
str = strcat_str(str, len, &tmplen, "PortMappingIndex"); | |
} | |
+ } else { | |
+ str = strcat_str(str, len, &tmplen, "PortMappingIndex"); | |
+ } | |
#else | |
str = strcat_str(str, len, &tmplen, "PortMappingIndex"); | |
#endif | |
@@ -1096,9 +1325,9 @@ genServiceDesc(int * len, const struct serviceDesc * s) | |
str = strcat_str(str, len, &tmplen, p + 11); | |
} | |
#ifdef IGD_V2 | |
- } else if(plen >= 11 && 0 == memcmp(p, "A_ARG_TYPE_", 11)) { | |
+ } else if((s != &ms_scpdWANIPCn) && plen >= 11 && 0 == memcmp(p, "A_ARG_TYPE_", 11)) { | |
str = strcat_str(str, len, &tmplen, p + 11); | |
- } else if(plen >= 13 && 0 == memcmp(p, "ExternalPort", 13) | |
+ } else if((s != &ms_scpdWANIPCn) && plen >= 13 && 0 == memcmp(p, "ExternalPort", 13) | |
&& args[j].dir == 2 | |
&& 0 == memcmp(acts[i].name, "AddAnyPortMapping", 18)) { | |
str = strcat_str(str, len, &tmplen, "ReservedPort"); | |
@@ -1183,6 +1412,10 @@ genServiceDesc(int * len, const struct serviceDesc * s) | |
char * | |
genWANIPCn(int * len) | |
{ | |
+#ifdef IGD_V2 | |
+ if ( *len == 1 ) | |
+ return genServiceDesc(len, &ms_scpdWANIPCn); | |
+#endif | |
return genServiceDesc(len, &scpdWANIPCn); | |
} | |
diff --git a/miniupnpd/upnphttp.c b/miniupnpd/upnphttp.c | |
index e40bb7b..39e44d8 100644 | |
--- a/miniupnpd/upnphttp.c | |
+++ b/miniupnpd/upnphttp.c | |
@@ -221,6 +221,9 @@ ParseHttpHeaders(struct upnphttp * h) | |
int n; | |
if((h->req_buf == NULL) || (h->req_contentoff <= 0)) | |
return; | |
+#ifdef IGD_V2 | |
+ h->req_is_ms = 0; | |
+#endif | |
line = h->req_buf; | |
while(line < (h->req_buf + h->req_contentoff)) | |
{ | |
@@ -308,6 +311,15 @@ ParseHttpHeaders(struct upnphttp * h) | |
syslog(LOG_DEBUG, "\"Expect: 100-Continue\" header detected"); | |
} | |
} | |
+#ifdef IGD_V2 | |
+ else if(strncasecmp(line, "user-agent:", 11) == 0) | |
+ { | |
+ if(strcasestr(line, "microsoft") != NULL) { | |
+ h->req_is_ms = 1; | |
+ syslog(LOG_DEBUG, "MS client detected"); | |
+ } | |
+ } | |
+#endif | |
#ifdef ENABLE_EVENTS | |
else if(strncasecmp(line, "Callback:", 9)==0) | |
{ | |
@@ -461,7 +473,10 @@ static void | |
sendXMLdesc(struct upnphttp * h, char * (f)(int *)) | |
{ | |
char * desc; | |
- int len; | |
+ int len = 0; | |
+#ifdef IGD_V2 | |
+ if (h->req_is_ms == 1) len = 1; | |
+#endif | |
desc = f(&len); | |
if(!desc) | |
{ | |
diff --git a/miniupnpd/upnphttp.h b/miniupnpd/upnphttp.h | |
index 9d9cf48..881f643 100644 | |
--- a/miniupnpd/upnphttp.h | |
+++ b/miniupnpd/upnphttp.h | |
@@ -88,6 +88,9 @@ struct upnphttp { | |
int res_buflen; | |
int res_sent; | |
int res_buf_alloclen; | |
+#ifdef IGD_V2 | |
+ int req_is_ms; | |
+#endif | |
LIST_ENTRY(upnphttp) entries; | |
}; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment