Sure, I will open a TSI next week. Meanwhile, continuing my investigation, I looked into console logs and I can see SSL3_RT_ALERT, description: close notify. Which means Mac client is receiving TLS close but is not closing the connection.
The screenshot for console log is available here: https://ibb.co/bXYrPT4
The server side calls SSL_shutdown which only closes the write direction from server side while keeping read side open.
SSL_shutdown() only closes the write direction. It is not possible to call SSL_write() after calling SSL_shutdown(). The read direction is closed by the peer.
So, as per the OpenSSL docs, server is doing right thing but NWConnection is not responding back with notify close, to finish the connection from both sides.
Post
Replies
Boosts
Views
Activity
Hi @eskimo,
After our discussion last evening, we did some deliberations and now we are able to get FIN from server to client. However, we still notice that NWConnection does not close the connection after receiving FIN and subsequent writes are being sent to server. Is there any reason NWConnection is not closing web-socket after receiving FIN and ACKing to the FIN?
Our server has separate management of read and write web sockets. They are sending FIN after closing their write socket while keeping their read socket open for a little while longer so that client can write any last message or send FIN and close.
Could there be any reason/configuration for NWConnection to not disconnect by writing client FIN after receiving server FIN? In Windows client, we see client side FIN after server FIN and then connection closes completely.
The packet capture screenshot with server FIN can be seen https://ibb.co/M6cLz85 since image upload here was failing.
Here is the code we use for reading data continuously on web socket. We only stop reading only when we encounter an error.
func listen() {
connection?.receiveMessage { [weak self] (data, context, _, error) in
guard let self = self else {
return
}
if let data = data, !data.isEmpty, let context = context {
self.receiveMessage(data: data, context: context)
}
if let error = error {
self.reportErrorOrDisconnection(error)
} else {
self.listen()
}
}
}
Sorry, I mistyped my previous post and did not notice it till now. Here is the right version:
I am not sure I completely understood what do you mean but let me try to answer that: I add an FQDN in searchDomains and then I try to access the same exact FQDN in browser. But the DNS queries for that FQDN are not sent to my PacketTunnel.
Is this what you are asking?
Are you handling this DNS query in your System Extension?
Within the SystemExtension, I am actually trying to connect to server FQDN using NWConnection(to: NWEndpoint.url(server_FQDN), using: parameters). So, I am expecting the FQDN to be resolved to IP from hosts file and connection being established. But that is not happening.
If you try to resolve the query in the context of the System Extension does this respect the hosts file?
I did not try resolving the host myself using something like getaddrinfo or CFHostStartInfoResolution. So, I am not sure about this behaviour.
Also, just FYI, I have split tunnel and a few matchDomains in my extension but they are very different from server FQDN I am using to connect to, in case this matters.
do you pickup the exact values in searchDomains?
I am not sure I completely understood what do you mean but let me try to answer that: I add an FQDN in searchDomains and then I try to access the same exact FQDN in browser. But the DNS queries for that FQDN are sent to my PacketTunnel.
Is this what you are asking?
Hi Matt, since I had never used searchDomains, I just did some testing and results are not what I expected.
I added few domains like google.com, amazon.com, www-google.com and www-amazon.com (- are dots here since www URLs are not allowed) into search domains, added nothing in matchDomains and matchDomainsNoSearch is set to true . So, I expected to get DNS queries for all the above exact domains in my NE. But that is not the case. I get no DNS queries at all.
If I add the same domains in matchDomains and nothing in searchDomains, I get all the exact as well as subdomain queries. Which is working as expected but is not something I need. I only need queries for exact domain names. So, how can that be achieved? I thought adding only to searchDomains would do that. But that is not the case.
Thanks for the response, Matt. We may have to change support from Big Sur and above to avoid conflict with KEXT based VPNs.
Last two queries:
Is there a way to create custom VPN tunnel or utun interface, from an app, apart from using NetworkExtension or KEXT, in macOS?
Is there a way to find out tunnel address, match domains and include routes of other VPN tunnels or utun interfaces created by other applications (kext or NE or any other way)? This may help us do some tricks with include routes and avoid route overlap. netstat -rn seems to be one way to get some of this information. Is there any better way?
Thanks for your response Matt.
Regarding
Is it possible to have one NEPacketTunnelProvider based VPN and one kext based VPN tunnel running at the same time? We are planning on supporting from macOS Catalina.
and
Is there a way to create custom VPN tunnel or utun interface, from an app, apart from suing NetworkExtension or kext, in macOS? Could that cause a route overlap or conflict with our NetworkExtension tunnel when running simultaneously?
We have no plans of using kext for our VPN tunnel. These questions are in context of our VPN using NetworkExtension and some other simultaneous VPN using kext. Since we can not control other VPN providers, we are trying to assess whether their kext based VPNs could be a challenge for our NetworkExtension base VPN tunnel.
Can you please answer these two questions with in this context as well as below question?
Assuming answer to second question is, yes, what would be the behaviour if there is include route overlap between our NEPacketTunnelProvider based VPN tunnel and other kext based VPN tunnel?
Thanks. Here is the feedback reported: FB9108985
Accepting you first reply as answer since it provides a very good solution.
I would expect name and PID to work equally well here, that is, they both work or they both don’t. That fact that’s not the case is weird.
Yep. Thats how it appears right now. If I go to Terminal or Activity Monitor and fetch the process ID of the running sysex, then Xcode attaches fine with PID. But if I use the name of the sysex, it just keeps on waiting to attach.
Try this…
Tried your suggestion and lldb provides the bundle identifier of the sysex as the candidate process. Copied and used the same to attach in Xcode and it still keeps on waiting to attach. Verified in Terminal (ps -ax | grep ***) as well as in Activity Monitor and they both provide bundle identifier itself as process name. lldb is able to attach with that name but Xcode is not. PID works fine in both cases.
Oh, and btw, if you want to debug from the start of your sysex, add a call to pause at the beginning of main. That’ll pause waiting for you to attach with the debugger (attaching delivers a signal which breaks you out of pause).
Thanks for this awesome suggestion. With this, I am able to get pid of the process in Terminal and use it to attach debugger in Xcode before any code is executed.
Thanks Matt. Here is the feedback ID: FB9108197
Thanks for the update Matt.
However, I received this issue with Packet Tunnel. Whenever includeAllNetworks is enabled, if PacketTunnelProvider tries to apply a split tunnel rule, the rule fails to apply (but no error returned) and packet tunnel receives all the traffic as if its full tunnel and wildcard match domain.
Now I understand that when includeAllNetworks is enabled, split tunnel rules conflict with this setting and should not be used. But there is no clear documentation or error when settings split tunnel rules. There is just a cryptic message in Console.app System Policy: deny(1) system-privilege 10006 which is easy to miss. It does not even specify the problem.
So, I think it would be nicer to have documentation mention this conflict and its impact. It would be even nicer to have NETunnelProvider.setTunnelNetworkSettings method return an error in its completion block when such conflicts take place.
I was also facing this issue (deny(1) system-privilege 10006) with PacketTunnel on macOS and includeAllNetworks was the culprit. Thanks to your answer, I was able to resolve the issue (only after wasting more than a day). Has there been any update on FB7468866 to fix this issue?
Thanks @eskimo. That clarifies it.