7

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.

olaf trolldalen
  • 71
  • 1
  • 1
  • 2

3 Answers3

10

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;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
1

I wrote a modern C++ implementation for sending and receiving data through a SOCKS5 proxy server, with 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/harsath/SOCKS5-Proxy-Handler

(Disclaimer: I am the author of the linked repository).

Harsath
  • 133
  • 3
  • 6
0

Olof, the routines you are using are notoriously difficult. If your goal is to actually get something working, I would recommend that you use a tool that has been built on top of these low-level routines.

The best one is curl. At the curl website, they compare themselves with the other tools you could consider: http://curl.haxx.se/docs/comparison-table.html

Edit: all right, so you voted down my answer. Go and look at the source code for torsocks, which tries to use these routines. Compile it and try to run it. Does it work? No. Look at the source code. Try to run the test suite. Does it work? No. Look at the routines they call. Many are deprecated. Can you even figure out which routines are deprecated?

If you look around, you will see that the people who are able to actually transfer data over Tor are using curl.

zkilnbqi
  • 1,141
  • 11
  • 23
  • Seriously? You want him to call `curl` from a C++ program? – Navin Mar 12 '14 at 04:19
  • 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 May 01 '14 at 08:35
  • 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. – Navin May 01 '14 at 19:25
  • 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++. –  Dec 03 '19 at 20:59