Use simulated dual-stack binds when using WSL
Resolves a WSL problem where traffic from only one stack is relayed Signed-off-by: Jason T. Greene <jason.greene@redhat.com>
This commit is contained in:
parent
5ac00a7287
commit
772ead2531
|
@ -1,3 +1,6 @@
|
|||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
|
@ -307,11 +310,11 @@ func exposePorts(pm rkport.Manager, portMappings []types.PortMapping, childIP st
|
|||
ChildPort: int(port.ContainerPort + i),
|
||||
ChildIP: childIP,
|
||||
}
|
||||
if err := rkportutil.ValidatePortSpec(spec, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := pm.AddPort(ctx, spec); err != nil {
|
||||
return err
|
||||
|
||||
for _, spec = range splitDualStackSpecIfWsl(spec) {
|
||||
if err := validateAndAddPort(ctx, pm, spec); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -319,6 +322,17 @@ func exposePorts(pm rkport.Manager, portMappings []types.PortMapping, childIP st
|
|||
return nil
|
||||
}
|
||||
|
||||
func validateAndAddPort(ctx context.Context, pm rkport.Manager, spec rkport.Spec) error {
|
||||
if err := rkportutil.ValidatePortSpec(spec, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := pm.AddPort(ctx, spec); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func child() error {
|
||||
// load the config from the parent
|
||||
var opaque map[string]string
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/common/pkg/machine"
|
||||
rkport "github.com/rootless-containers/rootlesskit/pkg/port"
|
||||
)
|
||||
|
||||
// WSL machines do not relay ipv4 traffic to dual-stack ports, simulate instead
|
||||
func splitDualStackSpecIfWsl(spec rkport.Spec) []rkport.Spec {
|
||||
specs := []rkport.Spec{spec}
|
||||
protocol := spec.Proto
|
||||
if machine.MachineHostType() != machine.Wsl || strings.HasSuffix(protocol, "4") || strings.HasSuffix(protocol, "6") {
|
||||
return specs
|
||||
}
|
||||
|
||||
ip := net.ParseIP(spec.ParentIP)
|
||||
splitLoopback := ip.IsLoopback() && ip.To4() == nil
|
||||
// Map ::1 and 0.0.0.0/:: to ipv4 + ipv6 to simulate dual-stack
|
||||
if ip.IsUnspecified() || splitLoopback {
|
||||
specs = append(specs, spec)
|
||||
specs[0].Proto = protocol + "4"
|
||||
specs[1].Proto = protocol + "6"
|
||||
if splitLoopback {
|
||||
// Hacky, but we will only have one ipv4 loopback with WSL config
|
||||
specs[0].ParentIP = "127.0.0.1"
|
||||
}
|
||||
if ip.IsUnspecified() {
|
||||
specs[0].ParentIP = "0.0.0.0"
|
||||
specs[1].ParentIP = "::"
|
||||
}
|
||||
}
|
||||
|
||||
return specs
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/containers/common/pkg/machine"
|
||||
"github.com/rootless-containers/rootlesskit/pkg/port"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type SpecData struct {
|
||||
mach string
|
||||
sourceProto string
|
||||
sourceIP string
|
||||
expectCount int
|
||||
expectProto string
|
||||
expectIP string
|
||||
secondProto string
|
||||
secondIP string
|
||||
}
|
||||
|
||||
func TestDualStackSplit(t *testing.T) {
|
||||
//nolint
|
||||
const (
|
||||
IP4_ALL = "0.0.0.0"
|
||||
IP4__LO = "127.0.0.1"
|
||||
IP6_ALL = "::"
|
||||
IP6__LO = "::1"
|
||||
TCP_ = "tcp"
|
||||
TCP4 = "tcp4"
|
||||
TCP6 = "tcp6"
|
||||
WSL = "wsl"
|
||||
___ = ""
|
||||
IP6_REG = "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
|
||||
IP4_REG = "10.0.0.1"
|
||||
)
|
||||
|
||||
tests := []SpecData{
|
||||
// Split cases
|
||||
{WSL, TCP_, IP4_ALL, 2, TCP4, IP4_ALL, TCP6, IP6_ALL},
|
||||
{WSL, TCP_, IP6_ALL, 2, TCP4, IP4_ALL, TCP6, IP6_ALL},
|
||||
{WSL, TCP_, IP6__LO, 2, TCP4, IP4__LO, TCP6, IP6__LO},
|
||||
|
||||
// Non-Split
|
||||
{WSL, TCP_, IP4__LO, 1, TCP_, IP4__LO, "", ""},
|
||||
{WSL, TCP4, IP4_ALL, 1, TCP4, IP4_ALL, "", ""},
|
||||
{WSL, TCP6, IP6__LO, 1, TCP6, IP6__LO, "", ""},
|
||||
{WSL, TCP_, IP4_REG, 1, TCP_, IP4_REG, "", ""},
|
||||
{WSL, TCP_, IP6_REG, 1, TCP_, IP6_REG, "", ""},
|
||||
{___, TCP_, IP4_ALL, 1, TCP_, IP4_ALL, "", ""},
|
||||
{___, TCP_, IP6_ALL, 1, TCP_, IP6_ALL, "", ""},
|
||||
{___, TCP_, IP4__LO, 1, TCP_, IP4__LO, "", ""},
|
||||
{___, TCP_, IP6__LO, 1, TCP_, IP6__LO, "", ""},
|
||||
}
|
||||
|
||||
for _, data := range tests {
|
||||
verifySplit(t, data)
|
||||
}
|
||||
}
|
||||
|
||||
func verifySplit(t *testing.T, data SpecData) {
|
||||
machine := machine.GetMachineMarker()
|
||||
oldEnable, oldType := machine.Enabled, machine.Type
|
||||
machine.Enabled, machine.Type = len(data.mach) > 0, data.mach
|
||||
|
||||
source := port.Spec{
|
||||
Proto: data.sourceProto,
|
||||
ParentIP: data.sourceIP,
|
||||
ParentPort: 100,
|
||||
ChildIP: "1.1.1.1",
|
||||
ChildPort: 200,
|
||||
}
|
||||
expect, second := source, source
|
||||
specs := splitDualStackSpecIfWsl(source)
|
||||
|
||||
assert.Equal(t, data.expectCount, len(specs))
|
||||
|
||||
expect.Proto = data.expectProto
|
||||
expect.ParentIP = data.expectIP
|
||||
assert.Equal(t, expect, specs[0])
|
||||
|
||||
if data.expectCount > 1 {
|
||||
second.Proto = data.secondProto
|
||||
second.ParentIP = data.secondIP
|
||||
assert.Equal(t, second, specs[1])
|
||||
}
|
||||
|
||||
machine.Enabled, machine.Type = oldEnable, oldType
|
||||
}
|
Loading…
Reference in New Issue