Repository navigation
IPGlobalProperties.GetActiveTcpListeners() returns zero listeners on macOS 27 #133960
Description
Activity
- addeduntriagedNew issue has not been triaged by the area ownerNew issue has not been triaged by the area owner
on Sep 15, 2026 dotnet-policy-service commented
on Sep 15, 2026 ContributorMore actionsTagging subscribers to this area: @karelz, @dotnet/ncl
See info in area-owners.md if you want to be subscribed.I'm a bot. Here is a possible related and/or duplicate issue (I may be wrong):
- addedos-macosmacOS aka OSXmacOS aka OSXand removeduntriagedNew issue has not been triaged by the area ownerNew issue has not been triaged by the area owner
on Sep 15, 2026 I reproduced this on macOS 27.0 build 26A428 with .NET 8.0.421, the .NET
10.0.12 runtime, and current runtime development bits.This is not an
xtcpcblayout change. On macOS 27,
net.inet.tcp.pcblistnow filters the returned records for ordinary
third-party processes. If the querying process does not own a TCP socket,
the sysctl call returns only the 24-byte header and trailer and no PCB
records. Sockets owned by the querying process remain visible.That explains why the existing runtime test still passes: it creates and
queries its listener in the same process. A listener owned by a separate
Python process is visible tolsofandnetstat, but not to
GetActiveTcpListeners().Apple's
netstatbinary has the private
com.apple.private.network.statisticsentitlement, which is unavailable
to third-party applications.I also confirmed that
GetActiveUdpListeners()is affected in the same
way. Alibproc-based fallback can recover many same-user sockets,
including the reported local-development scenario, but cannot inspect
every protected or system process, so it would not fully restore the
previous machine-wide behavior.The only alternative would be spawn the
netstator wait for Apple to have the entertainment available for 3rd party pass.Reacted by Benjamin DehliThanks for tracking that down, it explains everything I saw. The listener in my repro is a separate process started by the same user, so it falls inside what you describe a libproc fallback recovering.
Possibly relevant to that:
The tool that led me here (Altinn/altinn-studio#20453) spawnsnetstatand parses its output, and that still returns other processes' PIDs on macOS 27 because Apple's binary has the entitlement. So for same-user local development the information is reachable, just not through the sysctl the runtime uses.
Happy to test a libproc-based build on 27.0 (26A428) if that would help.we will need to figure out if we want to call external binary or document it its platform limitation. The changed behavior comes from Apple's change. I can somewhat see the motivation but 1) the netstat is still there so one can get equal information and 2) they should add public entitlement so one can choose.
Reacted by Benjamin DehliThanks a lot, Tomas! Either direction works for my case, since the tool that led me here spawns
netstatitself.
Today the failure is silent so an empty array looks just like a machine with nothing listening. So the first assumption (at least in my case) is a local misconfiguration rather than the API. It cost me a fair amount of time before I suspectedGetActiveTcpListeners()at all. If this ends up documented as a platform limitation, stating plainly that on macOS 27 and later the result contains only sockets owned by the current process would help.
However if there's a cheap/easy way to surface the truncation at runtime, that would help more.
Description
IPGlobalProperties.GetActiveTcpListeners()returns zero listeners on macOS 27.This looks like the macOS
sysctlPCB-list path returning nothing, plausibly a struct or ABI change in macOS 27. That attribution is inference from how the API is implemented on macOS, not something observed directly. Reproduces on .NET 8.0.421 and on the .NET 10.0.12 runtime.Real-world impact: tooling that discovers local services this way silently finds nothing rather than failing loudly.
Reproduction Steps
Start any process that listens on a TCP port. In my case an ASP.NET Core app on
127.0.0.1:5005, butpython3 -m http.server 5005behaves the same.Run:
Output:
Confirm that the operating system does list the socket at the same moment:
Run the same binary against the .NET 10 runtime:
Expected behavior
The machine's listening TCP endpoints, including 127.0.0.1:5005
Actual behavior
listeners: 0Regression?
I don't know. I never ran
GetActiveTcpListeners()on macOS 26, so all I can say is that the same SDK version returns zero on macOS 27 whilelsofandnetstatboth see the listener.Known Workarounds
Read the listener list from the operating system instead:
netstat -anv -p tcpand filter onLISTEN. Note that on macOS 27 the verbose output merges the formerpidandepidcolumns into a singleprocess:pidfield whose value can contain spaces, for exampleCode Helper:7260, so splitting on whitespace by field index no longer works for the process part.libproc(proc_listpidsplusproc_pidfdinfo), which returns ports and owning PIDs directly.lsof -nP -iTCP -sTCP:LISTEN.Configuration
DOTNET_ROLL_FORWARD=LatestMajorOther information
This surfaced while debugging a local development tool that could no longer find a running app after a macOS 26 to 27 upgrade. That tool uses its own
netstatparsing rather than this API, so the two failures are independent, but both point at port enumeration on macOS 27 as the common factor.