olaf trolldalen
olaf trolldalen

Reputation: 71

Send and receive via SOCKS5 c++

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.

Upvotes: 7

Views: 15154

Answers (3)

Harsath
Harsath

Reputation: 173

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).

Upvotes: 1

zkilnbqi
zkilnbqi

Reputation: 1204

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.

Upvotes: 0

Remy Lebeau
Remy Lebeau

Reputation: 597971

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;
}

Upvotes: 11

Related Questions