From f733440873c6f174bf649583bd595c1e6a749847 Mon Sep 17 00:00:00 2001 From: ShiroKSH Date: Mon, 29 Jun 2026 13:09:41 +0300 Subject: [PATCH] fix: filter local bindings in ISPN mode --- environment/allocations.go | 28 +++++++++----- environment/allocations_test.go | 65 +++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 9 deletions(-) create mode 100644 environment/allocations_test.go diff --git a/environment/allocations.go b/environment/allocations.go index e55a2b88b..41a49ecbf 100644 --- a/environment/allocations.go +++ b/environment/allocations.go @@ -65,26 +65,36 @@ func (a *Allocations) Bindings() nat.PortMap { // any reference to 127.0.0.1 with the IP of the pterodactyl0 network interface which will allow the // server to operate on a local address while still being accessible by other containers. func (a *Allocations) DockerBindings() nat.PortMap { - iface := config.Get().Docker.Network.Interface + nw := config.Get().Docker.Network out := a.Bindings() // Loop over all the bindings for this container, and convert any that reference 127.0.0.1 // to use the pterodactyl0 network interface IP, as that is the true local for what people are // trying to do when creating servers. for p, binds := range out { + if nw.ISPN { + filtered := binds[:0] + for _, alloc := range binds { + if alloc.HostIP != "127.0.0.1" { + filtered = append(filtered, alloc) + } + } + if len(filtered) == 0 { + delete(out, p) + } else { + out[p] = filtered + } + continue + } + for i, alloc := range binds { if alloc.HostIP != "127.0.0.1" { continue } - // If using ISPN just delete the local allocation from the server. - if config.Get().Docker.Network.ISPN { - out[p] = append(out[p][:i], out[p][i+1:]...) - } else { - out[p][i] = nat.PortBinding{ - HostIP: iface, - HostPort: alloc.HostPort, - } + out[p][i] = nat.PortBinding{ + HostIP: nw.Interface, + HostPort: alloc.HostPort, } } } diff --git a/environment/allocations_test.go b/environment/allocations_test.go new file mode 100644 index 000000000..61a520e81 --- /dev/null +++ b/environment/allocations_test.go @@ -0,0 +1,65 @@ +package environment + +import ( + "testing" + + "github.com/docker/go-connections/nat" + + "github.com/pterodactyl/wings/config" +) + +func configureNetwork(t *testing.T, ispn bool) { + t.Helper() + + cfg, err := config.NewAtPath("") + if err != nil { + t.Fatal(err) + } + cfg.Docker.Network.Interface = "172.18.0.1" + cfg.Docker.Network.ISPN = ispn + config.Set(cfg) +} + +func TestAllocationsDockerBindingsRewritesLocalhostBindings(t *testing.T) { + configureNetwork(t, false) + + allocations := Allocations{ + Mappings: map[string][]int{ + "127.0.0.1": {25565, 25565}, + }, + } + + bindings := allocations.DockerBindings() + for _, port := range []nat.Port{"25565/tcp", "25565/udp"} { + got := bindings[port] + if len(got) != 2 { + t.Fatalf("expected two bindings for %s, got %d", port, len(got)) + } + for _, binding := range got { + if binding.HostIP != "172.18.0.1" { + t.Fatalf("expected binding for %s to use interface IP, got %q", port, binding.HostIP) + } + } + } +} + +func TestAllocationsDockerBindingsDropsLocalhostBindingsForISPN(t *testing.T) { + configureNetwork(t, true) + + allocations := Allocations{ + Mappings: map[string][]int{ + "127.0.0.1": {25565, 25565}, + }, + } + + bindings := allocations.DockerBindings() + for _, port := range []nat.Port{"25565/tcp", "25565/udp"} { + if got, ok := bindings[port]; ok { + t.Fatalf("expected no bindings for %s, got %d", port, len(got)) + } + } + + if exposed := allocations.Exposed(); len(exposed) != 0 { + t.Fatalf("expected no exposed ports, got %d", len(exposed)) + } +}