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

141
back/cmd/knock_routes.go Normal file
View File

@@ -0,0 +1,141 @@
package cmd
import (
"fmt"
"strconv"
"strings"
"time"
"port-knocker/internal"
"github.com/gin-gonic/gin"
)
// setupKnockRoutes настраивает роуты для выполнения port knocking
func setupKnockRoutes(api *gin.RouterGroup) {
// Execute: вход inline или YAML конфиг
api.POST("/execute", func(c *gin.Context) {
var req struct {
Targets string `json:"targets"`
Delay string `json:"delay"`
Verbose bool `json:"verbose"`
WaitConnection bool `json:"waitConnection"`
Gateway string `json:"gateway"`
ConfigYaml string `json:"config_yaml"`
}
if err := c.BindJSON(&req); err != nil {
c.JSON(400, gin.H{"error": fmt.Sprintf("bad json: %v", err)})
return
}
knocker := internal.NewPortKnocker()
// Определяем режим: inline или YAML
if strings.TrimSpace(req.ConfigYaml) != "" {
// YAML режим - загружаем конфигурацию из строки
config, err := internal.LoadConfigFromString(req.ConfigYaml)
if err != nil {
c.JSON(400, gin.H{"error": fmt.Sprintf("invalid yaml: %v", err)})
return
}
// Применяем дополнительные параметры из запроса
if req.Gateway != "" {
for i := range config.Targets {
config.Targets[i].Gateway = req.Gateway
}
}
if err := knocker.ExecuteWithConfig(config, req.Verbose, req.WaitConnection); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
c.JSON(200, gin.H{"status": "ok"})
return
} else {
// Inline режим
if strings.TrimSpace(req.Targets) == "" {
c.JSON(400, gin.H{"error": "targets is required in inline mode"})
return
}
config, err := parseInlineTargetsWithWait(req.Targets, req.Delay, req.WaitConnection)
if err != nil {
c.JSON(400, gin.H{"error": fmt.Sprintf("invalid targets: %v", err)})
return
}
// Применяем gateway к каждой цели
if req.Gateway != "" {
for i := range config.Targets {
config.Targets[i].Gateway = req.Gateway
}
}
if err := knocker.ExecuteWithConfig(&config, req.Verbose, req.WaitConnection); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
c.JSON(200, gin.H{"status": "ok"})
}
})
}
// parseInlineTargetsWithWait парсит inline строку целей в Config с поддержкой waitConnection
func parseInlineTargetsWithWait(targets, delay string, waitConnection bool) (internal.Config, error) {
var config internal.Config
// Парсим targets
targetStrings := strings.Split(targets, ";")
for _, targetStr := range targetStrings {
targetStr = strings.TrimSpace(targetStr)
if targetStr == "" {
continue
}
parts := strings.Split(targetStr, ":")
if len(parts) != 3 {
return config, fmt.Errorf("invalid target format: %s (expected protocol:host:port)", targetStr)
}
protocol := strings.TrimSpace(parts[0])
host := strings.TrimSpace(parts[1])
portStr := strings.TrimSpace(parts[2])
if protocol != "tcp" && protocol != "udp" {
return config, fmt.Errorf("unsupported protocol: %s (only tcp/udp supported)", protocol)
}
port, err := strconv.Atoi(portStr)
if err != nil {
return config, fmt.Errorf("invalid port: %s", portStr)
}
// Парсим delay
var targetDelay internal.Duration
if delay != "" {
duration, err := time.ParseDuration(delay)
if err != nil {
return config, fmt.Errorf("invalid delay: %s", delay)
}
targetDelay = internal.Duration(duration)
} else {
targetDelay = internal.Duration(time.Second)
}
target := internal.Target{
Protocol: protocol,
Host: host,
Ports: []int{port},
Delay: targetDelay,
WaitConnection: waitConnection,
}
config.Targets = append(config.Targets, target)
}
if len(config.Targets) == 0 {
return config, fmt.Errorf("no valid targets found")
}
return config, nil
}