diff --git a/mist/mist.cpp b/mist/mist.cpp index 5b3827e..6f54c2c 100644 --- a/mist/mist.cpp +++ b/mist/mist.cpp @@ -732,7 +732,7 @@ bool CheckWANAccess(PSOCKADDR_IN wanAddr, PSOCKADDR_IN reportedWanAddr, bool* fo fprintf(LOG_OUT, "Detecting WAN IP address via STUN..."); fprintf(CONSOLE_OUT, "\tTesting STUN...\n"); - if (!getExternalAddressPortIP4(IPPROTO_UDP, 0, wanAddr) && !getExternalAddressPortIP4(IPPROTO_TCP, 0, wanAddr)) { + if (!getExternalAddressPortIP4(0, wanAddr)) { DisplayMessage("Unable to determine your public IP address. Please check your Internet connection or try again in a few minutes."); return false; } diff --git a/mist/mist.h b/mist/mist.h index 7e2becb..f91d6b1 100644 --- a/mist/mist.h +++ b/mist/mist.h @@ -7,6 +7,7 @@ #define WIN32_LEAN_AND_MEAN #define _WINSOCK_DEPRECATED_NO_WARNINGS #include +#include #include #include "..\version.h" @@ -14,4 +15,4 @@ #define CONSOLE_OUT stdout #define LOG_OUT stderr -bool getExternalAddressPortIP4(int proto, unsigned short localPort, PSOCKADDR_IN wanAddr); \ No newline at end of file +bool getExternalAddressPortIP4(unsigned short localPort, PSOCKADDR_IN wanAddr); \ No newline at end of file diff --git a/mist/stun.cpp b/mist/stun.cpp index 9653af8..1e7572d 100644 --- a/mist/stun.cpp +++ b/mist/stun.cpp @@ -38,7 +38,7 @@ typedef struct _STUN_MESSAGE { #pragma pack(pop) -bool getExternalAddressPortIP4(int proto, unsigned short localPort, PSOCKADDR_IN wanAddr) +bool getExternalAddressPortIP4(unsigned short localPort, PSOCKADDR_IN wanAddr) { SOCKET sock; STUN_MESSAGE reqMsg; @@ -46,32 +46,41 @@ bool getExternalAddressPortIP4(int proto, unsigned short localPort, PSOCKADDR_IN int bytesRead; int tries; int timeout; + int err; PSTUN_ATTRIBUTE_HEADER attribute; PSTUN_MAPPED_IPV4_ADDRESS_ATTRIBUTE ipv4Attrib; - struct hostent *host; + struct addrinfo* result; + struct addrinfo hints; union { STUN_MESSAGE hdr; char buf[1024]; } resp; - host = gethostbyname("stun.moonlight-stream.org"); - if (host == nullptr) { - fprintf(LOG_OUT, "gethostbyname() failed: %d\n", WSAGetLastError()); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_flags = AI_ADDRCONFIG; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + err = getaddrinfo("stun.moonlight-stream.org", "3478", &hints, &result); + if (err != 0 || result == NULL) { + fprintf(LOG_OUT, "getaddrinfo() failed: %d\n", err); return false; } - sock = socket(AF_INET, proto == IPPROTO_TCP ? SOCK_STREAM : SOCK_DGRAM, proto); + sock = socket(hints.ai_family, hints.ai_socktype, hints.ai_protocol); if (sock == INVALID_SOCKET) { fprintf(LOG_OUT, "socket() failed: %d\n", WSAGetLastError()); + freeaddrinfo(result); return false; } struct sockaddr_in bindAddr = {}; - bindAddr.sin_family = AF_INET; + bindAddr.sin_family = hints.ai_family; bindAddr.sin_port = htons(localPort); if (bind(sock, (struct sockaddr*)&bindAddr, sizeof(bindAddr)) == SOCKET_ERROR) { fprintf(LOG_OUT, "bind() failed: %d\n", WSAGetLastError()); closesocket(sock); + freeaddrinfo(result); return false; } @@ -82,36 +91,13 @@ bool getExternalAddressPortIP4(int proto, unsigned short localPort, PSOCKADDR_IN reqMsg.transactionId[i] = rand(); } - SOCKADDR_IN stunAddr = {}; - stunAddr.sin_family = AF_INET; - stunAddr.sin_port = htons(STUN_PORT); - stunAddr.sin_addr = *(struct in_addr*)host->h_addr; - - // We'll connect() even for UDP so we can use send()/recv() and share more code - if (connect(sock, (struct sockaddr*)&stunAddr, sizeof(stunAddr)) == SOCKET_ERROR) { - fprintf(LOG_OUT, "connect() failed: %d\n", WSAGetLastError()); - closesocket(sock); - return false; - } - - // For UDP, we'll do 3 iterations of 1 second each. For TCP, - // we'll do one iteration with a 3 second wait. - if (proto == IPPROTO_TCP) { - tries = 1; - timeout = STUN_RECV_TIMEOUT_SEC; - } - else { - tries = STUN_RECV_TIMEOUT_SEC; - timeout = 1; - } - bytesRead = 0; - for (i = 0; i < tries; i++) { - // Retransmit the request every second until the timeout elapses - if (send(sock, (char *)&reqMsg, sizeof(reqMsg), 0) == SOCKET_ERROR) { - fprintf(LOG_OUT, "send() failed: %d\n", WSAGetLastError()); - closesocket(sock); - return false; + for (i = 0; i < STUN_RECV_TIMEOUT_SEC; i++) { + // Retransmit the request every second to all resolved IP addresses until the timeout elapses + for (struct addrinfo* current = result; current != NULL; current = current->ai_next) { + if (sendto(sock, (char*)&reqMsg, sizeof(reqMsg), 0, current->ai_addr, current->ai_addrlen) == SOCKET_ERROR) { + fprintf(LOG_OUT, "sendto() failed: %d\n", WSAGetLastError()); + } } fd_set fds; @@ -119,7 +105,7 @@ bool getExternalAddressPortIP4(int proto, unsigned short localPort, PSOCKADDR_IN FD_SET(sock, &fds); struct timeval tv; - tv.tv_sec = timeout; + tv.tv_sec = 1; tv.tv_usec = 0; int selectRes = select(0, &fds, nullptr, nullptr, &tv); @@ -130,14 +116,16 @@ bool getExternalAddressPortIP4(int proto, unsigned short localPort, PSOCKADDR_IN else if (selectRes == SOCKET_ERROR) { fprintf(LOG_OUT, "select() failed: %d\n", WSAGetLastError()); closesocket(sock); + freeaddrinfo(result); return false; } // Error handling is below - bytesRead = recv(sock, resp.buf, sizeof(resp.buf), 0); + bytesRead = recvfrom(sock, resp.buf, sizeof(resp.buf), 0, NULL, NULL); break; } + freeaddrinfo(result); closesocket(sock); if (bytesRead == 0) {