iOS Code Snippet Resolve host to ip address (IPv4)

Add to B4XMainPage or any other module, at the end:
B4X:
#if OBJC
@end
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
@interface AddressForHost : NSObject
@end
@implementation AddressForHost


- (NSString *)ipv4AddressForHost:(NSString *)hostName {
    struct addrinfo hints, *res = NULL;
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_INET; 
    hints.ai_socktype = SOCK_STREAM;

    int err = getaddrinfo([hostName UTF8String], NULL, &hints, &res);
    if (err != 0) {
        NSLog(@"getaddrinfo error: %s", gai_strerror(err));
        return nil;
    }

    char ip[INET_ADDRSTRLEN];
    struct sockaddr_in *ipv4 = (struct sockaddr_in *)res->ai_addr;
    inet_ntop(AF_INET, &(ipv4->sin_addr), ip, sizeof(ip));
    freeaddrinfo(res);

    return [NSString stringWithUTF8String:ip];
}
#End If

Usage example:
B4X:
Private Sub Button1_Click
    Dim no As NativeObject
    no = no.Initialize("AddressForHost").RunMethod("new", Null)
    Dim ip As String = no.RunMethod("ipv4AddressForHost:", Array("google.com")).AsString
    Log(ip)
End Sub
 

BanditMrP

Member
Licensed User
Thanks

I've added that code, and will be able to test on Tuesday (Monday is a bank holiday in the UK).

I've also added an xui.msgboxasync to show the info.

It's a bit of a pain only being able to do this when on-site, but that's the only place it doesn't work!
 

BanditMrP

Member
Licensed User
Out of interest, I've added to the code as shown in the snippet below. The code compiles and can be called. If I was in an IPv6 environment, would this show the resolved address if it was resolved as an IPv6 address?

B4X:
#if OBJC
@end
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
@interface AddressForHost : NSObject
@end
@implementation AddressForHost


- (NSString *)ipv4AddressForHost:(NSString *)hostName {
    struct addrinfo hints, *res = NULL;
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;

    int err = getaddrinfo([hostName UTF8String], NULL, &hints, &res);
    if (err != 0) {
        NSLog(@"getaddrinfo error: %s", gai_strerror(err));
        return nil;
    }

    char ip[INET_ADDRSTRLEN];
    struct sockaddr_in *ipv4 = (struct sockaddr_in *)res->ai_addr;
    inet_ntop(AF_INET, &(ipv4->sin_addr), ip, sizeof(ip));
    freeaddrinfo(res);

    return [NSString stringWithUTF8String:ip];
}
@end

@interface Address6ForHost : NSObject
@end
@implementation Address6ForHost

- (NSString *)ipv6AddressForHost:(NSString *)hostName {
    struct addrinfo hints, *res = NULL;
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;

    int err = getaddrinfo([hostName UTF8String], NULL, &hints, &res);
    if (err != 0) {
        NSLog(@"getaddrinfo error: %s", gai_strerror(err));
        return nil;
    }

    char ip[INET_ADDRSTRLEN];
    struct sockaddr_in *ipv6 = (struct sockaddr_in *)res->ai_addr;
    inet_ntop(AF_INET, &(ipv6->sin_addr), ip, sizeof(ip));
    freeaddrinfo(res);

    return [NSString stringWithUTF8String:ip];
}
#End If

I've added the following to call the second implementation

Experimental:
Dim no As NativeObject
no = no.Initialize("Address6ForHost").RunMethod("new", Null)
Dim ip6 As String = no.RunMethod("ipv6AddressForHost:", Array("redacted.co.uk")).AsString
Log("IPv6: " & ip6)
 
Last edited:

BanditMrP

Member
Licensed User
The difference is in the second half where I’m hoping to retrieve the IPv6 address instead of the IPv4 address

these lines
IPv6?:
struct sockaddr_in *ipv6 = (struct sockaddr_in *)res->ai_addr;
    inet_ntop(AF_INET, &(ipv6->sin_addr), ip, sizeof(ip));

pure guesswork on my part, but trying to cover all possible reasons why this isn’t resolving internally, or where it is resolving to (in-app).

If its not doing what I wanted, is there a way to see the resolved IPv6 (if any)?
 

BanditMrP

Member
Licensed User
OK, I've changed the variables, and I can now see if the IPv6 address is resolved.

Many thanks. Roll on Tuesday when I'm on site again (the only place this app doesn't work) so I can see what's going on!
 

BanditMrP

Member
Licensed User
Hmmm... So the URL is resolving through DNS to the correct IP Address, and as expected, isn't resolving an IPv6 address.

So for a change, it's not DNS!

Time to look at why the server can be accessed from a B4X App on Android, and not from the same B4X App on Apple - It's not even triggering anything in the IIS logs.
 

BanditMrP

Member
Licensed User
I feel like a right idiot, but maybe this comment will help others.

In a B4X or B4i app:
  • we are able to resolve DNS addresses internally to a local DNS server
  • using a WebView we are able to load a "local" i.e. on the same LAN web site no issues (i.e. https://server01/index.html)
  • using iHttpUtils2 we are able to query a web service
UNLESS - When we first run the App, and it asks for "Allow <appname> to discover devices on the local network" we click "Do Not Allow".

At which point:
  • we are able to resolve DNS addresses internally to a local DNS server
  • using a WebView we are able to load a "local" i.e. on the same LAN web site no issues (i.e. https://server01/index.html)
  • using iHttpUtils2 we are NOT ABLE to query a web service (at least in my case!)
The solution to my ongoing problems with a B4X App not working when locally on-site sitting literally next to the server is that I habitually click "Do Not Allow" when asked if I want to allow an App to be able to find devices on the local network.

If ever there was time for a Homer Simpson "DOH!" this is it.

Thank you @Erel for your help with IP Address resolution etc., but the overall result is "It was me!" :oops:
 
Top