how to resolve the hostname of a device in my LAN from its ip address on this LAN? - ios

I have to resolve the hostname of a device in my LAN from its ip address on this LAN.
I have some code that works for external ip address but not the internally connected devices .
Below i have attached the code .
if you have any idea to get hostname of remote machine from it's IP in iOS/OSX, it'll make my day.
int error;
struct addrinfo *results = NULL;
error = getaddrinfo("173.194.34.24", NULL, NULL, &results);
if (error != 0)
{
NSLog (#"Could not get any info for the address");
}
for (struct addrinfo *r = results; r; r = r->ai_next)
{
char hostname[NI_MAXHOST] = {0};
error = getnameinfo(r->ai_addr, r->ai_addrlen, hostname, sizeof hostname, NULL, 0 , 0);
if (error != 0)
{
continue; // try next one
}
else
{
NSLog (#"Found hostname: %s", hostname);
break;
}
}
freeaddrinfo(results);
or with NSHost
NSLog(#"%# \n%#",[NSHost currentHost],[[NSHost hostWithAddress:#"172.17.241.61"] names]);

Only way to make a DNS lookup directly to a specific DNS is to implement the protocol yourself or use some library.
https://serverfault.com/questions/173187/what-does-a-dns-request-look-like
https://www.ietf.org/rfc/rfc1035.txt
https://github.com/adeboer/rfc1035lib

Related

How to select which network interface to use in a ESP32

I'm currently using a Esp32 which presents, in addition to wifi, an ethernet interface.
I'm using the esp-idf v3.3 with FreeRTOS.
To use it I included the "esp_eth.h" library (https://docs.espressif.com/projects/esp-idf/en/release-v3.1/api-reference/ethernet/esp_eth.html#api-reference-phy-lan8720).
I'd like to use both Wifi and ethernet interfaces basing on what I want to do but selecting which one to use, is there a way?
The practical use is to receive a command through the ethernet interface (for example a site to ping), ping the server through the wifi interface and answer back to the ethernet interface the ping result.
How can I select which interface to use (i dont want that the ping is made through the ethernet or that the response go through the wifi).
#edit: i found the method netif_set_default(struct netif * netif), but i dont know if it is the best way to select the interface to use for the specific action(i should swap from one interface to another)
Just get the IP of the Ethernet interface, then bind a socket to that IP address.
struct in_addr iaddr = {0};
#if USE_ANY_IF
// Bind the socket to any address
iaddr.s_addr = htonl(INADDR_ANY);
#else
// bind only to the Ethernet interface
tcpip_adapter_ip_info_t ip_info = {0};
tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_ETH, &ip_info);
inet_addr_from_ip4addr(&iaddr, &ip_info.ip);
#endif
Then use it to bind a socket, for example:
static int create_multicast_ipv4_socket(struct in_addr bind_iaddr)
{
struct sockaddr_in saddr = {0};
int sock = -1;
int err = 0;
char addrbuf[32] = {0};
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
if (sock < 0)
{
ESP_LOGE(V4TAG, "Failed to create socket. Error %d", errno);
return -1;
}
saddr.sin_addr.s_addr = bind_iaddr.s_addr; // what interface IP to bind to. Can be htonl(INADDR_ANY)
saddr.sin_family = PF_INET;
saddr.sin_port = htons(UDP_PORT);
inet_ntoa_r(saddr.sin_addr.s_addr, addrbuf, sizeof(addrbuf) - 1);
ESP_LOGI(TAG, "Binding to interface %s...", addrbuf);
err = bind(sock, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in));
if (err < 0)
{
ESP_LOGE(V4TAG, "Failed to bind socket. Error %d", errno);
goto err;
}
// Assign multicast TTL (set separately from normal interface TTL)
uint8_t ttl = MULTICAST_TTL;
setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(uint8_t));
if (err < 0)
{
ESP_LOGE(V4TAG, "Failed to set IP_MULTICAST_TTL. Error %d", errno);
goto err;
}
// All set, socket is configured for sending
return sock;
err:
close(sock);
return -1;
}

Resolve NetBIOS name on iOS

Is there any way on iOS to resolve NetBIOS name using IP address?
One could resolve NetBIOS name on a Mac using terminal command:
smbutil -v status -ae
The smbutil is opensourced so you can find it here:
http://www.apple.com/opensource/ -> http://opensource.apple.com//source/smb/
And the same on GitHub:
https://github.com/unofficial-opensource-apple/smb
But the util extensively uses private and Mac OS-specific frameworks so Xcode couldn't even compile the source for iOS.
I think you just need to do a reverse DNS lookup, gethostbyaddr, because it looks like DNS, gethostbyname, is the only thing being used to go from NetBios name to IP.
Looking at the source from Apple, the smbutil application in the 'status' mode first calls 'nb_resolvehost' which just uses 'gethostbyname' to get the IP address from NetBios name. 'gethostbyname' uses DNS under the hood:
nb_resolvehost_in(const char *name, struct sockaddr **dest)
{
struct hostent* h;
struct sockaddr_in *sinp;
int len;
h = gethostbyname(name);
if (!h) {
warnx("can't get server address `%s': ", name);
herror(NULL);
return ENETDOWN;
}
if (h->h_addrtype != AF_INET) {
warnx("address for `%s' is not in the AF_INET family", name);
return EAFNOSUPPORT;
}
if (h->h_length != 4) {
warnx("address for `%s' has invalid length", name);
return EAFNOSUPPORT;
}
len = sizeof(struct sockaddr_in);
sinp = malloc(len);
if (sinp == NULL)
return ENOMEM;
bzero(sinp, len);
sinp->sin_len = len;
sinp->sin_family = h->h_addrtype;
memcpy(&sinp->sin_addr.s_addr, h->h_addr, 4);
sinp->sin_port = htons(SMB_TCP_PORT);
*dest = (struct sockaddr*)sinp;
return 0;
}
After this call the 'smbutil status' then sends some sort of SMB query using the function 'nbns_getnodestatus' to the previously given IP address on the SMB port. From this query the command gets Workgroup and Servername (not sure which server this is referring to).

iOS - Get device's DNS server address on IPv6 only network

I am trying to get device's DNS server address while connected to IPv6 only network on iOS. The following code works well for when connected to IPv4 network but doesn't work on IPv6 network. Code taken from this answer.
res_ninit(&_res);
res_state res = &_res;
for (int i=0; i < res->nscount; i++) {
sa_family_t family = res->nsaddr_list[i].sin_family;
if (family == AF_INET) {
NSLog(#"IPv4");
char str[INET_ADDRSTRLEN]; // String representation of address
inet_ntop(AF_INET, & (res->nsaddr_list[i].sin_addr.s_addr), str, INET_ADDRSTRLEN);
} else if (family == AF_INET6) {
NSLog(#"IPv6");
char address[INET6_ADDRSTRLEN]; // String representation of address
inet_ntop(AF_INET6, &(res->nsaddr_list [i].sin_addr.s_addr), address, INET6_ADDRSTRLEN);
} else {
NSLog(#"Unspecified");
}
}
On IPv6 network, sin_family is always AF_UNSPEC. Any suggestions/alternatives?
Try using res._u._ext.nsaddrs for IPv6.
See https://chromium.googlesource.com/chromium/src/+/master/net/dns/dns_config_service_posix.cc#437

How to Get Host Name connected to a Socket using CFSocketNativeHandle iOS?

I am using Socket programming to connect devices each other in iOS.
I want to get connected device's Host Name which is connected to a socket using CFSocketNativeHandle.
When other device connected to my Socket i get callback in following callback function:
static void serverAcceptCallback(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *data, void *info)
{
// We can only process "connection accepted" calls here
if ( type != kCFSocketAcceptCallBack )
{
return;
}
// for an AcceptCallBack, the data parameter is a pointer to a CFSocketNativeHandle
CFSocketNativeHandle nativeSocketHandle = *(CFSocketNativeHandle*)data;
uint8_t name[SOCK_MAXADDRLEN];
socklen_t namelen = sizeof(name);
NSData *peer = nil;
if (0 == getpeername(nativeSocketHandle, (struct sockaddr *)name, &namelen)) {
peer = [NSData dataWithBytes:name length:namelen];
NSString *hostName = [[NSString alloc] initWithData:peer encoding:NSUTF8StringEncoding];
NSLog(#"HostName=%#",hostName);
}
}
Here I am getting NSData for "peer" but i am getting NSString *hostName=null.
How can i get exact Host name with this NSData.
getpeername() returns the address of the peer connected to the socket. You can access it using code below:
struct sockaddr_in addr ;
socklen_t len = sizeof(addr) ;
int res = getpeername(nativeSocketHandle, (struct sockaddr *)&addr, &len) ;
if (res == 0) {
char strAddr[20] ;
inet_ntop(AF_INET, &addr.sin_addr, strAddr, sizeof(strAddr)) ;
printf("ip %s\n", strAddr) ;
}
The only thing the socket knows is the IP address of the other end of the connection, so when you use getpeername it returns you the IP address. You will need to look up the IP address using either CFhost or POSIX calls - there are a squillion references to how to accomplish this using the POSIX APIs.
There is a very good chance that the other end will not be the same as the name of the device.

how can i get programmaticaly in Objective-C the name of local domain Knowing the ip adress?

Hi have many iPad in 2 differents local networks and I want to know programatically in Objective-C the local domain based in the IP address in each iPad.
for example I have an iPad in local domain "project.local". In this domain we have many IP address as 192.168.12.50. The IOS device get automaticaly their ip address.
Now I want to get programmaticaly in objective-C the domain name "projet.local" knowing the ip address??
Try this (similar to dreamlax's answer https://stackoverflow.com/a/3575383/1758762):
struct addrinfo *results = NULL;
char hostname[NI_MAXHOST] = {0};
if ( getaddrinfo("192.168.12.50", NULL, NULL, &results) != 0 )
return;
for (struct addrinfo *r = results; r; r = r->ai_next)
{
if (getnameinfo(r->ai_addr, r->ai_addrlen, hostname, sizeof hostname, NULL, 0 , 0) != 0)
continue; // try next one
else
{
NSLog (#"Found hostname: %s", hostname);
break;
}
}
freeaddrinfo(results);

Resources