mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/1Panel-dev/1Panel.git
synced 2026-09-21 00:24:12 +08:00
Port forwarding no longer shares the filter client. FilterClient keeps only
filter capabilities, and forwarding gets its own adapter, service and boot
replay:
- utils/firewall/forwarding holds the provider adapters. firewalld uses native
forward-port, ufw and iptables share the NAT implementation moved out of
client/iptables/forward.go.
- service/forwarding.go owns base info, search, operate, enable and replay.
The API keeps its routes and dispatches on name/type/operate.
- init/firewall replays forwarding through that service instead of loading NAT
rule files inline.
Also adds 1PANEL_FORWARD to the IptablesOp name enum: the frontend already
sends {"name":"1PANEL_FORWARD","operate":"init-forward"} and the validator
rejected it with 400 before reaching the service. Besides that, the only
observable difference is that a forward-tab search no longer triggers the
port/address record cleanup goroutine on the side.
118 lines
3.4 KiB
Go
118 lines
3.4 KiB
Go
package forwarding
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/1Panel-dev/1Panel/agent/buserr"
|
|
"github.com/1Panel-dev/1Panel/agent/global"
|
|
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
|
|
)
|
|
|
|
type firewalldCommandRunner interface {
|
|
Run(name string, args ...string) error
|
|
RunWithStdout(name string, args ...string) (string, error)
|
|
}
|
|
|
|
type defaultFirewalldCommandRunner struct{}
|
|
|
|
func (defaultFirewalldCommandRunner) Run(name string, args ...string) error {
|
|
return cmd.NewCommandMgr().Run(name, args...)
|
|
}
|
|
|
|
func (defaultFirewalldCommandRunner) RunWithStdout(name string, args ...string) (string, error) {
|
|
return cmd.NewCommandMgr().RunWithStdout(name, args...)
|
|
}
|
|
|
|
type firewalldAdapter struct {
|
|
runner firewalldCommandRunner
|
|
}
|
|
|
|
func newFirewalldAdapter() *firewalldAdapter {
|
|
return &firewalldAdapter{runner: defaultFirewalldCommandRunner{}}
|
|
}
|
|
|
|
func (f *firewalldAdapter) Name() string {
|
|
return "firewalld"
|
|
}
|
|
|
|
func (f *firewalldAdapter) List() ([]Rule, error) {
|
|
if err := f.Enable(); err != nil {
|
|
global.LOG.Errorf("init port forward failed, err: %v", err)
|
|
}
|
|
stdout, err := f.runner.RunWithStdout("firewall-cmd", "--zone=public", "--list-forward-ports")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return parseFirewalldRules(stdout), nil
|
|
}
|
|
|
|
func parseFirewalldRules(stdout string) []Rule {
|
|
var rules []Rule
|
|
for _, line := range strings.Split(stdout, "\n") {
|
|
line = strings.TrimSpace(line)
|
|
parts := strings.Split(line, ":")
|
|
if len(parts) < 4 {
|
|
continue
|
|
}
|
|
if parts[3] == "toaddr=" {
|
|
parts[3] = "127.0.0.1"
|
|
}
|
|
rules = append(rules, Rule{
|
|
Port: strings.TrimPrefix(parts[0], "port="),
|
|
Protocol: strings.TrimPrefix(parts[1], "proto="),
|
|
TargetIP: strings.TrimPrefix(parts[3], "toaddr="),
|
|
TargetPort: strings.TrimPrefix(parts[2], "toport="),
|
|
})
|
|
}
|
|
return rules
|
|
}
|
|
|
|
func (f *firewalldAdapter) Operate(rule Rule, operation string) error {
|
|
if cmd.CheckIllegal(operation, rule.Port, rule.Protocol, rule.TargetIP, rule.TargetPort) {
|
|
return buserr.New("ErrCmdIllegal")
|
|
}
|
|
args := buildFirewalldForwardArgs(rule, operation)
|
|
if err := f.runner.Run("firewall-cmd", args...); err != nil {
|
|
return fmt.Errorf("%s port forward failed, %s", operation, err)
|
|
}
|
|
return f.reload()
|
|
}
|
|
|
|
func buildFirewalldForwardArgs(rule Rule, operation string) []string {
|
|
forwardRule := fmt.Sprintf("--%s-forward-port=port=%s:proto=%s:toport=%s", operation, rule.Port, rule.Protocol, rule.TargetPort)
|
|
if rule.TargetIP != "" && rule.TargetIP != "127.0.0.1" && rule.TargetIP != "localhost" {
|
|
forwardRule = fmt.Sprintf("--%s-forward-port=port=%s:proto=%s:toaddr=%s:toport=%s", operation, rule.Port, rule.Protocol, rule.TargetIP, rule.TargetPort)
|
|
}
|
|
return []string{"--zone=public", forwardRule, "--permanent"}
|
|
}
|
|
|
|
func (f *firewalldAdapter) Enable() error {
|
|
stdout, err := f.runner.RunWithStdout("firewall-cmd", "--zone=public", "--query-masquerade")
|
|
if err != nil {
|
|
if strings.HasSuffix(strings.TrimSpace(stdout), "no") {
|
|
if err := f.runner.Run("firewall-cmd", "--zone=public", "--add-masquerade", "--permanent"); err != nil {
|
|
return err
|
|
}
|
|
return f.reload()
|
|
}
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (f *firewalldAdapter) reload() error {
|
|
if err := f.runner.Run("firewall-cmd", "--reload"); err != nil {
|
|
return fmt.Errorf("reload firewall failed, err: %v", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (f *firewalldAdapter) InitStatus() (bool, bool) {
|
|
return true, true
|
|
}
|
|
|
|
func (f *firewalldAdapter) Replay() error {
|
|
return nil
|
|
}
|