Skip to content

system stack panic: As4 called on IPv6 address under dual-stack TCP churn on iOS #86

Description

@LuciusChen

Environment

  • sing-box for Apple: 1.14.0
  • sing-box core: 1.14.0-rc.1
  • sing-tun: v0.9.0-beta.2
  • Go: go1.26.6, ios/arm64
  • Device: iPhone 16 (iPhone17,3)
  • OS: iOS 27.0 beta (24A5424a)
  • TUN stack: system
  • TUN addresses: dual stack (one IPv4 prefix and one IPv6 prefix)

This was reproduced twice with the official, unmodified core/framework. No locally patched sing-tun code was installed.

What happened

The Network Extension hit critical memory pressure during a burst of dual-stack TCP connection retries and then panicked in rewriteIPv4TCP because an IPv6 address reached netip.Addr.As4().

Both reproductions followed the same pattern:

  1. Start the Network Extension with a dual-stack system TUN.
  2. Generate high connection churn, including repeated TCP attempts to currently unreachable IPv6 destinations.
  3. The in-process OOM monitor reports critical memory pressure.
  4. About 1–2 minutes after launch, the Network Extension aborts with the same panic.

The two observed timelines were:

  • Start 07:31:51Z; memory-pressure report 07:32:21Z; panic 07:34:54Z.
  • Start 08:46:30Z; memory-pressure report 08:47:12Z; panic 08:48:42Z.

Panic

panic: As4 called on IPv6 address

net/netip.Addr.As4(...)
github.com/sagernet/sing-tun.rewriteIPv4TCP(...)
    github.com/sagernet/sing-tun@v0.9.0-beta.2/stack_system.go:553
github.com/sagernet/sing-tun.(*System).processIPv4TCP(...)
    github.com/sagernet/sing-tun@v0.9.0-beta.2/stack_system.go:483
github.com/sagernet/sing-tun.(*System).processIPv4(...)
github.com/sagernet/sing-tun.(*System).processPacket(...)
github.com/sagernet/sing-tun.(*System).tunLoop(...)

The native exception is SIGABRT, with exceptionReason set to As4 called on IPv6 address; it was not a jetsam termination.

Memory-pressure evidence from the second reproduction

At 08:47:12Z, 42 seconds after launch:

memoryUsage:    40 MB
availableMemory: 9.5 MB
heapAlloc:      19 MB
heapInuse:      25 MB
heapSys:        33 MB
sys:            42 MB
totalAlloc:     1.7 GB
numGC:          305
numGoroutine:   228

Heap inuse_space top entries:

7.24 MB  github.com/sagernet/sing-tun.(*TCPNat).Lookup
3.27 MB  github.com/sagernet/sing-tun.(*ForwardDispatcher).insertEntry
4.27 MB  github.com/sagernet/sing-tun.(*ForwardDispatcher).installSimple (cumulative)

Heap inuse_objects included:

43,734  github.com/sagernet/sing-tun.(*TCPNat).Lookup
32,769  github.com/sagernet/sing-tun.(*ForwardDispatcher).installSimple

Source observation

In the system stack, IPv4 and IPv6 TCP processing appear to share the same tcpNat. Both families call Lookup/LookupBack, while processIPv4TCP passes the returned session addresses to rewriteIPv4TCP, which calls As4() without checking the address family.

I cannot yet prove whether the wrong-family session is caused by NAT-port reuse, a stale entry, or a race, but the panic proves that an IPv6 address was returned to the IPv4 rewrite path. It may be worth either separating the TCP NAT state by address family or validating the session family before rewriting.

Expected behavior

High dual-stack connection churn, including unreachable IPv6 destinations, should not allow an IPv6 session to reach the IPv4 rewrite path and should not panic the Network Extension.

Full crash/OOM reports and pprof data can be provided privately if useful. The active configuration is not attached because it contains proxy credentials and subscription data.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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