Created
April 8, 2023 19:34
-
-
Save vstumpf/4a60eab4592c8cd0bed32421d878ab74 to your computer and use it in GitHub Desktop.
New files for Trog Proxy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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