How to Proxychain properly with WinSocks?

Hello there,

ive been working on a school project to demonstrate the (onion routing like) process of Proxychaining with C++ and WinSocks from Scratch and i ran into knowledge gap on how to connect to the second Proxy over Proxy 1 by somewhat sending a command to Proxy 1 to connect to Proxy 2, because Proxy 2 shalt not know the original address but only Proxy 1's one.
So to see wheather this workes ive decided to connect to httpbin.org/ip with GET to get back the response to see which ip showed up on httpbin.
Hopefully something like that:

1
2
3
4
5
6
7
8
9
10
11
12
HTTP/1.1 200 OK
Date: Thu, 25 May 2023 07:57:31 GMT
Content-Type: application/json
Content-Length: 30
Connection: close
Server: gunicorn/19.9.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true

{
  "origin": "70.166.167.55"
}


I am using Socks-5 Proxies:
1
2
Proxy 1: 192.111.134.10:4145
Proxy 2: 70.166.167.55:57745

which i have found on https://spys.one/en/socks-proxy-list/

Now i reached the limit of my knowledge how to achieve that Proxy 2 and how to make sure its sending the response back to me over Proxy 1..

I would not have bothered you if I had gotten anywhere else or with ChatPGT, but even GPT is at its limit there and could not help me.

Source Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>

#pragma comment(lib, "ws2_32.lib")

int main()
{
    WSADATA wsaData;
    SOCKET ConnectSocket = INVALID_SOCKET;
    struct sockaddr_in server;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    {
        printf("Failed. Error Code: %d", WSAGetLastError());
        return 1;
    }

    // Create a socket.
    if ((ConnectSocket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
        printf("Could not create socket: %d", WSAGetLastError());
    }

    // Setup address and port of Proxy 1.
    server.sin_addr.s_addr = inet_addr("192.111.134.10");
    server.sin_family = AF_INET;
    server.sin_port = htons(4145);

    // Connect to Proxy 1.
    if (connect(ConnectSocket, (struct sockaddr *) &server, sizeof(server)) < 0) {
        puts("connect error");
        return 1;
    }
    puts("connection to proxy 1");

    // Send SOCKS5 initialization request (no authentication).
    char initRequest[3] = {0x05, 0x01, 0x00};
    if (send(ConnectSocket, initRequest, 3, 0) < 0) {
        puts("Send failed");
        return 1;
    }

    // Receive SOCKS5 initialization response.
    char initResponse[2];
    if (recv(ConnectSocket, initResponse, 2, 0) < 0) {
        puts("recv failed");
        return 1;
    }

    // Check SOCKS5 initialization response.
    if (initResponse[0] != 0x05 || initResponse[1] != 0x00) {
        puts("SOCKS5 initialization failed");
        return 1;
    }

    // Send SOCKS5 connection request (Proxy 1 to Proxy 2).
    char connectRequest1[10] = {0x05, 0x01, 0x00, 0x01};
    unsigned long proxy2_ip = inet_addr("70.166.167.55");
    unsigned short proxy2_port = htons(57745);
    memcpy(connectRequest1 + 4, &proxy2_ip, 4);
    memcpy(connectRequest1 + 8, &proxy2_port, 2);

    if (send(ConnectSocket, connectRequest1, 10, 0) < 0) {
        puts("Send failed");
        return 1;
    }

    // Receive SOCKS5 connection response (from Proxy 1).
    char connectResponse1[10];
    if (recv(ConnectSocket, connectResponse1, 10, 0) < 0) {
        puts("recv failed");
        return 1;
    }

    // Check SOCKS5 connection response (from Proxy 1).
    if (connectResponse1[0] != 0x05 || connectResponse1[1] != 0x00) {
        puts("SOCKS5 connection failed (Proxy 1)");
        return 1;
    }

    puts("successfully linked\n");

    // Now we are connected and can send the final HTTP request through the connection.

    // Send the HTTP request through the proxy.
    char message[100] = "GET /ip HTTP/1.1\r\nHost: 3.227.25.103\r\nConnection: close\r\n\r\n";
    if (send(ConnectSocket, message, strlen(message), 0) < 0) {
        puts("Send failed");
        return 1;
    }

    // Receive and print the response.
    char server_reply[2000];
    if (recv(ConnectSocket, server_reply, 2000, 0) < 0) {
        puts("recv failed");
    }

    puts(server_reply);

    closesocket(ConnectSocket);
    WSACleanup();

    return 0;
}

I have commented a bit to make the code more readable for you.

This code does not currently link the two proxies correctly (l.55) .

Do you have an idea how i can achieve that?

Thank you all in advance,

Luke
Last edited on
Now i reached the limit of my knowledge how to achieve that Proxy 2 and how to make sure its sending the response back to me over Proxy 1..

I think, in a chain of proxy servers, each proxy normally only "knows" about its direct predecessor. Therefore, proxy #2 doesn't know anything about you. It only knows that it go a request from proxy #1 – proxy #2 actually doesn't know that proxy #1 is a proxy; from the view of proxy #2, proxy #1 is just an arbitrary client – and therefore proxy #2 automatically/unavoidably sends its response back to proxy #1.

Consequently, you totally have to rely on proxy #1 to forward the response of proxy #2 back to you.

Note: There is an important difference between "Onion routing" and simple chaining of proxy servers: In Onion routing, the request (and response) use multiple layers of encryption, arranged carefully in such a way that each "node" (proxy) along the chain can only remove one layer of encryption. This makes sure that each "node" can only learn its direct predecessor and its direct successor, but neither the original source nor the final destination, because it can't further decrypt the packet it received (it can only forward it to the next node).

In a simple chaining of proxy servers, you don't have those multiple layers of encryption. So, even the first proxy in the chain – if it is malicious – could easily determine the final destination, by fully inspecting/unwrapping the request that it got from you...

(The actual contents may be protected by SSL/TLS, but that doesn't protect you from a malicious proxy learning the real destination!)
Last edited on
My connection will be end to end - encrypted. This is just to make it work and i dont care about encryption yet, whilst there is no sensitive data. But what is wrong with this code?
I cound not figure it out.
Last edited on
I'm not an expert on SOCKS5, but what exactly is your problem? Did you try to break it down step by step?

I mean: Does your code using WinSocks work, when you simply connect to the final HTTP-Server directly? That's the first thing you should verify! If so, does it still work, if you add just a single SOCKS5 proxy? If so, what changes if you try to add the second SOCKS5 proxy?

If any of the above doesn't work, what exactly is the "problem" that you are running into?

I suggest to implement/test/fix this step by step, not all at once 😏

BTW: End-to-end encryption doesn't help at all for "anonymity", because only the innermost stream would be encrypted – allowing any proxy along the way to figure out the full route and the final destination. They can't look into the actual payloads, as they are encrypted, but that's not the point! If you want "anonymity", as in Tor, what you need are multiple layers of encryption. That is the idea of "Onion routing".

BTW2: It may be helpful to use a tool like WireShark to see what is really going on, on the wire:
https://www.wireshark.org/
Last edited on
Registered users can post here. Sign in or register to post.