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"}) }