mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-10-12 08:00:34 +00:00
Replace database rule synchronization with native rule operations and file-based backup, import, and recovery. Update firewall management views, descriptions, whitelist handling, and translations. Include terminal reconnect fixes and xpack build tags for Darwin build targets. Remove temporary regression test files before committing.
491 lines
18 KiB
Go
491 lines
18 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"slices"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
|
"github.com/1Panel-dev/1Panel/agent/app/task"
|
|
"github.com/1Panel-dev/1Panel/agent/buserr"
|
|
"github.com/1Panel-dev/1Panel/agent/constant"
|
|
"github.com/1Panel-dev/1Panel/agent/i18n"
|
|
dockerfirewall "github.com/1Panel-dev/1Panel/agent/utils/firewall/docker_guard"
|
|
"github.com/1Panel-dev/1Panel/agent/utils/firewall/filter"
|
|
"github.com/docker/docker/client"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
const (
|
|
dockerGuardComposeProjectLabel = "com.docker.compose.project"
|
|
dockerGuardComposeCreatedBy = "createdBy"
|
|
dockerTrafficPathForward = "forward"
|
|
dockerTrafficPathInput = "input"
|
|
dockerTrafficPathUnknown = "unknown"
|
|
dockerManagementContainerGuard = "container_guard"
|
|
dockerManagementHostFirewall = "host_firewall"
|
|
dockerManagementNeedsDiagnosis = "needs_diagnosis"
|
|
dockerReasonNATInspectFailed = "nat_inspect_failed"
|
|
dockerReasonNATChainUnreachable = "nat_chain_unreachable"
|
|
dockerReasonProxyInspectFailed = "proxy_inspect_failed"
|
|
dockerReasonNoMatchingPath = "no_matching_path"
|
|
)
|
|
|
|
type DockerPortGuardService struct {
|
|
runtime dockerfirewall.Runtime
|
|
runtimeForBackend func(context.Context, string) dockerfirewall.Runtime
|
|
client func() (*client.Client, error)
|
|
version func(string) string
|
|
}
|
|
|
|
var dockerPortGuardServiceMu sync.Mutex
|
|
|
|
type IDockerPortGuardService interface {
|
|
LoadOverview(context.Context) (dto.DockerPortGuardList, error)
|
|
ExportBackup(context.Context, filter.Provider) (dto.FirewallSubsystemBackup, error)
|
|
LoadPublishedPorts(context.Context) ([]dto.DockerPortGuardContainer, error)
|
|
Operate(context.Context, dto.DockerPortGuardOperation) error
|
|
QueueInitialization(dto.DockerPortGuardOperation) (dto.FilterChainOperationResponse, error)
|
|
DeletePolicies(dto.DockerPortGuardPolicyBatchDelete) (dto.FilterChainOperationResponse, error)
|
|
UpsertPolicies(dto.DockerPortGuardPolicyBatch) (dto.FilterChainOperationResponse, error)
|
|
Restore(context.Context) error
|
|
}
|
|
|
|
func NewIDockerPortGuardService() IDockerPortGuardService {
|
|
return newDockerPortGuardService()
|
|
}
|
|
|
|
func (s *DockerPortGuardService) LoadOverview(ctx context.Context) (dto.DockerPortGuardList, error) {
|
|
families, err := loadFirewallFamilies()
|
|
if err != nil {
|
|
return dto.DockerPortGuardList{}, err
|
|
}
|
|
backend := selectedDockerFirewallBackend("")
|
|
inventory, err := s.guardRuntime(ctx, backend).ListPolicies()
|
|
if err != nil {
|
|
return dto.DockerPortGuardList{}, err
|
|
}
|
|
policies := dockerGuardInventoryEndpoints(inventory)
|
|
unavailable := func() dto.DockerPortGuardList {
|
|
backend := selectedDockerFirewallBackend("")
|
|
base := s.runtimeStatus(s.guardRuntime(ctx, backend), backend, len(families) > 1)
|
|
base.Message = i18n.Get("ErrDockerFailed")
|
|
return dto.DockerPortGuardList{Base: base, Containers: []dto.DockerPortGuardContainer{}, OrphanPolicies: policies}
|
|
}
|
|
cli, err := s.client()
|
|
if err != nil {
|
|
return unavailable(), nil
|
|
}
|
|
defer cli.Close()
|
|
info, err := cli.Info(ctx)
|
|
if err != nil {
|
|
return unavailable(), nil
|
|
}
|
|
detectedBackend := dockerFirewallBackend(info)
|
|
backend = selectedDockerFirewallBackend(detectedBackend)
|
|
base := s.runtimeStatus(s.guardRuntime(ctx, backend), backend, len(families) > 1)
|
|
endpoints, err := discoverDockerEndpoints(ctx, cli, true)
|
|
if err != nil {
|
|
return dto.DockerPortGuardList{}, err
|
|
}
|
|
annotateDockerEndpointManagement(ctx, endpoints, detectedBackend)
|
|
endpoints, orphanPolicies := matchDockerGuardPolicies(base, policies, endpoints)
|
|
sort.Slice(endpoints, func(i, j int) bool {
|
|
return fmt.Sprintf("%s|%s|%d|%s", endpoints[i].Family, endpoints[i].HostIP, endpoints[i].HostPort, endpoints[i].Protocol) < fmt.Sprintf("%s|%s|%d|%s", endpoints[j].Family, endpoints[j].HostIP, endpoints[j].HostPort, endpoints[j].Protocol)
|
|
})
|
|
sort.Slice(orphanPolicies, func(i, j int) bool {
|
|
return fmt.Sprintf("%s|%s|%d|%s", orphanPolicies[i].Family, orphanPolicies[i].HostIP, orphanPolicies[i].HostPort, orphanPolicies[i].Protocol) < fmt.Sprintf("%s|%s|%d|%s", orphanPolicies[j].Family, orphanPolicies[j].HostIP, orphanPolicies[j].HostPort, orphanPolicies[j].Protocol)
|
|
})
|
|
return dto.DockerPortGuardList{Base: base, Containers: groupDockerGuardContainers(endpoints), OrphanPolicies: orphanPolicies}, nil
|
|
}
|
|
|
|
func (s *DockerPortGuardService) ExportBackup(ctx context.Context, provider filter.Provider) (dto.FirewallSubsystemBackup, error) {
|
|
backend := string(provider)
|
|
if backend == "" {
|
|
backend = selectedDockerFirewallBackend("")
|
|
}
|
|
if backend != constant.FirewallProviderIptables && backend != constant.FirewallProviderNftables {
|
|
return dto.FirewallSubsystemBackup{}, filter.ErrInvalidRule
|
|
}
|
|
inventory, err := s.guardRuntime(ctx, backend).ListPolicies()
|
|
if err != nil {
|
|
return dto.FirewallSubsystemBackup{}, err
|
|
}
|
|
if inventory.Policies == nil {
|
|
inventory.Policies = []dockerfirewall.Policy{}
|
|
}
|
|
return dto.FirewallSubsystemBackup{Subsystem: "docker", Provider: filter.Provider(backend), Docker: &inventory}, nil
|
|
}
|
|
|
|
func (s *DockerPortGuardService) LoadPublishedPorts(ctx context.Context) ([]dto.DockerPortGuardContainer, error) {
|
|
cli, err := s.client()
|
|
if err != nil {
|
|
return nil, buserr.WithDetail("ErrDockerFailed", err.Error(), err)
|
|
}
|
|
defer cli.Close()
|
|
|
|
if socketPath, local := strings.CutPrefix(cli.DaemonHost(), "unix://"); local {
|
|
if _, statErr := os.Stat(socketPath); errors.Is(statErr, os.ErrNotExist) {
|
|
return []dto.DockerPortGuardContainer{}, nil
|
|
}
|
|
}
|
|
|
|
endpoints, err := discoverDockerEndpoints(ctx, cli, false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
backend := selectedDockerFirewallBackend("")
|
|
if info, infoErr := cli.Info(ctx); infoErr == nil {
|
|
backend = dockerFirewallBackend(info)
|
|
}
|
|
annotateDockerEndpointManagement(ctx, endpoints, backend)
|
|
return groupDockerGuardContainers(endpoints), nil
|
|
}
|
|
|
|
func (s *DockerPortGuardService) Operate(ctx context.Context, request dto.DockerPortGuardOperation) error {
|
|
dockerPortGuardServiceMu.Lock()
|
|
defer dockerPortGuardServiceMu.Unlock()
|
|
switch request.Operation {
|
|
case "initialize":
|
|
return s.initialize(ctx, request, nil)
|
|
case "bind":
|
|
runtime, _, err := s.runtimeForDocker(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
families, err := loadFirewallFamilies()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := errors.Join(runtime.Bind(families...), ctx.Err()); err != nil {
|
|
return err
|
|
}
|
|
return settingRepo.UpdateOrCreate(constant.FirewallDockerPortGuardStatusKey, constant.StatusEnable)
|
|
case "unbind":
|
|
var err error
|
|
if s.runtime != nil {
|
|
err = s.runtime.Unbind()
|
|
} else {
|
|
err = errors.Join(dockerfirewall.NewIptables(ctx).Unbind(), dockerfirewall.NewNftables(ctx).Unbind())
|
|
}
|
|
if err = errors.Join(err, ctx.Err()); err != nil {
|
|
return err
|
|
}
|
|
return settingRepo.UpdateOrCreate(constant.FirewallDockerPortGuardStatusKey, constant.StatusDisable)
|
|
default:
|
|
return fmt.Errorf("unsupported Docker port guard operation: %s", request.Operation)
|
|
}
|
|
}
|
|
|
|
func (s *DockerPortGuardService) QueueInitialization(request dto.DockerPortGuardOperation) (dto.FilterChainOperationResponse, error) {
|
|
if err := task.CheckScopeTaskIsExecuting(task.TaskScopeFirewall, 0); err != nil {
|
|
return dto.FilterChainOperationResponse{}, err
|
|
}
|
|
if request.Operation != "initialize" {
|
|
return dto.FilterChainOperationResponse{}, filter.ErrInvalidRule
|
|
}
|
|
if request.BackupFile != "" {
|
|
if _, err := readFirewallSubsystemBackup(request.BackupFile, "docker"); err != nil {
|
|
return dto.FilterChainOperationResponse{}, err
|
|
}
|
|
}
|
|
return queueFirewallRuleTask(firewallTaskDocker, task.TaskExec, request.TaskID, []string{firewallTaskDocker}, func(t *task.Task) error {
|
|
dockerPortGuardServiceMu.Lock()
|
|
defer dockerPortGuardServiceMu.Unlock()
|
|
return s.initialize(t.TaskCtx, request, t)
|
|
})
|
|
}
|
|
|
|
func (s *DockerPortGuardService) DeletePolicies(request dto.DockerPortGuardPolicyBatchDelete) (dto.FilterChainOperationResponse, error) {
|
|
uuids, err := normalizeDockerFirewallUUIDs(request.UUIDs)
|
|
if err != nil {
|
|
return dto.FilterChainOperationResponse{}, err
|
|
}
|
|
return queueFirewallRuleTask(firewallTaskDocker, task.TaskDelete, "", uuids, func(t *task.Task) error {
|
|
ctx := t.TaskCtx
|
|
dockerPortGuardServiceMu.Lock()
|
|
defer dockerPortGuardServiceMu.Unlock()
|
|
runtime, backend, err := s.runtimeForDocker(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
inventory, err := runtime.ListPolicies()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
wanted := make(map[string]bool, len(uuids))
|
|
for _, id := range uuids {
|
|
wanted[id] = true
|
|
}
|
|
remaining := make([]dockerfirewall.Policy, 0, len(inventory.Policies))
|
|
for _, policy := range inventory.Policies {
|
|
if wanted[policy.UUID] {
|
|
delete(wanted, policy.UUID)
|
|
} else {
|
|
remaining = append(remaining, policy)
|
|
}
|
|
}
|
|
if len(wanted) > 0 {
|
|
return filter.ErrRuleStale
|
|
}
|
|
return applyDockerPolicies(ctx, runtime, backend, inventory, remaining)
|
|
})
|
|
}
|
|
|
|
func (s *DockerPortGuardService) UpsertPolicies(request dto.DockerPortGuardPolicyBatch) (dto.FilterChainOperationResponse, error) {
|
|
if len(request.Policies) > filter.MaxAtomicExpansion {
|
|
return dto.FilterChainOperationResponse{}, fmt.Errorf("create or import at most %d rules per batch (after expansion)", filter.MaxAtomicExpansion)
|
|
}
|
|
labels := make([]string, len(request.Policies))
|
|
policies := make([]dockerfirewall.Policy, 0, len(request.Policies))
|
|
endpoints := make([]dto.DockerPortGuardEndpointIdentity, 0, len(request.Policies))
|
|
count := 0
|
|
for i, policy := range request.Policies {
|
|
labels[i] = fmt.Sprintf("[%d/%d] %s %s %s:%d %s", i+1, len(request.Policies), policy.Family, policy.Protocol, policy.HostIP, policy.HostPort, policy.Mode)
|
|
normalized, err := normalizeDockerFirewallPolicy(dockerfirewall.Policy{
|
|
Family: policy.Family, HostIP: policy.HostIP, HostPort: policy.HostPort,
|
|
Protocol: policy.Protocol, Mode: policy.Mode, Sources: policy.Sources,
|
|
})
|
|
if err != nil {
|
|
return dto.FilterChainOperationResponse{}, fmt.Errorf("%s: %w", labels[i], err)
|
|
}
|
|
if normalized.Mode == dockerfirewall.ModeAll || normalized.Mode == dockerfirewall.ModeAcceptAll {
|
|
count++
|
|
} else {
|
|
count += len(normalized.Sources)
|
|
if normalized.Mode == dockerfirewall.ModeAllow {
|
|
count++
|
|
}
|
|
}
|
|
if count > filter.MaxAtomicExpansion {
|
|
return dto.FilterChainOperationResponse{}, fmt.Errorf("create or import at most %d rules per batch (after expansion)", filter.MaxAtomicExpansion)
|
|
}
|
|
normalized.UUID = uuid.NewString()
|
|
policies = append(policies, normalized)
|
|
}
|
|
return queueFirewallRuleTask(firewallTaskDocker, task.TaskUpdate, "", labels, func(t *task.Task) error {
|
|
ctx := t.TaskCtx
|
|
dockerPortGuardServiceMu.Lock()
|
|
defer dockerPortGuardServiceMu.Unlock()
|
|
if err := ctx.Err(); err != nil {
|
|
return err
|
|
}
|
|
runtime, backend, err := s.runtimeForDocker(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
inventory, err := runtime.ListPolicies()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
current := append([]dockerfirewall.Policy(nil), inventory.Policies...)
|
|
if request.Import {
|
|
backup := dto.FirewallSubsystemBackup{Provider: filter.Provider(backend), Docker: &dockerfirewall.PolicyInventory{Policies: policies}}
|
|
merged, err := mergeDockerBackup(inventory, backup, backend, t)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
current = merged.Policies
|
|
}
|
|
byEndpoint := make(map[string]int, len(current))
|
|
for i, policy := range current {
|
|
byEndpoint[dockerPolicyEndpointKey(policy)] = i
|
|
}
|
|
for i := range policies {
|
|
key := dockerPolicyEndpointKey(policies[i])
|
|
index, exists := byEndpoint[key]
|
|
if request.Import {
|
|
if !exists || current[index].UUID != policies[i].UUID {
|
|
labels[i] = ""
|
|
continue
|
|
}
|
|
} else if exists {
|
|
policies[i].UUID = current[index].UUID
|
|
current[index] = policies[i]
|
|
} else {
|
|
byEndpoint[key] = len(current)
|
|
current = append(current, policies[i])
|
|
}
|
|
endpoints = append(endpoints, dto.DockerPortGuardEndpointIdentity{
|
|
Family: policies[i].Family, HostIP: policies[i].HostIP, HostPort: policies[i].HostPort, Protocol: policies[i].Protocol,
|
|
})
|
|
}
|
|
if len(endpoints) == 0 {
|
|
return nil
|
|
}
|
|
if err := s.rejectHostInputDockerGuardEndpoints(ctx, endpoints); err != nil {
|
|
return err
|
|
}
|
|
if err := applyDockerPolicies(ctx, runtime, backend, inventory, current); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func (s *DockerPortGuardService) Restore(ctx context.Context) error {
|
|
dockerPortGuardServiceMu.Lock()
|
|
defer dockerPortGuardServiceMu.Unlock()
|
|
enabled, err := dockerPortGuardPersistedEnabled()
|
|
if err != nil || !enabled {
|
|
return err
|
|
}
|
|
runtime, backend, err := s.runtimeForDocker(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
backup, err := readFirewallSubsystemBackup("docker-"+backend+".rules", "docker")
|
|
if errors.Is(err, os.ErrNotExist) {
|
|
return nil
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
families, err := loadFirewallFamilies()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !slices.Contains(families, constant.FirewallFamilyIPv6) {
|
|
before := len(backup.Docker.Policies)
|
|
backup.Docker.Policies = slices.DeleteFunc(backup.Docker.Policies, func(policy dockerfirewall.Policy) bool { return policy.Family == constant.FirewallFamilyIPv6 })
|
|
logFirewallIPv6Skipped(nil, "Docker startup", before-len(backup.Docker.Policies))
|
|
}
|
|
missing := make(map[string]bool)
|
|
needsBind := false
|
|
for _, family := range families {
|
|
status := runtime.Status(family)
|
|
if status.Reason == dockerfirewall.ReasonInspectFailed {
|
|
return fmt.Errorf("inspect Docker guard %s failed", family)
|
|
}
|
|
if status.Reason == dockerfirewall.ReasonCommandMissing {
|
|
continue
|
|
}
|
|
missing[family] = !status.Initialized
|
|
needsBind = needsBind || (status.Initialized && !status.Effective)
|
|
}
|
|
if !missing[dockerfirewall.FamilyIPv4] && !missing[dockerfirewall.FamilyIPv6] {
|
|
if needsBind {
|
|
return runtime.Bind(families...)
|
|
}
|
|
return nil
|
|
}
|
|
inventory, err := runtime.ListPolicies()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, policy := range inventory.Policies {
|
|
missing[policy.Family] = false
|
|
}
|
|
if inventory.RuleOrders == nil {
|
|
inventory.RuleOrders = make(map[string][]int64)
|
|
}
|
|
for _, policy := range backup.Docker.Policies {
|
|
if !missing[policy.Family] {
|
|
continue
|
|
}
|
|
inventory.Policies = append(inventory.Policies, policy)
|
|
key := policy.Family + "\x00" + policy.UUID
|
|
inventory.RuleOrders[key] = backup.Docker.RuleOrders[key]
|
|
}
|
|
return runtime.Initialize(inventory.Policies, inventory, families...)
|
|
}
|
|
|
|
func (s *DockerPortGuardService) runtimeStatus(runtime dockerfirewall.Runtime, backend string, ipv6Enabled bool) dto.DockerPortGuardBase {
|
|
ipv4 := runtime.Status(dockerfirewall.FamilyIPv4)
|
|
var ipv6 dockerfirewall.FamilyStatus
|
|
if ipv6Enabled {
|
|
ipv6 = runtime.Status(dockerfirewall.FamilyIPv6)
|
|
}
|
|
version := "-"
|
|
if s.version != nil {
|
|
version = s.version(backend)
|
|
}
|
|
name := "iptables-docker"
|
|
if strings.EqualFold(strings.TrimSpace(backend), constant.FirewallProviderNftables) {
|
|
name = "nftables-docker"
|
|
}
|
|
return dto.DockerPortGuardBase{
|
|
IPv6Enabled: ipv6Enabled,
|
|
Name: name,
|
|
Version: version,
|
|
Backend: backend,
|
|
IsExist: ipv4.Reason != dockerfirewall.ReasonCommandMissing || (ipv6Enabled && ipv6.Reason != dockerfirewall.ReasonCommandMissing),
|
|
Initialized: ipv4.Initialized || ipv6.Initialized,
|
|
Bound: ipv4.Bound || ipv6.Bound,
|
|
IPv4: dto.DockerPortGuardFamilyStatus{Partial: ipv4.Partial, State: ipv4.State, Reason: ipv4.Reason, Initialized: ipv4.Initialized, Bound: ipv4.Bound, Effective: ipv4.Effective},
|
|
IPv6: dto.DockerPortGuardFamilyStatus{Partial: ipv6.Partial, State: ipv6.State, Reason: ipv6.Reason, Initialized: ipv6.Initialized, Bound: ipv6.Bound, Effective: ipv6.Effective},
|
|
}
|
|
}
|
|
|
|
func matchDockerGuardPolicies(base dto.DockerPortGuardBase, policies []dto.DockerPortGuardEndpoint, endpoints []dto.DockerPortGuardEndpoint) ([]dto.DockerPortGuardEndpoint, []dto.DockerPortGuardEndpoint) {
|
|
matched := make(map[int]bool, len(policies))
|
|
byEndpoint := make(map[string]int, len(policies))
|
|
for index, policy := range policies {
|
|
key := strings.Join([]string{policy.Family, policy.HostIP, strconv.Itoa(int(policy.HostPort)), policy.Protocol}, "\x00")
|
|
if _, exists := byEndpoint[key]; !exists {
|
|
byEndpoint[key] = index
|
|
}
|
|
}
|
|
for i := range endpoints {
|
|
key := strings.Join([]string{endpoints[i].Family, endpoints[i].HostIP, strconv.Itoa(int(endpoints[i].HostPort)), endpoints[i].Protocol}, "\x00")
|
|
index, exists := byEndpoint[key]
|
|
if !exists {
|
|
continue
|
|
}
|
|
policy := policies[index]
|
|
endpoints[i].PolicyUUID, endpoints[i].Mode, endpoints[i].Sources = policy.PolicyUUID, policy.Mode, policy.Sources
|
|
endpoints[i].Effective = endpoints[i].ManagementTarget == dockerManagementContainerGuard && ((policy.Family == dockerfirewall.FamilyIPv4 && base.IPv4.Effective) || (policy.Family == dockerfirewall.FamilyIPv6 && base.IPv6.Effective))
|
|
matched[index] = true
|
|
}
|
|
orphans := make([]dto.DockerPortGuardEndpoint, 0)
|
|
for i, policy := range policies {
|
|
if !matched[i] {
|
|
orphans = append(orphans, policy)
|
|
}
|
|
}
|
|
return endpoints, orphans
|
|
}
|
|
|
|
func (s *DockerPortGuardService) rejectHostInputDockerGuardEndpoints(ctx context.Context, requested []dto.DockerPortGuardEndpointIdentity) error {
|
|
if s.client == nil || len(requested) == 0 {
|
|
return ctx.Err()
|
|
}
|
|
cli, err := s.client()
|
|
if err != nil {
|
|
return ctx.Err()
|
|
}
|
|
defer cli.Close()
|
|
info, err := cli.Info(ctx)
|
|
if err != nil {
|
|
return ctx.Err()
|
|
}
|
|
endpoints, err := discoverDockerEndpoints(ctx, cli, true)
|
|
if err != nil {
|
|
return ctx.Err()
|
|
}
|
|
annotateDockerEndpointManagement(ctx, endpoints, dockerFirewallBackend(info))
|
|
if err := ctx.Err(); err != nil {
|
|
return err
|
|
}
|
|
targets := make(map[string]string, len(endpoints))
|
|
for _, endpoint := range endpoints {
|
|
targets[fmt.Sprintf("%s|%s|%d|%s", endpoint.Family, endpoint.HostIP, endpoint.HostPort, endpoint.Protocol)] = endpoint.ManagementTarget
|
|
}
|
|
for _, endpoint := range requested {
|
|
target := targets[fmt.Sprintf("%s|%s|%d|%s", endpoint.Family, endpoint.HostIP, endpoint.HostPort, endpoint.Protocol)]
|
|
if target == dockerManagementHostFirewall {
|
|
return buserr.WithDetail("ErrInvalidParams", "endpoint traffic is handled by the host input firewall", nil)
|
|
}
|
|
if target == dockerManagementNeedsDiagnosis {
|
|
return buserr.WithDetail("ErrInvalidParams", "endpoint traffic management target requires diagnosis", nil)
|
|
}
|
|
}
|
|
return nil
|
|
}
|