Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Enhancement]: Resolve port bindings according to IPv4 and IPv6 #825

Closed
HofmeisterAn opened this issue Mar 9, 2023 · 1 comment · Fixed by #1363
Closed

[Enhancement]: Resolve port bindings according to IPv4 and IPv6 #825

HofmeisterAn opened this issue Mar 9, 2023 · 1 comment · Fixed by #1363
Assignees
Labels
enhancement New feature or request

Comments

@HofmeisterAn
Copy link
Collaborator

HofmeisterAn commented Mar 9, 2023

Problem

In some cases, Docker does not assign the same port to the IPv4 and IPv6 socket. Additionally, the operating system can resolve localhost to either an IPv4 or IPv6 address. To access the application or service running inside the container, it is essential to use the appropriate port binding according to the resolved IP. Otherwise, Testcontainers will be unable to connect to the app or service.

To avoid running into the issue mentioned above, Testcontainers for .NET only binds IPv4 bindings at present. However, this approach has a disadvantage, as it does not work in IPv6-only environments.

Solution

Something like:

// Contains two items:
// IsIPv6 ::1
// IsIPv4 127.0.0.1
var ips = Dns.GetHostAddresses("localhost");

var httpPort = 80;
var httpPortKey = httpPort + "/tcp";
var ipv4Binding = new PortBinding { HostIP = "0.0.0.0", HostPort = string.Format(CultureInfo.CurrentCulture, "{0}", ++httpPort) };
var ipv6Binding = new PortBinding { HostIP = "::", HostPort = string.Format(CultureInfo.CurrentCulture, "{0}", ++httpPort) };

IDictionary<string, IList<PortBinding>> mappedPortBindings = new Dictionary<string, IList<PortBinding>>();
mappedPortBindings.Add(new KeyValuePair<string, IList<PortBinding>>(httpPortKey, new List<PortBinding> { ipv4Binding, ipv6Binding }));
mappedPortBindings.TryGetValue(httpPortKey, out var portBindings);

// Lets imagine Dns.GetHostAddresses(string) returns the preferred order.
var addressFamilies = ips
  .Select(ip => ip.AddressFamily)
  .ToList();

// We can order the port bindings due to their address family, and use the first item.
var portBinding = portBindings
  .Select(portBinding => new IPEndPoint(IPAddress.Parse(portBinding.HostIP), ushort.Parse(portBinding.HostPort, NumberStyles.None, CultureInfo.InvariantCulture)))
  .OrderBy(portBinding => addressFamilies.IndexOf(portBinding.AddressFamily))
  .First();

Benefit

Support either IPv4, IPv6 or both environments.

Alternatives

Would you like to help contributing this enhancement?

Yes

@HofmeisterAn
Copy link
Collaborator Author

Relates: moby/moby#47871.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant