如何确定 Mac 上 Objective-C 中活动接口的网络掩码?

问题描述 投票:0回答:4

我试图确定我的 Macbook 所在的网段,因为我想使用 CFHost 类扫描该网段中的活动主机(基本 IP 扫描仪)。因此我需要活动接口的 IP 和网络掩码。这就是我获取IP的方式:

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

但我完全不知道如何获取网络掩码,所以我有点陷入困境。特别是因为我对 Objective-C 还很陌生,而且我对普通 C 也没有广泛的了解。我看过 CFHost、CFNetwork、NSHost 和各种 Google 搜索结果,但到目前为止没有发现任何有用的东西。

作为最后的手段,我想,我可以进行某种系统调用,或者从文件中读取它(哪个?),但如果可能的话,我想避免这种情况。

那么,如何获取与通过 NSHost 获取的 ip 相匹配的网络掩码呢?任何建议将不胜感激。

谢谢!

objective-c cocoa macos networking netmask
4个回答
12
投票

因此,为了总结这一点,我终于开始研究系统配置 API。与往常一样,一旦您知道如何,它就不那么困难了。

@0xced - 感谢您为我指明了正确的方向。我会赞成你的答案,但我没有足够的声誉来这样做。

这是我的解决方案,适合任何好奇或处于相同情况的人。它涉及到动态存储中的挖掘。有关 API 的信息,请参阅this。您可以使用 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);

这只是为了测试,所以边缘有点粗糙。您将必须寻找保留计数等。编写它只是为了了解如何完成它。


3
投票

马丁给出了很好的答案。
他的 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
投票

您必须使用系统配置 API。请参阅系统配置编程指南系统配置框架参考


0
投票

斯威夫特5

我翻译了@Martin 对 Swift 的回答:

let storeRef = SCDynamicStoreCreate(nil, "FindCurrentInterfaceIpMac" as CFString, nil, nil)

if let global: CFPropertyList = SCDynamicStoreCopyValue(storeRef, "State:/Network/Global/IPv4" as CFString) {
    
    var primaryInterface: String = global.value(forKey: "PrimaryInterface") as! String
    
    var interfaceState = "State:/Network/Interface/\(primaryInterface)/IPv4"
    
    if let ipv4: CFPropertyList = SCDynamicStoreCopyValue(storeRef, interfaceState as CFString) {
        
        let ip: String = (ipv4.value(forKey: "Addresses") as! [String]).first!
        let netmask: String = (ipv4.value(forKey: "SubnetMasks") as! [String]).first!
        
        print("\(primaryInterface), \(ip), \(netmask)")
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.