Tor as a SOCKS5 proxy in your C++ applications with socks5-cppsteemCreated with Sketch.

in #tor7 years ago (edited)

So you just decided that your applications need a way to reach an endpoint under relative anonymity yet with simplicity in mind. That might be a good choice! Far too much of our traffic goes through bulk surveillance networks placed by three-letter agencies and other profiteers looking to capitalize off or monitor your precious data. So let's route our data through Tor, and make it a bit harder for the d-bags to know who or where we are.

That being said, Tor is not the one answer to all of your problems. Tor by no means guarantees your anonymity or security during every situation, and precautions should be taken when designing your application if you do not wish for it to be easily identified or manipulated. It remains up to you to make sure that your application is designed with safety in mind. Also remember that when handing your trust to the Tor network, your traffic is only encrypted all the way to the Tor exit node. People can instead log (and manipulate, if you're the node operator) all your traffic from there. They'll just have a harder time pinpointing where it's coming from. Use encryption as needed.

The code provided in this article uses the socks5-cpp library.

Full main code snippet at the bottom of the page.

1. What we need

Obviously we will need Tor. Go to their website and download the Expert bundle, and extract it to a folder named "Tor" on your desktop for now.

We will code this for Windows, and we're going to use the socks5-cpp library. The code should be easy enough to port to most platforms though.

Let's start with including the stuff we need in our main

#include "socks.h"

#include <iostream>

using namespace std;

The library includes everything we need to start using Winsock and Tor as a proxy. Obviously, we have to have an instance of Tor running and listening on whatever port (usually 9050) on the local computer. Let's start by initializing Winsock and the SocksClient class provided by socks5-cpp in the socks header.

int main()
{
    WSADATA wsadata;
    WSAStartup((WORD)0x202, &wsadata);

    socks5cpp::SocksClient sockCli("127.0.0.1:9050", "google.com:80");

    WSACleanup();
    return 0;
}

That would be what we need for now. The SocksClient constructor takes two arguments.

First the SOCKS5 proxy IP or domain name, which in our case is 127.0.0.1 (localhost) and port, 9050 in this case, where tor is waiting for our program.

The second argument is the IP or domain name of whom we want to connect to.

2. Creating our socket and connecting to the host

The library will be connecting the socket for us based off the info we gave it upon construction. Just add these few lines to the program before the call to WSACleanup and return

    SOCKET sock = 0;
    if (sockCli.connect(sock) < 0 ||
        !sock) {
        cout << "fault at connect:" << WSAGetLastError() << endl;
        WSACleanup();
        cin.ignore();
        return -1;
    }

    if (sockCli.getState() == sockCli.Closed) {
        cout << "fault at connect:" << WSAGetLastError() << ". Connection closed." << endl;
        WSACleanup();
        cin.ignore();
        return -1;
    }

Now if our program hasn't returned at this point our connection to the host via Tor should be established.

At this point I modified the library slightly to make it easier in our specific use case, since we're connecting to a domain name. Replace lines 143-147 in the file socks.cpp with:

    buffer.push_back(0x03); // IPv4 = 0x01, domain name = 0x03, IPv6 = 0x04
    //buffer.push_back(targetUrl.ipv4[0]); // connecting to IPv4 
    //buffer.push_back(targetUrl.ipv4[1]);
    //buffer.push_back(targetUrl.ipv4[2]);
    //buffer.push_back(targetUrl.ipv4[3]);
    buffer.push_back(targetUrl.ip.length()); // connecting to domain name
    for(int i = 0; i < targetUrl.ip.length(); ++i)
        buffer.push_back(targetUrl.ip.c_str()[i]);

3. Let's communicate!!

At this point we should be able to write the host some messages, let's go ahead and make a HTTP request for google.com whom we earlier configured our SocketClient object for staying connected to. Append to main before cleanup:

    char buf[4096] = { 0 };
    int iRes = -1;

    string getReq =
        "GET / HTTP/1.1\r\n"
        "Host: google.com\r\n"
        "\r\n";

    iRes = sockCli.sendPacket(sock, getReq.c_str(), getReq.length());
    if (iRes != getReq.length()) {
        WSACleanup();
        cout << "fault at send" << endl;
        cin.ignore();
        return -1;
    }

    do {
        iRes = sockCli.recvPacket(sock, buf, 4095);
    } while (WSAGetLastError() == 10035);

    if (iRes < 0) {
        cout << "fault at recv: " << WSAGetLastError() << endl;
        WSACleanup();
        cin.ignore();
        return -1;
    }


    cout << buf << endl;

This code may be dangerous and should only be used if you understand the risks associated with the Tor protocol.

4. Testing our code

By now our code should be executable and enough behavior should be defined for us to try it out. In case you missed something I've posted the full main.cpp at the bottom of the page. Let's fire up Tor on port 9050 and run our program!

In case you need help with that too, if you extracted the package in the folder "Tor" on your desktop, open up a command prompt, navigate to that folder using the cd command. Then simply type tor.exe, press enter and leave the window open. You should see something like [notice] Opening Socks listener on 127.0.0.1:9050 followed by Bootstrapped 100%: Done after a few seconds.

Nice! Now, when we request the resource '/' from google.com on port 80, they respond that the document has moved. To a french address. I'm not french :>.

Let's check our actual IP address out. You should be able to discern how to modify the HTTP request to ask for your IP address from api you choose. In this example I'll use canihazip.com/s which sends us an answer containing only our perceived IP address upon our request. Here's the new request:

    string getReq =
        "GET /s HTTP/1.1\r\n"
        "Host: canihazip.com\r\n"
        "\r\n";

And let's set our initialization of the SocksClient object to canihazip.com as well.

    SocksClient sockCli("127.0.0.1:9050", "canihazip.com:80");

Let's run and see what's up.

HTTP/1.1 200 OK
Date: Thu, 29 Jun 2017 17:15:20 GMT
Server: Apache
X-Powered-By: PHP/5.5.9-1ubuntu4.14
Access-Control-Allow-Origin: *
X-Content-Type-Options: nosniff
X-Frame-Options: sameorigin
Content-Length: 12
Content-Type: text/plain

51.15.63.229

That is not my IP address, that's a Tor exit node IP address =)
Success! Torifying an application was really super easy with the help of the socks5-cpp library.
Just remember that the exit node operators can both view and manipulate all traffic, so you'll have to take some further steps to stay anonymous and keep your data private.

Feel free to review the code of the library we used. It's short, concise and easily understandable.

This is my first blog post and I'd love to hear about what you guys think that I can do better.

Full main.cpp code

#include "socks.h"

#include <iostream>

using namespace std;

int main()
{
    WSADATA wsadata;
    WSAStartup((WORD)0x202, &wsadata);

    socks5cpp::SocksClient sockCli("127.0.0.1:9050", "canihazip.com:80");
    SOCKET sock = 0;
    if (sockCli.connect(sock) < 0 ||
        !sock) {
        cout << "fault at connect:" << WSAGetLastError() << endl;
        WSACleanup();
        cin.ignore();
        return -1;
    }

    if(sockCli.getState() == sockCli.Closed){
        cout << "fault at connect:" << WSAGetLastError() << endl;
        WSACleanup();
        cin.ignore();
        return -1;
    }


    char buf[4096] = { 0 };
    int iRes = -1;
    
    string getReq =
        "GET /s HTTP/1.1\r\n"
        "Host: canihazip.com\r\n"
        "\r\n";

    iRes = sockCli.sendPacket(sock, getReq.c_str(), getReq.length());
    if (iRes != getReq.length()) {
        WSACleanup();
        cout << "fault at send" << endl;
        cin.ignore();
        return -1;
    }

    do {
        iRes = sockCli.recvPacket(sock, buf, 4095);
    } while (WSAGetLastError() == 10035);

    if (iRes < 0) {
        cout << "fault at recv: " << WSAGetLastError() << endl;
        WSACleanup();
        cin.ignore();
        return -1;
    }


    cout << buf << endl;


    WSACleanup();

    cin.ignore();
    return 0;
}

Sort:  

Interesting thoughts

Congratulations @scriptkid! You have received a personal award!

1 Year on Steemit
Click on the badge to view your Board of Honor.

Do not miss the last post from @steemitboard!


Participate in the SteemitBoard World Cup Contest!
Collect World Cup badges and win free SBD
Support the Gold Sponsors of the contest: @good-karma and @lukestokes


Do you like SteemitBoard's project? Then Vote for its witness and get one more award!

Congratulations @scriptkid! You received a personal award!

Happy Birthday! - You are on the Steem blockchain for 2 years!

You can view your badges on your Steem Board and compare to others on the Steem Ranking

Do not miss the last post from @steemitboard:

SteemitBoard - Witness Update
Do not miss the coming Rocky Mountain Steem Meetup and get a new community badge!
Vote for @Steemitboard as a witness to get one more award and increased upvotes!

Coin Marketplace

STEEM 0.26
TRX 0.11
JST 0.033
BTC 64498.18
ETH 3079.08
USDT 1.00
SBD 3.86