I am trying to use the SystemConfiguration on mac OS to get a notification when a new network interface appears on the mac and a new IP address is assigned for it.
I set it up to watch for the system configuration key
State:/Network/Interface
and it works that I get a notification whenever a new network interface appears or disappears.However I would like to get a notification whenever the IPv4 address is assigned on the new network interface (e.g. by DHCP). I know that the key
State:/Network/Interface/en0/IPv4
is holding the IPv4 address for the en0 interface. But using regular expressions as depicted in the man page for all IPv4 addresses State:/Network/Interface/.*/IPv4
does not work for the new interface.I have put together a small minimal code example on github, however one can also use the
scutil
command line tool.main.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;
}
What you’d normally do here is pass
NULL
to the
keys
parameter of
SCDynamicStoreSetNotificationKeys
and then pass an array containing a regex to the
patterns
parameter. The regex would look something like
State:/Network/Interface/[^/]+/IPv4
. If you do this then you can extract the interface name for each change from the keys passed to the
changedKeys
parameter of your callback.
Having said that, I generally avoid doing this and just use the notification as a trigger to re-read the dynamic store and re-generate my state. The problem with relies on the details of the notification is that it’s brittle: If something goes wrong you never recover.
Share and Enjoy
—
Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
let myEmail = "eskimo" + "1" + "@apple.com"