package api import ( "encoding/json" "net/http" "proxmox-router/internal/vpn" ) func (s *Server) handleOverallVPNStatus(w http.ResponseWriter, r *http.Request) { status := s.vpnMgr.GetOverallStatus() writeJSON(w, http.StatusOK, status) } // ======================== PPPoE Multi-Instance Handlers ======================== func (s *Server) handleListPPPoE(w http.ResponseWriter, r *http.Request) { list := s.vpnMgr.PPPoE.List() writeJSON(w, http.StatusOK, list) } func (s *Server) handleSavePPPoE(w http.ResponseWriter, r *http.Request) { var inst vpn.PPPoEInstance if err := json.NewDecoder(r.Body).Decode(&inst); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } if err := s.vpnMgr.PPPoE.Save(inst); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "name": inst.Name}) } func (s *Server) handleDeletePPPoE(w http.ResponseWriter, r *http.Request) { name := r.PathValue("name") if err := s.vpnMgr.PPPoE.Delete(name); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "name": name}) } func (s *Server) handleSetPPPoEState(w http.ResponseWriter, r *http.Request) { name := r.PathValue("name") var req struct { Enabled bool `json:"enabled"` } _ = json.NewDecoder(r.Body).Decode(&req) if err := s.vpnMgr.PPPoE.SetEnabled(name, req.Enabled); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "name": name, "enabled": req.Enabled}) } func (s *Server) handleConnectPPPoE(w http.ResponseWriter, r *http.Request) { name := r.PathValue("name") if err := s.vpnMgr.PPPoE.Connect(name); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "name": name}) } func (s *Server) handleDisconnectPPPoE(w http.ResponseWriter, r *http.Request) { name := r.PathValue("name") if err := s.vpnMgr.PPPoE.Disconnect(name); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "name": name}) } // ======================== WireGuard Multi-Interface & Peer Handlers ======================== func (s *Server) handleListWireGuardInterfaces(w http.ResponseWriter, r *http.Request) { ifaces := s.vpnMgr.WireGuard.ListInterfaces() writeJSON(w, http.StatusOK, ifaces) } func (s *Server) handleSaveWireGuardInterface(w http.ResponseWriter, r *http.Request) { var req vpn.SaveWireGuardInterfaceRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } if err := s.vpnMgr.WireGuard.SaveInterface(req); err != nil { writeError(w, http.StatusBadRequest, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "name": req.Name}) } func (s *Server) handleDeleteWireGuardInterface(w http.ResponseWriter, r *http.Request) { name := r.PathValue("name") if err := s.vpnMgr.WireGuard.DeleteInterface(name); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "name": name}) } func (s *Server) handleSetWireGuardInterfaceState(w http.ResponseWriter, r *http.Request) { name := r.PathValue("name") var req struct { Enabled bool `json:"enabled"` } _ = json.NewDecoder(r.Body).Decode(&req) if err := s.vpnMgr.WireGuard.SetInterfaceEnabled(name, req.Enabled); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "name": name, "enabled": req.Enabled}) } func (s *Server) handleStartWireGuardInterface(w http.ResponseWriter, r *http.Request) { name := r.PathValue("name") if err := s.vpnMgr.WireGuard.StartInterface(name); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "name": name}) } func (s *Server) handleStopWireGuardInterface(w http.ResponseWriter, r *http.Request) { name := r.PathValue("name") if err := s.vpnMgr.WireGuard.StopInterface(name); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "name": name}) } func (s *Server) handleListWireGuardPeers(w http.ResponseWriter, r *http.Request) { ifaceFilter := r.URL.Query().Get("interface") peers := s.vpnMgr.WireGuard.ListPeers(ifaceFilter) writeJSON(w, http.StatusOK, peers) } func (s *Server) handleSaveWireGuardPeer(w http.ResponseWriter, r *http.Request) { var req vpn.SaveWireGuardPeerRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil || req.PublicKey == "" || req.Interface == "" { writeError(w, http.StatusBadRequest, "interface and public_key are required") return } if err := s.vpnMgr.WireGuard.SavePeer(req); err != nil { writeError(w, http.StatusBadRequest, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "interface": req.Interface, "public_key": req.PublicKey}) } func (s *Server) handleDeleteWireGuardPeer(w http.ResponseWriter, r *http.Request) { iface := r.PathValue("iface") pubkey := r.PathValue("pubkey") if iface == "" || pubkey == "" { iface = r.URL.Query().Get("interface") pubkey = r.URL.Query().Get("public_key") } if iface == "" || pubkey == "" { var body struct { Interface string `json:"interface"` PublicKey string `json:"public_key"` } _ = json.NewDecoder(r.Body).Decode(&body) if body.Interface != "" { iface = body.Interface } if body.PublicKey != "" { pubkey = body.PublicKey } } if iface == "" || pubkey == "" { writeError(w, http.StatusBadRequest, "interface and public_key are required") return } if err := s.vpnMgr.WireGuard.DeletePeer(iface, pubkey); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "interface": iface, "public_key": pubkey}) } func (s *Server) handleSetWireGuardPeerState(w http.ResponseWriter, r *http.Request) { var req struct { Interface string `json:"interface"` PublicKey string `json:"public_key"` Enabled bool `json:"enabled"` } _ = json.NewDecoder(r.Body).Decode(&req) if req.Interface == "" { req.Interface = r.PathValue("iface") } if req.PublicKey == "" { req.PublicKey = r.PathValue("pubkey") } if req.Interface == "" || req.PublicKey == "" { writeError(w, http.StatusBadRequest, "interface and public_key are required") return } if err := s.vpnMgr.WireGuard.SetPeerEnabled(req.Interface, req.PublicKey, req.Enabled); err != nil { writeError(w, http.StatusBadRequest, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "interface": req.Interface, "public_key": req.PublicKey, "enabled": req.Enabled}) } func (s *Server) handleWireGuardGenKeys(w http.ResponseWriter, r *http.Request) { priv, pub, err := s.vpnMgr.WireGuard.GenerateKeyPair() if err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]string{ "private_key": priv, "public_key": pub, }) } func (s *Server) handleWireGuardCalcPubKey(w http.ResponseWriter, r *http.Request) { var req struct { PrivateKey string `json:"private_key"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil || req.PrivateKey == "" { writeError(w, http.StatusBadRequest, "private_key is required") return } pub, err := s.vpnMgr.WireGuard.CalcPublicKey(req.PrivateKey) if err != nil { writeError(w, http.StatusBadRequest, err.Error()) return } writeJSON(w, http.StatusOK, map[string]string{"public_key": pub}) } // ======================== PPTP Multi-Instance Handlers ======================== func (s *Server) handleListPPTP(w http.ResponseWriter, r *http.Request) { list := s.vpnMgr.PPTP.List() writeJSON(w, http.StatusOK, list) } func (s *Server) handleSavePPTP(w http.ResponseWriter, r *http.Request) { var inst vpn.PPTPInstance if err := json.NewDecoder(r.Body).Decode(&inst); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } if err := s.vpnMgr.PPTP.Save(inst); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "name": inst.Name}) } func (s *Server) handleDeletePPTP(w http.ResponseWriter, r *http.Request) { name := r.PathValue("name") if err := s.vpnMgr.PPTP.Delete(name); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "name": name}) } func (s *Server) handleSetPPTPState(w http.ResponseWriter, r *http.Request) { name := r.PathValue("name") var req struct { Enabled bool `json:"enabled"` } _ = json.NewDecoder(r.Body).Decode(&req) if err := s.vpnMgr.PPTP.SetEnabled(name, req.Enabled); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "name": name, "enabled": req.Enabled}) } func (s *Server) handleConnectPPTP(w http.ResponseWriter, r *http.Request) { name := r.PathValue("name") if err := s.vpnMgr.PPTP.Connect(name); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "name": name}) } func (s *Server) handleDisconnectPPTP(w http.ResponseWriter, r *http.Request) { name := r.PathValue("name") if err := s.vpnMgr.PPTP.Disconnect(name); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "name": name}) } // ======================== L2TP Multi-Instance Handlers ======================== func (s *Server) handleListL2TP(w http.ResponseWriter, r *http.Request) { list := s.vpnMgr.L2TP.List() writeJSON(w, http.StatusOK, list) } func (s *Server) handleSaveL2TP(w http.ResponseWriter, r *http.Request) { var inst vpn.L2TPInstance if err := json.NewDecoder(r.Body).Decode(&inst); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } if err := s.vpnMgr.L2TP.Save(inst); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "name": inst.Name}) } func (s *Server) handleDeleteL2TP(w http.ResponseWriter, r *http.Request) { name := r.PathValue("name") if err := s.vpnMgr.L2TP.Delete(name); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "name": name}) } func (s *Server) handleSetL2TPState(w http.ResponseWriter, r *http.Request) { name := r.PathValue("name") var req struct { Enabled bool `json:"enabled"` } _ = json.NewDecoder(r.Body).Decode(&req) if err := s.vpnMgr.L2TP.SetEnabled(name, req.Enabled); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "name": name, "enabled": req.Enabled}) } func (s *Server) handleConnectL2TP(w http.ResponseWriter, r *http.Request) { name := r.PathValue("name") if err := s.vpnMgr.L2TP.Connect(name); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "name": name}) } func (s *Server) handleDisconnectL2TP(w http.ResponseWriter, r *http.Request) { name := r.PathValue("name") if err := s.vpnMgr.L2TP.Disconnect(name); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "name": name}) } // ======================== IPSec Multi-Tunnel Handlers ======================== func (s *Server) handleListIPSec(w http.ResponseWriter, r *http.Request) { list := s.vpnMgr.IPSec.List() writeJSON(w, http.StatusOK, list) } func (s *Server) handleSaveIPSecTunnel(w http.ResponseWriter, r *http.Request) { var conn vpn.IPSecConnection if err := json.NewDecoder(r.Body).Decode(&conn); err != nil || conn.Name == "" { writeError(w, http.StatusBadRequest, "invalid request body") return } if err := s.vpnMgr.IPSec.SaveConnection(conn); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "name": conn.Name}) } func (s *Server) handleDeleteIPSecTunnel(w http.ResponseWriter, r *http.Request) { name := r.PathValue("name") if err := s.vpnMgr.IPSec.DeleteConnection(name); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "name": name}) } func (s *Server) handleSetIPSecState(w http.ResponseWriter, r *http.Request) { name := r.PathValue("name") var req struct { Enabled bool `json:"enabled"` } _ = json.NewDecoder(r.Body).Decode(&req) if err := s.vpnMgr.IPSec.SetEnabled(name, req.Enabled); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "name": name, "enabled": req.Enabled}) } func (s *Server) handleInitiateIPSecTunnel(w http.ResponseWriter, r *http.Request) { name := r.PathValue("name") if err := s.vpnMgr.IPSec.StartTunnel(name); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "name": name}) } func (s *Server) handleTerminateIPSecTunnel(w http.ResponseWriter, r *http.Request) { name := r.PathValue("name") if err := s.vpnMgr.IPSec.StopTunnel(name); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "name": name}) } // ======================== EoIP (Ethernet-over-IP) Handlers ======================== func (s *Server) handleListEoIP(w http.ResponseWriter, r *http.Request) { list := s.vpnMgr.EoIP.List() writeJSON(w, http.StatusOK, list) } func (s *Server) handleSaveEoIP(w http.ResponseWriter, r *http.Request) { var inst vpn.EoIPInstance if err := json.NewDecoder(r.Body).Decode(&inst); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } if err := s.vpnMgr.EoIP.Save(&inst); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": inst.ID, "name": inst.Name}) } func (s *Server) handleDeleteEoIP(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") if err := s.vpnMgr.EoIP.Delete(id); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id}) } func (s *Server) handleSetEoIPState(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") var req struct { Disabled bool `json:"disabled"` } _ = json.NewDecoder(r.Body).Decode(&req) if err := s.vpnMgr.EoIP.SetState(id, req.Disabled); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id, "disabled": req.Disabled}) } // ======================== PPP Profiles Handlers ======================== func (s *Server) handleListPPPProfiles(w http.ResponseWriter, r *http.Request) { list := s.vpnMgr.PPPServer.ListProfiles() writeJSON(w, http.StatusOK, list) } func (s *Server) handleSavePPPProfile(w http.ResponseWriter, r *http.Request) { var prof vpn.PPPProfile if err := json.NewDecoder(r.Body).Decode(&prof); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } if err := s.vpnMgr.PPPServer.SaveProfile(&prof); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "name": prof.Name}) } func (s *Server) handleDeletePPPProfile(w http.ResponseWriter, r *http.Request) { name := r.PathValue("name") if err := s.vpnMgr.PPPServer.DeleteProfile(name); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "name": name}) } // ======================== PPP Secrets Handlers ======================== func (s *Server) handleListPPPSecrets(w http.ResponseWriter, r *http.Request) { list := s.vpnMgr.PPPServer.ListSecrets() writeJSON(w, http.StatusOK, list) } func (s *Server) handleSavePPPSecret(w http.ResponseWriter, r *http.Request) { var sec vpn.PPPSecret if err := json.NewDecoder(r.Body).Decode(&sec); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } if err := s.vpnMgr.PPPServer.SaveSecret(&sec); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": sec.ID, "name": sec.Name}) } func (s *Server) handleSetPPPSecretState(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") var req struct { Disabled bool `json:"disabled"` } _ = json.NewDecoder(r.Body).Decode(&req) if err := s.vpnMgr.PPPServer.SetSecretState(id, req.Disabled); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id, "disabled": req.Disabled}) } func (s *Server) handleDeletePPPSecret(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") if err := s.vpnMgr.PPPServer.DeleteSecret(id); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "id": id}) } // ======================== Active PPP Sessions Handlers ======================== func (s *Server) handleListPPPSessions(w http.ResponseWriter, r *http.Request) { list := s.vpnMgr.PPPServer.ListActiveSessions() writeJSON(w, http.StatusOK, list) } func (s *Server) handleDisconnectPPPSession(w http.ResponseWriter, r *http.Request) { iface := r.PathValue("iface") if err := s.vpnMgr.PPPServer.DisconnectSession(iface); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "interface": iface}) } // ======================== VPN Servers Configuration Handlers ======================== func (s *Server) handleGetPPPoEServer(w http.ResponseWriter, r *http.Request) { cfg := s.vpnMgr.PPPServer.GetPPPoEServer() writeJSON(w, http.StatusOK, cfg) } func (s *Server) handleSetPPPoEServer(w http.ResponseWriter, r *http.Request) { var cfg vpn.PPPoEServerConfig if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } if err := s.vpnMgr.PPPServer.SetPPPoEServer(cfg); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true}) } func (s *Server) handleGetPPTPServer(w http.ResponseWriter, r *http.Request) { cfg := s.vpnMgr.PPPServer.GetPPTPServer() writeJSON(w, http.StatusOK, cfg) } func (s *Server) handleSetPPTPServer(w http.ResponseWriter, r *http.Request) { var cfg vpn.PPTPServerConfig if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } if err := s.vpnMgr.PPPServer.SetPPTPServer(cfg); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true}) } func (s *Server) handleGetL2TPServer(w http.ResponseWriter, r *http.Request) { cfg := s.vpnMgr.PPPServer.GetL2TPServer() writeJSON(w, http.StatusOK, cfg) } func (s *Server) handleSetL2TPServer(w http.ResponseWriter, r *http.Request) { var cfg vpn.L2TPServerConfig if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } if err := s.vpnMgr.PPPServer.SetL2TPServer(cfg); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true}) } func (s *Server) handleGetIPSecServer(w http.ResponseWriter, r *http.Request) { cfg := s.vpnMgr.PPPServer.GetIPSecServer() writeJSON(w, http.StatusOK, cfg) } func (s *Server) handleSetIPSecServer(w http.ResponseWriter, r *http.Request) { var cfg vpn.IPSecServerConfig if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } if err := s.vpnMgr.PPPServer.SetIPSecServer(cfg); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true}) } // WireGuard Client Config Generator func (s *Server) handleGenerateWGClientConfig(w http.ResponseWriter, r *http.Request) { var req struct { Interface string `json:"interface"` Address string `json:"address"` PrivKey string `json:"private_key"` Endpoint string `json:"endpoint"` DNS string `json:"dns"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil || req.Interface == "" { writeError(w, http.StatusBadRequest, "interface is required") return } if req.PrivKey == "" { priv, _, err := s.vpnMgr.WireGuard.GenerateKeyPair() if err == nil { req.PrivKey = priv } } conf, err := s.vpnMgr.WireGuard.GenerateClientConfig(req.Interface, req.PrivKey, req.Address, req.Endpoint, req.DNS) if err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, map[string]any{"success": true, "config": conf, "client_private_key": req.PrivKey}) }