Skip to content

Instantly share code, notes, and snippets.

@vstumpf
Created April 8, 2023 19:34
Show Gist options
  • Save vstumpf/4a60eab4592c8cd0bed32421d878ab74 to your computer and use it in GitHub Desktop.
Save vstumpf/4a60eab4592c8cd0bed32421d878ab74 to your computer and use it in GitHub Desktop.
New files for Trog Proxy
#include "proxy.hpp"
#include <algorithm>
#include <vector>
#include <stdio.h>
#ifdef WIN32
#include "winapi.hpp"
#include <winsock2.h>
#include <iphlpapi.h>
#pragma comment(lib, "IPHLPAPI.lib")
#else
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <unistd.h>
#include <linux/if_link.h>
#endif
#include "core.hpp"
#include "malloc.hpp"
#include "utils.hpp"
#include "socket.hpp"
#include "showmsg.hpp"
ProxyDatabase proxy_db;
bool ProxyDatabase::asIP(const c4::yml::NodeRef &node, const std::string &name, uint32 &out) {
std::string ips;
bool ret = this->asString(node, name, ips);
if (!ret)
return ret;
out = host2ip(ips.c_str());
return true;
}
bool ProxyDatabase::asServerInfo(const ryml::NodeRef& node, const std::string &name, struct ServerInfo &out) {
if (!this->nodeExists(node, name)) {
ShowError("Missing %s node\n", name.c_str());
return false;
}
auto proxyNode = node[c4::to_csubstr(name)];
if (!this->asIP(proxyNode, "PublicIP", out.public_ip))
return false;
if (!this->asUInt16(proxyNode, "Port", out.port))
return false;
if (this->nodeExists(proxyNode, "LocalIP") && !this->asIP(proxyNode, "LocalIP", out.local_ip))
return false;
return true;
}
/**
* Reads and parses an entry from the proxy_db.
* @param node: YAML node containing the entry.
* @return count of successfully parsed rows
*/
uint64 ProxyDatabase::parseBodyNode(const ryml::NodeRef& node) {
Proxy proxy = {};
if (this->nodeExists(node, "Name")) {
if (!this->asString(node, "Name", proxy.name))
return 0;
}
if (!this->asServerInfo(node, "ProxyServer", proxy.proxy))
return 0;
if (!this->asServerInfo(node, "TargetServer", proxy.target))
return 0;
if (!this->asString(node, "Secret", proxy.secret))
return 0;
if (proxy.secret.length() >= PROXY_SECRET_LEN) {
ShowError("Secret %s must be less than %d characters", proxy.secret.c_str(), PROXY_SECRET_LEN - 1);
return 0;
}
proxyServers.push_back(proxy);
return 1;
}
const Proxy* ProxyDatabase::searchProxyIp(uint32 ip) {
auto result = std::find_if(listenServers.cbegin(), listenServers.cend(), [&](const Proxy &proxy){
return proxy.proxy.public_ip == ip;
});
if (result == listenServers.end())
return nullptr;
return &*result;
}
const Proxy* ProxyDatabase::searchTargetIPPortProxyIp(uint32 target_ip, uint16 target_port, uint32 proxy_ip) {
ShowInfo("Searching for target_ip %s\n", ip2str(target_ip, nullptr));
ShowInfo("Searching for target_port %hu\n", target_port);
ShowInfo("Searching for proxy_ip %s\n", ip2str(proxy_ip, nullptr));
auto result = std::find_if(proxyServers.cbegin(), proxyServers.cend(), [&](const Proxy &proxy){
return (proxy.target.public_ip == target_ip || proxy.target.local_ip == target_ip)
&& proxy.target.port == target_port
&& proxy.proxy.public_ip == proxy_ip;
});
if (result == proxyServers.end())
return nullptr;
return &*result;
}
// if ip == 0, use getifaddr
void ProxyDatabase::filterTargetIPPort(uint32 ip, uint16 port) {
ShowInfo("Matching ip %s and port %lu\n", ip2str(ip, nullptr), port);
ShowInfo("List of loaded proxy servers:\n");
for (const auto &proxy : proxyServers) {
ShowInfo("%s : %s:%d\n", proxy.name.c_str(), ip2str(proxy.proxy.public_ip, nullptr), proxy.proxy.port);
}
if (ip) {
std::copy_if(proxyServers.begin(), proxyServers.end(), std::back_inserter(listenServers), [&](Proxy &proxy) {
return (proxy.target.public_ip == ip || proxy.target.local_ip == ip) && proxy.target.port == port;
});
ShowInfo("List of available proxy servers:\n");
for (const auto &proxy : listenServers) {
ShowInfo("%s : %s:%d\n", proxy.name.c_str(), ip2str(proxy.proxy.public_ip, nullptr), proxy.proxy.port);
}
return;
}
#ifdef WIN32
ULONG outBufLen = 15000;
PIP_ADAPTER_ADDRESSES pAddresses = nullptr;
int counter = 0;
ULONG ret = 0;
do {
pAddresses = (IP_ADAPTER_ADDRESSES*)aMalloc(outBufLen);
ret = GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &outBufLen);
if (ret == ERROR_BUFFER_OVERFLOW) {
aFree(pAddresses);
pAddresses = nullptr;
}
else {
break;
}
counter++;
} while (ret == ERROR_BUFFER_OVERFLOW && counter < 3);
if (ret == ERROR_BUFFER_OVERFLOW) {
ShowError("Failed to get adapter addresses (%d), no proxies will be loaded\n", ret);
}
std::copy_if(proxyServers.begin(), proxyServers.end(), std::back_inserter(listenServers), [&](Proxy& proxy) {
auto curr = pAddresses;
while (curr) {
for (auto uni = curr->FirstUnicastAddress; uni != nullptr; uni = uni->Next) {
auto* sa = reinterpret_cast<struct sockaddr_in*>(uni->Address.lpSockaddr);
if (ntohl(sa->sin_addr.s_addr) == proxy.target.public_ip)
return true;
if (ntohl(sa->sin_addr.s_addr) == proxy.target.local_ip)
return true;
}
curr = curr->Next;
}
return false;
});
aFree(pAddresses);
#else
struct ifaddrs *ifaddr = nullptr;
if (getifaddrs(&ifaddr) == -1) {
perror("getifaddrs");
exit(EXIT_FAILURE);
}
std::copy_if(proxyServers.begin(), proxyServers.end(), std::back_inserter(listenServers), [&](Proxy &proxy) {
if (proxy.target.port != port) {
return false;
}
auto *ifa = ifaddr;
for (; ifa != nullptr; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == nullptr)
continue;
if (ifa->ifa_addr->sa_family != AF_INET)
continue;
auto * sa = reinterpret_cast<struct sockaddr_in *>(ifa->ifa_addr);
if (ntohl(sa->sin_addr.s_addr) == proxy.target.public_ip)
return true;
if (ntohl(sa->sin_addr.s_addr) == proxy.target.local_ip)
return true;
}
return false;
});
freeifaddrs(ifaddr);
#endif
ShowInfo("List of available proxy servers:\n");
for (const auto &proxy : listenServers) {
ShowInfo("%s : %s:%d\n", proxy.name.c_str(), ip2str(proxy.proxy.public_ip, nullptr), proxy.proxy.port);
}
}
int clif_parse_proxy(int fd) {
const size_t packet_len = 2 + 4 + PROXY_SECRET_LEN;
if (RFIFOREST(fd) < packet_len)
return 0;
if (session[fd]->flag.parsed) {
ShowInfo("Connection refused from '" CL_WHITE "%s" CL_RESET "'. \n", ip2str(session[fd]->client_addr, nullptr));
ShowInfo("\tClient already sent info!\n");
RFIFOSKIP(fd, packet_len);
do_close(fd);
return 0;
}
auto proxy = proxy_db.searchProxyIp(session[fd]->client_addr);
if (!proxy) {
ShowInfo("Connection refused from '" CL_WHITE "%s" CL_RESET "'. \n", ip2str(session[fd]->client_addr, nullptr));
ShowInfo("\tReceived proxy packet from an unknown proxy!\n");
RFIFOSKIP(fd, packet_len);
do_close(fd);
return 0;
}
if (strncmp(RFIFOCP(fd, 6), proxy->secret.c_str(), PROXY_SECRET_LEN)) {
ShowInfo("Connection refused from '" CL_WHITE "%s" CL_RESET "'. \n", ip2str(session[fd]->client_addr, nullptr));
ShowInfo("\tProxy packet has incorrect secret! %s != %s\n", RFIFOCP(fd, 6), proxy->secret.c_str());
RFIFOSKIP(fd, packet_len);
do_close(fd);
return 0;
}
uint32 ip = RFIFOL(fd, 2);
session[fd]->proxy_addr = session[fd]->client_addr;
session[fd]->client_addr = ip;
RFIFOSKIP(fd, packet_len);
ShowInfo("Proxy connection detected from '" CL_WHITE "%s" CL_RESET "'!\n", ip2str(session[fd]->client_addr, nullptr));
ShowInfo("\tProxy ip is '" CL_WHITE "%s" CL_RESET "'.\n", ip2str(session[fd]->proxy_addr, nullptr));
return 1;
}
#ifndef COMMON_PROXY_HPP
#define COMMON_PROXY_HPP
#include <vector>
#include <string>
#include <unordered_map>
#include "cbasetypes.hpp"
#include "database.hpp"
#define PROXY_SECRET_LEN 30
struct ServerInfo {
uint32 public_ip;
uint16 port;
uint32 local_ip{0};
};
struct Proxy {
struct ServerInfo proxy;
struct ServerInfo target;
std::string name;
std::string secret;
};
class ProxyDatabase : public YamlDatabase {
private:
std::vector<struct Proxy> proxyServers;
std::vector<struct Proxy> listenServers; // used for login/char/map
std::string filename;
public:
ProxyDatabase() : YamlDatabase("PROXY_DB", 1, 1), filename(std::string(db_path) + "/proxy_servers.yml") {
}
class iterator : public std::vector<struct Proxy>::iterator {};
const std::string getDefaultLocation() override {
return filename;
};
void setDefaultLocation(const std::string& s) {
filename = s;
}
uint64 parseBodyNode(const ryml::NodeRef& node) override;
void loadingFinished() override {};
void clear() override{
proxyServers.clear();
}
// Additional
const Proxy* searchTargetIPPortProxyIp(uint32 target_ip, uint16 target_port, uint32 proxy_ip);
const Proxy* searchProxyIp(uint32 ip);
void filterTargetIPPort(uint32 ip, uint16 port);
const std::vector<struct Proxy>::iterator begin() {
return proxyServers.begin();
}
const std::vector<struct Proxy>::iterator end() {
return proxyServers.end();
}
bool asIP(const c4::yml::NodeRef &node, const std::string &name, uint32 &out);
bool asServerInfo(const ryml::NodeRef& node, const std::string &name, struct ServerInfo &out);
};
extern ProxyDatabase proxy_db;
int clif_parse_proxy(int fd);
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment