ohmu
·
2026-10-15
1#include "detection/dns/dns.h"
2
3#include "common/io.h"
4#include "common/mallocHelper.h"
5#include "common/strutil.h"
6#include "common/apple/cf_helpers.h"
7#include "common/debug.h"
8
9#include <SystemConfiguration/SystemConfiguration.h>
10
11static const char* detectDnsFromConf(const char* path, FFDNSOptions* options, FFlist* results) {
12 FF_DEBUG("Attempting to read DNS config from %s", path);
13
14 FF_AUTO_CLOSE_FILE FILE* file = fopen(path, "r");
15 if (!file) {
16 FF_DEBUG("Failed to open %s: %s", path, strerror(errno));
17 return "fopen(path, r) failed";
18 }
19
20 if (results->length > 0) {
21 FF_DEBUG("Clearing existing DNS entries (%u entries)", results->length);
22 FF_LIST_FOR_EACH (FFstrbuf, item, *results) {
23 ffStrbufDestroy(item);
24 }
25 ffListClear(results);
26 }
27
28 FF_AUTO_FREE char* line = nullptr;
29 size_t len = 0;
30
31 while (getline(&line, &len, file) != -1) {
32 if (ffStrStartsWith(line, "nameserver")) {
33 char* nameserver = line + strlen("nameserver");
34 while (*nameserver == ' ' || *nameserver == '\t') {
35 nameserver++;
36 }
37 if (*nameserver == '\0') {
38 continue;
39 }
40
41 char* comment = strchr(nameserver, '#');
42 if (comment) {
43 *comment = '\0';
44 }
45
46 if ((ffStrContainsC(nameserver, ':') && !(options->showType & FF_DNS_TYPE_IPV6_BIT)) ||
47 (ffStrContainsC(nameserver, '.') && !(options->showType & FF_DNS_TYPE_IPV4_BIT))) {
48 continue;
49 }
50
51 FFstrbuf* item = FF_LIST_ADD(FFstrbuf, *results);
52 ffStrbufInitS(item, nameserver);
53 ffStrbufTrimRightSpace(item);
54 FF_DEBUG("Found DNS server: %s", item->chars);
55 }
56 }
57
58 FF_DEBUG("Found %u DNS servers in %s", results->length, path);
59 return nullptr;
60}
61
62const char* ffDetectDNS(FFDNSOptions* options, FFlist* results) {
63 // Handle macOS-specific DNS configurations
64 FF_DEBUG("Using SystemConfiguration framework for macOS");
65
66 // Create a reference to the dynamic store
67 FF_CFTYPE_AUTO_RELEASE SCDynamicStoreRef store = SCDynamicStoreCreate(nullptr, CFSTR("fastfetch"), nullptr, nullptr);
68 if (store) {
69 // Get the network global IPv4 and IPv6 configuration
70 FF_CFTYPE_AUTO_RELEASE CFStringRef key = SCDynamicStoreKeyCreateNetworkGlobalEntity(nullptr, kSCDynamicStoreDomainState, kSCEntNetDNS);
71 if (key) {
72 FF_CFTYPE_AUTO_RELEASE CFDictionaryRef dict = SCDynamicStoreCopyValue(store, key);
73 if (dict) {
74 // Get the DNS server addresses array
75 CFArrayRef dnsServers = CFDictionaryGetValue(dict, kSCPropNetDNSServerAddresses);
76
77 if (dnsServers) {
78 FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
79 for (CFIndex i = 0; i < CFArrayGetCount(dnsServers); i++) {
80 if (ffCfStrGetString(CFArrayGetValueAtIndex(dnsServers, i), &buffer) == nullptr) {
81 // Check if the address matches our filter
82 if ((ffStrbufContainC(&buffer, ':') && !(options->showType & FF_DNS_TYPE_IPV6_BIT)) ||
83 (ffStrbufContainC(&buffer, '.') && !(options->showType & FF_DNS_TYPE_IPV4_BIT))) {
84 continue;
85 }
86
87 // Add to results
88 FFstrbuf* item = FF_LIST_ADD(FFstrbuf, *results);
89 ffStrbufInitMove(item, &buffer);
90 FF_DEBUG("Found DNS server on macOS: %s", item->chars);
91 }
92 }
93 }
94 }
95 }
96 }
97
98 // If we didn't find any servers, try resolv.conf as fallback
99 if (results->length > 0) {
100 return nullptr;
101 }
102
103 FF_DEBUG("No DNS servers found via SystemConfiguration, trying resolv.conf");
104 // Try standard resolv.conf location on macOS as a fallback
105 return detectDnsFromConf("/var/run/resolv.conf", options, results);
106}