From: Johan Ur Riise
Subject: SNMP1 - a package for Simple Network Management Protocol
Date: 
Message-ID: <87lkkjkglg.fsf@morr.riise-data.net>
I have put a package for SNMP communication on common-lisp.net,
http://common-lisp.net/project/snmp1/

Part of the doc:

The Simple Network Management Protocol (SNMP) has, on the bottom, tagged values
of types integer, octet string, object identifier, null and sequence. 

The oid's (object identifiers) are pointers into an agent's information database.

For example, an object identifier
could look like this: (:object-identifier ".1.3.6.1.2.1.1.1.0")

This specific object identifier also has the name 
.iso.org.dod.internet.mgmt.mib-2.system.sysDescr.0 . 
You can set or get this piece of data using the oid as a
reference.

On the wire the values are encoded with Basic Encoding Rules (BER). The 
oid above would be encoded like this:

SNMP1> (ber-encode '(:object-identifier ".1.3.6.1.2.1.1.1.0"))
=> #(6 8 43 6 1 2 1 1 1 0)

Basically, the encoding is a tag octet, a length octet, and an octet
for each sub-identifier, with a few special cases.

An integer would be coded like this:

SNMP1> (ber-encode '(:integer 12345))
=> #(2 2 48 57)

Again a tag, a length and a number of octets representing the value.

This also works the other way around:

SNMP1> (ber-decode #(2 2 48 57))
=> (:INTEGER 12345)

When you need to encode a computed value, use backquote instead of
quote, and use the comma operator to unquote. For example:

SNMP1> (let ((request-id (random 1000)))
         (ber-encode `(:integer ,request-id)))
=> #(2 2 0 254)

A null value is a tag and a length of zero:

SNMP1> (ber-encode '(:null))
=> #(5 0)

We now put two of these values in a sequence. The effect is that
two octets are prepended to the other encodings, a sequence tag and the 
length of the content of the sequence:

SNMP1> (ber-encode '(:sequence (:object-identifier ".1.3.6.1.2.1.1.1.0") (:null)))
=> #(48 12 6 8 43 6 1 2 1 1 1 0 5 0)

This form, a sequence of an oid and a value, is in SNMP called a varbind 
(variable binding).

The Protocol Transfer Unit (PDU) uses a sequence of these, so we wrap it in
another sequence to get a list of varbinds:

SNMP1> (ber-encode '(:sequence (:sequence (:object-identifier ".1.3.6.1.2.1.1.1.0") (:null))))
=> #(48 14 48 12 6 8 43 6 1 2 1 1 1 0 5 0)

This is a GET PDU constructed around the previous varbind list:
(:get (:integer 12345) (:integer 0) (:integer 0) 
      (:sequence (:sequence (:object-identifier ".1.3.6.1.2.1.1.1.0") (:null))))

The :get keyword is the same as :sequence, except it has its own tag. The first integer
is the request id, whatever we put in there we get back in the response. 

To finish it up, we create an SNMP message, which is a sequence of version, community
and the PDU. Version is 0 for version 1. The community is a kind of password.

(:sequence (:integer 0) (:octet-string "public")
	   (:get (:integer 12345) (:integer 0) (:integer 0) 
		 (:sequence (:object-identifier ".1.3.6.1.2.1.1.1.0") (:null))))

We encode the complete message, the result is of type (SIMPLE-ARRAY (UNSIGNED-BYTE 8))

SNMP1> (ber-encode '(:sequence (:integer 0) (:octet-string "public")
		     (:get (:integer 12345) (:integer 0) (:integer 0) 
		      (:sequence (:sequence (:object-identifier ".1.3.6.1.2.1.1.1.0") (:null))))))
=> #(48 39 2 1 0 4 6 112 117 98 108 105 99 160 26 2 2 48 57 2 1 0 2 1 0 48 14 48
  12 6 8 43 6 1 2 1 1 1 0 5 0)

Then we send this message to the agent. The udp-send-and-receive function is
a wrapper around sbcl's socket library, the parameters are ip-adress, port,
wait-between-retries, retry-count and then the buffer to send.

SNMP1> (udp-send-and-receive #(127 0 0 1) 161 1 3 *)
=> #(48 124 2 1 0 4 6 112 117 98 108 105 99 162 111 2 2 48 57 2 1 0 2 1 0 48 99 48
  97 6 8 43 6 1 2 1 1 1 0 4 85 76 105 110 117 120 32 98 114 101 97 100 32 50 46
  54 46 49 53 45 50 55 45 97 109 100 54 52 45 103 101 110 101 114 105 99 32 35
  49 32 83 77 80 32 80 82 69 69 77 80 84 32 70 114 105 32 68 101 99 32 56 32 49
  55 58 53 48 58 53 52 32 85 84 67 32 50 48 48 54 32 120 56 54 95 54 52)

The array above is the encoded response message from the agent. 

When we decode it we see that we have a :response PDU, where the :null in
the varbind has been replaced with an octet string from the agent's
information database:

SNMP1> (ber-decode *)
=> (:SEQUENCE (:INTEGER 0) (:OCTET-STRING "public")
 (:RESPONSE (:INTEGER 12345) (:INTEGER 0) (:INTEGER 0)
  (:SEQUENCE
   (:SEQUENCE (:OBJECT-IDENTIFIER ".1.3.6.1.2.1.1.1.0")
    (:OCTET-STRING
     "Linux bread 2.6.15-27-amd64-generic #1 SMP PREEMPT Fri Dec 8 17:50:54 UTC 2006 x86_64")))))

We can also do SET, GETNEXT and TRAP PDUs.

There is no conversion function between the symbolic representation and the dotted integer
representation of object identifiers in this package, i.e. there is no mib-compiler.

The encoding and decoding functions should work in all implementations. The
udp-send-and-receive function will have to be coded again for implementations other than sbcl.
As long as you have means to send and receive discrete udp packets, that should be easy.

This is Free Software. The license is GPLv2 or later. 

From: Rainer Joswig
Subject: Re: SNMP1 - a package for Simple Network Management Protocol
Date: 
Message-ID: <joswig-8E72FC.18171404012007@news-europe.giganews.com>
In article <··············@morr.riise-data.net>,
 Johan Ur Riise <·····@riise-data.no> wrote:

> I have put a package for SNMP communication on common-lisp.net,
> http://common-lisp.net/project/snmp1/

What are the differences to this one:

http://www.switch.ch/misc/leinen/snmp/sysman.html

> 
> Part of the doc:
> 
> The Simple Network Management Protocol (SNMP) has, on the bottom, tagged 
> values
> of types integer, octet string, object identifier, null and sequence. 
> 
> The oid's (object identifiers) are pointers into an agent's information 
> database.
> 
> For example, an object identifier
> could look like this: (:object-identifier ".1.3.6.1.2.1.1.1.0")
> 
> This specific object identifier also has the name 
> .iso.org.dod.internet.mgmt.mib-2.system.sysDescr.0 . 
> You can set or get this piece of data using the oid as a
> reference.
> 
> On the wire the values are encoded with Basic Encoding Rules (BER). The 
> oid above would be encoded like this:
> 
> SNMP1> (ber-encode '(:object-identifier ".1.3.6.1.2.1.1.1.0"))
> => #(6 8 43 6 1 2 1 1 1 0)
> 
> Basically, the encoding is a tag octet, a length octet, and an octet
> for each sub-identifier, with a few special cases.
> 
> An integer would be coded like this:
> 
> SNMP1> (ber-encode '(:integer 12345))
> => #(2 2 48 57)
> 
> Again a tag, a length and a number of octets representing the value.
> 
> This also works the other way around:
> 
> SNMP1> (ber-decode #(2 2 48 57))
> => (:INTEGER 12345)
> 
> When you need to encode a computed value, use backquote instead of
> quote, and use the comma operator to unquote. For example:
> 
> SNMP1> (let ((request-id (random 1000)))
>          (ber-encode `(:integer ,request-id)))
> => #(2 2 0 254)
> 
> A null value is a tag and a length of zero:
> 
> SNMP1> (ber-encode '(:null))
> => #(5 0)
> 
> We now put two of these values in a sequence. The effect is that
> two octets are prepended to the other encodings, a sequence tag and the 
> length of the content of the sequence:
> 
> SNMP1> (ber-encode '(:sequence (:object-identifier ".1.3.6.1.2.1.1.1.0") 
> (:null)))
> => #(48 12 6 8 43 6 1 2 1 1 1 0 5 0)
> 
> This form, a sequence of an oid and a value, is in SNMP called a varbind 
> (variable binding).
> 
> The Protocol Transfer Unit (PDU) uses a sequence of these, so we wrap it in
> another sequence to get a list of varbinds:
> 
> SNMP1> (ber-encode '(:sequence (:sequence (:object-identifier 
> ".1.3.6.1.2.1.1.1.0") (:null))))
> => #(48 14 48 12 6 8 43 6 1 2 1 1 1 0 5 0)
> 
> This is a GET PDU constructed around the previous varbind list:
> (:get (:integer 12345) (:integer 0) (:integer 0) 
>       (:sequence (:sequence (:object-identifier ".1.3.6.1.2.1.1.1.0") 
>       (:null))))
> 
> The :get keyword is the same as :sequence, except it has its own tag. The 
> first integer
> is the request id, whatever we put in there we get back in the response. 
> 
> To finish it up, we create an SNMP message, which is a sequence of version, 
> community
> and the PDU. Version is 0 for version 1. The community is a kind of password.
> 
> (:sequence (:integer 0) (:octet-string "public")
> 	   (:get (:integer 12345) (:integer 0) (:integer 0) 
> 		 (:sequence (:object-identifier ".1.3.6.1.2.1.1.1.0") (:null))))
> 
> We encode the complete message, the result is of type (SIMPLE-ARRAY 
> (UNSIGNED-BYTE 8))
> 
> SNMP1> (ber-encode '(:sequence (:integer 0) (:octet-string "public")
> 		     (:get (:integer 12345) (:integer 0) (:integer 0) 
> 		      (:sequence (:sequence (:object-identifier ".1.3.6.1.2.1.1.1.0") 
> (:null))))))
> => #(48 39 2 1 0 4 6 112 117 98 108 105 99 160 26 2 2 48 57 2 1 0 2 1 0 48 14 
> 48
>   12 6 8 43 6 1 2 1 1 1 0 5 0)
> 
> Then we send this message to the agent. The udp-send-and-receive function is
> a wrapper around sbcl's socket library, the parameters are ip-adress, port,
> wait-between-retries, retry-count and then the buffer to send.
> 
> SNMP1> (udp-send-and-receive #(127 0 0 1) 161 1 3 *)
> => #(48 124 2 1 0 4 6 112 117 98 108 105 99 162 111 2 2 48 57 2 1 0 2 1 0 48 
> 99 48
>   97 6 8 43 6 1 2 1 1 1 0 4 85 76 105 110 117 120 32 98 114 101 97 100 32 50 
>   46
>   54 46 49 53 45 50 55 45 97 109 100 54 52 45 103 101 110 101 114 105 99 32 
>   35
>   49 32 83 77 80 32 80 82 69 69 77 80 84 32 70 114 105 32 68 101 99 32 56 32 
>   49
>   55 58 53 48 58 53 52 32 85 84 67 32 50 48 48 54 32 120 56 54 95 54 52)
> 
> The array above is the encoded response message from the agent. 
> 
> When we decode it we see that we have a :response PDU, where the :null in
> the varbind has been replaced with an octet string from the agent's
> information database:
> 
> SNMP1> (ber-decode *)
> => (:SEQUENCE (:INTEGER 0) (:OCTET-STRING "public")
>  (:RESPONSE (:INTEGER 12345) (:INTEGER 0) (:INTEGER 0)
>   (:SEQUENCE
>    (:SEQUENCE (:OBJECT-IDENTIFIER ".1.3.6.1.2.1.1.1.0")
>     (:OCTET-STRING
>      "Linux bread 2.6.15-27-amd64-generic #1 SMP PREEMPT Fri Dec 8 17:50:54 
>      UTC 2006 x86_64")))))
> 
> We can also do SET, GETNEXT and TRAP PDUs.
> 
> There is no conversion function between the symbolic representation and the 
> dotted integer
> representation of object identifiers in this package, i.e. there is no 
> mib-compiler.
> 
> The encoding and decoding functions should work in all implementations. The
> udp-send-and-receive function will have to be coded again for implementations 
> other than sbcl.
> As long as you have means to send and receive discrete udp packets, that 
> should be easy.
> 
> This is Free Software. The license is GPLv2 or later. 

That's unfortunate. LGPL or LLGPL would be better??!
From: Johan Ur Riise
Subject: Re: SNMP1 - a package for Simple Network Management Protocol
Date: 
Message-ID: <87k602ica4.fsf@morr.riise-data.net>
Rainer Joswig <······@lisp.de> writes:

> In article <··············@morr.riise-data.net>,
>  Johan Ur Riise <·····@riise-data.no> wrote:
> 
> > I have put a package for SNMP communication on common-lisp.net,
> > http://common-lisp.net/project/snmp1/
> 
> What are the differences to this one:
> 
> http://www.switch.ch/misc/leinen/snmp/sysman.html
> 

It runs in sbcl
It has a straigthforward interface
It is free software
From: Matthew D Swank
Subject: Re: SNMP1 - a package for Simple Network Management Protocol
Date: 
Message-ID: <pan.2007.01.11.07.37.01.664519@c.net>
On Fri, 05 Jan 2007 00:48:35 +0100, Johan Ur Riise wrote:

> It is free software

I suppose, but straight GPL seems like a hard sell in the Common Lisp free
software ecosystem* (especially for what is essentially a library).

Matt

*CLisp and GCL not withstanding.
-- 
"You do not really understand something unless you can
 explain it to your grandmother." — Albert Einstein.
From: ······@corporate-world.lisp.de
Subject: Re: SNMP1 - a package for Simple Network Management Protocol
Date: 
Message-ID: <1168565739.850410.186720@38g2000cwa.googlegroups.com>
Matthew D Swank schrieb:

> On Fri, 05 Jan 2007 00:48:35 +0100, Johan Ur Riise wrote:
>
> > It is free software
>
> I suppose, but straight GPL seems like a hard sell in the Common Lisp free
> software ecosystem* (especially for what is essentially a library).

Yep.

That's why there is the LGPL and LLGPL.

http://www.cliki.net/LLGPL

>
> Matt
>
> *CLisp and GCL not withstanding.
> --
> "You do not really understand something unless you can
>  explain it to your grandmother." - Albert Einstein.
From: Johan Ur Riise
Subject: Re: SNMP1 - a package for Simple Network Management Protocol
Date: 
Message-ID: <873b6hhysa.fsf@morr.riise-data.net>
Matthew D Swank <·······································@c.net> writes:

> On Fri, 05 Jan 2007 00:48:35 +0100, Johan Ur Riise wrote:
> 
> > It is free software
> 
> I suppose, but straight GPL seems like a hard sell in the Common Lisp free
> software ecosystem* (especially for what is essentially a library).
> 
Noted, but this is what I want.