summaryrefslogtreecommitdiff
path: root/protocols/MSN/src/msn_natdetect.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/MSN/src/msn_natdetect.cpp')
-rw-r--r--protocols/MSN/src/msn_natdetect.cpp471
1 files changed, 0 insertions, 471 deletions
diff --git a/protocols/MSN/src/msn_natdetect.cpp b/protocols/MSN/src/msn_natdetect.cpp
deleted file mode 100644
index 35f518b51b..0000000000
--- a/protocols/MSN/src/msn_natdetect.cpp
+++ /dev/null
@@ -1,471 +0,0 @@
-/*
-Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
-
-Copyright (c) 2012-2017 Miranda NG Team
-Copyright (c) 2007-2012 Boris Krasnovskiy.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "stdafx.h"
-#include "msn_proto.h"
-#include <netfw.h>
-#ifdef OBSOLETE
-
-#ifndef CLSID_NetFwMgr
-#define MDEF_CLSID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
- const CLSID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
-
- MDEF_CLSID(CLSID_NetFwMgr, 0x304ce942, 0x6e39, 0x40d8, 0x94, 0x3a, 0xb9, 0x13, 0xc4, 0x0c, 0x9c, 0xd4);
- MDEF_CLSID(IID_INetFwMgr, 0xf7898af5, 0xcac4, 0x4632, 0xa2, 0xec, 0xda ,0x06, 0xe5, 0x11, 0x1a, 0xf2);
-#endif
-
-
-MyConnectionType MyConnection;
-
-const char* conStr[] =
-{
- "Unknown-Connect",
- "Direct-Connect",
- "Unknown-NAT",
- "IP-Restrict-NAT",
- "Port-Restrict-NAT",
- "Symmetric-NAT",
- "Firewall",
- "ISALike"
-};
-
-
-void CMsnProto::DecryptEchoPacket(UDPProbePkt& pkt)
-{
- pkt.clientPort ^= 0x3141;
- pkt.discardPort ^= 0x3141;
- pkt.testPort ^= 0x3141;
- pkt.clientIP ^= 0x31413141;
- pkt.testIP ^= 0x31413141;
-
-
- IN_ADDR addr;
- debugLogA("Echo packet: version: 0x%x service code: 0x%x transaction ID: 0x%x",
- pkt.version, pkt.serviceCode, pkt.trId);
- addr.S_un.S_addr = pkt.clientIP;
- debugLogA("Echo packet: client port: %u client addr: %s",
- pkt.clientPort, inet_ntoa(addr));
- addr.S_un.S_addr = pkt.testIP;
- debugLogA("Echo packet: discard port: %u test port: %u test addr: %s",
- pkt.discardPort, pkt.testPort, inet_ntoa(addr));
-}
-
-
-static void DiscardExtraPackets(SOCKET s)
-{
- Sleep(3000);
-
- static const TIMEVAL tv = { 0, 0 };
- unsigned buf;
-
- for (;;) {
- if (g_bTerminated) break;
-
- fd_set fd;
- FD_ZERO(&fd);
- FD_SET(s, &fd);
-
- if (select(1, &fd, NULL, NULL, &tv) == 1)
- recv(s, (char*)&buf, sizeof(buf), 0);
- else
- break;
- }
-}
-
-
-void CMsnProto::MSNatDetect(void)
-{
- PHOSTENT host = gethostbyname("echo.edge.messenger.live.com");
- if (host == NULL) {
- debugLogA("P2PNAT could not find echo server \"echo.edge.messenger.live.com\"");
- return;
- }
-
- SOCKADDR_IN addr;
- addr.sin_family = AF_INET;
- addr.sin_port = _htons(7001);
- addr.sin_addr = *(PIN_ADDR)host->h_addr_list[0];
-
- debugLogA("P2PNAT Detected echo server IP %d.%d.%d.%d",
- addr.sin_addr.S_un.S_un_b.s_b1, addr.sin_addr.S_un.S_un_b.s_b2,
- addr.sin_addr.S_un.S_un_b.s_b3, addr.sin_addr.S_un.S_un_b.s_b4);
-
- SOCKET s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- if (connect(s, (SOCKADDR*)&addr, sizeof(addr)) == SOCKET_ERROR) {
- debugLogA("P2PNAT could not connect to echo server \"echo.edge.messenger.live.com\"");
- closesocket(s);
- return;
- }
-
- UDPProbePkt pkt = { 0 }, pkt2;
-
- // Detect My IP
- pkt.version = 2;
- pkt.serviceCode = 4;
- send(s, (char*)&pkt, sizeof(pkt), 0);
-
- SOCKADDR_IN myaddr;
- int szname = sizeof(myaddr);
- getsockname(s, (SOCKADDR*)&myaddr, &szname);
-
- MyConnection.intIP = myaddr.sin_addr.S_un.S_addr;
- debugLogA("P2PNAT Detected IP facing internet %d.%d.%d.%d",
- myaddr.sin_addr.S_un.S_un_b.s_b1, myaddr.sin_addr.S_un.S_un_b.s_b2,
- myaddr.sin_addr.S_un.S_un_b.s_b3, myaddr.sin_addr.S_un.S_un_b.s_b4);
-
- SOCKET s1 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-
- pkt.version = 2;
- pkt.serviceCode = 1;
- pkt.clientPort = 0x3141;
- pkt.clientIP = 0x31413141;
-
- UDPProbePkt rpkt = { 0 };
-
- // NAT detection
- unsigned i;
- for (i = 0; i < 4; ++i) {
- if (g_bTerminated) break;
-
- // Send echo request to server 1
- debugLogA("P2PNAT Request 1 attempt %d sent", i);
- sendto(s1, (char*)&pkt, sizeof(pkt), 0, (SOCKADDR*)&addr, sizeof(addr));
-
- fd_set fd;
- FD_ZERO(&fd);
- FD_SET(s1, &fd);
- TIMEVAL tv = { 0, 200000 * (1 << i) };
-
- if (select(1, &fd, NULL, NULL, &tv) == 1) {
- debugLogA("P2PNAT Request 1 attempt %d response", i);
- recv(s1, (char*)&rpkt, sizeof(rpkt), 0);
- pkt2 = rpkt;
- DecryptEchoPacket(rpkt);
- break;
- }
- else debugLogA("P2PNAT Request 1 attempt %d timeout", i);
- }
-
- closesocket(s);
-
- // Server did not respond
- if (i >= 4) {
- MyConnection.udpConType = conFirewall;
- closesocket(s1);
- return;
- }
-
- MyConnection.extIP = rpkt.clientIP;
-
- // Check if NAT not found
- if (MyConnection.extIP == MyConnection.intIP) {
- if (msnExternalIP != NULL && inet_addr(msnExternalIP) != MyConnection.extIP)
- MyConnection.udpConType = conISALike;
- else
- MyConnection.udpConType = conDirect;
-
- closesocket(s1);
- return;
- }
-
- // Detect UPnP NAT
- NETLIBBIND nlb = { 0 };
- nlb.cbSize = sizeof(nlb);
- nlb.pfnNewConnectionV2 = MSN_ConnectionProc;
- nlb.pExtra = this;
-
- HANDLE sb = (HANDLE)CallService(MS_NETLIB_BINDPORT, (WPARAM)m_hNetlibUser, (LPARAM)&nlb);
- if (sb != NULL) {
- MyConnection.upnpNAT = htonl(nlb.dwExternalIP) == MyConnection.extIP;
- Sleep(100);
- Netlib_CloseHandle(sb);
- }
-
- DiscardExtraPackets(s1);
-
- // Start IP Restricted NAT detection
- UDPProbePkt rpkt2 = { 0 };
- pkt2.serviceCode = 3;
- SOCKADDR_IN addr2 = addr;
- addr2.sin_addr.S_un.S_addr = rpkt.testIP;
- addr2.sin_port = rpkt.discardPort;
- for (i = 0; i < 4; ++i) {
- if (g_bTerminated) break;
-
- debugLogA("P2PNAT Request 2 attempt %d sent", i);
- // Remove IP restriction for server 2
- sendto(s1, NULL, 0, 0, (SOCKADDR*)&addr2, sizeof(addr2));
- // Send echo request to server 1 for server 2
- sendto(s1, (char*)&pkt2, sizeof(pkt2), 0, (SOCKADDR*)&addr, sizeof(addr));
-
- fd_set fd;
- FD_ZERO(&fd);
- FD_SET(s1, &fd);
- TIMEVAL tv = { 0, 200000 * (1 << i) };
-
- if (select(1, &fd, NULL, NULL, &tv) == 1) {
- debugLogA("P2PNAT Request 2 attempt %d response", i);
- recv(s1, (char*)&rpkt2, sizeof(rpkt2), 0);
- DecryptEchoPacket(rpkt2);
- break;
- }
- else
- debugLogA("P2PNAT Request 2 attempt %d timeout", i);
- }
-
- // Response recieved so it's an IP Restricted NAT (Restricted Cone NAT)
- // (MSN does not detect Full Cone NAT and consider it as IP Restricted NAT)
- if (i < 4) {
- MyConnection.udpConType = conIPRestrictNAT;
- closesocket(s1);
- return;
- }
-
- DiscardExtraPackets(s1);
-
- // Symmetric NAT detection
- addr2.sin_port = rpkt.testPort;
- for (i = 0; i < 4; ++i) {
- if (g_bTerminated) break;
-
- debugLogA("P2PNAT Request 3 attempt %d sent", i);
- // Send echo request to server 1
- sendto(s1, (char*)&pkt, sizeof(pkt), 0, (SOCKADDR*)&addr2, sizeof(addr2));
-
- fd_set fd;
- FD_ZERO(&fd);
- FD_SET(s1, &fd);
- TIMEVAL tv = { 1 << i, 0 };
-
- if (select(1, &fd, NULL, NULL, &tv) == 1) {
- debugLogA("P2PNAT Request 3 attempt %d response", i);
- recv(s1, (char*)&rpkt2, sizeof(rpkt2), 0);
- DecryptEchoPacket(rpkt2);
- break;
- }
- else
- debugLogA("P2PNAT Request 3 attempt %d timeout", i);
- }
- if (i < 4) {
- // If ports different it's symmetric NAT
- MyConnection.udpConType = rpkt.clientPort == rpkt2.clientPort ?
-conPortRestrictNAT : conSymmetricNAT;
- }
- closesocket(s1);
-}
-
-
-static bool IsIcfEnabled(void)
-{
- HRESULT hr;
- VARIANT_BOOL fwEnabled = VARIANT_FALSE;
-
- INetFwProfile* fwProfile = NULL;
- INetFwMgr* fwMgr = NULL;
- INetFwPolicy* fwPolicy = NULL;
- INetFwAuthorizedApplication* fwApp = NULL;
- INetFwAuthorizedApplications* fwApps = NULL;
- BSTR fwBstrProcessImageFileName = NULL;
- wchar_t *wszFileName = NULL;
-
- hr = CoInitialize(NULL);
- if (FAILED(hr)) return false;
-
- // Create an instance of the firewall settings manager.
- hr = CoCreateInstance(CLSID_NetFwMgr, NULL, CLSCTX_INPROC_SERVER,
- IID_INetFwMgr, (void**)&fwMgr);
- if (FAILED(hr)) goto error;
-
- // Retrieve the local firewall policy.
- hr = fwMgr->get_LocalPolicy(&fwPolicy);
- if (FAILED(hr)) goto error;
-
- // Retrieve the firewall profile currently in effect.
- hr = fwPolicy->get_CurrentProfile(&fwProfile);
- if (FAILED(hr)) goto error;
-
- // Get the current state of the firewall.
- hr = fwProfile->get_FirewallEnabled(&fwEnabled);
- if (FAILED(hr)) goto error;
-
- if (fwEnabled == VARIANT_FALSE) goto error;
-
- // Retrieve the authorized application collection.
- hr = fwProfile->get_AuthorizedApplications(&fwApps);
- if (FAILED(hr)) goto error;
-
- wchar_t szFileName[MAX_PATH];
- GetModuleFileName(NULL, szFileName, _countof(szFileName));
-
- wszFileName = mir_wstrdup(szFileName);
-
- // Allocate a BSTR for the process image file name.
- fwBstrProcessImageFileName = SysAllocString(wszFileName);
- if (FAILED(hr)) goto error;
-
- // Attempt to retrieve the authorized application.
- hr = fwApps->Item(fwBstrProcessImageFileName, &fwApp);
- if (SUCCEEDED(hr)) {
- // Find out if the authorized application is enabled.
- fwApp->get_Enabled(&fwEnabled);
- fwEnabled = ~fwEnabled;
- }
-
-error:
- // Free the BSTR.
- SysFreeString(fwBstrProcessImageFileName);
- mir_free(wszFileName);
-
- // Release the authorized application instance.
- if (fwApp != NULL) fwApp->Release();
-
- // Release the authorized application collection.
- if (fwApps != NULL) fwApps->Release();
-
- // Release the firewall profile.
- if (fwProfile != NULL) fwProfile->Release();
-
- // Release the local firewall policy.
- if (fwPolicy != NULL) fwPolicy->Release();
-
- // Release the firewall settings manager.
- if (fwMgr != NULL) fwMgr->Release();
-
- CoUninitialize();
-
- return fwEnabled != VARIANT_FALSE;
-}
-
-void CMsnProto::MSNConnDetectThread(void*)
-{
- char parBuf[512] = "";
-
- memset(&MyConnection, 0, sizeof(MyConnection));
-
- MyConnection.icf = IsIcfEnabled();
- bool portsMapped = getByte("NLSpecifyIncomingPorts", 0) != 0;
-
- unsigned gethst = getByte("AutoGetHost", 1);
- switch (gethst) {
- case 0:
- debugLogA("P2PNAT User overwrote IP connection is guessed by user settings only");
-
- // User specified host by himself so check if it matches MSN information
- // if it does, move to connection type autodetection,
- // if it does not, guess connection type from available info
- db_get_static(NULL, m_szModuleName, "YourHost", parBuf, sizeof(parBuf));
- if (msnExternalIP == NULL || mir_strcmp(msnExternalIP, parBuf) != 0) {
- MyConnection.extIP = inet_addr(parBuf);
- if (MyConnection.extIP == INADDR_NONE) {
- PHOSTENT myhost = gethostbyname(parBuf);
- if (myhost != NULL)
- MyConnection.extIP = ((PIN_ADDR)myhost->h_addr)->S_un.S_addr;
- else
- setByte("AutoGetHost", 1);
- }
- if (MyConnection.extIP != INADDR_NONE) {
- MyConnection.intIP = MyConnection.extIP;
- MyConnection.udpConType = MyConnection.extIP ? (ConEnum)portsMapped : conUnknown;
- MyConnection.CalculateWeight();
- return;
- }
- else
- MyConnection.extIP = 0;
- }
- break;
-
- case 1:
- if (msnExternalIP != NULL)
- MyConnection.extIP = inet_addr(msnExternalIP);
- else {
- gethostname(parBuf, sizeof(parBuf));
- PHOSTENT myhost = gethostbyname(parBuf);
- if (myhost != NULL)
- MyConnection.extIP = ((PIN_ADDR)myhost->h_addr)->S_un.S_addr;
- }
- MyConnection.intIP = MyConnection.extIP;
- break;
-
- case 2:
- MyConnection.udpConType = conUnknown;
- MyConnection.CalculateWeight();
- return;
- }
-
- if (getByte("NLSpecifyOutgoingPorts", 0)) {
- // User specified outgoing ports so the connection must be firewalled
- // do not autodetect and guess connection type from available info
- MyConnection.intIP = MyConnection.extIP;
- MyConnection.udpConType = (ConEnum)portsMapped;
- MyConnection.upnpNAT = false;
- MyConnection.CalculateWeight();
- return;
- }
-
- MSNatDetect();
-
- // If user mapped incoming ports consider direct connection
- if (portsMapped) {
- debugLogA("P2PNAT User manually mapped ports for incoming connection");
- switch (MyConnection.udpConType) {
- case conUnknown:
- case conFirewall:
- case conISALike:
- MyConnection.udpConType = conDirect;
- break;
-
- case conUnknownNAT:
- case conPortRestrictNAT:
- case conIPRestrictNAT:
- case conSymmetricNAT:
- MyConnection.upnpNAT = true;
- break;
- }
- }
-
- debugLogA("P2PNAT Connection %s found UPnP: %d ICF: %d", conStr[MyConnection.udpConType],
- MyConnection.upnpNAT, MyConnection.icf);
-
- MyConnection.CalculateWeight();
-}
-
-void MyConnectionType::SetUdpCon(const char* str)
-{
- for (unsigned i = 0; i < sizeof(conStr) / sizeof(char*); ++i) {
- if (mir_strcmp(conStr[i], str) == 0) {
- udpConType = (ConEnum)i;
- break;
- }
- }
-}
-
-void MyConnectionType::CalculateWeight(void)
-{
- if (icf) weight = 0;
- else if (udpConType == conDirect) weight = 6;
- else if (udpConType >= conIPRestrictNAT && udpConType <= conSymmetricNAT)
- weight = upnpNAT ? 5 : 2;
- else if (udpConType == conUnknownNAT)
- weight = upnpNAT ? 4 : 1;
- else if (udpConType == conUnknown) weight = 1;
- else if (udpConType == conFirewall) weight = 2;
- else if (udpConType == conISALike) weight = 3;
-}
-#endif