/* * ===================================================================================== * PROXY VPN DUAL (TCP + TLS) - ULTIMATE BARE-METAL EDITION V9 * Correcciones: * 1. Bugfix de OpenSSL Internal Buffer (SSL_pending) para NetMod. * 2. Anti-Flood calibrado para evitar auto-baneos por hilos múltiples de VPN. * Compilación: gcc -O3 -o proxy_dual proxy_dual.c -lssl -lcrypto -lpthread * ===================================================================================== */ #include #include #include #include #include #include #include #include #include #include #include #include // --- CONFIGURACIÓN BASE --- #define DEFAULT_PORT_TCP 80 #define DEFAULT_PORT_TLS 443 #define SSH_HOST "127.0.0.1" #define SSH_PORT 22 #define BUFLEN 16384 #define MAX_CONNECTIONS 500 #define LOG_FILE "/root/proxy-dual.log" #define CERT_FILE "/root/cert.pem" #define KEY_FILE "/root/key.pem" // --- CONFIGURACIÓN DE SEGURIDAD (ANTI-FLOOD & BAN) --- #define MAX_TRACKED_IPS 200 #define AUTO_BAN_STRIKES 15 // Aumentado a 15 para soportar los hilos de NetMod #define BAN_TIME 3600 // 1 Hora #define COOLDOWN_SEC 1 // Ventana de 1 segundo typedef struct { char ip[INET6_ADDRSTRLEN]; time_t last_connect; int strikes; time_t ban_until; } ip_record_t; ip_record_t ip_database[MAX_TRACKED_IPS]; pthread_mutex_t ip_db_mutex = PTHREAD_MUTEX_INITIALIZER; // --- RESPUESTAS FAKE WEB --- const char *FAKE_WEB_TCP = "HTTP/1.1 400 Bad Request\r\nServer: nginx/1.24.0\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n

400 Bad Request


nginx/1.24.0
\r\n"; const char *FAKE_WEB_TLS = "HTTP/1.1 400 OK\r\nServer: nginx/1.21.0\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n

400 Bad Request

