mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-09-23 08:00:55 +00:00
127 lines
3.6 KiB
Go
127 lines
3.6 KiB
Go
package forwarding
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/netip"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/1Panel-dev/1Panel/agent/constant"
|
|
"github.com/1Panel-dev/1Panel/agent/utils/re"
|
|
)
|
|
|
|
const (
|
|
FamilyIPv4 = constant.FirewallFamilyIPv4
|
|
FamilyIPv6 = constant.FirewallFamilyIPv6
|
|
ChainPreRouting = "1PANEL_PREROUTING"
|
|
ChainPostRouting = "1PANEL_POSTROUTING"
|
|
ChainForward = "1PANEL_FORWARD"
|
|
ForwardFile = "1panel_forward.rules"
|
|
PreRoutingFile = "1panel_forward_pre.rules"
|
|
PostRoutingFile = "1panel_forward_post.rules"
|
|
)
|
|
|
|
type Rule struct {
|
|
Num string
|
|
Family string
|
|
Protocol string
|
|
Port string
|
|
TargetIP string
|
|
TargetPort string
|
|
Interface string
|
|
}
|
|
|
|
func (r Rule) Identity() string {
|
|
return strings.Join([]string{r.Family, r.Protocol, r.Port, r.TargetIP, r.TargetPort, r.Interface}, "\x00")
|
|
}
|
|
|
|
type OperationType string
|
|
|
|
const (
|
|
OperationAdd OperationType = "add"
|
|
OperationRemove OperationType = "remove"
|
|
)
|
|
|
|
type Adapter interface {
|
|
Name() string
|
|
List() ([]Rule, error)
|
|
CreateRules(context.Context, []Rule) error
|
|
DeleteRules(context.Context, []Rule) error
|
|
ReplaceRules(rules []Rule) error
|
|
Enable() error
|
|
Cleanup() error
|
|
InitStatus() (bool, bool, error)
|
|
FamilyStatus(family string) (bool, bool, error)
|
|
Replay() error
|
|
}
|
|
|
|
func NormalizeRule(rule Rule) (Rule, error) {
|
|
rule.Family = strings.ToLower(strings.TrimSpace(rule.Family))
|
|
if rule.Family == "" {
|
|
rule.Family = FamilyIPv4
|
|
}
|
|
if rule.Family != FamilyIPv4 && rule.Family != FamilyIPv6 {
|
|
return Rule{}, fmt.Errorf("unsupported forwarding family %q", rule.Family)
|
|
}
|
|
rule.Protocol = strings.ToLower(strings.TrimSpace(rule.Protocol))
|
|
if rule.Protocol != "tcp" && rule.Protocol != "udp" {
|
|
return Rule{}, fmt.Errorf("unsupported forwarding protocol %q", rule.Protocol)
|
|
}
|
|
var err error
|
|
if rule.Port, err = normalizeForwardPort(rule.Port); err != nil {
|
|
return Rule{}, fmt.Errorf("invalid forwarding port: %w", err)
|
|
}
|
|
if rule.TargetPort, err = normalizeForwardPort(rule.TargetPort); err != nil {
|
|
return Rule{}, fmt.Errorf("invalid forwarding target port: %w", err)
|
|
}
|
|
rule.TargetIP = strings.TrimSpace(rule.TargetIP)
|
|
if rule.TargetIP == "" || strings.EqualFold(rule.TargetIP, "localhost") {
|
|
if rule.Family == FamilyIPv6 {
|
|
rule.TargetIP = "::1"
|
|
} else {
|
|
rule.TargetIP = "127.0.0.1"
|
|
}
|
|
}
|
|
address, err := netip.ParseAddr(rule.TargetIP)
|
|
if err == nil {
|
|
address = address.Unmap()
|
|
}
|
|
if err != nil || (rule.Family == FamilyIPv4) != address.Is4() {
|
|
return Rule{}, fmt.Errorf("invalid %s forwarding target %q", rule.Family, rule.TargetIP)
|
|
}
|
|
rule.TargetIP = address.String()
|
|
rule.Interface = strings.TrimSpace(rule.Interface)
|
|
if rule.Interface == "all" || rule.Interface == "*" {
|
|
rule.Interface = ""
|
|
}
|
|
if rule.Interface != "" && !re.ForwardInterfaceRegex.MatchString(rule.Interface) {
|
|
return Rule{}, fmt.Errorf("invalid forwarding interface %q", rule.Interface)
|
|
}
|
|
return rule, nil
|
|
}
|
|
|
|
func normalizeForwardPort(value string) (string, error) {
|
|
parts := strings.Split(strings.TrimSpace(value), "-")
|
|
if len(parts) < 1 || len(parts) > 2 {
|
|
return "", fmt.Errorf("invalid port range %q", value)
|
|
}
|
|
ports := make([]int, len(parts))
|
|
for index, part := range parts {
|
|
port, err := strconv.Atoi(strings.TrimSpace(part))
|
|
if err != nil || port < 1 || port > 65535 {
|
|
return "", fmt.Errorf("invalid port %q", part)
|
|
}
|
|
ports[index] = port
|
|
}
|
|
if len(ports) == 2 {
|
|
if ports[0] > ports[1] {
|
|
return "", fmt.Errorf("descending port range %q", value)
|
|
}
|
|
if ports[0] != ports[1] {
|
|
return strconv.Itoa(ports[0]) + "-" + strconv.Itoa(ports[1]), nil
|
|
}
|
|
}
|
|
return strconv.Itoa(ports[0]), nil
|
|
}
|