Page 1 of 1

SNMP WinAPI Example (Need help)

Posted: Sun Feb 02, 2020 11:41 am
by tatanas
Hi, Hi !

For a long time i'm looking for a way to use internal functions (not external app like net-snmp) to make a SNMP wrapper for questioning network devices.
I found nothing in PB so I searched in C++ and I found this code :
https://github.com/microsoft/Windows-cl ... Helper.Cpp
https://github.com/microsoft/Windows-cl ... mpUtil.Cpp
https://github.com/microsoft/Windows-cl ... SnmpUtil.h

Header with all the constants/structures : http://www.naic.edu/~phil/hardware/vert ... /winsnmp.h

Here is my attempt to translate it in PureBasic :
http://s000.tinyupload.com/?file_id=028 ... 9679928152
Archive files : conversionSNMP.pb, conversionSNMP_DEF.pbi and the 3 required libraries mgmtapi.lib, snmpapi.lib, wsnmp32.lib

EDIT : Archive reuploaded : Ive got response from device agent (a printer). The Get request works (at least under Wireshark). However the program still hangs at SnmpRecvMsg() function.
EDIT2 : I receive the message and the only thing to finish is the format of output result : PrintOidValue()
EDIT3 : Archive updated. Before the print of the result I will have to understand the smiOCTETS and smiOID structure to handle more than one result.
EDIT4 : Archive updated again. And it works pretty well !!!

I will greatly appreciate some help.
Thanks.

P.S : I'm using Windows 7 64bits and Purebasic 64bits compiler.

Re: SNMP WinAPI Example (Need help)

Posted: Sun Feb 02, 2020 4:06 pm
by infratec
You didn't searched enough:

viewtopic.php?f=13&t=17512&hilit=snmp

I also did snmp stuff in PB, but I think it's only v1.
I don't know the original source, but I think Michael Vogel was also involved.

But it is at work and not at home.
I'll publish the code tommorow.

Re: SNMP WinAPI Example (Need help)

Posted: Sun Feb 02, 2020 6:06 pm
by tatanas
Thanks for the link but I already tested this code and it doesn't work for me (I verify with Snmpb in parallel).

EDIT : got some results with the C++ conversion code :
Wireshark tells me that the message is send to the agent but there is no OID bind to it... Let's dig deeper

EDIT 2 : OID ok and response from a Get request without error. Program still hangs and crashes at SnmpRecvMsg() function... - RESOLVED : POINTER PROBLEM
EDIT 3 : There is an error with SetWindowLongPtr_(*pSession\hWnd, 0, *pSession). It returns 0 and getlasterror too. So I don't know if it's the source of the problem. However the *pSession pointer is passed correctly to the NotificationWndProc callback function. - SEEMS NORMAL

Re: SNMP WinAPI Example (Need help)

Posted: Tue Feb 04, 2020 1:07 pm
by tatanas
It's almost working ! (archive updated)

EDIT : More important, how should I declare the 'ptr' variable of smiOCTETS and smiOID structures ?

EDIT2 : Change this procedure to get a partially working 'WALK'

Code: Select all

