Post not yet marked as solved
12-17-2021 Xcode Version 13.2 (13C90) MBP 13-inch,i7, 2017, macOS 11.6.1
I honestly can't believe how after all this years the bug is still there. It is extremely anoying to have to restart Xcode everytime I want to test something in playgrounds
Quinn, as you said, for apps as big as XCode this can be very slow. I understand I can cache the result but if I am doing this in the context of an ES_EVENT_TYPE_AUTH_EXEC I would be blocking the first execution of Xcode for a long time before my analysis finishes. What would you do in my case?
Turns out I was setting the exportedInterface instead of the remoteObjectInterface on the NSXPCConnection.
Post not yet marked as solved
Another question I had about the willCompleteAfterReboot is why is this called? I want to better understand this problem I am having about extensions needing a reboot to complete an upgrade. What is preventing the system from starting my extension without the need of a reboot?
I am using a Network Extension, if I were to add Endpoint Security to my extension would something in the activation process change? I can't see antivirus software that uses this framework requiring a reboot for every update to their extension.
Would this work? Just accessing the NEAppProxyFlow and returning true without having to handle the flow
// NEDNSProxyProvider
override func handleNewFlow(_ flow: NEAppProxyFlow) -> Bool {
NSLog("DNSProxyProvider: handleFlow")
if let tcpFlow = flow as? NEAppProxyTCPFlow {
let remoteHost = (tcpFlow.remoteEndpoint as! NWHostEndpoint).hostname
let remotePort = (tcpFlow.remoteEndpoint as! NWHostEndpoint).port
// Do whatever I want with this data
} else if let udpFlow = flow as? NEAppProxyUDPFlow {
let localHost = (udpFlow.localEndpoint as! NWHostEndpoint).hostname
let localPort = (udpFlow.localEndpoint as! NWHostEndpoint).port
// Do whatever I want with this data
}
return true
}
Ok so here is what I came up with. This works fine, the only thing I have yet to see is if it has any memory leaks. I hope this helps someone in the future :) If you have any suggestions to the func please let me know.
Also, you should first convert the audit_token to pid using the function mentioned above.
func getArgs(from pid: Int32) -> [NSString]? {
var arguments: [NSString] = []
var mib: [Int32] = [0, 0, 0]
var argsMax: Int = 0
mib[0] = CTL_KERN
mib[1] = KERN_ARGMAX
var size = MemoryLayout<Int>.stride(ofValue: argsMax)
if sysctl(&mib, 2, &argsMax, &size, nil, 0) == -1 {
return nil
}
let processArgs = UnsafeMutablePointer<CChar>.allocate(capacity: argsMax)
mib[0] = CTL_KERN
mib[1] = KERN_PROCARGS2
mib[2] = pid
size = argsMax as size_t
// Get process arguments
if sysctl(&mib, 3, processArgs, &size, nil, 0) == -1 {
return nil
}
if size <= MemoryLayout<Int>.size {
return nil
}
var numberOfArgs: Int32 = 0
//Get number of args
memcpy(&numberOfArgs, processArgs, MemoryLayout.size(ofValue: numberOfArgs))
// Initialize the pointer to the start of args
var parser: UnsafeMutablePointer<CChar> = processArgs + MemoryLayout.size(ofValue: numberOfArgs)
// Iterate until NULL terminated path
while parser < &processArgs[size] {
if 0x0 == parser.pointee {
// arrived ar argv[0]
break
}
parser += 1
}
// sanity check
if parser == &processArgs[size] {
return nil
}
while parser < &processArgs[size] {
if 0x0 != parser.pointee {
break
}
parser += 1
}
// sanity check
if parser == &processArgs[size] {
return nil
}
var argStart: UnsafeMutablePointer<CChar>? = parser
// Get all args
while parser < &processArgs[size] {
if parser.pointee == CChar(0) {
if nil != argStart {
let argument = NSString(utf8String: argStart!)
if argument != nil {
arguments.append(argument!)
}
}
argStart = parser + 1
if arguments.count == numberOfArgs {
break
}
}
parser += 1
}
// Is this free necessary?
free(processArgs)
return arguments
}
Yes, I can get the remoteEndpoint populated
guard let socketFlow = flow as? NEFilterSocketFlow,
let remoteEndpoint = socketFlow.remoteEndpoint as? NWHostEndpoint,
let localEndpoint = socketFlow.localEndpoint as? NWHostEndpoint else {
return nil
}
if #available(macOS 11.0, *) {
if let hostname = socketFlow.remoteHostname {
// Access hostname
}
}
Post not yet marked as solved
Thanks for the help!
Lastly, do you guys have a sample project using NETransparentProxyProvider because I could not find a single repo on github using this api.
Post not yet marked as solved
create your outbound copier, and then open the flow with your inbound copier.
So no matter the direction of the flow (inbound/outbound) I need to use both inboundCopier and outboundCopier correct?
Post not yet marked as solved
Im having trouble understanding how this transparent proxy would work.
Given that i only want to modify the headers of this requests flowing through my proxy and not re-route them i should return false in handleNewFlow ?
Im trying to follow the link you provided but i can't seem to grasp how this works.
let flow: NEAppProxyTCPFlow
let connection: NWConnection
// Reads from the flow and writes to the remote connection.
func outboundCopier() {
flow.readData { (data, error) in
if error == nil, let readData = data, !readData.isEmpty {
connection.send(content: readData,
completion: .contentProcessed( { connectionError in
// Handle completion success or error.
// Set up another read if there is no error.
if connectionError == nil {
self.outboundCopier()
}
}))
} else {
// Handle error case or the read that contains empty data.
}
}
}
Where should i create that NWConnection? Should i initialize one with the endpoint data contained in the flow i receive? Also I asume the headers i want are contained in the data from readData but how can interpret this data and modify it?
Post not yet marked as solved
There is nothing technically stopping you from doing this
Great! Given that i don't want to redirect the flow and only modify the headers i think NETransparentProxyProvider might be the better option for me.
however this will be something that you need to research on your own
I didn't find any information on how to do this. Do you know if there is a function from the NETransparentProxyProvider that can give me access to the headers?
Thanks for the help btw :)