| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337 |
- /*
- * =====================================================================================
- * PROXY VPN v6 TLS - EDICION PERSONALIZADA (NATIVA EN C)
- * Compilación en Ubuntu 24.04: gcc -o vpn_proxy vpn_proxy.c -lssl -lcrypto -lpthread
- * =====================================================================================
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <arpa/inet.h>
- #include <sys/socket.h>
- #include <sys/select.h>
- #include <sys/time.h>
- #include <pthread.h>
- #include <openssl/ssl.h>
- #include <openssl/err.h>
- #include <time.h>
- #include <fcntl.h>
- // --- CONFIGURACIÓN BASE ---
- #define DEFAULT_PORT 443
- #define SSH_HOST "127.0.0.1"
- #define SSH_PORT 22
- #define CERT_FILE "/root/cert.pem"
- #define KEY_FILE "/root/key.pem"
- #define LOG_FILE "/root/proxy-ssl-c.log"
- // --- SEGURIDAD Y LIMITES ---
- #define MAX_CONNECTIONS 200
- #define BUFLEN 16384
- #define BAN_TIME 3600
- #define AUTO_BAN_STRIKES 3
- #define COOLDOWN_SEC 1
- // --- FAKE WEB RESPONSE (400 OK) ---
- const char *FAKE_WEB_RESPONSE =
- "HTTP/1.1 400 OK\r\n"
- "Server: nginx/1.21.0\r\n"
- "Content-Type: text/html; charset=UTF-8\r\n"
- "Connection: close\r\n\r\n"
- "<!DOCTYPE html>\n<html>\n<head><title>Error</title></head>\n"
- "<body style='text-align:center; padding:50px; font-family:sans-serif;'>\n"
- "<h1>Hola</h1>\n<p>400 Bad Request</p>\n"
- "</body>\n</html>\n";
- // --- MENSAJES ROTATIVOS ---
- const char *MENSAJES[] = {
- "🚀 CONEXION TLS ESTABLECIDA", "🛡️ CIFRADO MILITAR ACTIVO", "Pfsense", "OPNsense", "VyOS", "Claro"
- };
- #define NUM_MENSAJES (sizeof(MENSAJES) / sizeof(MENSAJES[0]))
- int mensaje_idx = 0;
- pthread_mutex_t msg_mutex = PTHREAD_MUTEX_INITIALIZER;
- // --- ESTADO GLOBAL ---
- int active_connections = 0;
- pthread_mutex_t conn_mutex = PTHREAD_MUTEX_INITIALIZER;
- pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
- // Estructura para pasar datos al hilo
- typedef struct {
- int client_fd;
- struct sockaddr_in addr;
- SSL_CTX *ssl_ctx;
- } client_data_t;
- // --- FUNCIONES DE SOPORTE ---
- void write_log(const char *ip, 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 time_str[64];
- strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", t);
- fprintf(f, "[%s] [%s] %s\n", time_str, ip ? ip : "SISTEMA", msg);
- printf("[%s] [%s] %s\n", time_str, ip ? ip : "SISTEMA", msg);
- fclose(f);
- }
- pthread_mutex_unlock(&log_mutex);
- }
- SSL_CTX *create_context() {
- const SSL_METHOD *method = TLS_server_method();
- SSL_CTX *ctx = SSL_CTX_new(method);
- if (!ctx) {
- perror("No se pudo crear el contexto SSL");
- ERR_print_errors_fp(stderr);
- exit(EXIT_FAILURE);
- }
- return ctx;
- }
- void configure_context(SSL_CTX *ctx) {
- if (SSL_CTX_use_certificate_file(ctx, CERT_FILE, SSL_FILETYPE_PEM) <= 0) {
- ERR_print_errors_fp(stderr);
- exit(EXIT_FAILURE);
- }
- if (SSL_CTX_use_PrivateKey_file(ctx, KEY_FILE, SSL_FILETYPE_PEM) <= 0 ) {
- ERR_print_errors_fp(stderr);
- exit(EXIT_FAILURE);
- }
- }
- // --- HILO DE CONEXIÓN (HANDLER) ---
- void *connection_handler(void *arg) {
- client_data_t *data = (client_data_t *)arg;
- int client_sock = data->client_fd;
- SSL_CTX *ctx = data->ssl_ctx;
-
- char client_ip[INET_ADDRSTRLEN];
- inet_ntop(AF_INET, &(data->addr.sin_addr), client_ip, INET_ADDRSTRLEN);
- free(data); // Liberar la memoria de la estructura
- SSL *ssl = SSL_new(ctx);
- SSL_set_fd(ssl, client_sock);
- if (SSL_accept(ssl) <= 0) {
- // Fallo en el Handshake SSL (Probablemente un escáner no-TLS)
- SSL_free(ssl);
- close(client_sock);
- pthread_mutex_lock(&conn_mutex); active_connections--; pthread_mutex_unlock(&conn_mutex);
- pthread_exit(NULL);
- }
- // Configurar timeout de lectura inicial (3 segundos)
- struct timeval tv;
- tv.tv_sec = 3; tv.tv_usec = 0;
- setsockopt(client_sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
- char buffer[BUFLEN];
- int bytes_read = SSL_read(ssl, buffer, sizeof(buffer) - 1);
-
- int target_sock = -1;
- if (bytes_read > 0) {
- buffer[bytes_read] = '\0';
- // Conectar al destino SSH local
- struct sockaddr_in target_addr;
- target_sock = socket(AF_INET, SOCK_STREAM, 0);
- target_addr.sin_family = AF_INET;
- target_addr.sin_port = htons(SSH_PORT);
- inet_pton(AF_INET, SSH_HOST, &target_addr.sin_addr);
- if (connect(target_sock, (struct sockaddr *)&target_addr, sizeof(target_addr)) < 0) {
- write_log(client_ip, "❌ Error conectando a SSH local");
- goto cleanup;
- }
- if (strncmp(buffer, "SSH-", 4) == 0) {
- write_log(client_ip, "✅ Túnel (Modo SSH Directo)");
- send(target_sock, buffer, bytes_read, 0);
- } else if (strstr(buffer, "HTTP/") != NULL && strstr(buffer, "Upgrade: websocket") == NULL) {
- write_log(client_ip, "🕵️ Escáner detectado. Respondiendo 400 OK Fake Web.");
- SSL_write(ssl, FAKE_WEB_RESPONSE, strlen(FAKE_WEB_RESPONSE));
- goto cleanup;
- } else {
- // Modo Websocket / Inyector HTTP
- 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.21.0\r\n"
- "X-Proxy-Agent: Gemini-Ultra-Robust-C-Native\r\n"
- "Connection: Upgrade\r\n"
- "Upgrade: websocket\r\n\r\n", status_msg);
-
- SSL_write(ssl, response, strlen(response));
-
- char log_msg[256];
- snprintf(log_msg, sizeof(log_msg), "✅ Túnel (Modo WebSocket HTTP): %s", status_msg);
- write_log(client_ip, log_msg);
-
- // Si el payload tiene más datos después de las cabeceras HTTP, enviarlos
- // (En este proxy simplificado, asumimos que el handshake viene limpio)
- }
- } else {
- // Conexión vacía (Modo Stunnel Silencioso)
- struct sockaddr_in target_addr;
- target_sock = socket(AF_INET, SOCK_STREAM, 0);
- target_addr.sin_family = AF_INET;
- target_addr.sin_port = htons(SSH_PORT);
- inet_pton(AF_INET, SSH_HOST, &target_addr.sin_addr);
- if (connect(target_sock, (struct sockaddr *)&target_addr, sizeof(target_addr)) == 0) {
- write_log(client_ip, "✅ Túnel (Modo Stunnel Silencioso)");
- } else {
- goto cleanup;
- }
- }
- // --- BUCLE DEL TÚNEL (I/O MULTIPLEXING) ---
- tv.tv_sec = 0; // Quitar timeout para el túnel
- setsockopt(client_sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
-
- int max_fd = (client_sock > target_sock) ? client_sock : target_sock;
- long tx_bytes = 0, rx_bytes = 0;
- while (1) {
- fd_set readfds;
- FD_ZERO(&readfds);
- FD_SET(client_sock, &readfds);
- FD_SET(target_sock, &readfds);
- struct timeval select_tv;
- select_tv.tv_sec = 300; // 5 minutos de inactividad máxima
- select_tv.tv_usec = 0;
- // Validar si OpenSSL tiene datos pendientes en memoria desencriptada
- int pending = SSL_pending(ssl);
- if (pending == 0) {
- int activity = select(max_fd + 1, &readfds, NULL, NULL, &select_tv);
- if (activity <= 0) break; // Error o Timeout
- }
- // Datos del Cliente (SSL) -> SSH
- if (pending > 0 || FD_ISSET(client_sock, &readfds)) {
- int bytes = SSL_read(ssl, buffer, sizeof(buffer));
- if (bytes <= 0) break;
- send(target_sock, buffer, bytes, 0);
- rx_bytes += bytes;
- }
- // Datos del SSH -> Cliente (SSL)
- if (FD_ISSET(target_sock, &readfds)) {
- int bytes = recv(target_sock, buffer, sizeof(buffer), 0);
- if (bytes <= 0) break;
- SSL_write(ssl, buffer, bytes);
- tx_bytes += bytes;
- }
- }
- double total_mb = (double)(tx_bytes + rx_bytes) / (1024.0 * 1024.0);
- if (total_mb > 0.05) {
- char log_close[256];
- snprintf(log_close, sizeof(log_close), "[*] Cierre de sesión. Tráfico: %.2f MB", total_mb);
- write_log(client_ip, log_close);
- }
- cleanup:
- if (target_sock != -1) close(target_sock);
- SSL_shutdown(ssl);
- SSL_free(ssl);
- close(client_sock);
- pthread_mutex_lock(&conn_mutex);
- active_connections--;
- pthread_mutex_unlock(&conn_mutex);
- pthread_exit(NULL);
- }
- // --- BUCLE PRINCIPAL ---
- int main(int argc, char **argv) {
- int port = DEFAULT_PORT;
- if (argc > 1) port = atoi(argv[1]);
- // Inicializar OpenSSL
- SSL_load_error_strings();
- OpenSSL_add_ssl_algorithms();
- SSL_CTX *ctx = create_context();
- configure_context(ctx);
- int server_sock = socket(AF_INET, SOCK_STREAM, 0);
- int opt = 1;
- setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
- struct sockaddr_in server_addr;
- server_addr.sin_family = AF_INET;
- server_addr.sin_addr.s_addr = INADDR_ANY;
- server_addr.sin_port = htons(port);
- if (bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
- perror("Fallo el Bind");
- exit(EXIT_FAILURE);
- }
- if (listen(server_sock, 600) < 0) {
- perror("Fallo el Listen");
- exit(EXIT_FAILURE);
- }
- write_log(NULL, "=====================================================");
- char init_msg[256];
- snprintf(init_msg, sizeof(init_msg), "🚀 Servidor v6 TLS en NATIVO (C) - Puerto %d", port);
- write_log(NULL, init_msg);
- write_log(NULL, "🛡️ Máximo Rendimiento | Anti-Probing: 400 OK");
- write_log(NULL, "=====================================================");
- while (1) {
- struct sockaddr_in client_addr;
- socklen_t addr_len = sizeof(client_addr);
- int client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &addr_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);
- // Crear datos para el hilo
- client_data_t *data = malloc(sizeof(client_data_t));
- data->client_fd = client_sock;
- data->addr = client_addr;
- data->ssl_ctx = ctx;
- // Desplegar Hilo
- pthread_t thread_id;
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); // Auto-limpieza del hilo al terminar
-
- if (pthread_create(&thread_id, &attr, connection_handler, (void *)data) != 0) {
- write_log(NULL, "Error creando hilo. Cerrando socket.");
- close(client_sock);
- free(data);
- pthread_mutex_lock(&conn_mutex); active_connections--; pthread_mutex_unlock(&conn_mutex);
- }
- pthread_attr_destroy(&attr);
- }
- close(server_sock);
- SSL_CTX_free(ctx);
- EVP_cleanup();
- return 0;
- }
|