iOS Sandbox: deny(1) network-outbound*:<port #> from network extension


Code Block
if((sd = socket(PF_INET, SOCK_STREAM, 0)) < 1)
{
perror("Socket Creation");
//log_msg(LOG_ERR, "Socket creation failed");
return ERROR_SOCKET;
}
if ( connect(sd, addr, sizeof(addr)) == 0 )
{
conn_success = 1;
break;
}
else
{
log_msg(LOG_ERR, "errno = %d, %s", errno, strerror(errno));
}

The above chunk of C code is used to open TCP sockets on public and private servers on many platforms including Android and Mac OS. On iOS, it works if the device, an XR running 14.4.2, has an internal IP address when connecting to a public server. However, if the XR has a public IP address as it does when not connected to wifi, it fails with this in the log calling the same public server (or any public server) and errno = 1, Operation not permitted:

Sandbox: <extension name>(5616) deny(1) network-outbound*:<port no>

Why does the network extension, a packet tunnel provider, connect to a public server when the device has a private IP address and denied network outbound access when it has a public IP address?
Update.

I popped the sim card from the XR into a 5s running 12.5.2, and it worked like expected - the packet tunnel provider can open a tcp socket when it only has a public ip address.

Did something happen between 12.5.2 and 14.4.2 to break this or is it no longer permitted to open tcp sockets from packet tunnel providers from devices with public addresses?

Did something happen between 12.5.2 and 14.4.2 to break this or is it no longer permitted to open tcp sockets from packet tunnel providers from devices with public addresses?

Since you popped the sim card into the phone and it worked is your connection going over cellular and outside of tunnel? Have you also tried this with NWConnection, or nw_connection_t to see if it makes a difference?



Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
Hi Matt,

Since you popped the sim card into the phone and it worked is your connection going over cellular and outside of tunnel?

Yes it is. This is with wifi disabled and the phones having a public ip address. Same thing happens if wifi is enabled, but not connected to a network and the phones having a public ip address. The phone with 12.5.2 can make a TCP connection from the extension with the public ip address, and the phone with 14.4 fails with the above mentioned sandbox message, which comes from the kernel process.

Have you also tried this with NWConnection, or nw_connection_t to see if it makes a difference?

The app has to run on devices running < ios 12. That said, I tried it on the XR with the sim and wifi disabled, and the NWConnection did get a 'ready' state update. So it looks like NWConnections can get out.

This leads me to ask if you can find out or what I have to do to find out:

1) When did this stop working? I have an XR running 14.4.2, and 5s maxed out at 12.5.2. Since I can't figure this out on the simulator, being a network extension, I have no way to find out the ios version to put in ifdefs.

2) Is this by design? It seems rather arbitrary to allow outside tcp connections on 14.4 only using NWConnection when the device has a public ip address.

Is this by design?

No, NWConnection is just better equipped to handle these different network conditions than BSD sockets is. Especially between Wi-Fi and Cellular.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
Any possibility of finding out the version of iOS that this stopped working? As I said, I have a 5s maxed at 12.5.2 and an XR at 14.4.2. Since network extensions can't run on simulators, I don't have a way find the breaking point myself on iOS 13.


Any possibility of finding out the version of iOS that this stopped working?

I do not think this is a case where there is a version that this functionality started/stopped working, rather like I mentioned, NWConnection is just better equipped to handle these different network conditions and scenarios than BSD sockets is.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
Hi Matt,

Please excuse me for being blunt and not accepting "I do not think this is a case where there is a version that this functionality started/stopped working" as a legitimate answer. This is code. Of course there is a reason it doesn't work in network extensions, but does work properly in the app outside of the network extension. Code in the kernel spits out

Code Block
Sandbox: <extension name>(5616) deny(1) network-outbound*:<port no>

and doesn't do that when the code runs in the app.

I have a rather large body of C code interfacing with OpenSSL, which uses sockets, that runs on most every Linux platform except network extensions on iOS versions >= 14.0 because connect() fails. I want to confirm that you are telling me that because Linux C connect fails on PacketTunnelProvider extensions on >= 14.0, and NWConnection (or nw_connection_t) appears to be the only way to open a TCP connection in this environment, and you can't get a socket descriptor out of a NWConnection, the whole body of C code has to be rewritten in Objective-C or Swift because NWConnection is "better equipped".

Considering most of Secure Transport is deprecated, what Apple frameworks can be used with NWConnection to do the heavy lifting OpenSSL does in this situation?

