How to determine netmask of active interface in Objective-C on a Mac?

拈花ヽ惹草 提交于 2019-12-09 13:32:58

问题


I'm trying to determine the network segment my Macbook is in, because I then want to scan this segment for active hosts (basic IP scanner) by using the CFHost class. Therefore I need the IP and Netmask of my active interface. This is how I get the IP:

NSString *ipAddr = [[[NSHost currentHost] addresses] objectAtIndex:0];

But I have absolutely no idea how to get the Netmask, so I'm kind of stuck. Especially because I'm fairly new at Objective-C and because I also do not have extensive knowledge of plain C. I've looked at CFHost, CFNetwork, NSHost and various Google hits, but have found nothing useful, so far.

As a last resort I could do a system call of sorts, I suppose, or read it from a file (which one?), but I want to avoid that, if possible.

So, how do I get the matching netmask to the ip obtained through NSHost? Any suggestions would be greatly appreciated.

Thanks!


回答1:


You will have to use the System Configuration API. See System Configuration Programming Guidelines and System Configuration Framework Reference




回答2:


So, to wrap this up, I did finally get around to investigating the System Configuration API. As always, once you know how it's not that difficult.

@0xced - Thanks for pointing me in the right direction. I'd upvote your answer, but I do not have enough reputation to do so.

This is my solution, for anyone who is curious or in the same situation. It involves digging in the dynamic store. See this for infos on the API. You can look at the information the dynamic store holds by using the scutil command line utility (see x-man-page://8/scutil ).

Here are my steps. First, you need a session:

SCDynamicStoreRef storeRef = SCDynamicStoreCreate(NULL, (CFStringRef)@"FindCurrentInterfaceIpMac", NULL, NULL);

Then, I try to get the primary interface (en1, for example):

CFPropertyListRef global = SCDynamicStoreCopyValue (storeRef,CFSTR("State:/Network/Global/IPv4"));
NSString *primaryInterface = [(__bridge NSDictionary *)global valueForKey:@"PrimaryInterface"];

Last, I build a string containing the interface to be able to query the right key. It should look something like State:/Network/Interface/en1/IPv4, depending on the interface, of course. With that I am able to get an array with the ip and the netmask. On my Macbook these arrays hold only one ip and netmask, respectively. I suppose it is possible this could be different for other Macs, I will have to verify that. For my test I simply took the first (and only) element in the array, but some sort of checking for size would have to be implemented there.

NSString *interfaceState = [NSString stringWithFormat:@"State:/Network/Interface/%@/IPv4", primaryInterface];

CFPropertyListRef ipv4 = SCDynamicStoreCopyValue (storeRef, (CFStringRef)interfaceState);
CFRelease(storeRef);

NSString *ip = [(__bridge NSDictionary *)ipv4 valueForKey:@"Addresses"][0];
NSString *netmask = [(__bridge NSDictionary *)ipv4 valueForKey:@"SubnetMasks"][0];
CFRelease(ipv4);

This is just for testing, so it is a little rough around the edges. You will have to look for retain counts and the like. It was only written to get an idea of how it could be done.




回答3:


Martin had given a nice answer.
And his code in a ARC version is here:

+ (NSDictionary *)primaryIPv4AddressInfoFromSystemConfiguration
{
    SCDynamicStoreRef storeRef = SCDynamicStoreCreate(NULL, (CFStringRef)@"FindCurrentInterfaceIpMac", NULL, NULL);
    if (!storeRef)
    {
        return nil;
    }

    NSDictionary *IPv4Dictionary = nil;
    CFPropertyListRef global = SCDynamicStoreCopyValue(storeRef, CFSTR("State:/Network/Global/IPv4"));
    id primaryInterface = [(NSDictionary *)CFBridgingRelease(global) valueForKey:@"PrimaryInterface"];
    if (primaryInterface)
    {
        NSString *interfaceState = @"State:/Network/Interface/";
        interfaceState = [[interfaceState stringByAppendingString:(NSString *)primaryInterface] stringByAppendingString:@"/IPv4"];
        CFPropertyListRef IPv4PropertyList = SCDynamicStoreCopyValue(storeRef, (__bridge CFStringRef)interfaceState);
        IPv4Dictionary = (NSDictionary *)CFBridgingRelease(IPv4PropertyList);
    }

    CFRelease(storeRef);
    return IPv4Dictionary;
}

+ (NSDictionary *)primaryIPv6AddressInfoFromSystemConfiguration
{
    SCDynamicStoreRef storeRef = SCDynamicStoreCreate(NULL, (CFStringRef)@"FindCurrentInterfaceIpMac", NULL, NULL);
    if (!storeRef)
    {
        return nil;
    }

    NSDictionary *IPv6Dictionary = nil;
    CFPropertyListRef global = SCDynamicStoreCopyValue(storeRef, CFSTR("State:/Network/Global/IPv6"));
    id primaryInterface = [(NSDictionary *)CFBridgingRelease(global) valueForKey:@"PrimaryInterface"];
    if (primaryInterface)
    {
        NSString *interfaceState = @"State:/Network/Interface/";
        interfaceState = [[interfaceState stringByAppendingString:(NSString *)primaryInterface] stringByAppendingString:@"/IPv6"];
        CFPropertyListRef IPv6PropertyList = SCDynamicStoreCopyValue(storeRef, (__bridge CFStringRef)interfaceState);
        IPv6Dictionary = (NSDictionary *)CFBridgingRelease(IPv6PropertyList);
    }

    CFRelease(storeRef);
    return IPv6Dictionary;
}


来源:https://stackoverflow.com/questions/6795798/how-to-determine-netmask-of-active-interface-in-objective-c-on-a-mac

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!