/* Given an OID and a base OID that it must begin with, finds the item and * integer instance from the OID. E.g., given an OID foo.1.2 and a base OID * foo, returns item 1 and instance 2. * If bPduType is not SNMP_PDU_GETNEXT and either the item or instance is * missing, returns SNMP_ERRORSTATUS_NOSUCHNAME. * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item and * instance, or item 1, instance 1 if either is missing. */ static AsnInteger32 getItemAndIntegerInstanceFromOid(AsnObjectIdentifier *oid, AsnObjectIdentifier *base, BYTE bPduType, UINT *item, UINT *instance) { AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR; switch (bPduType) { case SNMP_PDU_GETNEXT: if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0) { *item = 1; *instance = 1; } else if (!SnmpUtilOidNCmp(oid, base, base->idLength)) { if (oid->idLength == base->idLength || oid->idLength == base->idLength + 1) { /* Either the table or an item within the table is specified, * but the instance is not. Get the first instance. */ *instance = 1; if (oid->idLength == base->idLength + 1) *item = oid->ids[base->idLength]; else *item = 1; } else { *item = oid->ids[base->idLength]; *instance = oid->ids[base->idLength + 1] + 1; } } else ret = SNMP_ERRORSTATUS_NOSUCHNAME; break; default: if (!SnmpUtilOidNCmp(oid, base, base->idLength)) { if (oid->idLength == base->idLength || oid->idLength == base->idLength + 1) { /* Either the table or an item within the table is specified, * but the instance is not. */ ret = SNMP_ERRORSTATUS_NOSUCHNAME; } else { *item = oid->ids[base->idLength]; *instance = oid->ids[base->idLength + 1]; } } else ret = SNMP_ERRORSTATUS_NOSUCHNAME; } return ret; }
void fixupql(SnmpMgmtQueryList *ql, UINT *errorStatus, UINT *errorIndex) { UINT v; // index into view list UINT q; // index into queue list UINT vb; // index into varbind list // process queries for (q=0; (q < ql->len) && !(*errorStatus); q++) { SNMPDBG((SNMP_LOG_TRACE, "SNMP: PDU: validating query 0x%08lx.\n", ql->query[q].addr)); // process variable bindings gathered for (vb=0; (vb < ql->query[q].vbl.len) && !(*errorStatus); vb++) { // calculate view index v = ql->query[q].xlat[vb].view; // check oid returned from subagent if (0 < SnmpUtilOidNCmp( &ql->query[q].vbl.list[vb].name, &extAgents[vl[v]].supportedView, extAgents[vl[v]].supportedView.idLength )) { // retry getnext using next view nextvb(&ql->query[q], vb, v, errorStatus, errorIndex); } } } } // end fixupql()
static struct mibImplementation *findSupportedQuery(UINT *ids, UINT idLength, UINT *matchingIndex) { int indexHigh = DEFINE_SIZEOF(supportedIDs) - 1, indexLow = 0, i; struct mibImplementation *impl = NULL; AsnObjectIdentifier oid1 = { idLength, ids}; if (!idLength) return NULL; for (i = (indexLow + indexHigh) / 2; !impl && indexLow <= indexHigh; i = (indexLow + indexHigh) / 2) { INT cmp; cmp = SnmpUtilOidNCmp(&oid1, &supportedIDs[i].name, idLength); if (!cmp) { impl = &supportedIDs[i]; *matchingIndex = i; } else if (cmp > 0) indexLow = i + 1; else indexHigh = i - 1; } return impl; }
static BOOL mib2IfNumberQuery(BYTE bPduType, SnmpVarBind *pVarBind, AsnInteger32 *pErrorStatus) { AsnObjectIdentifier numberOid = DEFINE_OID(mib2IfNumber); BOOL ret = TRUE; TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name), pErrorStatus); switch (bPduType) { case SNMP_PDU_GET: case SNMP_PDU_GETNEXT: if ((bPduType == SNMP_PDU_GET && !SnmpUtilOidNCmp(&pVarBind->name, &numberOid, numberOid.idLength)) || SnmpUtilOidNCmp(&pVarBind->name, &numberOid, numberOid.idLength) < 0) { DWORD numIfs = ifTable ? ifTable->dwNumEntries : 0; copyInt(&pVarBind->value, &numIfs); if (bPduType == SNMP_PDU_GETNEXT) { SnmpUtilOidFree(&pVarBind->name); SnmpUtilOidCpy(&pVarBind->name, &numberOid); } *pErrorStatus = SNMP_ERRORSTATUS_NOERROR; } else { *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; /* Caller deals with OID if bPduType == SNMP_PDU_GETNEXT, so don't * need to set it here. */ } break; case SNMP_PDU_SET: *pErrorStatus = SNMP_ERRORSTATUS_READONLY; ret = FALSE; break; default: FIXME("0x%02x: unsupported PDU type\n", bPduType); *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; } return ret; }
/*********************************************************************** * SnmpUtilOidCmp (SNMPAPI.@) */ INT WINAPI SnmpUtilOidCmp(AsnObjectIdentifier *oid1, AsnObjectIdentifier *oid2) { TRACE("(%p, %p)\n", oid1, oid2); if (oid1->idLength < oid2->idLength) return -1; if (oid1->idLength > oid2->idLength) return 1; return SnmpUtilOidNCmp(oid1, oid2, oid1->idLength); }
/* Given an OID and a base OID that it must begin with, finds the item from the * OID. E.g., given an OID foo.1 and a base OID foo, returns item 1. * If bPduType is not SNMP_PDU_GETNEXT and the item is missing, returns * SNMP_ERRORSTATUS_NOSUCHNAME. * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item, or item * 1 if the item is missing. */ static AsnInteger32 getItemFromOid(AsnObjectIdentifier *oid, AsnObjectIdentifier *base, BYTE bPduType, UINT *item) { AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR; switch (bPduType) { case SNMP_PDU_GETNEXT: if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0) *item = 1; else if (!SnmpUtilOidNCmp(oid, base, base->idLength)) { if (oid->idLength == base->idLength) { /* The item is missing, assume the first item */ *item = 1; } else *item = oid->ids[base->idLength] + 1; } else ret = SNMP_ERRORSTATUS_NOSUCHNAME; break; default: if (!SnmpUtilOidNCmp(oid, base, base->idLength)) { if (oid->idLength == base->idLength) { /* The item is missing */ ret = SNMP_ERRORSTATUS_NOSUCHNAME; } else { *item = oid->ids[base->idLength]; if (!*item) ret = SNMP_ERRORSTATUS_NOSUCHNAME; } } else ret = SNMP_ERRORSTATUS_NOSUCHNAME; } return ret; }
static struct mibImplementation *findSupportedQuery(UINT *ids, UINT idLength, UINT *matchingIndex) { int indexHigh = DEFINE_SIZEOF(supportedIDs) - 1, indexLow = 0; AsnObjectIdentifier oid1 = { idLength, ids}; if (!idLength) return NULL; while (indexLow <= indexHigh) { INT cmp, i = (indexLow + indexHigh) / 2; if (!(cmp = SnmpUtilOidNCmp(&oid1, &supportedIDs[i].name, idLength))) { *matchingIndex = i; return &supportedIDs[i]; } if (cmp > 0) indexLow = i + 1; else indexHigh = i - 1; } return NULL; }
//通过SNMP(简单网络访问协议) bool GetMacAddressBySNMP(std::string &mac_address) { bool ret = false; WSADATA winsock_data; if (WSAStartup(MAKEWORD(2, 0), &winsock_data) != 0) return false; // Load the SNMP dll and get the addresses of the functions necessary const HINSTANCE m_dll = LoadLibrary(L"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 poll_for_trap_event; AsnObjectIdentifier supported_view; f_SnmpExtensionInit(GetTickCount(), &poll_for_trap_event, &supported_view); // Initialize the variable list to be retrieved by f_SnmpExtensionQuery const AsnObjectIdentifier MIB_NULL = { 0, 0 }; RFC1157VarBind var_bind[2]; var_bind[0].name = MIB_NULL; var_bind[1].name = MIB_NULL; RFC1157VarBindList var_bind_list; var_bind_list.list = var_bind; 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 var_bind_list.len = 1; // Only retrieving one item SnmpUtilOidCpy(&var_bind[0].name, &MIB_ifEntryNum); AsnInteger errorStatus; AsnInteger errorIndex; f_SnmpExtensionQuery(ASN_RFC1157_GETNEXTREQUEST, &var_bind_list, &errorStatus, &errorIndex); var_bind_list.len = 2; // Copy in the OID of ifType, the type of interface SnmpUtilOidCpy(&var_bind[0].name, &MIB_ifEntryType); // Copy in the OID of ifPhysAddress, the address SnmpUtilOidCpy(&var_bind[1].name, &MIB_ifMACEntAddr); for(int j = 0; j < var_bind[0].value.asnValue.number; j++) { // Submit the query. Responses will be loaded into var_bind_list. // 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, &var_bind_list, &errorStatus, &errorIndex) == FALSE) continue; // Confirm that the proper type has been returned if(SnmpUtilOidNCmp(&var_bind[0].name, &MIB_ifEntryType, MIB_ifEntryType.idLength) != 0) continue; // Type 6 describes ethernet interfaces if(var_bind[0].value.asnValue.number != 6) continue; // Confirm that we have an address here if(SnmpUtilOidNCmp(&var_bind[1].name, &MIB_ifMACEntAddr, MIB_ifMACEntAddr.idLength) != 0) continue; if(var_bind[1].value.asnValue.address.stream == NULL) continue; // Ignore all dial-up networking adapters if ((var_bind[1].value.asnValue.address.stream[0] == 0x44) && (var_bind[1].value.asnValue.address.stream[1] == 0x45) && (var_bind[1].value.asnValue.address.stream[2] == 0x53) && (var_bind[1].value.asnValue.address.stream[3] == 0x54) && (var_bind[1].value.asnValue.address.stream[4] == 0x00)) continue; // Ignore NULL addresses returned by other network interfaces if ((var_bind[1].value.asnValue.address.stream[0] == 0x00) && (var_bind[1].value.asnValue.address.stream[1] == 0x00) && (var_bind[1].value.asnValue.address.stream[2] == 0x00) && (var_bind[1].value.asnValue.address.stream[3] == 0x00) && (var_bind[1].value.asnValue.address.stream[4] == 0x00) && (var_bind[1].value.asnValue.address.stream[5] == 0x00)) continue; StringPrintf(mac_address, "%02x-%02x-%02x-%02x-%02x-%02x", var_bind[1].value.asnValue.address.stream[0], var_bind[1].value.asnValue.address.stream[1], var_bind[1].value.asnValue.address.stream[2], var_bind[1].value.asnValue.address.stream[3], var_bind[1].value.asnValue.address.stream[4], var_bind[1].value.asnValue.address.stream[5]); ret = true; break; } // Free the bindings SnmpUtilVarBindFree(&var_bind[0]); SnmpUtilVarBindFree(&var_bind[1]); return ret; }
BOOL CSNMP::SnmpQueryTable( LPCTSTR apColumnOidList[], UINT nListLen, std::vector<std::pair<CString, std::vector<AsnAny>>> *pTable ) { if (!apColumnOidList || !pTable) { m_strLastError = L"[SnmpQueryTable] : Verify the arguments failed. "; return FALSE; } pTable->clear(); if (!nListLen) return TRUE; typedef std::map<CString, AsnAny> RELATIVE_OID_TO_VALUE_MAP; std::vector<RELATIVE_OID_TO_VALUE_MAP> vColumnRelativeOidToValue(nListLen); SnmpVarBindList CurrentVarBindList; CurrentVarBindList.len = 0; CurrentVarBindList.list = NULL; AsnObjectIdentifier TargetObjectIdentifier; TargetObjectIdentifier.idLength = 0; TargetObjectIdentifier.ids = NULL; BOOL bRes = FALSE; do { UINT i = 0; for (; i < nListLen; i++) { SnmpUtilVarBindListFree(&CurrentVarBindList); CurrentVarBindList.len = 1; CurrentVarBindList.list = (SnmpVarBind *)SnmpUtilMemAlloc(sizeof(SnmpVarBind)); CurrentVarBindList.list->name.idLength = 0; CurrentVarBindList.list->name.ids = NULL; CurrentVarBindList.list->value.asnType = ASN_NULL; #ifdef _UNICODE CStringA strOIDA = XLibS::StringCode::ConvertWideStrToAnsiStr(apColumnOidList[i]); #else CStringA strOIDA = apColumnOidList[i]; #endif if(!::SnmpMgrStrToOid(strOIDA.GetBuffer(), &CurrentVarBindList.list->name) || !CurrentVarBindList.list->name.ids || !CurrentVarBindList.list->name.idLength) { #ifdef _UNICODE CStringW strOIDW = apColumnOidList[i]; #else CStringW strOIDW = XLibS::StringCode::ConvertAnsiStrToWideStr(apColumnOidList[i]); #endif m_strLastError.Format(L"[SnmpQueryTable] : Bad OID string \"%s\". ", (LPCWSTR)strOIDW); strOIDA.ReleaseBuffer(); break; } strOIDA.ReleaseBuffer(); SnmpUtilOidFree(&TargetObjectIdentifier); TargetObjectIdentifier.idLength = 0; TargetObjectIdentifier.ids = NULL; if (!SnmpUtilOidCpy(&TargetObjectIdentifier, &CurrentVarBindList.list->name) || !TargetObjectIdentifier.ids || !TargetObjectIdentifier.idLength) { m_strLastError.Format(L"[SnmpQueryTable] : Copy OID failed. "); break; } BOOL bFailFlag = FALSE; while(1) { AsnInteger nSNMPErrorCode = 0; AsnInteger nSNMPErrorIndex = 0; if(!::SnmpMgrRequest(m_SnmpSession, SNMP_PDU_GETNEXT, &CurrentVarBindList, &nSNMPErrorCode, &nSNMPErrorIndex)) { DWORD dwLastWinError = ::GetLastError(); assert(nSNMPErrorIndex == 0); const WCHAR * SNMP_ERROR_MESSAGE[] = { L"The agent reports that no errors occurred during transmission. ", L"The agent could not place the results of the requested operation into a single SNMP message. ", L"The requested operation identified an unknown variable. ", L"The requested operation tried to change a variable but it specified either a syntax or value error. ", L"The requested operation tried to change a variable that was not allowed to change according to the community profile of the variable. " }; const WCHAR * WIN_ERROR_MESSAGE[] = {L"The request timed-out.", L"Unexpected error file descriptors indicated by the Windows Sockets select function." }; const WCHAR *pSNMPError = NULL; if (nSNMPErrorIndex < ARRAYSIZE(SNMP_ERROR_MESSAGE)) pSNMPError = SNMP_ERROR_MESSAGE[nSNMPErrorIndex]; else pSNMPError = L"Unknown error. "; const WCHAR *pWinError = NULL; if (dwLastWinError - 40 < ARRAYSIZE(WIN_ERROR_MESSAGE)) pWinError = WIN_ERROR_MESSAGE[dwLastWinError - 40]; else pWinError = L"Unknown error. "; m_strLastError.Format(L"SNMP requesting failed. SNMP ERROR : %s (%ld). WIN ERROR : %s (%lu). ", pSNMPError, nSNMPErrorIndex, pWinError, dwLastWinError); // LPCWSTR pSysError = NULL; // m_strLastError.Format(L"SNMP requesting failed. SNMP ERROR : %s (%ld). ", pError, nErrorIndex); // if (::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, // NULL, dwLastError, 0, (LPTSTR)&pSysError, 0, NULL) && pSysError) // { // m_strLastError.AppendFormat(L"Windows ERROR: %s (%lu). ", pSysError, dwLastError); // // ::LocalFree((HLOCAL)pSysError); // pSysError = NULL; // } bFailFlag = TRUE; break; } assert(SNMP_ERRORSTATUS_NOERROR == nSNMPErrorCode); if (!CurrentVarBindList.list || (!CurrentVarBindList.list->name.ids && CurrentVarBindList.list->name.idLength)) { #ifdef _UNICODE CStringW strOIDW = apColumnOidList[i]; #else CStringW strOIDW = XLibS::StringCode::ConvertAnsiStrToWideStr(apColumnOidList[i]); #endif m_strLastError.Format(L"[SnmpQueryTable] : GetNext returned a bad OID during the request for %s. ", (LPCWSTR)strOIDW); bFailFlag = TRUE; break; } if (CurrentVarBindList.list->name.idLength < TargetObjectIdentifier.idLength) break; if (SnmpUtilOidNCmp(&CurrentVarBindList.list->name, &TargetObjectIdentifier, TargetObjectIdentifier.idLength)) break; CStringA strOIDTarget = ThreadSafeSnmpUtilOidToA(&TargetObjectIdentifier); CStringA strOIDCurrent = ThreadSafeSnmpUtilOidToA(&CurrentVarBindList.list->name); assert(strOIDCurrent.Find(strOIDTarget) == 0); AsnAny value; SnmpUtilAsnAnyCpy(&value, &CurrentVarBindList.list->value); #ifdef _UNICODE CString strRelativeOID = XLibS::StringCode::ConvertAnsiStrToWideStr(strOIDCurrent.Mid(strOIDTarget.GetLength())); #else CString strRelativeOID = strOIDCurrent.Mid(strOIDTarget.GetLength()); #endif vColumnRelativeOidToValue[i].insert(std::make_pair(strRelativeOID, value)); } if (bFailFlag) break; } if (i < nListLen) break; const RELATIVE_OID_TO_VALUE_MAP & FirstCol = vColumnRelativeOidToValue[0]; for (RELATIVE_OID_TO_VALUE_MAP::const_iterator itFirstCol = FirstCol.begin(); itFirstCol != FirstCol.end(); itFirstCol++) { std::vector<RELATIVE_OID_TO_VALUE_MAP::const_iterator> vItFind; UINT i = 1; for (; i < nListLen; i++) { const RELATIVE_OID_TO_VALUE_MAP & CurrentCol = vColumnRelativeOidToValue[i]; RELATIVE_OID_TO_VALUE_MAP::const_iterator itFind = CurrentCol.find(itFirstCol->first); if (itFind == CurrentCol.end()) break; vItFind.push_back(itFind); } if (i < nListLen) continue; pTable->push_back(make_pair(itFirstCol->first, std::vector<AsnAny>(1, itFirstCol->second))); for (std::vector<RELATIVE_OID_TO_VALUE_MAP::const_iterator>::size_type i = 0; i < vItFind.size(); i++) { pTable->back().second.push_back(vItFind[i]->second); } } bRes = TRUE; } while (FALSE); SnmpUtilOidFree(&TargetObjectIdentifier); SnmpUtilVarBindListFree(&CurrentVarBindList); if (!bRes) { ClearQueryTableResult(*pTable); pTable->clear(); } return bRes; }
static void testQuery(void) { BOOL (WINAPI *pQuery)(BYTE, SnmpVarBindList *, AsnInteger32 *, AsnInteger32 *); BOOL ret, moreData, noChange; SnmpVarBindList list; AsnInteger32 error, index; UINT bogus[] = { 1,2,3,4 }; UINT mib2System[] = { 1,3,6,1,2,1,1 }; UINT mib2If[] = { 1,3,6,1,2,1,2 }; UINT mib2IfTable[] = { 1,3,6,1,2,1,2,2 }; UINT mib2IfDescr[] = { 1,3,6,1,2,1,2,2,1,2 }; UINT mib2IfAdminStatus[] = { 1,3,6,1,2,1,2,2,1,7 }; UINT mib2IfOperStatus[] = { 1,3,6,1,2,1,2,2,1,8 }; UINT mib2IpAddr[] = { 1,3,6,1,2,1,4,20,1,1 }; UINT mib2IpRouteTable[] = { 1,3,6,1,2,1,4,21,1,1 }; UINT mib2UdpTable[] = { 1,3,6,1,2,1,7,5,1,1 }; SnmpVarBind vars[3], vars2[3], vars3[3]; UINT entry; pQuery = (void *)GetProcAddress(inetmib1, "SnmpExtensionQuery"); if (!pQuery) { win_skip("couldn't find SnmpExtensionQuery\n"); return; } /* Crash ret = pQuery(0, NULL, NULL, NULL); ret = pQuery(0, NULL, &error, NULL); ret = pQuery(0, NULL, NULL, &index); ret = pQuery(0, &list, NULL, NULL); ret = pQuery(0, &list, &error, NULL); */ /* An empty list succeeds */ list.len = 0; error = 0xdeadbeef; index = 0xdeadbeef; ret = pQuery(SNMP_PDU_GET, &list, &error, &index); ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index); ok(error == SNMP_ERRORSTATUS_NOERROR, "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error); ok(index == 0, "expected index 0, got %d\n", index); /* Oddly enough, this "succeeds," even though the OID is clearly * unsupported. */ vars[0].name.idLength = sizeof(bogus) / sizeof(bogus[0]); vars[0].name.ids = bogus; vars[0].value.asnType = 0; list.len = 1; list.list = vars; SetLastError(0xdeadbeef); error = 0xdeadbeef; index = 0xdeadbeef; ret = pQuery(SNMP_PDU_GET, &list, &error, &index); ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index); ok(error == SNMP_ERRORSTATUS_NOERROR || error == ERROR_FILE_NOT_FOUND /* Win9x */, "expected SNMP_ERRORSTATUS_NOERROR or ERROR_FILE_NOT_FOUND, got %d\n", error); if (error == SNMP_ERRORSTATUS_NOERROR) ok(index == 0, "expected index 0, got %d\n", index); else if (error == ERROR_FILE_NOT_FOUND) ok(index == 1, "expected index 1, got %d\n", index); /* The OID isn't changed either: */ ok(!strcmp("1.2.3.4", SnmpUtilOidToA(&vars[0].name)), "expected 1.2.3.4, got %s\n", SnmpUtilOidToA(&vars[0].name)); /* The table is not an accessible variable, so it fails */ vars[0].name.idLength = sizeof(mib2IfTable) / sizeof(mib2IfTable[0]); vars[0].name.ids = mib2IfTable; SetLastError(0xdeadbeef); error = 0xdeadbeef; index = 0xdeadbeef; ret = pQuery(SNMP_PDU_GET, &list, &error, &index); ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index); ok(error == SNMP_ERRORSTATUS_NOSUCHNAME, "expected SNMP_ERRORSTATUS_NOSUCHNAME, got %d\n", error); /* The index is 1-based rather than 0-based */ ok(index == 1, "expected index 1, got %d\n", index); /* A Get fails on something that specifies a table (but not a particular * entry in it)... */ vars[0].name.idLength = sizeof(mib2IfDescr) / sizeof(mib2IfDescr[0]); vars[0].name.ids = mib2IfDescr; vars[1].name.idLength = sizeof(mib2IfAdminStatus) / sizeof(mib2IfAdminStatus[0]); vars[1].name.ids = mib2IfAdminStatus; vars[2].name.idLength = sizeof(mib2IfOperStatus) / sizeof(mib2IfOperStatus[0]); vars[2].name.ids = mib2IfOperStatus; list.len = 3; SetLastError(0xdeadbeef); error = 0xdeadbeef; index = 0xdeadbeef; ret = pQuery(SNMP_PDU_GET, &list, &error, &index); ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index); ok(error == SNMP_ERRORSTATUS_NOSUCHNAME, "expected SNMP_ERRORSTATUS_NOSUCHNAME, got %d\n", error); ok(index == 1, "expected index 1, got %d\n", index); /* but a GetNext succeeds with the same values, because GetNext gets the * entry after the specified OID, not the entry specified by it. The * successor to the table is the first entry in the table. * The OIDs need to be allocated, because GetNext modifies them to indicate * the end of data. */ SnmpUtilOidCpy(&vars2[0].name, &vars[0].name); SnmpUtilOidCpy(&vars2[1].name, &vars[1].name); SnmpUtilOidCpy(&vars2[2].name, &vars[2].name); list.list = vars2; moreData = TRUE; noChange = FALSE; entry = 0; do { SetLastError(0xdeadbeef); error = 0xdeadbeef; index = 0xdeadbeef; ret = pQuery(SNMP_PDU_GETNEXT, &list, &error, &index); ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index); ok(error == SNMP_ERRORSTATUS_NOERROR, "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error); ok(index == 0, "expected index 0, got %d\n", index); if (!ret) moreData = FALSE; else if (error) moreData = FALSE; else if (SnmpUtilOidNCmp(&vars2[0].name, &vars[0].name, vars[0].name.idLength)) moreData = FALSE; else if (SnmpUtilOidNCmp(&vars2[1].name, &vars[1].name, vars[1].name.idLength)) moreData = FALSE; else if (SnmpUtilOidNCmp(&vars2[2].name, &vars[2].name, vars[2].name.idLength)) moreData = FALSE; else if (!SnmpUtilOidCmp(&vars[0].name, &vars2[0].name) || !SnmpUtilOidCmp(&vars[1].name, &vars2[1].name) || !SnmpUtilOidCmp(&vars[2].name, &vars2[2].name)) { /* If the OID isn't modified, the function isn't implemented on this * platform, skip the remaining tests. */ noChange = TRUE; } if (moreData) { UINT lastID; /* Check the OIDs. For these types of values (display strings and * integers) they should increase by 1 for each element of the table * according to RFC 1158. Windows sometimes has a weird value in the * table, so allow any value as long as it's greater than the previous * value on Windows. */ ok(vars2[0].name.idLength == vars[0].name.idLength + 1, "expected length %d, got %d\n", vars[0].name.idLength + 1, vars2[0].name.idLength); lastID = vars2[0].name.ids[vars2[0].name.idLength - 1]; ok(lastID == entry + 1 || broken(lastID > entry), "expected %d, got %d\n", entry + 1, lastID); ok(vars2[1].name.idLength == vars[1].name.idLength + 1, "expected length %d, got %d\n", vars[1].name.idLength + 1, vars2[1].name.idLength); lastID = vars2[1].name.ids[vars2[1].name.idLength - 1]; ok(lastID == entry + 1 || broken(lastID > entry), "expected %d, got %d\n", entry + 1, lastID); ok(vars2[2].name.idLength == vars[2].name.idLength + 1, "expected length %d, got %d\n", vars[2].name.idLength + 1, vars2[2].name.idLength); lastID = vars2[2].name.ids[vars2[2].name.idLength - 1]; ok(lastID == entry + 1 || broken(lastID > entry), "expected %d, got %d\n", entry + 1, lastID); entry = lastID; /* Check the types while we're at it */ ok(vars2[0].value.asnType == ASN_OCTETSTRING, "expected ASN_OCTETSTRING, got %02x\n", vars2[0].value.asnType); ok(vars2[1].value.asnType == ASN_INTEGER, "expected ASN_INTEGER, got %02x\n", vars2[1].value.asnType); ok(vars2[2].value.asnType == ASN_INTEGER, "expected ASN_INTEGER, got %02x\n", vars2[2].value.asnType); } else if (noChange) skip("no change in OID, no MIB2 IF table implementation\n"); } while (moreData && !noChange); SnmpUtilVarBindFree(&vars2[0]); SnmpUtilVarBindFree(&vars2[1]); SnmpUtilVarBindFree(&vars2[2]); /* Even though SnmpExtensionInit says this DLL supports the MIB2 system * variables, on recent systems (at least Win2k) the first variable it * returns a value for is the first interface. */ vars[0].name.idLength = sizeof(mib2System) / sizeof(mib2System[0]); vars[0].name.ids = mib2System; SnmpUtilOidCpy(&vars2[0].name, &vars[0].name); vars2[0].value.asnType = 0; list.len = 1; list.list = vars2; moreData = TRUE; noChange = FALSE; ret = pQuery(SNMP_PDU_GETNEXT, &list, &error, &index); ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index); ok(error == SNMP_ERRORSTATUS_NOERROR, "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error); ok(index == 0, "expected index 0, got %d\n", index); vars3[0].name.idLength = sizeof(mib2If) / sizeof(mib2If[0]); vars3[0].name.ids = mib2If; ok(!SnmpUtilOidNCmp(&vars2[0].name, &vars[0].name, vars[0].name.idLength) || !SnmpUtilOidNCmp(&vars2[0].name, &vars3[0].name, vars3[0].name.idLength), "expected 1.3.6.1.2.1.1 or 1.3.6.1.2.1.2, got %s\n", SnmpUtilOidToA(&vars2[0].name)); SnmpUtilVarBindFree(&vars2[0]); /* Check the type and OIDs of the IP address table */ vars[0].name.idLength = sizeof(mib2IpAddr) / sizeof(mib2IpAddr[0]); vars[0].name.ids = mib2IpAddr; SnmpUtilOidCpy(&vars2[0].name, &vars[0].name); vars2[0].value.asnType = 0; list.len = 1; list.list = vars2; moreData = TRUE; do { ret = pQuery(SNMP_PDU_GETNEXT, &list, &error, &index); ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index); ok(error == SNMP_ERRORSTATUS_NOERROR, "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error); ok(index == 0, "expected index 0, got %d\n", index); if (!ret) moreData = FALSE; else if (error) moreData = FALSE; else if (SnmpUtilOidNCmp(&vars2[0].name, &vars[0].name, vars[0].name.idLength)) moreData = FALSE; else if (!SnmpUtilOidCmp(&vars2[0].name, &vars[0].name)) { /* If the OID isn't modified, the function isn't implemented on this * platform, skip the remaining tests. */ noChange = TRUE; } if (moreData) { /* Make sure the size of the OID is right. * FIXME: don't know if IPv6 addrs are shared with this table. * Don't think so, but I'm not certain. */ ok(vars2[0].name.idLength == vars[0].name.idLength + 4, "expected length %d, got %d\n", vars[0].name.idLength + 4, vars2[0].name.idLength); /* Make sure the type is right */ ok(vars2[0].value.asnType == ASN_IPADDRESS, "expected type ASN_IPADDRESS, got %02x\n", vars2[0].value.asnType); if (vars2[0].value.asnType == ASN_IPADDRESS) { UINT i; /* This looks uglier than it is: the base OID for the IP * address, 1.3.6.1.2.1.4.20.1.1, is appended with the IP * address of the entry. So e.g. the loopback address is * identified in MIB2 as 1.3.6.1.2.1.4.20.1.1.127.0.0.1 */ for (i = 0; i < vars2[0].value.asnValue.address.length; i++) { ok(vars2[0].value.asnValue.address.stream[i] == vars2[0].name.ids[vars2[0].name.idLength - 4 + i], "expected ident byte %d to be %d, got %d\n", i, vars2[0].value.asnValue.address.stream[i], vars2[0].name.ids[vars2[0].name.idLength - 4 + i]); } } } else if (noChange) skip("no change in OID, no MIB2 IP address table implementation\n"); } while (moreData && !noChange); SnmpUtilVarBindFree(&vars2[0]); /* Check the type and OIDs of the IP route table */ vars[0].name.idLength = DEFINE_SIZEOF(mib2IpRouteTable); vars[0].name.ids = mib2IpRouteTable; SnmpUtilOidCpy(&vars2[0].name, &vars[0].name); vars2[0].value.asnType = 0; list.len = 1; list.list = vars2; moreData = TRUE; noChange = FALSE; do { ret = pQuery(SNMP_PDU_GETNEXT, &list, &error, &index); ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index); ok(error == SNMP_ERRORSTATUS_NOERROR, "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error); ok(index == 0, "expected index 0, got %d\n", index); if (!ret) moreData = FALSE; else if (error) moreData = FALSE; else if (SnmpUtilOidNCmp(&vars2[0].name, &vars[0].name, vars[0].name.idLength)) moreData = FALSE; else if (!SnmpUtilOidCmp(&vars2[0].name, &vars[0].name)) { /* If the OID isn't modified, the function isn't implemented on this * platform, skip the remaining tests. */ noChange = TRUE; } if (moreData) { /* Make sure the size of the OID is right. * FIXME: don't know if IPv6 addrs are shared with this table. * Don't think so, but I'm not certain. */ ok(vars2[0].name.idLength == vars[0].name.idLength + 4, "expected length %d, got %d\n", vars[0].name.idLength + 4, vars2[0].name.idLength); /* Make sure the type is right */ ok(vars2[0].value.asnType == ASN_IPADDRESS, "expected type ASN_IPADDRESS, got %02x\n", vars2[0].value.asnType); if (vars2[0].value.asnType == ASN_IPADDRESS) { UINT i; /* The base OID for the route table, 1.3.6.1.2.1.4.21.1.1, is * appended with the dest IP address of the entry. So e.g. a * route entry for 224.0.0.0 is identified in MIB2 as * 1.3.6.1.2.1.4.21.1.1.224.0.0.0 */ for (i = 0; i < vars2[0].value.asnValue.address.length; i++) { ok(vars2[0].value.asnValue.address.stream[i] == vars2[0].name.ids[vars2[0].name.idLength - 4 + i], "expected ident byte %d to be %d, got %d\n", i, vars2[0].value.asnValue.address.stream[i], vars2[0].name.ids[vars2[0].name.idLength - 4 + i]); } } } else if (noChange) skip("no change in OID, no MIB2 IP route table implementation\n"); } while (moreData && !noChange); SnmpUtilVarBindFree(&vars2[0]); /* Check the type and OIDs of the UDP table */ vars[0].name.idLength = DEFINE_SIZEOF(mib2UdpTable); vars[0].name.ids = mib2UdpTable; SnmpUtilOidCpy(&vars2[0].name, &vars[0].name); vars2[0].value.asnType = 0; list.len = 1; list.list = vars2; moreData = TRUE; noChange = FALSE; do { ret = pQuery(SNMP_PDU_GETNEXT, &list, &error, &index); ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index); /* FIXME: error and index aren't checked here because the UDP table is * the last OID currently supported by Wine, so the last GetNext fails. * todo_wine is also not effective because it will succeed for all but * the last GetNext. Remove the if (0) if any later OID is supported * by Wine. */ if (0) { ok(error == SNMP_ERRORSTATUS_NOERROR, "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error); ok(index == 0, "expected index 0, got %d\n", index); } if (!ret) moreData = FALSE; else if (error) moreData = FALSE; else if (SnmpUtilOidNCmp(&vars2[0].name, &vars[0].name, vars[0].name.idLength)) moreData = FALSE; else if (!SnmpUtilOidCmp(&vars2[0].name, &vars[0].name)) { /* If the OID isn't modified, the function isn't implemented on this * platform, skip the remaining tests. */ noChange = TRUE; } if (moreData) { /* Make sure the size of the OID is right. */ ok(vars2[0].name.idLength == vars[0].name.idLength + 5, "expected length %d, got %d\n", vars[0].name.idLength + 5, vars2[0].name.idLength); /* Make sure the type is right */ ok(vars2[0].value.asnType == ASN_IPADDRESS, "expected type ASN_IPADDRESS, got %02x\n", vars2[0].value.asnType); if (vars2[0].value.asnType == ASN_IPADDRESS) { UINT i; /* Again with the ugly: the base OID for the UDP table, * 1.3.6.1.2.1.7.5.1, is appended with the local IP address and * port number of the entry. So e.g. an entry for * 192.168.1.1:4000 is identified in MIB2 as * 1.3.6.1.2.1.7.5.1.192.168.1.1.4000 */ for (i = 0; i < vars2[0].value.asnValue.address.length; i++) { ok(vars2[0].value.asnValue.address.stream[i] == vars2[0].name.ids[vars2[0].name.idLength - 5 + i], "expected ident byte %d to be %d, got %d\n", i, vars2[0].value.asnValue.address.stream[i], vars2[0].name.ids[vars2[0].name.idLength - 5 + i]); } } } else if (noChange) skip("no change in OID, no MIB2 UDP table implementation\n"); } while (moreData && !noChange); SnmpUtilVarBindFree(&vars2[0]); }
/* Given an OID and a base OID that it must begin with, finds the item and * element of the table whose value matches the instance from the OID. * The OID is converted to a key with the function makeKey, and compared * against entries in the table with the function compare. * If bPduType is not SNMP_PDU_GETNEXT and either the item or instance is * missing, returns SNMP_ERRORSTATUS_NOSUCHNAME. * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item and * instance, or item 1, instance 1 if either is missing. */ static AsnInteger32 getItemAndInstanceFromTable(AsnObjectIdentifier *oid, AsnObjectIdentifier *base, UINT instanceLen, BYTE bPduType, struct GenericTable *table, size_t tableEntrySize, oidToKeyFunc makeKey, compareFunc compare, UINT *item, UINT *instance) { AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR; if (!table) return SNMP_ERRORSTATUS_NOSUCHNAME; switch (bPduType) { case SNMP_PDU_GETNEXT: if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0) { /* Return the first item and instance from the table */ *item = 1; *instance = 1; } else if (!SnmpUtilOidNCmp(oid, base, base->idLength) && oid->idLength < base->idLength + instanceLen + 1) { /* Either the table or an item is specified, but the instance is * not. */ *instance = 1; if (oid->idLength >= base->idLength + 1) { *item = oid->ids[base->idLength]; if (!*item) *item = 1; } else *item = 1; } else if (!SnmpUtilOidNCmp(oid, base, base->idLength) && oid->idLength == base->idLength + instanceLen + 1) { *item = oid->ids[base->idLength]; if (!*item) { *instance = 1; *item = 1; } else { AsnObjectIdentifier instanceOid = { instanceLen, oid->ids + base->idLength + 1 }; *instance = findNextOidInTable(&instanceOid, table, tableEntrySize, makeKey, compare); if (!*instance || *instance > table->numEntries) ret = SNMP_ERRORSTATUS_NOSUCHNAME; } } else ret = SNMP_ERRORSTATUS_NOSUCHNAME; break; default: if (!SnmpUtilOidNCmp(oid, base, base->idLength) && oid->idLength == base->idLength + instanceLen + 1) { *item = oid->ids[base->idLength]; if (!*item) ret = SNMP_ERRORSTATUS_NOSUCHNAME; else { AsnObjectIdentifier instanceOid = { instanceLen, oid->ids + base->idLength + 1 }; *instance = findOidInTable(&instanceOid, table, tableEntrySize, makeKey, compare); if (!*instance) ret = SNMP_ERRORSTATUS_NOSUCHNAME; } } else ret = SNMP_ERRORSTATUS_NOSUCHNAME; } return ret; }
/***************************************************************************** * SnmpExtensionQuery [INETMIB1.@] */ BOOL WINAPI SnmpExtensionQuery(BYTE bPduType, SnmpVarBindList *pVarBindList, AsnInteger32 *pErrorStatus, AsnInteger32 *pErrorIndex) { AsnObjectIdentifier mib2oid = DEFINE_OID(mib2); AsnInteger32 error = SNMP_ERRORSTATUS_NOERROR, errorIndex = 0; UINT i; BOOL ret = TRUE; TRACE("(0x%02x, %p, %p, %p)\n", bPduType, pVarBindList, pErrorStatus, pErrorIndex); for (i = 0; !error && i < pVarBindList->len; i++) { /* Ignore any OIDs not in MIB2 */ if (!SnmpUtilOidNCmp(&pVarBindList->list[i].name, &mib2oid, mib2oid.idLength)) { struct mibImplementation *impl = NULL; UINT len, matchingIndex = 0; TRACE("%s\n", SnmpUtilOidToA(&pVarBindList->list[i].name)); /* Search for an implementation matching as many octets as possible */ for (len = pVarBindList->list[i].name.idLength; len >= minSupportedIDLength && !impl; len--) impl = findSupportedQuery(pVarBindList->list[i].name.ids, len, &matchingIndex); if (impl && impl->query) ret = impl->query(bPduType, &pVarBindList->list[i], &error); else error = SNMP_ERRORSTATUS_NOSUCHNAME; if (error == SNMP_ERRORSTATUS_NOSUCHNAME && bPduType == SNMP_PDU_GETNEXT) { /* GetNext is special: it finds the successor to the given OID, * so we have to continue until an implementation handles the * query or we exhaust the table of supported OIDs. */ for (matchingIndex++; error == SNMP_ERRORSTATUS_NOSUCHNAME && matchingIndex < DEFINE_SIZEOF(supportedIDs); matchingIndex++) { error = SNMP_ERRORSTATUS_NOERROR; impl = &supportedIDs[matchingIndex]; if (impl->query) ret = impl->query(bPduType, &pVarBindList->list[i], &error); else error = SNMP_ERRORSTATUS_NOSUCHNAME; } /* If the query still isn't resolved, set the OID to the * successor to the last entry in the table. */ if (error == SNMP_ERRORSTATUS_NOSUCHNAME) { SnmpUtilOidFree(&pVarBindList->list[i].name); ret = SnmpUtilOidCpy(&pVarBindList->list[i].name, &supportedIDs[matchingIndex - 1].name); pVarBindList->list[i].name.ids[ pVarBindList->list[i].name.idLength - 1] += 1; } } if (error) errorIndex = i + 1; } } *pErrorStatus = error; *pErrorIndex = errorIndex; return ret; }
void nextvb(SnmpMgmtQuery *q, UINT vb, UINT v, UINT *errorStatus, UINT *errorIndex) { RFC1157VarBindList vbl; // process single varbind vbl.list = &q->vbl.list[vb]; vbl.len = 1; SNMPDBG((SNMP_LOG_TRACE, "SNMP: PDU: %s no longer in view.\n", SnmpUtilOidToA(&vbl.list[0].name))); // process remaining views while ((++v < vlLen) && !(*errorStatus)) { // trim oid if necessary vbl.list[0].name.idLength = min( vbl.list[0].name.idLength, extAgents[vl[v]].supportedView.idLength ); // validate order if (0 >= SnmpUtilOidNCmp( &vbl.list[0].name, &extAgents[vl[v]].supportedView, extAgents[vl[v]].supportedView.idLength )) { SNMPDBG((SNMP_LOG_TRACE, "SNMP: PDU: re-routing request to %s.\n", extAgents[vl[v]].pathName)); // send getnext query to subagent if ((*(extAgents[vl[v]].queryAddr))( ASN_RFC1157_GETNEXTREQUEST, &vbl, errorStatus, errorIndex )) { // check the subagent status code returned if (*errorStatus == SNMP_ERRORSTATUS_NOERROR) { // check oid returned from subagent if (0 >= SnmpUtilOidNCmp( &vbl.list[0].name, &extAgents[vl[v]].supportedView, extAgents[vl[v]].supportedView.idLength )) { return; // success... } } } else { // subagent unable to process query *errorStatus = SNMP_ERRORSTATUS_GENERR; } } } *errorStatus = *errorStatus ? *errorStatus : SNMP_ERRORSTATUS_NOSUCHNAME; *errorIndex = q->xlat[vb].index+1; SNMPDBG((SNMP_LOG_TRACE, "SNMP: PDU: %s not in supported view(s).\n", SnmpUtilOidToA(&vbl.list[0].name))); } // end nextvb()
void vbltoql(RFC1157VarBindList *vbl, SnmpMgmtQueryList *ql, UINT *errorStatus, UINT *errorIndex) { UINT v; // index into view list UINT vb; // index into varbind list INT nDiff; BOOL fAnyOk; BOOL fFoundOk = FALSE; SNMPDBG((SNMP_LOG_TRACE, "SNMP: PDU: processing %s request containing %d variable(s).\n", (ql->type == ASN_RFC1157_GETREQUEST) ? "get" : (ql->type == ASN_RFC1157_SETREQUEST) ? "set" : (ql->type == ASN_RFC1157_GETNEXTREQUEST) ? "getnext" : "unknown", vbl->len)); // check to see if getnext is being requested fAnyOk = (ql->type == ASN_RFC1157_GETNEXTREQUEST); // initialize status return values *errorStatus = SNMP_ERRORSTATUS_NOERROR; *errorIndex = 0; // process variable bindings for (vb=0; vb < vbl->len; vb++) { // process supported views for (v=0; v < vlLen; v++) { // compare request nDiff = SnmpUtilOidNCmp( &vbl->list[vb].name, &extAgents[vl[v]].supportedView, extAgents[vl[v]].supportedView.idLength ); // analyze results based on request type fFoundOk = (!nDiff || (fAnyOk && (nDiff < 0))); // save if (fFoundOk) { // insert into query addql(ql, vbl, vb, v); break; } } // not found if (!fFoundOk) { SNMPDBG((SNMP_LOG_TRACE, "SNMP: PDU: %s not in supported view(s).\n", SnmpUtilOidToA(&vbl->list[vb].name))); *errorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; *errorIndex = vb+1; break; } } } // end vbltoql()
// Main program. INT _CRTAPI1 main( IN int argumentCount, IN char *argumentVector[]) { INT operation; LPSTR agent = NULL; LPSTR community = NULL; RFC1157VarBindList variableBindings; LPSNMP_MGR_SESSION session = NULL; INT timeout = TIMEOUT; INT retries = RETRIES; BYTE requestType; AsnInteger errorStatus; AsnInteger errorIndex; // Parse command line arguments to determine requested operation. // Verify number of arguments... if (argumentCount < 5 && argumentCount != 2) { printf("Error: Incorrect number of arguments specified.\n"); printf( "\nusage: snmputil [get|getnext|walk] agent community oid [oid ...]\n"); printf( " snmputil trap\n"); return 1; } // Get/verify operation... argumentVector++; argumentCount--; if (!strcmp(*argumentVector, "get")) operation = GET; else if (!strcmp(*argumentVector, "getnext")) operation = GETNEXT; else if (!strcmp(*argumentVector, "walk")) operation = WALK; else if (!strcmp(*argumentVector, "trap")) operation = TRAP; else { printf("Error: Invalid operation, '%s', specified.\n", *argumentVector); return 1; } if (operation != TRAP) { if (argumentCount < 4) { printf("Error: Incorrect number of arguments specified.\n"); printf( "\nusage: snmputil [get|getnext|walk] agent community oid [oid ...]\n"); printf( " snmputil trap\n"); return 1; } // Get agent address... argumentVector++; argumentCount--; agent = (LPSTR)SnmpUtilMemAlloc((UINT)(strlen(*argumentVector) + 1)); if (agent != NULL) StringCchCopyA(agent, strlen(*argumentVector) + 1, *argumentVector); else { printf("Error: SnmpUtilMemAlloc failed to allocate memory.\n"); return 1; } // Get agent community... argumentVector++; argumentCount--; community = (LPSTR)SnmpUtilMemAlloc((UINT)(strlen(*argumentVector) + 1)); if (community != NULL) StringCchCopyA(community, strlen(*argumentVector) + 1, *argumentVector); else { printf("Error: SnmpUtilMemAlloc failed to allocate memory.\n"); SnmpUtilMemFree(agent); return 1; } // Get oid's... variableBindings.list = NULL; variableBindings.len = 0; while(--argumentCount) { AsnObjectIdentifier reqObject; RFC1157VarBind * tmpVb; argumentVector++; // Convert the string representation to an internal representation. if (!SnmpMgrStrToOid(*argumentVector, &reqObject)) { printf("Error: Invalid oid, %s, specified.\n", *argumentVector); SnmpUtilMemFree(agent); SnmpUtilMemFree(community); SnmpUtilVarBindListFree(&variableBindings); return 1; } else { // Since sucessfull, add to the variable bindings list. variableBindings.len++; if ((tmpVb = (RFC1157VarBind *)SnmpUtilMemReAlloc( variableBindings.list, sizeof(RFC1157VarBind) * variableBindings.len)) == NULL) { printf("Error: Error allocating oid, %s.\n", *argumentVector); SnmpUtilMemFree(agent); SnmpUtilMemFree(community); SnmpUtilOidFree(&reqObject); variableBindings.len--; SnmpUtilVarBindListFree(&variableBindings); return 1; } variableBindings.list = tmpVb; variableBindings.list[variableBindings.len - 1].name = reqObject; // NOTE! structure copy variableBindings.list[variableBindings.len - 1].value.asnType = ASN_NULL; } } // end while() // Make sure only one variable binding was specified if operation // is WALK. if (operation == WALK && variableBindings.len != 1) { printf("Error: Multiple oids specified for WALK.\n"); SnmpUtilMemFree(agent); SnmpUtilMemFree(community); SnmpUtilVarBindListFree(&variableBindings); return 1; } // Establish a SNMP session to communicate with the remote agent. The // community, communications timeout, and communications retry count // for the session are also required. if ((session = SnmpMgrOpen(agent, community, timeout, retries)) == NULL) { printf("error on SnmpMgrOpen %d\n", GetLastError()); SnmpUtilMemFree(agent); SnmpUtilMemFree(community); SnmpUtilVarBindListFree(&variableBindings); return 1; } } // end if(TRAP) // Determine and perform the requested operation. if (operation == GET || operation == GETNEXT) { // Get and GetNext are relatively simple operations to perform. // Simply initiate the request and process the result and/or // possible error conditions. if (operation == GET) requestType = ASN_RFC1157_GETREQUEST; else requestType = ASN_RFC1157_GETNEXTREQUEST; // Request that the API carry out the desired operation. if (!SnmpMgrRequest(session, requestType, &variableBindings, &errorStatus, &errorIndex)) { // The API is indicating an error. printf("error on SnmpMgrRequest %d\n", GetLastError()); } else { // The API succeeded, errors may be indicated from the remote // agent. if (errorStatus > 0) { printf("Error: errorStatus=%d, errorIndex=%d\n", errorStatus, errorIndex); } else { // Display the resulting variable bindings. UINT i; for(i=0; i < variableBindings.len; i++) { char *string = NULL; if (SnmpMgrOidToStr(&variableBindings.list[i].name, &string)) { printf("Variable = %s\n", string); if (string) SnmpUtilMemFree(string); } printf("Value = "); SnmpUtilPrintAsnAny(&variableBindings.list[i].value); printf("\n"); } // end for() } } // Free the variable bindings that have been allocated. SnmpUtilVarBindListFree(&variableBindings); // Free other allocated resources SnmpUtilMemFree(agent); SnmpUtilMemFree(community); } else if (operation == WALK) { // Walk is a common term used to indicate that all MIB variables // under a given OID are to be traversed and displayed. This is // a more complex operation requiring tests and looping in addition // to the steps for get/getnext above. AsnObjectIdentifier root; AsnObjectIdentifier tempOid; if (!SnmpUtilOidCpy(&root, &variableBindings.list[0].name)) { printf("error on SnmpUtilOidCpy\n"); SnmpUtilMemFree(agent); SnmpUtilMemFree(community); SnmpUtilVarBindListFree(&variableBindings); return 1; } requestType = ASN_RFC1157_GETNEXTREQUEST; while(1) { if (!SnmpMgrRequest(session, requestType, &variableBindings, &errorStatus, &errorIndex)) { // The API is indicating an error. printf("error on SnmpMgrRequest %d\n", GetLastError()); break; } else { // The API succeeded, errors may be indicated from the remote // agent. // Test for end of subtree or end of MIB. if (errorStatus == SNMP_ERRORSTATUS_NOSUCHNAME || SnmpUtilOidNCmp(&variableBindings.list[0].name, &root, root.idLength)) { printf("End of MIB subtree.\n\n"); break; } // Test for general error conditions or sucesss. if (errorStatus > 0) { printf("Error: errorStatus=%d, errorIndex=%d \n", errorStatus, errorIndex); break; } else { // Display resulting variable binding for this iteration. char *string = NULL; if (SnmpMgrOidToStr(&variableBindings.list[0].name, &string)) { printf("Variable = %s\n", string); if (string) SnmpUtilMemFree(string); } printf("Value = "); SnmpUtilPrintAsnAny(&variableBindings.list[0].value); printf("\n"); } } // end if() // Prepare for the next iteration. Make sure returned oid is // preserved and the returned value is freed. if (!SnmpUtilOidCpy(&tempOid, &variableBindings.list[0].name)) { printf("error on SnmpUtilOidCpy\n"); SnmpUtilOidFree(&root); SnmpUtilMemFree(agent); SnmpUtilMemFree(community); SnmpUtilVarBindListFree(&variableBindings); return 1; } SnmpUtilVarBindFree(&variableBindings.list[0]); if (!SnmpUtilOidCpy(&variableBindings.list[0].name, &tempOid)) { printf("error on SnmpUtilOidCpy\n"); SnmpUtilOidFree(&tempOid); SnmpUtilOidFree(&root); SnmpUtilMemFree(agent); SnmpUtilMemFree(community); SnmpUtilVarBindListFree(&variableBindings); return 1; } variableBindings.list[0].value.asnType = ASN_NULL; SnmpUtilOidFree(&tempOid); } // end while() // Free the variable bindings that have been allocated. SnmpUtilVarBindListFree(&variableBindings); // Free other allocated resources SnmpUtilOidFree(&root); SnmpUtilMemFree(agent); SnmpUtilMemFree(community); } else if (operation == TRAP) { // Trap handling can be done two different ways: event driven or // polled. The following code illustrates the steps to use event // driven trap reception in a management application. HANDLE hNewTraps = NULL; if (!SnmpMgrTrapListen(&hNewTraps)) { printf("error on SnmpMgrTrapListen %d\n", GetLastError()); return 1; } else { printf("snmputil: listening for traps...\n"); } while(1) { DWORD dwResult; if ((dwResult = WaitForSingleObject(hNewTraps, INFINITE)) == WAIT_FAILED) { printf("error on WaitForSingleObject %d\n", GetLastError()); } else if (dwResult != WAIT_OBJECT_0) { printf("hNewTraps is not signaled\n"); } else if (!ResetEvent(hNewTraps)) { printf("error on ResetEvent %d\n", GetLastError()); } else { AsnObjectIdentifier enterprise; AsnNetworkAddress agentAddress; AsnNetworkAddress sourceAddress; AsnInteger genericTrap; AsnInteger specificTrap; AsnOctetString communityTrap; AsnTimeticks timeStamp; RFC1157VarBindList variableBindingsTrap; UINT i; while(SnmpMgrGetTrapEx( &enterprise, &agentAddress, &sourceAddress, &genericTrap, &specificTrap, &communityTrap, &timeStamp, &variableBindingsTrap)) { LPSTR string = NULL; printf("Incoming Trap:\n" " generic = %d\n" " specific = %d\n" " timeStamp = %u\n", genericTrap, specificTrap, timeStamp); if (SnmpMgrOidToStr(&enterprise, &string)) { printf (" enterprise = %s\n", string); if (string) SnmpUtilMemFree(string); } SnmpUtilOidFree(&enterprise); if (agentAddress.length == 4) { printf (" agent = %d.%d.%d.%d\n", (int)agentAddress.stream[0], (int)agentAddress.stream[1], (int)agentAddress.stream[2], (int)agentAddress.stream[3]); } if (agentAddress.dynamic) { SnmpUtilMemFree(agentAddress.stream); } if (sourceAddress.length == 4) { printf (" source IP = %d.%d.%d.%d\n", (int)sourceAddress.stream[0], (int)sourceAddress.stream[1], (int)sourceAddress.stream[2], (int)sourceAddress.stream[3]); } else if (sourceAddress.length == 10) { printf (" source IPX = %.2x%.2x%.2x%.2x." "%.2x%.2x%.2x%.2x%.2x%.2x\n", (int)sourceAddress.stream[0], (int)sourceAddress.stream[1], (int)sourceAddress.stream[2], (int)sourceAddress.stream[3], (int)sourceAddress.stream[4], (int)sourceAddress.stream[5], (int)sourceAddress.stream[6], (int)sourceAddress.stream[7], (int)sourceAddress.stream[8], (int)sourceAddress.stream[9]); } if (sourceAddress.dynamic) { SnmpUtilMemFree(sourceAddress.stream); } if (communityTrap.length) { string = (LPSTR)SnmpUtilMemAlloc (communityTrap.length + 1); if (string) { memcpy (string, communityTrap.stream, communityTrap.length); string[communityTrap.length] = '\0'; printf (" community = %s\n", string); SnmpUtilMemFree(string); } } if (communityTrap.dynamic) { SnmpUtilMemFree(communityTrap.stream); } for(i=0; i < variableBindingsTrap.len; i++) { string = NULL; if (SnmpMgrOidToStr(&variableBindingsTrap.list[i].name, &string)) { printf(" variable = %s\n", string); if (string) SnmpUtilMemFree(string); } printf(" value = "); SnmpUtilPrintAsnAny(&variableBindingsTrap.list[i].value); } // end for() printf("\n"); SnmpUtilVarBindListFree(&variableBindingsTrap); } dwResult = GetLastError(); // check for errors... if ((dwResult != NOERROR) && (dwResult != SNMP_MGMTAPI_NOTRAPS)) { printf("error on SnmpMgrGetTrap %d\n", dwResult); } } } // end while() } // end if(operation) if (operation != TRAP) { // Close SNMP session with the remote agent. if (!SnmpMgrClose(session)) { printf("error on SnmpMgrClose %d\n", GetLastError()); return 1; } } // Let the command interpreter know things went ok. return 0; } // end main()
void _php3_snmp(INTERNAL_FUNCTION_PARAMETERS, int st) { pval *a1, *a2, *a3; INT operation; LPSTR agent; LPSTR community; RFC1157VarBindList variableBindings; LPSNMP_MGR_SESSION session; INT timeout = TIMEOUT; INT retries = RETRIES; BYTE requestType; AsnInteger errorStatus; AsnInteger errorIndex; AsnObjectIdentifier oid; char *chkPtr = NULL; if (getParameters(ht, 3, &a1, &a2, &a3) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_string(a1); convert_to_string(a2); convert_to_string(a3); agent=a1->value.str.val; community=a2->value.str.val; operation=st; SnmpMgrStrToOid(a3->value.str.val, &oid); /* I've limited this to only one oid, but we can create a list of oid's here, and expand the function to take multiple oid's */ variableBindings.list->name = oid; variableBindings.list->value.asnType = ASN_NULL; variableBindings.len = 1; /* Establish a SNMP session to communicate with the remote agent. The community, communications timeout, and communications retry count for the session are also required. */ if ((session = SnmpMgrOpen(agent, community, timeout, retries)) == NULL){ php_error(E_WARNING,"error on SnmpMgrOpen %d\n", GetLastError()); } /* Determine and perform the requested operation.*/ if (operation == GET || operation == GETNEXT){ /* Get and GetNext are relatively simple operations to perform. Simply initiate the request and process the result and/or possible error conditions. */ if (operation == GET){ requestType = ASN_RFC1157_GETREQUEST; } else { requestType = ASN_RFC1157_GETNEXTREQUEST; } /* Request that the API carry out the desired operation.*/ if (!SnmpMgrRequest(session, requestType, &variableBindings, &errorStatus, &errorIndex)){ /* The API is indicating an error. */ php_error(E_WARNING,"error on SnmpMgrRequest %d\n", GetLastError()); } else { /* The API succeeded, errors may be indicated from the remote agent. */ if (errorStatus > 0){ php_error(E_WARNING,"Error: errorStatus=%d, errorIndex=%d\n", errorStatus, errorIndex); } else { /* Display the resulting variable bindings.*/ UINT i; char *str = NULL; for(i=0; i < variableBindings.len; i++) { SnmpMgrOidToStr(&variableBindings.list[i].name, &str); php_printf("Variable = %s\n", str); if (str) SNMP_free(str); php_printf("Value = "); SnmpUtilPrintAsnAny(&variableBindings.list[i].value); php_printf("\n"); } /* end for() */ } } /* Free the variable bindings that have been allocated.*/ SnmpUtilVarBindListFree(&variableBindings); } else if (operation == WALK) { /* Walk is a common term used to indicate that all MIB variables under a given OID are to be traversed and displayed. This is a more complex operation requiring tests and looping in addition to the steps for get/getnext above. */ AsnObjectIdentifier root; AsnObjectIdentifier tempOid; SnmpUtilOidCpy(&root, &variableBindings.list[0].name); requestType = ASN_RFC1157_GETNEXTREQUEST; while(1) { if (!SnmpMgrRequest(session, requestType, &variableBindings, &errorStatus, &errorIndex)){ /* The API is indicating an error.*/ php_error(E_WARNING,"error on SnmpMgrRequest %d\n", GetLastError()); break; } else { /* The API succeeded, errors may be indicated from the remote agent. Test for end of subtree or end of MIB. */ if (errorStatus == SNMP_ERRORSTATUS_NOSUCHNAME || SnmpUtilOidNCmp(&variableBindings.list[0].name, &root, root.idLength)) { PUTS("End of MIB subtree.\n\n"); break; } /* Test for general error conditions or sucesss. */ if (errorStatus > 0){ php_error(E_ERROR,"Error: errorStatus=%d, errorIndex=%d \n", errorStatus, errorIndex); break; } else { /* Display resulting variable binding for this iteration. */ char *str = NULL; SnmpMgrOidToStr(&variableBindings.list[0].name, &str); php_printf("Variable = %s\n", str); if (str) SNMP_free(str); php_printf("Value = "); SnmpUtilPrintAsnAny(&variableBindings.list[0].value); php_printf("\n"); } } /* end if () */ /* Prepare for the next iteration. Make sure returned oid is preserved and the returned value is freed. */ SnmpUtilOidCpy(&tempOid, &variableBindings.list[0].name); SnmpUtilVarBindFree(&variableBindings.list[0]); SnmpUtilOidCpy(&variableBindings.list[0].name, &tempOid); variableBindings.list[0].value.asnType = ASN_NULL; SnmpUtilOidFree(&tempOid); } /* end while() */ /* Free the variable bindings that have been allocated.*/ SnmpUtilVarBindListFree(&variableBindings); SnmpUtilOidFree(&root); } /* end if (operation) */ /* Close SNMP session with the remote agent.*/ if (!SnmpMgrClose(session)){ php_error(E_WARNING,"error on SnmpMgrClose %d\n", GetLastError()); } }