I wanted to build an iOS application that could discover macOS caching servers on the local network, I thought it would be straightforward. I was wrong.
What followed was a deep dive into Apple's content caching discovery mechanisms, network protocols, and the many ways assumptions can lead you down the wrong path.
The iOS Application
I needed an iOS app that could:
- Request local network permissions at startup
- Discover macOS caching servers on the same Wi-Fi network
- Display results professionally with server status
- Allow manual IP address scanning as a fallback
The challenge was understanding how macOS caching servers actually work in modern versions of macOS, versus outdated documentation and assumptions.
Lets take a look at the visuals, first we have the main application screen:
When a server is found you will get a confirmation as you can see below, which will show the port and IP:
The First Pitfall: Bonjour Assumptions
My initial approach assumed that macOS caching servers would advertise themselves via Bonjour service discovery, like many network services do.
// WRONG APPROACH - Don't do this
let browser = NWBrowser(for: .bonjourWithTXTRecord(type: "_http._tcp", domain: nil), using: .tcp)
Modern macOS caching servers don't use traditional Bonjour service advertising, whereas older versions of MacOS did - this approach led nowhere and wasted considerable development time.
The Second Pitfall: Standard HTTP Ports
Next, I assumed caching servers would listen on standard HTTP ports like 80 or 443.
// WRONG ASSUMPTION - Caching servers don't use these ports
let standardPorts = [80, 443, 8080, 8443]
macOS caching servers listen on ephemeral ports in the range 49152-65535. These ports are assigned dynamically at startup, making discovery more challenging.
Understanding the Real Discovery Mechanism
Through research, I discovered that macOS caching server discovery works through a sophisticated process:
- The caching server registers with Apple's cloud service at
lcdn-registration.apple.com
- Client devices contact Apple's locator service at
lcdn-locator.apple.com
- Apple matches clients to registered caching servers based on public IP addresses
- Results are stored in system files and used by applications like the App Store
The official command-line tool AssetCacheLocatorUtil
performs this discovery:
AssetCacheLocatorUtil
This tool revealed that caching servers appear with entries like:
192.168.1.100:49159, rank 1, guid <guid>..., supports shared caching: yes
The Third Pitfall: Automatic Discovery Complexity
I attempted to replicate Apple's discovery protocol within the iOS app:
private func contactAppleLocatorService(localIP: String, publicIP: String) async throws -> [CachingServer] {
let url = URL(string: "https://lcdn-locator.apple.com/lcdn/locator")!
// ... complex implementation
}
While this approach is theoretically correct, it's overly complex for most use cases. The manual IP scanning approach proved more reliable and practical.
Manual IP Scanning with Proper Verification
The final solution focuses on what actually works: scanning specific IP addresses for caching servers on ephemeral ports.
Setting Up the Xcode Project
Create a new iOS project:
- File → New → Project → iOS → App
- Interface: SwiftUI
- Language: Swift|
- File → New → Project → iOS → App
Add required permissions in project settings:
The Core of the iOS Application : Network Manager
class NetworkManager: ObservableObject {
@Published var hasLocalNetworkPermission = false
@Published var isScanning = false
@Published var discoveredServers: [CachingServer] = []
@Published var scanningStatus = ""
func scanIPForCachingServer(_ ipAddress: String) {
guard hasLocalNetworkPermission else { return }
guard isValidIPAddress(ipAddress) else { return }
Task {
await scanEphemeralPorts(for: ipAddress)
}
}
}
Port Scanning Discovery
The key insight was understanding which ports to scan:
private func scanEphemeralPorts(for ipAddress: String) async {
let commonCachingPorts = [
49152, 49153, 49154, 49155, 49156, 49157, 49158, 49159, 49160,
49200, 49268, 49300, 49313, 49400, 49500, 49558, 49600,
50000, 51000, 51858, 52000, 52613, 53000, 60000, 60093
]
for port in commonCachingPorts {
let isResponding = try await testConnection(ip: ipAddress, port: port)
if isResponding {
// Add to discovered servers
}
}
}
The Fourth Pitfall: TCP Connection vs. HTTP Verification
Initially, I assumed that any open TCP port in the ephemeral range was a caching server:
// TOO SIMPLISTIC - Just checks if port accepts connections
private func testConnection(ip: String, port: Int) async throws -> Bool {
// TCP connection test only
return portIsOpen
}
This led to false positives from other services running on those ports.
Optimized Scanning : Apple-Specific HTTP Header Verification
The breakthrough came when I tested the actual caching server manually:
curl -v http://localhost:49159/
This revealed that caching servers return HTTP 400 Bad Request with a distinctive header:
< HTTP/1.1 400 Bad Request
< X-Apple-Cache-Session: VLXIhAoVV7Ij
The final verification function:
private func verifyCachingServer(ip: String, port: Int) async throws -> Bool {
let url = URL(string: "http://\(ip):\(port)/")!
let (_, response) = try await URLSession.shared.data(from: url)
if let httpResponse = response as? HTTPURLResponse {
// Check for Apple Cache specific headers - the smoking gun!
if let cacheSession = httpResponse.value(forHTTPHeaderField: "X-Apple-Cache-Session") {
return true // Definitely a caching server
}
// Accept 400 Bad Request as valid (caching servers often return this)
if httpResponse.statusCode == 400 {
return true
}
}
return false
}
Adding App Icons
I thought it was worth designing a new icon for this application, however, I’m not a graphic designer, but I did find a very good logo generator that took my human words and converted them logos - which I simply adapted for icon files, this is the icon I have chosen to use:
Before distributing via Test Flight, an app icon is required:
- Generate a single 1024x1024 icon using an icon generation utility
- The icon must be in PNG format (no transparency, square dimensions)
- In Xcode Project Navigator (left sidebar): Click on
Assets.xcassets
- Click on "AppIcon" in the Assets list (or create "New iOS App Icon" if missing)
- Drag your 1024x1024 PNG file into the single App Store 1024pt slot
- Xcode automatically generates all other required sizes
Publishing to Test Flight
Note : Your application cannot be published to Test Flight unless it has an icon
- Set deployment target to "Any iOS Device (arm64)"
- Product menu → Archive
- In Organizer: Click "Distribute App"
- Select "App Store Connect"
- Upload to TestFlight
- Add external testers via App Store Connect
- Install TestFlight app on target devices
- Install your app via TestFlight
Key Lessons Learned
Test on Real Hardware
Network discovery features must be tested on physical devices. The iOS Simulator cannot properly test local network functionality.
Understand the Actual Protocol
The breakthrough came from understanding that caching servers return HTTP 400 with Apple-specific headers, not the HTTP 200 you might expect from a web server.
Iterative Problem Solving
Each failure taught us something important:
- Bonjour isn't used → Led to port scanning approach
- Standard ports don't work → Discovered ephemeral port ranges
- TCP isn't enough → Required HTTP verification
- Generic HTTP checks give false positives → Apple-specific headers are the solution
The Final Application : Caching Checker
The finished app successfully:
- Requests and handles local network permissions properly
- Scans ephemeral port ranges where caching servers actually operate
- Verifies discovered services are genuine Apple caching servers
- Provides professional UI with proper error handling and status updates
- Dismisses keyboard appropriately when interacting with the interface
Verification Results
Caching Server ON:
🍎 APPLE CACHE SERVER DETECTED! Session: VLXIhAoVV7Ij
Found: 192.168.1.100:49159
Caching Server OFF:
No caching servers found
The application now reliably distinguishes between active caching servers and other network services, providing network administrators with an accurate tool for auditing their Apple content caching infrastructure.