如何使用系统配置框架检测 macOS 上的 IPv4 地址更改



我正在尝试使用 mac OS 上的系统配置,以便在 mac 上出现新的网络接口并为其分配新的 IP 地址时收到通知。

我将其设置为监视系统配置密钥State:/Network/Interface并且每当出现或消失新的网络接口时,我都会收到通知。

但是,每当在新网络接口上分配IPv4地址(例如通过DHCP)时,我都希望收到通知。我知道State:/Network/Interface/en0/IPv4的关键是保存 en0 接口的 IPv4 地址。但是,对手册页中描述的所有 IPv4 地址使用正则表达式State:/Network/Interface/.*/IPv4不适用于新接口。

我在 github 上整理了一个很小的代码示例,但是也可以使用 scutil 命令行工具。

链接到演示存储库

主.c

#import <Foundation/Foundation.h>
#import <SystemConfiguration/SystemConfiguration.h>
/* Callback used if a configuration change on monitored keys was detected.
 */
void dynamicStoreCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void* __nullable info) {
    CFIndex count = CFArrayGetCount(changedKeys);
    for (CFIndex i=0; i<count; i++) {
        NSLog(@"Key "%@" was changed", CFArrayGetValueAtIndex(changedKeys, i));
    }
}
int main(int argc, const char * argv[]) {
    NSArray *SCMonitoringInterfaceKeys = @[@"State:/Network/Interface.*"];
    @autoreleasepool {
        SCDynamicStoreRef dsr = SCDynamicStoreCreate(NULL, CFSTR("network_interface_detector"), &dynamicStoreCallback, NULL);
        SCDynamicStoreSetNotificationKeys(dsr, CFBridgingRetain(SCMonitoringInterfaceKeys), NULL);
        CFRunLoopAddSource(CFRunLoopGetCurrent(), SCDynamicStoreCreateRunLoopSource(NULL, dsr, 0), kCFRunLoopDefaultMode);
        NSLog(@"Starting RunLoop...");
        while([[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
    }
    return 0;
}

在一些开发人员同事的帮助下,我发现了哪里出了问题。SCDynamicStoreSetNotificationKeys函数的签名如下:

Boolean SCDynamicStoreSetNotificationKeys (SCDynamicStoreRef store,
                CFArrayRef          __nullable  keys,
                CFArrayRef          __nullable  patterns
                )

这意味着我必须将模式与键分开设置,键充当将发生模式匹配的树的根。这是我的main.m的修改版本:

int main(int argc, const char * argv[]) {
    NSArray *SCMonitoringInterfaceKeys = @[@"State:/Network/Interface"];
    NSArray *patterns = @[@"en\d*/IPv4"];
    @autoreleasepool {
        SCDynamicStoreRef dsr = SCDynamicStoreCreate(NULL, CFSTR("network_interface_detector"), &dynamicStoreCallback, NULL);
        SCDynamicStoreSetNotificationKeys(dsr, CFBridgingRetain(SCMonitoringInterfaceKeys), CFBridgingRetain(patterns));
        CFRunLoopAddSource(CFRunLoopGetCurrent(), SCDynamicStoreCreateRunLoopSource(NULL, dsr, 0), kCFRunLoopDefaultMode);
        NSLog(@"Starting RunLoop...");
        while([[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
    }
    return 0;
}

我已将解决方案包含在存储库的已解决分支中。

最新更新