iOS local HTTP server on a different loopback address

We are trying to create a local HTTP server on iOS that receives a redirect request from a remote server. The request is processed by the local server and an HTTP response is returned. The local server runs on a port 9078 and our requirement is bind the local server to the loopback address 127.50.100.1. But when trying to bind the server to an address other than 127.0.0.1, it isn't working as expected and it throws an error something like address can't be used. Is there any way that we could bind the local server to a loopback address that's other than localhost / 127.0.0.1?

We tried working with different HTTP server libraries like Vapor, CocoaHTTP, SwiftNIO, GCD Webserver and none of them seem to support this behavior. Any leads on this would be very helpful. TIA!

Answered by DTS Engineer in 744969022

the application server will always redirect to this loopback address

I hate to be the bearer of bad news but you’re going to have to change that code. Consider this snippet:

int sock = socket(AF_INET, SOCK_STREAM, 0);
assert(sock >= 0);

struct sockaddr_in addr = {};
addr.sin_len = sizeof(addr);
addr.sin_family = AF_INET;
addr.sin_port = htons(12345);
addr.sin_addr.s_addr = htonl(0x7f000001);

NSLog(@"will bind");
BOOL success = bind(sock, (const struct sockaddr *) &addr, sizeof(addr)) >= 0;
if (success) {
    NSLog(@"did bind");
} else {
    NSLog(@"did not bind, error: %d", errno);
}

success = close(sock) >= 0;
assert(success);

It prints [1]:

will bind
did bind

If you change the 0x7f000001 to 0x7f000002, so you’re binding to 127.0.0.2, it prints:

will bind
did not bind, error: 49

where 49 is EADDRNOTAVAIL.

iOS simply does not support this.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] I’m testing on iOS 16.3.1 but I believe that this isn’t new behaviour.

It kind of seems like you are describing virtual hosts here and this should work fine on a Mac with Apache.

i haven’t really played with any of the servers you mentioned; but, if you want to add another local host address you should try what Linux does for IPv6 addresses in the /etc/hosts file.. and the way they do that is by creating multiple localhosts in that file, each on their own line..

hope this helps, please submit more info if you come across any issues.

But when trying to bind the server to an address other than 127.0.0.1, it isn't working as expected

I’m not surprised by this. Binding to a non-standard localhost address puts you far off the well-trodden path.

Why are you trying to do that? What’s wrong with 127.0.0.1?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thanks Quinn, for the response.

Unfortunately, this iOS app is the client for an enterprise application and the enterprise application in tightly bound to this IP. Tightly bound in the sense, the application server will always redirect to this loopback address 127.50.100.1 and making changes to the application server to redirect to 127.0.0.1 is something not possible. There are other (desktop) clients that work well with this specific loopback and changing that behavior on the application server will have regression impacts on existing clients.

So we don't see a solution rather than binding the HTTP server to this non-standard localhost address. Would appreciate if there is any other viable solution for this to work, something through Network Extension or different options.

Accepted Answer

the application server will always redirect to this loopback address

I hate to be the bearer of bad news but you’re going to have to change that code. Consider this snippet:

int sock = socket(AF_INET, SOCK_STREAM, 0);
assert(sock >= 0);

struct sockaddr_in addr = {};
addr.sin_len = sizeof(addr);
addr.sin_family = AF_INET;
addr.sin_port = htons(12345);
addr.sin_addr.s_addr = htonl(0x7f000001);

NSLog(@"will bind");
BOOL success = bind(sock, (const struct sockaddr *) &addr, sizeof(addr)) >= 0;
if (success) {
    NSLog(@"did bind");
} else {
    NSLog(@"did not bind, error: %d", errno);
}

success = close(sock) >= 0;
assert(success);

It prints [1]:

will bind
did bind

If you change the 0x7f000001 to 0x7f000002, so you’re binding to 127.0.0.2, it prints:

will bind
did not bind, error: 49

where 49 is EADDRNOTAVAIL.

iOS simply does not support this.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] I’m testing on iOS 16.3.1 but I believe that this isn’t new behaviour.

Thanks much Quinn for the response and also the piece of code that it doesn't work in that way. Though it is unfortunate, I believe we might have to resort to a different option.

Does your app include this web server and a webview in the same process?

If it does, you can hack the webview to change 127.50.100.1 to 127.0.0.1. There is a delegate method that is called when the server sends a redirect. (IIRC) Then you don’t need to update your corporate server.

iOS local HTTP server on a different loopback address
 
 
Q