This commit is contained in:
66 changed files with 19815 additions and 0 deletions

144
back/cmd/root.go Normal file
View File

@@ -0,0 +1,144 @@
package cmd
import (
"fmt"
"strconv"
"strings"
"time"
"port-knocker/internal"
"github.com/spf13/cobra"
)
var (
configFile string
keyFile string
verbose bool
waitConnection bool
targetsInline string
defaultDelay string
)
var rootCmd = &cobra.Command{
Use: "port-knocker",
Short: "Утилита для отправки port knocking пакетов",
Long: `Port Knocker - утилита для отправки TCP/UDP пакетов на определенные порты
в заданной последовательности для активации портов на удаленных серверах.
Поддерживает:
- TCP и UDP протоколы
- Зашифрованные конфигурационные файлы
- Автоматическое определение зашифрованных файлов
- Ключи шифрования из файла или системной переменной
- Настройка шлюза для отправки пакетов
- Гибкая настройка ожидания соединения
- Инлайн задание целей без конфигурационного файла`,
RunE: runKnock,
}
func Execute() error {
return rootCmd.Execute()
}
func init() {
rootCmd.PersistentFlags().StringVarP(&configFile, "config", "c", "", "Путь к файлу конфигурации")
rootCmd.PersistentFlags().StringVarP(&keyFile, "key", "k", "", "Путь к файлу ключа шифрования")
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Подробный вывод")
rootCmd.PersistentFlags().BoolVarP(&waitConnection, "wait-connection", "w", false, "Ждать установления соединения (по умолчанию не ждать)")
rootCmd.PersistentFlags().StringVarP(&targetsInline, "targets", "t", "", "Инлайн цели в формате [proto]:[host]:[port];[proto]:[host]:[port]")
rootCmd.PersistentFlags().StringVarP(&defaultDelay, "delay", "d", "1s", "Задержка между пакетами (по умолчанию 1s)")
// НЕ делаем config глобально обязательным - проверяем в runKnock
}
func runKnock(cmd *cobra.Command, args []string) error {
// Проверяем что указан либо config файл, либо инлайн цели
if configFile == "" && targetsInline == "" {
return fmt.Errorf("необходимо указать либо файл конфигурации (-c), либо инлайн цели (-t)")
}
if configFile != "" && targetsInline != "" {
return fmt.Errorf("нельзя одновременно использовать файл конфигурации (-c) и инлайн цели (-t)")
}
knocker := internal.NewPortKnocker()
// Если используем инлайн цели
if targetsInline != "" {
config, err := parseInlineTargets(targetsInline, defaultDelay)
if err != nil {
return fmt.Errorf("ошибка разбора инлайн целей: %w", err)
}
return knocker.ExecuteWithConfig(config, verbose, waitConnection)
}
// Иначе используем файл конфигурации
return knocker.Execute(configFile, keyFile, verbose, waitConnection)
}
// parseInlineTargets разбирает строку инлайн целей в Config
func parseInlineTargets(targetsStr, delayStr string) (*internal.Config, error) {
// Парсим задержку
delay, err := time.ParseDuration(delayStr)
if err != nil {
return nil, fmt.Errorf("неверная задержка '%s': %w", delayStr, err)
}
config := &internal.Config{
Targets: []internal.Target{},
}
// Разбиваем по точкам с запятой
targetParts := strings.Split(targetsStr, ";")
for _, targetStr := range targetParts {
targetStr = strings.TrimSpace(targetStr)
if targetStr == "" {
continue
}
// Разбираем формат [proto]:[host]:[port]
parts := strings.Split(targetStr, ":")
if len(parts) != 3 {
return nil, fmt.Errorf("неверный формат цели '%s', ожидается [proto]:[host]:[port]", targetStr)
}
protocol := strings.TrimSpace(parts[0])
host := strings.TrimSpace(parts[1])
portStr := strings.TrimSpace(parts[2])
// Проверяем протокол
if protocol != "tcp" && protocol != "udp" {
return nil, fmt.Errorf("неподдерживаемый протокол '%s' в цели '%s'", protocol, targetStr)
}
// Парсим порт
port, err := strconv.Atoi(portStr)
if err != nil {
return nil, fmt.Errorf("неверный порт '%s' в цели '%s': %w", portStr, targetStr, err)
}
if port < 1 || port > 65535 {
return nil, fmt.Errorf("порт %d вне допустимого диапазона (1-65535) в цели '%s'", port, targetStr)
}
// Создаем цель
target := internal.Target{
Host: host,
Ports: []int{port},
Protocol: protocol,
Delay: internal.Duration(delay),
WaitConnection: false,
Gateway: "",
}
config.Targets = append(config.Targets, target)
}
if len(config.Targets) == 0 {
return nil, fmt.Errorf("не найдено ни одной валидной цели")
}
return config, nil
}