First, for the employees reading, I filed FB14844573 over the weekend, because this is a reproducible panic or hang. whee
I ran our stress tests for an entire long weekend, and my machine panicked, due to mbufs. Normally, I tell my coworkers that we can't really do anything to cause a panic -- but we're doing network things, so this is an exception. I started periodically testing the mbufs while the tests were running -- netstat -m | grep 'mbufs in use' -- and noticed that in fact they were going up, and never decreasing. Even if I killed our code and uninstalled the extensions. (They're increasing at about ~4mbufs/sec.)
Today I confirmed that this only happens if we include UDP packets:
let udpRule = NENetworkRule(destinationNetwork: host, prefix: 0, protocol: .UDP)
let tcpRule = NENetworkRule(destinationNetwork: host, prefix: 0, protocol: .TCP)
...
settings.includedNetworkRules = [udpRule, tcpRule]
If I comment out that udpRule, part, mbufs don't leak.
Our handleNewUDPFlow(:, initialRemoteEndpoint:) method checks to see if the application is a friendly one, and if so it returns false. If it isn't friendly, we want to block QUIC packets:
if let host = endpoint as? NWHostEndpoint {
if host.port == "80" || host.port == "443" {
// We need to open it and then close it
flow.open(withLocalEndpoint: nil) { error in
Self.workQueue.asyncAfter(deadline: .now() + 0.01) {
let err = error ?? POSIXError(POSIXErrorCode.ECONNABORTED)
flow.closeReadWithError(err)
flow.closeWriteWithError(err)
}
}
return true
}
}
return false
Has anyone else run into this? I can't see that it's my problem at that point, since the only thing we do with UDP flows is to either say "we don't want it, you handle it" or "ok sure, we'll take it but then let's close it immediately".
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
The archive build part works, and uses the correct entitlements file:
[Key] com.apple.developer.networking.networkextension
[Value]
[Array]
[String] app-proxy-provider-systemextension
That's from codesign -dv --entitlements - ...../NetworkExtensionExperiment.app
However, the distribution log shows
"Error Domain=DVTPortalProfileErrorDomain Code=4 \"Cannot create a Developer ID provisioning profile for \"com.kithrup.NetworkExtensionExperiment\".\" UserInfo={NSLocalizedDescription=Cannot create a Developer ID provisioning profile for \"com.kithrup.NetworkExtensionExperiment\"., IDEDistributionIssueSeverity=3, NSLocalizedRecoverySuggestion=The Network Extensions capability is not available for Developer ID provisioning profiles. Disable this feature and try again., NSUnderlyingError=0x600013e719b0 {Error Domain=DVTPortalProfileTypeErrorDomain Code=0 \"Cannot create a Developer ID provisioning profile.\" UserInfo={UnsupportedFeatureNames=(\n \"Network Extensions\"\n), NSLocalizedDescription=Cannot create a Developer ID provisioning profile., NSLocalizedRecoverySuggestion=The Network Extensions capability is not available for Developer ID provisioning profiles. Disable this feature and try again.}}}",
"Error Domain=IDEProfileLocatorErrorDomain Code=1 \"No profiles for 'com.kithrup.NetworkExtensionExperiment' were found\" UserInfo={IDEDistributionIssueSeverity=3, NSLocalizedDescription=No profiles for 'com.kithrup.NetworkExtensionExperiment' were found, NSLocalizedRecoverySuggestion=Xcode couldn't find any Developer ID provisioning profiles matching 'com.kithrup.NetworkExtensionExperiment'.}"
which, given that I was able to build a signed version with the entitlement as shown first, seems to be a problem.
All my years of hating xcode are coming back to haunt me, I can tell.
There's the NSWorkspaceSessionDidBecomeActiveNotification et al, but that doesn't say who the current user is. Is there a way to find out that? (I mean, I could have a LaunchAgent that send "I've become active!" log message or something, and then use the most recent one. Is there another way?)
As I asked earlier, I was trying to figure out who the current user is. Since the proposed solution doesn't work, I thought, okay, let's try sending notifications from a LaunchAgent! Only, right, notifications are per-process, so I tried Distributed Notifications... and that doesn't seem to work across users. (Now, since I log while also sending the distributed notifications, I can see that it is working the way I want. Except that willPowerOffNotification doesn't actually seem to happen with a logout. Maybe that's because it's a CLI program? But the other notifications do work...)
We're using CMake here, so we can build on Windows, Linux, and macOS. So now I'm trying to convert from Xcode to CMake (which then generates an xcode project, whee).
The main problems I'm running into are figuring out which settings to do via CMakeLists.txt. That's mostly tiresome. But theres a new issue, and I don't know enough about CMake to figure it out: compiling my .swift file generates a ${PROJECT}-Swift.h file, which is used by the ObjC files. Which is great.
Except I don't know how to tell CMake about that. (And I haven't figured out what variable describes where Xcode puts it, but that's more of a tiresome issue than head-against-desk issue...)
Has anyone run into and hopefully figured this out?
Just to make sure I'm not once again doing something dumb or stupid: this notification only gets sent to the application that loads & starts the VPN? If I want some other process to be aware of it, I have to use the SC* APIs?
In a deamon, I register using:
[[NSDistributedNotificationCenter defaultCenter] addObserver:loader
selector:@selector(getNotifications:)
name:kProxyStartNotification
object:@"MyProxy"];
In the transparent proxy provider, I post using:
static let dnc = DistributedNotificationCenter.default()
// later
Self.dnc.postNotificationName(.proxyStart,
object:"MyProxy",
deliverImmediately:true)
(I also tried putting the same observer code in the containing app, just to be sure.)
(Also, btw: the automatic conversion of kProxyStartNotification to Notification.Name.proxyStart is really sweet.)
I'm not getting the notification in other processes. I tried putting an observer in the extension, and sure enough that did get the notification, so it is being generated. Just... not leaving my process.
I tried checking for sandbox violations, using Quinn's instructions, but see nothing.
I also tried
[[NSDistributedNotificationCenter defaultCenter] addObserver:loader
selector:@selector(getNotifications:)
name:nil
object:@"MyProxy"];
(and the same in Swift, for the network extension), and -- as can be guessed by my still asking this question -- no luck.
This specifically seems to happen when my network extension is spawned by launchd, but has not actually been connected. (That is my conclusion based on the evidence: ps shows the process existing, but the logs show that main() hasn't run yet, let alone the proxy provider's init(). Without being able to debug launchd, I would say the situation is that launchd has said "yes this XPC port exists, when you try to connect to it I will send it on over to the extension, and thereafter you two will happily communicate directly," but the process hasn't gotten around to accepting XPC connections.) This seems to be most likely to happen when the extension crashes, or I kill -9 it to see how it handles respawning.
I have a little CLI tool that talks (over XPC, of course) to the extension, mainly to say "Hi are you alive?" If the extension is not loaded, the XPC connection fails, as expected, and my tool says "NOT YET." If it is loaded and running, the XPC connection succeeds, as expected, and I get back a response of true.
So my first question is: is this expected behaviour?
My second question is: is there a way to do an XPC connection with a timeout?
A bad time to ask, I'm sure, since everyone is busy with WWDC.
What is the difference between filterSockets and filterPackets? In terms of code and classes, I mean. (For my very simple test, if I set filterSockets to true, it just doesn't seem to work.)
Related to that: with filterPackets set to true, what data is NEFilterPacketProvider.packetHandler getting? It looks like a subset of an ethernet packet on my system (which, in fact, does have wired ethernet!). But it's missing some of the wire bits (the preamble and SFP), and the length is wrong. (Eg., the handler is given bytes of length 1514, but the ethernet length field is 1500 -- but there are 16 bytes before the length field, plus the two bytes of the length/type.) I suppose it's possible it's not an ethernet packet, but it certainly looks like one, just... slightly wrong.
This is somewhat to my question at On reboot, two instances of faceless app - but slightly different focus.
This is my understanding of how the system works, and please correct me if I'm wrong:
A network extension can only be loaded by an application
That application must contain the extension (in Contents/Library/SystemExtensions)
Only the application instance that loads an extension can get VPN notifications (eg, NEVPNStatusDidChangeNotification)
There does not appear to be a way to get the version of installed network extensions programmatically?
When a second user logs in, and runs the containing app, and requests loading the extension, it does the normal replacement request.
Given that... how is it supposed to handle multiple users (via Fast User Switching)?
In order to set up an asynchronous query looking for a specific application, I have a predicate of:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K LIKE[cd] %@ AND %K = %@",
@"kMDItemDisplayName", name,
@"kMDItemContentType", UTTypeApplicationBundle.identifier];
I tested it with standalone code, and this did what I wanted -- finding applications with the given name. But recently, it seems to have stopped working.
That query should be the equivalent of
mdfind 'kMDItemDisplayName LIKE[cd] "Safari" AND kMDItemContentType == "com.apple.application-bundle"'
but that gives me
Failed to create query for 'kMDItemDisplayName LIKE[cd] "Safari" AND kMDItemContentType == "com.apple.application-bundle"'.
If I drop the compound, and just do
% mdfind 'kMDItemDisplayName LIKE[cd] "Safari"'
then I get no output:
% mdfind 'kMDItemDisplayName LIKE[cd] "Safari"'
%
And yet clearly I do have Safari installed on my system.
What am I doing wrong, or missing? Anyone?
I don't have enough physical machines to install Sonoma; I do, however, have lots of CPU cycles, memory, and disk space -- so can I get Sonoma running in VMWare Fusion? Ideally on both AS and Intel.
I searched to see if this had been asked, but I will be the first to admit my searching skills are bad. (This is why I like find and grep.)
The crash is at
do {
retval = try ModelContainer(for: schema, configurations: [modelConfiguration])
} catch {
fatalError("Could not create ModelContainer: \(error)")
}
When I first set it up, it complained (at run-time) about a lot of issues, mainly items not being optional and I apparently had a couple of @Attribute(.unique)s left. After I got rid of all of those, however, I get the crash there.
I assume this is an obvious thing that I am doing wrong, but I can't figure it out.
I've got a core data model, with a name, which I've cleverly called cdName. My view has:
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(sortDescriptors: [
SortDescriptor(\Item.cdName),
])
private var items: FetchedResults<Item>
and then, later
ForEach(self.items, id: \.self) { item in
NavigationLink {
ItemView(item: item)
.environment(\.managedObjectContext, self.viewContext)
} label: {
LabelWithMenuView(label: item.cdName ?? "<no name>") { ptr in
if let newName = ptr {
let oldName = item.cdName!
item.cdName = newName
do {
try self.viewContext.save()
} catch {
print("Could not save rename of \(oldName) to \(newName)")
}
}
(LabelWithMenuView is a view that has an on-hover button which brings up a rename sheet and passes the new name off to the completion handler.)
When I do this (macOS)... it does change the name in Core Data, but it doesn't update the view. If I quit&restart my app, it shows up with the new name.
What am I doing wrong, please?
Why doesn't this work? (Specifically, it crashes.)
struct Item: Identifiable, Hashable, Codable {
var id = UUID()
var name: String? = nil
}
private let defaults: [Item] = [
Item(name: "Bread"),
Item(),
Item(name: "Peanut Butter"),
Item(name: "Jelly")
]
struct ContentView: View {
@State var selectedItem = Set<Item>()
@State var showSheet = false
var body: some View {
VStack {
ForEach(defaults, id: \.self) { item in
Button(item.name ?? "<unnamed>") {
self.selectedItem.removeAll()
self.selectedItem.insert(item)
print("Selected item is now \(self.selectedItem)")
self.showSheet = true
}
}
}
.sheet(isPresented: self.$showSheet) {
let _ = print("selected item \(self.selectedItem)")
RenameSheet(name: self.selectedItem.first!.name ?? "<no name>") {
self.selectedItem.removeAll()
}
}
.padding()
}
}
Based on the output from the prints, it gets set when the button is clicked, but is then empty when the sheet is presented.