Send and receive via SOCKS5 c++

11,914

Solution 1

Once you have successfully authenticated with the proxy and told it where to connect to, then you simply send/recv your desired data (in this case, the HTTP data) using the existing connection to the proxy, as if you had connected to the target server directly and not to a proxy. Once the proxy session is established, all subsequent sends/receives are transparent to your app.

Update: You might also want to clean up your code so it is easier to read, fix your existing broken error handling, and add some additional error handling that is missing:

#include <stdio.h>
#include <WinSock2.h>
#include <stdlib.h>
#pragma comment(lib,"ws2_32.lib")

#include <pshpack1.h>
struct socks5_ident_req
{
    unsigned char Version;
    unsigned char NumberOfMethods;
    unsigned char Methods[256];
};

struct socks5_ident_resp
{
    unsigned char Version;
    unsigned char Method;
};

struct socks5_req
{
    unsigned char Version;
    unsigned char Cmd;
    unsigned char Reserved;
    unsigned char AddrType;
    union {
        in_addr IPv4;
        in6_addr IPv6;
        struct {
            unsigned char DomainLen;
            char Domain[256];
        };
    } DestAddr;
    unsigned short DestPort;
};

struct socks5_resp
{
    unsigned char Version;
    unsigned char Reply;
    unsigned char Reserved;
    unsigned char AddrType;
    union {
        in_addr IPv4;
        in6_addr IPv6;
        struct {
            unsigned char DomainLen;
            char Domain[256];
        };
    } BindAddr;
    unsigned short BindPort;
};
#include <poppack.h>

bool sendData(SOCKET fd, void *data, int len)
{
    char *ptr = (char *) data;

    while (len > 0)
    {
        int sent = send(fd, ptr, len, 0);
        if (sent <= 0)
        {
            printf("send() error: %d", WSAGetLastError());
            return false;
        }
        ptr += sent;
        len -= sent;
    }

    return true;
}

int recvData(SOCKET fd, void *data, int len, bool disconnectOk = false)
{
    char *ptr = (char *) data;
    int total = 0;

    while (len > 0)
    {
        int recvd = recv(fd, ptr, len, 0);
        if (recvd < 0)
        {
            printf("recv() error: %d", WSAGetLastError());
            return -1;
        }
        if (recvd == 0)
        {
            if (disconnectOk)
                break;
            printf("disconnected");
            return -1;
        }
        ptr += recvd;
        len -= recvd;
        total -= recvd;
    }

    return total;
}

bool socksLogin(SOCKET fd)
{
    socks5_ident_req req;
    socks5_ident_req resp;

    req.Version = 5;
    req.NumberOfMethods = 1;
    req.Methods[0] = 0x00;
    // add other methods as needed...

    if (!sendData(fd, &req, 2+req.NumberOfMethods))
        return false;

    if (recvData(fd, &resp, sizeof(resp)) == -1)
        return false;

    if (resp.Version != 5)
    {
        printf("SOCKS v5 identification failed");
        return false;
    }

    if (resp.Method == 0xFF)
    {
        printf("SOCKS v5 authentication failed");
        return false;
    }

    /*
    if (resp.Method != 0x00)
    {
        // authenticate as needed...
    }
    */

    return true;
}

bool socksRequest(SOCKET fd, const socks5_req &req, socks5_resp &resp)
{
    memset(&resp, 0, sizeof(resp));

    if (!sendData(fd, &req, 4))
        return false;

    switch (req.AddrType)
    {                         
        case 1:                                     
        {
            if (!sendData(fd, &(req.DestAddr.IPv4), sizeof(in_addr)))
                return false;              

            break;
        }
        case 3:
        {                                     
            if (!sendData(fd, &(req.DestAddr.DomainLen), 1))
                return false;

            if (!sendData(fd, req.DestAddr.Domain, req.DestAddr.DomainLen))
                return false;

            break;
        }
        case 4:
        {                                    
            if (!sendData(fd, &(req.DestAddr.IPv6), sizeof(in6_addr)))
                return false;              

            break;
        }

        default:
        {
            printf("SOCKS 5 requesting unknown address type");
            return false;
        }
    }

    unsigned short port = htons(req.DestPort);
    if (!sendData(fd, &port, 2))
        return false;

    if (recvData(fd, &resp, 4) == -1)
        return false;

    switch (resp.AddrType)
    {                         
        case 1:                                     
        {
            if (recvData(fd, &(resp.BindAddr.IPv4), sizeof(in_addr)) == -1)
                return false;              

            break;
        }
        case 3:
        {                                     
            if (recvData(fd, &(resp.BindAddr.DomainLen), 1) == -1)
                return false;

            if (recvData(fd, resp.BindAddr.Domain, resp.BindAddr.DomainLen) == -1)
                return false;

            break;
        }
        case 4:
        {                                    
            if (recvData(fd, &(resp.BindAddr.IPv6), sizeof(in6_addr)) == -1)
                return false;              

            break;
        }

        default:
        {
            printf("SOCKS 5 bound to unknown address type");
            return false;
        }
    }

    if (recvData(fd, &port, 2, 0) == -1)
        return false;

    resp.BindPort = ntohs(port);

    return true;
}

bool socksConnect(SOCKET fd, const in_addr &dest, unsigned short port)
{
    socks5_req req;
    socks5_resp resp;

    req.Version = 5;
    req.Cmd = 1;
    req.Reserved = 0;
    req.AddrType = 1;
    req.DestAddr.IPv4 = dest;
    req.DestPort = port;

    if (!socksRequest(fd, req, resp))
        return false;

    if (resp.Reply != 0x00)
    {
        printf("SOCKS v5 connect failed, error: 0x%02X", resp.Reply);
        return false;
    }

    return true;
}

