Programmatic IP Discovery for VZVirtualMachine in an App Store Sandbox

Hi everyone,

I am developing a macOS virtualization manager (VirtualProg) using the Virtualization.framework. The application is distributed via the Mac App Store, so it operates strictly within the App Store Sandbox.

I am looking for a reliable, programmatic way to discover the IP address assigned to a guest (both macOS and Linux).

Is there a recommended "Sandbox-safe" API or pattern within the Virtualization framework—or a lower-level networking entitlement—that allows a host application to retrieve the guest's assigned IP address?

Ideally, I am looking for a solution that does not require the user to manually install a non-sandboxed helper tool.

Thanks in advance for any insights or guidance!

Answered by DTS Engineer in 883963022

i [want] to determine ip address of guest os without any cooperation from guest.

Thanks for confirming that.

This is a fundamentally tricky problem to solve, at least in the general case. The guest chooses how it’s going to assign IP addresses to an interface, and the host has no direct control over that choice.

However, there may be an indirect way to do this:

  • Virtualization framework lets you create a network that’s backed by a vmnet network (VZVmnetNetworkDeviceAttachment).
  • vmnet framework lets your configure a network with a specific DHCP mapping (vmnet_network_configuration_add_dhcp_reservation).

There are some significant caveats:

  • The guest must default to using DHCP.
  • You can’t support bridged mode (VMNET_BRIDGED_MODE), because in bridged mode the guest isn’t talking to the vmnet DHCP server.
  • This is all new in macOS 26.

But otherwise I think it’ll work. So please try it out and let me know how you get along.

ps It’s better to reply as a reply, rather than in the comments; see Quinn’s Top Ten DevForums Tips for this and other titbits.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

it does not work in both mode

Thanks for confirming that.

So what’s are the exact symptoms of the failure you’re seeing?

I’m asking because I took the code from your bug report, put it in a test tool, and I saw two different things:

  • In some cases the first sysctl would fail with EPERM.
  • In other cases it just worked.

Neither of these match the behaviour that I thought I might see [1], which has left me quite confused.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] I thought I might end up seeing the MAC addresses being scrubbed, à la iOS.

this is the line failing in macOS 27

   var needed = 0
               guard sysctl(&mib, 6, nil, &needed, nil, 0) == 0, needed > 0 else { return [:] }

since this is failing it does not go to the second sysctl but when i use AF_INET6 it goes to the second sysctl and succeed there also. but with macOS 26 this worked

I took the help of claude code and come to a conclusion like this

Summary: IPv4 ARP cache invisible via PF_ROUTE sysctl on macOS 27 — bundled apps only; cause unknown

TL;DR: On macOS 27, querying the IPv4 ARP cache via sysctl(CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO) returns an empty result (needed == 0) inside our built .app bundle, with or without the App Sandbox entitlement. The identical query with AF_INET6 returns real data in the same app. arp -a (system binary) shows IPv4 entries fine. Crucially, the identical sysctl code run as a bare, unbundled swift repro.swift script also returns real IPv4 data — so this is not about code-signing or sandboxing in general, it's specific to being a launched, bundled GUI app. We suspected the Local Network privacy permission next (the app had never appeared in System Settings → Privacy & Security → Local Network), added NSLocalNetworkUsageDescription/NSBonjourServices, forced the permission prompt via an NWBrowser Bonjour browse, and granted it — the sysctl result was unchanged. Local Network permission is ruled out too. The unbundled script also has no Local Network grant, yet works fine, confirming that permission isn't the differentiator either way. The actual cause is still unknown. Worked correctly, unchanged, on macOS 26. Full write-up: macos27_arp_sandbox_bug_report.md.

Minimal repro

Save as repro.swift and run with swift repro.swift:

  • From Terminal (unbundled script): returns real IPv4 + IPv6 data — bug does not reproduce.
  • Built into the actual .app bundle and run from Finder/LaunchServices: AF_INET returns needed=0; AF_INET6 still works — bug reproduces, with or without the App Sandbox entitlement.
import Darwin

func probe(_ family: Int32, label: String) {
    var mib: [Int32] = [CTL_NET, PF_ROUTE, 0, family, NET_RT_FLAGS, Int32(RTF_LLINFO)]
    var needed = 0
    let rc = sysctl(&mib, 6, nil, &needed, nil, 0)
    print("\(label): rc=\(rc) errno=\(errno) needed=\(needed)")
}

probe(AF_INET, label: "AF_INET  (expect IPv4 ARP entries)")
probe(AF_INET6, label: "AF_INET6 (IPv6 neighbor entries)")

Run as swift repro.swift from Terminal — bug does NOT reproduce

AF_INET  (expect IPv4 ARP entries): rc=0 errno=0 needed=7324
AF_INET6 (IPv6 neighbor entries): rc=0 errno=0 needed=15464

Both calls succeed with real, non-empty data — exactly as expected, matching macOS 26 behavior.

Same code, built into and run as our app bundle on macOS 27 — bug reproduces

AF_INET  (expect IPv4 ARP entries): rc=0 errno=2 needed=0
AF_INET6 (IPv6 neighbor entries): rc=0 errno=0 needed=<nonzero>

rc == 0 means the call succeeded — it's not an error, just an empty result for AF_INET specifically, and only inside the app bundle. arp -a run at the same time in Terminal also lists IPv4 entries normally. Reproduces with the App Sandbox entitlement present and with it removed — sandboxing is not the differentiator. The differentiator is bundled-app-vs-bare-script.

this is the line failing in macOS 27

OK, but there are two reasons that can fail:

  • The sysctl(…) call returns a non-zero value.
  • The returned needed is zero or less.

You’re hitting the second case, right?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

You’re hitting the second case, right?

Yes sysctl returns zero and the returned needed also zero

the returned needed also zero

Thanks for confirming that. That explains why I was seeing EPERM errors. I modified your program to print errno in the the body of the guard statement, but that was a mistake on my part because if sysctl returns zero then it doesn’t set errno, and so I was looking at a junk value.

The fact that needed is zero suggests that the results are being scrubbed, and that’s much less of a surprise. macOS 27 beta definitely includes new code for this. However, I’m not 100% sure of the new rules. I’ll do some research and get back to you.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

However, I’m not 100% sure of the new rules.

I’m glad I checked (-:

Xcode 27 beta has a new Network Topology Observation capability. That authorises your use of the com.apple.developer.networking.topology-observation entitlement, and that should allow your code to work on macOS 27 beta. (I haven’t tried this myself yet, because a) I don’t have time for that today, and b) my ability to reproduce this problem was rather limited.)

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Xcode 27 beta has a new Network Topology Observation capability. That authorises your use of the com.apple.developer.networking.topology-observation entitlement

yay. It worked after adding the capability. thank you very much for closing the loop.

Programmatic IP Discovery for VZVirtualMachine in an App Store Sandbox
 
 
Q