Procedure CreatePduSendRequest(*pSession.SNMP_MGR_SESSION, *pValue.smiVALUE)
	
	; check For the validity of the Structure
	If *pSession = #Null
		ProcedureReturn #False
	EndIf
	
	; set the pdu type
	Select gVars\operation
		Case "GET"
			*pSession\nPduType = #SNMP_PDU_GET
			
		Case "GET_NEXT"
			*pSession\nPduType = #SNMP_PDU_GETNEXT
			
		Case "WALK"
			*pSession\nPduType = #SNMP_PDU_GETNEXT
			
		Case "SET"
			*pSession\nPduType = #SNMP_PDU_SET
			
		Case "SUB_TREE"
			*pSession\nPduType = #SNMP_PDU_GETNEXT
			
		Case "GET_BULK"
			*pSession\nPduType = #SNMP_PDU_GETBULK
			
	EndSelect
	
	; first time around, walk: always use the first oid
	If (gVars\nRequestId = 1) And (gVars\operation = "WALK" Or gVars\operation = "SUB_TREE") ; Or ( gVars\operation = #GET_BULK ) ) )
		
		If SnmpStrToOid(gVars\pszOid[0], @gVars\oid) = #SNMPAPI_FAILURE
			
			If SnmpMgrStrToOid(gVars\pszOid[0], @gVars\oid) = #False
				Debug "snmputil: Failed in SnmpStrToOid( ) or SnmpMgrStrToOid( ) function"
				ProcedureReturn #False
			EndIf
		Else
			; copy the var bind
			gVars\startOid = gVars\oid
		EndIf
	EndIf
	
	; create the appropriate Varbind lists depending on the operation.
	If gVars\operation = "WALK" Or gVars\operation = "SUB_TREE"
		
		If CreateVbl(*pSession, @gVars\oid, #Null) = #False
			ProcedureReturn #False
		EndIf
		
	ElseIf gVars\operation = "GET_NEXT" Or gVars\operation = "GET"

		If SnmpStrToOid(gVars\pszOid[gVars\nRequestId - 1], gVars\oid) = #SNMPAPI_FAILURE
			Debug "SnmpStrToOid failed : " + SnmpGetLastError(#Null) ; 9 = Invalid OID parameter, The string parameter is invalid

			If SnmpMgrStrToOid(gVars\pszOid[gVars\nRequestId - 1], gVars\oid) = #False
				Debug "SnmpMgrStrToOid failed"
				ProcedureReturn #False
			EndIf

		EndIf  
		
		If CreateVbl(*pSession, @gVars\oid, #Null ) = #False
			ProcedureReturn #False
		EndIf
		
	ElseIf gVars\operation = "SET"
		*pSession\hVbl = SnmpCreateVbl(*pSession\hSnmpSession, @gVars\oid, *pValue)
		
	ElseIf gVars\operation = "GET_BULK"
		; CreateVbl first then add OIDs To the Vbl
		*pSession\hVbl = SnmpCreateVbl(*pSession\hSnmpSession,  ; handle To the WinSNMP session 
		                               #Null,						  ; pointer To the variable name 
		                               #Null)						  ; pointer To the value To associate With the variable        
		
		If *pSession\hVbl = #SNMPAPI_FAILURE
			ProcedureReturn #False
		EndIf
		
		For i = 0 To gVars\oidCount - 1
			
			; the very last gVars.oid in the loop will be freed later
			If i > 0
				SnmpFreeDescriptor(#SNMP_SYNTAX_OID, @gVars\oid)
			EndIf
			
			If SnmpStrToOid(gVars\pszOid[i], @gVars\oid) = #SNMPAPI_FAILURE
				If SnmpMgrStrToOid(gVars\pszOid[i], @gVars\oid) = #False
					Debug "snmputil: Failed in SnmpStrToOid( ) or SnmpMgrStrToOid( ) function"
					ProcedureReturn #False
				EndIf
			EndIf
			
			; append vb To Vbl
			If SnmpSetVb(*pSession\hVbl, 0, @gVars\oid, #Null) = #SNMPAPI_FAILURE
				Debug "snmputil: Failed in SnmpSetVb( ) function"
				ProcedureReturn #False
			EndIf
			
		Next
		
	EndIf
	
	gVars\nRequestId = gVars\nRequestId + 1
	*pSession\nRequestId = gVars\nRequestId
	
	If gVars\operation = "GET_BULK"
		error_status = gVars\non_repeaters
		error_index = gVars\max_repetitions
	Else	
		error_status = #Null
		error_index = #Null
	EndIf
	
	; create a pdu using the parameters in pSession Structure
	*pSession\hPdu = SnmpCreatePdu(*pSession\hSnmpSession, *pSession\nPduType, *pSession\nRequestId, error_status, error_index, *pSession\hVbl)
	
	If *pSession\hPdu = #SNMPAPI_FAILURE
		Debug "snmputil: Failed in creating PDU"
		ProcedureReturn #False
	EndIf
	
	; send the message To the agent
	*pSession\nError = SnmpSendMsg(*pSession\hSnmpSession, *pSession\hManagerEntity, *pSession\hAgentEntity, *pSession\hViewContext, *pSession\hPdu)
	
	If gVars\operation <> "SUB_TREE"
		SnmpFreeDescriptor(#SNMP_SYNTAX_OID, @gVars\oid)
	EndIf
	
	
	; check error status And Return
	If *pSession\nError = #SNMPAPI_FAILURE  
		*pSession\nError = SnmpGetLastError(*pSession\hSnmpSession)
		Debug "snmputil: Failed in send message, Last Error " + *pSession\nError
		FreeVblandPdu(*pSession)
		ProcedureReturn #False
	Else
		FreeVblandPdu(*pSession)
		ProcedureReturn ProcessAgentResponse(*pSession)
	EndIf
	
EndProcedure
The problem is still the smiOCTETS and smiVALUE structures...

Re: SNMP WinAPI Example (Need help)

Posted: Wed Feb 05, 2020 10:38 am
by tatanas
Archive updated.

GET, WALK and SUB_TREE requests work !

Got some problem with COUNTER64 Base Type because the smiCNTR64 structure should host high part and low part of this value. It didn't and I don't know why. I have to do it manually.