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

前端 未结 3 789
春和景丽
春和景丽 2021-02-10 17:20

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

相关标签:
3条回答
  • 2021-02-10 17:26

    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;
    }
    
    0 讨论(0)
  • 2021-02-10 17:28

    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.

    0 讨论(0)
  • 2021-02-10 17:38

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

    0 讨论(0)
提交回复
热议问题