我正在开发监视公司网络中机器的应用程序。 每台机器都会运行我的应用程序,并且会跟踪许多有关机器状态的信息。
我要跟踪的一件事是网络配置。
我可以轻松获取网络设备列表(SCNetworkInterfaceCopyAll),也可以获取其MAC地址或BSD名称。
获取两个协议(IPv4和IPv6)的机器IP地址信息时遇到问题。
我尝试使用SCNetworkInterfaceGetConfiguration和SCNetworkInterfaceGetExtendedConfiguration,但是我只有空值,并且SCError返回kSCStatusInvalidArgument。
在使用SCNetworkInterfaceGetExtendedConfiguration
的情况下,我使用了以下值:kSCEntNetIPSec
,kSCEntNetIPv4
,kSCEntNetIPv6
。
文档不够精确清晰,因此我在found some project中使用了此API,这给了我一些提示,但仍然无济于事。
我做错了什么?
这里有一些我用来探索API的测试代码(因为我正在将应用程序移植到Mac,所以它是C ++代码):
#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;
}
答案 0 :(得分:0)
感谢@Hofi和@johnelemans提供帮助。这些提示足以找到答案。 对于可能存在类似问题的其他人:
要获取Mac地址SCDynamicStore,必须使用。由此,我可以fetch BSD name,稍后需要它来获取连接详细信息。
现在使用SCDynamicStore API有点奇怪。
要探索可以做什么,可以使用命令行工具scutil
。
最好在没有参数的情况下运行它并键入以下命令:
list
list State:/Network/Interfaces/.*
get State:/Network/Interface/en0/IPv6
d.show
我找到了examples here。
基于从该工具获得的信息,我提出了如何获取所需数据的方法。 C ++中的测试代码:
#include <iostream>
#include <string>
#include <SystemConfiguration/SystemConfiguration.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 exploreServiceQuery(CFStringRef query, CFStringRef serviceId, SCDynamicStoreRef scSession) {
auto resolvedQuery =
CFStringCreateWithFormat(kCFAllocatorDefault,
NULL,
query, serviceId);
auto dic = (CFDictionaryRef)SCDynamicStoreCopyValue(scSession,
resolvedQuery);
std::cout << resolvedQuery << " - " << LOGCF(dic) << '\n';
myRelease(dic);
CFRelease(resolvedQuery);
}
void printIpv4Data(SCDynamicStoreRef scSession,
CFStringRef bsdName) {
exploreServiceQuery(CFSTR("State:/Network/Interface/%@/IPv4"),
bsdName,
scSession);
}
void printIpv6Data(SCDynamicStoreRef scSession,
CFStringRef bsdName) {
exploreServiceQuery(CFSTR("State:/Network/Interface/%@/IPv6"),
bsdName,
scSession);
}
void desiriedData() {
auto allInterfaces = SCNetworkInterfaceCopyAll();
auto scSession = SCDynamicStoreCreate(kCFAllocatorDefault,
CFSTR("Custom"),
NULL,
NULL);
auto count = CFArrayGetCount(allInterfaces);
for (CFIndex i = 0; i < count; ++i) {
auto netInterface = (SCNetworkInterfaceRef)CFArrayGetValueAtIndex(allInterfaces, i);
auto macString = SCNetworkInterfaceGetHardwareAddressString(netInterface);
auto bsdName = SCNetworkInterfaceGetBSDName(netInterface);
std::cout << bsdName << " " << macString << '\n';
printIpv4Data(scSession, bsdName);
printIpv6Data(scSession, bsdName);
}
CFRelease(scSession);
CFRelease(allInterfaces);
}
int main(int argc, const char * argv[]) {
desiriedData();
return 0;
}