Given the BSD name or a reference to a network interface, how to get its gateway and DNS servers?

182 views Asked by At

In a macOS app, I'm trying to get the gateway / router and DNS servers for a network interface. The interface could be identified by its BSD name, or using System Configuration with a SCNetworkInterfaceRef or a SCNetworkServiceRef. (Whichever is appropriate.)

Specifically, I want to get the same information that would be displayed to the user if they open the Network system preferences and select this connection. (Note that its gateway is called "router" in the Network system preferences, and I'm using the two terms interchangeably for the purposes of this question.)

This app is written in Objective-C, but a Swift solution is fine too as it's generally straightforward to port it to Objective-C.

1

There are 1 answers

0
Bri Bri On BEST ANSWER

I've figured out how to do this, given a SCNetworkServiceRef. These two functions will return the gateway and DNS servers for the specified network:

CFStringRef copyNetworkServiceGateway(SCNetworkServiceRef service)
{
    CFStringRef result = NULL;
    CFStringRef interfaceServiceID = SCNetworkServiceGetServiceID(service);
    CFStringRef servicePath = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Service/%@/IPv4"),
                                                       interfaceServiceID);
    SCDynamicStoreRef dynamicStoreRef = SCDynamicStoreCreate(kCFAllocatorSystemDefault,
                                                             CFSTR("your.app.name.here"), NULL, NULL);
    CFDictionaryRef propList = (CFDictionaryRef)SCDynamicStoreCopyValue(dynamicStoreRef, servicePath);
    
    if (propList) {    
        result = (CFStringRef)CFDictionaryGetValue(propList, CFSTR("Router"));
        CFRetain(result);
        CFRelease(propList);
    }
    
    CFRelease(servicePath);
    CFRelease(dynamicStoreRef);
    
    return result;
}

CFArrayRef copyNetworkServiceDNSServers(SCNetworkServiceRef service)
{
    CFArrayRef result = NULL;
    CFStringRef interfaceServiceID = SCNetworkServiceGetServiceID(service);
    // If the user has added custom DNS servers, then we have to use this path to find them:
    CFStringRef servicePath = CFStringCreateWithFormat(NULL, NULL, CFSTR("Setup:/Network/Service/%@/DNS"),
                                                       interfaceServiceID);
    SCDynamicStoreRef dynamicStoreRef = SCDynamicStoreCreate(kCFAllocatorSystemDefault,
                                                             CFSTR("your.app.name.here"), NULL, NULL);
    CFDictionaryRef propList = (CFDictionaryRef)SCDynamicStoreCopyValue(dynamicStoreRef, servicePath);
    CFRelease(servicePath);
    
    if (!propList) {
        // In this case, the user has not added custom DNS servers and we use this path to
        // get the default DNS servers:
        servicePath = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Service/%@/DNS"),
                                               interfaceServiceID);
        propList = (CFDictionaryRef)SCDynamicStoreCopyValue(dynamicStoreRef, servicePath);
        CFRelease(servicePath);
    }
    
    if (propList) {
        result = (CFArrayRef)CFDictionaryGetValue(propList, CFSTR("ServerAddresses"));
        
        if (result) {
            CFRetain(result);
        }
        
        CFRelease(propList);
    }
    
    CFRelease(dynamicStoreRef);
    
    return result;
}