Skip to content

Instantly share code, notes, and snippets.

@leiless
Last active July 26, 2023 03:22
Show Gist options
  • Save leiless/5dddcdfbb1d578bd96c44ff727b2cc05 to your computer and use it in GitHub Desktop.
Save leiless/5dddcdfbb1d578bd96c44ff727b2cc05 to your computer and use it in GitHub Desktop.
Finding DNS server addresses programmatically on macOS
/**
* Finding DNS server addresses programmatically on macOS
* see:
* https://stackoverflow.com/questions/260518/finding-dns-server-settings-programmatically-on-mac-os-x
*/
#import <Foundation/Foundation.h>
#import <SystemConfiguration/SystemConfiguration.h>
int main(void) {
CFStringRef callerName = CFSTR("foobar");
SCPreferencesRef scPrefs = SCPreferencesCreate(NULL, callerName, NULL);
CFArrayRef services = SCNetworkServiceCopyAll(scPrefs);
if (services) {
CFIndex count = CFArrayGetCount(services);
for (CFIndex i = 0; i < count; i++) {
NSLog(@"> i = %ld", i);
SCNetworkServiceRef service = CFArrayGetValueAtIndex(services, i);
SCNetworkInterfaceRef interface = SCNetworkServiceGetInterface(service);
NSLog(@"%@", interface);
NSString *interfaceServiceID = (__bridge NSString *) SCNetworkServiceGetServiceID(service);
CFStringRef primaryServicePath = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Service/%@/DNS"), interfaceServiceID);
NSLog(@"%@", primaryServicePath);
SCDynamicStoreRef dynRef = SCDynamicStoreCreate(kCFAllocatorSystemDefault, callerName, NULL, NULL);
CFDictionaryRef dnskey = SCDynamicStoreCopyValue(dynRef, primaryServicePath);
// dnskey will give you the DNS server address.
NSLog(@"DNS dict: %@", dnskey);
}
}
return 0;
}
@leiless
Copy link
Author

leiless commented Jun 22, 2021

Sample output

gcc -Wall -Wextra -lobjc -framework Foundation -framework SystemConfiguration dhcp_dns.m


$ ./a.out
2021-06-22 22:16:11.917 a.out[10975:94052] > i = 0
2021-06-22 22:16:11.929 a.out[10975:94052] <SCNetworkInterface 0x7f8c896040b0 [0x7fff807f9b70]> {type = Ethernet, entity_device = en3, entity_type = Ethernet, name(k) = "bluetooth-pan-gn", builtin = FALSE, order = 15 (BluetoothPAN_GN), prefs = 0x7f8c89704300, service = 3348B7DC-0F04-49AC-84FF-6D00B417A932}
2021-06-22 22:16:11.929 a.out[10975:94052] State:/Network/Service/3348B7DC-0F04-49AC-84FF-6D00B417A932/DNS
2021-06-22 22:16:11.930 a.out[10975:94052] DNS dict: (null)
2021-06-22 22:16:11.930 a.out[10975:94052] > i = 1
2021-06-22 22:16:11.932 a.out[10975:94052] <SCNetworkInterface 0x7f8c89508420 [0x7fff807f9b70]> {type = IEEE80211, entity_device = en0, entity_type = Ethernet, name(k) = "airport", address = 18:65:90:d3:53:e3, builtin = TRUE, path = IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/RP03@1C,2/IOPP/ARPT@0/AirPort_BrcmNIC/en0, entryID = 0x100000376, type = 6, unit = 0, order = 11 (AirPort), prefs = 0x7f8c89704300, service = 2CC351F0-1C0D-416F-BB89-77A3F7ECFEEE}
2021-06-22 22:16:11.932 a.out[10975:94052] State:/Network/Service/2CC351F0-1C0D-416F-BB89-77A3F7ECFEEE/DNS
2021-06-22 22:16:11.932 a.out[10975:94052] DNS dict: {
    ServerAddresses =     (
        "192.168.200.1"
    );
}
2021-06-22 22:16:11.932 a.out[10975:94052] > i = 2
2021-06-22 22:16:11.939 a.out[10975:94052] <SCNetworkInterface 0x7f8c89508750 [0x7fff807f9b70]> {type = Bridge, entity_device = bridge0, entity_type = Ethernet, name(k) = "thunderbolt-bridge", address = 82:13:21:4d:c9:00, builtin = TRUE, order = 21 (Bridge), prefs = 0x7f8c89704300, service = 476D71DB-D464-4560-9DF7-D506EB5AB172, interfaces = en1,en2, options = <dictionary> {
  __AUTO__ : thunderbolt-bridge
}}
2021-06-22 22:16:11.939 a.out[10975:94052] State:/Network/Service/476D71DB-D464-4560-9DF7-D506EB5AB172/DNS
2021-06-22 22:16:11.940 a.out[10975:94052] DNS dict: (null)


$ ./a.out
2021-06-22 22:12:49.213 a.out[10856:92277] > i = 0
2021-06-22 22:12:49.221 a.out[10856:92277] <SCNetworkInterface 0x7fa05ed068a0 [0x7fff807f9b70]> {type = Ethernet, entity_device = en3, entity_type = Ethernet, name(k) = "bluetooth-pan-gn", builtin = FALSE, order = 15 (BluetoothPAN_GN), prefs = 0x7fa05ee05810, service = 3348B7DC-0F04-49AC-84FF-6D00B417A932}
2021-06-22 22:12:49.221 a.out[10856:92277] State:/Network/Service/3348B7DC-0F04-49AC-84FF-6D00B417A932/DNS
2021-06-22 22:12:49.221 a.out[10856:92277] DNS dict: (null)
2021-06-22 22:12:49.221 a.out[10856:92277] > i = 1
2021-06-22 22:12:49.222 a.out[10856:92277] <SCNetworkInterface 0x7fa05ec07d10 [0x7fff807f9b70]> {type = IEEE80211, entity_device = en0, entity_type = Ethernet, name(k) = "airport", address = 18:65:90:d3:53:e3, builtin = TRUE, path = IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/RP03@1C,2/IOPP/ARPT@0/AirPort_BrcmNIC/en0, entryID = 0x100000376, type = 6, unit = 0, order = 11 (AirPort), prefs = 0x7fa05ee05810, service = 2CC351F0-1C0D-416F-BB89-77A3F7ECFEEE}
2021-06-22 22:12:49.222 a.out[10856:92277] State:/Network/Service/2CC351F0-1C0D-416F-BB89-77A3F7ECFEEE/DNS
2021-06-22 22:12:49.223 a.out[10856:92277] DNS dict: {
    ServerAddresses =     (
        "192.168.43.60",
        "2408:840c:de3e:ecbd::2a"
    );
}
2021-06-22 22:12:49.223 a.out[10856:92277] > i = 2
2021-06-22 22:12:49.225 a.out[10856:92277] <SCNetworkInterface 0x7fa05ef06160 [0x7fff807f9b70]> {type = Bridge, entity_device = bridge0, entity_type = Ethernet, name(k) = "thunderbolt-bridge", address = 82:13:21:4d:c9:00, builtin = TRUE, order = 21 (Bridge), prefs = 0x7fa05ee05810, service = 476D71DB-D464-4560-9DF7-D506EB5AB172, interfaces = en1,en2, options = <dictionary> {
  __AUTO__ : thunderbolt-bridge
}}
2021-06-22 22:12:49.225 a.out[10856:92277] State:/Network/Service/476D71DB-D464-4560-9DF7-D506EB5AB172/DNS
2021-06-22 22:12:49.225 a.out[10856:92277] DNS dict: (null)

@leiless
Copy link
Author

leiless commented Jun 22, 2021

global_dns.m

/**
 * Get global DNS addresses on macOS
 * see:
 *  https://github.com/seladb/PcapPlusPlus/blob/master/Pcap%2B%2B/src/PcapLiveDeviceList.cpp#L163
 */

#import <Foundation/Foundation.h>
#import <SystemConfiguration/SystemConfiguration.h>

int main(void) {
    CFStringRef callerName = CFSTR("foobar");

	SCDynamicStoreRef dynRef = SCDynamicStoreCreate(kCFAllocatorSystemDefault, callerName, NULL, NULL);
	if (dynRef == NULL) {
		NSLog(@"Couldn't set DNS server list: failed to retrieve SCDynamicStore");
		return 1;
	}

	CFDictionaryRef dnsDict = (CFDictionaryRef)SCDynamicStoreCopyValue(dynRef, CFSTR("State:/Network/Global/DNS"));
	if (dnsDict == NULL) {
		NSLog(@"Couldn't set DNS server list: failed to get DNS dictionary");
		CFRelease(dynRef);
		return 1;
	}

    NSLog(@"%@", dnsDict);

    CFRelease(dynRef);
    CFRelease(dnsDict);

    return 0;
}

Sample output

gcc -Wall -Wextra -lobjc -framework Foundation -framework SystemConfiguration global_dns.m


$ ./a.out
2021-06-22 22:29:44.876 a.out[11381:101072] {
    ServerAddresses =     (
        "192.168.200.1"
    );
    "__CONFIGURATION_ID__" = "Default: 0";
    "__FLAGS__" = 2;
    "__IF_INDEX__" = 5;
    "__ORDER__" = 0;
}


$ ./a.out
2021-06-22 22:30:47.812 a.out[11464:101860] {
    ServerAddresses =     (
        "2408:840c:de3e:ecbd::2a",
        "192.168.43.60"
    );
    "__CONFIGURATION_ID__" = "Default: 0";
    "__FLAGS__" = 6;
    "__IF_INDEX__" = 5;
    "__ORDER__" = 0;
}

@leiless
Copy link
Author

leiless commented Jun 22, 2021

Other commands

scutil --dns
networksetup -getdnsservers Wi-Fi
ipconfig getpacket en0

nm `which networksetup` | grep -Ev "^[0-9a-z]+\s"
nm `which scutil` | grep -Ev "^[0-9a-z]+\s"
nm `which ifconfig` | grep -Ev "^[0-9a-z]+\s"
nm `which ipconfig` | grep -Ev "^[0-9a-z]+\s"

scutil
> list
...

> show State:/Network/Interface
<dictionary> {
  Interfaces : <array> {
    0 : lo0
    1 : gif0
    2 : stf0
    3 : XHC20
    4 : en0
    5 : en1
    6 : en2
    7 : bridge0
    8 : p2p0
    9 : awdl0
    10 : llw0
    11 : utun0
    12 : utun1
  }
}

> show State:/Network/Global/DNS
<dictionary> {
  ServerAddresses : <array> {
    0 : 192.168.200.1
  }
  __CONFIGURATION_ID__ : Default: 0
  __FLAGS__ : 2
  __IF_INDEX__ : 5
  __ORDER__ : 0
}

> show State:/Network/Service/2CC351F0-1C0D-416F-BB89-77A3F7ECFEEE/DHCP
<dictionary> {
  LeaseExpirationTime : 06/23/2021 22:31:24
  LeaseStartTime : 06/22/2021 22:31:24
  Option_1 : <data> 0xffffff00
  Option_252 : <data> 0x0a
  Option_3 : <data> 0xc0a8c801
  Option_51 : <data> 0x00015180
  Option_53 : <data> 0x05
  Option_54 : <data> 0xc0a8c801
  Option_58 : <data> 0x0000a8c0
  Option_59 : <data> 0x00012750
  Option_6 : <data> 0xc0a8c801
}
# Option_1: Subnet Mask
# Option_3: Router
# Option_6: Domain Server
# SEE ALSO: https://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xhtml

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment