NSHost will give you the addresses given in DNS (or NetInfo) to the local hostname -- typically just one, and if the hostname is "localhost", then you'll get 127.0.0.1 .
To get the addresses for each local interface, that's an entirely different kettle of fish, and it has nothing to do with DNS. You basically have to walk the interface list, getting the interface address for each interface.
The code to do it is in the ifconfig command (see the Darwin CVS repository), and it basically uses sysctl(3) to get the interface
information (found in routing table messages).
If you have no experience in the depths of BSD networking code, this may not be for you. For what it's worth however, here is some code to do it. This just gets AF_INET addresses; if you want AF_INET6 (IPv6, coming in MacOS X 10.2 I think) you'll have to alter the code. I doubt you'll care
about that for quite a while to come though.
The code is mostly paraphrased from the code to the ifconfig command. Copy this into a "ifenum.m" file, and compile with "cc ifenum.m -o ifenum -framework Foundation".
</font><blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">code:</font><hr /><pre style="font-size:x-small; font-family: monospace;">#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/socket.h>
#include <net/route.h>
#include <netinet/in.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <stdlib.h>
/*
* The rt_addrinfo struct has an array of sockaddr pointers, with each slot
* being a possible type of address (interface, broadcast, netmask, etc.). Since
* there are 8 slots, a lot of these are empty. The sysctl() call comes back
* with a "packed" array, with the sockaddr structures all back to back, and the
* rti_addrs field a mask specifying which ones are there. This function expands
* it into the full rt_addrinfo struct. Stolen directly from ifconfig, as I have
* no desire to figure out the actual bits here.
*/
#define ROUNDUP(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
static void rt_expand_addrs(void *cp, void *cplim, struct rt_addrinfo *rtinfo)
{
struct sockaddr *sa;
int i;
memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
if ((rtinfo->rti_addrs & (1 << i)) == 0)
continue;
rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
ADVANCE(cp, sa);
}
}
NSDictionary *HostAddresses()
{
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
NSString *interfaceName;
int mib[6];
char *buffer, *end;
size_t buffsize = 0;
/*
* The sysctl() setup to get the interface list out of the routing table. We
* expect an RTM_IFINFO message followed by zero or more RTM_NEWADDR
* messages for each interface. struct if_msghdr is the basic structure,
* with other message types defining additional fields in specific structures.
*/
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = AF_INET;
mib[4] = NET_RT_IFLIST;
mib[5] = 0;
/* A dummy sysctl to get the memory size needed, malloc, then the real call */
if (sysctl(mib, 6, NULL, &buffsize, NULL, 0) < 0)
return nil;
if ((buffer = (char*)malloc(buffsize)) == NULL)
return nil;
if (sysctl(mib, 6, buffer, &buffsize, NULL, 0) < 0)
return nil;
end = buffer + buffsize;
while (buffer < end)
{
struct if_msghdr *if_header = (struct if_msghdr *)buffer;
int if_flags = 0;
/* The interface info route message; should be first */
if (if_header->ifm_type == RTM_IFINFO)
{
struct sockaddr_dl *sdl;
if_flags = if_header->ifm_flags; //flags for this interface
sdl = (struct sockaddr_dl *)(if_header+1); // sockaddr_dl is extra field; has the name
interfaceName = [NSString stringWithCString:sdl->sdl_data length:sdl->sdl_nlen];
}
else if (if_header->ifm_type == RTM_NEWADDR)
{
struct ifa_msghdr *ifam;
struct rt_addrinfo info;
/* this message is a ifa_msghdr structure */
ifam = (struct ifa_msghdr *)if_header;
/* the packed address array (data follows ifam header) into an rt_addrinfo structure. */
info.rti_addrs = ifam->ifam_addrs;
rt_expand_addrs((char *)(ifam+1), ifam->ifam_msglen+(char*)ifam, &info);
// make sure we have the right family
if (info.rti_info[RTAX_IFA]->sa_family == AF_INET)
{
NSString *address;
struct sockaddr_in *sin = (struct sockaddr_in *)info.rti_info[RTAX_IFA];
unsigned char *addr = (unsigned char *)&sin->sin_addr;
address = [NSString stringWithFormat:@"%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]];
if (interfaceName != nil) //should always be set, but...
[dict setObject:address forKey:interfaceName];
// if (if_flags & IFF_POINTTOPOINT), then info.rtf_info[RTAX_BRD] is the dest address. Do we care?
}
// AF_INET6 has a different sockaddr type...
}
else
{
#if DEBUG
printf("Unexpected route message type: %d\n", if_header->ifm_type);
#endif
}
buffer += if_header->ifm_msglen; //increment the buffer to the next message
}
return dict;
}
#import <Foundation/Foundation.h>
int main()
{
id pool = [[NSAutoreleasePool alloc] init];
NSDictionary *addresses = HostAddresses();
NSEnumerator *ifEnum = [addresses keyEnumerator];
NSString *iface;
while (iface = [ifEnum nextObject])
{
printf("%s: %s\n", [iface cString], [[addresses objectForKey:iface] cString]);
}
[pool release];
exit(0);
return 0;
}</pre><hr /></blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">