Skip to content

IPv6 to container *.orb.local addresses silently drops packets larger than 1280 bytes (no ICMPv6 Packet Too Big) #2617

Description

@geggo98

Describe the bug

IPv6 packets to a container's *.orb.local address are silently dropped when they
are larger than 1280 bytes (the IPv6 minimum MTU). No ICMPv6 "Packet Too Big" is
sent back, and both the interface and the route keep reporting MTU 1500. IPv4 to
the very same container works fine with a 1500-byte packet and DF set.

Because *.orb.local resolves to an A and an AAAA record, clients often pick
IPv6. Small replies arrive, so the TCP connection comes up and looks healthy —
but any response larger than ~1280 bytes stalls until the client times out. curl
then reports a valid HTTP status with an incomplete body:

$ curl -sS -o /dev/null -w 'code=%{http_code} exit=%{exitcode} ip=%{remote_ip} size=%{size_download}\n' \
    --max-time 10 http://my-app.k8s.orb.local/
code=200 exit=28 ip=fd07:b51a:cc66:0:a617:db5e:c0a8:8a03 size=0
curl: (28) Operation timed out after 10002 ms with 0 out of 63166 bytes received

$ curl -sS -o /dev/null -w 'code=%{http_code} exit=%{exitcode} ip=%{remote_ip} size=%{size_download}\n' \
    -H 'Host: my-app.k8s.orb.local' http://192.168.138.3/
code=200 exit=0 ip=192.168.138.3 size=63166        # same page over IPv4: 27 ms

Which address family a client picks is not deterministic. In one series the same
URL went over IPv6 five times in a row (all broken), then over IPv4 three times
(all fine), so containers appear to fail at random. Happy Eyeballs does not help,
because the connect succeeds — only the data transfer stalls. Safari recovers
(it retries over IPv4), Chrome stays on the broken socket and the page never
finishes loading.

To Reproduce

# 1. Start any container that just stays alive
docker run -d --rm --name mtu-probe --entrypoint sh alpine -c 'sleep 300'

# 2. Look up both addresses
dscacheutil -q host -a name mtu-probe.orb.local
#   ip_address:   192.168.138.173
#   ipv6_address: fd07:b51a:cc66:0:a617:db5e:c0a8:8aad

# 3. IPv6 at exactly the minimum MTU -> works (1232 + 48 = 1280 bytes)
ping6 -c1 -s 1232 fd07:b51a:cc66:0:a617:db5e:c0a8:8aad     # reply

# 4. One byte more -> no reply, and no ICMPv6 Packet Too Big
ping6 -c1 -s 1233 fd07:b51a:cc66:0:a617:db5e:c0a8:8aad     # silent timeout
ping6 -c1 -s 1300 fd07:b51a:cc66:0:a617:db5e:c0a8:8aad     # silent timeout

# 5. IPv4 to the same container, 1500 bytes with DF -> works
ping -D -c1 -s 1472 192.168.138.173                        # reply

For the HTTP symptom, serve any page larger than ~1280 bytes from the container
and fetch it over the IPv6 address with a Host header.

What I already narrowed down

  • Not Kubernetes-specific. I first hit this through <ns>.k8s.orb.local
    behind an ingress controller, but a plain Docker container shows exactly the
    same 1280-byte cliff.
  • The bridge itself is fine. ping6 -s 1300 to the OrbStack gateway
    (fd07:b51a:cc66::1) and to the Mac's own bridge100 address
    (fd07:b51a:cc66:0:a617:db5e:ab7:e9f1) both get replies. Only the
    per-container ULA is capped.
  • The container ULA embeds its IPv4 address: …:c0a8:8aad = 192.168.138.173.
  • The container has no global IPv6 address inside the VM.
    ip -6 addr show scope global in the container is empty, so the ULA looks
    like a host-side mapping rather than an address configured in the guest.
  • Nothing advertises a smaller MTU. ndp -i bridge100 reports
    linkmtu=1500, ifconfig bridge100 reports mtu 1500, and
    route -n get -inet6 <ula> still reports mtu 1500 after the failed pings —
    so no Packet Too Big is arriving.
  • IPv6 is not disabled in my configuration. network.subnet4 is
    192.168.138.0/23; I could not find an IPv6 switch in orb config.
  • Occasionally a few bytes do get through before the stall (I have seen curl
    receive 3830 of 63166 bytes, and also 0 of 63166), so it is not a hard block
    on the connection.

Possibly related but not the same: #1790 (closed, milestone v2.2.0) was about
an AAAA being resolved inside containers while IPv6 was disabled. Here the AAAA
resolves and connects fine — it just cannot carry more than 1280 bytes. I am on
2.2.1, so after that fix.

Expected behavior

Either IPv6 carries packets up to the link MTU (1500) like IPv4 does, or OrbStack
replies with ICMPv6 Packet Too Big so the client can lower its path MTU. Dropping
packets silently while the interface and route still advertise MTU 1500 leaves
clients hanging until they time out, and makes containers look randomly broken
depending on which address family the client happened to pick.

Diagnostic report

OrbStack info:
  Version: 2.2.1
  Commit: 0e182b501fcd9e05b99ffb363fce03610390c400 (v2.2.1)

System info:
  macOS: 26.5.2 (25F84)
  CPU: arm64, 12 cores
  CPU model: Apple M2 Max
  Model: Mac14,5
  Memory: 32 GiB

Full report: https://orbstack.dev/_admin/diag/orbstack-diagreport_2026-07-29T16-44-12.892423Z.zip

Screenshots and additional context

  • network.subnet4: 192.168.138.0/23, network_bridge: true, k8s.enable: true
  • docker.expose_ports_to_lan: true, k8s.expose_services: false
  • No IPv6 setting found in orb config on 2.2.1.

A practical note for others hitting this: forcing IPv4 (curl -4, or connecting
to the container's IPv4 address with a Host header) works around it, but
browsers and other clients still pick IPv6 on their own.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions