static bool getUPnPURLs(char* szUrl, size_t sizeUrl) { char* szData = (char*)mir_alloc(8192); gatewayFound = httpTransact(szUrl, szData, 8192, NULL, DeviceGetReq) == 200; if (gatewayFound) { char szTemp[256], *rpth; size_t ctlLen; txtParseParam(szData, NULL, "<URLBase>", "</URLBase>", szTemp, sizeof(szTemp)); strncpy(szCtlUrl, szTemp[0] ? szTemp : szUrl, sizeof(szCtlUrl)); szCtlUrl[sizeof(szCtlUrl)-1] = 0; mir_snprintf(szTemp, sizeof(szTemp), search_device, szDev); txtParseParam(szData, szTemp, "<controlURL>", "</controlURL>", szUrl, sizeUrl); // URL combining per RFC 2396 if ( szUrl[0] != 0 ) { if (strstr(szUrl, "://") != NULL) // absolute URI rpth = szCtlUrl; else if (strncmp(szUrl, "//", 2) == 0) // relative URI net_path { rpth = strstr(szCtlUrl, "//"); if (rpth == NULL) rpth = szCtlUrl; } else if (szUrl[0] == '/') // relative URI abs_path { rpth = strstr(szCtlUrl, "//"); rpth = rpth ? rpth + 2 : szCtlUrl; rpth = strchr(rpth, '/'); if (rpth == NULL) rpth = szCtlUrl + strlen(szCtlUrl); } else { // relative URI rel_path size_t ctlCLen = strlen(szCtlUrl); rpth = szCtlUrl + ctlCLen; if (ctlCLen != 0 && *(rpth-1) != '/') strncpy(rpth++, "/", sizeof(szCtlUrl) - ctlCLen); } ctlLen = sizeof(szCtlUrl) - (rpth - szCtlUrl); strncpy(rpth, szUrl, ctlLen); szCtlUrl[sizeof(szCtlUrl)-1] = 0; } else { szCtlUrl[0] = 0; gatewayFound = false; } } mir_free(szData); return gatewayFound; }
static unsigned getExtIP(void) { char szExtIP[30]; char* szData = (char*)mir_alloc(4096); szData[0] = 0; unsigned extip = 0; int res = httpTransact(szCtlUrl, szData, 4096, "GetExternalIPAddress", ControlAction); if (res == 200 && txtParseParam(szData, "<NewExternalIPAddress", ">", "<", szExtIP, sizeof(szExtIP))) extip = ntohl(inet_addr(szExtIP)); mir_free(szData); return extip; }
bool NetlibUPnPAddPortMapping(WORD intport, char *proto, WORD *extport, DWORD *extip, bool search) { int res = 0, i = 5; if (findUPnPGateway()) { char* szData = (char*)mir_alloc(4096); char szExtIP[30]; *extport = intport - 1; *extip = ntohl(locIP.sin_addr.S_un.S_addr); WaitForSingleObject(portListMutex, INFINITE); do { ++*extport; mir_snprintf(szData, 4096, add_port_mapping, *extport, proto, intport, inet_ntoa(locIP.sin_addr)); res = httpTransact(szCtlUrl, szData, 4096, "AddPortMapping", ControlAction); txtParseParam(szData, NULL, "<errorCode>", "</errorCode>", szExtIP, sizeof(szExtIP)); } while (search && res == 500 && atol(szExtIP) == 718 && --i); mir_free(szData); if (res == 200) { unsigned ip = getExtIP(); if (ip) *extip = ip; if (numports >= numportsAlloc) mir_realloc(portList, sizeof(WORD)*(numportsAlloc += 10)); portList[numports++] = *extport; } ReleaseMutex(portListMutex); } return res == 200; }
void NetlibUPnPCleanup(void*) { // upnp is disabled globally, no need for a cleanup if (db_get_b(NULL, "Netlib", "NLEnableUPnP", 1) == 0) return; { int incoming = 0; mir_cslock lck(csNetlibUser); for (int i = 0; i < netlibUser.getCount(); i++) if (netlibUser[i]->user.flags & NUF_INCOMING) { incoming = 1; break; } if (!incoming) return; } if (findUPnPGateway()) { char *szData = (char*)alloca(4096); char buf[50], lip[50]; unsigned j = 0, k, num = 100; strncpy_s(lip, inet_ntoa(locIP.sin_addr), _TRUNCATE); WaitForSingleObject(portListMutex, INFINITE); if (httpTransact(szCtlUrl, szData, 4096, "PortMappingNumberOfEntries", ControlQuery) == 200 && txtParseParam(szData, "QueryStateVariableResponse", "<return>", "<", buf, sizeof(buf))) num = atol(buf); WORD ports[30]; for (unsigned i = 0; i < num && !Miranda_Terminated(); i++) { mir_snprintf(szData, 4096, get_port_mapping, i); ReleaseMutex(portListMutex); WaitForSingleObject(portListMutex, INFINITE); if (httpTransact(szCtlUrl, szData, 4096, "GetGenericPortMappingEntry", ControlAction) != 200) break; if (!txtParseParam(szData, "<NewPortMappingDescription", ">", "<", buf, sizeof(buf)) || mir_strcmp(buf, "Miranda") != 0) continue; if (!txtParseParam(szData, "<NewInternalClient", ">", "<", buf, sizeof(buf)) || mir_strcmp(buf, lip) != 0) continue; if (txtParseParam(szData, "<NewExternalPort", ">", "<", buf, sizeof(buf))) { WORD mport = (WORD)atol(buf); if (j >= _countof(ports)) break; for (k = 0; k < numports; ++k) if (portList[k] == mport) break; if (k >= numports) ports[j++] = mport; } } ReleaseMutex(portListMutex); for (unsigned i = 0; i < j && !Miranda_Terminated(); i++) NetlibUPnPDeletePortMapping(ports[i], "TCP"); } }
static void discoverUPnP(void) { char* buf; int buflen; unsigned i, j, nip = 0; unsigned* ips = NULL; static const unsigned any = INADDR_ANY; static const TIMEVAL tv = { 1, 600000 }; char szUrl[256] = ""; char hostname[256]; PHOSTENT he; fd_set readfd; SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); SOCKADDR_IN enetaddr; enetaddr.sin_family = AF_INET; enetaddr.sin_port = htons(1900); enetaddr.sin_addr.s_addr = inet_addr("239.255.255.250"); gethostname(hostname, sizeof(hostname)); he = gethostbyname(hostname); if (he) { while (he->h_addr_list[nip]) ++nip; ips = (unsigned*)mir_alloc(nip * sizeof(unsigned)); for (j = 0; j < nip; j++) ips[j] = *(unsigned*)he->h_addr_list[j]; } buf = (char*)mir_alloc(1500); for (i = 3; --i && szUrl[0] == 0;) { for (j = 0; j < nip; j++) { if (ips) setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (char *)&ips[j], sizeof(unsigned)); buflen = mir_snprintf(buf, 1500, search_request_msg, "WANIPConnection:1"); sendto(sock, buf, buflen, 0, (SOCKADDR*)&enetaddr, sizeof(enetaddr)); LongLog(buf); buflen = mir_snprintf(buf, 1500, search_request_msg, "WANPPPConnection:1"); sendto(sock, buf, buflen, 0, (SOCKADDR*)&enetaddr, sizeof(enetaddr)); LongLog(buf); } if (Miranda_Terminated()) break; FD_ZERO(&readfd); FD_SET(sock, &readfd); while (select(1, &readfd, NULL, NULL, &tv) >= 1) { buflen = recv(sock, buf, 1500, 0); if (buflen != SOCKET_ERROR) { buf[buflen] = 0; LongLog(buf); if (txtParseParam(buf, NULL, "LOCATION:", "\n", szUrl, sizeof(szUrl)) || txtParseParam(buf, NULL, "Location:", "\n", szUrl, sizeof(szUrl))) { char age[30]; char szHostNew[256], szHostExist[256]; lrtrim(szUrl); parseURL(szUrl, szHostNew, NULL, NULL); parseURL(szCtlUrl, szHostExist, NULL, NULL); if (mir_strcmp(szHostNew, szHostExist) == 0) { gatewayFound = true; break; } txtParseParam(buf, NULL, "ST:", "\n", szDev, sizeof(szDev)); txtParseParam(buf, "max-age", " = ", "\n", age, sizeof(age)); expireTime = atoi(lrtrimp(age)); lrtrim(szDev); if (getUPnPURLs(szUrl, sizeof(szUrl))) { gatewayFound = getExtIP() != 0; if (gatewayFound) break; } } } FD_ZERO(&readfd); FD_SET(sock, &readfd); } } mir_free(buf); mir_free(ips); setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (char *)&any, sizeof(unsigned)); closesocket(sock); }
static int httpTransact(char* szUrl, char* szResult, int resSize, char* szActionName, ReqType reqtype) { // Parse URL char szHost[256], szPath[256], szRes[16]; int sz = 0, res = 0; unsigned short sPort; bool needClose = false; const char* szPostHdr = soap_post_hdr; char* szData = (char*)mir_alloc(4096); char* szReq = NULL; parseURL(szUrl, szHost, &sPort, szPath); if (sPort != sConnPort || _stricmp(szHost, szConnHost)) closeRouterConnection(); else validateSocket(); while (true) { retryCount = 0; switch (reqtype) { case DeviceGetReq: sz = mir_snprintf(szData, 4096, xml_get_hdr, szPath, szHost, sPort); break; case ControlAction: { char szData1[1024]; szReq = mir_strdup(szResult); sz = mir_snprintf(szData1, _countof(szData1), soap_action, szActionName, szDev, szReq, szActionName); sz = mir_snprintf(szData, 4096, szPostHdr, szPath, szHost, sPort, sz, szDev, szActionName, szData1); } break; case ControlQuery: { char szData1[1024]; sz = mir_snprintf(szData1, _countof(szData1), soap_query, szActionName); sz = mir_snprintf(szData, 4096, szPostHdr, szPath, szHost, sPort, sz, "urn:schemas-upnp-org:control-1-0", "QueryStateVariable", szData1); } break; } szResult[0] = 0; { static const TIMEVAL tv = { 6, 0 }; static unsigned ttl = 4; static u_long mode = 1; fd_set rfd, wfd, efd; SOCKADDR_IN enetaddr; retrycon: if (sock == INVALID_SOCKET) { sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); enetaddr.sin_family = AF_INET; enetaddr.sin_port = htons(sPort); enetaddr.sin_addr.s_addr = inet_addr(szHost); // Resolve host name if needed if (enetaddr.sin_addr.s_addr == INADDR_NONE) { PHOSTENT he = gethostbyname(szHost); if (he) enetaddr.sin_addr.s_addr = *(unsigned*)he->h_addr_list[0]; } NetlibLogf(NULL, "UPnP HTTP connection Host: %s Port: %u", szHost, sPort); FD_ZERO(&rfd); FD_ZERO(&wfd); FD_ZERO(&efd); FD_SET(sock, &rfd); FD_SET(sock, &wfd); FD_SET(sock, &efd); // Limit the scope of the connection (does not work for setsockopt(sock, IPPROTO_IP, IP_TTL, (char *)&ttl, sizeof(unsigned)); // Put socket into non-blocking mode for timeout on connect ioctlsocket(sock, FIONBIO, &mode); // Connect to the remote host if (connect(sock, (SOCKADDR*)&enetaddr, sizeof(enetaddr)) == SOCKET_ERROR) { int err = WSAGetLastError(); // Socket connection failed if (err != WSAEWOULDBLOCK) { closeRouterConnection(); NetlibLogf(NULL, "UPnP connect failed %d", err); break; } // Wait for socket to connect else if (select(1, &rfd, &wfd, &efd, &tv) != 1) { closeRouterConnection(); NetlibLogf(NULL, "UPnP connect timeout"); break; } else if (!FD_ISSET(sock, &wfd)) { closeRouterConnection(); NetlibLogf(NULL, "UPnP connect failed"); break; } } strncpy_s(szConnHost, szHost, _TRUNCATE); sConnPort = sPort; } if (send(sock, szData, sz, 0) != SOCKET_ERROR) { char *hdrend = NULL; int acksz = 0, pktsz = 0; if (szActionName == NULL) { int len = sizeof(locIP); getsockname(sock, (SOCKADDR*)&locIP, &len); if (locIP.sin_addr.S_un.S_addr == 0x0100007f) { struct hostent *he; gethostname(szPath, sizeof(szPath)); he = gethostbyname(szPath); if (he != NULL) locIP.sin_addr.S_un.S_addr = *(PDWORD)he->h_addr_list[0]; } } LongLog(szData); sz = 0; while (true) { int bytesRecv; FD_ZERO(&rfd); FD_SET(sock, &rfd); // Wait for the next packet if (select(1, &rfd, NULL, NULL, &tv) != 1) { closeRouterConnection(); NetlibLogf(NULL, "UPnP recieve timeout"); break; } // bytesRecv = recv(sock, &szResult[sz], resSize - sz, 0); // Connection closed or aborted, all data received if (bytesRecv == 0 || bytesRecv == SOCKET_ERROR) { closeRouterConnection(); if ((bytesRecv == SOCKET_ERROR || sz == 0) && retryCount < 2) { ++retryCount; goto retrycon; } break; } sz += bytesRecv; // Insert null terminator to use string functions if (sz >= (resSize - 1)) { szResult[resSize - 1] = 0; break; } else szResult[sz] = 0; // HTTP header found? if (hdrend == NULL) { // Find HTTP header end hdrend = strstr(szResult, "\r\n\r\n"); if (hdrend == NULL) { hdrend = strstr(szResult, "\n\n"); if (hdrend) hdrend += 2; } else hdrend += 4; if (hdrend != NULL) { // Get packet size if provided if (txtParseParam(szResult, NULL, "Content-Length:", "\n", szRes, sizeof(szRes)) || txtParseParam(szResult, NULL, "CONTENT-LENGTH:", "\n", szRes, sizeof(szRes))) { // Add size of HTTP header to the packet size to compute full transmission size pktsz = atol(ltrimp(szRes)) + (hdrend - szResult); } // Get encoding type if provided else if (txtParseParam(szResult, NULL, "Transfer-Encoding:", "\n", szRes, sizeof(szRes))) { if (_stricmp(lrtrimp(szRes), "Chunked") == 0) acksz = hdrend - szResult; } if (txtParseParam(szResult, NULL, "Connection:", "\n", szRes, sizeof(szRes))) { needClose = (_stricmp(lrtrimp(szRes), "close") == 0); } } } // Content-Length bytes reached, all data received if (sz >= pktsz && pktsz != 0) { szResult[pktsz] = 0; break; } // Chunked encoding processing if (sz > acksz && acksz != 0) { retry: // Parse out chunk size char* data = szResult + acksz; char* peol1 = data == hdrend ? data - 1 : strchr(data, '\n'); if (peol1 != NULL) { char *peol2 = strchr(++peol1, '\n'); if (peol2 != NULL) { // Get chunk size int chunkBytes = strtol(peol1, NULL, 16); acksz += chunkBytes; peol2++; memmove(data, peol2, mir_strlen(peol2) + 1); sz -= peol2 - data; // Last chunk, all data received if (chunkBytes == 0) break; if (sz > acksz) goto retry; } } } } LongLog(szResult); } else { if (retryCount < 2) { closeRouterConnection(); ++retryCount; goto retrycon; } else NetlibLogf(NULL, "UPnP send failed %d", WSAGetLastError()); } } txtParseParam(szResult, "HTTP", " ", " ", szRes, sizeof(szRes)); res = atol(szRes); if (szActionName != NULL && res == 405 && szPostHdr == soap_post_hdr) szPostHdr = soap_post_hdr_m; else break; } if (needClose) closeRouterConnection(); mir_free(szData); mir_free(szReq); return res; }
void CMsnProto::getOIMs(ezxml_t xmli) { ezxml_t toki = ezxml_child(xmli, "M"); if (toki == NULL) return; char* getReqHdr; ezxml_t reqmsg; ezxml_t xmlreq = oimRecvHdr("GetMessage", reqmsg, getReqHdr); ezxml_t reqmid = ezxml_add_child(reqmsg, "messageId", 0); ezxml_t reqmrk = ezxml_add_child(reqmsg, "alsoMarkAsRead", 0); ezxml_set_txt(reqmrk, "false"); char* delReqHdr; ezxml_t delmsg; ezxml_t xmldel = oimRecvHdr("DeleteMessages", delmsg, delReqHdr); ezxml_t delmids = ezxml_add_child(delmsg, "messageIds", 0); while (toki != NULL) { const char* szId = ezxml_txt(ezxml_child(toki, "I")); const char* szEmail = ezxml_txt(ezxml_child(toki, "E")); ezxml_set_txt(reqmid, szId); char* szData = ezxml_toxml(xmlreq, true); unsigned status; char* url = (char*)mir_strdup(oimRecvUrl); char* tResult = getSslResult(&url, szData, getReqHdr, status); free(szData); mir_free(url); if (tResult != NULL && status == 200) { ezxml_t xmlm = ezxml_parse_str(tResult, mir_strlen(tResult)); ezxml_t body = getSoapResponse(xmlm, "GetMessage"); MimeHeaders mailInfo; const char* mailbody = mailInfo.readFromBuffer((char*)ezxml_txt(body)); time_t evtm = time(NULL); const char* arrTime = mailInfo["X-OriginalArrivalTime"]; if (arrTime != NULL) { char szTime[32], *p; txtParseParam(arrTime, "FILETIME", "[", "]", szTime, sizeof(szTime)); unsigned filetimeLo = strtoul(szTime, &p, 16); if (*p == ':') { unsigned __int64 filetime = strtoul(p + 1, &p, 16); filetime <<= 32; filetime |= filetimeLo; filetime /= 10000000; #ifndef __GNUC__ filetime -= 11644473600ui64; #else filetime -= 11644473600ull; #endif evtm = (time_t)filetime; } } PROTORECVEVENT pre = { 0 }; pre.szMessage = mailInfo.decodeMailBody((char*)mailbody); pre.timestamp = evtm; ProtoChainRecvMsg(MSN_HContactFromEmail(szEmail), &pre); mir_free(pre.szMessage); ezxml_t delmid = ezxml_add_child(delmids, "messageId", 0); ezxml_set_txt(delmid, szId); ezxml_free(xmlm); } mir_free(tResult); toki = ezxml_next(toki); } ezxml_free(xmlreq); mir_free(getReqHdr); if (ezxml_child(delmids, "messageId") != NULL) { char* szData = ezxml_toxml(xmldel, true); unsigned status; char* url = (char*)mir_strdup(oimRecvUrl); char* tResult = getSslResult(&url, szData, delReqHdr, status); mir_free(url); mir_free(tResult); free(szData); } ezxml_free(xmldel); mir_free(delReqHdr); }