mirror of
https://github.com/MengMengCode/CLICD.git
synced 2026-08-07 22:24:42 +08:00
修复了一些已知问题
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -29,8 +30,9 @@ func getFirewall(w http.ResponseWriter, r *http.Request, id int) {
|
||||
jsonResponse(w, http.StatusOK, APIResponse{
|
||||
Success: true,
|
||||
Data: map[string]interface{}{
|
||||
"enabled": c.FirewallEnabled,
|
||||
"rules": c.FirewallRules,
|
||||
"enabled": c.FirewallEnabled,
|
||||
"default_action": normalizeFirewallDefaultAction(c.FirewallDefaultAction),
|
||||
"rules": c.FirewallRules,
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -43,17 +45,32 @@ func updateFirewall(w http.ResponseWriter, r *http.Request, id int) {
|
||||
}
|
||||
|
||||
var req struct {
|
||||
Enabled *bool `json:"enabled"`
|
||||
Rules *[]config.FirewallRule `json:"rules"`
|
||||
Enabled *bool `json:"enabled"`
|
||||
DefaultAction *string `json:"default_action"`
|
||||
Rules *[]config.FirewallRule `json:"rules"`
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
jsonResponse(w, http.StatusBadRequest, APIResponse{Success: false, Message: "Invalid request body"})
|
||||
return
|
||||
}
|
||||
|
||||
oldEnabled := c.FirewallEnabled
|
||||
oldDefaultAction := c.FirewallDefaultAction
|
||||
oldRules := append([]config.FirewallRule(nil), c.FirewallRules...)
|
||||
|
||||
if req.Enabled != nil {
|
||||
c.FirewallEnabled = *req.Enabled
|
||||
}
|
||||
if req.DefaultAction != nil {
|
||||
action := normalizeFirewallDefaultAction(*req.DefaultAction)
|
||||
if action == "" {
|
||||
jsonResponse(w, http.StatusBadRequest, APIResponse{Success: false, Message: "Invalid default action"})
|
||||
return
|
||||
}
|
||||
c.FirewallDefaultAction = action
|
||||
} else if strings.TrimSpace(c.FirewallDefaultAction) == "" {
|
||||
c.FirewallDefaultAction = "DROP"
|
||||
}
|
||||
if req.Rules != nil {
|
||||
// Validate and assign IDs to new rules
|
||||
rules := *req.Rules
|
||||
@@ -61,9 +78,14 @@ func updateFirewall(w http.ResponseWriter, r *http.Request, id int) {
|
||||
rules[i].Direction = strings.ToLower(strings.TrimSpace(rules[i].Direction))
|
||||
rules[i].Protocol = strings.ToLower(strings.TrimSpace(rules[i].Protocol))
|
||||
rules[i].Action = strings.ToUpper(strings.TrimSpace(rules[i].Action))
|
||||
rules[i].Network = normalizeFirewallNetwork(rules[i].Network)
|
||||
rules[i].SourceIP = strings.TrimSpace(rules[i].SourceIP)
|
||||
rules[i].Port = strings.TrimSpace(rules[i].Port)
|
||||
|
||||
if rules[i].Network == "" {
|
||||
jsonResponse(w, http.StatusBadRequest, APIResponse{Success: false, Message: "Invalid network"})
|
||||
return
|
||||
}
|
||||
if rules[i].Direction != "in" && rules[i].Direction != "out" {
|
||||
jsonResponse(w, http.StatusBadRequest, APIResponse{Success: false, Message: "Invalid direction: " + rules[i].Direction})
|
||||
return
|
||||
@@ -76,11 +98,21 @@ func updateFirewall(w http.ResponseWriter, r *http.Request, id int) {
|
||||
jsonResponse(w, http.StatusBadRequest, APIResponse{Success: false, Message: "Invalid action: " + rules[i].Action})
|
||||
return
|
||||
}
|
||||
if rules[i].ID == "" {
|
||||
if rules[i].SourceIP != "" {
|
||||
if err := validateFirewallIPSpec(rules[i].SourceIP, rules[i].Network); err != nil {
|
||||
jsonResponse(w, http.StatusBadRequest, APIResponse{Success: false, Message: "Invalid IP: " + err.Error()})
|
||||
return
|
||||
}
|
||||
}
|
||||
if rules[i].ID == "" || strings.HasPrefix(rules[i].ID, "tmp-") {
|
||||
rules[i].ID = generateFirewallRuleID()
|
||||
}
|
||||
// Validate port spec
|
||||
if rules[i].Port != "" {
|
||||
if rules[i].Protocol != "tcp" && rules[i].Protocol != "udp" {
|
||||
jsonResponse(w, http.StatusBadRequest, APIResponse{Success: false, Message: "Ports are only supported for TCP and UDP rules"})
|
||||
return
|
||||
}
|
||||
if err := validatePortSpec(rules[i].Port); err != nil {
|
||||
jsonResponse(w, http.StatusBadRequest, APIResponse{Success: false, Message: "Invalid port: " + err.Error()})
|
||||
return
|
||||
@@ -90,11 +122,14 @@ func updateFirewall(w http.ResponseWriter, r *http.Request, id int) {
|
||||
c.FirewallRules = rules
|
||||
}
|
||||
|
||||
config.SaveConfig()
|
||||
|
||||
// Apply firewall rules to iptables if container is running
|
||||
if c.Status == "running" {
|
||||
if err := lxc.ApplyFirewallRules(id); err != nil {
|
||||
c.FirewallEnabled = oldEnabled
|
||||
c.FirewallDefaultAction = oldDefaultAction
|
||||
c.FirewallRules = oldRules
|
||||
_ = lxc.ApplyFirewallRules(id)
|
||||
config.SaveConfig()
|
||||
jsonResponse(w, http.StatusInternalServerError, APIResponse{Success: false, Message: "Failed to apply firewall rules: " + err.Error()})
|
||||
return
|
||||
}
|
||||
@@ -102,28 +137,54 @@ func updateFirewall(w http.ResponseWriter, r *http.Request, id int) {
|
||||
// If disabled and not running, clean any lingering rules
|
||||
lxc.CleanFirewallRules(id)
|
||||
}
|
||||
config.SaveConfig()
|
||||
|
||||
jsonResponse(w, http.StatusOK, APIResponse{
|
||||
Success: true,
|
||||
Message: "Firewall updated",
|
||||
Data: map[string]interface{}{
|
||||
"enabled": c.FirewallEnabled,
|
||||
"rules": c.FirewallRules,
|
||||
"enabled": c.FirewallEnabled,
|
||||
"default_action": normalizeFirewallDefaultAction(c.FirewallDefaultAction),
|
||||
"rules": c.FirewallRules,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func normalizeFirewallDefaultAction(action string) string {
|
||||
action = strings.ToUpper(strings.TrimSpace(action))
|
||||
if action == "ACCEPT" || action == "DROP" {
|
||||
return action
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func normalizeFirewallNetwork(network string) string {
|
||||
network = strings.ToLower(strings.TrimSpace(network))
|
||||
switch network {
|
||||
case "", "ipv4", "nat4":
|
||||
return "ipv4"
|
||||
case "ipv6":
|
||||
return "ipv6"
|
||||
case "all", "both":
|
||||
return "all"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func validatePortSpec(port string) error {
|
||||
port = strings.TrimSpace(port)
|
||||
if port == "" {
|
||||
return nil
|
||||
}
|
||||
// Support: "22", "80,443", "8000-9000", "80,443,8000-9000"
|
||||
partCount := 0
|
||||
for _, part := range strings.Split(port, ",") {
|
||||
part = strings.TrimSpace(part)
|
||||
if part == "" {
|
||||
continue
|
||||
return &portValidationError{port}
|
||||
}
|
||||
partCount++
|
||||
if strings.Contains(part, "-") {
|
||||
// Range
|
||||
bounds := strings.SplitN(part, "-", 2)
|
||||
@@ -135,6 +196,9 @@ func validatePortSpec(port string) error {
|
||||
if err != nil || hi < 1 || hi > 65535 {
|
||||
return &portValidationError{part}
|
||||
}
|
||||
if hi < lo {
|
||||
return &portValidationError{part}
|
||||
}
|
||||
} else {
|
||||
p, err := strconv.Atoi(part)
|
||||
if err != nil || p < 1 || p > 65535 {
|
||||
@@ -142,9 +206,48 @@ func validatePortSpec(port string) error {
|
||||
}
|
||||
}
|
||||
}
|
||||
if partCount > 15 {
|
||||
return &portValidationError{"too many ports; maximum 15 items per rule"}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateFirewallIPSpec(value string, network string) error {
|
||||
var addr netip.Addr
|
||||
if strings.Contains(value, "/") {
|
||||
prefix, err := netip.ParsePrefix(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
addr = prefix.Addr()
|
||||
} else {
|
||||
parsed, err := netip.ParseAddr(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
addr = parsed
|
||||
}
|
||||
switch network {
|
||||
case "ipv4":
|
||||
if !addr.Is4() {
|
||||
return &ipValidationError{"IPv4 rule requires an IPv4 address or CIDR: " + value}
|
||||
}
|
||||
case "ipv6":
|
||||
if !addr.Is6() || addr.Is4In6() {
|
||||
return &ipValidationError{"IPv6 rule requires an IPv6 address or CIDR: " + value}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ipValidationError struct {
|
||||
value string
|
||||
}
|
||||
|
||||
func (e *ipValidationError) Error() string {
|
||||
return e.value
|
||||
}
|
||||
|
||||
type portValidationError struct {
|
||||
port string
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user