Как определить маску активного интерфейса в Objective-C на Mac? - PullRequest
4 голосов
/ 23 июля 2011

Я пытаюсь определить сегмент сети, в котором находится мой Macbook, потому что затем я хочу просканировать этот сегмент на наличие активных хостов (базовый IP-сканер) с помощью класса CFHost.Поэтому мне нужны IP-адрес и маска моего активного интерфейса.Вот как я получаю IP:

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

Но я абсолютно не знаю, как получить сетевую маску, так что я застрял.Особенно потому, что я довольно новичок в Objective-C и потому что у меня нет глубоких знаний простого C. Я посмотрел CFHost, CFNetwork, NSHost и различные хиты Google, но пока не нашел ничего полезного.

В качестве последнего средства я мог бы сделать системный вызов, я полагаю, или прочитать его из файла (какой?), Но я хочу избежать этого, если это возможно.

Итак,Как я могу получить соответствующую маску для IP-адреса, полученного через NSHost?Любые предложения будут с благодарностью.

Спасибо!

Ответы [ 3 ]

12 голосов
/ 11 августа 2011

Итак, чтобы подвести итог, я наконец-то приступил к изучению API конфигурации системы.Как всегда, когда вы знаете, как это не так сложно.

@ 0xced - Спасибо, что указали мне в правильном направлении.Я бы одобрил ваш ответ, но у меня недостаточно репутации, чтобы сделать это.

Это мое решение для всех, кто интересуется или находится в такой же ситуации.Это связано с копанием в динамическом магазине.См. this для получения информации об API.Вы можете просмотреть информацию, которую хранит динамическое хранилище, используя утилиту командной строки scutil (см. X-man-page: // 8 / scutil).

Вот мои шаги.Во-первых, вам нужен сеанс:

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

Затем я пытаюсь получить основной интерфейс (например, en1):

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

Наконец, я строю строку, содержащую интерфейсчтобы иметь возможность запросить правильный ключ.Это должно выглядеть примерно так: State: / Network / Interface / en1 / IPv4, в зависимости от интерфейса, конечно.При этом я могу получить массив с IP и сетевой маской.На моем MacBook эти массивы содержат только один ip и маску соответственно.Я полагаю, что это может отличаться для других компьютеров Mac, я должен это проверить.Для моего теста я просто взял первый (и единственный) элемент в массиве, но там нужно было бы выполнить какую-то проверку размера.

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);

Это только для тестирования, так что этонемного грубо по краям.Вам придется искать счетчики и тому подобное.Он был написан только для того, чтобы понять, как это можно сделать.

2 голосов
/ 07 июля 2015

Мартин дал хороший ответ.
И его код в версии ARC находится здесь:

+ (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;
}
2 голосов
/ 31 июля 2011
...