|
@@ -0,0 +1,627 @@
|
|
|
|
|
+package cli
|
|
|
|
|
+
|
|
|
|
|
+import (
|
|
|
|
|
+ "fmt"
|
|
|
|
|
+ "strconv"
|
|
|
|
|
+ "strings"
|
|
|
|
|
+
|
|
|
|
|
+ "debtik/internal/auth"
|
|
|
|
|
+ "debtik/internal/vpn"
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
|
|
+// ==================== PPP (/ppp) ====================
|
|
|
|
|
+
|
|
|
|
|
+func (e *Executor) handlePPP(parts []string, user *auth.PublicUser) string {
|
|
|
|
|
+ if len(parts) == 0 {
|
|
|
|
|
+ return ColorRed + "Usage: /ppp [profile|secret|active]\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ sub := strings.ToLower(parts[0])
|
|
|
|
|
+ switch sub {
|
|
|
|
|
+ case "profile":
|
|
|
|
|
+ return e.handlePPPProfile(parts[1:], user)
|
|
|
|
|
+ case "secret":
|
|
|
|
|
+ return e.handlePPPSecret(parts[1:], user)
|
|
|
|
|
+ case "active":
|
|
|
|
|
+ return e.handlePPPActive(parts[1:], user)
|
|
|
|
|
+ default:
|
|
|
|
|
+ return fmt.Sprintf(ColorRed+"Unknown ppp command %q. Usage: /ppp [profile|secret|active]\n"+ColorReset, sub)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// ----------------- /ppp profile -----------------
|
|
|
|
|
+
|
|
|
|
|
+func (e *Executor) handlePPPProfile(parts []string, user *auth.PublicUser) string {
|
|
|
|
|
+ if e.vpnMgr == nil || e.vpnMgr.PPPServer == nil {
|
|
|
|
|
+ return ColorRed + "PPP server subsystem not available.\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ mgr := e.vpnMgr.PPPServer
|
|
|
|
|
+
|
|
|
|
|
+ action := "print"
|
|
|
|
|
+ if len(parts) > 0 {
|
|
|
|
|
+ action = strings.ToLower(parts[0])
|
|
|
|
|
+ parts = parts[1:]
|
|
|
|
|
+ }
|
|
|
|
|
+ pos, params := parseArgs(parts)
|
|
|
|
|
+
|
|
|
|
|
+ switch action {
|
|
|
|
|
+ case "print", "pr", "show", "list":
|
|
|
|
|
+ list := mgr.ListProfiles()
|
|
|
|
|
+ tbl := NewTable("#", "NAME", "LOCAL-ADDRESS", "REMOTE-ADDRESS", "DNS-SERVERS", "ENCRYPTION", "ONLY-ONE", "COMMENT")
|
|
|
|
|
+ for i, p := range list {
|
|
|
|
|
+ tbl.AddRow(
|
|
|
|
|
+ strconv.Itoa(i),
|
|
|
|
|
+ p.Name,
|
|
|
|
|
+ p.LocalAddress,
|
|
|
|
|
+ p.RemoteAddress,
|
|
|
|
|
+ p.DNSServers,
|
|
|
|
|
+ p.UseEncryption,
|
|
|
|
|
+ strconv.FormatBool(p.OnlyOne),
|
|
|
|
|
+ p.Comment,
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+ return tbl.String()
|
|
|
|
|
+
|
|
|
|
|
+ case "add":
|
|
|
|
|
+ if user != nil && user.Role == auth.RoleRead {
|
|
|
|
|
+ return ColorRed + "Permission denied: viewer cannot modify profiles\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ name := params["name"]
|
|
|
|
|
+ if name == "" {
|
|
|
|
|
+ if len(pos) > 0 {
|
|
|
|
|
+ name = pos[0]
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return ColorRed + "Syntax error: name is required. Usage: /ppp profile add name=<name> [local-address=...] [remote-address=...]\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ p := vpn.PPPProfile{
|
|
|
|
|
+ ID: name,
|
|
|
|
|
+ Name: name,
|
|
|
|
|
+ LocalAddress: params["local-address"],
|
|
|
|
|
+ RemoteAddress: params["remote-address"],
|
|
|
|
|
+ DNSServers: params["dns-server"],
|
|
|
|
|
+ UseEncryption: params["use-encryption"],
|
|
|
|
|
+ Comment: params["comment"],
|
|
|
|
|
+ }
|
|
|
|
|
+ if p.DNSServers == "" {
|
|
|
|
|
+ p.DNSServers = params["dns-servers"]
|
|
|
|
|
+ }
|
|
|
|
|
+ if p.LocalAddress == "" {
|
|
|
|
|
+ p.LocalAddress = "10.10.10.1"
|
|
|
|
|
+ }
|
|
|
|
|
+ if p.RemoteAddress == "" {
|
|
|
|
|
+ p.RemoteAddress = "10.10.10.10-10.10.10.50"
|
|
|
|
|
+ }
|
|
|
|
|
+ if p.UseEncryption == "" {
|
|
|
|
|
+ p.UseEncryption = "no"
|
|
|
|
|
+ }
|
|
|
|
|
+ if val, ok := params["only-one"]; ok {
|
|
|
|
|
+ p.OnlyOne = val == "yes" || val == "true"
|
|
|
|
|
+ } else {
|
|
|
|
|
+ p.OnlyOne = true
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if err := mgr.SaveProfile(&p); err != nil {
|
|
|
|
|
+ return ColorRed + "Error adding profile: " + err.Error() + "\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ return ColorGreen + fmt.Sprintf("PPP profile %q created successfully.\n", name) + ColorReset
|
|
|
|
|
+
|
|
|
|
|
+ case "set":
|
|
|
|
|
+ if user != nil && user.Role == auth.RoleRead {
|
|
|
|
|
+ return ColorRed + "Permission denied: viewer cannot modify profiles\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ if len(pos) == 0 {
|
|
|
|
|
+ return ColorRed + "Syntax error: target profile name or index required. Usage: /ppp profile set <name> [params...]\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ target := pos[0]
|
|
|
|
|
+ prof := mgr.GetProfile(target)
|
|
|
|
|
+ if prof == nil {
|
|
|
|
|
+ // Check if numeric index was provided
|
|
|
|
|
+ if idx, err := strconv.Atoi(target); err == nil {
|
|
|
|
|
+ all := mgr.ListProfiles()
|
|
|
|
|
+ if idx >= 0 && idx < len(all) {
|
|
|
|
|
+ prof = all[idx]
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if prof == nil {
|
|
|
|
|
+ return ColorRed + fmt.Sprintf("Profile %q not found.\n", target) + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if val, ok := params["local-address"]; ok {
|
|
|
|
|
+ prof.LocalAddress = val
|
|
|
|
|
+ }
|
|
|
|
|
+ if val, ok := params["remote-address"]; ok {
|
|
|
|
|
+ prof.RemoteAddress = val
|
|
|
|
|
+ }
|
|
|
|
|
+ if val, ok := params["dns-server"]; ok {
|
|
|
|
|
+ prof.DNSServers = val
|
|
|
|
|
+ }
|
|
|
|
|
+ if val, ok := params["dns-servers"]; ok {
|
|
|
|
|
+ prof.DNSServers = val
|
|
|
|
|
+ }
|
|
|
|
|
+ if val, ok := params["use-encryption"]; ok {
|
|
|
|
|
+ prof.UseEncryption = val
|
|
|
|
|
+ }
|
|
|
|
|
+ if val, ok := params["only-one"]; ok {
|
|
|
|
|
+ prof.OnlyOne = val == "yes" || val == "true"
|
|
|
|
|
+ }
|
|
|
|
|
+ if val, ok := params["comment"]; ok {
|
|
|
|
|
+ prof.Comment = val
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if err := mgr.SaveProfile(prof); err != nil {
|
|
|
|
|
+ return ColorRed + "Error updating profile: " + err.Error() + "\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ return ColorGreen + fmt.Sprintf("PPP profile %q updated successfully.\n", prof.Name) + ColorReset
|
|
|
|
|
+
|
|
|
|
|
+ case "remove", "delete", "rem":
|
|
|
|
|
+ if user != nil && user.Role == auth.RoleRead {
|
|
|
|
|
+ return ColorRed + "Permission denied: viewer cannot delete profiles\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ if len(pos) == 0 {
|
|
|
|
|
+ return ColorRed + "Syntax error: target profile name or index required. Usage: /ppp profile remove <name>\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ target := pos[0]
|
|
|
|
|
+ if prof := mgr.GetProfile(target); prof == nil {
|
|
|
|
|
+ if idx, err := strconv.Atoi(target); err == nil {
|
|
|
|
|
+ all := mgr.ListProfiles()
|
|
|
|
|
+ if idx >= 0 && idx < len(all) {
|
|
|
|
|
+ target = all[idx].Name
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if err := mgr.DeleteProfile(target); err != nil {
|
|
|
|
|
+ return ColorRed + "Error deleting profile: " + err.Error() + "\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ return ColorGreen + fmt.Sprintf("PPP profile %q removed successfully.\n", target) + ColorReset
|
|
|
|
|
+
|
|
|
|
|
+ default:
|
|
|
|
|
+ return ColorRed + fmt.Sprintf("Unknown action %q. Usage: /ppp profile [print|add|set|remove]\n", action) + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// ----------------- /ppp secret -----------------
|
|
|
|
|
+
|
|
|
|
|
+func (e *Executor) handlePPPSecret(parts []string, user *auth.PublicUser) string {
|
|
|
|
|
+ if e.vpnMgr == nil || e.vpnMgr.PPPServer == nil {
|
|
|
|
|
+ return ColorRed + "PPP server subsystem not available.\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ mgr := e.vpnMgr.PPPServer
|
|
|
|
|
+
|
|
|
|
|
+ action := "print"
|
|
|
|
|
+ if len(parts) > 0 {
|
|
|
|
|
+ action = strings.ToLower(parts[0])
|
|
|
|
|
+ parts = parts[1:]
|
|
|
|
|
+ }
|
|
|
|
|
+ pos, params := parseArgs(parts)
|
|
|
|
|
+
|
|
|
|
|
+ switch action {
|
|
|
|
|
+ case "print", "pr", "show", "list":
|
|
|
|
|
+ list := mgr.ListSecrets()
|
|
|
|
|
+ tbl := NewTable("#", "FLAGS", "NAME", "SERVICE", "PROFILE", "LOCAL-ADDRESS", "REMOTE-ADDRESS", "CALLER-ID", "COMMENT")
|
|
|
|
|
+ for i, s := range list {
|
|
|
|
|
+ flags := " "
|
|
|
|
|
+ if s.Disabled {
|
|
|
|
|
+ flags = "X"
|
|
|
|
|
+ }
|
|
|
|
|
+ tbl.AddRow(
|
|
|
|
|
+ strconv.Itoa(i),
|
|
|
|
|
+ flags,
|
|
|
|
|
+ s.Name,
|
|
|
|
|
+ s.Service,
|
|
|
|
|
+ s.Profile,
|
|
|
|
|
+ s.LocalAddress,
|
|
|
|
|
+ s.RemoteAddress,
|
|
|
|
|
+ s.CallerID,
|
|
|
|
|
+ s.Comment,
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+ return tbl.String()
|
|
|
|
|
+
|
|
|
|
|
+ case "add":
|
|
|
|
|
+ if user != nil && user.Role == auth.RoleRead {
|
|
|
|
|
+ return ColorRed + "Permission denied: viewer cannot add secrets\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ name := params["name"]
|
|
|
|
|
+ pass := params["password"]
|
|
|
|
|
+ if name == "" || pass == "" {
|
|
|
|
|
+ return ColorRed + "Syntax error: name and password are required. Usage: /ppp secret add name=<user> password=<pass> [profile=...] [service=any|l2tp|pptp|pppoe]\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ sec := vpn.PPPSecret{
|
|
|
|
|
+ Name: name,
|
|
|
|
|
+ Password: pass,
|
|
|
|
|
+ Service: params["service"],
|
|
|
|
|
+ Profile: params["profile"],
|
|
|
|
|
+ LocalAddress: params["local-address"],
|
|
|
|
|
+ RemoteAddress: params["remote-address"],
|
|
|
|
|
+ CallerID: params["caller-id"],
|
|
|
|
|
+ Comment: params["comment"],
|
|
|
|
|
+ }
|
|
|
|
|
+ if sec.Service == "" {
|
|
|
|
|
+ sec.Service = "any"
|
|
|
|
|
+ }
|
|
|
|
|
+ if sec.Profile == "" {
|
|
|
|
|
+ sec.Profile = "default"
|
|
|
|
|
+ }
|
|
|
|
|
+ if val, ok := params["disabled"]; ok {
|
|
|
|
|
+ sec.Disabled = val == "yes" || val == "true"
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if err := mgr.SaveSecret(&sec); err != nil {
|
|
|
|
|
+ return ColorRed + "Error adding secret: " + err.Error() + "\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ return ColorGreen + fmt.Sprintf("PPP secret %q created successfully.\n", name) + ColorReset
|
|
|
|
|
+
|
|
|
|
|
+ case "set":
|
|
|
|
|
+ if user != nil && user.Role == auth.RoleRead {
|
|
|
|
|
+ return ColorRed + "Permission denied: viewer cannot modify secrets\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ if len(pos) == 0 {
|
|
|
|
|
+ return ColorRed + "Syntax error: target secret name or index required. Usage: /ppp secret set <name> [params...]\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ target := pos[0]
|
|
|
|
|
+ sec := findSecret(mgr, target)
|
|
|
|
|
+ if sec == nil {
|
|
|
|
|
+ return ColorRed + fmt.Sprintf("Secret %q not found.\n", target) + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if val, ok := params["password"]; ok {
|
|
|
|
|
+ sec.Password = val
|
|
|
|
|
+ }
|
|
|
|
|
+ if val, ok := params["profile"]; ok {
|
|
|
|
|
+ sec.Profile = val
|
|
|
|
|
+ }
|
|
|
|
|
+ if val, ok := params["service"]; ok {
|
|
|
|
|
+ sec.Service = val
|
|
|
|
|
+ }
|
|
|
|
|
+ if val, ok := params["local-address"]; ok {
|
|
|
|
|
+ sec.LocalAddress = val
|
|
|
|
|
+ }
|
|
|
|
|
+ if val, ok := params["remote-address"]; ok {
|
|
|
|
|
+ sec.RemoteAddress = val
|
|
|
|
|
+ }
|
|
|
|
|
+ if val, ok := params["caller-id"]; ok {
|
|
|
|
|
+ sec.CallerID = val
|
|
|
|
|
+ }
|
|
|
|
|
+ if val, ok := params["comment"]; ok {
|
|
|
|
|
+ sec.Comment = val
|
|
|
|
|
+ }
|
|
|
|
|
+ if val, ok := params["disabled"]; ok {
|
|
|
|
|
+ sec.Disabled = val == "yes" || val == "true"
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if err := mgr.SaveSecret(sec); err != nil {
|
|
|
|
|
+ return ColorRed + "Error updating secret: " + err.Error() + "\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ return ColorGreen + fmt.Sprintf("PPP secret %q updated successfully.\n", sec.Name) + ColorReset
|
|
|
|
|
+
|
|
|
|
|
+ case "remove", "delete", "rem":
|
|
|
|
|
+ if user != nil && user.Role == auth.RoleRead {
|
|
|
|
|
+ return ColorRed + "Permission denied: viewer cannot delete secrets\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ if len(pos) == 0 {
|
|
|
|
|
+ return ColorRed + "Syntax error: target secret name or index required. Usage: /ppp secret remove <name>\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ sec := findSecret(mgr, pos[0])
|
|
|
|
|
+ if sec == nil {
|
|
|
|
|
+ return ColorRed + fmt.Sprintf("Secret %q not found.\n", pos[0]) + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ if err := mgr.DeleteSecret(sec.ID); err != nil {
|
|
|
|
|
+ return ColorRed + "Error deleting secret: " + err.Error() + "\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ return ColorGreen + fmt.Sprintf("PPP secret %q removed successfully.\n", sec.Name) + ColorReset
|
|
|
|
|
+
|
|
|
|
|
+ case "enable":
|
|
|
|
|
+ if user != nil && user.Role == auth.RoleRead {
|
|
|
|
|
+ return ColorRed + "Permission denied\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ if len(pos) == 0 {
|
|
|
|
|
+ return ColorRed + "Usage: /ppp secret enable <name>\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ sec := findSecret(mgr, pos[0])
|
|
|
|
|
+ if sec == nil {
|
|
|
|
|
+ return ColorRed + fmt.Sprintf("Secret %q not found.\n", pos[0]) + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ if err := mgr.SetSecretState(sec.ID, false); err != nil {
|
|
|
|
|
+ return ColorRed + err.Error() + "\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ return ColorGreen + fmt.Sprintf("PPP secret %q enabled.\n", sec.Name) + ColorReset
|
|
|
|
|
+
|
|
|
|
|
+ case "disable":
|
|
|
|
|
+ if user != nil && user.Role == auth.RoleRead {
|
|
|
|
|
+ return ColorRed + "Permission denied\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ if len(pos) == 0 {
|
|
|
|
|
+ return ColorRed + "Usage: /ppp secret disable <name>\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ sec := findSecret(mgr, pos[0])
|
|
|
|
|
+ if sec == nil {
|
|
|
|
|
+ return ColorRed + fmt.Sprintf("Secret %q not found.\n", pos[0]) + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ if err := mgr.SetSecretState(sec.ID, true); err != nil {
|
|
|
|
|
+ return ColorRed + err.Error() + "\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ return ColorGreen + fmt.Sprintf("PPP secret %q disabled.\n", sec.Name) + ColorReset
|
|
|
|
|
+
|
|
|
|
|
+ default:
|
|
|
|
|
+ return ColorRed + fmt.Sprintf("Unknown action %q. Usage: /ppp secret [print|add|set|remove|enable|disable]\n", action) + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func findSecret(mgr *vpn.PPPServerManager, target string) *vpn.PPPSecret {
|
|
|
|
|
+ list := mgr.ListSecrets()
|
|
|
|
|
+ for _, s := range list {
|
|
|
|
|
+ if s.ID == target || s.Name == target {
|
|
|
|
|
+ return s
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if idx, err := strconv.Atoi(target); err == nil && idx >= 0 && idx < len(list) {
|
|
|
|
|
+ return list[idx]
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// ----------------- /ppp active -----------------
|
|
|
|
|
+
|
|
|
|
|
+func (e *Executor) handlePPPActive(parts []string, user *auth.PublicUser) string {
|
|
|
|
|
+ if e.vpnMgr == nil || e.vpnMgr.PPPServer == nil {
|
|
|
|
|
+ return ColorRed + "PPP server subsystem not available.\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ mgr := e.vpnMgr.PPPServer
|
|
|
|
|
+
|
|
|
|
|
+ action := "print"
|
|
|
|
|
+ if len(parts) > 0 {
|
|
|
|
|
+ action = strings.ToLower(parts[0])
|
|
|
|
|
+ parts = parts[1:]
|
|
|
|
|
+ }
|
|
|
|
|
+ pos, _ := parseArgs(parts)
|
|
|
|
|
+
|
|
|
|
|
+ switch action {
|
|
|
|
|
+ case "print", "pr", "show", "list":
|
|
|
|
|
+ list := mgr.ListActiveSessions()
|
|
|
|
|
+ tbl := NewTable("#", "INTERFACE", "USER", "SERVICE", "CALLER-ID", "ADDRESS", "UPTIME", "RX", "TX")
|
|
|
|
|
+ for i, s := range list {
|
|
|
|
|
+ tbl.AddRow(
|
|
|
|
|
+ strconv.Itoa(i),
|
|
|
|
|
+ s.Interface,
|
|
|
|
|
+ s.Username,
|
|
|
|
|
+ s.Service,
|
|
|
|
|
+ s.CallerID,
|
|
|
|
|
+ s.Address,
|
|
|
|
|
+ s.Uptime,
|
|
|
|
|
+ s.RxHuman,
|
|
|
|
|
+ s.TxHuman,
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+ return tbl.String()
|
|
|
|
|
+
|
|
|
|
|
+ case "remove", "disconnect", "kill":
|
|
|
|
|
+ if user != nil && user.Role == auth.RoleRead {
|
|
|
|
|
+ return ColorRed + "Permission denied\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ if len(pos) == 0 {
|
|
|
|
|
+ return ColorRed + "Usage: /ppp active remove <interface>\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ iface := pos[0]
|
|
|
|
|
+ if err := mgr.DisconnectSession(iface); err != nil {
|
|
|
|
|
+ return ColorRed + "Error disconnecting session: " + err.Error() + "\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ return ColorGreen + fmt.Sprintf("Session on %s disconnected.\n", iface) + ColorReset
|
|
|
|
|
+
|
|
|
|
|
+ default:
|
|
|
|
|
+ return ColorRed + fmt.Sprintf("Unknown action %q. Usage: /ppp active [print|remove <iface>]\n", action) + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// ==================== INTERFACE VPN SERVERS ====================
|
|
|
|
|
+
|
|
|
|
|
+// ----------------- /interface l2tp-server server -----------------
|
|
|
|
|
+
|
|
|
|
|
+func (e *Executor) handleInterfaceL2TPServer(parts []string, user *auth.PublicUser) string {
|
|
|
|
|
+ if e.vpnMgr == nil || e.vpnMgr.PPPServer == nil {
|
|
|
|
|
+ return ColorRed + "VPN server subsystem not available.\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ mgr := e.vpnMgr.PPPServer
|
|
|
|
|
+
|
|
|
|
|
+ // Skip optional "server" subkeyword if present (e.g. /interface l2tp-server server print)
|
|
|
|
|
+ if len(parts) > 0 && strings.ToLower(parts[0]) == "server" {
|
|
|
|
|
+ parts = parts[1:]
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ action := "print"
|
|
|
|
|
+ if len(parts) > 0 {
|
|
|
|
|
+ action = strings.ToLower(parts[0])
|
|
|
|
|
+ parts = parts[1:]
|
|
|
|
|
+ }
|
|
|
|
|
+ _, params := parseArgs(parts)
|
|
|
|
|
+
|
|
|
|
|
+ switch action {
|
|
|
|
|
+ case "print", "pr", "show":
|
|
|
|
|
+ cfg := mgr.GetL2TPServer()
|
|
|
|
|
+ tbl := NewTable("ENABLED", "PORT", "DEFAULT-PROFILE", "USE-IPSEC", "RUNNING", "ACTIVE-SESSIONS", "LAST-ERROR")
|
|
|
|
|
+ tbl.AddRow(
|
|
|
|
|
+ strconv.FormatBool(cfg.Enabled),
|
|
|
|
|
+ strconv.Itoa(cfg.Port),
|
|
|
|
|
+ cfg.DefaultProfile,
|
|
|
|
|
+ cfg.UseIPSec,
|
|
|
|
|
+ strconv.FormatBool(cfg.Running),
|
|
|
|
|
+ strconv.Itoa(cfg.ActiveSessions),
|
|
|
|
|
+ cfg.LastError,
|
|
|
|
|
+ )
|
|
|
|
|
+ return tbl.String()
|
|
|
|
|
+
|
|
|
|
|
+ case "set":
|
|
|
|
|
+ if user != nil && user.Role == auth.RoleRead {
|
|
|
|
|
+ return ColorRed + "Permission denied\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ cfg := mgr.GetL2TPServer()
|
|
|
|
|
+ if val, ok := params["enabled"]; ok {
|
|
|
|
|
+ cfg.Enabled = val == "yes" || val == "true"
|
|
|
|
|
+ }
|
|
|
|
|
+ if val, ok := params["port"]; ok {
|
|
|
|
|
+ if p, err := strconv.Atoi(val); err == nil && p > 0 {
|
|
|
|
|
+ cfg.Port = p
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if val, ok := params["default-profile"]; ok {
|
|
|
|
|
+ cfg.DefaultProfile = val
|
|
|
|
|
+ }
|
|
|
|
|
+ if val, ok := params["use-ipsec"]; ok {
|
|
|
|
|
+ cfg.UseIPSec = val
|
|
|
|
|
+ }
|
|
|
|
|
+ if val, ok := params["ipsec-secret"]; ok {
|
|
|
|
|
+ cfg.IPSecSecret = val
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if err := mgr.SetL2TPServer(cfg); err != nil {
|
|
|
|
|
+ return ColorRed + "Error applying L2TP server: " + err.Error() + "\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ return ColorGreen + "L2TP server configuration updated successfully.\n" + ColorReset
|
|
|
|
|
+
|
|
|
|
|
+ default:
|
|
|
|
|
+ return ColorRed + fmt.Sprintf("Unknown action %q. Usage: /interface l2tp-server server [print|set enabled=yes|no default-profile=...]\n", action) + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// ----------------- /interface pptp-server server -----------------
|
|
|
|
|
+
|
|
|
|
|
+func (e *Executor) handleInterfacePPTPServer(parts []string, user *auth.PublicUser) string {
|
|
|
|
|
+ if e.vpnMgr == nil || e.vpnMgr.PPPServer == nil {
|
|
|
|
|
+ return ColorRed + "VPN server subsystem not available.\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ mgr := e.vpnMgr.PPPServer
|
|
|
|
|
+
|
|
|
|
|
+ if len(parts) > 0 && strings.ToLower(parts[0]) == "server" {
|
|
|
|
|
+ parts = parts[1:]
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ action := "print"
|
|
|
|
|
+ if len(parts) > 0 {
|
|
|
|
|
+ action = strings.ToLower(parts[0])
|
|
|
|
|
+ parts = parts[1:]
|
|
|
|
|
+ }
|
|
|
|
|
+ _, params := parseArgs(parts)
|
|
|
|
|
+
|
|
|
|
|
+ switch action {
|
|
|
|
|
+ case "print", "pr", "show":
|
|
|
|
|
+ cfg := mgr.GetPPTPServer()
|
|
|
|
|
+ tbl := NewTable("ENABLED", "PORT", "DEFAULT-PROFILE", "REQUIRE-MPPE", "RUNNING", "ACTIVE-SESSIONS", "LAST-ERROR")
|
|
|
|
|
+ tbl.AddRow(
|
|
|
|
|
+ strconv.FormatBool(cfg.Enabled),
|
|
|
|
|
+ strconv.Itoa(cfg.Port),
|
|
|
|
|
+ cfg.DefaultProfile,
|
|
|
|
|
+ strconv.FormatBool(cfg.RequireMPPE),
|
|
|
|
|
+ strconv.FormatBool(cfg.Running),
|
|
|
|
|
+ strconv.Itoa(cfg.ActiveSessions),
|
|
|
|
|
+ cfg.LastError,
|
|
|
|
|
+ )
|
|
|
|
|
+ return tbl.String()
|
|
|
|
|
+
|
|
|
|
|
+ case "set":
|
|
|
|
|
+ if user != nil && user.Role == auth.RoleRead {
|
|
|
|
|
+ return ColorRed + "Permission denied\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ cfg := mgr.GetPPTPServer()
|
|
|
|
|
+ if val, ok := params["enabled"]; ok {
|
|
|
|
|
+ cfg.Enabled = val == "yes" || val == "true"
|
|
|
|
|
+ }
|
|
|
|
|
+ if val, ok := params["port"]; ok {
|
|
|
|
|
+ if p, err := strconv.Atoi(val); err == nil && p > 0 {
|
|
|
|
|
+ cfg.Port = p
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if val, ok := params["default-profile"]; ok {
|
|
|
|
|
+ cfg.DefaultProfile = val
|
|
|
|
|
+ }
|
|
|
|
|
+ if val, ok := params["require-mppe"]; ok {
|
|
|
|
|
+ cfg.RequireMPPE = val == "yes" || val == "true"
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if err := mgr.SetPPTPServer(cfg); err != nil {
|
|
|
|
|
+ return ColorRed + "Error applying PPTP server: " + err.Error() + "\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ return ColorGreen + "PPTP server configuration updated successfully.\n" + ColorReset
|
|
|
|
|
+
|
|
|
|
|
+ default:
|
|
|
|
|
+ return ColorRed + fmt.Sprintf("Unknown action %q. Usage: /interface pptp-server server [print|set enabled=yes|no default-profile=...]\n", action) + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// ----------------- /interface pppoe-server server -----------------
|
|
|
|
|
+
|
|
|
|
|
+func (e *Executor) handleInterfacePPPoEServer(parts []string, user *auth.PublicUser) string {
|
|
|
|
|
+ if e.vpnMgr == nil || e.vpnMgr.PPPServer == nil {
|
|
|
|
|
+ return ColorRed + "VPN server subsystem not available.\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ mgr := e.vpnMgr.PPPServer
|
|
|
|
|
+
|
|
|
|
|
+ if len(parts) > 0 && strings.ToLower(parts[0]) == "server" {
|
|
|
|
|
+ parts = parts[1:]
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ action := "print"
|
|
|
|
|
+ if len(parts) > 0 {
|
|
|
|
|
+ action = strings.ToLower(parts[0])
|
|
|
|
|
+ parts = parts[1:]
|
|
|
|
|
+ }
|
|
|
|
|
+ _, params := parseArgs(parts)
|
|
|
|
|
+
|
|
|
|
|
+ switch action {
|
|
|
|
|
+ case "print", "pr", "show":
|
|
|
|
|
+ cfg := mgr.GetPPPoEServer()
|
|
|
|
|
+ tbl := NewTable("ENABLED", "SERVICE-NAME", "INTERFACE", "DEFAULT-PROFILE", "ONE-SESSION-PER-HOST", "RUNNING", "ACTIVE-SESSIONS", "LAST-ERROR")
|
|
|
|
|
+ tbl.AddRow(
|
|
|
|
|
+ strconv.FormatBool(cfg.Enabled),
|
|
|
|
|
+ cfg.ServiceName,
|
|
|
|
|
+ cfg.Interface,
|
|
|
|
|
+ cfg.DefaultProfile,
|
|
|
|
|
+ strconv.FormatBool(cfg.OneSessionPerHost),
|
|
|
|
|
+ strconv.FormatBool(cfg.Running),
|
|
|
|
|
+ strconv.Itoa(cfg.ActiveSessions),
|
|
|
|
|
+ cfg.LastError,
|
|
|
|
|
+ )
|
|
|
|
|
+ return tbl.String()
|
|
|
|
|
+
|
|
|
|
|
+ case "set":
|
|
|
|
|
+ if user != nil && user.Role == auth.RoleRead {
|
|
|
|
|
+ return ColorRed + "Permission denied\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ cfg := mgr.GetPPPoEServer()
|
|
|
|
|
+ if val, ok := params["enabled"]; ok {
|
|
|
|
|
+ cfg.Enabled = val == "yes" || val == "true"
|
|
|
|
|
+ }
|
|
|
|
|
+ if val, ok := params["service-name"]; ok {
|
|
|
|
|
+ cfg.ServiceName = val
|
|
|
|
|
+ }
|
|
|
|
|
+ if val, ok := params["interface"]; ok {
|
|
|
|
|
+ cfg.Interface = val
|
|
|
|
|
+ }
|
|
|
|
|
+ if val, ok := params["default-profile"]; ok {
|
|
|
|
|
+ cfg.DefaultProfile = val
|
|
|
|
|
+ }
|
|
|
|
|
+ if val, ok := params["one-session-per-host"]; ok {
|
|
|
|
|
+ cfg.OneSessionPerHost = val == "yes" || val == "true"
|
|
|
|
|
+ }
|
|
|
|
|
+ if val, ok := params["max-mtu"]; ok {
|
|
|
|
|
+ if m, err := strconv.Atoi(val); err == nil && m > 0 {
|
|
|
|
|
+ cfg.MaxMTU = m
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if val, ok := params["max-mru"]; ok {
|
|
|
|
|
+ if m, err := strconv.Atoi(val); err == nil && m > 0 {
|
|
|
|
|
+ cfg.MaxMRU = m
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if err := mgr.SetPPPoEServer(cfg); err != nil {
|
|
|
|
|
+ return ColorRed + "Error applying PPPoE server: " + err.Error() + "\n" + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+ return ColorGreen + "PPPoE server configuration updated successfully.\n" + ColorReset
|
|
|
|
|
+
|
|
|
|
|
+ default:
|
|
|
|
|
+ return ColorRed + fmt.Sprintf("Unknown action %q. Usage: /interface pppoe-server server [print|set enabled=yes|no interface=... default-profile=...]\n", action) + ColorReset
|
|
|
|
|
+ }
|
|
|
|
|
+}
|