refresh back
This commit is contained in:
116
back/cmd/knock-local/main.go
Normal file
116
back/cmd/knock-local/main.go
Normal file
@@ -0,0 +1,116 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"port-knocker/internal"
|
||||
)
|
||||
|
||||
type Request struct {
|
||||
Targets []string `json:"targets"`
|
||||
Delay string `json:"delay"`
|
||||
Verbose bool `json:"verbose"`
|
||||
Gateway string `json:"gateway"`
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
Success bool `json:"success"`
|
||||
Error string `json:"error,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
func parseTargets(in []string, delayStr string, gateway string) (*internal.Config, error) {
|
||||
cfg := &internal.Config{Targets: []internal.Target{}}
|
||||
d := time.Second
|
||||
if strings.TrimSpace(delayStr) != "" {
|
||||
dur, err := time.ParseDuration(delayStr)
|
||||
if err == nil {
|
||||
d = dur
|
||||
}
|
||||
}
|
||||
for _, t := range in {
|
||||
t = strings.TrimSpace(t)
|
||||
if t == "" {
|
||||
continue
|
||||
}
|
||||
parts := strings.Split(t, ":")
|
||||
if len(parts) < 3 {
|
||||
return nil, fmt.Errorf("invalid target: %s", t)
|
||||
}
|
||||
protocol := strings.ToLower(parts[0])
|
||||
host := parts[1]
|
||||
portStr := parts[2]
|
||||
gw := ""
|
||||
if len(parts) >= 4 && strings.TrimSpace(parts[3]) != "" {
|
||||
gw = strings.TrimSpace(parts[3])
|
||||
} else if strings.TrimSpace(gateway) != "" {
|
||||
gw = strings.TrimSpace(gateway)
|
||||
}
|
||||
// single port
|
||||
var port int
|
||||
fmt.Sscanf(portStr, "%d", &port)
|
||||
cfg.Targets = append(cfg.Targets, internal.Target{
|
||||
Host: host,
|
||||
Ports: []int{port},
|
||||
Protocol: protocol,
|
||||
Delay: internal.Duration(d),
|
||||
WaitConnection: false,
|
||||
Gateway: gw,
|
||||
})
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func readAllStdin() ([]byte, error) {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
var b []byte
|
||||
for {
|
||||
chunk, isPrefix, err := reader.ReadLine()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b = append(b, chunk...)
|
||||
if !isPrefix {
|
||||
b = append(b, '\n')
|
||||
}
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Read JSON from stdin
|
||||
data, err := readAllStdin()
|
||||
if err != nil || len(strings.TrimSpace(string(data))) == 0 {
|
||||
// fallback to args? not required; expect stdin
|
||||
}
|
||||
var req Request
|
||||
if err := json.Unmarshal(data, &req); err != nil {
|
||||
_ = json.NewEncoder(os.Stdout).Encode(Response{Success: false, Error: fmt.Sprintf("invalid json: %v", err)})
|
||||
return
|
||||
}
|
||||
|
||||
cfg, err := parseTargets(req.Targets, req.Delay, req.Gateway)
|
||||
if err != nil {
|
||||
_ = json.NewEncoder(os.Stdout).Encode(Response{Success: false, Error: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
pk := internal.NewPortKnocker()
|
||||
// Всегда без лишних логов на stdout (stdout должен содержать только JSON ответ)
|
||||
verbose := false
|
||||
if err := pk.ExecuteWithConfig(cfg, verbose, false); err != nil {
|
||||
_ = json.NewEncoder(os.Stdout).Encode(Response{Success: false, Error: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
_ = json.NewEncoder(os.Stdout).Encode(Response{Success: true, Message: "ok"})
|
||||
}
|
@@ -24,10 +24,13 @@ func setupKnockRoutes(api *gin.RouterGroup) {
|
||||
ConfigYaml string `json:"config_yaml"`
|
||||
}
|
||||
if err := c.BindJSON(&req); err != nil {
|
||||
// fmt.Printf("bad json: %v\n", err)
|
||||
c.JSON(400, gin.H{"error": fmt.Sprintf("bad json: %v", err)})
|
||||
return
|
||||
}
|
||||
|
||||
// fmt.Printf("req: %+v\n", req)
|
||||
|
||||
knocker := internal.NewPortKnocker()
|
||||
|
||||
// Определяем режим: inline или YAML
|
||||
@@ -39,6 +42,8 @@ func setupKnockRoutes(api *gin.RouterGroup) {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("config: %+v\n", config)
|
||||
|
||||
// Применяем дополнительные параметры из запроса
|
||||
if req.Gateway != "" {
|
||||
for i := range config.Targets {
|
||||
@@ -47,7 +52,8 @@ func setupKnockRoutes(api *gin.RouterGroup) {
|
||||
}
|
||||
|
||||
if err := knocker.ExecuteWithConfig(config, req.Verbose, req.WaitConnection); err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
fmt.Printf("error: %v\n", err)
|
||||
c.JSON(400, gin.H{"status": "error","error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(200, gin.H{"status": "ok"})
|
||||
@@ -101,7 +107,6 @@ func parseInlineTargetsWithWait(targets, delay string, waitConnection bool, gate
|
||||
host := strings.TrimSpace(parts[1])
|
||||
portStr := strings.TrimSpace(parts[2])
|
||||
|
||||
|
||||
if len(parts) == 4 {
|
||||
gateway = strings.TrimSpace(parts[3])
|
||||
}
|
||||
|
@@ -100,13 +100,17 @@ func parseInlineTargets(targetsStr, delayStr string) (*internal.Config, error) {
|
||||
|
||||
// Разбираем формат [proto]:[host]:[port]
|
||||
parts := strings.Split(targetStr, ":")
|
||||
if len(parts) != 3 {
|
||||
return nil, fmt.Errorf("неверный формат цели '%s', ожидается [proto]:[host]:[port]", targetStr)
|
||||
if len(parts) != 3 && len(parts) != 4 {
|
||||
return nil, fmt.Errorf("неверный формат цели '%s', ожидается [proto]:[host]:[port] или [proto]:[host]:[port]:[gateway]", targetStr)
|
||||
}
|
||||
|
||||
protocol := strings.TrimSpace(parts[0])
|
||||
host := strings.TrimSpace(parts[1])
|
||||
portStr := strings.TrimSpace(parts[2])
|
||||
gateway := ""
|
||||
if len(parts) == 4 {
|
||||
gateway = strings.TrimSpace(parts[3])
|
||||
}
|
||||
|
||||
// Проверяем протокол
|
||||
if protocol != "tcp" && protocol != "udp" {
|
||||
@@ -130,7 +134,7 @@ func parseInlineTargets(targetsStr, delayStr string) (*internal.Config, error) {
|
||||
Protocol: protocol,
|
||||
Delay: internal.Duration(delay),
|
||||
WaitConnection: false,
|
||||
Gateway: "",
|
||||
Gateway: gateway,
|
||||
}
|
||||
|
||||
config.Targets = append(config.Targets, target)
|
||||
|
@@ -43,11 +43,16 @@ func runServe(cmd *cobra.Command, args []string) error {
|
||||
port = "8888"
|
||||
}
|
||||
|
||||
host := os.Getenv("GO_KNOCKER_SERVE_HOST")
|
||||
if strings.TrimSpace(port) == "" {
|
||||
host = ""
|
||||
}
|
||||
|
||||
r := gin.Default()
|
||||
|
||||
// CORS: разрешаем для локальной разработки
|
||||
r.Use(cors.New(cors.Config{
|
||||
AllowOrigins: []string{"http://localhost:4200", "http://127.0.0.1:8888", "http://localhost:8888"},
|
||||
AllowOrigins: []string{"http://localhost:4200", "http://127.0.0.1:8888", "http://localhost:" + port},
|
||||
AllowMethods: []string{"GET", "POST", "OPTIONS"},
|
||||
AllowHeaders: []string{"Authorization", "Content-Type"},
|
||||
AllowCredentials: true,
|
||||
@@ -65,6 +70,6 @@ func runServe(cmd *cobra.Command, args []string) error {
|
||||
setupCryptoRoutes(api, passHash)
|
||||
setupStaticRoutes(r, embeddedFS)
|
||||
|
||||
fmt.Printf("Serving on :%s\n", port)
|
||||
return r.Run(":" + port)
|
||||
fmt.Printf("Serving on %s:%s\n", host, port)
|
||||
return r.Run(host + ":" + port)
|
||||
}
|
||||
|
@@ -6,7 +6,6 @@ require (
|
||||
github.com/gin-contrib/cors v1.7.2
|
||||
github.com/gin-gonic/gin v1.10.0
|
||||
github.com/spf13/cobra v1.8.0
|
||||
golang.org/x/sys v0.20.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
@@ -36,6 +35,7 @@ require (
|
||||
golang.org/x/arch v0.8.0 // indirect
|
||||
golang.org/x/crypto v0.23.0 // indirect
|
||||
golang.org/x/net v0.25.0 // indirect
|
||||
golang.org/x/sys v0.20.0
|
||||
golang.org/x/text v0.15.0 // indirect
|
||||
google.golang.org/protobuf v1.34.1 // indirect
|
||||
)
|
||||
|
@@ -7,7 +7,7 @@ import (
|
||||
"port-knocker/cmd"
|
||||
)
|
||||
|
||||
|
||||
// Version и BuildTime устанавливаются при сборке через ldflags
|
||||
var (
|
||||
Version = "v1.0.10"
|
||||
BuildTime = "unknown"
|
||||
|
@@ -112,7 +112,6 @@ git push origin main
|
||||
# Сборка бинарников
|
||||
log_info "Собираем бинарники для всех платформ..."
|
||||
export VERSION_NUM="${VERSION#v}"
|
||||
# shellcheck disable=SC2155
|
||||
export BUILD_TIME=$(date -u '+%Y-%m-%d_%H:%M:%S')
|
||||
|
||||
# Функция сборки для платформы
|
||||
@@ -156,7 +155,6 @@ log_info "Создаем Git тег..."
|
||||
# Читаем release-notes.md и сохраняем содержимое в переменную NOTES
|
||||
NOTES=$(cat docs/scripts/release-notes.md)
|
||||
# Заменяем все переменные вида $VERSION в NOTES на их значения
|
||||
# shellcheck disable=SC2001
|
||||
NOTES=$(echo "$NOTES" | sed "s/\\\$VERSION/$VERSION/g")
|
||||
|
||||
git tag -a "$VERSION" -m "$NOTES"
|
||||
|
Reference in New Issue
Block a user