#include <snmp.h>
#pragma comment(lib, "snmpapi.lib")
#pragma comment(lib, "Ws2_32.lib")
bool
GetMacBySNMP(std::string& macOUT)
{
bool ret = false;
WSADATA WinsockData;
if (WSAStartup(MAKEWORD(2, 0), &WinsockData) != 0)
return false;
// Load the SNMP dll and get the addresses of the functions necessary
const HINSTANCE m_dll = LoadLibrary("inetmib1.dll");
if (m_dll < (HINSTANCE) HINSTANCE_ERROR)
return false;
const PFNSNMPEXTENSIONINIT f_SnmpExtensionInit = (PFNSNMPEXTENSIONINIT) GetProcAddress(m_dll, "SnmpExtensionInit");
const PFNSNMPEXTENSIONINITEX f_SnmpExtensionInitEx = (PFNSNMPEXTENSIONINITEX) GetProcAddress(m_dll, "SnmpExtensionInitEx");
const PFNSNMPEXTENSIONQUERY f_SnmpExtensionQuery = (PFNSNMPEXTENSIONQUERY) GetProcAddress(m_dll, "SnmpExtensionQuery");
const PFNSNMPEXTENSIONTRAP f_SnmpExtensionTrap = (PFNSNMPEXTENSIONTRAP) GetProcAddress(m_dll, "SnmpExtensionTrap");
HANDLE pollForTrapEvent;
AsnObjectIdentifier supportedView;
f_SnmpExtensionInit(GetTickCount(), &pollForTrapEvent, &supportedView);
// Initialize the variable list to be retrieved by f_SnmpExtensionQuery
const AsnObjectIdentifier MIB_NULL = { 0, 0 };
RFC1157VarBind varBind[2];
varBind[0].name = MIB_NULL;
varBind[1].name = MIB_NULL;
RFC1157VarBindList varBindList;
varBindList.list = varBind;
UINT OID_ifEntryType[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 3 };
UINT OID_ifEntryNum[] = { 1, 3, 6, 1, 2, 1, 2, 1 };
UINT OID_ipMACEntAddr[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 6 };
AsnObjectIdentifier MIB_ifMACEntAddr = { sizeof(OID_ipMACEntAddr) / sizeof(UINT), OID_ipMACEntAddr };
AsnObjectIdentifier MIB_ifEntryType = { sizeof(OID_ifEntryType) / sizeof(UINT), OID_ifEntryType };
AsnObjectIdentifier MIB_ifEntryNum = { sizeof(OID_ifEntryNum) / sizeof(UINT), OID_ifEntryNum };
// Copy in the OID to find the number of entries in the Inteface table
varBindList.len = 1; // Only retrieving one item
SnmpUtilOidCpy(&varBind[0].name, &MIB_ifEntryNum);
AsnInteger errorStatus;
AsnInteger errorIndex;
f_SnmpExtensionQuery(ASN_RFC1157_GETNEXTREQUEST, &varBindList, &errorStatus, &errorIndex);
varBindList.len = 2;
// Copy in the OID of ifType, the type of interface
SnmpUtilOidCpy(&varBind[0].name, &MIB_ifEntryType);
// Copy in the OID of ifPhysAddress, the address
SnmpUtilOidCpy(&varBind[1].name, &MIB_ifMACEntAddr);
for(int j = 0; j < varBind[0].value.asnValue.number; j++)
{
// Submit the query. Responses will be loaded into varBindList.
// We can expect this call to succeed a # of times corresponding to the # of adapters reported to be in the system
if(f_SnmpExtensionQuery(ASN_RFC1157_GETNEXTREQUEST, &varBindList, &errorStatus, &errorIndex) == FALSE)
continue;
// Confirm that the proper type has been returned
if(SnmpUtilOidNCmp(&varBind[0].name, &MIB_ifEntryType, MIB_ifEntryType.idLength) != 0)
continue;
// Type 6 describes ethernet interfaces
if(varBind[0].value.asnValue.number != 6)
continue;
// Confirm that we have an address here
if(SnmpUtilOidNCmp(&varBind[1].name, &MIB_ifMACEntAddr, MIB_ifMACEntAddr.idLength) != 0)
continue;
if(varBind[1].value.asnValue.address.stream == NULL)
continue;
// Ignore all dial-up networking adapters
if ((varBind[1].value.asnValue.address.stream[0] == 0x44)
&& (varBind[1].value.asnValue.address.stream[1] == 0x45)
&& (varBind[1].value.asnValue.address.stream[2] == 0x53)
&& (varBind[1].value.asnValue.address.stream[3] == 0x54)
&& (varBind[1].value.asnValue.address.stream[4] == 0x00))
continue;
// Ignore NULL addresses returned by other network interfaces
if ((varBind[1].value.asnValue.address.stream[0] == 0x00)
&& (varBind[1].value.asnValue.address.stream[1] == 0x00)
&& (varBind[1].value.asnValue.address.stream[2] == 0x00)
&& (varBind[1].value.asnValue.address.stream[3] == 0x00)
&& (varBind[1].value.asnValue.address.stream[4] == 0x00)
&& (varBind[1].value.asnValue.address.stream[5] == 0x00))
continue;
char buf[32];
sprintf(buf, "%02X-%02X-%02X-%02X-%02X-%02X",
varBind[1].value.asnValue.address.stream[0],
varBind[1].value.asnValue.address.stream[1],
varBind[1].value.asnValue.address.stream[2],
varBind[1].value.asnValue.address.stream[3],
varBind[1].value.asnValue.address.stream[4],
varBind[1].value.asnValue.address.stream[5]);
macOUT = buf;
ret = true;
break;
}
// Free the bindings
SnmpUtilVarBindFree(&varBind[0]);
SnmpUtilVarBindFree(&varBind[1]);
return ret;
}