Snmp Get
Snmp Get
Anybody has information how to implement this function in PureBasic ?
			
			
									
									
						- Michael Vogel
 - Addict

 - Posts: 2821
 - Joined: Thu Feb 09, 2006 11:27 pm
 - Contact:
 
Re: Snmp Get
Someone did some snmp code in the german forum, using an UDPnetwork lib (which I couldn't install, but this should be possible)...Droopy wrote:Anybody has information how to implement this function in PureBasic ?
http://www.purebasic.fr/german/viewtopi ... light=snmp
- Michael Vogel
 - Addict

 - Posts: 2821
 - Joined: Thu Feb 09, 2006 11:27 pm
 - Contact:
 
Looking for SNMP code examples... anyone that has a suggestion?
			
			
									
									( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB - upgrade incoming...)
( The path to enlightenment and the PureBasic Survival Guide right here... )
						( The path to enlightenment and the PureBasic Survival Guide right here... )
- Michael Vogel
 - Addict

 - Posts: 2821
 - Joined: Thu Feb 09, 2006 11:27 pm
 - Contact:
 
Would be fine for me also - I used a very rude method: calling SNMPUtil.exe in a hidden window by different threads and capturing its output to memory...blueznl wrote:Looking for SNMP code examples... anyone that has a suggestion?
Indeed not brilliant
But I didn't find a simple method (without libraries) to do SNMP communications by my own (wether as "client" to poll nor as a "server" to simulate network manageable components)
Michael
If you can use WMI in PB you could do this
http://msdn2.microsoft.com/en-us/librar ... S.85).aspx.
I think some people have got this working (WMI that is)
			
			
									
									http://msdn2.microsoft.com/en-us/librar ... S.85).aspx.
I think some people have got this working (WMI that is)
Paul Dwyer
“In nature, it’s not the strongest nor the most intelligent who survives. It’s the most adaptable to change” - Charles Darwin
“If you can't explain it to a six-year old you really don't understand it yourself.” - Albert Einstein
						“In nature, it’s not the strongest nor the most intelligent who survives. It’s the most adaptable to change” - Charles Darwin
“If you can't explain it to a six-year old you really don't understand it yourself.” - Albert Einstein
SNMP GET and GET_NEXT
Not finished, but functional
You may help me to finish it
			
			
													Not finished, but functional
You may help me to finish it
Code: Select all
Procedure.l Set_Integer      ( value.l )
  If value <= $7F
  
    *Integer = AllocateMemory ( 1 )
    PokeB ( *Integer, value )
    
  Else
  
    *Integer = AllocateMemory ( 2 )
    PokeB ( *Integer + 00, ( value & $FF00 ) >> 8 )
    PokeB ( *Integer + 01, value & $FF )
  
  EndIf
  
  ProcedureReturn *Integer
EndProcedure
Procedure.l Get_Integer      ( *Integer, free_memory.l )
  value = 0
  For position = 0 To MemorySize ( *Integer ) - 1
  
    value.l = ( x_value << 8 ) | PeekB ( *Integer + position )
    
  Next
  If free_memory = #True
    FreeMemory ( *Integer )
  EndIf
  ProcedureReturn value
EndProcedure
Procedure.l BER_Encode       ( value.q )
  *BER_Encode = #Null
  If value >= 0 And value < 128
    *BER_Encode = AllocateMemory ( 1 )
    PokeB ( *BER_Encode + 00, value )
    
  ElseIf value >= 128       And value < 16384
    *BER_Encode = AllocateMemory ( 2 )
    PokeB ( *BER_Encode + 00, $80 | ( value >> 7 ) )
    PokeB ( *BER_Encode + 01, value & $7f )
    
  ElseIf value >= 16384     And value < 2097152
    *BER_Encode = AllocateMemory ( 3 )
    PokeB ( *BER_Encode + 00, $80 | ( ( value >> 14 ) & $7f ) )
    PokeB ( *BER_Encode + 01, $80 | ( ( value >>  7 ) & $7f ) )
    PokeB ( *BER_Encode + 02, value & $7f )
    
  ElseIf value >= 2097152   And value < 268435456
    *BER_Encode = AllocateMemory ( 4 )
    PokeB ( *BER_Encode + 00, $80 | ( ( value >> 21 ) & $7f ) )
    PokeB ( *BER_Encode + 01, $80 | ( ( value >> 14 ) & $7f ) )
    PokeB ( *BER_Encode + 02, $80 | ( ( value >>  7 ) & $7f ) )
    PokeB ( *BER_Encode + 03, value & $7f )
    
  ElseIf value >= 268435456 And value < 4294967296
    *BER_Encode = AllocateMemory ( 5 )
    PokeB ( *BER_Encode + 00, $80 | ( ( value >> 28 ) & $0f ) )
    PokeB ( *BER_Encode + 01, $80 | ( ( value >> 21 ) & $7f ) )
    PokeB ( *BER_Encode + 02, $80 | ( ( value >> 14 ) & $7f ) )
    PokeB ( *BER_Encode + 03, $80 | ( ( value >>  7 ) & $7f ) )
    PokeB ( *BER_Encode + 04, value & $7f )
  EndIf
  ProcedureReturn *BER_Encode
EndProcedure
Procedure.l BER_Decode_2     ( *input_data, cut.l, free_memory.l )
  output_value.l = 0
  
  value_1.l = PeekB( *input_data + 00 ) & $FF
  value_2.l = PeekB( *input_data + 01 ) & $FF
  counter.l = 2
  
  If value_1 = $80
    output_value = $80
      
  ElseIf value_1 > $80 And value_2 > $80
    output_value = ( ( value_1 - $80 ) << 7 ) + ( value_2 - $80 )
    
  ElseIf value_1 > $80 And value_2 < $80
  
    output_value = ( ( value_1 - $80 ) << 7 ) + value_2
  
  ElseIf value_1 < $80
  
    output_value = value_1
    counter = 1
  
  EndIf
  If cut = #True
    CopyMemory ( *input_data + counter , *input_data, MemorySize ( *input_data ) - counter )
    ReAllocateMemory ( *input_data, MemorySize ( *input_data ) - counter )
  EndIf
  
  If free_memory = #True
    FreeMemory ( *input_data )
  EndIf
  
  ProcedureReturn output_value
EndProcedure
Procedure.l OID_Encode       ( oid_string.s )
  dot_numbers = CountString ( oid_string, "." )
  *OID_Encode       = AllocateMemory ( 1024 )
  OID_Encode_Length = 0
  
  If Left ( oid_string, 1 ) = "."
    oid_string = Mid ( oid_string, 2, Len ( oid_string ) - 1 )
  EndIf
  
  first  = Val ( StringField( oid_string, 1, "." ) )
  second = Val ( StringField( oid_string, 2, "." ) )
  
  first  = ( first * 40 ) + second
  
  *mem_value = BER_Encode ( first )
  
  CopyMemory ( *mem_value, *OID_Encode, MemorySize ( *mem_value ) )
  
  OID_Encode_Length + MemorySize ( *mem_value )
  
  FreeMemory ( *mem_value )
  
  If CountString ( oid_string, "." ) > 1
    For position.l = 3 To dot_numbers + 1
     
      *mem_value = BER_Encode ( Val ( StringField( oid_string, position, "." ) ) )
      CopyMemory ( *mem_value, *OID_Encode + OID_Encode_Length, MemorySize ( *mem_value ) )
      OID_Encode_Length + MemorySize ( *mem_value )
      FreeMemory ( *mem_value )
  
    Next
  EndIf
  
  ReAllocateMemory ( *OID_Encode, OID_Encode_Length )
  
  ProcedureReturn *OID_Encode
  
EndProcedure
Procedure.s OID_Decode       ( *OID_Decode )
  Dim OID.l ( 256 )
  
  OID_string.s  = ""
  OID_count     = 1
  subid         = 0
  For counter = 0 To MemorySize ( *OID_Decode ) - 1
    value = PeekB( *OID_Decode + counter ) & $FF
  
    If subid & $FE000000
      Debug "object too large"
    EndIf
    
    subid = ( subid << 7 ) | ( value & $7F )
    
    If Not( value & $80 )
      OID ( OID_count ) = subid
      OID_count + 1
      subid = 0
    
    EndIf
                    
  Next
  If OID ( 1 ) = 43
    OID ( 0 ) = 1
    OID ( 1 ) = 3
  ElseIf OID ( 1 ) < 64
    OID ( 0 ) = 0
  ElseIf OID ( 1 ) < 128
    OID ( 0 ) = 1
    OID ( 1 ) = 64
  Else
    OID ( 0 ) = 2
    OID ( 1 ) = 128
  EndIf
  For counter = 0 To OID_count - 1
    OID_string + "." + Str( OID ( counter ) )
  
  Next
  ProcedureReturn OID_string
EndProcedure
Procedure.l Make_TLV         ( type.b, *input_data, free_memory.l )
  Data_Length.l  = MemorySize   ( *input_data   )
  *Octet_Length  = Set_Integer  ( Data_Length   )
  Length.l       = MemorySize   ( *Octet_Length )
  *TLV = AllocateMemory ( 1 + Length + Data_Length )
  
  PokeB      ( *TLV, type )
  CopyMemory ( *Octet_Length, *TLV + 1         , Length)
  CopyMemory ( *input_data  , *TLV + 1 + Length, Data_Length )
  
  FreeMemory ( *Octet_Length )
  
  If free_memory = #True
    FreeMemory ( *input_data )
  EndIf
  
  ProcedureReturn *TLV
EndProcedure
Procedure.l Make_TLV_Null    ( type.b )
  *TLV = AllocateMemory ( 2 )
  
  PokeB ( *TLV + 00, type )
  PokeB ( *TLV + 01, 00   )
  
  ProcedureReturn *TLV
EndProcedure
Procedure.l Join_Data        ( *memory_1, *memory_2, free_memory.l )
  *Joined = AllocateMemory ( MemorySize ( *memory_1 ) + MemorySize ( *memory_2 ) )
  
  CopyMemory ( *memory_1, *Joined, MemorySize ( *memory_1 ) )
  CopyMemory ( *memory_2, *Joined + MemorySize ( *memory_1 ), MemorySize ( *memory_2 ) )
  
  If free_memory = #True
    FreeMemory ( *memory_1 )
    FreeMemory ( *memory_2 )
  EndIf
  
  ProcedureReturn *Joined
EndProcedure
Procedure.l Make_String      ( string.s )
  *String = AllocateMemory ( Len (string) )
  
  PokeS ( *String, string )
  
  ProcedureReturn *String
EndProcedure
Procedure.l Memory_Move_Left ( *memory, offset.l )
  If MemorySize ( *memory ) > offset
    CopyMemory ( *memory + offset, *memory, MemorySize ( *memory ) - offset )
    ReAllocateMemory ( *memory, MemorySize ( *memory ) - offset )
    ProcedureReturn #True
  EndIf
  
  ProcedureReturn #False
EndProcedure
Procedure.l Unpack_TLV       ( *input_data, cut_memory.l, free_memory.l )
  *TMP = AllocateMemory ( MemorySize ( *input_data ) - 1 )
  CopyMemory ( *input_data + 1, *TMP, MemorySize ( *TMP ) )
  
  type.l = PeekB ( *input_data ) & $FF
  
  return_value = #False
  cut_length = 0
  
  If type = $05
    cut_length = 2
  
  ElseIf type = $30 Or type > $9F
    ; SEQUENCE
    sequence_length = BER_Decode_2 ( *TMP, #True, #False )
    If sequence_length = MemorySize ( *TMP )
      return_value = *TMP
    EndIf
  Else
    ; Other
    Length = PeekB ( *TMP ) & $FF
    
    Memory_Move_Left ( *TMP, 1 )
    ReAllocateMemory ( *TMP, Length )
    
    return_value = *TMP
    cut_length = 2 + Length
    
  EndIf
  
  If cut_memory = #True
  
    Memory_Move_Left ( *input_data, cut_length )
  
  EndIf
  
  If free_memory = #True
    FreeMemory ( *input_data )
  
  EndIf
  ProcedureReturn return_value
EndProcedure
Procedure.l Make_SNMP_Packet  ( community_string.s, snmp_pdu.s, request_id.l, object_identifier.s )
  return_value = #False
  If UCase ( snmp_pdu ) = "GET_NEXT"
    SNMP_PDU_Type.l = $A1
    *Value = Make_TLV_Null ( $05 )
  
  Else ; GET
    SNMP_PDU_Type.l = $A0
    *Value = Make_TLV_Null ( $05 )
  
  EndIf
  ; [ SNMP_Message [ Version_Number ] [ Community_String ] [ SNMP_PDU [ Request_ID ] [ Error ] [ Error_Index ] [ Varbind_List [ Varbind [ Object_Identifier ] [ Value ] ] ] ] ]
  
  *OID = OID_Encode ( object_identifier )
  
  If *OID
    *Object_Identifier = Make_TLV ( $06, *OID, #True )
  EndIf
  
  If *Object_Identifier And *Value
    *Varbind_Data = Join_Data ( *Object_Identifier, *Value, #True )
  EndIf
  If *Varbind_Data
    *Varbind = Make_TLV ( $30, *Varbind_Data, #True )
  EndIf    
  If *Varbind
    *Varbind_List     = Make_TLV    ( $30, *Varbind, #True )
    *Request_ID_Value = Set_Integer ( request_id )
  EndIf
  If *Request_ID_Value And *Varbind_List
    *Request_ID  = Make_TLV ( $02, *Request_ID_Value, #True )
    *Error_Value = Set_Integer ( $00 )
  EndIf
              
  If *Request_ID And *Error_Value
    *Error             = Make_TLV ( $02, *Error_Value, #True )
    *Error_Index_Value = Set_Integer ( $00 )
  EndIf          
  If *Error And *Error_Index_Value
    *Error_Index = Make_TLV ( $02, *Error_Index_Value, #True )
    *Temp_1      = Join_Data ( *Request_ID, *Error, #True )
  EndIf
                    
  If *Error_Index And *Temp_1
    *Temp_2 = Join_Data ( *Temp_1, *Error_Index, #True )
  EndIf                  
  If *Temp_2
    *SNMP_PDU_Data = Join_Data ( *Temp_2, *Varbind_List, #True )
  EndIf
                    
  If *SNMP_PDU_Data
    *SNMP_PDU                    = Make_TLV    ( SNMP_PDU_Type, *SNMP_PDU_Data, #True )
    *SNMP_Community_String_Value = Make_String ( community_string )
  EndIf
                    
  If *SNMP_PDU And *SNMP_Community_String_Value
    *SNMP_Community_String = Make_TLV ( $04, *SNMP_Community_String_Value, #True )
    *SNMP_Version_Value    = Set_Integer   ( $00 )
  EndIf
                          
  If *SNMP_Community_String And *SNMP_Version_Value
    *SNMP_Version = Make_TLV ( $02, *SNMP_Version_Value, #True )
  EndIf
                            
  If *SNMP_Version
    *Temp_3 = Join_Data ( *SNMP_Version, *SNMP_Community_String, #True )
  EndIf
                              
  If *Temp_3
    *SNMP_Message_Data = Join_Data ( *Temp_3, *SNMP_PDU, #True )
  EndIf                          
  If *SNMP_Message_Data
    *SNMP_Message = Make_TLV ( $30, *SNMP_Message_Data, #True )
    return_value  = *SNMP_Message
  EndIf                            
  ProcedureReturn return_value
  
EndProcedure
Procedure.l Unpack_SNMP_Response ( *SNMP_Packet, request_id.l )
  return_value = #False
  
  *SNMP_Message = Unpack_TLV ( *SNMP_Packet, #True, #False )
  
  If *SNMP_Message
  
    *SNMP_Version = Unpack_TLV ( *SNMP_Message, #True, #False )
    
    If *SNMP_Version
    
      *SNMP_Community = Unpack_TLV ( *SNMP_Message, #True, #False )
      
      If *SNMP_Community
      
        SNMP_Version_Value.l   = Get_Integer ( *SNMP_Version, #True )
        SNMP_Community_Value.s = PeekS       ( *SNMP_Community, MemorySize ( *SNMP_Community ) )
        FreeMemory ( *SNMP_Community )
        
        *SNMP_PDU = Unpack_TLV ( *SNMP_Message, #True, #True )
        
        If *SNMP_PDU
        
          *Request_ID  = Unpack_TLV ( *SNMP_PDU, #True, #False )
          *Error       = Unpack_TLV ( *SNMP_PDU, #True, #False )
          *Error_Index = Unpack_TLV ( *SNMP_PDU, #True, #False )
          
          *Varbind_List = Unpack_TLV ( *SNMP_PDU, #True, #True )
          
          Request_ID = Get_Integer ( *Request_ID, #True )
;           Debug Request_ID
          
          If *Varbind_List
            *Varbind = Unpack_TLV ( *Varbind_List, #True, #True )
            return_value = *Varbind
          
          EndIf
        EndIf
      EndIf
    EndIf
  EndIf
  ProcedureReturn return_value
EndProcedure
Procedure.l SNMP_Send_And_Receieve ( ip_address.s, community.s, oid.s, type.s)
  return_value.l = #False
  
  If ip_address <> ""
    *ptr                = sockinfo.sockaddr_in
    sockinfo\sin_family = #AF_INET
    sockinfo\sin_port   = htons_(161)
    sockinfo\sin_addr   = inet_addr_(ip_address)
    SockIdent           = SOCKET_(#AF_INET, 2, 0)  ;create socket (#SOCK_DGRAM for UDP)	
    If SockIdent = #INVALID_SOCKET		
;       Debug "Socket cant be created!"	
    Else 		
;       Debug "UDP socket created!"
      RandomSeed ( Random ( 99999 ) )
      Request_ID = Random ( 99999 )
      *packet  = Make_SNMP_Packet ( community, type, Request_ID, oid )
      
      If *packet
      
        packet_length = MemorySize ( *packet )
        send = sendto_(SockIdent, *packet, packet_length, 0, *ptr, SizeOf(sockaddr_in))
        
        If send <> #SOCKET_ERROR 
        
          *recv_buffer     = AllocateMemory ( 512 )
          
          If *recv_buffer
            recv_buffer_size = MemorySize ( *recv_buffer )
          
            start = Date ()
            Repeat 
  
              Delay(1) 
              bytesRecv = recv_(SockIdent, *recv_buffer, recv_buffer_size, 2) 
              
              If Date () - start > 5
                bytesRecv = #SOCKET_ERROR
                Break
              
              EndIf
  
            Until bytesRecv <> -1 
  
            If bytesRecv <> #SOCKET_ERROR
            
              ReAllocateMemory(*recv_buffer, bytesRecv)
              
              *value = Unpack_SNMP_Response ( *recv_buffer, Request_ID )
              If *value
              
                 return_value = *value
                    
              EndIf
              
            EndIf
            
            FreeMemory ( *recv_buffer )
            
          EndIf
        EndIf
        FreeMemory (*packet)
      EndIf
    EndIf
  EndIf
  
  ProcedureReturn return_value
EndProcedure
Procedure.l Decode_Result ( *result )
  type    = PeekB ( *result + 00 ) & $FF
  length  = PeekB ( *result + 01 ) & $FF
  
  If type = $06
  
    *oid    = AllocateMemory (length)
    CopyMemory (*result + 2, *oid, length)
    oid_s.s = OID_Decode ( *oid )
    FreeMemory ( *oid )
    
    Debug oid_s
    
    Memory_Move_Left ( *result, length + 2 )
  
  EndIf
  
  type    = PeekB ( *result + 00 ) & $FF
  length  = PeekB ( *result + 01 ) & $FF
  
  If type = $04 And length > 0
    
    *tmp = AllocateMemory ( length )
    
    CopyMemory ( *result + 2, *tmp, length)
    
    Debug PeekS ( *tmp, length )
  
  EndIf
  
  FreeMemory ( *result )
EndProcedure
Procedure ping (sIPAddress.s)
  EchoMessage.s = "Echo" 
  ResultSize.l = SizeOf(ICMP_ECHO_REPLY) + Len(EchoMessage) 
  *Result = AllocateMemory(ResultSize) 
  *Echo.ICMP_ECHO_REPLY = *Result 
  result = #False
   
  If Len(sIPAddress ) > 0 
    hFile.l = IcmpCreateFile_() 
    IPAddress.l = MakeIPAddress(Val(StringField(sIPAddress,1,".")),Val(StringField(sIPAddress,2,".")),Val(StringField(sIPAddress,3,".")),Val(StringField(sIPAddress+".",4,".")))  
    lngResult.l = IcmpSendEcho_(hFile, IPAddress, EchoMessage, Len(EchoMessage), 0, *Result, ResultSize, 500) 
        If lngResult
          result = #True
;           Debug ("Ping " + sIPAddress + " Octets: " + Str(*Echo\DataSize) + " Temps: " + Str(*Echo\RoundTripTime) + " ms TTL:" + StrU(*Echo\Options\Ttl,#Byte)) 
        EndIf
      IcmpCloseHandle_(hFile) 
    EndIf 
  
  FreeMemory(*Result) 
  ProcedureReturn result
EndProcedure
If InitNetwork()
    
  IPAddress.s = "192.168.1.25"
    
  Debug IPAddress
        
  If ping (IPAddress)
    *rec = SNMP_Send_And_Receieve ( IPAddress, "public", "1.3.6.1.2.1.1.1.0", "GET") ; or GET_NEXT
    If *rec
      Decode_Result ( *rec )
    EndIf
      
  EndIf
  Debug "------------------"
EndIf
					Last edited by peterb on Fri Feb 29, 2008 4:05 pm, edited 1 time in total.
									
			
									
						- Michael Vogel
 - Addict

 - Posts: 2821
 - Joined: Thu Feb 09, 2006 11:27 pm
 - Contact:
 
Please help me!
I cant get the code to work! I'll get a correct response from the device, but decoding seems to be the problem.
I added some debug lines to find out, where the problem occurs - but then it got too complicate for me
 
Maybe someone can give me a clue - I'll give you all the information I have:
1. the response packet (taken from an analyzer)
2. the debug output
3. The code // only some debug-lines have been added...
[/list]
			
			
									
									
						I cant get the code to work! I'll get a correct response from the device, but decoding seems to be the problem.
I added some debug lines to find out, where the problem occurs - but then it got too complicate for me
Maybe someone can give me a clue - I'll give you all the information I have:
1. the response packet (taken from an analyzer)
Code: Select all
00 02 3F B1 4E AF 00 0E 6A CC 32 28 08 00 45 00   ..?±N¯..jÌ2(..E.
00 6A 01 A2 00 00 40 11 63 E0 AC 10 DE DE AC 10   .j.¢..@.cà¬.ÞÞ¬.
DE 01 00 A1 0C 23 00 56 32 96 30 82 00 4A 02 01   Þ..¡.#.V2?0?.J..
00 04 06 70 75 62 6C 69 63 A2 82 00 3B 02 02 A1   ...public¢?.;..¡
C9 02 01 00 02 01 00 30 82 00 2D 30 82 00 29 06   É......0?.-0?.).
08 2B 06 01 02 01 01 01 00 04 1D 42 72 6F 61 64   .+.........Broad
62 61 6E 64 20 52 65 73 69 64 65 6E 74 69 61 6C   band Residential 
20 47 61 74 65 77 61 79                           Gateway 
Code: Select all
172.16.222.222                                                                                                                                                                                       
PING OK                                                                                                                                                                                              
S&R I: 0'30' ‚'82' J'4A' '2' '1' '4' '6' p'70' u'75' b'62' l'6C' i'69' c'63' ¢'A2' ‚'82' ;'3B' '2' '2' '17' æ'E6' '2' '1' '2' '1' 0'30' ‚'82' -'2D' 0'30' ‚'82' )'29' '6' '8' +'2B'     
Unpack I: 0'30' ‚'82' J'4A' '2' '1' '4' '6' p'70' u'75' b'62' l'6C' i'69' c'63' ¢'A2' ‚'82' ;'3B' '2' '2' '17' æ'E6' '2' '1' '2' '1' 0'30' ‚'82' -'2D' 0'30' ‚'82' )'29' '6' '8' +'2B'  
TLV I: ‚'82' J'4A' '2' '1' '4' '6' p'70' u'75' b'62' l'6C' i'69' c'63' ¢'A2' ‚'82' ;'3B' '2' '2' '17' æ'E6' '2' '1' '2' '1' 0'30' ‚'82' -'2D' 0'30' ‚'82' )'29' '6' '8' +'2B' '6'      
TLV II: J'4A' '2' '1' '4' '6' p'70' u'75' b'62' l'6C' i'69' c'63' ¢'A2' ‚'82' ;'3B' '2' '2' '17' æ'E6' '2' '1' '2' '1' 0'30' ‚'82' -'2D' 0'30' ‚'82' )'29' '6' '8' +'2B' '6' '1' '2' 
ÖHA?256 / 75                                                                                                                                                                                         
Cut: 0'30' ‚'82' J'4A' '2' '1' '4' '6' p'70' u'75' b'62' l'6C' i'69' c'63' ¢'A2' ‚'82' ;'3B' '2' '2' '17' æ'E6' '2' '1' '2' '1' 0'30' ‚'82' -'2D' 0'30' ‚'82' )'29' '6' '8' +'2B'       
Return:  - <<EMPTY>>                                                                                                                                                                                 
Unpack II:  - <<EMPTY>>                                                                                                                                                                              
S&R II:  - <<EMPTY>>                                                                                                                                                                             
Main:  - <<EMPTY>>Code: Select all
Procedure DebugString(s.s,*mem)
Protected i,b
If *mem
For i=0 To 39
	b=PeekB(*mem+i)
	s=s+Chr(b)+"'"+Hex(b&$FF)+"' "	
Next i
Else
s+ " - <<EMPTY>>"
EndIf
Debug s
EndProcedure
Procedure.l Set_Integer(value.l)
	If value <= $7F
		*Integer=AllocateMemory(1)
		PokeB(*Integer,value)
	Else
		*Integer=AllocateMemory(2)
		PokeB(*Integer + 00,(value & $FF00) >> 8)
		PokeB(*Integer + 01,value & $FF)
	EndIf
	ProcedureReturn *Integer
EndProcedure
Procedure.l Get_Integer(*Integer,free_memory.l)
	value=0
	For position=0 To MemorySize(*Integer) - 1
		value.l=(x_value << 8) | PeekB(*Integer + position)
	Next
	If free_memory=#True
		FreeMemory(*Integer)
	EndIf
	ProcedureReturn value
EndProcedure
Procedure.l BER_Encode(value.q)
	*BER_Encode=#Null
;Debug -value
	If value >= 0 And value < 128
		*BER_Encode=AllocateMemory(1)
		PokeB(*BER_Encode + 00,value)
	ElseIf value >= 128       And value < 16384
		*BER_Encode=AllocateMemory(2)
		PokeB(*BER_Encode + 00,$80 |(value >> 7))
		PokeB(*BER_Encode + 01,value & $7f)
	ElseIf value >= 16384     And value < 2097152
		*BER_Encode=AllocateMemory(3)
		PokeB(*BER_Encode + 00,$80 |((value >> 14) & $7f))
		PokeB(*BER_Encode + 01,$80 |((value >>  7) & $7f))
		PokeB(*BER_Encode + 02,value & $7f)
	ElseIf value >= 2097152   And value < 268435456
		*BER_Encode=AllocateMemory(4)
		PokeB(*BER_Encode + 00,$80 |((value >> 21) & $7f))
		PokeB(*BER_Encode + 01,$80 |((value >> 14) & $7f))
		PokeB(*BER_Encode + 02,$80 |((value >>  7) & $7f))
		PokeB(*BER_Encode + 03,value & $7f)
	ElseIf value >= 268435456 And value < 4294967296
		*BER_Encode=AllocateMemory(5)
		PokeB(*BER_Encode + 00,$80 |((value >> 28) & $0f))
		PokeB(*BER_Encode + 01,$80 |((value >> 21) & $7f))
		PokeB(*BER_Encode + 02,$80 |((value >> 14) & $7f))
		PokeB(*BER_Encode + 03,$80 |((value >>  7) & $7f))
		PokeB(*BER_Encode + 04,value & $7f)
	EndIf
	ProcedureReturn *BER_Encode
EndProcedure
Procedure.l BER_Decode_2(*input_data,cut.l,free_memory.l)
	output_value.l=0
	value_1.l=PeekB(*input_data+00)&$FF
	value_2.l=PeekB(*input_data+01)&$FF
	counter.l=2
	If value_1=$80
		output_value=$80
	ElseIf value_1 > $80 And value_2 > $80
		output_value=((value_1 - $80) << 7) +(value_2 - $80)
	ElseIf value_1 > $80 And value_2 < $80
		output_value=((value_1 - $80) << 7) + value_2
	ElseIf value_1 < $80
		output_value=value_1
		counter=1
	EndIf
	If cut=#True
		CopyMemory(*input_data + counter,*input_data,MemorySize(*input_data) - counter)
		ReAllocateMemory(*input_data,MemorySize(*input_data) - counter)
	EndIf
	If free_memory=#True
		FreeMemory(*input_data)
	EndIf
	ProcedureReturn output_value
EndProcedure
Procedure.l OID_Encode(oid_string.s)
	dot_numbers=CountString(oid_string,".")
	*OID_Encode=AllocateMemory(1024)
	OID_Encode_Length=0
	If Left(oid_string,1)="."
		oid_string=Mid(oid_string,2,Len(oid_string) - 1)
	EndIf
	first=Val(StringField(oid_string,1,"."))
	second=Val(StringField(oid_string,2,"."))
	first=(first * 40) + second
	*mem_value=BER_Encode(first)
	CopyMemory(*mem_value,*OID_Encode,MemorySize(*mem_value))
	OID_Encode_Length + MemorySize(*mem_value)
	FreeMemory(*mem_value)
	If CountString(oid_string,".") > 1
		For position.l=3 To dot_numbers + 1
			*mem_value=BER_Encode(Val(StringField(oid_string,position,".")))
			CopyMemory(*mem_value,*OID_Encode + OID_Encode_Length,MemorySize(*mem_value))
			OID_Encode_Length + MemorySize(*mem_value)
			FreeMemory(*mem_value)
		Next
	EndIf
	ReAllocateMemory(*OID_Encode,OID_Encode_Length)
	ProcedureReturn *OID_Encode
EndProcedure
Procedure.s OID_Decode(*OID_Decode)
	Dim OID.l(256)
	OID_string.s=""
	OID_count=1
	subid=0
	For counter=0 To MemorySize(*OID_Decode) - 1
		value=PeekB(*OID_Decode + counter) & $FF
		If subid & $FE000000
			Debug "object too large"
		EndIf
		subid=(subid << 7) |(value & $7F)
		If Not(value & $80)
			OID(OID_count)=subid
			OID_count + 1
			subid=0
		EndIf
	Next
	If OID(1)=43
		OID(0)=1
		OID(1)=3
	ElseIf OID(1) < 64
		OID(0)=0
	ElseIf OID(1) < 128
		OID(0)=1
		OID(1)=64
	Else
		OID(0)=2
		OID(1)=128
	EndIf
	For counter=0 To OID_count - 1
		OID_string + "." + Str(OID(counter))
	Next
	ProcedureReturn OID_string
EndProcedure
Procedure.l Make_TLV(type.b,*input_data,free_memory.l)
	Data_Length.l=MemorySize(*input_data  )
	*Octet_Length=Set_Integer(Data_Length  )
	Length.l=MemorySize(*Octet_Length)
	*TLV=AllocateMemory(1 + Length + Data_Length)
	PokeB(*TLV,type)
	CopyMemory(*Octet_Length,*TLV + 1        ,Length)
	CopyMemory(*input_data ,*TLV + 1 + Length,Data_Length)
	FreeMemory(*Octet_Length)
	If free_memory=#True
		FreeMemory(*input_data)
	EndIf
	ProcedureReturn *TLV
EndProcedure
Procedure.l Make_TLV_Null(type.b)
	*TLV=AllocateMemory(2)
	PokeB(*TLV + 00,type)
	PokeB(*TLV + 01,00  )
	ProcedureReturn *TLV
EndProcedure
Procedure.l Join_Data(*memory_1,*memory_2,free_memory.l)
	*Joined=AllocateMemory(MemorySize(*memory_1) + MemorySize(*memory_2))
	CopyMemory(*memory_1,*Joined,MemorySize(*memory_1))
	CopyMemory(*memory_2,*Joined + MemorySize(*memory_1),MemorySize(*memory_2))
	If free_memory=#True
		FreeMemory(*memory_1)
		FreeMemory(*memory_2)
	EndIf
	ProcedureReturn *Joined
EndProcedure
Procedure.l Make_String(string.s)
	*String=AllocateMemory(Len(string))
	PokeS(*String,string)
	ProcedureReturn *String
EndProcedure
Procedure.l Memory_Move_Left(*memory,offset.l)
	If MemorySize(*memory) > offset
		CopyMemory(*memory + offset,*memory,MemorySize(*memory) - offset)
		ReAllocateMemory(*memory,MemorySize(*memory) - offset)
		ProcedureReturn #True
	EndIf
	ProcedureReturn #False
EndProcedure
Procedure.l Unpack_TLV(*input_data,cut_memory.l,free_memory.l)
	*TMP=AllocateMemory(MemorySize(*input_data) - 1)
	CopyMemory(*input_data + 1,*TMP,MemorySize(*TMP))
	type.l=PeekB(*input_data) & $FF
	return_value=#False
	cut_length=0
	If type=$05
		cut_length=2
	ElseIf type=$30 Or type > $9F
DebugString("TLV I: ",*TMP)
		; SEQUENCE
		sequence_length=BER_Decode_2(*TMP,#True,#False)
DebugString("TLV II: ",*TMP)
		If sequence_length=MemorySize(*TMP)
			return_value=*TMP
		Else
		Debug "ÖHA?"+Str(sequence_length)+" / "+Str(MemorySize(*tmp))
		EndIf
	Else
		; Other
		Length=PeekB(*TMP) & $FF
		Memory_Move_Left(*TMP,1)
		ReAllocateMemory(*TMP,Length)
		return_value=*TMP
		cut_length=2 + Length
	EndIf
	If cut_memory=#True
		Memory_Move_Left(*input_data,cut_length)
DebugString("Cut: ",*input_data)
	EndIf
	If free_memory=#True
	FreeMemory(*input_data)
	EndIf
DebugString("Return: ",return_value)
	ProcedureReturn return_value
EndProcedure
Procedure.l Make_SNMP_Packet(community_string.s,snmp_pdu.s,request_id.l,object_identifier.s)
	return_value=#False
	If UCase(snmp_pdu)="GET_NEXT"
		SNMP_PDU_Type.l=$A1
		*Value=Make_TLV_Null($05)
	Else ; GET
		SNMP_PDU_Type.l=$A0
		*Value=Make_TLV_Null($05)
	EndIf
	; [ SNMP_Message [ Version_Number ] [ Community_String ] [ SNMP_PDU [ Request_ID ] [ Error ] [ Error_Index ] [ Varbind_List [ Varbind [ Object_Identifier ] [ Value ] ] ] ] ]
	*OID=OID_Encode(object_identifier)
	If *OID
		*Object_Identifier=Make_TLV($06,*OID,#True)
	EndIf
	If *Object_Identifier And *Value
		*Varbind_Data=Join_Data(*Object_Identifier,*Value,#True)
	EndIf
	If *Varbind_Data
		*Varbind=Make_TLV($30,*Varbind_Data,#True)
	EndIf
	If *Varbind
		*Varbind_List=Make_TLV($30,*Varbind,#True)
		*Request_ID_Value=Set_Integer(request_id)
	EndIf
	If *Request_ID_Value And *Varbind_List
		*Request_ID=Make_TLV($02,*Request_ID_Value,#True)
		*Error_Value=Set_Integer($00)
	EndIf
	If *Request_ID And *Error_Value
		*Error=Make_TLV($02,*Error_Value,#True)
		*Error_Index_Value=Set_Integer($00)
	EndIf
	If *Error And *Error_Index_Value
		*Error_Index=Make_TLV($02,*Error_Index_Value,#True)
		*Temp_1=Join_Data(*Request_ID,*Error,#True)
	EndIf
	If *Error_Index And *Temp_1
		*Temp_2=Join_Data(*Temp_1,*Error_Index,#True)
	EndIf
	If *Temp_2
		*SNMP_PDU_Data=Join_Data(*Temp_2,*Varbind_List,#True)
	EndIf
	If *SNMP_PDU_Data
		*SNMP_PDU=Make_TLV(SNMP_PDU_Type,*SNMP_PDU_Data,#True)
		*SNMP_Community_String_Value=Make_String(community_string)
	EndIf
	If *SNMP_PDU And *SNMP_Community_String_Value
		*SNMP_Community_String=Make_TLV($04,*SNMP_Community_String_Value,#True)
		*SNMP_Version_Value=Set_Integer($00)
	EndIf
	If *SNMP_Community_String And *SNMP_Version_Value
		*SNMP_Version=Make_TLV($02,*SNMP_Version_Value,#True)
	EndIf
	If *SNMP_Version
		*Temp_3=Join_Data(*SNMP_Version,*SNMP_Community_String,#True)
	EndIf
	If *Temp_3
		*SNMP_Message_Data=Join_Data(*Temp_3,*SNMP_PDU,#True)
	EndIf
	If *SNMP_Message_Data
		*SNMP_Message=Make_TLV($30,*SNMP_Message_Data,#True)
		return_value=*SNMP_Message
	EndIf
	ProcedureReturn return_value
EndProcedure
Procedure.l Unpack_SNMP_Response(*SNMP_Packet,request_id.l)
	return_value=#False
DebugString("Unpack I: ",*snmp_packet)
	*SNMP_Message=Unpack_TLV(*SNMP_Packet,#True,#False)
DebugString("Unpack II: ",*snmp_message)
	If *SNMP_Message
		*SNMP_Version=Unpack_TLV(*SNMP_Message,#True,#False)
		If *SNMP_Version
			*SNMP_Community=Unpack_TLV(*SNMP_Message,#True,#False)
			If *SNMP_Community
				SNMP_Version_Value.l=Get_Integer(*SNMP_Version,#True)
				SNMP_Community_Value.s=PeekS(*SNMP_Community,MemorySize(*SNMP_Community))
				FreeMemory(*SNMP_Community)
				*SNMP_PDU=Unpack_TLV(*SNMP_Message,#True,#True)
				If *SNMP_PDU
					*Request_ID=Unpack_TLV(*SNMP_PDU,#True,#False)
					*Error=Unpack_TLV(*SNMP_PDU,#True,#False)
					*Error_Index=Unpack_TLV(*SNMP_PDU,#True,#False)
					*Varbind_List=Unpack_TLV(*SNMP_PDU,#True,#True)
					Request_ID=Get_Integer(*Request_ID,#True)
					;           Debug Request_ID
					If *Varbind_List
						*Varbind=Unpack_TLV(*Varbind_List,#True,#True)
						return_value=*Varbind
					EndIf
				EndIf
			EndIf
		EndIf
	EndIf
	ProcedureReturn return_value
EndProcedure
Procedure.l SNMP_Send_And_Receive(ip_address.s,community.s,oid.s,type.s)
	return_value.l=#False
	If ip_address<>""
		*ptr=sockinfo.sockaddr_in
		sockinfo\sin_family=#AF_INET
		sockinfo\sin_port=htons_(161)
		sockinfo\sin_addr=inet_addr_(ip_address)
		SockIdent=SOCKET_(#AF_INET,2,0)  ;create socket (#SOCK_DGRAM for UDP)
		If SockIdent=#INVALID_SOCKET
			       Debug "Socket cant be created!"
		Else
		;	       Debug "UDP socket created!"
			RandomSeed(Random(99999))
			Request_ID=Random(99999)
			*packet=Make_SNMP_Packet(community,type,Request_ID,oid)
			If *packet
				packet_length=MemorySize(*packet)
				send=sendto_(SockIdent,*packet,packet_length,0,*ptr,SizeOf(sockaddr_in))
				If send<>#SOCKET_ERROR
					*recv_buffer=AllocateMemory(512)
					If *recv_buffer
						recv_buffer_size=MemorySize(*recv_buffer)
						
			;			Debug recv_buffer_size
						start=Date()
						Repeat
							Delay(1)
							bytesRecv=recv_(SockIdent,*recv_buffer,recv_buffer_size,2)
							If Date()-start>5
								bytesRecv=#SOCKET_ERROR
								Break
							EndIf
						Until bytesRecv<>-1
				;		Debug bytesRecv
						DebugString("S&R I: ",*recv_buffer)
						If bytesRecv<>#SOCKET_ERROR
							ReAllocateMemory(*recv_buffer,bytesRecv)
							*value=Unpack_SNMP_Response(*recv_buffer,Request_ID)
							If *value
								return_value=*value
							EndIf
						EndIf
						DebugString("S&R II: ",*value)
						
						FreeMemory(*recv_buffer)
					EndIf
				EndIf
				FreeMemory(*packet)
			EndIf
		EndIf
	EndIf
	ProcedureReturn return_value
EndProcedure
Procedure.l Decode_Result(*result)
	type=PeekB(*result + 00) & $FF
	length=PeekB(*result + 01) & $FF
	If type=$06
		*oid=AllocateMemory(length)
		CopyMemory(*result + 2,*oid,length)
		oid_s.s=OID_Decode(*oid)
		FreeMemory(*oid)
		Debug oid_s
		MessageRequester("OID S",oid_s)
		Memory_Move_Left(*result,length + 2)
	EndIf
	type=PeekB(*result + 00) & $FF
	length=PeekB(*result + 01) & $FF
	If type=$04 And length > 0
		*tmp=AllocateMemory(length)
		CopyMemory(*result + 2,*tmp,length)
		Debug PeekS(*tmp,length)
		MessageRequester("Tpe 4",PeekS(*tmp,length))
	EndIf
	debugstring("Decode: ",*result)
	FreeMemory(*result)
EndProcedure
Procedure ping(sIPAddress.s)
	EchoMessage.s="Echo"
	ResultSize.l=SizeOf(ICMP_ECHO_REPLY) + Len(EchoMessage)
	*Result=AllocateMemory(ResultSize)
	*Echo.ICMP_ECHO_REPLY=*Result
	result=#False
	If Len(sIPAddress) > 0
		hFile.l=IcmpCreateFile_()
		IPAddress.l=MakeIPAddress(Val(StringField(sIPAddress,1,".")),Val(StringField(sIPAddress,2,".")),Val(StringField(sIPAddress,3,".")),Val(StringField(sIPAddress+".",4,".")))
		lngResult.l=IcmpSendEcho_(hFile,IPAddress,EchoMessage,Len(EchoMessage),0,*Result,ResultSize,500)
		If lngResult
			result=#True
			;           Debug ("Ping " + sIPAddress + " Octets: " + Str(*Echo\DataSize) + " Temps: " + Str(*Echo\RoundTripTime) + " ms TTL:" + StrU(*Echo\Options\Ttl,#Byte))
		EndIf
		IcmpCloseHandle_(hFile)
	EndIf
	FreeMemory(*Result)
	ProcedureReturn result
EndProcedure
If InitNetwork()
	IPAddress.s="172.16.222.222"
	Debug IPAddress
	If ping(IPAddress)
		;MessageRequester("Ping",ipaddress+" successfull.")
Debug "PING OK"
		*rec=SNMP_Send_And_Receive(IPAddress,"public","1.3.6.1.2.1.1.1.0","GET") ; or GET_NEXT
		debugstring("Main: ",*rec)
		If *rec
		Debug "REC"
			;MessageRequester("GET",PeekS(*rec))
			Decode_Result(*rec)
		
		EndIf
		
	EndIf
	Debug "------------------"
EndIf- Michael Vogel
 - Addict

 - Posts: 2821
 - Joined: Thu Feb 09, 2006 11:27 pm
 - Contact:
 
Still being confused - Peters code is a really great program, but hard to understand (for me) in all details.
As posted before, with this code I do not get any output on the components around me (3Com, Cisco, Foundry).
Tools like Getif&Co show me correct results and also the received packets from peters code are perfect, but there must be a (small) hole in decoding...
So I tried to understand the ASN.1 structure and wrote some lines for decoding a catched packet:
Now I'm able to get (most) of the records, but I have no idea, when to stop and which records can be ignored and which one is the result. In this case its the field #12, I know - but will that be the same independently which SNMP message will have to be decoded? 
And where is the difference to peters code which does not show me any results (see posting above)?
Any ideas?
Thanks,
Michael
			
			
									
									
						As posted before, with this code I do not get any output on the components around me (3Com, Cisco, Foundry).
Tools like Getif&Co show me correct results and also the received packets from peters code are perfect, but there must be a (small) hole in decoding...
So I tried to understand the ASN.1 structure and wrote some lines for decoding a catched packet:
Code: Select all
Packet.s="30 82 00 4A 02 01 00 04 06 70 75 62 6C 69 63 A2 82 00 3B 02 02 C7 2B 02 01 00 02 01 00 30 82 00 2D 30 82 00 29 06 08 2B 06 01 02 01 01 01 00 04 1D 42 72 6F 61 64 62 61 6E 64 20 52 65 73 69 64 65 6E 74 69 61 6C 20 47 61 74 65 77 61 79 "
Global FrameLength=Len(Packet.s)/3
Global FrameData.s=Space(FrameLength)
For i=0 To FrameLength-1
PokeB(@FrameData+i,Val("$"+Mid(Packet,i*3+1,2)))
Next i
Procedure DebugString(s.s,*mem)
Protected i,b
If *mem
For i=0 To 39
	b=PeekB(*mem+i)&$ff
	If b>31
		s=s+Hex(b&$FF)+"|"+Chr(b)+" "	
	Else
		s=s+RSet(Hex(b),2,"0")+"|. "	
	EndIf
Next i
Else
s+ " - <<EMPTY>>"
EndIf
Debug s
EndProcedure
Structure Reference
	value.l
EndStructure
Procedure.l BER_Length(*memory,*pos.Reference)
	
	Protected byte
	Protected length
	Protected n
		
	byte=PeekB(*memory+*pos\Value)
	*pos\Value+1
				
	If byte&$80;				multi-byte length
		byte&$3;					number of bytes For length information
			
		While byte
			length<<8
			length+(PeekB(*memory+*pos\Value)&$ff)
			byte-1
			*pos\Value+1
		Wend
	Else
		length=byte&$7f
	EndIf	
;Debug "Len: "+Str(length)
	ProcedureReturn length
EndProcedure
Procedure.l BER_Integer(*memory,length)
Protected n
While length
			n<<8
			n+(PeekB(*memory)&$ff)
			length-1
			*memory+1
		Wend
		ProcedureReturn n
EndProcedure
Procedure.s BER_Object(*memory,length)
Protected byte
Protected OID.s
While length
byte=PeekB(*memory)&$ff
If byte='+'
	OID="1.3"
Else
OID+"."+Chr('0'+PeekB(*memory))
EndIf
*memory+1
length-1
Wend
ProcedureReturn OID
EndProcedure
Procedure.l BER_Class(*memory)
	Protected byte
	Protected length
	Protected pos
	; Class (Bits 7/8)
	; 0 - Universal (integer, string etc.)
	; 1 - Application (IP address)
	; 2 - Context (complex data)
	; 3 - Private (non standard data)
	
	; Data Type (Bit 6)
	; 0 - primitive data-type
	; 1 - constucted data-type
	; ASN.1 Type (Bit 5)
	; 0 - no
	; 1 - yes
pos=0
For i=1 To 12
	
	byte=PeekB(*memory+pos)&$ff
	Debug "----------"
	Debug "Pos: "+Str(pos)+" (=$"+Hex(byte&$ff)+")"
	pos+1
	
	Select byte>>6;					class...
	
	Case 0;										universal class
		If byte&$20;						constructed data type
			If byte&$10;					ASN.1
				length=BER_Length(*memory,@pos);
			EndIf
						
		Else;										primitive data type
			
			length=BER_Length(*memory,@pos);
			
			Select byte&$f
			Case 2
				Debug "integer: "+Str(BER_Integer(*memory+pos,length))
			Case 3
				Debug "bit string"
			Case 4
				Debug "octet string: "+PeekS(*memory+pos,length)
			Case 5
				Debug "null"
			Case 6
				Debug "object: "+BER_Object(*memory+pos,length)
			EndSelect
			
		pos+length
		EndIf
	
	Case 2;											context specific
	
		Debug "SNMP"
		If byte&$20;						constructed data type
			length=BER_Length(*memory,@pos);
				Debug "S:"+Str(length)
		Else;										primitive data type
			Debug "?"
		EndIf
		
	EndSelect
Next i
	
EndProcedure
DebugString("Init:",@FrameData)
BER_Class(@FrameData)
And where is the difference to peters code which does not show me any results (see posting above)?
Any ideas?
Thanks,
Michael
- Michael Vogel
 - Addict

 - Posts: 2821
 - Joined: Thu Feb 09, 2006 11:27 pm
 - Contact:
 
Got it 
 
It's not as fine as peters original code, but should work...
Also threading is not a problem and all results are kept in a structure (SNMP)...
Beside some missing actions (convert tick value into string, check for additional data types) there is one unsolved issue: some strings (MAX addresses) should be converted by using a hex function, but i see no difference in the SNMP response packet to other (octet) strings...
			
			
									
									
						It's not as fine as peters original code, but should work...
Also threading is not a problem and all results are kept in a structure (SNMP)...
Beside some missing actions (convert tick value into string, check for additional data types) there is one unsolved issue: some strings (MAX addresses) should be converted by using a hex function, but i see no difference in the SNMP response packet to other (octet) strings...
Code: Select all
; Define
	EnableExplicit
	; Alive state
	Enumeration
		#Station_Unknown
		#Station_Down
		#Station_Up
	EndEnumeration
	; GetType
	Enumeration $A0
		#GET
		#GET_NEXT
	EndEnumeration
	; Status
	Enumeration
		#SNMP_Unknown
		#SNMP_Ok
		#SNMP_Sent
		#SNMP_Received
		#SNMP_Error
		#SNMP_Error_OID
		#SNMP_Error_RID
		#SNMP_Error_Name
	EndEnumeration
	
	;ValueType
	Enumeration
		#TypeUnknown
		#TypeInteger
		#TypeString
		#TypeIP
		#TypeTicks
		#TypeObject
	EndEnumeration
	; internally used
	Enumeration
		#Field_Header
		#Field_Version
		#Field_Community
		#Field_PDU
		#Field_RequestID
		#Field_ErrorState
		#Field_ErrorIndex
		#Field_VariableLengthWithHeader
		#Field_VariableLengthWithoutHeader
		#Field_OID
		#Field_Variable
		#Field_Nil
	EndEnumeration
	#SNMP_MaxPacketSize=548
	Structure Reference
		value.l
	EndStructure
	Structure StationType
		IP.l
		Community.s
		Alive.w
	EndStructure
	Structure SNMPType
		StationNumber.w
		GetType.w
		RequestID.w
		OID.s
		ResponseOID.s
		ValueType.w
		Value.s
		Status.w
	EndStructure
	Global MaxStations=50
	Global MaxRequests=100
	Global Dim Station.StationType(MaxStations)
	Global Dim SNMP.SNMPType(MaxRequests)
	Global RequestID.w
; EndDefine
Procedure.l BE_Length(*memory,*pos.Reference)
	; Calculates length of actual field...
	Protected byte
	Protected length
	Protected n
	byte=PeekB(*memory+*pos\Value)
	*pos\Value+1
	If byte&$80;				multi-byte length
		byte&$3;				number of bytes for length information
		While byte
			length<<8
			length+(PeekB(*memory+*pos\Value)&$ff)
			byte-1
			*pos\Value+1
		Wend
	Else
		length=byte&$7f
	EndIf
	;Debug "Len: "+Str(length)
	ProcedureReturn length
EndProcedure
Procedure.l BE_Integer(*memory,length)
	; Encodes memory to integer value...
	Protected n
	While length
		n<<8
		n+(PeekB(*memory)&$ff)
		length-1
		*memory+1
	Wend
	ProcedureReturn n
EndProcedure
Procedure.s BE_Object(*memory,length)
	; Encodes Memory to OID string...
	Protected ID
	Protected OID.s
	Protected byte
	Protected i=0
	While i<length
		byte=PeekB(*memory+i)&$FF
		If ID & $FE000000
			OID+".???"
			Break
		EndIf
		ID<<7
		ID|(byte&$7F)
		If byte&$80=0
			If i
				OID+"."+Str(ID)
			Else
				Select byte
				Case 43
					OID=".1.3"
				Case 0 To 63
					OID=".0"
				Case 64 To 127
					OID=".1.64"
				Default
					OID=".2.128"
				EndSelect
			EndIf
			ID=0
		EndIf
		i+1
	Wend
	ProcedureReturn OID
EndProcedure
Procedure.l BM_Integer(value.l,*memory,*pos.Reference)
	; Writes integer value into memory, starting at position *pos
	; Returns number of used Bytes...
	If (value<$80)
		PokeB(*memory+*pos\Value,value)
		value=1
	Else
		PokeB(*memory+*pos\Value,(value>>8)&$ff)
		PokeB(*memory+*pos\Value+1,value&$ff)
		value=2
	EndIf
	*pos\Value+value
	ProcedureReturn value
EndProcedure
Procedure.l BM_Value(value.l,*memory,*pos.Reference)
	; should use quads, but because of pures poor quad handling limited to long for now ;(
	; Writes integer value into memory, starting at position *pos
	; Returns number of used Bytes...
	If (value>=0) And (value<128)
		PokeB(*memory+*pos\Value,value)
		value=1
	ElseIf  (value>=128) And (value<16384)
		Debug Str(value)+" = "+Str($80|(value>>7))+", "+Str(value&$7f)
		PokeB(*memory+*pos\Value, $80|(value>>7))
		PokeB(*memory+*pos\Value+1, value&$7f)
		value=2
	ElseIf (value>=16384) And (value<2097152)
		PokeB(*memory+*pos\Value, $80|((value>>14)&$7f))
		PokeB(*memory+*pos\Value+1, $80|((value>>7)&$7f))
		PokeB(*memory+*pos\Value+2, value&$7f)
		value=3
	ElseIf (value>=2097152) And (value<268435456)
		PokeB(*memory+*pos\Value, $80|((value>>21)&$7f))
		PokeB(*memory+*pos\Value+1, $80|((value>>14)&$7f))
		PokeB(*memory+*pos\Value+2, $80|((value>>7)&$7f))
		PokeB(*memory+*pos\Value+3, value&$7f)
		value=4
	ElseIf (value>=268435456) And (value<4294967296)
		PokeB(*memory+*pos\Value, $80|((value>>28)&$7f))
		PokeB(*memory+*pos\Value+1, $80|((value>>21)&$7f))
		PokeB(*memory+*pos\Value+2, $80|((value>>14)&$7f))
		PokeB(*memory+*pos\Value+3, $80|((value>>7)&$7f))
		PokeB(*memory+*pos\Value+4, value&$7f)
		value=5
	Else
		value=0
	EndIf
	*pos\Value+value
	ProcedureReturn value
EndProcedure
Procedure.l BM_String(value.s,*memory,*pos.Reference)
	; Writes string value into memory, starting at position *pos
	; Returns number of used Bytes...
	Protected length=Len(value)
	If length
		PokeS(*memory+*pos\Value,value,length)
		*pos\Value+length
	EndIf
	ProcedureReturn length
EndProcedure
Procedure.l BM_Object(OID.s,*memory,*pos.Reference)
	; Writes OID object into memory starting at position *pos
	; Returns number of used bytes
	Protected value
	Protected i,n
	Protected length=0
	If PeekB(@OID)='.'
		OID=PeekS(@OID+1)
	EndIf
	n=CountString(OID,".")
	value=Val(StringField(OID,1,".")) *40 + Val(StringField(OID,2,"."))
	length+BM_Value(value,*memory,*pos)
	If CountString(OID,".") > 1
		For i=3 To n+1
			length+BM_Value(Val(StringField(OID,i,".")),*memory,*pos)
		Next
	EndIf
	ProcedureReturn length
EndProcedure
Procedure.l BM_Move(value.l,length.l,*memory,*pos.Reference)
	; Insert byte value into memory block...
	; Returns total length
	CopyMemory(*memory+*pos\Value-length,*memory+*pos\Value-length+2,length)
	PokeB(*memory+*pos\Value-length,value)
	PokeB(*memory+*pos\Value-length+1,length)
	*pos\Value+2
	ProcedureReturn length+2
EndProcedure
Procedure.l BM_Null(value.l,*memory,*pos.Reference)
	; Writes byte value into memory address...
	; Returns length (=2)
	PokeB(*memory+*pos\Value,value)
	PokeB(*memory+*pos\Value+1,0)
	*pos\Value+2
	ProcedureReturn 2
EndProcedure
Procedure.l Ping(n)
	; Pings Station(n)\IP...
	; Returns #True if a reply packet is seen from the station
	Protected EchoMessage.s
	Protected EchoSize
	Protected *Echo.ICMP_ECHO_REPLY
	Protected *EchoResult
	Protected Handle
	With Station(n)
		\Alive=#Station_Down
		
		EchoMessage.s="Michael Vogel"
		EchoSize.l=SizeOf(ICMP_ECHO_REPLY)+Len(EchoMessage)
		*EchoResult=AllocateMemory(EchoSize)
		*Echo=*EchoResult
		If \IP
			Handle=IcmpCreateFile_()
			If IcmpSendEcho_(Handle,\IP,EchoMessage,Len(EchoMessage),0,*EchoResult,EchoSize,500)
				; Received an ICMP-Response...
				If PeekL(*EchoResult)=\IP
					;...from the destination address (otherwise it will be a destination unreachable message from the default gateway)
					\Alive=#Station_Up
				EndIf
			EndIf
			IcmpCloseHandle_(Handle)
		EndIf
		FreeMemory(*EchoResult)
		ProcedureReturn \Alive
		
	EndWith
	
EndProcedure
Procedure.l PDU_Check(n,*memory)
	Protected byte
	Protected length
	Protected pos
	Protected field
	Protected Value.s
	; Class (Bits 7/8)
	; 0 - Universal (integer, string etc.)
	; 1 - Application (IP address, Time Ticks)
	; 2 - Context (complex data)
	; 3 - Private (non standard data)
	; Data Type (Bit 6)
	; 0 - primitive data-type
	; 1 - constructed data-type
	; ASN.1 Type (Bit 5)
	; 0 - no
	; 1 - yes
	With SNMP(n)
		pos=0
		Repeat
			byte=PeekB(*memory+pos)&$ff
			;Debug "Field: "+Str(field)+"  Pos: "+Str(pos)+" (=$"+Hex(byte&$ff)+")"
			pos+1
			length=BE_Length(*memory,@pos);
			Select byte>>6;						class...
				; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			Case 0;										universal class
				; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
				If byte&$20;							constructed data type
					If byte&$10;						ASN.1
						;Debug "   Length: "+Str(length)
					EndIf
				Else;										primitive data type
					Select byte&$f
					Case 2
						\ValueType=#TypeInteger
						Value=Str(BE_Integer(*memory+pos,length))
						;Debug "   integer: "+Value
					Case 3
						;Debug "   bit string"
					Case 4
						\ValueType=#TypeString
						Value=PeekS(*memory+pos,length)
						;Debug "   octet string: "+Value
					Case 5
						;Debug "   null"
					Case 6
						\ValueType=#TypeObject
						Value=BE_Object(*memory+pos,length)
						;Debug "   object: "+Value
					Default
						Debug Str(n)+" UNKNOWN TYPE: "+Str(byte)
					EndSelect
					pos+length
				EndIf
				; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			Case 1;										application
				; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
				If byte&$20=0;						primitive data type
					Select byte&$f
					Case 3;							ticks
						Value=Str(BE_Integer(*memory+pos,length))
						\ValueType=#TypeTicks
					EndSelect
				EndIf
				; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			Case 2;										context specific
				; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
				If byte&$20;							constructed data type
					If byte=$A2
						; $A2 GetResponse PDU...
					EndIf
				Else;										primitive data type
					Debug Str(n)+" ERROR: Unknown Packet"
					\Status=#SNMP_Error
					field=#Field_Nil
				EndIf
			EndSelect
			; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			Select field
			Case #Field_ErrorState
				If Val(Value)
					\Status=#SNMP_Error_Name
					Debug \Status
					Debug Str(n)+" NAME ERROR: "+Value
					field=#Field_Nil
				EndIf
			Case #Field_RequestID
				If Val(Value)<>\RequestID
					\Status=#SNMP_Error_RID
					Debug Str(n)+" RID ERROR: "+Value+"~"+Value
					field=#Field_Nil
				EndIf
			Case #Field_OID
				\ResponseOID=Value
				If (\GetType=#Get) And (Value<>\OID)
					\Status=#SNMP_Error_OID
					Debug Str(n)+" OID ERROR: "+Value+"~"+\OID
					field=#Field_Nil
				EndIf
			Case #Field_Variable
				SNMP(n)\Value=Value
				\Status=#SNMP_Ok
			EndSelect
			field+1
		Until field>#Field_Variable
		ProcedureReturn \Status
	EndWith
EndProcedure
Procedure.l PDU_Make(n,*memory)
	; compose SNMP packet into reserved memory (548 bytes)
	; n = Request number
	; Returns packet length
	Protected length
	Protected pos
	Protected PositionA,PositionB
	With SNMP(n)
		RequestID+1;Random(65535)
		\RequestID=RequestID
		If \GetType<>#GET_NEXT : \GetType=#GET : EndIf
		; SNMPv1
		length=BM_Value($00,*memory,@pos)
		length=BM_Move($02,length,*memory,@pos)
		; Community
		length=BM_String(Station(\StationNumber)\Community,*memory,@pos)
		length=BM_Move($04,length,*memory,@pos)
		PositionA=pos
		; Request ID
		length=BM_Integer(\RequestID,*memory,@pos)
		length=BM_Move($02,length,*memory,@pos)
		; Error-Status
		length=BM_Value(0,*memory,@pos)
		length=BM_Move($02,length,*memory,@pos)
		; Error-Index
		length=BM_Value(0,*memory,@pos)
		length=BM_Move($02,length,*memory,@pos)
		PositionB=pos
		; OID
		length=BM_Object(\OID,*memory,@pos)
		\OID=BE_Object(*memory+PositionB,length); put normalized OID into database
		length=BM_Move($06,length,*memory,@pos)
		; NULL
		length=BM_Null($05,*memory,@pos)
		; Envelope OID and Null-field (two times)
		length=BM_Move($30,pos-PositionB,*memory,@pos)
		length=BM_Move($30,pos-PositionB,*memory,@pos)
		; Envelope Request-ID, Error Information and OID-Envelope
		length=BM_Move(\GetType,pos-PositionA,*memory,@pos)
		; Envelope all SNMP fields
		length=BM_Move($30,pos,*memory,@pos)
	EndWith
	ProcedureReturn pos
EndProcedure
Procedure.l SNMP_Get(n)
	Protected *pointer
	Protected *Buffer
	Protected Status
	Protected Start
	Protected SockInfo.sockaddr_in
	Protected SockIdent
	With SNMP(n)
		\Value=""
		\ValueType=#TypeUnknown
		\Status=#SNMP_Unknown
		If Station(\StationNumber)\IP
			*pointer=Sockinfo
			sockinfo\sin_family=#AF_INET
			sockinfo\sin_port=htons_(161)
			sockinfo\sin_addr=Station(\StationNumber)\IP
			SockIdent=SOCKET_(#AF_INET,2,0)
			If SockIdent<>#INVALID_SOCKET
				*Buffer=AllocateMemory(#SNMP_MaxPacketSize)
				If *Buffer
					Status=PDU_Make(n,*Buffer)
					If Status
						If  sendto_(SockIdent,*Buffer,Status,0,*pointer,SizeOf(sockaddr_in)) <> #SOCKET_ERROR
							;Status=0
							Start=Date()
							Repeat
								Delay(1)
								Status=recv_(SockIdent,*Buffer,#SNMP_MaxPacketSize,2)
								If Date()-Start>5
									Status=#SOCKET_ERROR
								EndIf
							Until Status<>0
							If Status<>#SOCKET_ERROR
								;ReAllocateMemory(*Buffer,Status)
								Status=PDU_Check(n,*Buffer)
								\Status=Status
							Else
								Status=0
								\Status=#SNMP_Error
							EndIf
						EndIf
					EndIf
					FreeMemory(*Buffer)
				EndIf
			EndIf
		EndIf
	EndWith
	ProcedureReturn Status
EndProcedure
Procedure Main()
	If InitNetwork()
		Station(0)\IP=inet_addr_("172.16.222.222")
		Station(0)\Community="public"
		; *** just for testing ***
		Protected i
		For i=1 To 7
			SNMP(i)\StationNumber=0
			SNMP(i)\OID="1.3.6.1.2.1.1."+Str(i)+".0"
			SNMP(i)\Gettype=#GET
		Next i
		For i=1 To 7
			SNMP(i+7)\StationNumber=0
			SNMP(i+7)\OID=".1.3.6.1.2.1.2.2.1."+Str(i)+".1"
			SNMP(i+7)\Gettype=#GET
		Next i
		If Ping(0)=#Station_Up
			
			; *** brute force, have to be modified ***
			For i=1 To 14
				CreateThread(@SNMP_Get(),i)
			Next i
			Delay(2000)   ;)
			Protected Look.s
			For i=1 To 14
				Look+"[ "+Str(i)+":"+Str(SNMP(i)\Status)+","+Str(SNMP(i)\ValueType)+" ] "+SNMP(i)\Value+#CR$
				Debug "~~~ "+Str(i)+" ~~~"
				Debug Str(SNMP(i)\Status)+" / "+Str(SNMP(i)\ValueType)+" / "+SNMP(i)\ResponseOID
				Debug SNMP(i)\Value
			Next i
			MessageRequester("Results",Look)
		EndIf
	EndIf
EndProcedure
Main()
Bringing up something old (and assuming herr Vogel is still around 
) did you fix the issue with hex vs. octal?
			
			
									
									( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB - upgrade incoming...)
( The path to enlightenment and the PureBasic Survival Guide right here... )
						( The path to enlightenment and the PureBasic Survival Guide right here... )


