Ok, so there is a CREATE event when either a file or a directory is created. But there's no information as to what type of object is being / has been created, unless I missed something again. Also, there doesn't seem to be a CREATE event for symlinks.
Post
Replies
Boosts
Views
Activity
Ok. So there *is* an authorization event for creating filesystem objects, including directories and symlinks, and this includes the mode. However, and this confused me for quite a while, the create notification is only after the fact, so it will never indicate it's a new file, and the only way you can find out file information is to lstat/getattrinfo/etc. on the given path then.
It makes complete and utter sense, and is also completely and utterly annoying. :)
If I remove 'as? Hello', it gives me a value, but then I can't call the method on it. Note that I have connection.exportedInterface = NSXPCInterface(with: Hello.self) in there.
Ok, so I guess I can't make a command-line Mach server. So I'm trying just a minimal gui app that does essentially the same thing, and that's still not working. Perhaps I need a launchd.plist, rather than putting the MachServices dictionary in Info.plist? (And then I was trying my command-line client, as above.)
Oh! So I can't do my test with two programs, but I can do it with one, without having to use xcode or launchd? That'll work for playing-around purposes!
The real programs will be done in xcode, with either XPC Services, or with system extensions -- I'm simply trying to figure out why the bad code I have so far is bad, and (for me) that meant going back to basics with XPC.
Thank you! (Again. And hi again! It's been a very long time since I've seen you.)
My attempt at the comment didn't work with formatting.
Ok. I've got this code, and proxy still ends up as nil.
I'm still playing with it so hopefully I'll figure out on my own what I'm doing wrong.
import Foundation
class ConnectionHandler: NSObject, NSXPCListenerDelegate {
override init() {
super.init()
print("ConnectionHandler.init()")
}
func listener(_ listener: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool {
print("ConnectionHandler.listener()")
newConnection.resume()
return true
}
}
let handler = ConnectionHandler()
let listener = NSXPCListener.anonymous()
let endpoint = listener.endpoint
listener.delegate = handler
listener.resume()
@objc protocol Hello {
func hello()
}
class HelloClass: NSObject, Hello {
override init() {
super.init()
}
func hello() {
print("In HelloClass.hello()")
}
}
let hello = HelloClass()
let connection = NSXPCConnection(listenerEndpoint: endpoint)
connection.exportedInterface = NSXPCInterface(with: Hello.self)
print("Connection = \(connection)")
connection.resume()
let proxy = connection.remoteObjectProxyWithErrorHandler({ error in
print("Got error \(error)")
}) as? Hello
print("Proxy = \(proxy)")
dispatchMain()
Ok, progress! Yay! Not that I grok how it all works together yet, but I did make progress!
let connection = NSXPCConnection(listenerEndpoint: endpoint)
connection.exportedInterface = NSXPCInterface(with: Hello.self)
connection.exportedObject = hello
print("Connection = \(connection)")
connection.remoteObjectInterface = NSXPCInterface(with: Hello.self) // This is new!
connection.resume()
let proxy = connection.remoteObjectProxyWithErrorHandler({ error in
print("Got error \(error)")
}) as? Hello
gives me a valid proxy object, that I can do proxy?.hello() on. Not that it does anything yet but I am getting there!
And with a couple of smaller changes, it now does something. In particular, adding a goodbye object that conforms to Hello and says "goodbye" (I'm not very original here), and doing:
func listener(_ listener: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool {
print("ConnectionHandler.listener()")
newConnection.resume()
newConnection.exportedInterface = NSXPCInterface(with: Hello.self)
newConnection.exportedObject = goodbye // This is new!
return true
}
results in the "client" side being able to have "goodbye" printed.
Ahhhhhhhhhhhh.
(Apparently only answers get formatting, so this isn't an answer but here it goes anyway.)
My code is shamefully bad, of course. I can hopefully be forgiven due to the lack of sample code...
I have "class AppProxyProvider: NEAppProxyProvider" in the extension; however, it does not seem to load. Interestingly, I can see it in Network preferences -- but it says "Please use 'AppProxyTest' to control this content filter configuration." But then I'm back to not sure what I'm supposed to do...
This is the code I'm using to try to load it; there is a lot of extraneous code in there, I'm aware, as well as a lot of prints, because those continue to be my favourite method for tracing progress. I have os_log() calls in the extension, but as I said, it doesn't seem to get loaded.
private func loadExtension() {
guard let extensionIdentifier = extensionBundle.bundleIdentifier else {
print("Can't get the extension identifier")
return
}
NEAppProxyProviderManager.loadAllFromPreferences() { providers, error in
if let err = error {
print("Got provider manager error \(err.localizedDescription)")
} else {
print("providers = \(providers)")
}
}
let activationRequest = OSSystemExtensionRequest.activationRequest(forExtensionWithIdentifier: extensionIdentifier, queue: .main)
activationRequest.delegate = self
OSSystemExtensionManager.shared.submitRequest(activationRequest)
os_log("Bundle ID = %{public}@", activationRequest.identifier)
let filterManager = NEFilterManager.shared()
filterManager.loadFromPreferences { error in
if error != nil {
print("The first loadFromPreferences got error \(error)")
} else {
print("Was able to load filterManager preferences the first time")
}
}
if filterManager.providerConfiguration == nil {
let providerConfiguration = NEFilterProviderConfiguration()
providerConfiguration.filterSockets = false
providerConfiguration.filterPackets = true
filterManager.providerConfiguration = providerConfiguration
if let appName = Bundle.main.infoDictionary?["CFBundleName"] as? String {
filterManager.localizedDescription = appName
}
print("providerConfiguration = \(providerConfiguration)")
} else {
print("filterManager.providerconfiguration = \(filterManager.providerConfiguration)")
}
filterManager.isEnabled = true
filterManager.localizedDescription = "Test App Proxy Provider"
print("filterManager = \(filterManager)")
filterManager.saveToPreferences { saveError in
if saveError == nil {
return
}
if let error = saveError as NSError? {
print("Failed to save the filter configuration: \(error)")
}
}
filterManager.loadFromPreferences() { error in
if let err = error {
print("The second loadFromPreferences got error \(err.localizedDescription)")
}
}
}
Both v4 and v6, of course!
As I said, I can do it in ObjC pretty easily, I was just hopeful someone had already saved me a bit of work.
In some sense, this is a dumb question, since the AppProxyFlow is a bridge between endpoints, not an actual IP tunnel; however, this surprised me in the sense that if an app asks what the remote connection is, or asks for a specific address family, etc. But I’m guessing that the app proxy only works with the higher-level libraries, and not with the BSD layer?
Or of course I’m completely wrong!
But, essentially, it's not supposed to matter, right? As I just described it to someone, the App Proxy Provider turns the data transport from IP to itself (ok, it sounded better in my head before I said it). You could, I suppose, use it to implement some wildly-different transport scheme that did not involve any IP packets at all.
I just wanted to make sure I did understand it properly. 😄
No, it occurred to me in my sleep that it's behaving as if I told it to install a packet proxy and not an App Proxy. So I no doubt did something fairly wrong; I just need to figure out what that is. (If you have any common suggestions, that'd be great, otherwise I'll need to double check the entitlements, the Info.plists, the proxy setups for networks, how I am activating it, and how I am starting it.)
Ok, I got it working in its minimal fashion again (which is to say, at this point, handleNewProxy just logs each flow and then returns false). I had proto.includeAllNetworks = true and removed it. Yay.
However... a ping I have running fails whenever I have it connected. I can continue to load websites in Safari, so I didn't breakall networking this time.
Right, NEAppProxyProvider only supports TCP and UDP, so I was very surprised when the already-running ping was interrupted.
However, if I turned it into two rules:
let host = NWHostEndpoint(hostname: "", port: "0")
let udpRule = NENetworkRule(destinationNetwork: host, prefix: 0, protocol: .UDP)
let tcpRule = NENetworkRule(destinationNetwork: host, prefix: 0, protocol: .TCP)
settings.includedNetworkRules = [udpRule, tcpRule]
then the ping was unaffected. (Before I'd had one rule, with .any.)
The ping failure, btw, was sendto: No route to host.