I have created a small package for SNMP (Simple Network Management Protocol). It does BER-encoding and decoding of the SNMP V1 protocol. There is also a udp-send-and-receive function for sbcl, and some salt-functions for getting a value from the agent, and a walk function. Then there are some test-functions, and some comments in the code.
There is already a SNMP project on common-lisp.net, (cl-snmp or SYSMAN) but it is not maintained lately, I could not easily make it compile on sbcl, it is not marked as Free Software, and I could not get in contact with the author.
There is no project participants beyond myself.
The code is GPLv2 or later.
My gpg-key: riise@egg:~$ gpg --armor --export riise -----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1.4.1 (GNU/Linux)
mQGiBEIQo9cRBADfR4yqLWOkn2LJoWPwipwFhZ6C6TU+TYnXLGGhFYyRZGZWZmMa hFGW56HcU4rzR2JqwrE7lC6KiZ7eu6J89SboyYfptz9SD8Mc3kMp8Bo4Ce55jo6J hnbFRFgOh9j9wABYASXjaWNtgtM14TsAJh5X84DUJTs2Q4P9k/gttzryCwCg6uAI 3tfqx445PmcEF8WvQxsBkEkEAIXQ5rKmw8OafwGAqmw4NMHNrJubK7Rjmy8VcKXG 9+fOweYOp/iABXyEv28sbFWgL5/aKaDhYN6evPELFNbdyt0XVbNUKpunqoAsVGs7 lx9iOuuBM3fJuhRS4WX0n3484VESdWBiawNPp678fCgM0mdfoIp9pWYMSjuJJ4y1 RgAVA/9XOkuNpT7dQigUWsZ4tT2HhM09Exh/dGRZg9ED6l+oPr5VG8FMY9+wKqAM kew/KNbFl3Tl1VsshXlItYoTLwHxxifZAdNRxvdXmGtce+FcnB5coFk4OJNf6PUf gleh9K8TKziHVIwkuDuddukUuSwqhO6OT3ZUgdV2d7P14PmAhLQkSm9oYW4gVXIg Umlpc2UgPGpvaGFuQHJpaXNlLWRhdGEubm8+iF4EExECAB4FAkIQo9cCGwMGCwkI BwMCAxUCAwMWAgECHgECF4AACgkQLwkimGnQPWkwgwCg5dXxX4gNEn80u37EA87I IJ4fvrEAn3rtTEx/tET19rWON1UylvC8Km1WuQENBEIQo9kQBACxdlIJlBmvIQe+ 32kYnUXPKhoaAMXvsxopV10StIPMyVDtRbodwMeHgVg09KPyzgag00W2bKhF13yu pxtBG1upZNFKJx2qCEvM4PJ+vbKvtYhuToBRAR9A/8cB+RmMoGn5PW/32+Fpx403 gdJLzQ/bGZyQzAs7TeYAZupzgGp2awADBgQAjJZhpLRimOfRhwdE6TrMbMiX2T4U YC+k72kALwqKx8Sx6VgKV4bih+4o6dONuxNAUCr+xx9sNK4dppkRmiF3FCN491sf XCk5lgbYPk/IN+MdyOpMva/YR2bcfb4l8vhQYEnPrSvdpDtNLpuBh5knXwYRLClJ WC4RQjKNft2HjkKISQQYEQIACQUCQhCj2QIbDAAKCRAvCSKYadA9acZ8AJ90+lbz S7O2kjiZGvo6ek23qygnOACguPQlw/K8ohbH8zllOhJiwR9iOmk= =Gzz+ -----END PGP PUBLIC KEY BLOCK-----
The code itself is at http://www.riise-data.net/snmp1/.
When I announce it on comp.lang.lisp, I would like to have the project in shape on common-lisp.net.
The rest of this message is just about what I would post there:
================================================================
I have put together an ASDF-system for SNMP. Here is a description of how it works:
The Simple Network Management Protocol (SNMP) has, on the bottom, tagged values of types integer, octet string, object identifier, null and sequence.
The object identifiers are pointers into an agent's database of values.
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 or system.sysDescr.0 for short. There are no conversions between the two forms in this package.
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)
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 sequence is encoded into two octets in this case, a tag and the length of the other two values:
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 variable binding.
The Protocol Transfer Unit (PDU) uses a sequence of these, so we wrap it in another sequence:
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 a 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)
When we decode it we see that we have a :response PDU, where the :null in the varbind has been replaced with the value from the agent:
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.
The encoding and decoding functions should work in all implementations, but the udp-send-and-receive function will have to be coded for implementations other than sbcl.
The license is GPLv2 or later.
The package is available on common-lisp.net under the name SNMP1. To get it, issue this command
cvs -d ....