int main()
{
    WSADATA wsaData;
    int rv = WSAStartup(MAKEWORD(2,0), &wsaData);
    if (rv != 0)
    {
        printf("WSAStartup() error: %d", rv);
        return 1;
    }

    SOCKET fd = socket( AF_INET, SOCK_STREAM, 0);
    if (fd == INVALID_SOCKET)
    {
        printf("socket() error: %d", WSAGetLastError());
        return 1;
    }

    struct sockaddr_in saddr;
    memset(&saddr, 0, sizeof(saddr));
    saddr.sin_family = AF_INET;
    saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    saddr.sin_port = htons(9150);

    if (connect(fd, (struct sockaddr *) &saddr, sizeof(saddr)) != 0)
    {
        printf("connect() error: %d", WSAGetLastError());
        return 1;
    }

    if (!socksLogin(fd))
        return 1;

    if (!socksConnect(fd, inet_addr("xx.xx.xx.xx"), 80))
        return 1;

    printf("Success!");

    // now send/receive desired data as needed using existing fd ...

    return 0;
}

Solution 2

I recently found a modern C++ implementation for sending and receiving data through a SOCKS5 proxy server, this person looks like he had implemented the SOCKS5's User/Pass Authentication too (along with Anonymous mode) and also with remote and local DNS resolution options (for more privacy).

Take a look: https://github.com/harsathAI/SOCKS5-Proxy-Handler

(Note: I'm not the author of that SOCKS5 client interface I linked above)

Share:
11,914
Admin
Author by

Admin

Updated on June 14, 2022

Comments

  • Admin
    Admin about 2 years

    I am playing with SOCKS5 proxy ( TOR ). I am able to estabilish connection but now I dont know how to send and receive data to/from destination. Thanks for help. Code:

    #include <stdio.h>
    #include <WinSock2.h>
    #include <stdlib.h>
    #pragma comment(lib,"ws2_32.lib")
    #define PUT_BYTE(ptr,data) (*(unsigned char*)ptr = data)
    
    int main()
    {
        WORD wVersionRequested = MAKEWORD(2,0);
        WSADATA wsaData;
        if(WSAStartup(wVersionRequested,&wsaData) != 0 )
        {
            return 1;
        }
        int fd = socket( AF_INET, SOCK_STREAM, 0);
        if (fd < 0)
            return 1;
        struct sockaddr_in destaddr;
        destaddr.sin_addr.s_addr = inet_addr("xx.xx.xx.xx");
        int dest_port = 80;
    
        struct sockaddr_in saddr;
        saddr.sin_port = htons(9150);
        saddr.sin_family = AF_INET;
        saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
        int rv = connect( fd, (struct sockaddr *)&saddr, sizeof(saddr));
        if(rv < SOCKET_ERROR)
            return 1;
        char buf[256], *ptr;
        ptr = buf;
        PUT_BYTE( ptr++,5);
        PUT_BYTE( ptr++,1);
        PUT_BYTE(ptr++,0x00);
        send(fd,buf,ptr-buf,0);
        recv(fd,buf,2,0);
        if ( (buf[0] != 5) || buf[1] == 0xFF )
        {
            return 1;
        }
        ptr = buf;
        PUT_BYTE(ptr++,5);
        PUT_BYTE(ptr++,1);
        PUT_BYTE(ptr++,0);
        PUT_BYTE(ptr++,1);
        memcpy( ptr, &destaddr.sin_addr.s_addr,sizeof(destaddr.sin_addr));
        ptr += sizeof(destaddr.sin_addr);
        PUT_BYTE(ptr++,dest_port>>8);
        PUT_BYTE(ptr++,dest_port&0xFF);
        send(fd,buf,ptr-buf,0);
        recv(fd,buf,4,0);
        if(buf[1] != 0x00)
        {
            return 1;
        }
        ptr = buf + 4;
        switch ( buf[3] ) {                         
        case 1:                                     
            recv( fd, ptr, 4+2,0 );              
            break;
        case 3:                                     
            recv( fd, ptr, 1 ,0);                 
            recv( fd, ptr+1, *(unsigned char*)ptr + 2,0);
            break;
        case 4:                                    
            recv( fd, ptr, 16+2,0 );              
            break;
        }
    
        printf("Succes!");
        //How to send and receive data now? Now we are connected on port 80 and for example I want to send http get request and receive the answer.
    
        return 0;
    
    
    }
    

    How to send and receive data now? Now we are connected on port 80 and for example I want to send http get request and receive the answer.

  • Navin
    Navin over 10 years
    Seriously? You want him to call curl from a C++ program?
  • zkilnbqi
    zkilnbqi about 10 years
    Curl has libraries for many programming languages, including C++. It is silly to try and use send/recv when curl does all this for you. No need to re-invent the wheel.
  • zkilnbqi
    zkilnbqi about 10 years
    I would dispute the claim that this is simpler than using curl below.
  • Remy Lebeau
    Remy Lebeau about 10 years
    Look at the timestamps. My answer was posted over a month before the curl answer was posted.
  • Navin
    Navin about 10 years
    I thought you are referring to the "curl" tool. Anyway, just because you can't compile a SOCKS client does not mean the rest of us can't. In fact, it works just fine. Curl is good for scripts, not programs.
  • Admin
    Admin over 4 years
    I still can't believe, even 5 years later, that someone would say "curl library is good for scripts, not programs". Internet itself is only good for scripts so it's fine I guess, considering it's a bit too slow for C++.