Skip to content

Instantly share code, notes, and snippets.

@CavalcanteLeo
Forked from amcgregor/BDHost.m
Created September 6, 2017 18:43
Show Gist options
  • Save CavalcanteLeo/c12725cd70adcd94933ae0c595dbbfcd to your computer and use it in GitHub Desktop.
Save CavalcanteLeo/c12725cd70adcd94933ae0c595dbbfcd to your computer and use it in GitHub Desktop.
Useful Objective-C methods, classes, objects, and categories. Basically a snippit collection.
// From: http://www.bdunagan.com/2009/11/28/iphone-tip-no-nshost/
// MIT license
// Remember to add CFNetwork.framework to your project using Add=>Existing Frameworks.
#import "BDHost.h"
#import <CFNetwork/CFNetwork.h>
#import <netinet/in.h>
#import <netdb.h>
#import <ifaddrs.h>
#import <arpa/inet.h>
#import <net/ethernet.h>
#import <net/if_dl.h>
@implementation BDHost
+ (NSString *)addressForHostname:(NSString *)hostname {
NSArray *addresses = [BDHost addressesForHostname:hostname];
if ([addresses count] > 0)
return [addresses objectAtIndex:0];
else
return nil;
}
+ (NSArray *)addressesForHostname:(NSString *)hostname {
// Get the addresses for the given hostname.
CFHostRef hostRef = CFHostCreateWithName(kCFAllocatorDefault, (CFStringRef)hostname);
BOOL isSuccess = CFHostStartInfoResolution(hostRef, kCFHostAddresses, nil);
if (!isSuccess) return nil;
CFArrayRef addressesRef = CFHostGetAddressing(hostRef, nil);
if (addressesRef == nil) return nil;
// Convert these addresses into strings.
char ipAddress[INET6_ADDRSTRLEN];
NSMutableArray *addresses = [NSMutableArray array];
CFIndex numAddresses = CFArrayGetCount(addressesRef);
for (CFIndex currentIndex = 0; currentIndex < numAddresses; currentIndex++) {
struct sockaddr *address = (struct sockaddr *)CFDataGetBytePtr(CFArrayGetValueAtIndex(addressesRef, currentIndex));
if (address == nil) return nil;
getnameinfo(address, address->sa_len, ipAddress, INET6_ADDRSTRLEN, nil, 0, NI_NUMERICHOST);
if (ipAddress == nil) return nil;
[addresses addObject:[NSString stringWithCString:ipAddress encoding:NSASCIIStringEncoding]];
}
return addresses;
}
+ (NSString *)hostnameForAddress:(NSString *)address {
NSArray *hostnames = [BDHost hostnamesForAddress:address];
if ([hostnames count] > 0)
return [hostnames objectAtIndex:0];
else
return nil;
}
+ (NSArray *)hostnamesForAddress:(NSString *)address {
// Get the host reference for the given address.
struct addrinfo hints;
struct addrinfo *result = NULL;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_NUMERICHOST;
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
int errorStatus = getaddrinfo([address cStringUsingEncoding:NSASCIIStringEncoding], NULL, &hints, &result);
if (errorStatus != 0) return nil;
CFDataRef addressRef = CFDataCreate(NULL, (UInt8 *)result->ai_addr, result->ai_addrlen);
if (addressRef == nil) return nil;
freeaddrinfo(result);
CFHostRef hostRef = CFHostCreateWithAddress(kCFAllocatorDefault, addressRef);
if (hostRef == nil) return nil;
CFRelease(addressRef);
BOOL isSuccess = CFHostStartInfoResolution(hostRef, kCFHostNames, NULL);
if (!isSuccess) return nil;
// Get the hostnames for the host reference.
CFArrayRef hostnamesRef = CFHostGetNames(hostRef, NULL);
NSMutableArray *hostnames = [NSMutableArray array];
for (int currentIndex = 0; currentIndex < [(NSArray *)hostnamesRef count]; currentIndex++) {
[hostnames addObject:[(NSArray *)hostnamesRef objectAtIndex:currentIndex]];
}
return hostnames;
}
+ (NSArray *)ipAddresses {
NSMutableArray *addresses = [NSMutableArray array];
struct ifaddrs *interfaces = NULL;
struct ifaddrs *currentAddress = NULL;
int success = getifaddrs(&interfaces);
if (success == 0) {
currentAddress = interfaces;
while(currentAddress != NULL) {
if(currentAddress->ifa_addr->sa_family == AF_INET) {
NSString *address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)currentAddress->ifa_addr)->sin_addr)];
if (![address isEqual:@"127.0.0.1"]) {
NSLog(@"%@ ip: %@", [NSString stringWithUTF8String:currentAddress->ifa_name], address);
[addresses addObject:address];
}
}
currentAddress = currentAddress->ifa_next;
}
}
freeifaddrs(interfaces);
return addresses;
}
+ (NSArray *)ethernetAddresses {
NSMutableArray *addresses = [NSMutableArray array];
struct ifaddrs *interfaces = NULL;
struct ifaddrs *currentAddress = NULL;
int success = getifaddrs(&interfaces);
if (success == 0) {
currentAddress = interfaces;
while(currentAddress != NULL) {
if(currentAddress->ifa_addr->sa_family == AF_LINK) {
NSString *address = [NSString stringWithUTF8String:ether_ntoa((const struct ether_addr *)LLADDR((struct sockaddr_dl *)currentAddress->ifa_addr))];
// ether_ntoa doesn't format the ethernet address with padding.
char paddedAddress[80];
int a,b,c,d,e,f;
sscanf([address UTF8String], "%x:%x:%x:%x:%x:%x", &a, &b, &c, &d, &e, &f);
sprintf(paddedAddress, "%02X:%02X:%02X:%02X:%02X:%02X",a,b,c,d,e,f);
address = [NSString stringWithUTF8String:paddedAddress];
if (![address isEqual:@"00:00:00:00:00:00"] && ![address isEqual:@"00:00:00:00:00:FF"]) {
NSLog(@"%@ mac: %@", [NSString stringWithUTF8String:currentAddress->ifa_name], address);
[addresses addObject:address];
}
}
currentAddress = currentAddress->ifa_next;
}
}
freeifaddrs(interfaces);
return addresses;
}
@end
// This is to get around NSHost being crippled on iOS.
+ (NSString *)getIPAddress {
NSString *address = @"error";
struct ifaddrs *interfaces = NULL; struct ifaddrs *temp_addr = NULL;
int success = 0; // retrieve the current interfaces - returns 0 on success
success = getifaddrs(&interfaces);
if (success == 0) {
// Loop through linked list of interfaces
temp_addr = interfaces;
while(temp_addr != NULL) {
if(temp_addr->ifa_addr->sa_family == AF_INET) {
// Check if interface is en0 which is the wifi connection on the iPhone
if([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]) {
// Get NSString from C String
address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];
}
}
temp_addr = temp_addr->ifa_next;
}
}
// Free memory
freeifaddrs(interfaces);
return address;
}
// From: http://wiki.gonzofamily.com/a/DNS_resolution_with_IPv6_in_Objective_C
/**
Give the IPs corresponding to a Hostname
Sometime only 1 IPv4 is shown even if there's more.
Sometime only 1 IPv6 is shown even if there's more.
Certainly due to iOS Memory optimisation when locally cached
@author Christian Gonzalvez, http://wiki.gonzofamily.com
@param hostName A hostname
@return an Array of NSString of all the corresponding IP addresses. The first
is the Canonical name, the following are IPs (all NSString)
*/
+ (NSArray *)addressesForHostname:(NSString *)hostname
{
const char* hostnameC = [hostname UTF8String];
struct addrinfo hints, *res;
struct sockaddr_in *s4;
struct sockaddr_in6 *s6;
int retval;
char buf[64];
NSMutableArray *result; //the array which will be return
NSMutableArray *result4; //the array of IPv4, to order them at the end
NSString *previousIP = nil;
memset (&hints, 0, sizeof (struct addrinfo));
hints.ai_family = PF_UNSPEC;//AF_INET6;
hints.ai_flags = AI_CANONNAME;
//AI_ADDRCONFIG, AI_ALL, AI_CANONNAME, AI_NUMERICHOST
//AI_NUMERICSERV, AI_PASSIVE, OR AI_V4MAPPED
retval = getaddrinfo(hostnameC, NULL, &hints, &res);
if (retval == 0)
{
if (res->ai_canonname)
{
result = [NSMutableArray arrayWithObject:[NSString stringWithUTF8String:res->ai_canonname]];
}
else
{
//it means the DNS didn't know this host
return nil;
}
result4= [NSMutableArray array];
while (res) {
switch (res->ai_family){
case AF_INET6:
s6 = (struct sockaddr_in6 *)res->ai_addr;
if(inet_ntop(res->ai_family, (void *)&(s6->sin6_addr), buf, sizeof(buf))
== NULL)
{
NSLog(@"inet_ntop failed for v6!\n");
}
else
{
//surprisingly every address is in double, let's add this test
if (![previousIP isEqualToString:[NSString stringWithUTF8String:buf]]) {
[result addObject:[NSString stringWithUTF8String:buf]];
}
}
break;
case AF_INET:
s4 = (struct sockaddr_in *)res->ai_addr;
if(inet_ntop(res->ai_family, (void *)&(s4->sin_addr), buf, sizeof(buf))
== NULL)
{
NSLog(@"inet_ntop failed for v4!\n");
}
else
{
//surprisingly every address is in double, let's add this test
if (![previousIP isEqualToString:[NSString stringWithUTF8String:buf]]) {
[result4 addObject:[NSString stringWithUTF8String:buf]];
}
}
break;
default:
NSLog(@"Neither IPv4 nor IPv6!");
}
//surprisingly every address is in double, let's add this test
previousIP = [NSString stringWithUTF8String:buf];
res = res->ai_next;
}
}else{
NSLog(@"no IP found");
return nil;
}
return [result arrayByAddingObjectsFromArray:result4];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment