Background
I'm developing application which monitors machines in corporate network. Each machines will run my application and it tracks many things regarding machine status.
One of the things I want to track is network configuration.
- list of network interfaces
- ipv4
- ipv6
- name
Question
I have no problem to get list of the network devices (SCNetworkInterfaceCopyAll), or fetching its MAC address or BSD name.
I have problem fetching information about machine IP address for both protocols (IPv4 and IPv6).
I've tried use SCNetworkInterfaceGetConfiguration and SCNetworkInterfaceGetExtendedConfiguration, but I've got only null values and SCError returns kSCStatusInvalidArgument.
In case of SCNetworkInterfaceGetExtendedConfiguration
I used values: kSCEntNetIPSec
, kSCEntNetIPv4
, kSCEntNetIPv6
.
Documentation is not precise and clear, so I've found some project where this API is used, this give me some hints, but still doesn't help.
What I'm doing wrong?
Here some test code I'm using to explore API (it is C++ code since I'm porting application to Mac):
#include <iostream>
#include <string>
#include <SystemConfiguration/SystemConfiguration.h>
#include <SystemConfiguration/SCPreferences.h>
#include <SystemConfiguration/SCNetwork.h>
#include <SystemConfiguration/SCNetworkReachability.h>
#include <SystemConfiguration/SCNetworkConnection.h>
#include <SystemConfiguration/SCNetworkConfiguration.h>
#include <CoreFoundation/CoreFoundation.h>
inline void myRelease(CFTypeRef p)
{
if (p) CFRelease(p);
}
inline std::string toStd(CFStringRef s)
{
if (!s) {
return {};
}
if (auto fastCString = CFStringGetCStringPtr(s, kCFStringEncodingUTF8)) {
return fastCString;
}
auto len = CFStringGetLength(s);
auto size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(s), kCFStringEncodingUTF8) + 1;
std::string result(size, '\0');
CFStringGetBytes(s, { 0, len }, kCFStringEncodingUTF8, '?', 0,
reinterpret_cast<UInt8 *>(&result[0]), result.size(), &size);
result.resize(size);
return result;
}
std::ostream &operator<<(std::ostream &out, CFStringRef s) {
return out << toStd(s);
}
struct DebugCf {
DebugCf(CFTypeRef p) : mP(p) {}
std::string toString() const {
if (!mP) {
return "<null>";
}
auto idOfType = CFGetTypeID(mP);
if (CFStringGetTypeID() == idOfType) {
return toStd((CFStringRef)mP);
}
auto s = CFCopyDescription(mP);
auto result = toStd(s);
CFRelease(s);
return result;
}
private:
CFTypeRef mP;
};
std::ostream &operator<<(std::ostream &out, const DebugCf d) {
return out << d.toString();
}
#define LOGCF(x) " " #x "["<< DebugCf(x) << "], "
std::string SCErrorString()
{
switch (SCError()) {
case kSCStatusOK: return "OK";
case kSCStatusFailed: return "Failed";
case kSCStatusInvalidArgument: return "InvalidArgument";
case kSCStatusAccessError: return "AccessError";
case kSCStatusNoKey: return "NoKey";
case kSCStatusKeyExists: return "KeyExists";
case kSCStatusLocked: return "Locked";
case kSCStatusNeedLock: return "NeedLock";
case kSCStatusNoStoreSession: return "NoStoreSession";
case kSCStatusNoStoreServer: return "NoStoreServer";
case kSCStatusNotifierActive: return "NotifierActive";
case kSCStatusNoPrefsSession: return "NoPrefsSession";
case kSCStatusPrefsBusy: return "PrefsBusy";
case kSCStatusNoConfigFile: return "NoConfigFile";
case kSCStatusNoLink: return "NoLink";
case kSCStatusStale: return "Stale";
case kSCStatusMaxLink: return "MaxLink";
case kSCStatusReachabilityUnknown: return "ReachabilityUnknown";
default:
return std::to_string(SCError());
}
}
void exploreInterface(SCNetworkInterfaceRef netInterface) {
auto macString = SCNetworkInterfaceGetHardwareAddressString(netInterface);
auto bsdName = SCNetworkInterfaceGetBSDName(netInterface);
std::cout << bsdName << ' ' << macString << '\n';
CFDictionaryRef current = NULL;
CFDictionaryRef active = NULL;
CFArrayRef available = NULL;
auto result = SCNetworkInterfaceCopyMediaOptions(netInterface,
¤t,
&active,
&available,
1);
std::cout << "SCNetworkInterfaceCopyMediaOptions: "
<< (bool)result << " e=" << SCErrorString()
// << LOGCF(current) << LOGCF(active) << LOGCF(available)
<< '\n';
auto interfaceConfig = SCNetworkInterfaceGetConfiguration(netInterface);
std::cout << "SCNetworkInterfaceGetConfiguration: " << LOGCF(interfaceConfig)
<< "e = " << SCErrorString() << '\n';
auto interfaceExtConfig = SCNetworkInterfaceGetExtendedConfiguration(netInterface, kSCEntNetIPSec);
std::cout << "SCNetworkInterfaceGetExtendedConfiguration: " << LOGCF(interfaceExtConfig)
<< "e = " << SCErrorString() << '\n';
std::cout << "SCNetworkInterfaceGetInterfaceType: "
<< SCNetworkInterfaceGetInterfaceType(netInterface)
<< " SCNetworkInterfaceGetLocalizedDisplayName: "
<< SCNetworkInterfaceGetLocalizedDisplayName(netInterface) << '\n';
auto supportedProtocols = SCNetworkInterfaceGetSupportedProtocolTypes(netInterface);
std::cout << "SCNetworkInterfaceGetSupportedProtocolTypes: "
<< LOGCF(supportedProtocols) << '\n';
myRelease(current);
myRelease(active);
myRelease(available);
}
int main(int argc, const char * argv[]) {
auto allNetwork = SCNetworkInterfaceCopyAll();
auto count = CFArrayGetCount(allNetwork);
for (CFIndex i=0; i<count; ++i) {
auto netInterface = (SCNetworkInterfaceRef)CFArrayGetValueAtIndex(allNetwork, i);
exploreInterface(netInterface);
std::cout << "-------------------------\n";
}
CFRelease(allNetwork);
return 0;
}