diff --git a/VERSION.txt b/VERSION.txt index bcab45a..81340c7 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -0.0.3 +0.0.4 diff --git a/internal/server/handlers_panel.go b/internal/server/handlers_panel.go index 94a8906..7619c39 100644 --- a/internal/server/handlers_panel.go +++ b/internal/server/handlers_panel.go @@ -146,6 +146,12 @@ func (s *Server) handleAgentDelete(w http.ResponseWriter, r *http.Request) { return } id := r.PathValue("id") + // Its forward rules go with it: left behind they would keep their host + // ports bound and busy with no page to remove them from. + rules, _ := s.db.ListForwardRulesByAgent(id) + for _, rule := range rules { + s.removeForward(rule.ID) + } _ = s.db.DeleteAgent(id) http.Redirect(w, r, "/", http.StatusSeeOther) } diff --git a/internal/server/handlers_panel_fwd.go b/internal/server/handlers_panel_fwd.go index 3f7a5f1..9c159d2 100644 --- a/internal/server/handlers_panel_fwd.go +++ b/internal/server/handlers_panel_fwd.go @@ -18,6 +18,7 @@ func (s *Server) handleForwardsPage(w http.ResponseWriter, r *http.Request) { rules, _ := s.db.ListForwardRulesByAgent(id) errMsg := map[string]string{ "busy": "Этот порт хоста уже занят другим правилом.", + "tunnel": "Этот порт занят прямым туннелем панели (см. Настройки).", "port": "Некорректный номер порта.", "listen": "Не удалось занять порт на хосте (возможно, уже используется).", "db": "Ошибка базы данных.", @@ -76,7 +77,11 @@ func (s *Server) handleForwardAdd(w http.ResponseWriter, r *http.Request) { return } // Reject a host port already bound by another forward rule or the tunnel. - if s.db.HostPortUsed(hostPort) || hostPort == s.TunnelPort() { + if hostPort == s.TunnelPort() { + http.Redirect(w, r, "/agents/"+id+"/forwards?err=tunnel", http.StatusSeeOther) + return + } + if s.db.HostPortUsed(hostPort) { http.Redirect(w, r, "/agents/"+id+"/forwards?err=busy", http.StatusSeeOther) return } @@ -107,14 +112,19 @@ func (s *Server) handleForwardDelete(w http.ResponseWriter, r *http.Request) { } rid, _ := strconv.ParseInt(r.PathValue("rid"), 10, 64) rule, _ := s.db.GetForwardRule(rid) - s.fwd.close(rid) - _ = s.db.DeleteForwardRule(rid) - // Remove the ufw rule bound to this forward rule (the shared tunnel port - // stays while another direct forward needs it). - s.ufw.revokeForRule(rid) + s.removeForward(rid) dest := "/" if rule != nil { dest = "/agents/" + rule.AgentID + "/forwards" } http.Redirect(w, r, dest, http.StatusSeeOther) } + +// removeForward closes a forward rule's listener and deletes the rule, along +// with the ufw rule bound to it (the shared tunnel port stays while another +// direct forward needs it). +func (s *Server) removeForward(rid int64) { + s.fwd.close(rid) + _ = s.db.DeleteForwardRule(rid) + s.ufw.revokeForRule(rid) +} diff --git a/internal/server/server.go b/internal/server/server.go index bf6f213..0018527 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -161,6 +161,12 @@ func (s *Server) restoreForwards() { return } for _, r := range rules { + // Rules of an agent deleted by an older version: drop them. + if a, err := s.db.GetAgent(r.AgentID); err == nil && a == nil { + log.Printf("forward rule %d: agent %s is gone, removing", r.ID, r.AgentID) + s.removeForward(r.ID) + continue + } if err := s.fwd.open(r); err != nil { log.Printf("restore forward rule %d (%s:%d): %v", r.ID, r.ListenAddr, r.HostPort, err) }