\r\n"; // --- MENSAJES ROTATIVOS --- const char *MENSAJES[] = {"🚀 CONEXION ESTABLECIDA", "🛡️ CIFRADO MILITAR ACTIVO", "🔋 MODO SIGILO SSL OK", "Pfsense", "OPNsense", "VyOS", "Claro", "Google", "TNSR", "🌐 BYPASS OK"}; #define NUM_MENSAJES (sizeof(MENSAJES) / sizeof(MENSAJES[0])) int mensaje_idx = 0; pthread_mutex_t msg_mutex = PTHREAD_MUTEX_INITIALIZER; int active_connections = 0; pthread_mutex_t conn_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER; typedef struct { int client_fd; struct sockaddr_storage addr; int is_tls; SSL_CTX *ssl_ctx; } client_data_t; // --- FUNCIONES DE SOPORTE --- void write_log(const char *ip, const char *proto, const char *msg) { pthread_mutex_lock(&log_mutex); FILE *f = fopen(LOG_FILE, "a"); if (f) { time_t now = time(NULL); struct tm *t = localtime(&now); char ts[64]; strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S", t); fprintf(f, "[%s] [%s] [%s] %s\n", ts, proto, ip ? ip : "SISTEMA", msg); printf("[%s] [%s] [%s] %s\n", ts, proto, ip ? ip : "SISTEMA", msg); fclose(f); } pthread_mutex_unlock(&log_mutex); } // --- MOTOR DE SEGURIDAD --- int check_and_update_ip(const char *ip) { pthread_mutex_lock(&ip_db_mutex); time_t now = time(NULL); int empty_slot = -1; int found = 0; for (int i = 0; i < MAX_TRACKED_IPS; i++) { if (ip_database[i].ip[0] == '\0' && empty_slot == -1) empty_slot = i; else if (strcmp(ip_database[i].ip, ip) == 0) { found = 1; if (ip_database[i].ban_until > now) { pthread_mutex_unlock(&ip_db_mutex); return 0; // Sigue baneado } if (now - ip_database[i].last_connect <= COOLDOWN_SEC) { ip_database[i].strikes++; ip_database[i].last_connect = now; if (ip_database[i].strikes >= AUTO_BAN_STRIKES) { ip_database[i].ban_until = now + BAN_TIME; pthread_mutex_unlock(&ip_db_mutex); return -1; // Acaba de ser baneado } } else { ip_database[i].strikes = 1; ip_database[i].last_connect = now; } break; } } if (!found && empty_slot != -1) { strcpy(ip_database[empty_slot].ip, ip); ip_database[empty_slot].last_connect = now; ip_database[empty_slot].strikes = 1; ip_database[empty_slot].ban_until = 0; } pthread_mutex_unlock(&ip_db_mutex); return 1; } SSL_CTX *create_ssl_context() { SSL_load_error_strings(); OpenSSL_add_ssl_algorithms(); SSL_CTX *ctx = SSL_CTX_new(TLS_server_method()); if (!ctx) exit(1); SSL_CTX_use_certificate_file(ctx, CERT_FILE, SSL_FILETYPE_PEM); SSL_CTX_use_PrivateKey_file(ctx, KEY_FILE, SSL_FILETYPE_PEM); return ctx; } int create_server_socket(int port) { int s_sock = socket(AF_INET6, SOCK_STREAM, 0); if (s_sock < 0) return -1; int opt = 1; setsockopt(s_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); int no = 0; setsockopt(s_sock, IPPROTO_IPV6, IPV6_V6ONLY, &no, sizeof(no)); struct sockaddr_in6 addr; memset(&addr, 0, sizeof(addr)); addr.sin6_family = AF_INET6; addr.sin6_addr = in6addr_any; addr.sin6_port = htons(port); if (bind(s_sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) return -1; listen(s_sock, 600); return s_sock; } void *connection_handler(void *arg) { client_data_t *data = (client_data_t *)arg; int client_sock = data->client_fd; int is_tls = data->is_tls; SSL_CTX *ctx = data->ssl_ctx; char client_ip[INET6_ADDRSTRLEN]; if (data->addr.ss_family == AF_INET) { struct sockaddr_in *s = (struct sockaddr_in *)&data->addr; inet_ntop(AF_INET, &s->sin_addr, client_ip, sizeof(client_ip)); } else { struct sockaddr_in6 *s = (struct sockaddr_in6 *)&data->addr; inet_ntop(AF_INET6, &s->sin6_addr, client_ip, sizeof(client_ip)); } free(data); const char *proto_name = is_tls ? "TLS" : "TCP"; // --- FILTRO DE SEGURIDAD --- int sec_status = check_and_update_ip(client_ip); if (sec_status == 0) { close(client_sock); pthread_mutex_lock(&conn_mutex); active_connections--; pthread_mutex_unlock(&conn_mutex); pthread_exit(NULL); } else if (sec_status == -1) { write_log(client_ip, proto_name, "⛔ IP Baneada (Flood/Spam detectado)"); close(client_sock); pthread_mutex_lock(&conn_mutex); active_connections--; pthread_mutex_unlock(&conn_mutex); pthread_exit(NULL); } SSL *ssl = NULL; if (is_tls) { ssl = SSL_new(ctx); SSL_set_fd(ssl, client_sock); if (SSL_accept(ssl) <= 0) { SSL_free(ssl); close(client_sock); pthread_mutex_lock(&conn_mutex); active_connections--; pthread_mutex_unlock(&conn_mutex); pthread_exit(NULL); } } // ========================================================================= // BUGFIX: REVISAR LA MEMORIA INTERNA DE OPENSSL ANTES DE ESPERAR EN EL CABLE // ========================================================================= fd_set init_fds; FD_ZERO(&init_fds); FD_SET(client_sock, &init_fds); struct timeval init_tv = {3, 0}; char buffer[BUFLEN]; int bytes_read = 0; int ssl_has_data = is_tls ? SSL_pending(ssl) : 0; // Si SSL ya secuestró el paquete, lo leemos de inmediato. Si no, esperamos 3 seg. if (ssl_has_data > 0 || select(client_sock + 1, &init_fds, NULL, NULL, &init_tv) > 0) { if (is_tls) bytes_read = SSL_read(ssl, buffer, sizeof(buffer)-1); else bytes_read = recv(client_sock, buffer, sizeof(buffer)-1, 0); } int target_sock = -1; long tx_bytes = 0, rx_bytes = 0; if (bytes_read > 0) { buffer[bytes_read] = '\0'; struct sockaddr_in t_addr; target_sock = socket(AF_INET, SOCK_STREAM, 0); t_addr.sin_family = AF_INET; t_addr.sin_port = htons(SSH_PORT); inet_pton(AF_INET, SSH_HOST, &t_addr.sin_addr); if (connect(target_sock, (struct sockaddr *)&t_addr, sizeof(t_addr)) < 0) goto cleanup; if (strncmp(buffer, "SSH-", 4) == 0) { send(target_sock, buffer, bytes_read, 0); } else if (strstr(buffer, "HTTP/") != NULL && strstr(buffer, "Upgrade: websocket") == NULL) { write_log(client_ip, proto_name, "🕵️ Escáner detectado. Fake Web (400 OK)."); if (is_tls) SSL_write(ssl, FAKE_WEB_TLS, strlen(FAKE_WEB_TLS)); else send(client_sock, FAKE_WEB_TCP, strlen(FAKE_WEB_TCP), 0); goto cleanup; } else { // --- ENCABEZADOS EXTENDIDOS RECUPERADOS --- pthread_mutex_lock(&msg_mutex); const char *status_msg = MENSAJES[mensaje_idx]; mensaje_idx = (mensaje_idx + 1) % NUM_MENSAJES; pthread_mutex_unlock(&msg_mutex); char response[1024]; snprintf(response, sizeof(response), "HTTP/1.1 101 %s\r\n" "Server: nginx/1.24.0\r\n" "X-Forwarded-For: 127.0.0.1\r\n" "Content-Type: text/html; charset=UTF-8\r\n" "Proxy-Connection: keep-alive\r\n" "Cache-Control: no-cache\r\n" "X-Proxy-Agent: Gemini-Ultra-Dual-C\r\n" "Connection: Upgrade\r\n" "Upgrade: websocket\r\n\r\n", status_msg); if (is_tls) SSL_write(ssl, response, strlen(response)); else send(client_sock, response, strlen(response), 0); write_log(client_ip, proto_name, "✅ Túnel Inyectado OK"); } } else { struct sockaddr_in t_addr; target_sock = socket(AF_INET, SOCK_STREAM, 0); t_addr.sin_family = AF_INET; t_addr.sin_port = htons(SSH_PORT); inet_pton(AF_INET, SSH_HOST, &t_addr.sin_addr); if (connect(target_sock, (struct sockaddr *)&t_addr, sizeof(t_addr)) != 0) goto cleanup; write_log(client_ip, proto_name, "✅ Túnel Modo Silencioso"); } int max_fd = (client_sock > target_sock) ? client_sock : target_sock; while (1) { fd_set readfds; FD_ZERO(&readfds); FD_SET(client_sock, &readfds); FD_SET(target_sock, &readfds); struct timeval select_tv = {300, 0}; int pending = is_tls ? SSL_pending(ssl) : 0; if (pending == 0) { if (select(max_fd + 1, &readfds, NULL, NULL, &select_tv) <= 0) break; } if (pending > 0 || FD_ISSET(client_sock, &readfds)) { int b = is_tls ? SSL_read(ssl, buffer, BUFLEN) : recv(client_sock, buffer, BUFLEN, 0); if (b <= 0) break; send(target_sock, buffer, b, 0); rx_bytes += b; } if (FD_ISSET(target_sock, &readfds)) { int b = recv(target_sock, buffer, BUFLEN, 0); if (b <= 0) break; if (is_tls) SSL_write(ssl, buffer, b); else send(client_sock, buffer, b, 0); tx_bytes += b; } } cleanup: if (target_sock != -1) close(target_sock); if (is_tls) { SSL_shutdown(ssl); SSL_free(ssl); } close(client_sock); pthread_mutex_lock(&conn_mutex); active_connections--; pthread_mutex_unlock(&conn_mutex); pthread_exit(NULL); } int main(int argc, char **argv) { int port_tcp = DEFAULT_PORT_TCP, port_tls = DEFAULT_PORT_TLS; if (argc >= 3) { port_tcp = atoi(argv[1]); port_tls = atoi(argv[2]); } // Limpiar base de datos de IPs al inicio memset(ip_database, 0, sizeof(ip_database)); signal(SIGPIPE, SIG_IGN); SSL_CTX *ctx = create_ssl_context(); int server_tcp = create_server_socket(port_tcp); int server_tls = create_server_socket(port_tls); if (server_tcp < 0 || server_tls < 0) exit(1); write_log(NULL, "SISTEMA", "🚀 PROXY DUAL BARE-METAL INICIADO (Ultimate Edition V9)"); write_log(NULL, "SISTEMA", "🛡️ Módulos cargados: Anti-Flood (15/s), Auto-Ban, SSL_pending Fix, Full Headers"); int max_server_fd = (server_tcp > server_tls) ? server_tcp : server_tls; while (1) { fd_set master_fds; FD_ZERO(&master_fds); FD_SET(server_tcp, &master_fds); FD_SET(server_tls, &master_fds); if (select(max_server_fd + 1, &master_fds, NULL, NULL, NULL) < 0) continue; int active_sock = -1, is_tls = 0; if (FD_ISSET(server_tcp, &master_fds)) { active_sock = server_tcp; is_tls = 0; } else if (FD_ISSET(server_tls, &master_fds)) { active_sock = server_tls; is_tls = 1; } struct sockaddr_storage c_addr; socklen_t c_len = sizeof(c_addr); int client_sock = accept(active_sock, (struct sockaddr *)&c_addr, &c_len); if (client_sock < 0) continue; pthread_mutex_lock(&conn_mutex); if (active_connections >= MAX_CONNECTIONS) { pthread_mutex_unlock(&conn_mutex); close(client_sock); continue; } active_connections++; pthread_mutex_unlock(&conn_mutex); client_data_t *d = malloc(sizeof(client_data_t)); d->client_fd = client_sock; d->addr = c_addr; d->is_tls = is_tls; d->ssl_ctx = ctx; pthread_t tid; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); if (pthread_create(&tid, &attr, connection_handler, d) != 0) { close(client_sock); free(d); pthread_mutex_lock(&conn_mutex); active_connections--; pthread_mutex_unlock(&conn_mutex); } pthread_attr_destroy(&attr); } return 0; }