142 lines
3.9 KiB
Go
142 lines
3.9 KiB
Go
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
|
||
}
|