|
|
@@ -1,7 +1,8 @@
|
|
|
/*
|
|
|
* =====================================================================================
|
|
|
* PROXY MULTIFILAMENTADO PROFESIONAL - VERSIÓN 3 (NATIVO EN C)
|
|
|
- * Compilación en Ubuntu: gcc -O3 -o proxy_v3 proxy_v3_nativo.c -lpthread
|
|
|
+ * Mejoras: Registro de Logs detallados y Monitoreo de tráfico.
|
|
|
+ * Compilación: gcc -O3 -o proxy_v3 proxy_v3_nativo.c -lpthread
|
|
|
* =====================================================================================
|
|
|
*/
|
|
|
|
|
|
@@ -15,15 +16,17 @@
|
|
|
#include <pthread.h>
|
|
|
#include <signal.h>
|
|
|
#include <time.h>
|
|
|
+#include <sys/stat.h>
|
|
|
|
|
|
// --- CONFIGURACIÓN BASE ---
|
|
|
-#define DEFAULT_PORT 80 // Puedes cambiarlo al ejecutar
|
|
|
+#define DEFAULT_PORT 8080
|
|
|
#define SSH_HOST "127.0.0.1"
|
|
|
#define SSH_PORT 22
|
|
|
#define BUFLEN 16384
|
|
|
#define MAX_CONNECTIONS 300
|
|
|
+#define LOG_FILE "/root/proxy-v3.log"
|
|
|
|
|
|
-// --- FAKE WEB ROBUSTA (Réplica exacta de Nginx 1.24) ---
|
|
|
+// --- FAKE WEB ROBUSTA (Nginx 1.24) ---
|
|
|
const char *FAKE_WEB_RESPONSE =
|
|
|
"HTTP/1.1 400 Bad Request\r\n"
|
|
|
"Server: nginx/1.24.0\r\n"
|
|
|
@@ -34,7 +37,6 @@ const char *FAKE_WEB_RESPONSE =
|
|
|
"<body>\r\n<center><h1>400 Bad Request</h1></center>\r\n"
|
|
|
"<hr><center>nginx/1.24.0</center>\r\n</body>\r\n</html>\r\n";
|
|
|
|
|
|
-// --- RESPUESTA DE CONEXIÓN ACEPTADA (Con tu Agent) ---
|
|
|
const char *HTTP_101_RESPONSE =
|
|
|
"HTTP/1.1 101 Switching Protocols\r\n"
|
|
|
"Server: nginx/1.24.0\r\n"
|
|
|
@@ -42,35 +44,46 @@ const char *HTTP_101_RESPONSE =
|
|
|
"Connection: Upgrade\r\n"
|
|
|
"X-Proxy-Agent: Gemini-Ultra-Robust-v3\r\n\r\n";
|
|
|
|
|
|
-// Variables globales de estado
|
|
|
-int active_connections = 0;
|
|
|
+// Mutexes para sincronización
|
|
|
+pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
|
pthread_mutex_t conn_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
|
+int active_connections = 0;
|
|
|
|
|
|
-// Estructura para pasar datos al hilo
|
|
|
typedef struct {
|
|
|
int client_fd;
|
|
|
struct sockaddr_in addr;
|
|
|
} client_data_t;
|
|
|
|
|
|
-// Imprimir logs en pantalla
|
|
|
-void log_msg(const char *ip, const char *msg) {
|
|
|
- time_t now = time(NULL);
|
|
|
- struct tm *t = localtime(&now);
|
|
|
- char time_str[64];
|
|
|
- strftime(time_str, sizeof(time_str), "%H:%M:%S", t);
|
|
|
- printf("[%s] [%s] %s\n", time_str, ip ? ip : "SISTEMA", msg);
|
|
|
+// --- FUNCIÓN DE LOGS (ESTILO V6 TLS) ---
|
|
|
+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 ts[64];
|
|
|
+ strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S", t);
|
|
|
+
|
|
|
+ if (ip) {
|
|
|
+ fprintf(f, "[%s] [%s] %s\n", ts, ip, msg);
|
|
|
+ printf("[%s] [%s] %s\n", ts, ip, msg);
|
|
|
+ } else {
|
|
|
+ fprintf(f, "[%s] %s\n", ts, msg);
|
|
|
+ printf("[%s] %s\n", ts, msg);
|
|
|
+ }
|
|
|
+ fclose(f);
|
|
|
+ }
|
|
|
+ pthread_mutex_unlock(&log_mutex);
|
|
|
}
|
|
|
|
|
|
-// Hilo de manejo de conexión
|
|
|
+// --- MANEJADOR DE CONEXIÓN ---
|
|
|
void *connection_handler(void *arg) {
|
|
|
client_data_t *data = (client_data_t *)arg;
|
|
|
int client_sock = data->client_fd;
|
|
|
-
|
|
|
char client_ip[INET_ADDRSTRLEN];
|
|
|
inet_ntop(AF_INET, &(data->addr.sin_addr), client_ip, INET_ADDRSTRLEN);
|
|
|
- free(data); // Liberar memoria del argumento
|
|
|
+ free(data);
|
|
|
|
|
|
- // Timeout inicial para leer la petición
|
|
|
struct timeval tv;
|
|
|
tv.tv_sec = 3; tv.tv_usec = 0;
|
|
|
setsockopt(client_sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
|
|
|
@@ -78,88 +91,102 @@ void *connection_handler(void *arg) {
|
|
|
char buffer[BUFLEN];
|
|
|
int 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';
|
|
|
|
|
|
- // Conectar al destino (SSH Local)
|
|
|
- struct sockaddr_in target_addr;
|
|
|
+ // Conectar a SSH local
|
|
|
+ struct sockaddr_in t_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);
|
|
|
+ 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 *)&target_addr, sizeof(target_addr)) < 0) {
|
|
|
- log_msg(client_ip, "❌ Error destino SSH");
|
|
|
+ if (connect(target_sock, (struct sockaddr *)&t_addr, sizeof(t_addr)) < 0) {
|
|
|
+ write_log(client_ip, "❌ Error: No se pudo conectar al SSH local");
|
|
|
goto cleanup;
|
|
|
}
|
|
|
|
|
|
- // Lógica de ruteo y Fake Web
|
|
|
if (strncmp(buffer, "SSH-", 4) == 0) {
|
|
|
- log_msg(client_ip, "✅ Túnel Directo SSH");
|
|
|
+ write_log(client_ip, "✅ Túnel cifrado (Modo SSH Directo)");
|
|
|
send(target_sock, buffer, bytes_read, 0);
|
|
|
+ rx_bytes += bytes_read;
|
|
|
} else if (strstr(buffer, "HTTP/") != NULL && strstr(buffer, "Upgrade: websocket") == NULL) {
|
|
|
- log_msg(client_ip, "🕵️ Escáner detectado. Enviando Nginx Fake Web (400).");
|
|
|
+ write_log(client_ip, "🕵️ Escáner detectado. Respondiendo 400 Bad Request Fake Web.");
|
|
|
send(client_sock, FAKE_WEB_RESPONSE, strlen(FAKE_WEB_RESPONSE), 0);
|
|
|
goto cleanup;
|
|
|
} else {
|
|
|
- // Es NetMod / Inyector HTTP
|
|
|
- log_msg(client_ip, "✅ Túnel WebSocket Inyectado (V3)");
|
|
|
+ write_log(client_ip, "✅ Túnel cifrado (Modo WebSocket HTTP): Gemini-V3");
|
|
|
send(client_sock, HTTP_101_RESPONSE, strlen(HTTP_101_RESPONSE), 0);
|
|
|
- // Si hay datos extra (payload SSH adelantado), reenviarlo
|
|
|
- char *headers_end = strstr(buffer, "\r\n\r\n");
|
|
|
- if (headers_end) {
|
|
|
- int header_len = (headers_end - buffer) + 4;
|
|
|
- if (bytes_read > header_len) {
|
|
|
- send(target_sock, buffer + header_len, bytes_read - header_len, 0);
|
|
|
+ tx_bytes += strlen(HTTP_101_RESPONSE);
|
|
|
+
|
|
|
+ char *h_end = strstr(buffer, "\r\n\r\n");
|
|
|
+ if (h_end) {
|
|
|
+ int h_len = (h_end - buffer) + 4;
|
|
|
+ if (bytes_read > h_len) {
|
|
|
+ send(target_sock, buffer + h_len, bytes_read - h_len, 0);
|
|
|
+ rx_bytes += (bytes_read - h_len);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
- goto cleanup; // Conexión vacía o timeout
|
|
|
+ // Posible Stunnel o NetMod Silencioso
|
|
|
+ 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) {
|
|
|
+ write_log(client_ip, "✅ Túnel cifrado (Modo Stunnel Silencioso)");
|
|
|
+ } else {
|
|
|
+ goto cleanup;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- // --- BUCLE SELECT (EL PUENTE DE DATOS) ---
|
|
|
- tv.tv_sec = 0; // Quitar timeout
|
|
|
+ // --- PUENTE DE DATOS ---
|
|
|
+ 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;
|
|
|
|
|
|
while (1) {
|
|
|
- fd_set readfds;
|
|
|
- FD_ZERO(&readfds);
|
|
|
- FD_SET(client_sock, &readfds);
|
|
|
- FD_SET(target_sock, &readfds);
|
|
|
-
|
|
|
- // Timeout de inactividad de 5 minutos
|
|
|
- struct timeval select_tv = {300, 0};
|
|
|
-
|
|
|
- int activity = select(max_fd + 1, &readfds, NULL, NULL, &select_tv);
|
|
|
- if (activity <= 0) break; // Cierre por timeout o error
|
|
|
-
|
|
|
- // Del Cliente al SSH
|
|
|
- if (FD_ISSET(client_sock, &readfds)) {
|
|
|
- int bytes = recv(client_sock, buffer, sizeof(buffer), 0);
|
|
|
- if (bytes <= 0) break;
|
|
|
- if (send(target_sock, buffer, bytes, 0) <= 0) break;
|
|
|
+ fd_set fds;
|
|
|
+ FD_ZERO(&fds);
|
|
|
+ FD_SET(client_sock, &fds);
|
|
|
+ FD_SET(target_sock, &fds);
|
|
|
+ struct timeval sel_tv = {300, 0};
|
|
|
+
|
|
|
+ if (select(max_fd + 1, &fds, NULL, NULL, &sel_tv) <= 0) break;
|
|
|
+
|
|
|
+ if (FD_ISSET(client_sock, &fds)) {
|
|
|
+ int b = recv(client_sock, buffer, BUFLEN, 0);
|
|
|
+ if (b <= 0) break;
|
|
|
+ send(target_sock, buffer, b, 0);
|
|
|
+ rx_bytes += b;
|
|
|
}
|
|
|
-
|
|
|
- // Del SSH al Cliente
|
|
|
- if (FD_ISSET(target_sock, &readfds)) {
|
|
|
- int bytes = recv(target_sock, buffer, sizeof(buffer), 0);
|
|
|
- if (bytes <= 0) break;
|
|
|
- if (send(client_sock, buffer, bytes, 0) <= 0) break;
|
|
|
+ if (FD_ISSET(target_sock, &fds)) {
|
|
|
+ int b = recv(target_sock, buffer, BUFLEN, 0);
|
|
|
+ if (b <= 0) break;
|
|
|
+ send(client_sock, buffer, b, 0);
|
|
|
+ tx_bytes += b;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
cleanup:
|
|
|
+ // Log de tráfico final
|
|
|
+ double total_mb = (double)(tx_bytes + rx_bytes) / (1024.0 * 1024.0);
|
|
|
+ if (total_mb > 0.01) {
|
|
|
+ char stat_msg[128];
|
|
|
+ snprintf(stat_msg, sizeof(stat_msg), "[*] Conexión finalizada. Tráfico consumido: %.2f MB", total_mb);
|
|
|
+ write_log(client_ip, stat_msg);
|
|
|
+ }
|
|
|
+
|
|
|
if (target_sock != -1) close(target_sock);
|
|
|
close(client_sock);
|
|
|
|
|
|
pthread_mutex_lock(&conn_mutex);
|
|
|
active_connections--;
|
|
|
pthread_mutex_unlock(&conn_mutex);
|
|
|
-
|
|
|
pthread_exit(NULL);
|
|
|
}
|
|
|
|
|
|
@@ -167,66 +194,63 @@ int main(int argc, char **argv) {
|
|
|
int port = DEFAULT_PORT;
|
|
|
if (argc > 1) port = atoi(argv[1]);
|
|
|
|
|
|
- // Ignorar SIGPIPE (Vital en C: evita que el servidor crashee si un cliente corta de golpe)
|
|
|
signal(SIGPIPE, SIG_IGN);
|
|
|
|
|
|
- int server_sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
+ int s_sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
int opt = 1;
|
|
|
- setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
|
|
+ setsockopt(s_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);
|
|
|
+ struct sockaddr_in s_addr;
|
|
|
+ s_addr.sin_family = AF_INET;
|
|
|
+ s_addr.sin_addr.s_addr = INADDR_ANY;
|
|
|
+ s_addr.sin_port = htons(port);
|
|
|
|
|
|
- if (bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
|
|
|
- perror("Fallo en bind");
|
|
|
- exit(EXIT_FAILURE);
|
|
|
+ if (bind(s_sock, (struct sockaddr *)&s_addr, sizeof(s_addr)) < 0) {
|
|
|
+ perror("Error Bind");
|
|
|
+ exit(1);
|
|
|
}
|
|
|
|
|
|
- if (listen(server_sock, 500) < 0) {
|
|
|
- perror("Fallo en listen");
|
|
|
- exit(EXIT_FAILURE);
|
|
|
- }
|
|
|
+ listen(s_sock, 500);
|
|
|
|
|
|
- printf("=====================================================\n");
|
|
|
- printf("🚀 PROXY NATIVO V3 (TCP) INICIADO - PUERTO %d\n", port);
|
|
|
- printf("🛡️ Fake Web: Nginx 1.24 | Agent: Gemini-Ultra-Robust-v3\n");
|
|
|
- printf("=====================================================\n");
|
|
|
+ write_log(NULL, "=====================================================");
|
|
|
+ char start_msg[128];
|
|
|
+ snprintf(start_msg, sizeof(start_msg), "🚀 PROXY NATIVO V3 (TCP) INICIADO - PUERTO %d", port);
|
|
|
+ write_log(NULL, start_msg);
|
|
|
+ write_log(NULL, "🛡️ Backlog: 500 | Fake-Web: Nginx 1.24 | Logs: ACTIVADOS");
|
|
|
+ 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;
|
|
|
+ struct sockaddr_in c_addr;
|
|
|
+ socklen_t c_len = sizeof(c_addr);
|
|
|
+ int c_sock = accept(s_sock, (struct sockaddr *)&c_addr, &c_len);
|
|
|
+ if (c_sock < 0) continue;
|
|
|
|
|
|
pthread_mutex_lock(&conn_mutex);
|
|
|
if (active_connections >= MAX_CONNECTIONS) {
|
|
|
pthread_mutex_unlock(&conn_mutex);
|
|
|
- close(client_sock);
|
|
|
+ close(c_sock);
|
|
|
continue;
|
|
|
}
|
|
|
active_connections++;
|
|
|
pthread_mutex_unlock(&conn_mutex);
|
|
|
|
|
|
- client_data_t *data = malloc(sizeof(client_data_t));
|
|
|
- data->client_fd = client_sock;
|
|
|
- data->addr = client_addr;
|
|
|
+ client_data_t *d = malloc(sizeof(client_data_t));
|
|
|
+ d->client_fd = c_sock;
|
|
|
+ d->addr = c_addr;
|
|
|
|
|
|
- pthread_t thread_id;
|
|
|
+ pthread_t tid;
|
|
|
pthread_attr_t attr;
|
|
|
pthread_attr_init(&attr);
|
|
|
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
|
|
|
|
|
- if (pthread_create(&thread_id, &attr, connection_handler, (void *)data) != 0) {
|
|
|
- close(client_sock);
|
|
|
- free(data);
|
|
|
+ if (pthread_create(&tid, &attr, connection_handler, d) != 0) {
|
|
|
+ close(c_sock);
|
|
|
+ free(d);
|
|
|
pthread_mutex_lock(&conn_mutex); active_connections--; pthread_mutex_unlock(&conn_mutex);
|
|
|
}
|
|
|
pthread_attr_destroy(&attr);
|
|
|
}
|
|
|
|
|
|
- close(server_sock);
|
|
|
+ close(s_sock);
|
|
|
return 0;
|
|
|
-}
|
|
|
+}
|