Копирование папок desktop и desktop-angular из ветки main
This commit is contained in:
411
desktop/LOCAL_KNOCKING.md
Normal file
411
desktop/LOCAL_KNOCKING.md
Normal file
@@ -0,0 +1,411 @@
|
||||
# Локальное простукивание портов (Local Port Knocking)
|
||||
|
||||
## Обзор
|
||||
|
||||
Функционал локального простукивания позволяет выполнять knock операции напрямую через Node.js API без использования внешнего HTTP API сервера. Это обеспечивает независимость от внешних сервисов и возможность работы в автономном режиме.
|
||||
|
||||
## Условия активации
|
||||
|
||||
Локальное простукивание активируется автоматически когда:
|
||||
|
||||
1. **API URL пуст** - поле `apiBase` не заполнено или содержит пустую строку
|
||||
2. **API URL = "internal"** - значение `apiBase` установлено в `"internal"`
|
||||
3. **API URL не задан** - значение `apiBase` равно `null` или `undefined`
|
||||
|
||||
## Архитектура
|
||||
|
||||
### Файлы реализации
|
||||
|
||||
#### 1. `src/main/main.js` - Основная логика
|
||||
|
||||
**Строки 210-367**: Реализация локального простукивания
|
||||
|
||||
**Ключевые функции:**
|
||||
|
||||
- `parseTarget(targetStr)` - парсинг строки цели в объект
|
||||
- `parseDelay(delayStr)` - конвертация задержки в миллисекунды
|
||||
- `knockTcp(host, port, timeout)` - TCP простукивание
|
||||
- `knockUdp(host, port, timeout)` - UDP простукивание
|
||||
- `performLocalKnock(targets, delay, verbose)` - основная функция простукивания
|
||||
- `ipcMain.handle('knock:local', ...)` - IPC обработчик
|
||||
|
||||
**Поддерживаемые протоколы:**
|
||||
|
||||
- **TCP** - создает соединение и немедленно закрывает
|
||||
- **UDP** - отправляет пакет данных (fire-and-forget)
|
||||
|
||||
**Формат целей:**
|
||||
|
||||
``` text
|
||||
protocol:host:port[:gateway]
|
||||
```
|
||||
|
||||
Примеры:
|
||||
|
||||
- `tcp:127.0.0.1:22`
|
||||
- `udp:192.168.1.1:53`
|
||||
- `tcp:example.com:80:gateway.com`
|
||||
|
||||
**Поддержка Gateway:**
|
||||
|
||||
Gateway можно указать двумя способами:
|
||||
|
||||
1. **В строке цели**: `tcp:host:port:gateway_ip`
|
||||
2. **Глобально через поле Gateway**: используется для всех целей, если не указан в самой цели
|
||||
|
||||
**Приоритет gateway:**
|
||||
|
||||
- Gateway из строки цели имеет приоритет над глобальным
|
||||
- Если gateway не указан, используется системный маршрут по умолчанию
|
||||
|
||||
**Обход VPN/туннелей:**
|
||||
|
||||
Gateway использует `localAddress` для принудительного направления трафика через указанный локальный IP-адрес. Это позволяет:
|
||||
- Обходить VPN соединения (WireGuard, OpenVPN и др.)
|
||||
- Использовать конкретный сетевой интерфейс
|
||||
- Направлять трафик через локальный шлюз
|
||||
|
||||
**Пример обхода WireGuard:**
|
||||
```json
|
||||
{
|
||||
"gateway": "192.168.89.1"
|
||||
}
|
||||
```
|
||||
Трафик будет направлен через интерфейс с IP `192.168.89.1`, минуя WireGuard туннель.
|
||||
|
||||
## Хелпер для gateway (Rust приоритетно, Go как fallback)
|
||||
|
||||
Когда задан `gateway` (IP или имя интерфейса), десктоп-приложение запускает встроенный бинарь из `desktop/bin/`:
|
||||
|
||||
- `knock-local-rust` — приоритетный Rust-хелпер (если присутствует)
|
||||
- `knock-local` — Go-хелпер как запасной вариант
|
||||
|
||||
Оба на Linux используют `SO_BINDTODEVICE` для привязки к интерфейсу и надежного обхода VPN/туннелей (WireGuard и пр.).
|
||||
|
||||
Сборка при разработке:
|
||||
|
||||
- `npm run rust:build` — соберёт Rust-хелпер
|
||||
- `npm run go:build` — соберёт Go-хелпер
|
||||
|
||||
В прод-сборках оба бинаря автоматически включаются в образ приложения.
|
||||
|
||||
Важно для TCP: привязка интерфейса устанавливается до `connect()`. Это гарантирует, что исходящее соединение пойдёт через нужный интерфейс, а не в туннель.
|
||||
|
||||
**Формат задержки:**
|
||||
|
||||
- `1s` - 1 секунда
|
||||
- `500ms` - 500 миллисекунд (не поддерживается, используйте `0.5s`)
|
||||
- `2m` - 2 минуты
|
||||
- `1h` - 1 час
|
||||
|
||||
#### 2. `src/preload/preload.js` - IPC мост
|
||||
|
||||
**Строка 13**: Добавлен метод `localKnock`
|
||||
|
||||
```javascript
|
||||
localKnock: async (payload) => ipcRenderer.invoke('knock:local', payload)
|
||||
```
|
||||
|
||||
#### 3. `src/renderer/renderer.js` - UI логика
|
||||
|
||||
**Строки 317-376**: Логика выбора между локальным и API простукиванием
|
||||
|
||||
**Ключевые изменения:**
|
||||
|
||||
- Проверка условия `useLocalKnock = !apiBase || apiBase.trim() === '' || apiBase === 'internal'`
|
||||
- Извлечение targets из всех режимов (inline, form, yaml)
|
||||
- Вызов `window.api.localKnock()` вместо HTTP запросов
|
||||
|
||||
## Режимы работы
|
||||
|
||||
### 1. Inline режим
|
||||
|
||||
```javascript
|
||||
// Извлекает targets из поля #targets
|
||||
targets = qsi("#targets").value.split(';').filter(t => t.trim());
|
||||
```
|
||||
|
||||
### 2. Form режим
|
||||
|
||||
```javascript
|
||||
// Сериализует формы в строку targets
|
||||
targets = [serializeFormTargetsToInline()];
|
||||
```
|
||||
|
||||
### 3. YAML режим
|
||||
|
||||
```javascript
|
||||
// Парсит YAML и извлекает targets
|
||||
const config = yaml.load(yamlContent);
|
||||
targets = config.targets.map(t => {
|
||||
const protocol = t.protocol || 'tcp';
|
||||
const host = t.host || '127.0.0.1';
|
||||
const ports = t.ports || [t.port] || [22];
|
||||
return ports.map(port => `${protocol}:${host}:${port}`);
|
||||
}).flat();
|
||||
```
|
||||
|
||||
## API локального простукивания
|
||||
|
||||
### Входные параметры
|
||||
|
||||
```javascript
|
||||
{
|
||||
targets: string[], // Массив целей в формате "protocol:host:port[:gateway]"
|
||||
delay: string, // Задержка между целями (например "1s")
|
||||
verbose: boolean, // Подробный вывод в консоль
|
||||
gateway: string // Глобальный gateway для всех целей (опционально)
|
||||
}
|
||||
```
|
||||
|
||||
### Выходные данные
|
||||
|
||||
```javascript
|
||||
{
|
||||
success: boolean, // Успешность операции
|
||||
results: [ // Детальные результаты по каждой цели
|
||||
{
|
||||
target: string, // Исходная строка цели
|
||||
success: boolean, // Успешность простукивания
|
||||
message: string // Сообщение о результате
|
||||
}
|
||||
],
|
||||
summary: { // Общая статистика
|
||||
total: number, // Общее количество целей
|
||||
successful: number, // Количество успешных
|
||||
failed: number // Количество неудачных
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Примеры использования
|
||||
|
||||
### Настройка для локального режима
|
||||
|
||||
#### Вариант 1: Пустой API URL
|
||||
|
||||
```json
|
||||
{
|
||||
"apiBase": ""
|
||||
}
|
||||
```
|
||||
|
||||
#### Вариант 2: Специальное значение
|
||||
|
||||
```json
|
||||
{
|
||||
"apiBase": "internal"
|
||||
}
|
||||
```
|
||||
|
||||
### Пример конфигурации
|
||||
|
||||
```json
|
||||
{
|
||||
"apiBase": "internal",
|
||||
"gateway": "192.168.1.1",
|
||||
"inlineTargets": "tcp:127.0.0.1:22;tcp:192.168.1.100:80",
|
||||
"delay": "2s"
|
||||
}
|
||||
```
|
||||
|
||||
### Пример YAML конфигурации
|
||||
|
||||
```yaml
|
||||
targets:
|
||||
- protocol: tcp
|
||||
host: 127.0.0.1
|
||||
ports: [22, 80]
|
||||
- protocol: udp
|
||||
host: 192.168.1.1
|
||||
ports: [53]
|
||||
delay: 1s
|
||||
```
|
||||
|
||||
## Логирование и отладка
|
||||
|
||||
### Консольный вывод
|
||||
|
||||
При `verbose: true` в консоли main процесса появляются сообщения:
|
||||
|
||||
``` text
|
||||
Knocking TCP 127.0.0.1:22
|
||||
Knocking UDP 192.168.1.1:53 via 192.168.1.1
|
||||
Knocking TCP example.com:80 via 10.0.0.1
|
||||
```
|
||||
|
||||
### Результаты в DevTools
|
||||
|
||||
Детальные результаты логируются в консоль renderer процесса:
|
||||
|
||||
```javascript
|
||||
console.log('Local knock results:', result.results);
|
||||
```
|
||||
|
||||
### Статус в UI
|
||||
|
||||
В интерфейсе отображается краткий статус:
|
||||
|
||||
``` text
|
||||
"Локальное простукивание завершено: 2/3 успешно"
|
||||
```
|
||||
|
||||
## Ограничения
|
||||
|
||||
### Поддерживаемые протоколы
|
||||
|
||||
- ✅ **TCP** - полная поддержка
|
||||
- ✅ **UDP** - отправка пакетов
|
||||
- ❌ **ICMP** - не поддерживается
|
||||
- ❌ **Другие протоколы** - не поддерживаются
|
||||
|
||||
### Таймауты
|
||||
|
||||
- **TCP**: 5 секунд по умолчанию
|
||||
- **UDP**: 5 секунд по умолчанию
|
||||
- Настраивается в коде функций `knockTcp` и `knockUdp`
|
||||
|
||||
### Сетевая безопасность
|
||||
|
||||
- Локальное простукивание использует системные сокеты
|
||||
- Подчиняется правилам файрвола операционной системы
|
||||
- Не требует дополнительных разрешений в Electron
|
||||
|
||||
## Совместимость
|
||||
|
||||
### Операционные системы
|
||||
|
||||
- ✅ **Windows** - полная поддержка
|
||||
- ✅ **macOS** - полная поддержка
|
||||
- ✅ **Linux** - полная поддержка
|
||||
|
||||
### Electron версии
|
||||
|
||||
- ✅ **v28+** - протестировано
|
||||
- ⚠️ **v27 и ниже** - может потребовать адаптации
|
||||
|
||||
## Переключение между режимами
|
||||
|
||||
### API → Локальный
|
||||
|
||||
1. Открыть настройки (Ctrl/Cmd+,)
|
||||
2. Установить `apiBase` в `"internal"`
|
||||
3. Сохранить настройки
|
||||
4. Перезапустить приложение
|
||||
|
||||
### Локальный → API
|
||||
|
||||
1. Открыть настройки
|
||||
2. Установить корректный `apiBase` URL
|
||||
3. Сохранить настройки
|
||||
4. Перезапустить приложение
|
||||
|
||||
## Устранение неполадок
|
||||
|
||||
### Проблема: "No targets provided"
|
||||
|
||||
**Причина**: Не удалось извлечь цели из конфигурации
|
||||
**Решение**: Проверить корректность заполнения полей targets
|
||||
|
||||
### Проблема: "Unsupported protocol"
|
||||
|
||||
**Причина**: Использован неподдерживаемый протокол
|
||||
**Решение**: Использовать только `tcp` или `udp`
|
||||
|
||||
### Проблема: "Connection timeout"
|
||||
|
||||
**Причина**: Цель недоступна или заблокирована файрволом
|
||||
**Решение**: Проверить доступность цели и настройки файрвола
|
||||
|
||||
### Проблема: "Invalid target format"
|
||||
|
||||
**Причина**: Неверный формат строки цели
|
||||
**Решение**: Использовать формат `protocol:host:port`
|
||||
|
||||
### Проблема: "Uncaught Exception"
|
||||
|
||||
**Причина**: Необработанные ошибки в асинхронных операциях
|
||||
**Решение**: ✅ **ИСПРАВЛЕНО** - Добавлены глобальные обработчики ошибок и защита от двойного resolve
|
||||
|
||||
**Исправления в версии 1.1:**
|
||||
|
||||
- Добавлен флаг `resolved` в TCP/UDP функциях для предотвращения двойного вызова resolve
|
||||
- Глобальные обработчики `uncaughtException` и `unhandledRejection` в main процессе
|
||||
- Глобальные обработчики ошибок в renderer процессе
|
||||
- Улучшенная валидация входных данных в IPC обработчике
|
||||
- Try-catch блоки вокруг всех критических операций
|
||||
|
||||
## Безопасность
|
||||
|
||||
### Ограничения доступа
|
||||
|
||||
- Локальное простукивание выполняется с правами пользователя приложения
|
||||
- Не требует root/administrator прав
|
||||
- Подчиняется системным ограничениям сетевого доступа
|
||||
|
||||
### Логирование
|
||||
|
||||
- Результаты простукивания логируются в консоль
|
||||
- Не сохраняются в файлы по умолчанию
|
||||
- Можно отключить через параметр `verbose: false`
|
||||
|
||||
## Разработка и расширение
|
||||
|
||||
### Добавление новых протоколов
|
||||
|
||||
1. Создать функцию `knockProtocol()` в `src/main/main.js`
|
||||
2. Добавить обработку в `performLocalKnock()`
|
||||
3. Обновить документацию
|
||||
|
||||
### Настройка таймаутов
|
||||
|
||||
```javascript
|
||||
// В src/main/main.js
|
||||
function knockTcp(host, port, timeout = 10000) { // 10 секунд
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### Добавление дополнительных опций
|
||||
|
||||
```javascript
|
||||
// Расширить payload в IPC
|
||||
{
|
||||
targets: string[],
|
||||
delay: string,
|
||||
verbose: boolean,
|
||||
timeout: number, // новый параметр
|
||||
retries: number // новый параметр
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Пример обхода WireGuard
|
||||
|
||||
### Проблема
|
||||
WireGuard активен, весь трафик идет через туннель, но нужно простучать порт через локальный шлюз.
|
||||
|
||||
### Решение
|
||||
```json
|
||||
{
|
||||
"apiBase": "internal",
|
||||
"gateway": "192.168.89.1",
|
||||
"inlineTargets": "tcp:external-server.com:22",
|
||||
"delay": "1s"
|
||||
}
|
||||
```
|
||||
|
||||
### Логи
|
||||
```
|
||||
Using localAddress 192.168.89.1 to bypass VPN/tunnel
|
||||
Knocking TCP external-server.com:22 via 192.168.89.1
|
||||
TCP connection to external-server.com:22 via 192.168.89.1 successful
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Версия документации**: 1.2
|
||||
**Дата создания**: 2024
|
||||
**Дата обновления**: 2024 (поддержка обхода VPN)
|
||||
**Совместимость**: Electron Desktop App v1.0+
|
Reference in New Issue
Block a user