185 lines
5.3 KiB
Go
185 lines
5.3 KiB
Go
package handlers
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
|
|
"setec-manager/internal/system"
|
|
)
|
|
|
|
type firewallRule struct {
|
|
ID int64 `json:"id"`
|
|
Direction string `json:"direction"`
|
|
Protocol string `json:"protocol"`
|
|
Port string `json:"port"`
|
|
Source string `json:"source"`
|
|
Action string `json:"action"`
|
|
Comment string `json:"comment"`
|
|
}
|
|
|
|
type firewallStatus struct {
|
|
Enabled bool `json:"enabled"`
|
|
Rules []firewallRule `json:"rules"`
|
|
UFWOut string `json:"ufw_output"`
|
|
}
|
|
|
|
func (h *Handler) FirewallList(w http.ResponseWriter, r *http.Request) {
|
|
status := h.getFirewallStatus()
|
|
if acceptsJSON(r) {
|
|
writeJSON(w, http.StatusOK, status)
|
|
return
|
|
}
|
|
h.render(w, "firewall.html", status)
|
|
}
|
|
|
|
func (h *Handler) FirewallStatus(w http.ResponseWriter, r *http.Request) {
|
|
writeJSON(w, http.StatusOK, h.getFirewallStatus())
|
|
}
|
|
|
|
func (h *Handler) FirewallAddRule(w http.ResponseWriter, r *http.Request) {
|
|
var rule firewallRule
|
|
if err := json.NewDecoder(r.Body).Decode(&rule); err != nil {
|
|
rule.Port = r.FormValue("port")
|
|
rule.Protocol = r.FormValue("protocol")
|
|
rule.Source = r.FormValue("source")
|
|
rule.Action = r.FormValue("action")
|
|
rule.Comment = r.FormValue("comment")
|
|
}
|
|
|
|
if rule.Port == "" {
|
|
writeError(w, http.StatusBadRequest, "port is required")
|
|
return
|
|
}
|
|
if rule.Protocol == "" {
|
|
rule.Protocol = "tcp"
|
|
}
|
|
if rule.Action == "" {
|
|
rule.Action = "allow"
|
|
}
|
|
if rule.Source == "" {
|
|
rule.Source = "any"
|
|
}
|
|
|
|
ufwRule := system.UFWRule{
|
|
Port: rule.Port,
|
|
Protocol: rule.Protocol,
|
|
Source: rule.Source,
|
|
Action: rule.Action,
|
|
Comment: rule.Comment,
|
|
}
|
|
|
|
if err := system.FirewallAddRule(ufwRule); err != nil {
|
|
writeError(w, http.StatusInternalServerError, err.Error())
|
|
return
|
|
}
|
|
|
|
// Save to DB
|
|
h.DB.Conn().Exec(`INSERT INTO firewall_rules (direction, protocol, port, source, action, comment)
|
|
VALUES (?, ?, ?, ?, ?, ?)`, "in", rule.Protocol, rule.Port, rule.Source, rule.Action, rule.Comment)
|
|
|
|
writeJSON(w, http.StatusCreated, map[string]string{"status": "rule added"})
|
|
}
|
|
|
|
func (h *Handler) FirewallDeleteRule(w http.ResponseWriter, r *http.Request) {
|
|
id, err := paramInt(r, "id")
|
|
if err != nil {
|
|
writeError(w, http.StatusBadRequest, "invalid id")
|
|
return
|
|
}
|
|
|
|
// Get rule from DB to build delete command
|
|
var port, protocol, action string
|
|
err = h.DB.Conn().QueryRow(`SELECT port, protocol, action FROM firewall_rules WHERE id=?`, id).
|
|
Scan(&port, &protocol, &action)
|
|
if err != nil {
|
|
writeError(w, http.StatusNotFound, "rule not found")
|
|
return
|
|
}
|
|
|
|
system.FirewallDeleteRule(system.UFWRule{
|
|
Port: port,
|
|
Protocol: protocol,
|
|
Action: action,
|
|
})
|
|
h.DB.Conn().Exec(`DELETE FROM firewall_rules WHERE id=?`, id)
|
|
|
|
writeJSON(w, http.StatusOK, map[string]string{"status": "rule deleted"})
|
|
}
|
|
|
|
func (h *Handler) FirewallEnable(w http.ResponseWriter, r *http.Request) {
|
|
if err := system.FirewallEnable(); err != nil {
|
|
writeError(w, http.StatusInternalServerError, err.Error())
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, map[string]string{"status": "enabled"})
|
|
}
|
|
|
|
func (h *Handler) FirewallDisable(w http.ResponseWriter, r *http.Request) {
|
|
if err := system.FirewallDisable(); err != nil {
|
|
writeError(w, http.StatusInternalServerError, err.Error())
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, map[string]string{"status": "disabled"})
|
|
}
|
|
|
|
func (h *Handler) getFirewallStatus() firewallStatus {
|
|
status := firewallStatus{}
|
|
|
|
enabled, _, raw, _ := system.FirewallStatus()
|
|
status.UFWOut = raw
|
|
status.Enabled = enabled
|
|
|
|
// Load rules from DB
|
|
rows, err := h.DB.Conn().Query(`SELECT id, direction, protocol, port, source, action, comment
|
|
FROM firewall_rules WHERE enabled=TRUE ORDER BY id`)
|
|
if err == nil {
|
|
defer rows.Close()
|
|
for rows.Next() {
|
|
var rule firewallRule
|
|
rows.Scan(&rule.ID, &rule.Direction, &rule.Protocol, &rule.Port,
|
|
&rule.Source, &rule.Action, &rule.Comment)
|
|
status.Rules = append(status.Rules, rule)
|
|
}
|
|
}
|
|
|
|
return status
|
|
}
|
|
|
|
func (h *Handler) InstallDefaultFirewall() error {
|
|
// Set default policies
|
|
system.FirewallSetDefaults("deny", "allow")
|
|
|
|
// Add default rules
|
|
defaultRules := []system.UFWRule{
|
|
{Port: "22", Protocol: "tcp", Action: "allow", Comment: "SSH"},
|
|
{Port: "80", Protocol: "tcp", Action: "allow", Comment: "HTTP"},
|
|
{Port: "443", Protocol: "tcp", Action: "allow", Comment: "HTTPS"},
|
|
{Port: "9090", Protocol: "tcp", Action: "allow", Comment: "Setec Manager"},
|
|
{Port: "8181", Protocol: "tcp", Action: "allow", Comment: "AUTARCH Web"},
|
|
{Port: "53", Protocol: "", Action: "allow", Comment: "AUTARCH DNS"},
|
|
}
|
|
|
|
for _, rule := range defaultRules {
|
|
system.FirewallAddRule(rule)
|
|
}
|
|
|
|
// Enable the firewall
|
|
system.FirewallEnable()
|
|
|
|
// Record in DB
|
|
dbRules := []firewallRule{
|
|
{Port: "22", Protocol: "tcp", Action: "allow", Comment: "SSH"},
|
|
{Port: "80", Protocol: "tcp", Action: "allow", Comment: "HTTP"},
|
|
{Port: "443", Protocol: "tcp", Action: "allow", Comment: "HTTPS"},
|
|
{Port: "9090", Protocol: "tcp", Action: "allow", Comment: "Setec Manager"},
|
|
{Port: "8181", Protocol: "tcp", Action: "allow", Comment: "AUTARCH Web"},
|
|
{Port: "53", Protocol: "tcp", Action: "allow", Comment: "AUTARCH DNS"},
|
|
}
|
|
for _, rule := range dbRules {
|
|
h.DB.Conn().Exec(`INSERT OR IGNORE INTO firewall_rules (direction, protocol, port, source, action, comment)
|
|
VALUES ('in', ?, ?, 'any', ?, ?)`, rule.Protocol, rule.Port, rule.Action, rule.Comment)
|
|
}
|
|
|
|
return nil
|
|
}
|