Snmp Get

Just starting out? Need help? Post your questions and find answers here.
User avatar
Droopy
Enthusiast
Enthusiast
Posts: 658
Joined: Thu Sep 16, 2004 9:50 pm
Location: France
Contact:

Snmp Get

Post by Droopy »

Anybody has information how to implement this function in PureBasic ?
User avatar
Michael Vogel
Addict
Addict
Posts: 2807
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: Snmp Get

Post by Michael Vogel »

Droopy wrote:Anybody has information how to implement this function in PureBasic ?
Someone did some snmp code in the german forum, using an UDPnetwork lib (which I couldn't install, but this should be possible)...

http://www.purebasic.fr/german/viewtopi ... light=snmp
User avatar
Droopy
Enthusiast
Enthusiast
Posts: 658
Joined: Thu Sep 16, 2004 9:50 pm
Location: France
Contact:

Post by Droopy »

Thanks
Beach
Enthusiast
Enthusiast
Posts: 677
Joined: Mon Feb 02, 2004 3:16 am
Location: Beyond the sun...

Post by Beach »

Sorry to wake-up an old thread - just wondering if you made any headway using SNMP? I would really like to use it.

Thanks...
-Beach
User avatar
Michael Vogel
Addict
Addict
Posts: 2807
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Post by Michael Vogel »

And an additional question - is it possible to write a SNMP "agent" in Pure-Basic? Or does anyone know a simple free standalone program doing this?

Michael

*) the agent should simulate a simple SNMP managable device, what means the program should deliver answers to SNMP get etc.
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Post by blueznl »

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

Post by Michael Vogel »

blueznl wrote:Looking for SNMP code examples... anyone that has a suggestion?
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...

Indeed not brilliant :cry: but at least it works to scan a network :wink:

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
User avatar
pdwyer
Addict
Addict
Posts: 2813
Joined: Tue May 08, 2007 1:27 pm
Location: Chiba, Japan

Post by pdwyer »

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)
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
peterb
User
User
Posts: 60
Joined: Sun Oct 02, 2005 8:55 am
Location: Czech Republic
Contact:

Post by peterb »

SNMP GET and GET_NEXT
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.
Beach
Enthusiast
Enthusiast
Posts: 677
Joined: Mon Feb 02, 2004 3:16 am
Location: Beyond the sun...

Post by Beach »

Works great peterb! I tested it on a old Cisco 2500 router and it worked fine. I wish I could help you refine it, but it's way out of my league. Maybe Droopy or another guru here can help out. Its going to be wonderful being able to use SNMP in some of my monitoring apps. Thanks man!
-Beach
User avatar
Droopy
Enthusiast
Enthusiast
Posts: 658
Joined: Thu Sep 16, 2004 9:50 pm
Location: France
Contact:

Post by Droopy »

works fine @works
deep later

Thanks a lot :wink:
User avatar
Michael Vogel
Addict
Addict
Posts: 2807
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Post by Michael Vogel »

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 :cry:

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 
2. the debug output

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>>
3. The code // only some debug-lines have been added...

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
[/list]
User avatar
Michael Vogel
Addict
Addict
Posts: 2807
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Post by Michael Vogel »

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:

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)
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
User avatar
Michael Vogel
Addict
Addict
Posts: 2807
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Post by Michael Vogel »

Got it :D

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()
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Post by blueznl »

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)
( The path to enlightenment and the PureBasic Survival Guide right here... )
Post Reply