Files
Phantom/release/tools/phantom-client.c

1043 lines
36 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 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;
}