From 9f2cd561286784fd000eb8a00f1f80db3185062c Mon Sep 17 00:00:00 2001 From: frosty Date: Fri, 27 Feb 2026 18:32:23 -0500 Subject: added proxying --- src/Proxy/Proxy.c | 257 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/Proxy/Proxy.h | 31 +++++++ 2 files changed, 288 insertions(+) create mode 100644 src/Proxy/Proxy.c create mode 100644 src/Proxy/Proxy.h (limited to 'src/Proxy') diff --git a/src/Proxy/Proxy.c b/src/Proxy/Proxy.c new file mode 100644 index 0000000..939aea0 --- /dev/null +++ b/src/Proxy/Proxy.c @@ -0,0 +1,257 @@ +#include "Proxy.h" +#include +#include +#include +#include +#include + +Proxy *proxy_list = NULL; +int proxy_count = 0; +int max_proxy_retries = 3; +int randomize_username = 0; +int randomize_password = 0; +char proxy_url[512] = {0}; +static pthread_mutex_t proxy_mutex = PTHREAD_MUTEX_INITIALIZER; + +static const char RAND_CHARS[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + +static void generate_random_string(char *buf, size_t len) { + for (size_t i = 0; i < len - 1; i++) { + buf[i] = RAND_CHARS[rand() % (sizeof(RAND_CHARS) - 1)]; + } + buf[len - 1] = '\0'; +} + +void set_proxy_config(const char *proxy_str, int rand_user, int rand_pass) { + if (proxy_str && proxy_str[0]) { + strncpy(proxy_url, proxy_str, sizeof(proxy_url) - 1); + proxy_url[sizeof(proxy_url) - 1] = '\0'; + } + randomize_username = rand_user; + randomize_password = rand_pass; +} + +static Proxy parse_proxy_line(const char *line) { + Proxy proxy = {.type = PROXY_SOCKS5, .port = 0, .username[0] = '\0', .password[0] = '\0', .failures = 0}; + const char *host_start = NULL; + const char *port_start = NULL; + + size_t len = strlen(line); + if (len == 0) return proxy; + + if (strncmp(line, "http://", 7) == 0) { + proxy.type = PROXY_HTTP; + host_start = line + 7; + } else if (strncmp(line, "socks5://", 9) == 0) { + proxy.type = PROXY_SOCKS5; + host_start = line + 9; + } else if (strncmp(line, "socks4://", 9) == 0) { + proxy.type = PROXY_SOCKS4; + host_start = line + 9; + } else { + host_start = line; + } + + const char *at = strchr(host_start, '@'); + if (at) { + char cred_buf[128]; + size_t cred_len = at - host_start; + if (cred_len >= sizeof(cred_buf)) cred_len = sizeof(cred_buf) - 1; + strncpy(cred_buf, host_start, cred_len); + cred_buf[cred_len] = '\0'; + + char *colon = strchr(cred_buf, ':'); + if (colon) { + size_t user_len = colon - cred_buf; + if (user_len >= sizeof(proxy.username)) user_len = sizeof(proxy.username) - 1; + strncpy(proxy.username, cred_buf, user_len); + proxy.username[user_len] = '\0'; + strncpy(proxy.password, colon + 1, sizeof(proxy.password) - 1); + proxy.password[sizeof(proxy.password) - 1] = '\0'; + } + host_start = at + 1; + } + + port_start = strchr(host_start, ':'); + if (port_start) { + char host_buf[256]; + size_t host_len = port_start - host_start; + if (host_len >= sizeof(host_buf)) host_len = sizeof(host_buf) - 1; + strncpy(host_buf, host_start, host_len); + host_buf[host_len] = '\0'; + snprintf(proxy.host, sizeof(proxy.host), "%.*s", (int)host_len, host_buf); + proxy.port = atoi(port_start + 1); + } else { + snprintf(proxy.host, sizeof(proxy.host), "%s", host_start); + } + + return proxy; +} + +int load_proxy_list(const char *filename) { + if (!filename || filename[0] == '\0') { + return 0; + } + + pthread_mutex_lock(&proxy_mutex); + + if (proxy_list) { + free(proxy_list); + proxy_list = NULL; + } + proxy_count = 0; + + FILE *file = fopen(filename, "r"); + if (!file) { + pthread_mutex_unlock(&proxy_mutex); + fprintf(stderr, "[WARN] Could not open proxy list file: %s\n", filename); + return -1; + } + + int capacity = 16; + proxy_list = (Proxy *)malloc(capacity * sizeof(Proxy)); + if (!proxy_list) { + fclose(file); + return -1; + } + proxy_count = 0; + + char line[512]; + while (fgets(line, sizeof(line), file)) { + line[strcspn(line, "\r\n")] = 0; + + if (line[0] == '\0' || line[0] == '#') { + continue; + } + + char *p = line; + while (*p == ' ' || *p == '\t') p++; + + char *end = p + strlen(p) - 1; + while (end > p && (*end == ' ' || *end == '\t')) { + *end = '\0'; + end--; + } + + if (p[0] == '\0') continue; + + Proxy proxy = parse_proxy_line(p); + if (proxy.port == 0) { + continue; + } + + if (proxy_count >= capacity) { + capacity *= 2; + Proxy *new_list = (Proxy *)realloc(proxy_list, capacity * sizeof(Proxy)); + if (!new_list) { + free(proxy_list); + proxy_list = NULL; + proxy_count = 0; + fclose(file); + pthread_mutex_unlock(&proxy_mutex); + return -1; + } + proxy_list = new_list; + } + + proxy_list[proxy_count++] = proxy; + } + + fclose(file); + fprintf(stderr, "[INFO] Loaded %d proxies from %s\n", proxy_count, filename); + pthread_mutex_unlock(&proxy_mutex); + return proxy_count; +} + +void free_proxy_list(void) { + pthread_mutex_lock(&proxy_mutex); + if (proxy_list) { + free(proxy_list); + proxy_list = NULL; + } + proxy_count = 0; + pthread_mutex_unlock(&proxy_mutex); +} + +Proxy *get_random_proxy(void) { + pthread_mutex_lock(&proxy_mutex); + if (proxy_count == 0) { + pthread_mutex_unlock(&proxy_mutex); + return NULL; + } + + int start = rand() % proxy_count; + int checked = 0; + Proxy *selected = NULL; + + while (checked < proxy_count) { + int idx = (start + checked) % proxy_count; + if (proxy_list[idx].failures < max_proxy_retries) { + selected = &proxy_list[idx]; + break; + } + checked++; + } + + if (!selected) { + for (int i = 0; i < proxy_count; i++) { + proxy_list[i].failures = 0; + } + selected = &proxy_list[rand() % proxy_count]; + } + + pthread_mutex_unlock(&proxy_mutex); + return selected; +} + +void record_proxy_failure(Proxy *proxy) { + if (!proxy) return; + pthread_mutex_lock(&proxy_mutex); + proxy->failures++; + pthread_mutex_unlock(&proxy_mutex); +} + +void apply_proxy_settings(CURL *curl) { + if (proxy_url[0] != '\0') { + curl_easy_setopt(curl, CURLOPT_PROXY, proxy_url); + if (strncmp(proxy_url, "socks5://", 9) == 0) { + curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5); + } else if (strncmp(proxy_url, "socks4://", 9) == 0) { + curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4A); + } else { + curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP); + } + + if (randomize_username || randomize_password) { + char userpwd[256]; + char username[32] = {0}; + char password[32] = {0}; + + if (randomize_username) generate_random_string(username, sizeof(username)); + if (randomize_password) generate_random_string(password, sizeof(password)); + + snprintf(userpwd, sizeof(userpwd), "%s:%s", username, password); + curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, userpwd); + } + } else if (proxy_count > 0) { + Proxy *proxy = get_random_proxy(); + if (proxy) { + char proxy_url_buf[512]; + snprintf(proxy_url_buf, sizeof(proxy_url_buf), "%s:%d", proxy->host, proxy->port); + curl_easy_setopt(curl, CURLOPT_PROXY, proxy_url_buf); + if (proxy->type == PROXY_HTTP) { + curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP); + } else if (proxy->type == PROXY_SOCKS4) { + curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4A); + } else { + curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5); + } + + if (proxy->username[0] != '\0' || proxy->password[0] != '\0') { + char userpwd[128]; + snprintf(userpwd, sizeof(userpwd), "%s:%s", proxy->username, proxy->password); + curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, userpwd); + } + } + } +} diff --git a/src/Proxy/Proxy.h b/src/Proxy/Proxy.h new file mode 100644 index 0000000..d9a438d --- /dev/null +++ b/src/Proxy/Proxy.h @@ -0,0 +1,31 @@ +#ifndef PROXY_H +#define PROXY_H + +#include + +typedef enum { PROXY_HTTP, PROXY_SOCKS4, PROXY_SOCKS5 } ProxyType; + +typedef struct { + ProxyType type; + char host[256]; + int port; + char username[64]; + char password[64]; + int failures; +} Proxy; + +extern Proxy *proxy_list; +extern int proxy_count; +extern int max_proxy_retries; +extern int randomize_username; +extern int randomize_password; +extern char proxy_url[512]; + +int load_proxy_list(const char *filename); +void free_proxy_list(void); +Proxy *get_random_proxy(void); +void record_proxy_failure(Proxy *proxy); +void apply_proxy_settings(CURL *curl); +void set_proxy_config(const char *proxy_str, int rand_user, int rand_pass); + +#endif -- cgit v1.2.3