1043 lines
36 KiB
C
1043 lines
36 KiB
C
/**
|
||
* Phantom Client - Простой клиент для работы с Phantom сетью
|
||
*
|
||
* Эта утилита позволяет обычным пользователям легко подключаться
|
||
* к Phantom сети и использовать её для анонимной передачи данных.
|
||
*
|
||
* Примеры использования:
|
||
* ./phantom-client --connect # Подключение к сети
|
||
* ./phantom-client --send "Hello" node123 # Отправка сообщения
|
||
* ./phantom-client --proxy 8080 # SOCKS5 прокси на порту 8080
|
||
* ./phantom-client --tunnel 22 remote.phantom # SSH туннель
|
||
*
|
||
* Автор: Phantom Protocol Team 2025
|
||
* Версия: 1.0.0
|
||
*/
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <unistd.h>
|
||
#include <getopt.h>
|
||
#include <signal.h>
|
||
#include <sys/socket.h>
|
||
#include <netinet/in.h>
|
||
#include <arpa/inet.h>
|
||
#include <pthread.h>
|
||
#include <time.h>
|
||
#include <errno.h>
|
||
|
||
// Включение основных модулей Phantom
|
||
#include "../src/config.h"
|
||
#include "../src/kademlia.h"
|
||
#include "../src/path.h"
|
||
#include "../src/server.h"
|
||
|
||
#define PHANTOM_CLIENT_VERSION "1.0.0"
|
||
#define MAX_MESSAGE_SIZE 4096
|
||
#define MAX_NODES 100
|
||
#define DEFAULT_PHANTOM_PORT 8050
|
||
|
||
// Структура клиента Phantom
|
||
typedef struct {
|
||
bool is_connected;
|
||
bool is_running;
|
||
char local_node_id[64];
|
||
char phantom_address[64];
|
||
uint16_t phantom_port;
|
||
|
||
// Сетевые настройки
|
||
int phantom_socket;
|
||
struct sockaddr_in phantom_addr;
|
||
|
||
// Прокси настройки
|
||
bool proxy_enabled;
|
||
uint16_t proxy_port;
|
||
int proxy_socket;
|
||
pthread_t proxy_thread;
|
||
|
||
// Туннель настройки
|
||
bool tunnel_enabled;
|
||
uint16_t local_port;
|
||
char remote_host[256];
|
||
uint16_t remote_port;
|
||
pthread_t tunnel_thread;
|
||
|
||
// Статистика
|
||
uint64_t bytes_sent;
|
||
uint64_t bytes_received;
|
||
uint32_t connections_count;
|
||
time_t start_time;
|
||
} phantom_client_t;
|
||
|
||
// Глобальная переменная клиента
|
||
static phantom_client_t *g_client = NULL;
|
||
|
||
// Прототипы функций
|
||
phantom_client_t* phantom_client_create(void);
|
||
int phantom_client_connect(phantom_client_t *client, const char *address, uint16_t port);
|
||
int phantom_client_disconnect(phantom_client_t *client);
|
||
int phantom_client_send_message(phantom_client_t *client, const char *message, const char *target);
|
||
int phantom_client_start_proxy(phantom_client_t *client, uint16_t port);
|
||
int phantom_client_start_tunnel(phantom_client_t *client, uint16_t local_port, const char *remote_host, uint16_t remote_port);
|
||
void phantom_client_show_status(phantom_client_t *client);
|
||
void phantom_client_show_help(void);
|
||
void phantom_client_signal_handler(int signal);
|
||
void phantom_client_destroy(phantom_client_t *client);
|
||
|
||
/**
|
||
* Создание клиента Phantom
|
||
*/
|
||
phantom_client_t* phantom_client_create(void) {
|
||
phantom_client_t *client = calloc(1, sizeof(phantom_client_t));
|
||
if (!client) {
|
||
fprintf(stderr, "Не удалось выделить память для клиента\n");
|
||
return NULL;
|
||
}
|
||
|
||
// Инициализация значений по умолчанию
|
||
client->is_connected = false;
|
||
client->is_running = false;
|
||
client->phantom_port = DEFAULT_PHANTOM_PORT;
|
||
strcpy(client->phantom_address, "127.0.0.1");
|
||
client->phantom_socket = -1;
|
||
client->proxy_socket = -1;
|
||
|
||
// Генерация уникального ID клиента
|
||
snprintf(client->local_node_id, sizeof(client->local_node_id),
|
||
"client-%ld-%d", time(NULL), getpid());
|
||
|
||
client->start_time = time(NULL);
|
||
|
||
printf("Phantom Client создан (ID: %s)\n", client->local_node_id);
|
||
return client;
|
||
}
|
||
|
||
/**
|
||
* Подключение к Phantom сети
|
||
*/
|
||
int phantom_client_connect(phantom_client_t *client, const char *address, uint16_t port) {
|
||
if (!client) {
|
||
return -1;
|
||
}
|
||
|
||
if (client->is_connected) {
|
||
printf("Клиент уже подключен к сети\n");
|
||
return 0;
|
||
}
|
||
|
||
printf("Подключение к Phantom сети %s:%d...\n", address, port);
|
||
|
||
// Сохранение параметров подключения
|
||
strncpy(client->phantom_address, address, sizeof(client->phantom_address) - 1);
|
||
client->phantom_port = port;
|
||
|
||
// Создание сокета
|
||
client->phantom_socket = socket(AF_INET, SOCK_STREAM, 0);
|
||
if (client->phantom_socket < 0) {
|
||
perror("socket");
|
||
return -1;
|
||
}
|
||
|
||
// Настройка адреса сервера
|
||
memset(&client->phantom_addr, 0, sizeof(client->phantom_addr));
|
||
client->phantom_addr.sin_family = AF_INET;
|
||
client->phantom_addr.sin_port = htons(port);
|
||
|
||
if (inet_pton(AF_INET, address, &client->phantom_addr.sin_addr) <= 0) {
|
||
fprintf(stderr, "Неверный IP адрес: %s\n", address);
|
||
close(client->phantom_socket);
|
||
client->phantom_socket = -1;
|
||
return -1;
|
||
}
|
||
|
||
// Подключение к серверу
|
||
if (connect(client->phantom_socket, (struct sockaddr*)&client->phantom_addr,
|
||
sizeof(client->phantom_addr)) < 0) {
|
||
perror("connect");
|
||
close(client->phantom_socket);
|
||
client->phantom_socket = -1;
|
||
return -1;
|
||
}
|
||
|
||
// Отправка приветственного сообщения
|
||
char hello_msg[256];
|
||
snprintf(hello_msg, sizeof(hello_msg),
|
||
"PHANTOM_HELLO %s CLIENT %s",
|
||
client->local_node_id, PHANTOM_CLIENT_VERSION);
|
||
|
||
if (send(client->phantom_socket, hello_msg, strlen(hello_msg), 0) < 0) {
|
||
perror("send hello");
|
||
close(client->phantom_socket);
|
||
client->phantom_socket = -1;
|
||
return -1;
|
||
}
|
||
|
||
// Ожидание ответа
|
||
char response[256];
|
||
ssize_t received = recv(client->phantom_socket, response, sizeof(response) - 1, 0);
|
||
if (received <= 0) {
|
||
fprintf(stderr, "Не получен ответ от сервера\n");
|
||
close(client->phantom_socket);
|
||
client->phantom_socket = -1;
|
||
return -1;
|
||
}
|
||
|
||
response[received] = '\0';
|
||
|
||
if (strncmp(response, "PHANTOM_WELCOME", 15) != 0) {
|
||
fprintf(stderr, "Неожиданный ответ сервера: %s\n", response);
|
||
close(client->phantom_socket);
|
||
client->phantom_socket = -1;
|
||
return -1;
|
||
}
|
||
|
||
client->is_connected = true;
|
||
client->is_running = true;
|
||
|
||
printf("✅ Успешно подключен к Phantom сети!\n");
|
||
printf(" Узел ID: %s\n", client->local_node_id);
|
||
printf(" Сервер: %s:%d\n", address, port);
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* Отключение от Phantom сети
|
||
*/
|
||
int phantom_client_disconnect(phantom_client_t *client) {
|
||
if (!client || !client->is_connected) {
|
||
return 0;
|
||
}
|
||
|
||
printf("Отключение от Phantom сети...\n");
|
||
|
||
client->is_running = false;
|
||
|
||
// Остановка прокси
|
||
if (client->proxy_enabled) {
|
||
client->proxy_enabled = false;
|
||
if (client->proxy_socket >= 0) {
|
||
close(client->proxy_socket);
|
||
client->proxy_socket = -1;
|
||
}
|
||
pthread_cancel(client->proxy_thread);
|
||
}
|
||
|
||
// Остановка туннеля
|
||
if (client->tunnel_enabled) {
|
||
client->tunnel_enabled = false;
|
||
pthread_cancel(client->tunnel_thread);
|
||
}
|
||
|
||
// Отправка сообщения об отключении
|
||
if (client->phantom_socket >= 0) {
|
||
char goodbye_msg[128];
|
||
snprintf(goodbye_msg, sizeof(goodbye_msg),
|
||
"PHANTOM_GOODBYE %s", client->local_node_id);
|
||
send(client->phantom_socket, goodbye_msg, strlen(goodbye_msg), 0);
|
||
|
||
close(client->phantom_socket);
|
||
client->phantom_socket = -1;
|
||
}
|
||
|
||
client->is_connected = false;
|
||
|
||
printf("✅ Отключен от Phantom сети\n");
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* Отправка сообщения через Phantom сеть
|
||
*/
|
||
int phantom_client_send_message(phantom_client_t *client, const char *message, const char *target) {
|
||
if (!client || !client->is_connected || !message || !target) {
|
||
return -1;
|
||
}
|
||
|
||
printf("Отправка сообщения '%s' узлу %s...\n", message, target);
|
||
|
||
// Формирование пакета сообщения
|
||
char packet[MAX_MESSAGE_SIZE];
|
||
snprintf(packet, sizeof(packet),
|
||
"PHANTOM_MESSAGE %s %s %zu %s",
|
||
client->local_node_id, target, strlen(message), message);
|
||
|
||
// Отправка через Phantom сеть
|
||
ssize_t sent = send(client->phantom_socket, packet, strlen(packet), 0);
|
||
if (sent < 0) {
|
||
perror("send message");
|
||
return -1;
|
||
}
|
||
|
||
client->bytes_sent += sent;
|
||
|
||
// Ожидание подтверждения
|
||
char response[256];
|
||
ssize_t received = recv(client->phantom_socket, response, sizeof(response) - 1, 0);
|
||
if (received > 0) {
|
||
response[received] = '\0';
|
||
client->bytes_received += received;
|
||
|
||
if (strncmp(response, "PHANTOM_ACK", 11) == 0) {
|
||
printf("✅ Сообщение доставлено\n");
|
||
return 0;
|
||
} else if (strncmp(response, "PHANTOM_ERROR", 13) == 0) {
|
||
printf("❌ Ошибка доставки: %s\n", response + 14);
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
printf("⚠️ Статус доставки неизвестен\n");
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* Запуск SOCKS5 прокси
|
||
*/
|
||
int phantom_client_start_proxy(phantom_client_t *client, uint16_t port) {
|
||
if (!client || !client->is_connected) {
|
||
fprintf(stderr, "Клиент не подключен к сети\n");
|
||
return -1;
|
||
}
|
||
|
||
if (client->proxy_enabled) {
|
||
printf("Прокси уже запущен на порту %d\n", client->proxy_port);
|
||
return 0;
|
||
}
|
||
|
||
printf("Запуск SOCKS5 прокси на порту %d...\n", port);
|
||
|
||
// Создание серверного сокета
|
||
client->proxy_socket = socket(AF_INET, SOCK_STREAM, 0);
|
||
if (client->proxy_socket < 0) {
|
||
perror("socket");
|
||
return -1;
|
||
}
|
||
|
||
// Разрешение повторного использования адреса
|
||
int opt = 1;
|
||
setsockopt(client->proxy_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
||
|
||
// Настройка адреса прокси
|
||
struct sockaddr_in proxy_addr;
|
||
memset(&proxy_addr, 0, sizeof(proxy_addr));
|
||
proxy_addr.sin_family = AF_INET;
|
||
proxy_addr.sin_addr.s_addr = INADDR_ANY;
|
||
proxy_addr.sin_port = htons(port);
|
||
|
||
// Привязка сокета
|
||
if (bind(client->proxy_socket, (struct sockaddr*)&proxy_addr, sizeof(proxy_addr)) < 0) {
|
||
perror("bind");
|
||
close(client->proxy_socket);
|
||
client->proxy_socket = -1;
|
||
return -1;
|
||
}
|
||
|
||
// Прослушивание подключений
|
||
if (listen(client->proxy_socket, 10) < 0) {
|
||
perror("listen");
|
||
close(client->proxy_socket);
|
||
client->proxy_socket = -1;
|
||
return -1;
|
||
}
|
||
|
||
client->proxy_port = port;
|
||
client->proxy_enabled = true;
|
||
|
||
// Запуск потока прокси
|
||
if (pthread_create(&client->proxy_thread, NULL, phantom_proxy_thread, client) != 0) {
|
||
perror("pthread_create");
|
||
close(client->proxy_socket);
|
||
client->proxy_socket = -1;
|
||
client->proxy_enabled = false;
|
||
return -1;
|
||
}
|
||
|
||
printf("✅ SOCKS5 прокси запущен на порту %d\n", port);
|
||
printf(" Настройте браузер: 127.0.0.1:%d\n", port);
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* Поток SOCKS5 прокси
|
||
*/
|
||
void* phantom_proxy_thread(void *arg) {
|
||
phantom_client_t *client = (phantom_client_t*)arg;
|
||
|
||
printf("Поток SOCKS5 прокси запущен\n");
|
||
|
||
while (client->proxy_enabled && client->is_running) {
|
||
struct sockaddr_in client_addr;
|
||
socklen_t client_len = sizeof(client_addr);
|
||
|
||
// Принятие подключения
|
||
int client_sock = accept(client->proxy_socket,
|
||
(struct sockaddr*)&client_addr, &client_len);
|
||
|
||
if (client_sock < 0) {
|
||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||
usleep(100000); // 100ms
|
||
continue;
|
||
}
|
||
perror("accept");
|
||
continue;
|
||
}
|
||
|
||
client->connections_count++;
|
||
|
||
// Обработка SOCKS5 подключения в отдельном потоке
|
||
pthread_t connection_thread;
|
||
phantom_proxy_connection_t *conn_data = malloc(sizeof(phantom_proxy_connection_t));
|
||
if (conn_data) {
|
||
conn_data->client = client;
|
||
conn_data->client_socket = client_sock;
|
||
|
||
if (pthread_create(&connection_thread, NULL,
|
||
phantom_proxy_connection_thread, conn_data) == 0) {
|
||
pthread_detach(connection_thread);
|
||
} else {
|
||
close(client_sock);
|
||
free(conn_data);
|
||
}
|
||
} else {
|
||
close(client_sock);
|
||
}
|
||
}
|
||
|
||
printf("Поток SOCKS5 прокси завершен\n");
|
||
return NULL;
|
||
}
|
||
|
||
/**
|
||
* Структура данных подключения прокси
|
||
*/
|
||
typedef struct {
|
||
phantom_client_t *client;
|
||
int client_socket;
|
||
} phantom_proxy_connection_t;
|
||
|
||
/**
|
||
* Поток обработки подключения прокси
|
||
*/
|
||
void* phantom_proxy_connection_thread(void *arg) {
|
||
phantom_proxy_connection_t *conn = (phantom_proxy_connection_t*)arg;
|
||
|
||
// Простая реализация SOCKS5
|
||
char buffer[4096];
|
||
|
||
// Чтение запроса аутентификации SOCKS5
|
||
ssize_t received = recv(conn->client_socket, buffer, sizeof(buffer), 0);
|
||
if (received < 3) {
|
||
close(conn->client_socket);
|
||
free(conn);
|
||
return NULL;
|
||
}
|
||
|
||
// Проверка версии SOCKS
|
||
if (buffer[0] != 0x05) {
|
||
close(conn->client_socket);
|
||
free(conn);
|
||
return NULL;
|
||
}
|
||
|
||
// Ответ: без аутентификации
|
||
char auth_response[2] = {0x05, 0x00};
|
||
send(conn->client_socket, auth_response, 2, 0);
|
||
|
||
// Чтение запроса подключения
|
||
received = recv(conn->client_socket, buffer, sizeof(buffer), 0);
|
||
if (received < 10) {
|
||
close(conn->client_socket);
|
||
free(conn);
|
||
return NULL;
|
||
}
|
||
|
||
// Извлечение целевого адреса
|
||
char target_host[256];
|
||
uint16_t target_port;
|
||
|
||
if (buffer[3] == 0x01) { // IPv4
|
||
struct in_addr addr;
|
||
memcpy(&addr, buffer + 4, 4);
|
||
inet_ntop(AF_INET, &addr, target_host, sizeof(target_host));
|
||
memcpy(&target_port, buffer + 8, 2);
|
||
target_port = ntohs(target_port);
|
||
} else if (buffer[3] == 0x03) { // Доменное имя
|
||
uint8_t domain_len = buffer[4];
|
||
memcpy(target_host, buffer + 5, domain_len);
|
||
target_host[domain_len] = '\0';
|
||
memcpy(&target_port, buffer + 5 + domain_len, 2);
|
||
target_port = ntohs(target_port);
|
||
} else {
|
||
// Неподдерживаемый тип адреса
|
||
char error_response[10] = {0x05, 0x08, 0x00, 0x01, 0, 0, 0, 0, 0, 0};
|
||
send(conn->client_socket, error_response, 10, 0);
|
||
close(conn->client_socket);
|
||
free(conn);
|
||
return NULL;
|
||
}
|
||
|
||
printf("SOCKS5: Подключение к %s:%d через Phantom\n", target_host, target_port);
|
||
|
||
// Создание туннеля через Phantom сеть
|
||
char tunnel_request[512];
|
||
snprintf(tunnel_request, sizeof(tunnel_request),
|
||
"PHANTOM_TUNNEL %s %s %d",
|
||
conn->client->local_node_id, target_host, target_port);
|
||
|
||
if (send(conn->client->phantom_socket, tunnel_request, strlen(tunnel_request), 0) < 0) {
|
||
// Ошибка подключения
|
||
char error_response[10] = {0x05, 0x01, 0x00, 0x01, 0, 0, 0, 0, 0, 0};
|
||
send(conn->client_socket, error_response, 10, 0);
|
||
close(conn->client_socket);
|
||
free(conn);
|
||
return NULL;
|
||
}
|
||
|
||
// Успешное подключение
|
||
char success_response[10] = {0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0};
|
||
send(conn->client_socket, success_response, 10, 0);
|
||
|
||
// Проксирование данных между клиентом и Phantom сетью
|
||
phantom_proxy_relay_data(conn);
|
||
|
||
close(conn->client_socket);
|
||
free(conn);
|
||
return NULL;
|
||
}
|
||
|
||
/**
|
||
* Проксирование данных
|
||
*/
|
||
void phantom_proxy_relay_data(phantom_proxy_connection_t *conn) {
|
||
fd_set read_fds;
|
||
int max_fd = (conn->client_socket > conn->client->phantom_socket) ?
|
||
conn->client_socket : conn->client->phantom_socket;
|
||
|
||
char buffer[4096];
|
||
|
||
while (conn->client->is_running) {
|
||
FD_ZERO(&read_fds);
|
||
FD_SET(conn->client_socket, &read_fds);
|
||
FD_SET(conn->client->phantom_socket, &read_fds);
|
||
|
||
struct timeval timeout = {1, 0}; // 1 секунда
|
||
int activity = select(max_fd + 1, &read_fds, NULL, NULL, &timeout);
|
||
|
||
if (activity < 0) {
|
||
break;
|
||
}
|
||
|
||
if (activity == 0) {
|
||
continue; // Таймаут
|
||
}
|
||
|
||
// Данные от клиента к Phantom
|
||
if (FD_ISSET(conn->client_socket, &read_fds)) {
|
||
ssize_t received = recv(conn->client_socket, buffer, sizeof(buffer), 0);
|
||
if (received <= 0) {
|
||
break;
|
||
}
|
||
|
||
if (send(conn->client->phantom_socket, buffer, received, 0) <= 0) {
|
||
break;
|
||
}
|
||
|
||
conn->client->bytes_sent += received;
|
||
}
|
||
|
||
// Данные от Phantom к клиенту
|
||
if (FD_ISSET(conn->client->phantom_socket, &read_fds)) {
|
||
ssize_t received = recv(conn->client->phantom_socket, buffer, sizeof(buffer), 0);
|
||
if (received <= 0) {
|
||
break;
|
||
}
|
||
|
||
if (send(conn->client_socket, buffer, received, 0) <= 0) {
|
||
break;
|
||
}
|
||
|
||
conn->client->bytes_received += received;
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Запуск туннеля
|
||
*/
|
||
int phantom_client_start_tunnel(phantom_client_t *client, uint16_t local_port,
|
||
const char *remote_host, uint16_t remote_port) {
|
||
if (!client || !client->is_connected || !remote_host) {
|
||
return -1;
|
||
}
|
||
|
||
if (client->tunnel_enabled) {
|
||
printf("Туннель уже активен\n");
|
||
return 0;
|
||
}
|
||
|
||
printf("Создание туннеля %d -> %s:%d через Phantom...\n",
|
||
local_port, remote_host, remote_port);
|
||
|
||
client->local_port = local_port;
|
||
strncpy(client->remote_host, remote_host, sizeof(client->remote_host) - 1);
|
||
client->remote_port = remote_port;
|
||
client->tunnel_enabled = true;
|
||
|
||
// Запуск потока туннеля
|
||
if (pthread_create(&client->tunnel_thread, NULL, phantom_tunnel_thread, client) != 0) {
|
||
perror("pthread_create");
|
||
client->tunnel_enabled = false;
|
||
return -1;
|
||
}
|
||
|
||
printf("✅ Туннель создан: localhost:%d -> %s:%d\n",
|
||
local_port, remote_host, remote_port);
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* Поток туннеля
|
||
*/
|
||
void* phantom_tunnel_thread(void *arg) {
|
||
phantom_client_t *client = (phantom_client_t*)arg;
|
||
|
||
printf("Поток туннеля запущен\n");
|
||
|
||
// Создание серверного сокета для туннеля
|
||
int tunnel_socket = socket(AF_INET, SOCK_STREAM, 0);
|
||
if (tunnel_socket < 0) {
|
||
perror("socket");
|
||
return NULL;
|
||
}
|
||
|
||
int opt = 1;
|
||
setsockopt(tunnel_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
||
|
||
struct sockaddr_in tunnel_addr;
|
||
memset(&tunnel_addr, 0, sizeof(tunnel_addr));
|
||
tunnel_addr.sin_family = AF_INET;
|
||
tunnel_addr.sin_addr.s_addr = INADDR_ANY;
|
||
tunnel_addr.sin_port = htons(client->local_port);
|
||
|
||
if (bind(tunnel_socket, (struct sockaddr*)&tunnel_addr, sizeof(tunnel_addr)) < 0) {
|
||
perror("bind");
|
||
close(tunnel_socket);
|
||
return NULL;
|
||
}
|
||
|
||
if (listen(tunnel_socket, 5) < 0) {
|
||
perror("listen");
|
||
close(tunnel_socket);
|
||
return NULL;
|
||
}
|
||
|
||
while (client->tunnel_enabled && client->is_running) {
|
||
struct sockaddr_in client_addr;
|
||
socklen_t client_len = sizeof(client_addr);
|
||
|
||
int client_sock = accept(tunnel_socket, (struct sockaddr*)&client_addr, &client_len);
|
||
if (client_sock < 0) {
|
||
continue;
|
||
}
|
||
|
||
// Создание туннеля через Phantom для этого подключения
|
||
phantom_handle_tunnel_connection(client, client_sock);
|
||
}
|
||
|
||
close(tunnel_socket);
|
||
printf("Поток туннеля завершен\n");
|
||
return NULL;
|
||
}
|
||
|
||
/**
|
||
* Обработка подключения туннеля
|
||
*/
|
||
void phantom_handle_tunnel_connection(phantom_client_t *client, int client_sock) {
|
||
printf("Новое подключение к туннелю\n");
|
||
|
||
// Отправка запроса на создание туннеля через Phantom
|
||
char tunnel_request[512];
|
||
snprintf(tunnel_request, sizeof(tunnel_request),
|
||
"PHANTOM_TUNNEL %s %s %d",
|
||
client->local_node_id, client->remote_host, client->remote_port);
|
||
|
||
if (send(client->phantom_socket, tunnel_request, strlen(tunnel_request), 0) < 0) {
|
||
close(client_sock);
|
||
return;
|
||
}
|
||
|
||
// Простое проксирование данных
|
||
char buffer[4096];
|
||
fd_set read_fds;
|
||
int max_fd = (client_sock > client->phantom_socket) ? client_sock : client->phantom_socket;
|
||
|
||
while (client->is_running) {
|
||
FD_ZERO(&read_fds);
|
||
FD_SET(client_sock, &read_fds);
|
||
FD_SET(client->phantom_socket, &read_fds);
|
||
|
||
struct timeval timeout = {1, 0};
|
||
int activity = select(max_fd + 1, &read_fds, NULL, NULL, &timeout);
|
||
|
||
if (activity <= 0) {
|
||
break;
|
||
}
|
||
|
||
if (FD_ISSET(client_sock, &read_fds)) {
|
||
ssize_t received = recv(client_sock, buffer, sizeof(buffer), 0);
|
||
if (received <= 0) break;
|
||
|
||
if (send(client->phantom_socket, buffer, received, 0) <= 0) break;
|
||
client->bytes_sent += received;
|
||
}
|
||
|
||
if (FD_ISSET(client->phantom_socket, &read_fds)) {
|
||
ssize_t received = recv(client->phantom_socket, buffer, sizeof(buffer), 0);
|
||
if (received <= 0) break;
|
||
|
||
if (send(client_sock, buffer, received, 0) <= 0) break;
|
||
client->bytes_received += received;
|
||
}
|
||
}
|
||
|
||
close(client_sock);
|
||
}
|
||
|
||
/**
|
||
* Показ статуса клиента
|
||
*/
|
||
void phantom_client_show_status(phantom_client_t *client) {
|
||
if (!client) {
|
||
return;
|
||
}
|
||
|
||
printf("\n=== Статус Phantom Client ===\n");
|
||
printf("Версия: %s\n", PHANTOM_CLIENT_VERSION);
|
||
printf("ID узла: %s\n", client->local_node_id);
|
||
printf("Состояние: %s\n", client->is_connected ? "Подключен" : "Отключен");
|
||
|
||
if (client->is_connected) {
|
||
printf("Сервер: %s:%d\n", client->phantom_address, client->phantom_port);
|
||
|
||
time_t uptime = time(NULL) - client->start_time;
|
||
printf("Время работы: %ld сек\n", uptime);
|
||
|
||
printf("Отправлено: %llu байт\n", client->bytes_sent);
|
||
printf("Получено: %llu байт\n", client->bytes_received);
|
||
printf("Подключений: %u\n", client->connections_count);
|
||
|
||
if (client->proxy_enabled) {
|
||
printf("SOCKS5 прокси: активен на порту %d\n", client->proxy_port);
|
||
}
|
||
|
||
if (client->tunnel_enabled) {
|
||
printf("Туннель: %d -> %s:%d\n",
|
||
client->local_port, client->remote_host, client->remote_port);
|
||
}
|
||
}
|
||
printf("=============================\n\n");
|
||
}
|
||
|
||
/**
|
||
* Показ справки
|
||
*/
|
||
void phantom_client_show_help(void) {
|
||
printf("Phantom Client v%s - Клиент для работы с Phantom сетью\n\n", PHANTOM_CLIENT_VERSION);
|
||
printf("Использование:\n");
|
||
printf(" phantom-client [ОПЦИИ]\n\n");
|
||
printf("Опции:\n");
|
||
printf(" -c, --connect [АДРЕС:ПОРТ] Подключиться к Phantom сети\n");
|
||
printf(" -d, --disconnect Отключиться от сети\n");
|
||
printf(" -s, --send СООБЩЕНИЕ УЗЕЛ Отправить сообщение узлу\n");
|
||
printf(" -p, --proxy ПОРТ Запустить SOCKS5 прокси\n");
|
||
printf(" -t, --tunnel ПОРТ:ХОСТ:ПОРТ Создать туннель\n");
|
||
printf(" -S, --status Показать статус\n");
|
||
printf(" -i, --interactive Интерактивный режим\n");
|
||
printf(" -h, --help Показать эту справку\n\n");
|
||
printf("Примеры:\n");
|
||
printf(" phantom-client --connect # Подключение к локальному серверу\n");
|
||
printf(" phantom-client --connect 192.168.1.100:8050 # Подключение к удаленному серверу\n");
|
||
printf(" phantom-client --proxy 8080 # SOCKS5 прокси на порту 8080\n");
|
||
printf(" phantom-client --tunnel 2222:remote.phantom:22 # SSH туннель\n");
|
||
printf(" phantom-client --send \"Hello\" node123 # Отправка сообщения\n\n");
|
||
}
|
||
|
||
/**
|
||
* Обработчик сигналов
|
||
*/
|
||
void phantom_client_signal_handler(int signal) {
|
||
printf("\nПолучен сигнал %d, завершение работы...\n", signal);
|
||
|
||
if (g_client) {
|
||
phantom_client_disconnect(g_client);
|
||
}
|
||
|
||
exit(0);
|
||
}
|
||
|
||
/**
|
||
* Уничтожение клиента
|
||
*/
|
||
void phantom_client_destroy(phantom_client_t *client) {
|
||
if (!client) {
|
||
return;
|
||
}
|
||
|
||
phantom_client_disconnect(client);
|
||
free(client);
|
||
}
|
||
|
||
/**
|
||
* Интерактивный режим
|
||
*/
|
||
void phantom_client_interactive_mode(phantom_client_t *client) {
|
||
char input[512];
|
||
char command[64], arg1[256], arg2[256];
|
||
|
||
printf("\n=== Интерактивный режим Phantom Client ===\n");
|
||
printf("Введите 'help' для списка команд\n\n");
|
||
|
||
while (client->is_running) {
|
||
printf("phantom> ");
|
||
fflush(stdout);
|
||
|
||
if (!fgets(input, sizeof(input), stdin)) {
|
||
break;
|
||
}
|
||
|
||
// Удаление символа новой строки
|
||
input[strcspn(input, "\n")] = 0;
|
||
|
||
// Парсинг команды
|
||
int args = sscanf(input, "%s %s %s", command, arg1, arg2);
|
||
|
||
if (args == 0) {
|
||
continue;
|
||
}
|
||
|
||
if (strcmp(command, "help") == 0) {
|
||
printf("Доступные команды:\n");
|
||
printf(" connect [адрес:порт] - Подключиться к сети\n");
|
||
printf(" disconnect - Отключиться от сети\n");
|
||
printf(" send <сообщение> <узел> - Отправить сообщение\n");
|
||
printf(" proxy <порт> - Запустить SOCKS5 прокси\n");
|
||
printf(" tunnel <порт:хост:порт> - Создать туннель\n");
|
||
printf(" status - Показать статус\n");
|
||
printf(" quit - Выйти\n");
|
||
}
|
||
else if (strcmp(command, "connect") == 0) {
|
||
char *address = "127.0.0.1";
|
||
uint16_t port = DEFAULT_PHANTOM_PORT;
|
||
|
||
if (args > 1) {
|
||
char *colon = strchr(arg1, ':');
|
||
if (colon) {
|
||
*colon = '\0';
|
||
address = arg1;
|
||
port = atoi(colon + 1);
|
||
} else {
|
||
address = arg1;
|
||
}
|
||
}
|
||
|
||
phantom_client_connect(client, address, port);
|
||
}
|
||
else if (strcmp(command, "disconnect") == 0) {
|
||
phantom_client_disconnect(client);
|
||
}
|
||
else if (strcmp(command, "send") == 0) {
|
||
if (args >= 3) {
|
||
phantom_client_send_message(client, arg1, arg2);
|
||
} else {
|
||
printf("Использование: send <сообщение> <узел>\n");
|
||
}
|
||
}
|
||
else if (strcmp(command, "proxy") == 0) {
|
||
if (args >= 2) {
|
||
uint16_t port = atoi(arg1);
|
||
phantom_client_start_proxy(client, port);
|
||
} else {
|
||
printf("Использование: proxy <порт>\n");
|
||
}
|
||
}
|
||
else if (strcmp(command, "tunnel") == 0) {
|
||
if (args >= 2) {
|
||
// Парсинг формата порт:хост:порт
|
||
char *first_colon = strchr(arg1, ':');
|
||
if (first_colon) {
|
||
*first_colon = '\0';
|
||
char *second_colon = strchr(first_colon + 1, ':');
|
||
if (second_colon) {
|
||
*second_colon = '\0';
|
||
|
||
uint16_t local_port = atoi(arg1);
|
||
char *remote_host = first_colon + 1;
|
||
uint16_t remote_port = atoi(second_colon + 1);
|
||
|
||
phantom_client_start_tunnel(client, local_port, remote_host, remote_port);
|
||
} else {
|
||
printf("Неверный формат. Используйте: tunnel <локальный_порт:удаленный_хост:удаленный_порт>\n");
|
||
}
|
||
} else {
|
||
printf("Неверный формат. Используйте: tunnel <локальный_порт:удаленный_хост:удаленный_порт>\n");
|
||
}
|
||
} else {
|
||
printf("Использование: tunnel <локальный_порт:удаленный_хост:удаленный_порт>\n");
|
||
}
|
||
}
|
||
else if (strcmp(command, "status") == 0) {
|
||
phantom_client_show_status(client);
|
||
}
|
||
else if (strcmp(command, "quit") == 0 || strcmp(command, "exit") == 0) {
|
||
break;
|
||
}
|
||
else {
|
||
printf("Неизвестная команда: %s\n", command);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Главная функция
|
||
*/
|
||
int main(int argc, char *argv[]) {
|
||
printf("Phantom Client v%s\n", PHANTOM_CLIENT_VERSION);
|
||
printf("Простой клиент для работы с Phantom сетью\n\n");
|
||
|
||
// Создание клиента
|
||
g_client = phantom_client_create();
|
||
if (!g_client) {
|
||
return 1;
|
||
}
|
||
|
||
// Установка обработчиков сигналов
|
||
signal(SIGINT, phantom_client_signal_handler);
|
||
signal(SIGTERM, phantom_client_signal_handler);
|
||
|
||
// Парсинг аргументов командной строки
|
||
static struct option long_options[] = {
|
||
{"connect", optional_argument, 0, 'c'},
|
||
{"disconnect", no_argument, 0, 'd'},
|
||
{"send", required_argument, 0, 's'},
|
||
{"proxy", required_argument, 0, 'p'},
|
||
{"tunnel", required_argument, 0, 't'},
|
||
{"status", no_argument, 0, 'S'},
|
||
{"interactive", no_argument, 0, 'i'},
|
||
{"help", no_argument, 0, 'h'},
|
||
{0, 0, 0, 0}
|
||
};
|
||
|
||
int option_index = 0;
|
||
int c;
|
||
bool interactive_mode = false;
|
||
|
||
while ((c = getopt_long(argc, argv, "c::ds:p:t:Sih", long_options, &option_index)) != -1) {
|
||
switch (c) {
|
||
case 'c': {
|
||
char *address = "127.0.0.1";
|
||
uint16_t port = DEFAULT_PHANTOM_PORT;
|
||
|
||
if (optarg) {
|
||
char *colon = strchr(optarg, ':');
|
||
if (colon) {
|
||
*colon = '\0';
|
||
address = optarg;
|
||
port = atoi(colon + 1);
|
||
} else {
|
||
address = optarg;
|
||
}
|
||
}
|
||
|
||
phantom_client_connect(g_client, address, port);
|
||
break;
|
||
}
|
||
|
||
case 'd':
|
||
phantom_client_disconnect(g_client);
|
||
break;
|
||
|
||
case 's':
|
||
if (optind < argc) {
|
||
phantom_client_send_message(g_client, optarg, argv[optind]);
|
||
optind++;
|
||
} else {
|
||
fprintf(stderr, "Не указан получатель сообщения\n");
|
||
}
|
||
break;
|
||
|
||
case 'p': {
|
||
uint16_t port = atoi(optarg);
|
||
phantom_client_start_proxy(g_client, port);
|
||
break;
|
||
}
|
||
|
||
case 't': {
|
||
// Парсинг формата порт:хост:порт
|
||
char *arg_copy = strdup(optarg);
|
||
char *first_colon = strchr(arg_copy, ':');
|
||
if (first_colon) {
|
||
*first_colon = '\0';
|
||
char *second_colon = strchr(first_colon + 1, ':');
|
||
if (second_colon) {
|
||
*second_colon = '\0';
|
||
|
||
uint16_t local_port = atoi(arg_copy);
|
||
char *remote_host = first_colon + 1;
|
||
uint16_t remote_port = atoi(second_colon + 1);
|
||
|
||
phantom_client_start_tunnel(g_client, local_port, remote_host, remote_port);
|
||
} else {
|
||
fprintf(stderr, "Неверный формат туннеля. Используйте: порт:хост:порт\n");
|
||
}
|
||
} else {
|
||
fprintf(stderr, "Неверный формат туннеля. Используйте: порт:хост:порт\n");
|
||
}
|
||
free(arg_copy);
|
||
break;
|
||
}
|
||
|
||
case 'S':
|
||
phantom_client_show_status(g_client);
|
||
break;
|
||
|
||
case 'i':
|
||
interactive_mode = true;
|
||
break;
|
||
|
||
case 'h':
|
||
phantom_client_show_help();
|
||
phantom_client_destroy(g_client);
|
||
return 0;
|
||
|
||
default:
|
||
phantom_client_show_help();
|
||
phantom_client_destroy(g_client);
|
||
return 1;
|
||
}
|
||
}
|
||
|
||
// Интерактивный режим
|
||
if (interactive_mode) {
|
||
phantom_client_interactive_mode(g_client);
|
||
} else if (argc == 1) {
|
||
// Если нет аргументов, показать справку
|
||
phantom_client_show_help();
|
||
} else {
|
||
// Ожидание завершения работы
|
||
while (g_client->is_running) {
|
||
sleep(1);
|
||
}
|
||
}
|
||
|
||
// Очистка
|
||
phantom_client_destroy(g_client);
|
||
|
||
printf("Phantom Client завершен\n");
|
||
return 0;
|
||
}
|
||
|