mirror of
https://github.com/moonlight-stream/Internet-Hosting-Tool.git
synced 2026-04-09 01:06:10 +00:00
Add the ability to punch through multiple NATs in some situations
This commit is contained in:
131
miss/tracer.cpp
131
miss/tracer.cpp
@@ -1,5 +1,6 @@
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define _WINSOCK_DEPRECATED_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#include <Windows.h>
|
||||
|
||||
#include <WinSock2.h>
|
||||
@@ -8,6 +9,131 @@
|
||||
#include <icmpapi.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define MINIUPNP_STATICLIB
|
||||
#include <miniupnpc/miniupnpc.h>
|
||||
|
||||
static const char* k_SsdpSearchFormatString =
|
||||
"M-SEARCH * HTTP/1.1\r\n"
|
||||
"HOST: %s:1900\r\n"
|
||||
"ST: ssdp:all\r\n"
|
||||
"MAN: \"ssdp:discover\"\r\n"
|
||||
"MX: 5\r\n"
|
||||
"\r\n";
|
||||
|
||||
struct UPNPDev* getUPnPDevicesByAddress(IN_ADDR address)
|
||||
{
|
||||
SOCKET s;
|
||||
SOCKADDR_IN connAddr;
|
||||
char searchBuffer[512];
|
||||
int chars;
|
||||
|
||||
s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (s == INVALID_SOCKET) {
|
||||
printf("socket() failed: %d\n", WSAGetLastError());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
connAddr = {};
|
||||
connAddr.sin_family = AF_INET;
|
||||
connAddr.sin_port = htons(1900);
|
||||
connAddr.sin_addr = address;
|
||||
|
||||
// Use connect() to ensure we don't get responses from other devices
|
||||
if (connect(s, (struct sockaddr*)&connAddr, sizeof(connAddr)) == SOCKET_ERROR) {
|
||||
printf("connect() failed: %d\n", WSAGetLastError());
|
||||
closesocket(s);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Send the first search message with HOST set properly
|
||||
chars = snprintf(searchBuffer, ARRAYSIZE(searchBuffer), k_SsdpSearchFormatString, inet_ntoa(address));
|
||||
if (send(s, searchBuffer, chars, 0) == SOCKET_ERROR) {
|
||||
printf("send() failed: %d\n", WSAGetLastError());
|
||||
closesocket(s);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Send another search message with HOST set to 239.255.255.250 to avoid issues
|
||||
// on routers that explicitly check for that HOST value
|
||||
chars = snprintf(searchBuffer, ARRAYSIZE(searchBuffer), k_SsdpSearchFormatString, "239.255.255.250");
|
||||
if (send(s, searchBuffer, chars, 0) == SOCKET_ERROR) {
|
||||
printf("send() failed: %d\n", WSAGetLastError());
|
||||
closesocket(s);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Sleep(5000);
|
||||
|
||||
// Switch to non-blocking mode to read the responses
|
||||
u_long mode = 1;
|
||||
ioctlsocket(s, FIONBIO, &mode);
|
||||
|
||||
char responseBuffer[1024];
|
||||
struct UPNPDev* deviceList = nullptr;
|
||||
for (;;) {
|
||||
int bytesRead = recv(s, responseBuffer, sizeof(responseBuffer) - 1, 0);
|
||||
if (bytesRead == SOCKET_ERROR) {
|
||||
if (WSAGetLastError() != WSAEWOULDBLOCK) {
|
||||
printf("recv() failed: %d\n", WSAGetLastError());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Null-terminate the buffer
|
||||
responseBuffer[bytesRead] = 0;
|
||||
|
||||
// Parse the first status line:
|
||||
// HTTP/1.1 200 OK
|
||||
char* protocol = strtok(responseBuffer, " ");
|
||||
char* statusCodeStr = strtok(nullptr, " ");
|
||||
char* statusMessage = strtok(nullptr, "\r");
|
||||
if (_stricmp(protocol, "HTTP/1.0") && _stricmp(protocol, "HTTP/1.1")) {
|
||||
printf("Unexpected protocol: %s\n", protocol);
|
||||
continue;
|
||||
}
|
||||
if (atoi(statusCodeStr) != 200) {
|
||||
printf("Unexpected status: %s %s\n", statusCodeStr, statusMessage);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Parse the header options
|
||||
// SERVER: FreeBSD/11.2-RELEASE-p2 UPnP/1.1 MiniUPnPd/2.0\r\n
|
||||
char* location = nullptr;
|
||||
char* st = nullptr;
|
||||
while (char* headerName = strtok(nullptr, "\r\n:")) {
|
||||
char* headerValue = strtok(nullptr, "\r");
|
||||
|
||||
// Skip leading spaces
|
||||
while (*headerValue == ' ') headerValue++;
|
||||
|
||||
if (!_stricmp(headerName, "LOCATION")) {
|
||||
location = headerValue;
|
||||
}
|
||||
else if (!_stricmp(headerName, "ST")) {
|
||||
st = headerValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!location || location[0] == 0 || !st || st[0] == 0) {
|
||||
printf("Required value missing: \"%s\" \"%s\"\n", location, st);
|
||||
continue;
|
||||
}
|
||||
|
||||
struct UPNPDev* newDev = (struct UPNPDev*)malloc(sizeof(*newDev) + strlen(location) + strlen(st) + 2);
|
||||
|
||||
newDev->pNext = deviceList;
|
||||
newDev->usn = &newDev->buffer[0]; newDev->buffer[0] = 0;
|
||||
newDev->descURL = strcpy(newDev->usn + strlen(newDev->usn) + 1, location);
|
||||
newDev->st = strcpy(newDev->descURL + strlen(newDev->descURL) + 1, st);
|
||||
newDev->scope_id = 0; // IPv6 only
|
||||
|
||||
deviceList = newDev;
|
||||
}
|
||||
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
bool getHopsIP4(IN_ADDR* hopAddress, int* hopAddressCount)
|
||||
{
|
||||
@@ -64,12 +190,13 @@ bool getHopsIP4(IN_ADDR* hopAddress, int* hopAddressCount)
|
||||
else {
|
||||
// Bail on anything else
|
||||
printf("Hop %d: %s (error %d)\n", ttl, inet_ntoa(*(IN_ADDR*)&replies[0].Address), replies[0].Status);
|
||||
*hopAddressCount = ttl - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
IcmpCloseHandle(icmpFile);
|
||||
|
||||
*hopAddressCount = ttl - 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user