UNPKG

snmp-native

Version:

A native Javascript SNMP implementation for Node.js

1,337 lines (887 loc) 73.9 kB
<!DOCTYPE html> <html> <head> <title>snmp.js</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <ul id="jump_to"> <li> <a class="large" href="javascript:void(0);">Jump To &hellip;</a> <a class="small" href="javascript:void(0);">+</a> <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="example.html"> example.js </a> <a class="source" href="asn1ber.html"> asn1ber.js </a> <a class="source" href="snmp.html"> snmp.js </a> </div> </li> </ul> <ul class="sections"> <li id="title"> <div class="annotation"> <h1>snmp.js</h1> </div> </li> <li id="section-1"> <div class="annotation"> <div class="pilwrap for-h2"> <a class="pilcrow" href="#section-1">&#182;</a> </div> <h2>Introduction</h2> </div> </li> <li id="section-2"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-2">&#182;</a> </div> <p>This is <code>node-snmp-native</code>, a native (Javascript) implementation of an SNMP client library targeted at Node.js. It&#39;s MIT licensed and available at <a href="https://github.com/calmh/node-snmp-native">https://github.com/calmh/node-snmp-native</a></p> <p>(c) 2012 Jakob Borg, Nym Networks</p> </div> <div class="content"><div class='highlight'><pre><span class="string">"use strict"</span>;</pre></div></div> </li> <li id="section-3"> <div class="annotation"> <div class="pilwrap for-h2"> <a class="pilcrow" href="#section-3">&#182;</a> </div> <h2>Code</h2> </div> </li> <li id="section-4"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-4">&#182;</a> </div> <p>This file implements a structure representing an SNMP message and routines for converting to and from the network representation.</p> <p>Define our external dependencies.</p> </div> <div class="content"><div class='highlight'><pre><span class="keyword">var</span> assert = require(<span class="string">'assert'</span>); <span class="keyword">var</span> dgram = require(<span class="string">'dgram'</span>); <span class="keyword">var</span> events = require(<span class="string">'events'</span>);</pre></div></div> </li> <li id="section-5"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-5">&#182;</a> </div> <p>We also need our ASN.1 BER en-/decoding routines.</p> </div> <div class="content"><div class='highlight'><pre><span class="keyword">var</span> asn1ber = require(<span class="string">'./asn1ber'</span>);</pre></div></div> </li> <li id="section-6"> <div class="annotation"> <div class="pilwrap for-h2"> <a class="pilcrow" href="#section-6">&#182;</a> </div> <h2>Basic structures</h2> </div> </li> <li id="section-7"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-7">&#182;</a> </div> <p>A <code>VarBind</code> is the innermost structure, containing an OID-Value pair.</p> </div> <div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">VarBind</span><span class="params">()</span> {</span> <span class="keyword">this</span>.type = <span class="number">5</span>; <span class="keyword">this</span>.value = <span class="literal">null</span>; }</pre></div></div> </li> <li id="section-8"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-8">&#182;</a> </div> <p>The <code>PDU</code> contains the SNMP request or response fields and a list of <code>VarBinds</code>.</p> </div> <div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">PDU</span><span class="params">()</span> {</span> <span class="keyword">this</span>.type = asn1ber.pduTypes.GetRequestPDU; <span class="keyword">this</span>.reqid = <span class="number">1</span>; <span class="keyword">this</span>.error = <span class="number">0</span>; <span class="keyword">this</span>.errorIndex = <span class="number">0</span>; <span class="keyword">this</span>.varbinds = [ <span class="keyword">new</span> VarBind() ]; }</pre></div></div> </li> <li id="section-9"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-9">&#182;</a> </div> <p>The <code>Packet</code> contains the SNMP version and community and the <code>PDU</code>.</p> </div> <div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">Packet</span><span class="params">()</span> {</span> <span class="keyword">this</span>.version = <span class="number">1</span>; <span class="keyword">this</span>.community = <span class="string">'public'</span>; <span class="keyword">this</span>.pdu = <span class="keyword">new</span> PDU(); }</pre></div></div> </li> <li id="section-10"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-10">&#182;</a> </div> <p>Allow consumers to create packet structures from scratch.</p> </div> <div class="content"><div class='highlight'><pre>exports.Packet = Packet;</pre></div></div> </li> <li id="section-11"> <div class="annotation"> <div class="pilwrap for-h2"> <a class="pilcrow" href="#section-11">&#182;</a> </div> <h2>Private helper functions</h2> </div> </li> <li id="section-12"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-12">&#182;</a> </div> <p>Concatenate several buffers to one.</p> </div> <div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">concatBuffers</span><span class="params">(buffers)</span> {</span> <span class="keyword">var</span> total, cur = <span class="number">0</span>, buf;</pre></div></div> </li> <li id="section-13"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-13">&#182;</a> </div> <p>First we calculate the total length,</p> </div> <div class="content"><div class='highlight'><pre> total = buffers.reduce(<span class="function"><span class="keyword">function</span> <span class="params">(tot, b)</span> {</span> <span class="keyword">return</span> tot + b.length; }, <span class="number">0</span>);</pre></div></div> </li> <li id="section-14"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-14">&#182;</a> </div> <p>then we allocate a new Buffer large enough to contain all data,</p> </div> <div class="content"><div class='highlight'><pre> buf = <span class="keyword">new</span> Buffer(total); buffers.forEach(<span class="function"><span class="keyword">function</span> <span class="params">(buffer)</span> {</span></pre></div></div> </li> <li id="section-15"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-15">&#182;</a> </div> <p>finally we copy the data into the new larger buffer.</p> </div> <div class="content"><div class='highlight'><pre> buffer.copy(buf, cur, <span class="number">0</span>); cur += buffer.length; }); <span class="keyword">return</span> buf; }</pre></div></div> </li> <li id="section-16"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-16">&#182;</a> </div> <p>Clear a pending packet when it times out or is successfully received.</p> </div> <div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">clearRequest</span><span class="params">(reqs, reqid)</span> {</span> <span class="keyword">var</span> self = <span class="keyword">this</span>; <span class="keyword">var</span> entry = reqs[reqid]; <span class="keyword">if</span> (entry) { <span class="keyword">if</span> (entry.timeout) { clearTimeout(entry.timeout); } <span class="keyword">delete</span> reqs[reqid]; } }</pre></div></div> </li> <li id="section-17"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-17">&#182;</a> </div> <p>Convert a string formatted OID to an array, leaving anything non-string alone.</p> </div> <div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">parseSingleOid</span><span class="params">(oid)</span> {</span> <span class="keyword">if</span> (<span class="keyword">typeof</span> oid !== <span class="string">'string'</span>) { <span class="keyword">return</span> oid; } <span class="keyword">if</span> (oid[<span class="number">0</span>] !== <span class="string">'.'</span>) { <span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">'Invalid OID format'</span>); } oid = oid.split(<span class="string">'.'</span>) .filter(<span class="function"><span class="keyword">function</span> <span class="params">(s)</span> {</span> <span class="keyword">return</span> s.length &gt; <span class="number">0</span>; }) .map(<span class="function"><span class="keyword">function</span> <span class="params">(s)</span> {</span> <span class="keyword">return</span> parseInt(s, <span class="number">10</span>); }); <span class="keyword">return</span> oid; }</pre></div></div> </li> <li id="section-18"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-18">&#182;</a> </div> <p>Fix any OIDs in the &#39;oid&#39; or &#39;oids&#39; objects that are passed as strings.</p> </div> <div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">parseOids</span><span class="params">(options)</span> {</span> <span class="keyword">if</span> (options.oid) { options.oid = parseSingleOid(options.oid); } <span class="keyword">if</span> (options.oids) { options.oids = options.oids.map(parseSingleOid); } }</pre></div></div> </li> <li id="section-19"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-19">&#182;</a> </div> <p>Update targ with attributes from _defs. Any existing attributes on targ are untouched.</p> </div> <div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">defaults</span><span class="params">(targ, _defs)</span> {</span> [].slice.call(arguments, <span class="number">1</span>).forEach(<span class="function"><span class="keyword">function</span> <span class="params">(def)</span> {</span> Object.keys(def).forEach(<span class="function"><span class="keyword">function</span> <span class="params">(key)</span> {</span> <span class="keyword">if</span> (!targ.hasOwnProperty(key)) { targ[key] = def[key]; } }); }); }</pre></div></div> </li> <li id="section-20"> <div class="annotation"> <div class="pilwrap for-h2"> <a class="pilcrow" href="#section-20">&#182;</a> </div> <h2>Encode structure to ASN.1 BER</h2> </div> </li> <li id="section-21"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-21">&#182;</a> </div> <p>Return an ASN.1 BER encoding of a Packet structure. This is suitable for transmission on a UDP socket.</p> </div> <div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">encode</span><span class="params">(pkt)</span> {</span> <span class="keyword">var</span> version, community, reqid, err, erridx, vbs, pdu, message;</pre></div></div> </li> <li id="section-22"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-22">&#182;</a> </div> <p>We only support SNMPv2c, so enforce that version stamp.</p> </div> <div class="content"><div class='highlight'><pre> <span class="keyword">if</span> (pkt.version !== <span class="number">1</span>) { <span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">'Only SNMPv2c is supported.'</span>); }</pre></div></div> </li> <li id="section-23"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-23">&#182;</a> </div> <p>Encode the message header fields.</p> </div> <div class="content"><div class='highlight'><pre> version = asn1ber.encodeInteger(pkt.version); community = asn1ber.encodeOctetString(pkt.community);</pre></div></div> </li> <li id="section-24"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-24">&#182;</a> </div> <p>Encode the PDU header fields.</p> </div> <div class="content"><div class='highlight'><pre> reqid = asn1ber.encodeInteger(pkt.pdu.reqid); err = asn1ber.encodeInteger(pkt.pdu.error); erridx = asn1ber.encodeInteger(pkt.pdu.errorIndex);</pre></div></div> </li> <li id="section-25"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-25">&#182;</a> </div> <p>Encode the PDU varbinds.</p> </div> <div class="content"><div class='highlight'><pre> vbs = []; pkt.pdu.varbinds.forEach(<span class="function"><span class="keyword">function</span> <span class="params">(vb)</span> {</span> <span class="keyword">var</span> oid = asn1ber.encodeOid(vb.oid), val; <span class="keyword">if</span> (vb.type === asn1ber.types.Null) { val = asn1ber.encodeNull(); } <span class="keyword">else</span> <span class="keyword">if</span> (vb.type === asn1ber.types.Integer) { val = asn1ber.encodeInteger(vb.value); } <span class="keyword">else</span> <span class="keyword">if</span> (vb.type === asn1ber.types.IpAddress) { val = asn1ber.encodeIpAddress(vb.value); } <span class="keyword">else</span> <span class="keyword">if</span> (vb.type === asn1ber.types.OctetString) { val = asn1ber.encodeOctetString(vb.value); } <span class="keyword">else</span> { <span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">'Unknown varbind type "'</span> + vb.type + <span class="string">'" in encoding.'</span>); } vbs.push(asn1ber.encodeSequence(concatBuffers([oid, val]))); });</pre></div></div> </li> <li id="section-26"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-26">&#182;</a> </div> <p>Concatenate all the varbinds together.</p> </div> <div class="content"><div class='highlight'><pre> vbs = asn1ber.encodeSequence(concatBuffers(vbs));</pre></div></div> </li> <li id="section-27"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-27">&#182;</a> </div> <p>Create the PDU by concatenating the inner fields and adding a request structure around it.</p> </div> <div class="content"><div class='highlight'><pre> pdu = asn1ber.encodeRequest(pkt.pdu.type, concatBuffers([reqid, err, erridx, vbs]));</pre></div></div> </li> <li id="section-28"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-28">&#182;</a> </div> <p>Create the message by concatenating the header fields and the PDU.</p> </div> <div class="content"><div class='highlight'><pre> message = asn1ber.encodeSequence(concatBuffers([version, community, pdu])); <span class="keyword">return</span> message; } exports.encode = encode;</pre></div></div> </li> <li id="section-29"> <div class="annotation"> <div class="pilwrap for-h2"> <a class="pilcrow" href="#section-29">&#182;</a> </div> <h2>Parse ASN.1 BER into a structure</h2> </div> </li> <li id="section-30"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-30">&#182;</a> </div> <p>Parse an SNMP packet into its component fields. We don&#39;t do a lot of validation so a malformed packet will probably just make us blow up.</p> </div> <div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">parse</span><span class="params">(buf)</span> {</span> <span class="keyword">var</span> pkt, oid, bvb, vb, hdr; pkt = <span class="keyword">new</span> Packet();</pre></div></div> </li> <li id="section-31"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-31">&#182;</a> </div> <p>First we have a sequence marker (two bytes). We don&#39;t care about those, so cut them off.</p> </div> <div class="content"><div class='highlight'><pre> hdr = asn1ber.typeAndLength(buf); assert.equal(asn1ber.types.Sequence, hdr.type); buf = buf.slice(hdr.header);</pre></div></div> </li> <li id="section-32"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-32">&#182;</a> </div> <p>Then comes the version field (integer). Parse it and slice it.</p> </div> <div class="content"><div class='highlight'><pre> pkt.version = asn1ber.parseInteger(buf.slice(<span class="number">0</span>, buf[<span class="number">1</span>] + <span class="number">2</span>)); buf = buf.slice(<span class="number">2</span> + buf[<span class="number">1</span>]);</pre></div></div> </li> <li id="section-33"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-33">&#182;</a> </div> <p>We then get the community. Parse and slice.</p> </div> <div class="content"><div class='highlight'><pre> pkt.community = asn1ber.parseOctetString(buf.slice(<span class="number">0</span>, buf[<span class="number">1</span>] + <span class="number">2</span>)); buf = buf.slice(<span class="number">2</span> + buf[<span class="number">1</span>]);</pre></div></div> </li> <li id="section-34"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-34">&#182;</a> </div> <p>Here&#39;s the PDU structure. We&#39;re interested in the type. Slice the rest.</p> </div> <div class="content"><div class='highlight'><pre> hdr = asn1ber.typeAndLength(buf); assert.ok(hdr.type &gt;= <span class="number">0xA0</span>); pkt.pdu.type = hdr.type - <span class="number">0xA0</span>; buf = buf.slice(hdr.header);</pre></div></div> </li> <li id="section-35"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-35">&#182;</a> </div> <p>The request id field.</p> </div> <div class="content"><div class='highlight'><pre> pkt.pdu.reqid = asn1ber.parseInteger(buf.slice(<span class="number">0</span>, buf[<span class="number">1</span>] + <span class="number">2</span>)); buf = buf.slice(<span class="number">2</span> + buf[<span class="number">1</span>]);</pre></div></div> </li> <li id="section-36"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-36">&#182;</a> </div> <p>The error field.</p> </div> <div class="content"><div class='highlight'><pre> pkt.pdu.error = asn1ber.parseInteger(buf.slice(<span class="number">0</span>, buf[<span class="number">1</span>] + <span class="number">2</span>)); buf = buf.slice(<span class="number">2</span> + buf[<span class="number">1</span>]);</pre></div></div> </li> <li id="section-37"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-37">&#182;</a> </div> <p>The error index field.</p> </div> <div class="content"><div class='highlight'><pre> pkt.pdu.errorIndex = asn1ber.parseInteger(buf.slice(<span class="number">0</span>, buf[<span class="number">1</span>] + <span class="number">2</span>)); buf = buf.slice(<span class="number">2</span> + buf[<span class="number">1</span>]);</pre></div></div> </li> <li id="section-38"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-38">&#182;</a> </div> <p>Here&#39;s the varbind list. Not interested.</p> </div> <div class="content"><div class='highlight'><pre> hdr = asn1ber.typeAndLength(buf); assert.equal(asn1ber.types.Sequence, hdr.type); buf = buf.slice(hdr.header);</pre></div></div> </li> <li id="section-39"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-39">&#182;</a> </div> <p>Now comes the varbinds. There might be many, so we loop for as long as we have data.</p> </div> <div class="content"><div class='highlight'><pre> pkt.pdu.varbinds = []; <span class="keyword">while</span> (buf[<span class="number">0</span>] === asn1ber.types.Sequence) { vb = <span class="keyword">new</span> VarBind();</pre></div></div> </li> <li id="section-40"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-40">&#182;</a> </div> <p>Slice off the sequence header.</p> </div> <div class="content"><div class='highlight'><pre> hdr = asn1ber.typeAndLength(buf); assert.equal(asn1ber.types.Sequence, hdr.type); bvb = buf.slice(hdr.header);</pre></div></div> </li> <li id="section-41"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-41">&#182;</a> </div> <p>Parse and save the ObjectIdentifier.</p> </div> <div class="content"><div class='highlight'><pre> vb.oid = asn1ber.parseOid(bvb);</pre></div></div> </li> <li id="section-42"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-42">&#182;</a> </div> <p>Parse the value. We use the type marker to figure out what kind of value it is and call the appropriate parser routine. For the SNMPv2c error types, we simply set the value to a text representation of the error and leave handling up to the user.</p> </div> <div class="content"><div class='highlight'><pre> bvb = bvb.slice(<span class="number">2</span> + bvb[<span class="number">1</span>]); vb.type = bvb[<span class="number">0</span>]; <span class="keyword">if</span> (vb.type === asn1ber.types.Null) {</pre></div></div> </li> <li id="section-43"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-43">&#182;</a> </div> <p>Null type.</p> </div> <div class="content"><div class='highlight'><pre> vb.value = <span class="literal">null</span>; } <span class="keyword">else</span> <span class="keyword">if</span> (vb.type === asn1ber.types.OctetString) {</pre></div></div> </li> <li id="section-44"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-44">&#182;</a> </div> <p>Octet string type.</p> </div> <div class="content"><div class='highlight'><pre> vb.value = asn1ber.parseOctetString(bvb); } <span class="keyword">else</span> <span class="keyword">if</span> (vb.type === asn1ber.types.Integer || vb.type === asn1ber.types.Counter || vb.type === asn1ber.types.Counter64 || vb.type === asn1ber.types.TimeTicks || vb.type === asn1ber.types.Gauge) {</pre></div></div> </li> <li id="section-45"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-45">&#182;</a> </div> <p>Integer type and it&#39;s derivatives that behave in the same manner.</p> </div> <div class="content"><div class='highlight'><pre> vb.value = asn1ber.parseInteger(bvb); } <span class="keyword">else</span> <span class="keyword">if</span> (vb.type === asn1ber.types.ObjectIdentifier) {</pre></div></div> </li> <li id="section-46"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-46">&#182;</a> </div> <p>Object identifier type.</p> </div> <div class="content"><div class='highlight'><pre> vb.value = asn1ber.parseOid(bvb); } <span class="keyword">else</span> <span class="keyword">if</span> (vb.type === asn1ber.types.IpAddress) {</pre></div></div> </li> <li id="section-47"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-47">&#182;</a> </div> <p>IP Address type.</p> </div> <div class="content"><div class='highlight'><pre> vb.value = asn1ber.parseArray(bvb); } <span class="keyword">else</span> <span class="keyword">if</span> (vb.type === asn1ber.types.Opaque) {</pre></div></div> </li> <li id="section-48"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-48">&#182;</a> </div> <p>Opaque type. The &#39;parsing&#39; here is very light; basically we return a string representation of the raw bytes in hex.</p> </div> <div class="content"><div class='highlight'><pre> vb.value = asn1ber.parseOpaque(bvb); } <span class="keyword">else</span> <span class="keyword">if</span> (vb.type === asn1ber.types.EndOfMibView) {</pre></div></div> </li> <li id="section-49"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-49">&#182;</a> </div> <p>End of MIB view error, returned when attempting to GetNext beyond the end of the current view.</p> </div> <div class="content"><div class='highlight'><pre> vb.value = <span class="string">'endOfMibView'</span>; } <span class="keyword">else</span> <span class="keyword">if</span> (vb.type === asn1ber.types.NoSuchObject) {</pre></div></div> </li> <li id="section-50"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-50">&#182;</a> </div> <p>No such object error, returned when attempting to Get/GetNext an OID that doesn&#39;t exist.</p> </div> <div class="content"><div class='highlight'><pre> vb.value = <span class="string">'noSuchObject'</span>; } <span class="keyword">else</span> <span class="keyword">if</span> (vb.type === asn1ber.types.NoSuchInstance) {</pre></div></div> </li> <li id="section-51"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-51">&#182;</a> </div> <p>No such instance error, returned when attempting to Get/GetNext an instance that doesn&#39;t exist in a given table.</p> </div> <div class="content"><div class='highlight'><pre> vb.value = <span class="string">'noSuchInstance'</span>; } <span class="keyword">else</span> {</pre></div></div> </li> <li id="section-52"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-52">&#182;</a> </div> <p>Something else that we can&#39;t handle, so throw an error. The error will be caught and presented in a useful manner on stderr, with a dump of the message causing it.</p> </div> <div class="content"><div class='highlight'><pre> <span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">'Unrecognized value type '</span> + vb.type); }</pre></div></div> </li> <li id="section-53"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-53">&#182;</a> </div> <p>Take the raw octet string value and preseve it as a buffer and hex string.</p> </div> <div class="content"><div class='highlight'><pre> vb.valueRaw = bvb.slice(<span class="number">2</span>); vb.valueHex = vb.valueRaw.toString(<span class="string">'hex'</span>);</pre></div></div> </li> <li id="section-54"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-54">&#182;</a> </div> <p>Add the request id to the varbind (even though it doesn&#39;t really belong) so that it will be availble to the end user.</p> </div> <div class="content"><div class='highlight'><pre> vb.requestId = pkt.pdu.reqid;</pre></div></div> </li> <li id="section-55"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-55">&#182;</a> </div> <p>Push whatever we parsed to the varbind list.</p> </div> <div class="content"><div class='highlight'><pre> pkt.pdu.varbinds.push(vb);</pre></div></div> </li> <li id="section-56"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-56">&#182;</a> </div> <p>Go fetch the next varbind, if there seems to be any.</p> </div> <div class="content"><div class='highlight'><pre> <span class="keyword">if</span> (buf.length &gt; hdr.header + hdr.len) { buf = buf.slice(hdr.header + hdr.len); } <span class="keyword">else</span> { <span class="keyword">break</span>; } } <span class="keyword">return</span> pkt; } exports.parse = parse;</pre></div></div> </li> <li id="section-57"> <div class="annotation"> <div class="pilwrap for-h2"> <a class="pilcrow" href="#section-57">&#182;</a> </div> <h2>Utility functions</h2> </div> </li> <li id="section-58"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-58">&#182;</a> </div> <p>Compare two OIDs, returning -1, 0 or +1 depending on the relation between oidA and oidB.</p> </div> <div class="content"><div class='highlight'><pre>exports.compareOids = <span class="function"><span class="keyword">function</span> <span class="params">(oidA, oidB)</span> {</span> <span class="keyword">var</span> mlen, i;</pre></div></div> </li> <li id="section-59"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-59">&#182;</a> </div> <p>The undefined OID, if there is any, is deemed lesser.</p> </div> <div class="content"><div class='highlight'><pre> <span class="keyword">if</span> (<span class="keyword">typeof</span> oidA === <span class="string">'undefined'</span> &amp;&amp; <span class="keyword">typeof</span> oidB !== <span class="string">'undefined'</span>) { <span class="keyword">return</span> <span class="number">1</span>; } <span class="keyword">else</span> <span class="keyword">if</span> (<span class="keyword">typeof</span> oidA !== <span class="string">'undefined'</span> &amp;&amp; <span class="keyword">typeof</span> oidB === <span class="string">'undefined'</span>) { <span class="keyword">return</span> -<span class="number">1</span>; }</pre></div></div> </li> <li id="section-60"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-60">&#182;</a> </div> <p>Check each number part of the OIDs individually, and if there is any position where one OID is larger than the other, return accordingly. This will only check up to the minimum length of both OIDs.</p> </div> <div class="content"><div class='highlight'><pre> mlen = Math.min(oidA.length, oidB.length); <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; mlen; i++) { <span class="keyword">if</span> (oidA[i] &gt; oidB[i]) { <span class="keyword">return</span> -<span class="number">1</span>; } <span class="keyword">else</span> <span class="keyword">if</span> (oidB[i] &gt; oidA[i]) { <span class="keyword">return</span> <span class="number">1</span>; } }</pre></div></div> </li> <li id="section-61"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-61">&#182;</a> </div> <p>If there is one OID that is longer than the other after the above comparison, consider the shorter OID to be lesser.</p> </div> <div class="content"><div class='highlight'><pre> <span class="keyword">if</span> (oidA.length &gt; oidB.length) { <span class="keyword">return</span> -<span class="number">1</span>; } <span class="keyword">else</span> <span class="keyword">if</span> (oidB.length &gt; oidA.length) { <span class="keyword">return</span> <span class="number">1</span>; } <span class="keyword">else</span> {</pre></div></div> </li> <li id="section-62"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-62">&#182;</a> </div> <p>The OIDs are obviously equal.</p> </div> <div class="content"><div class='highlight'><pre> <span class="keyword">return</span> <span class="number">0</span>; } };</pre></div></div> </li> <li id="section-63"> <div class="annotation"> <div class="pilwrap for-h2"> <a class="pilcrow" href="#section-63">&#182;</a> </div> <h2>Communication functions</h2> </div> </li> <li id="section-64"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-64">&#182;</a> </div> <p>This is called for when we receive a message.</p> </div> <div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">msgReceived</span><span class="params">(msg, rinfo)</span> {</span> <span class="keyword">var</span> self = <span class="keyword">this</span>, now = Date.now(), pkt, entry; <span class="keyword">if</span> (msg.length === <span class="number">0</span>) {</pre></div></div> </li> <li id="section-65"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-65">&#182;</a> </div> <p>Not sure why we sometimes receive an empty message. As far as I&#39;m concerned it shouldn&#39;t happen, but we&#39;ll ignore it and if it&#39;s necessary a retransmission of the request will be made later.</p> </div> <div class="content"><div class='highlight'><pre> <span class="keyword">return</span>; }</pre></div></div> </li> <li id="section-66"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-66">&#182;</a> </div> <p>Parse the packet, or call the informative parse error display if we fail.</p> </div> <div class="content"><div class='highlight'><pre> <span class="keyword">try</span> { pkt = parse(msg); } <span class="keyword">catch</span> (error) { <span class="keyword">return</span> self.parseError(error, msg); }</pre></div></div> </li> <li id="section-67"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-67">&#182;</a> </div> <p>If this message&#39;s request id matches one we&#39;ve sent, cancel any outstanding timeout and call the registered callback.</p> </div> <div class="content"><div class='highlight'><pre> entry = self.reqs[pkt.pdu.reqid]; <span class="keyword">if</span> (entry) { clearRequest(self.reqs, pkt.pdu.reqid); <span class="keyword">if</span> (<span class="keyword">typeof</span> entry.callback === <span class="string">'function'</span>) { pkt.pdu.varbinds.forEach(<span class="function"><span class="keyword">function</span> <span class="params">(vb)</span> {</span> vb.receiveStamp = now; vb.sendStamp = entry.sendStamp; }); entry.callback(<span class="literal">null</span>, pkt.pdu.varbinds); } } <span class="keyword">else</span> {</pre></div></div> </li> <li id="section-68"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-68">&#182;</a> </div> <p>This happens if we receive the response to a message we&#39;ve already timed out and removed the request entry for. Maybe we shouldn&#39;t even log the warning.</p> <p>Calculate the approximate send time and how old the packet is.</p> </div> <div class="content"><div class='highlight'><pre> <span class="keyword">var</span> age = (Date.now() &amp; <span class="number">0x1fffff</span>) - (pkt.pdu.reqid &gt;&gt;&gt; <span class="number">10</span>); <span class="keyword">if</span> (age &lt; <span class="number">0</span>) { age += <span class="number">0x200000</span>; } console.warn(<span class="string">'Response with unknown request ID from '</span> + rinfo.address + <span class="string">'. Consider increasing timeouts ('</span> + age + <span class="string">' ms old?).'</span>); } }</pre></div></div> </li> <li id="section-69"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-69">&#182;</a> </div> <p>Default options for new sessions and operations.</p> </div> <div class="content"><div class='highlight'><pre>exports.defaultOptions = { host: <span class="string">'localhost'</span>, port: <span class="number">161</span>, community: <span class="string">'public'</span>, family: <span class="string">'udp4'</span>, timeouts: [ <span class="number">5000</span>, <span class="number">5000</span>, <span class="number">5000</span>, <span class="number">5000</span> ] };</pre></div></div> </li> <li id="section-70"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-70">&#182;</a> </div> <p>This creates a new SNMP session.</p> </div> <div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">Session</span><span class="params">(options)</span> {</span> <span class="keyword">var</span> self = <span class="keyword">this</span>; self.options = options || {}; defaults(self.options, exports.defaultOptions); self.reqs = {}; self.socket = dgram.createSocket(self.options.family); self.socket.on(<span class="string">'message'</span>, msgReceived.bind(self)); self.socket.on(<span class="string">'close'</span>, <span class="function"><span class="keyword">function</span> <span class="params">()</span> {</span></pre></div></div> </li> <li id="section-71"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-71">&#182;</a> </div> <p>Remove the socket so we don&#39;t try to send a message on it when it&#39;s closed.</p> </div> <div class="content"><div class='highlight'><pre> self.socket = <span class="literal">undefined</span>; }); self.socket.on(<span class="string">'error'</span>, <span class="function"><span class="keyword">function</span> <span class="params">()</span> {</span></pre></div></div> </li> <li id="section-72"> <div class="annotation"> <div class="pilwrap ">