| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- package cli
- import (
- "encoding/json"
- "fmt"
- "strconv"
- "strings"
- "proxmox-router/internal/aerotun"
- "proxmox-router/internal/auth"
- )
- func (e *Executor) handleInterfaceAeroTUN(parts []string, user *auth.PublicUser) string {
- if e.vpnMgr == nil || e.vpnMgr.AeroTUN == nil {
- return ColorRed + "AeroTUN subsystem not available.\n" + ColorReset
- }
- mgr := e.vpnMgr.AeroTUN
- action := "print"
- if len(parts) > 0 {
- action = strings.ToLower(parts[0])
- parts = parts[1:]
- }
- pos, params := parseArgs(parts)
- if action == "print" || action == "show" || action == "pr" {
- list := mgr.List()
- for i := range list {
- list[i] = list[i].PublicView()
- }
- if params["detail"] == "yes" {
- data, _ := json.MarshalIndent(list, "", " ")
- return string(data) + "\n"
- }
- tbl := NewTable("NAME", "VERSION", "STATE", "BACKEND", "LOCAL", "PEER", "ERROR")
- for _, inst := range list {
- tbl.AddRow(inst.Name, strconv.Itoa(inst.Protocol), aeroTUNState(inst), inst.Backend, inst.LocalAddress, inst.PeerAddress, inst.LastError)
- }
- return tbl.String()
- }
- if user == nil || user.Role != auth.RoleFull {
- return ColorRed + "Permission denied: admin role required to manage AeroTUN\n" + ColorReset
- }
- if action == "genkey" {
- key, err := aerotun.GenerateSecureKey()
- if err != nil {
- return cliError(err)
- }
- return key + "\n"
- }
- if action != "add" && action != "set" && action != "remove" && action != "enable" && action != "disable" && action != "start" && action != "stop" {
- return ColorRed + "Usage: /interface aerotun [print [detail=yes]|add|set <name>|remove <name>|enable <name>|disable <name>|start <name>|stop <name>|genkey]\n" + ColorReset
- }
- inst := aerotun.TunnelInstance{Protocol: 3, Mode: "server", Disabled: true, MTU: aerotun.DefaultMTU}
- if action != "add" {
- if len(pos) != 1 {
- return cliError(fmt.Errorf("%s requires one tunnel name or ID", action))
- }
- found := false
- for _, candidate := range mgr.List() {
- if candidate.Name == pos[0] || candidate.ID == pos[0] {
- inst, found = candidate, true
- break
- }
- }
- if !found {
- return cliError(fmt.Errorf("AeroTUN tunnel not found: %s", pos[0]))
- }
- }
- var err error
- switch action {
- case "remove":
- err = mgr.Delete(inst.ID)
- case "enable":
- err = mgr.ToggleState(inst.ID, false)
- case "disable":
- err = mgr.ToggleState(inst.ID, true)
- case "start":
- err = mgr.StartTunnel(inst.ID)
- case "stop":
- err = mgr.StopTunnel(inst.ID)
- case "add", "set":
- for key, value := range params {
- switch key {
- case "name":
- inst.Name = value
- case "mode":
- inst.Mode = value
- case "endpoint":
- inst.RemoteEndpoint = value
- case "local-address":
- inst.LocalAddress = value
- case "peer-address":
- inst.PeerAddress = value
- case "peer-public-key":
- inst.PeerPublicKey = value
- case "psk":
- inst.PSK = value
- case "comment":
- inst.Comment = value
- case "allowed-ips":
- inst.AllowedIPs = nil
- for _, prefix := range strings.Split(value, ",") {
- if s := strings.TrimSpace(prefix); s != "" {
- inst.AllowedIPs = append(inst.AllowedIPs, s)
- }
- }
- case "protocol", "listen-port", "mtu":
- var number int
- number, err = strconv.Atoi(value)
- if err == nil {
- switch key {
- case "protocol":
- inst.Protocol = number
- case "listen-port":
- inst.ListenPort = number
- case "mtu":
- inst.MTU = number
- }
- }
- case "disabled", "compression", "default-route":
- var enabled bool
- switch value {
- case "yes", "true":
- enabled = true
- case "no", "false":
- enabled = false
- default:
- err = fmt.Errorf("%s must be yes or no", key)
- }
- if err == nil {
- switch key {
- case "disabled":
- inst.Disabled = enabled
- case "compression":
- inst.Compression = enabled
- case "default-route":
- inst.DefaultRoute = enabled
- }
- }
- default:
- err = fmt.Errorf("unknown AeroTUN parameter: %s", key)
- }
- if err != nil {
- return cliError(err)
- }
- }
- if action == "add" {
- if inst.Name == "" {
- return cliError(fmt.Errorf("name is required"))
- }
- if inst.PSK == "" {
- return cliError(fmt.Errorf("psk is required; use /interface aerotun genkey and share it with the peer"))
- }
- }
- inst, err = mgr.Save(inst)
- }
- if err != nil {
- return cliError(err)
- }
- if current, ok := mgr.Get(inst.ID); ok {
- return ColorGreen + fmt.Sprintf("AeroTUN %s: %s\nPublic key: %s\n", current.Name, aeroTUNState(current), current.PublicKey) + ColorReset
- }
- return ColorGreen + "AeroTUN tunnel removed.\n" + ColorReset
- }
- func cliError(err error) string { return ColorRed + "Error: " + err.Error() + "\n" + ColorReset }
- func aeroTUNState(inst aerotun.TunnelInstance) string {
- switch {
- case inst.LastError != "":
- return "failed"
- case inst.Connected:
- return "connected"
- case inst.Running:
- return "connecting"
- case inst.Disabled:
- return "saved/disabled"
- default:
- return "stopped"
- }
- }
|