SNMP WinAPI - Conversion d'un code C++

Codes specifiques à Windows
tatanas
Messages : 39
Inscription : mar. 05/nov./2019 18:40

SNMP WinAPI - Conversion d'un code C++

Message par tatanas »

Bonjour tout le monde !

Je souhaiterais pouvoir requêter des périphériques réseaux en SNMP v2.
J'ai déjà des programmes fonctionnels qui utilisent les exécutables issus de Net-Snmp mais je voudrais le faire sans passer par des applications externes. J'ai repéré quelques scripts en Purebasic où les gens recréent les paquets entièrement mais je n'ai rien trouvé de fonctionnel (ou bien je m'y suis mal pris)

Après quelques recherches, je me suis rendu compte que Windows a une API dédiée (jusqu'au v2c). J'ai fouiné et trouvé un code C++ plutôt bien foutu et pas trop compliqué :
https://github.com/microsoft/Windows-cl ... Helper.Cpp
https://github.com/microsoft/Windows-cl ... mpUtil.Cpp
https://github.com/microsoft/Windows-cl ... SnmpUtil.h

Le header pour toutes les déclarations des constantes et structures : http://www.naic.edu/~phil/hardware/vert ... /winsnmp.h

Et voici le code adapté en PureBasic : http://s000.tinyupload.com/?file_id=028 ... 9679928152
(2 fichiers de code et les 3 librairies indispensables)

Alors normalement vous devriez avoir un plantage au bout de quelques secondes. Plantage qui provient de la fonction SnmpRecvMsg() sur laquelle je coince complètement.
Par contre en utilisant Wireshark ou équivalent, vous verrez que la requête Snmp est bien envoyée et que le retour fonctionne aussi (pour l'instant je n'ai testé qu'un simple GET).
Voilà ! Maintenant j'espère que vous pourrez m'aider à débugger ce programme.

En vous remerciant.

PS : J'utilise PureBasic en 64bits sur un Windows 7, ce sont donc les librairies 64 bits.

Edit : En compilant en 32 bits sous Windows 7 32 bits, j'ai une erreur "Invalid memory access. (write error at address 1)" au même endroit. Mais le tool Variable Viewer m'indique que les pointeurs passés en paramètre de SnmpRecvMsg se sont bien remplis sauf le *pSession\hpdu que je n'arrive pas à vérifier. Il semblerait que le plantage vienne bien de cette variable qui n'arrive pas à être remplie en sortie de la fonction.

Edit2 : c'est bon j'ai trouvé pourquoi ça plantait : une histoire de pointeurs... Il ne reste plus qu'à formater correctement le résultat mais printf() avec des formats est utilisé et là je ne connais pas. Si vous avez une idée...
Dernière modification par tatanas le mer. 05/févr./2020 10:42, modifié 2 fois.
Avatar de l’utilisateur
Ar-S
Messages : 9472
Inscription : dim. 09/oct./2005 16:51
Contact :

Re: SNMP WinAPI - Conversion d'un code C++

Message par Ar-S »

mais printf() avec des formats est utilisé et là je ne connais pas
Salut..
J'ai pas bien compris ta phrase.
Tu peux écrire un exemple concret
~~~~Règles du forum ~~~~
⋅.˳˳.⋅ॱ˙˙ॱ⋅.˳Ar-S ˳.⋅ॱ˙˙ॱ⋅.˳˳.⋅
W11x64 PB 6.x
Section HORS SUJET : ICI
LDV MULTIMEDIA : Dépannage informatique & mes Logiciels PB
UPLOAD D'IMAGES : Uploader des images de vos logiciels
Marc56
Messages : 2146
Inscription : sam. 08/févr./2014 15:19

Re: SNMP WinAPI - Conversion d'un code C++

Message par Marc56 »

tatanas a écrit :Il ne reste plus qu'à formater correctement le résultat mais printf() avec des formats est utilisé et là je ne connais pas. Si vous avez une idée...
Si c'est juste printf(), ça fonctionne exactement comme FormatDate() et FormatNumber() mais avec plus de type de formats
Voir https://fr.wikipedia.org/wiki/Printf

Ça fait partie de la lite de souhaits (printf et surtout scanf qui permettrait de filtrer facilement les entrées utilisateurs) :wink:
tatanas
Messages : 39
Inscription : mar. 05/nov./2019 18:40

Re: SNMP WinAPI - Conversion d'un code C++

Message par tatanas »

Bon j'ai réuploadé l'archive avec le code qui fonctionne pour GET. Attention dans le code que je vous ai fourni, c'est un WALK que j'ai testé et qui ne fonctionne pas mais ça me parait normal car la structure smiOID est un peu particulière. Je ne vois pas trop comment gérer la variable "ptr" (Pointer to an array of unsigned long integers) https://docs.microsoft.com/en-us/window ... nmp-smioid . La structure smiOCTETS est d'ailleurs identique. Elles permettent de stocker plusieurs résultats et pour l'instant je n'en gère qu'un.
Une idée pour définir cette variable 'ptr' ?
tatanas
Messages : 39
Inscription : mar. 05/nov./2019 18:40

Re: SNMP WinAPI - Conversion d'un code C++

Message par tatanas »

Petite amélioration au niveau du WALK. Remplacez la procédure CreatePduSendRequest par celle-ci :

Code : Tout sélectionner

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
Ces pointeurs de byte array restent toujours un problème.
tatanas
Messages : 39
Inscription : mar. 05/nov./2019 18:40

Re: SNMP WinAPI - Conversion d'un code C++

Message par tatanas »

Bon j'ai fini par réussir à faire fonctionner le GET, WALK et SUB_TREE (reste encore le GET_BULK qui m'intéresse).
J'ai mis à jour l'archive.
J'ai finalement réussi à accéder aux valeurs des structures qui m'embêtaient en jouant avec le pointeur de cette dernière et un décalage en fonction du type stocké.
Avatar de l’utilisateur
Ar-S
Messages : 9472
Inscription : dim. 09/oct./2005 16:51
Contact :

Re: SNMP WinAPI - Conversion d'un code C++

Message par Ar-S »

J'avoue que les pointeurs j'ai jamais été bien copain avec. Je ne peux pas t'aiguiller.
~~~~Règles du forum ~~~~
⋅.˳˳.⋅ॱ˙˙ॱ⋅.˳Ar-S ˳.⋅ॱ˙˙ॱ⋅.˳˳.⋅
W11x64 PB 6.x
Section HORS SUJET : ICI
LDV MULTIMEDIA : Dépannage informatique & mes Logiciels PB
UPLOAD D'IMAGES : Uploader des images de vos logiciels
Répondre