117 lines
2.7 KiB
Go
117 lines
2.7 KiB
Go
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"})
|
|
}
|