Or, what legitimate excuse could I use for an entitlement to allow background processing in the app: the code doesn't work as it should in the network extension?

I want to confirm that you are telling me that because Linux C connect fails on PacketTunnelProvider extensions on >= 14.0, and NWConnection (or nw_connection_t) appears to be the only way to open a TCP connection in this environment, and you can't get a socket descriptor out of a NWConnection, the whole body of C code has to be rewritten in Objective-C or Swift because NWConnection is "better equipped".

What I'm telling you is for almost all cases it is recommended to stay away from BSD sockets and use a modern network API for a TCP connection like NWConnection or nw_connection_t. If you have a large body of C code you can use the C interface for nw_connection_t.

Considering most of Secure Transport is deprecated, what Apple frameworks can be used with NWConnection to do the heavy lifting OpenSSL does in this situation?

You will want to start with the TLS Options that are provided here.

Or, what legitimate excuse could I use for an entitlement to allow background processing in the app: the code doesn't work as it should in the network extension?

A network extension should always be running and should not need any kind of background processing entitlement. Is your tunnel failing?


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
No, the tunnel is not failing. As I said when I started this thread:

The above chunk of C code is used to open TCP sockets on public and private servers on many platforms including Android and Mac OS. On iOS, it works if the device, an XR running 14.4.2, has an internal IP address when connecting to a public server. However, if the XR has a public IP address as it does when not connected to wifi, it fails with this in the log calling the same public server (or any public server) and errno = 1, Operation not permitted.

When the extension is started, the vpn becomes ready, and the above chunk of code sets up encryption with a server by first making a tcp connection to it and sending an encrypted packet through that connection that identifies the client and then sets up OpenSSL. Then control information and output from the vpn goes through that interface.

The problem is when the device is running iOS 14+ and has a public ip address, meaning either wifi is disabled or it's not connected to wifi, the connect() for the tcp connection fails with:

Code Block
Sandbox: <extension name>(<process #>) deny(1) network-outbound*:<port no>

The deny(1) means errno == 1.

I know that this is not a problem with extensions on iOS 12.5.2, and I also made sure that connect() worked from the app. So the situation is that a basic connect() fails in network extensions on iOS 14+, but works outside of extensions on 14+ and works inside and outside of extensions on 12.5.2 (and I'll assume earlier versions).

I see no other reason for connect() to fail in this single situation unless it is a bug/regression or a lack of documentation that says that BSD sockets are no longer supported in network extensions running iOS 14+ on devices with public ip addresses, which makes C next to useless. Saying that NWConnection is "better equipped" doesn't explain why the industry standard connect() fails after working on earlier releases. And without an OpenSSL implementation for it, it is only "better equipped" for relatively simple stuff.

It would be acceptable if I could get a socket descriptor out of a NWConnection, but that is not possible. Since connect() works in the app, I might be able to make it work if the app can do background processing, but this is not an acceptable use of background processing from what I can tell.

Then control information and output from the vpn goes through that interface.

It sounds like you are using the NEPacketTunnelProvider classes, but I did just want to confirm that you are setting up your tunnel with the standard infrastructure for NEPacketTunnelNetworkSettings and NEPacketTunnelFlow etc, correct?

Also, one option I forgot to mention is the in-provider networking class that is similar to nw_connection_t, NWTCPConnection and NWUDPSession.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com

It sounds like you are using the NEPacketTunnelProvider classes, but I did just want to confirm that you are setting up your tunnel with the standard infrastructure for NEPacketTunnelNetworkSettings and NEPacketTunnelFlow etc, correct? 

Correct. Stuff works in every other situation.

Also, one option I forgot to mention is the in-provider networking class that is similar to nw_connection_t, NWTCPConnection and NWUDPSession.

What is that option? Would it lead to me being able to get a socket descriptor?

And why doesn't connect() work in this single situation? I still say this is either a bug/regression, or there has to be some official statement in documentation somewhere that says that BSD sockets no longer work in network extensions running iOS 14+ when the device has a public ip address.


Would it lead to me being able to get a socket descriptor?

Not that I'm aware of. I mention this as another alternative to using sockets and if you are in-need of an in-provider network class for sending traffic through the tunnel.

And why doesn't connect() work in this single situation? I still say this is either a bug/regression

If you feel that you have hit a bug or regression please open a bug report.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
iOS Sandbox: deny(1) network-outbound*:&lt;port #&gt; from network extension
 
 
Q