|
|
@@ -1,9 +1,8 @@
|
|
|
/*
|
|
|
* =====================================================================================
|
|
|
* PROXY VPN DUAL (TCP + TLS) - GRADO ENTERPRISE NATIVO EN C
|
|
|
- * Integra V3 (Plaintext) y V6 (SSL/TLS) con Mensajes Rotativos Dinámicos.
|
|
|
+ * Mejoras: Soporte DUAL-STACK (IPv4 e IPv6 simultáneo en el mismo puerto).
|
|
|
* 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)
|
|
|
* =====================================================================================
|
|
|
*/
|
|
|
|
|
|
@@ -28,59 +27,29 @@
|
|
|
#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"
|
|
|
|
|
|
-// --- FAKE WEB RESPONSES ---
|
|
|
-const char *FAKE_WEB_TCP =
|
|
|
- "HTTP/1.1 400 Bad Request\r\n"
|
|
|
- "Server: nginx/1.24.0\r\n"
|
|
|
- "Content-Type: text/html\r\n"
|
|
|
- "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";
|
|
|
-
|
|
|
-const char *FAKE_WEB_TLS =
|
|
|
- "HTTP/1.1 400 Bad Request\r\n"
|
|
|
- "Server: nginx/1.24.0\r\n"
|
|
|
- "Content-Type: text/html\r\n"
|
|
|
- "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";
|
|
|
-
|
|
|
-// --- MENSAJES ROTATIVOS ---
|
|
|
-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"
|
|
|
-};
|
|
|
+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<html><body><center><h1>400 Bad Request</h1></center><hr><center>nginx/1.24.0</center></body></html>\r\n";
|
|
|
+const char *FAKE_WEB_TLS = "HTTP/1.1 400 Bad Request\r\nServer: nginx/1.24.0\r\nContent-Type: text/html\r\nConnection: 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";
|
|
|
+
|
|
|
+const char *MENSAJES[] = {"🚀 CONEXION ESTABLECIDA", "🛡️ CIFRADO MILITAR ACTIVO", "Pfsense", "OPNsense", "VyOS", "Claro", "Altice", "🌐 BYPASS 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 MODIFICADA: Usamos sockaddr_storage para soportar tanto IPv4 como IPv6
|
|
|
typedef struct {
|
|
|
int client_fd;
|
|
|
- struct sockaddr_in addr;
|
|
|
- int is_tls; // 1 = TLS (443), 0 = TCP (80)
|
|
|
+ struct sockaddr_storage addr;
|
|
|
+ int is_tls;
|
|
|
SSL_CTX *ssl_ctx;
|
|
|
} client_data_t;
|
|
|
|
|
|
-// --- 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");
|
|
|
@@ -100,36 +69,52 @@ 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 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("⚠️ Sin certificados en %s. TLS fallará.\n", CERT_FILE);
|
|
|
- }
|
|
|
+ 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;
|
|
|
}
|
|
|
|
|
|
+// CREACIÓN DE SOCKET DUAL-STACK
|
|
|
int create_server_socket(int port) {
|
|
|
- int s_sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
+ // 1. Crear socket IPv6 (AF_INET6)
|
|
|
+ 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));
|
|
|
- struct sockaddr_in addr;
|
|
|
- addr.sin_family = AF_INET;
|
|
|
- addr.sin_addr.s_addr = INADDR_ANY;
|
|
|
- addr.sin_port = htons(port);
|
|
|
+
|
|
|
+ // 2. MAGIA DUAL-STACK: Apagar la restricción de solo-IPv6
|
|
|
+ int no = 0;
|
|
|
+ setsockopt(s_sock, IPPROTO_IPV6, IPV6_V6ONLY, &no, sizeof(no));
|
|
|
+
|
|
|
+ // 3. Bind a in6addr_any (Equivale a "::")
|
|
|
+ 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;
|
|
|
}
|
|
|
|
|
|
-// --- HILO TRABAJADOR (TCP o TLS) ---
|
|
|
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[INET_ADDRSTRLEN];
|
|
|
- inet_ntop(AF_INET, &(data->addr.sin_addr), client_ip, INET_ADDRSTRLEN);
|
|
|
+ // EXTRAER IP (IPv4 o IPv6)
|
|
|
+ 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 { // AF_INET6
|
|
|
+ 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";
|
|
|
@@ -149,65 +134,39 @@ void *connection_handler(void *arg) {
|
|
|
setsockopt(client_sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
|
|
|
|
|
|
char buffer[BUFLEN];
|
|
|
- int bytes_read = 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 bytes_read = is_tls ? SSL_read(ssl, buffer, sizeof(buffer)-1) : 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) {
|
|
|
- write_log(client_ip, proto_name, "❌ Error conectando a SSH");
|
|
|
- goto cleanup;
|
|
|
- }
|
|
|
+ if (connect(target_sock, (struct sockaddr *)&t_addr, sizeof(t_addr)) < 0) goto cleanup;
|
|
|
|
|
|
if (strncmp(buffer, "SSH-", 4) == 0) {
|
|
|
- write_log(client_ip, proto_name, "✅ Túnel SSH Directo");
|
|
|
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. Enviando Fake Web.");
|
|
|
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 {
|
|
|
- // --- 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);
|
|
|
- }
|
|
|
+ snprintf(response, sizeof(response),
|
|
|
+ "HTTP/1.1 101 %s\r\nServer: nginx/1.24.0\r\nX-Proxy-Agent: Gemini-Ultra-Dual\r\nConnection: Upgrade\r\nUpgrade: 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 {
|
|
|
struct sockaddr_in t_addr;
|
|
|
@@ -215,9 +174,7 @@ void *connection_handler(void *arg) {
|
|
|
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, proto_name, "✅ Túnel Modo Silencioso");
|
|
|
- } else goto cleanup;
|
|
|
+ if (connect(target_sock, (struct sockaddr *)&t_addr, sizeof(t_addr)) != 0) goto cleanup;
|
|
|
}
|
|
|
|
|
|
tv.tv_sec = 0;
|
|
|
@@ -225,13 +182,10 @@ void *connection_handler(void *arg) {
|
|
|
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);
|
|
|
+ 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;
|
|
|
}
|
|
|
@@ -242,7 +196,6 @@ void *connection_handler(void *arg) {
|
|
|
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;
|
|
|
@@ -252,105 +205,55 @@ void *connection_handler(void *arg) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-cleanup: ; // <-- AQUÍ ESTÁ LA MAGIA QUE SOLUCIONA TU ERROR (El punto y coma vacío)
|
|
|
- double total_mb = (double)(tx_bytes + rx_bytes) / (1024.0 * 1024.0);
|
|
|
- if (total_mb > 0.05) {
|
|
|
- char stat_msg[128];
|
|
|
- snprintf(stat_msg, sizeof(stat_msg), "[*] Tráfico final: %.2f MB", total_mb);
|
|
|
- write_log(client_ip, proto_name, stat_msg);
|
|
|
- }
|
|
|
-
|
|
|
+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);
|
|
|
}
|
|
|
|
|
|
-// --- HILO MAESTRO ---
|
|
|
int main(int argc, char **argv) {
|
|
|
- int port_tcp = DEFAULT_PORT_TCP;
|
|
|
- int port_tls = DEFAULT_PORT_TLS;
|
|
|
-
|
|
|
- if (argc >= 3) {
|
|
|
- port_tcp = atoi(argv[1]);
|
|
|
- port_tls = atoi(argv[2]);
|
|
|
- }
|
|
|
+ int port_tcp = DEFAULT_PORT_TCP, port_tls = DEFAULT_PORT_TLS;
|
|
|
+ if (argc >= 3) { port_tcp = atoi(argv[1]); port_tls = atoi(argv[2]); }
|
|
|
|
|
|
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) {
|
|
|
- printf("Error iniciando sockets. ¿Tienes permisos root para puertos bajos?\n");
|
|
|
- exit(1);
|
|
|
- }
|
|
|
+ if (server_tcp < 0 || server_tls < 0) exit(1);
|
|
|
|
|
|
- write_log(NULL, "SISTEMA", "=====================================================");
|
|
|
- char msg[256];
|
|
|
- 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", "=====================================================");
|
|
|
+ write_log(NULL, "SISTEMA", "🚀 PROXY DUAL ENTERPRISE INICIADO (Soporte IPv4 + IPv6)");
|
|
|
|
|
|
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);
|
|
|
-
|
|
|
+ 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;
|
|
|
- int 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;
|
|
|
- }
|
|
|
+ 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_in c_addr;
|
|
|
+ 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);
|
|
|
+ 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);
|
|
|
-
|
|
|
+ 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);
|
|
|
}
|
|
|
-
|
|
|
- close(server_tcp);
|
|
|
- close(server_tls);
|
|
|
- SSL_CTX_free(ctx);
|
|
|
return 0;
|
|
|
}
|