feat: add basic (unfinished) proxy

This commit is contained in:
2026-03-20 05:03:11 -03:00
parent a65dfaf33b
commit 4a7957c1b6
2 changed files with 180 additions and 0 deletions
+155
View File
@@ -0,0 +1,155 @@
#include "proxy.h"
#include <winsock2.h>
#include <ws2tcpip.h>
#include <nerutils/log.h>
Proxy::Proxy() {}
Proxy::~Proxy() {}
bool Proxy::Init()
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
Log::error("WSAStartup failed");
return false;
}
_listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (_listenSocket == INVALID_SOCKET)
{
Log::error("Error creating listen socket: {0:x}", WSAGetLastError());
Shutdown();
return false;
}
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(PROXY_PORT);
inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr);
if (bind(_listenSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
{
Log::error("Error binding listen socket: {0:x}", WSAGetLastError());
Shutdown();
return false;
}
listen(_listenSocket, SOMAXCONN);
Log::verbose("Listening on 127.0.0.1:{}", PROXY_PORT);
_running = true;
_workerThread = std::thread(&Proxy::loop, this);
return true;
}
void Proxy::Shutdown()
{
_running = false;
if (_listenSocket != INVALID_SOCKET && _listenSocket != 0)
{
closesocket(_listenSocket);
_listenSocket = 0;
}
if (_workerThread.joinable()) _workerThread.join();
WSACleanup();
}
void Proxy::loop()
{
while (_running)
{
SOCKET clientSocket = accept(_listenSocket, NULL, NULL);
if (!_running)
{
if (clientSocket != INVALID_SOCKET) closesocket(clientSocket);
break;
}
if (clientSocket == INVALID_SOCKET) continue;
std::thread([this, clientSocket]() { this->handleClient(clientSocket); }).detach();
}
}
void Proxy::handleClient(SOCKET clientSocket)
{
char buffer[8192];
int bytesReceived = recv(clientSocket, buffer, sizeof(buffer) - 1, 0);
if (bytesReceived <= 0)
{
closesocket(clientSocket);
return;
}
std::string request(buffer, bytesReceived);
/*
get host
*/
std::string host;
size_t hostPos = request.find("Host: ");
if (hostPos != std::string::npos)
{
size_t endPos = request.find("\r\n", hostPos);
host = request.substr(hostPos + 6, endPos - (hostPos + 6));
}
if (host.empty())
{
closesocket(clientSocket);
return;
}
/*
handle remote
*/
struct addrinfo hints = {}, *res;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo(host.c_str(), "80", &hints, &res) != 0)
{
Log::error("Could not resolve host: {}", host);
closesocket(clientSocket);
return;
}
SOCKET remoteSocket = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (connect(remoteSocket, res->ai_addr, (int)res->ai_addrlen) == SOCKET_ERROR)
{
Log::error("Connection to {} failed", host);
freeaddrinfo(res);
closesocket(clientSocket);
return;
}
freeaddrinfo(res);
/*
fwd
*/
send(remoteSocket, buffer, bytesReceived, 0);
/*
recv
*/
int remoteBytes;
while ((remoteBytes = recv(remoteSocket, buffer, sizeof(buffer), 0)) > 0)
{
// Log::verbose("Forwarding {} bytes from server back to client", remoteBytes);
send(clientSocket, buffer, remoteBytes, 0);
}
closesocket(remoteSocket);
closesocket(clientSocket);
}