|
|
@@ -1,7 +1,7 @@
|
|
|
/*
|
|
|
* =====================================================================================
|
|
|
* PROXY VPN DUAL (TCP + TLS) - GRADO ENTERPRISE NATIVO EN C
|
|
|
- * Integra V3 (Plaintext) y V6 (SSL/TLS) en un solo Demonio.
|
|
|
+ * Integra V3 (Plaintext) y V6 (SSL/TLS) con Mensajes Rotativos Dinámicos.
|
|
|
* Compilación: gcc -O3 -o proxy_dual proxy_dual.c -lssl -lcrypto -lpthread
|
|
|
* Uso: ./proxy_dual [PUERTO_HTTP] [PUERTO_HTTPS] (Ej: ./proxy_dual 80 443)
|
|
|
* =====================================================================================
|
|
|
@@ -33,7 +33,6 @@
|
|
|
#define KEY_FILE "/root/key.pem"
|
|
|
|
|
|
// --- FAKE WEB RESPONSES ---
|
|
|
-// Para puerto 80 (TCP)
|
|
|
const char *FAKE_WEB_TCP =
|
|
|
"HTTP/1.1 400 Bad Request\r\n"
|
|
|
"Server: nginx/1.24.0\r\n"
|
|
|
@@ -41,7 +40,6 @@ const char *FAKE_WEB_TCP =
|
|
|
"Connection: close\r\n\r\n"
|
|
|
"<html><body><center><h1>400 Bad Request</h1></center><hr><center>nginx/1.24.0</center></body></html>\r\n";
|
|
|
|
|
|
-// Para puerto 443 (TLS)
|
|
|
const char *FAKE_WEB_TLS =
|
|
|
"HTTP/1.1 400 OK\r\n"
|
|
|
"Server: nginx/1.21.0\r\n"
|
|
|
@@ -49,24 +47,40 @@ const char *FAKE_WEB_TLS =
|
|
|
"Connection: close\r\n\r\n"
|
|
|
"<html><body><center><h1>400 Bad Request</h1></center></body></html>\r\n";
|
|
|
|
|
|
-// --- CUSTOM HEADERS PARA INYECTORES ---
|
|
|
-const char *RESP_101_TCP = "HTTP/1.1 101 Switching Protocols\r\nServer: nginx/1.24.0\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nX-Proxy-Agent: Gemini-Ultra-Robust-V3-TCP\r\n\r\n";
|
|
|
-const char *RESP_101_TLS = "HTTP/1.1 101 OK\r\nServer: nginx/1.21.0\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nX-Proxy-Agent: Gemini-Ultra-Robust-V6-TLS\r\n\r\n";
|
|
|
+// --- MENSAJES ROTATIVOS (Como en la V6) ---
|
|
|
+const char *MENSAJES[] = {
|
|
|
+ "🚀 CONEXION ESTABLECIDA",
|
|
|
+ "🛡️ CIFRADO MILITAR ACTIVO",
|
|
|
+ "🔋 MODO SIGILO OK",
|
|
|
+ "Pfsense",
|
|
|
+ "OPNsense",
|
|
|
+ "VyOS",
|
|
|
+ "Claro",
|
|
|
+ "Windows Server",
|
|
|
+ "BSD Free",
|
|
|
+ "Altice",
|
|
|
+ "Viva",
|
|
|
+ "Google",
|
|
|
+ "TNSR",
|
|
|
+ "🌐 BYPASS DE FIREWALL OK"
|
|
|
+};
|
|
|
+#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 trabajador
|
|
|
typedef struct {
|
|
|
int client_fd;
|
|
|
struct sockaddr_in addr;
|
|
|
- int is_tls; // 1 si es puerto 443, 0 si es puerto 80
|
|
|
+ int is_tls; // 1 = TLS (443), 0 = TCP (80)
|
|
|
SSL_CTX *ssl_ctx;
|
|
|
} client_data_t;
|
|
|
|
|
|
-// --- FUNCIONES DE SOPORTE ---
|
|
|
+// --- FUNCIONES DE LOG Y CONTEXTO ---
|
|
|
void write_log(const char *ip, const char *proto, const char *msg) {
|
|
|
pthread_mutex_lock(&log_mutex);
|
|
|
FILE *f = fopen(LOG_FILE, "a");
|
|
|
@@ -82,20 +96,18 @@ void write_log(const char *ip, const char *proto, const char *msg) {
|
|
|
pthread_mutex_unlock(&log_mutex);
|
|
|
}
|
|
|
|
|
|
-// Configuración OpenSSL
|
|
|
SSL_CTX *create_ssl_context() {
|
|
|
SSL_load_error_strings();
|
|
|
OpenSSL_add_ssl_algorithms();
|
|
|
SSL_CTX *ctx = SSL_CTX_new(TLS_server_method());
|
|
|
- if (!ctx) { perror("Error creando contexto SSL"); exit(1); }
|
|
|
+ if (!ctx) { perror("Error contexto SSL"); exit(1); }
|
|
|
if (SSL_CTX_use_certificate_file(ctx, CERT_FILE, SSL_FILETYPE_PEM) <= 0 ||
|
|
|
SSL_CTX_use_PrivateKey_file(ctx, KEY_FILE, SSL_FILETYPE_PEM) <= 0) {
|
|
|
- printf("⚠️ Advertencia: No se encontraron certificados en %s. El puerto TLS fallará.\n", CERT_FILE);
|
|
|
+ printf("⚠️ Sin certificados en %s. TLS fallará.\n", CERT_FILE);
|
|
|
}
|
|
|
return ctx;
|
|
|
}
|
|
|
|
|
|
-// Crear socket de escucha
|
|
|
int create_server_socket(int port) {
|
|
|
int s_sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
int opt = 1;
|
|
|
@@ -104,14 +116,12 @@ int create_server_socket(int port) {
|
|
|
addr.sin_family = AF_INET;
|
|
|
addr.sin_addr.s_addr = INADDR_ANY;
|
|
|
addr.sin_port = htons(port);
|
|
|
- if (bind(s_sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
|
|
- perror("Fallo en bind"); return -1;
|
|
|
- }
|
|
|
+ if (bind(s_sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) return -1;
|
|
|
listen(s_sock, 600);
|
|
|
return s_sock;
|
|
|
}
|
|
|
|
|
|
-// --- HILO TRABAJADOR (Maneja TCP o TLS dinámicamente) ---
|
|
|
+// --- HILO TRABAJADOR (TCP o TLS) ---
|
|
|
void *connection_handler(void *arg) {
|
|
|
client_data_t *data = (client_data_t *)arg;
|
|
|
int client_sock = data->client_fd;
|
|
|
@@ -125,19 +135,16 @@ void *connection_handler(void *arg) {
|
|
|
const char *proto_name = is_tls ? "TLS" : "TCP";
|
|
|
SSL *ssl = NULL;
|
|
|
|
|
|
- // 1. Handshake SSL si corresponde
|
|
|
if (is_tls) {
|
|
|
ssl = SSL_new(ctx);
|
|
|
SSL_set_fd(ssl, client_sock);
|
|
|
if (SSL_accept(ssl) <= 0) {
|
|
|
- // Escáner sin SSL tocó el puerto 443
|
|
|
SSL_free(ssl); close(client_sock);
|
|
|
pthread_mutex_lock(&conn_mutex); active_connections--; pthread_mutex_unlock(&conn_mutex);
|
|
|
pthread_exit(NULL);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 2. Leer Payload inicial
|
|
|
struct timeval tv = {3, 0};
|
|
|
setsockopt(client_sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
|
|
|
|
|
|
@@ -152,7 +159,6 @@ void *connection_handler(void *arg) {
|
|
|
if (bytes_read > 0) {
|
|
|
buffer[bytes_read] = '\0';
|
|
|
|
|
|
- // 3. Conectar al SSH local
|
|
|
struct sockaddr_in t_addr;
|
|
|
target_sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
t_addr.sin_family = AF_INET;
|
|
|
@@ -164,7 +170,6 @@ void *connection_handler(void *arg) {
|
|
|
goto cleanup;
|
|
|
}
|
|
|
|
|
|
- // 4. Lógica de Enrutamiento y Fake Web
|
|
|
if (strncmp(buffer, "SSH-", 4) == 0) {
|
|
|
write_log(client_ip, proto_name, "✅ Túnel SSH Directo");
|
|
|
send(target_sock, buffer, bytes_read, 0);
|
|
|
@@ -174,12 +179,37 @@ void *connection_handler(void *arg) {
|
|
|
else send(client_sock, FAKE_WEB_TCP, strlen(FAKE_WEB_TCP), 0);
|
|
|
goto cleanup;
|
|
|
} else {
|
|
|
- write_log(client_ip, proto_name, "✅ Túnel WebSocket Establecido");
|
|
|
- if (is_tls) SSL_write(ssl, RESP_101_TLS, strlen(RESP_101_TLS));
|
|
|
- else send(client_sock, RESP_101_TCP, strlen(RESP_101_TCP), 0);
|
|
|
+ // --- CONSTRUCCIÓN DINÁMICA DE LA RESPUESTA HTTP 101 ---
|
|
|
+ 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];
|
|
|
+ if (is_tls) {
|
|
|
+ snprintf(response, sizeof(response),
|
|
|
+ "HTTP/1.1 101 %s\r\n"
|
|
|
+ "Server: nginx/1.21.0\r\n"
|
|
|
+ "X-Proxy-Agent: Gemini-Ultra-Robust-V6-TLS\r\n"
|
|
|
+ "Connection: Upgrade\r\n"
|
|
|
+ "Upgrade: websocket\r\n\r\n", status_msg);
|
|
|
+ } else {
|
|
|
+ snprintf(response, sizeof(response),
|
|
|
+ "HTTP/1.1 101 %s\r\n"
|
|
|
+ "Server: nginx/1.24.0\r\n"
|
|
|
+ "X-Proxy-Agent: Gemini-Ultra-Robust-V3-TCP\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);
|
|
|
+
|
|
|
+ char log_msg[256];
|
|
|
+ snprintf(log_msg, sizeof(log_msg), "✅ Túnel WebSocket Inyectado: %s", status_msg);
|
|
|
+ write_log(client_ip, proto_name, log_msg);
|
|
|
}
|
|
|
} else {
|
|
|
- // Modo Stunnel (payload vacío inicial)
|
|
|
struct sockaddr_in t_addr;
|
|
|
target_sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
t_addr.sin_family = AF_INET;
|
|
|
@@ -190,7 +220,6 @@ void *connection_handler(void *arg) {
|
|
|
} else goto cleanup;
|
|
|
}
|
|
|
|
|
|
- // --- 5. BUCLE DEL TÚNEL (I/O MULTIPLEXING) ---
|
|
|
tv.tv_sec = 0;
|
|
|
setsockopt(client_sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
|
|
|
int max_fd = (client_sock > target_sock) ? client_sock : target_sock;
|
|
|
@@ -207,7 +236,6 @@ void *connection_handler(void *arg) {
|
|
|
if (select(max_fd + 1, &readfds, NULL, NULL, &select_tv) <= 0) break;
|
|
|
}
|
|
|
|
|
|
- // Cliente -> SSH
|
|
|
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;
|
|
|
@@ -215,7 +243,6 @@ void *connection_handler(void *arg) {
|
|
|
rx_bytes += b;
|
|
|
}
|
|
|
|
|
|
- // SSH -> Cliente
|
|
|
if (FD_ISSET(target_sock, &readfds)) {
|
|
|
int b = recv(target_sock, buffer, BUFLEN, 0);
|
|
|
if (b <= 0) break;
|
|
|
@@ -226,7 +253,6 @@ void *connection_handler(void *arg) {
|
|
|
}
|
|
|
|
|
|
cleanup:
|
|
|
- // Log final de tráfico
|
|
|
double total_mb = (double)(tx_bytes + rx_bytes) / (1024.0 * 1024.0);
|
|
|
if (total_mb > 0.05) {
|
|
|
char stat_msg[128];
|
|
|
@@ -242,7 +268,7 @@ cleanup:
|
|
|
pthread_exit(NULL);
|
|
|
}
|
|
|
|
|
|
-// --- HILO MAESTRO (ORQUESTADOR) ---
|
|
|
+// --- HILO MAESTRO ---
|
|
|
int main(int argc, char **argv) {
|
|
|
int port_tcp = DEFAULT_PORT_TCP;
|
|
|
int port_tls = DEFAULT_PORT_TLS;
|
|
|
@@ -252,29 +278,27 @@ int main(int argc, char **argv) {
|
|
|
port_tls = atoi(argv[2]);
|
|
|
}
|
|
|
|
|
|
- signal(SIGPIPE, SIG_IGN); // Prevenir caídas por desconexiones bruscas
|
|
|
+ signal(SIGPIPE, SIG_IGN);
|
|
|
|
|
|
- // Preparar Entorno
|
|
|
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) {
|
|
|
- printf("Error iniciando sockets. ¿Tienes permisos de root (sudo) para los puertos?\n");
|
|
|
+ printf("Error iniciando sockets. ¿Tienes permisos root para puertos bajos?\n");
|
|
|
exit(1);
|
|
|
}
|
|
|
|
|
|
write_log(NULL, "SISTEMA", "=====================================================");
|
|
|
char msg[256];
|
|
|
- snprintf(msg, sizeof(msg), "🚀 PROXY DUAL ENTERPRISE INICIADO");
|
|
|
- write_log(NULL, "SISTEMA", msg);
|
|
|
- snprintf(msg, sizeof(msg), "🌐 TCP Plaintext escuchando en puerto: %d", port_tcp);
|
|
|
- write_log(NULL, "SISTEMA", msg);
|
|
|
- snprintf(msg, sizeof(msg), "🔒 TLS Encriptado escuchando en puerto: %d", port_tls);
|
|
|
- write_log(NULL, "SISTEMA", msg);
|
|
|
+ write_log(NULL, "SISTEMA", "🚀 PROXY DUAL ENTERPRISE NATIVO INICIADO");
|
|
|
+ snprintf(msg, sizeof(msg), "🌐 TCP escuchando en puerto: %d", port_tcp);
|
|
|
+ write_log(NULL, "TCP", msg);
|
|
|
+ snprintf(msg, sizeof(msg), "🔒 TLS escuchando en puerto: %d", port_tls);
|
|
|
+ write_log(NULL, "TLS", msg);
|
|
|
+ write_log(NULL, "SISTEMA", "🛡️ Doble Fake Web | Mensajes Dinámicos | Multi-hilo");
|
|
|
write_log(NULL, "SISTEMA", "=====================================================");
|
|
|
|
|
|
- // Bucle de Multiplexación de Puertos
|
|
|
int max_server_fd = (server_tcp > server_tls) ? server_tcp : server_tls;
|
|
|
|
|
|
while (1) {
|
|
|
@@ -283,21 +307,15 @@ int main(int argc, char **argv) {
|
|
|
FD_SET(server_tcp, &master_fds);
|
|
|
FD_SET(server_tls, &master_fds);
|
|
|
|
|
|
- // Esperar a que alguien se conecte a CUALQUIERA de los dos puertos
|
|
|
if (select(max_server_fd + 1, &master_fds, NULL, NULL, NULL) < 0) continue;
|
|
|
|
|
|
int active_sock = -1;
|
|
|
int is_tls = 0;
|
|
|
|
|
|
- // ¿Fue en el puerto TCP?
|
|
|
if (FD_ISSET(server_tcp, &master_fds)) {
|
|
|
- active_sock = server_tcp;
|
|
|
- is_tls = 0;
|
|
|
- }
|
|
|
- // ¿O fue en el puerto TLS?
|
|
|
- else if (FD_ISSET(server_tls, &master_fds)) {
|
|
|
- active_sock = server_tls;
|
|
|
- is_tls = 1;
|
|
|
+ active_sock = server_tcp; is_tls = 0;
|
|
|
+ } else if (FD_ISSET(server_tls, &master_fds)) {
|
|
|
+ active_sock = server_tls; is_tls = 1;
|
|
|
}
|
|
|
|
|
|
struct sockaddr_in c_addr;
|
|
|
@@ -308,20 +326,17 @@ int main(int argc, char **argv) {
|
|
|
pthread_mutex_lock(&conn_mutex);
|
|
|
if (active_connections >= MAX_CONNECTIONS) {
|
|
|
pthread_mutex_unlock(&conn_mutex);
|
|
|
- close(client_sock);
|
|
|
- continue;
|
|
|
+ close(client_sock); continue;
|
|
|
}
|
|
|
active_connections++;
|
|
|
pthread_mutex_unlock(&conn_mutex);
|
|
|
|
|
|
- // Empaquetar datos para el hilo
|
|
|
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;
|
|
|
|
|
|
- // Lanzar hilo independiente
|
|
|
pthread_t tid;
|
|
|
pthread_attr_t attr;
|
|
|
pthread_attr_init(&attr);
|
|
|
@@ -340,3 +355,4 @@ int main(int argc, char **argv) {
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+
|