Source for file rfc1155.php

Documentation is available at rfc1155.php

  1. <?php
  2. /**
  3. * phpsnmp - a PHP SNMP library
  4. *
  5. * Copyright (C) 2004 David Eder <david@eder,us>
  6. *
  7. * Based on snmp - a Python SNMP library
  8. * Copyright (C) 2003 Unicity Pty Ltd <libsnmp@unicity.com.au>
  9. *
  10. * This library is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU Lesser General Public
  12. * License as published by the Free Software Foundation; either
  13. * version 2.1 of the License, or (at your option) any later version.
  14. *
  15. * This library is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18. * Lesser General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Lesser General Public
  21. * License along with this library; if not, write to the Free Software
  22. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  23. *
  24. * @author David Eder <david@eder.us>
  25. * @copyright 2004 David Eder
  26. * @package phpSNMP
  27. * @subpackage rfc1155
  28. * @version .7
  29. */
  30.  
  31. /**
  32. */
  33.  
  34. require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'oid_format.php');
  35.  
  36. /**
  37. * Dump a string in Hex and stripped ascii
  38. *
  39. * @param string $string
  40. * @return string
  41. */
  42. function hexdump($string)
  43. {
  44. $ret = '';
  45. for($i = 0; $i < strlen($string); $i++)
  46. $ret .= str_pad(dechex(ord($string{$i})), 2, '0', STR_PAD_LEFT) . ' ';
  47. $ret .= '[';
  48. for($i = 0; $i < strlen($string); $i++)
  49. {
  50. $o = ord($string{$i});
  51. if($o < 32 || $o > 127) $ret .= '.';
  52. else $ret .= chr($o);
  53. }
  54. return $ret . "]\n";
  55. }
  56.  
  57. /**
  58. * Convert a hex string to raw data
  59. *
  60. * @param string $hex
  61. * @return string
  62. */
  63. function hexbin($hex) // convert a hex string to raw data
  64.  
  65. {
  66. $ret = '';
  67. foreach(explode(' ', $hex) as $c)
  68. $ret .= chr(hexdec($c));
  69. return $ret;
  70. }
  71.  
  72. /**
  73. * Divide with Remainder
  74. *
  75. * This function uses float operation to do what was done with bit operations on integers previously.
  76. * This is the result of PHP automatically converting large numbers to floats. PHP has no unsigned longs.
  77. * One advantage is that it can handle 64 bit integers, although some precision is lost.
  78. *
  79. * @param integer $numerator
  80. * @param integer $denominator
  81. * @return array(quotient, remainder)
  82. */
  83. function divide_with_remainder($numerator, $denominator)
  84. {
  85. $q = intval($numerator / $denominator);
  86. $r = intval(($numerator / $denominator - $q) * $denominator);
  87. return array($q, $r);
  88. }
  89.  
  90. define('ASN_TAG_CLASS_UNIVERSAL', 0x00);
  91. define('ASN_TAG_CLASS_APPLICATION', 0x40);
  92. define('ASN_TAG_CLASS_CONTEXT', 0x80);
  93. define('ASN_TAG_CLASS_PRIVATE', 0xC0);
  94.  
  95. define('ASN_TAG_FORMAT_PRIMITIVE', 0x00);
  96. define('ASN_TAG_FORMAT_CONSTRUCTED', 0x20);
  97.  
  98. define('ASN_TAG_BOOLEAN', 0x01);
  99. define('ASN_TAG_INTEGER', 0x02);
  100. define('ASN_TAG_OCTETSTRING', 0x04);
  101. define('ASN_TAG_NULL', 0x05);
  102. define('ASN_TAG_OBJECTID', 0x06);
  103. define('ASN_TAG_SEQUENCE', 0x10);
  104.  
  105. define('ASN_TAG_IPADDRESS', 0x00);
  106. define('ASN_TAG_COUNTER', 0x01);
  107. define('ASN_TAG_GUAGE', 0x02);
  108. define('ASN_TAG_TIMETICKS', 0x03);
  109. define('ASN_TAG_OPAQUE', 0x04);
  110.  
  111. $ASN_TAG_DICT[0x01] = 'rfc1155_Boolean';
  112. $ASN_TAG_DICT[0x02] = 'rfc1155_Integer';
  113. $ASN_TAG_DICT[0x04] = 'rfc1155_OctetString';
  114. $ASN_TAG_DICT[0x05] = 'rfc1155_Null';
  115. $ASN_TAG_DICT[0x06] = 'rfc1155_ObjectID';
  116. $ASN_TAG_DICT[0x30] = 'rfc1155_Sequence';
  117. $ASN_TAG_DICT[0x40] = 'rfc1155_IPAddress';
  118. $ASN_TAG_DICT[0x41] = 'rfc1155_Counter';
  119. $ASN_TAG_DICT[0x42] = 'rfc1155_Guage';
  120. $ASN_TAG_DICT[0x43] = 'rfc1155_TimeTicks';
  121. $ASN_TAG_DICT[0x44] = 'rfc1155_Opaque';
  122.  
  123. /**
  124. * Asn1Objects
  125. *
  126. * Base class for all Asn1Objects. This is only intended to support a specific subset of ASN1 stuff as
  127. * defined by the RFCs to keep things as simple as possible.
  128. *
  129. * @package phpSNMP
  130. * @subpackage rfc1155
  131. */
  132. class rfc1155_Asn1Object
  133. {
  134. var $asnTagClass = ASN_TAG_CLASS_UNIVERSAL;
  135. var $asnTagFormat= ASN_TAG_FORMAT_PRIMITIVE;
  136. var $asnTagNumber = NULL;
  137.  
  138. var $value = NULL;
  139.  
  140. /**
  141. * Constructor
  142. */
  143. function rfc1155_Asn1Object(){}
  144.  
  145. /**
  146. * Encode Asn1Object
  147. *
  148. * encode() this Asn1Object using BER
  149. *
  150. * @return string encoded object
  151. */
  152. function encode()
  153. {
  154. $contents = $this->encodeContents();
  155. return $this->encodeIdentifier() . $this->encodeLength(strlen($contents)) . $contents;
  156. }
  157.  
  158. /**
  159. * Decode Tag
  160. *
  161. * Decode a BER tag field, returning the tag and the remainder of the stream
  162. *
  163. * @param string $stream
  164. * @return array (tag, remaining_stream)
  165. */
  166. function decodeTag($stream)
  167. {
  168. $tag = ord($stream{0});
  169. $n = 1;
  170. if(($tag & 0x1F) == 0x1F)
  171. {
  172. /* A large tag is encoded using concatenated 7-bit values over the following octets, ignoring the initial 5 bits
  173. in the first octet. The 8th bit represents a follow-on. */
  174. $tag = 0;
  175. do
  176. {
  177. $byte = ord($stream{$n});
  178. $tag = $tag * 128 + ($byte & 0x7F);
  179. $n += 1;
  180. } while($byte & 0x80);
  181. }
  182. return array($tag, substr($stream, $n));
  183. }
  184.  
  185. /**
  186. * Decode Length
  187. *
  188. * Decode a BER length field, returing the length and the remainder of the stream
  189. *
  190. * @param string $stream
  191. * @return array (length, remaining_stream)
  192. */
  193. function decodeLength($stream)
  194. {
  195. $length = ord($stream{0});
  196. $i = 1;
  197. if($length & 0x80)
  198. {
  199. // Multi-Octet length encoding. The first octet represents the run-length (the number of octets used to build the length)
  200. $run = $length & 0x7F;
  201. $length = 0;
  202. for($i = 1; $i <= $run; $i++)
  203. $length = $length * 256 + ord($stream{$i});
  204. }
  205. return array($length, substr($stream, $i));
  206. }
  207.  
  208. /**
  209. * Decode Stream
  210. *
  211. * decode() an octet stream into a sequence of Asn1Objects
  212. *
  213. * @param string $stream
  214. * @return array of rfc1155_Asn1Object
  215. */
  216. function decode($stream)
  217. {
  218. /* This method should be overridden by subclasses to define how to decode one of themselves from a fixed length stream. This
  219. general case method looks at the identifier at the beginning of a stream of octets and uses the appropriate decode() method
  220. of that known object. Attempts to decode() an unknown object type result in an error. */
  221. if(!is_string($stream))
  222. {
  223. trigger_error('stream should be of a string, not a ' . gettype($stream), E_USER_WARNING);
  224. return array();
  225. }
  226.  
  227. $objects = array();
  228. while(strlen($stream) > 0)
  229. {
  230. list($tag, $stream) = $this->decodeTag($stream);
  231. list($length, $stream) = $this->decodeLength($stream);
  232.  
  233. $objectData = substr($stream, 0, $length);
  234. $stream = substr($stream, $length);
  235.  
  236. global $ASN_TAG_DICT;
  237. if(isset($ASN_TAG_DICT[$tag]))
  238. {
  239. $decoder = $ASN_TAG_DICT[$tag];
  240. $o = new $decoder();
  241. $objects[] = $o->decodeContents($objectData);
  242. }
  243. else
  244. trigger_error("Unknown ASN.1 Type 0x" . dechex($tag), E_USER_WARNING);
  245. }
  246. return $objects;
  247. }
  248.  
  249. /**
  250. * Encode Contents
  251. *
  252. * encodeContents must be overridden by subclasses to encode the contents of a particular type
  253. *
  254. * @return string
  255. */
  256. function encodeContents()
  257. {
  258. trigger_error('encodeContents not implemented', E_USER_ERROR);
  259. }
  260.  
  261. /**
  262. * Encode Identifier
  263. *
  264. * encodeIdentifier() returns encoded identifier octets for this object. Section 6.3 of ITU-T-X.209
  265. *
  266. * @return string
  267. */
  268. function encodeIdentifier()
  269. {
  270. if($this->asnTagNumber < 0x1F)
  271. {
  272. return chr($this->asnTagClass | $this->asnTagFormat | $this->asnTagNumber);
  273. }
  274. else
  275. {
  276. /* Encode each number of the asnTagNumber from 31 upwards as a sequence of 7-bit numbers with bit 8 set to 1 for
  277. all but the last octet. Bit 8 set to 0 signifies the last octet of the Identifier octets */
  278.  
  279. // encode the first octet
  280. $resultlist = array();
  281. $resultlist[] = chr($this->asnTagClass | $this->asnTagFormat | 0x1F);
  282. // encode each subsequent octet
  283. $integer = $this->asnTagNumber;
  284. while($integer != 0)
  285. {
  286. list($integer, $remainder) = divide_with_remainder($integer, 256);
  287. $resultlist[] = chr($remainder);
  288. }
  289.  
  290. return join('', $resultlist);
  291. }
  292. }
  293.  
  294. /**
  295. * Encode Length
  296. *
  297. * encodeLength() takes the length of the contents and produces the encoding for that length. Section 6.3 of ITU-T-X.209
  298. *
  299. * define('SNMP_SHORT_INT_LENGTH', 1) to encode as short; needed by some Cisco software
  300. *
  301. * @param integer $length
  302. * @return string
  303. */
  304. function encodeLength($length)
  305. {
  306. if(defined('SNMP_SHORT_INT_LENGTH')) // hack to be compatible with Cisco software
  307. {
  308. list($a, $b) = divide_with_remainder($length, 256);
  309. return chr(0x82) . chr($a) . chr($b);
  310. }
  311. elseif($length < 127)
  312. return chr($length & 0xff);
  313. else
  314. {
  315. /* Long form - Octet one is the number of octets used to encode the length It has bit 8 set to 1 and the remaining 7 bits are
  316. used to encode the number of octets used to encode the length Each subsequent octet uses all 8 bits to encode the length */
  317. $resultlist = array();
  318. $numOctets = 0;
  319. while($length > 0)
  320. {
  321. list($length, $remainder) = divide_with_remainder($length, 256);
  322. array_unshift($resultlist, chr($remainder));
  323. $numOctets++;
  324. }
  325.  
  326. // Add a 1 to the front of the octet
  327. $numOctets = $numOctets | 0x80;
  328. array_unshift($resultlist, chr($numOctets & 0xff));
  329.  
  330. return join('', $resultlist);
  331. }
  332. }
  333.  
  334. /**
  335. * Encode End of Contents
  336. *
  337. * @return string
  338. */
  339. function encodeEndOfContents()
  340. {
  341. return "\000\000";
  342. }
  343. }
  344.  
  345. /**
  346. * rfc1155 Boolean
  347. *
  348. * An ASN.1 Boolean type
  349. *
  350. * @package phpSNMP
  351. * @subpackage rfc1155
  352. */
  353. class rfc1155_Boolean extends rfc1155_Asn1Object
  354. {
  355. /**
  356. * Constructor
  357. *
  358. * @param boolean $value
  359. */
  360. function rfc1155_Boolean($value=true)
  361. {
  362. $this->asnTagClass = ASN_TAG_CLASS_UNIVERSAL;
  363. $this->asnTagNumber = ASN_TAG_BOOLEAN;
  364. $this->value = ($value) ? true : false;
  365. }
  366.  
  367. /**
  368. * ToString
  369. *
  370. * @return string value of this object
  371. */
  372. function toString()
  373. {
  374. return ($this->value) ? 'true' : 'false';
  375. }
  376.  
  377. /**
  378. * Encode Contents
  379. *
  380. * encode into an octet stream
  381. *
  382. * @return string
  383. */
  384. function encodeContents()
  385. {
  386. trigger_error('encodeContents not written yet', E_USER_ERROR);
  387. }
  388.  
  389. /**
  390. * Decode Contents
  391. *
  392. * Decode octet stream
  393. *
  394. * @param string $stream
  395. * @return rfc1155_Boolean
  396. */
  397. function decodeContents(/*$stream*/)
  398. {
  399. trigger_error('decodeContents not written yet', E_USER_ERROR);
  400. return $this;
  401. }
  402. }
  403.  
  404. /**
  405. * rfc1155 Integer
  406. *
  407. * An ASN.1 Integer type
  408. *
  409. * @package phpSNMP
  410. * @subpackage rfc1155
  411. */
  412. class rfc1155_Integer extends rfc1155_Asn1Object
  413. {
  414. /**
  415. * Constructor
  416. *
  417. * @param integer $value
  418. */
  419. function rfc1155_Integer($value=0)
  420. {
  421. $this->asnTagClass = ASN_TAG_CLASS_UNIVERSAL;
  422. $this->asnTagNumber = ASN_TAG_INTEGER;
  423. $this->check_range($value);
  424. $this->value = $value;
  425. }
  426.  
  427. /**
  428. * Check range for integer value
  429. *
  430. * @param integer $value
  431. * @param integer $min
  432. * @param integer $max
  433. */
  434. function check_range($value, $min=NULL, $max=NULL)
  435. {
  436. static $MINVAL = -2147483648;
  437. static $MAXVAL = 2147483647;
  438. if(!is_null($min)) $MINVAL = $min;
  439. if(!is_null($max)) $MAXVAL = $max;
  440.  
  441. $value = intval($value);
  442. if(is_null($min) && is_null($max) && ($value < $MINVAL || $value > $MAXVAL))
  443. {
  444. trigger_error("Integer value of $value (".gettype($value).") is out of bounds ($MINVAL to $MAXVAL)", E_USER_WARNING);
  445. }
  446. }
  447.  
  448. /**
  449. * ToString
  450. *
  451. * @return string value of this object
  452. */
  453. function toString()
  454. {
  455. return $this->value;
  456. }
  457.  
  458. /**
  459. * Encode Contents
  460. *
  461. * encode into an octet stream
  462. *
  463. * @return string
  464. */
  465. function encodeContents()
  466. {
  467. // We handle two special cases otherwise we handle positive and negative numbers independently
  468.  
  469. $integer = $this->value;
  470.  
  471. if($integer == 0)
  472. return "\000";
  473. elseif($integer == -1)
  474. return "\377";
  475. elseif($integer > 0)
  476. {
  477. $result = array();
  478. while($integer != 0)
  479. {
  480. list($integer, $remainder) = divide_with_remainder($integer, 256);
  481. array_unshift($result, $remainder);
  482. }
  483. if($result[0] & 0x80)
  484. array_unshift($result, 0);
  485. return join('', array_map('chr', $result));
  486. }
  487. else
  488. {
  489. $result = array();
  490. while($integer != 0)
  491. {
  492. list($integer, $remainder) = divide_with_remainder($integer, 256);
  493. array_unshift($result, $remainder);
  494. }
  495. if($result[0] & 0x80 != 0x80)
  496. array_unshift($result, 0);
  497. return join('', array_map('chr', $result));
  498. }
  499. }
  500.  
  501. /**
  502. * Decode Contents
  503. *
  504. * Decode octet stream
  505. *
  506. * @param string $stream
  507. * @return rfc1155_Integer
  508. */
  509. function decodeContents($stream)
  510. {
  511. $this->value = 0;
  512. $byte = ord($stream{0});
  513. if(($byte & 0x80) == 0x80)
  514. {
  515. $negbit = 0x80;
  516. $this->value = $byte & 0x7f;
  517. for($i = 1; $i < strlen($stream); $i++)
  518. {
  519. $negbit *= 256;
  520. $this->value = $this->value * 256 + ord($stream{$i});
  521. }
  522. $this->value = $this->value - $negbit;
  523. }
  524. else
  525. {
  526. $this->value = $byte;
  527. for($i = 1; $i < strlen($stream); $i++)
  528. $this->value = $this->value * 256 + ord($stream{$i});
  529. }
  530. return $this;
  531. }
  532. }
  533.  
  534. /**
  535. * rfc1155 Octet String
  536. *
  537. * An ASN.1 Octet String type
  538. *
  539. * @package phpSNMP
  540. * @subpackage rfc1155
  541. */
  542. class rfc1155_OctetString extends rfc1155_Asn1Object
  543. {
  544. /**
  545. * Constructor
  546. *
  547. * @param strin $value
  548. */
  549. function rfc1155_OctetString($value='')
  550. {
  551. $this->asnTagClass = ASN_TAG_CLASS_UNIVERSAL;
  552. $this->asnTagNumber = ASN_TAG_OCTETSTRING;
  553. $this->value = $value;
  554. }
  555.  
  556. /**
  557. * Is Printable?
  558. *
  559. * Decides if its value is printable
  560. *
  561. * @return boolean
  562. */
  563. function is_printable()
  564. {
  565. for($i = strlen($this->value) - 1; $i >= 0; $i--)
  566. {
  567. if($this->value{$i} != "\n" && $this->value{$i} != "\t" && $this->value{$i} != "\r")
  568. {
  569. if(ord($this->value{$i}) < 16 || ord($this->value{$i}) > 127)
  570. {
  571. return false;
  572. }
  573. }
  574. }
  575. return true;
  576. }
  577.  
  578. /**
  579. * to Hex
  580. *
  581. * Converts its value to a hex string
  582. *
  583. * @return string
  584. */
  585. function toHex()
  586. {
  587. $ret = '';
  588. for($i = 0; $i < strlen($this->value); $i++)
  589. $ret .= str_pad(dechex(ord($this->value{$i})), 2, '0', STR_PAD_LEFT) . ' ';
  590. return trim($ret);
  591. }
  592.  
  593. /**
  594. * toString
  595. *
  596. * @return string
  597. */
  598. function toString()
  599. {
  600. if($this->is_printable())
  601. return $this->value;
  602. else
  603. return $this->toHex();
  604. }
  605.  
  606. /**
  607. * Encode Contents
  608. *
  609. * encode into an octet stream
  610. *
  611. * @return string
  612. */
  613. function encodeContents()
  614. {
  615. // An OctetString is already encoded. Whee!
  616. return $this->value;
  617. }
  618.  
  619. /**
  620. * Decode Contents
  621. *
  622. * Decode octet stream
  623. *
  624. * @param string $stream
  625. * @return rfc1155_OctetString
  626. */
  627. function decodeContents($stream)
  628. {
  629. // An OctetString is already decoded. Whee!
  630. $this->value = $stream;
  631. return $this;
  632. }
  633. }
  634.  
  635. /**
  636. * rfc1155 Object Identifier (oid)
  637. *
  638. * An ASN.1 Object Identifier type
  639. *
  640. * @package phpSNMP
  641. * @subpackage rfc1155
  642. */
  643. class rfc1155_ObjectID extends rfc1155_Asn1Object
  644. {
  645. /**
  646. * Constructor
  647. *
  648. * @param string $value
  649. */
  650. function rfc1155_ObjectID($value=array())
  651. {
  652. // Create an ObjectID - value is a list of subids as a string or list
  653. $this->asnTagClass = ASN_TAG_CLASS_UNIVERSAL;
  654. $this->asnTagFormat = ASN_TAG_FORMAT_PRIMITIVE;
  655. $this->asnTagNumber = ASN_TAG_OBJECTID;
  656.  
  657. if(is_string($value))
  658. $this->value = explode('.', $value);
  659. elseif(is_array($value))
  660. $this->value = $value;
  661. elseif(is_null($value))
  662. $this->value = array();
  663. else
  664. trigger_error('Unknown type passed as OID', E_USER_WARNING);
  665.  
  666. $this->value = oid_format($this->value, OID_NUMERIC);
  667.  
  668. foreach($this->value as $subid)
  669. if($subid < 0 || $subid > 0x7FFFFFFF)
  670. trigger_error("SubID $subid out of range", E_USER_WARNING);
  671. }
  672.  
  673. /**
  674. * toString
  675. *
  676. * @return string
  677. */
  678. function toString()
  679. {
  680. return '.' . join('.', $this->value);
  681. }
  682.  
  683. /**
  684. * Encode Contents
  685. *
  686. * encode into an octet stream
  687. *
  688. * @return string
  689. */
  690. function encodeContents()
  691. {
  692. $result = array();
  693. $idlist = $this->value;
  694.  
  695. // Do the bit with the first 2 subids; section 22.4 of X.209
  696. $idlist = array_reverse($idlist);
  697. $subid1 = (array_pop($idlist) * 40) + array_pop($idlist);
  698. $idlist = array_reverse($idlist);
  699. array_unshift($idlist, $subid1);
  700. foreach($idlist as $subid)
  701. {
  702. if(!is_numeric($subid))
  703. {
  704. trigger_error('Unable to encode non-numeric OID', E_USER_WARNING);
  705. return '';
  706. }
  707. if($subid < 128)
  708. $result[] = chr($subid & 0x7f);
  709. else
  710. {
  711. list($subid, $remainder) = divide_with_remainder($subid, 128);
  712. $r = array(chr($remainder));
  713. while($subid > 0)
  714. {
  715. list($subid, $remainder) = divide_with_remainder($subid, 128);
  716. $r[] = chr(0x80 | $remainder);
  717. }
  718. for($i = count($r) - 1; $i >=0; $i--) $result[] = $r[$i];
  719. }
  720. }
  721. return join('', $result);
  722. }
  723.  
  724. /**
  725. * Decode Contents
  726. *
  727. * Decode octet stream
  728. *
  729. * @param string $stream
  730. * @return rfc1155_ObjectID
  731. */
  732. function decodeContents($stream)
  733. {
  734. $this->value = array();
  735.  
  736. if(strlen($stream) == 0)
  737. {
  738. trigger_error('Stream of zero length in ' . get_class($this), E_USER_WARNING);
  739. return $this;
  740. }
  741. // Do the funky decode of the first octet
  742. if(ord($stream{0}) < 128)
  743. {
  744. $this->value[] = intval(ord($stream{0}) / 40);
  745. $this->value[] = ord($stream{0}) % 40;
  746. }
  747. else
  748. {
  749. /* I haven't bothered putting in the convoluted logic here because the highest likely assignment for the first
  750. octet is 83 according to Annex B of X.208 Those X.209 does give as an example 2.100.3, which is kinda stupid.
  751. Actually, a lot of the space-saving encodings, like this first octet, are a real PITA later on. So yeah,
  752. stuff it, we'll just raise an exception. */
  753.  
  754. trigger_error('NotImplementedError: First octet is > 128! Unsupported oid detected', E_USER_ERROR);
  755. return $this;
  756. }
  757.  
  758. // Decode the rest of the octets
  759. $n = 1;
  760. while($n < strlen($stream))
  761. {
  762. $subid = ord($stream{$n});
  763. $n += 1;
  764.  
  765. // If bit 8 is not set, this is the last octet of this subid
  766. // If bit 8 is set, the subid spans this octet and the ones afterwards, up until bit 8 isn't set.
  767. if(($subid & 0x80) == 0x80)
  768. {
  769. $val = $subid & 0x7f;
  770. while(($subid & 0x80) == 0x80)
  771. {
  772. $subid = ord($stream{$n});
  773. $n += 1;
  774. $val = $val * 128 + ($subid & 0x7f);
  775. }
  776. $this->value[] = $val;
  777. }
  778. else
  779. {
  780. $this->value[] = $subid;
  781. }
  782. }
  783. return $this;
  784. }
  785. }
  786.  
  787. /**
  788. * rfc1155 Null
  789. *
  790. * An ASN.1 Null type
  791. *
  792. * @package phpSNMP
  793. * @subpackage rfc1155
  794. */
  795. class rfc1155_Null extends rfc1155_Asn1Object // An ASN.1 Object Identifier type
  796.  
  797. {
  798. /**
  799. * Constructor
  800. */
  801. function rfc1155_Null()
  802. {
  803. $this->asnTagClass = ASN_TAG_CLASS_UNIVERSAL;
  804. $this->asnTagFormat = ASN_TAG_FORMAT_PRIMITIVE;
  805. $this->asnTagNumber = ASN_TAG_NULL;
  806. }
  807.  
  808. /**
  809. * toString
  810. *
  811. * @return string
  812. */
  813. function toString()
  814. {
  815. return '';
  816. }
  817.  
  818. /**
  819. * Encode Contents
  820. *
  821. * encode into an octet stream
  822. *
  823. * @return string
  824. */
  825. function encodeContents()
  826. {
  827. return '';
  828. }
  829.  
  830. /**
  831. * Decode Contents
  832. *
  833. * Decode octet stream
  834. *
  835. * @param string $stream
  836. * @return rfc1155_Null
  837. */
  838. function decodeContents($stream)
  839. {
  840. if(strlen($stream) != 0)
  841. trigger_error('Input stream too long for ' . get_class($this), E_USER_WARNING);
  842. return $this;
  843. }
  844. }
  845.  
  846. /**
  847. * rfc1155 Sequence
  848. *
  849. * An ASN.1 Sequence type
  850. *
  851. * A Sequence is basically a list of name, value pairs with the name being an object Type and the
  852. * value being an instance of an Asn1Object of that Type.
  853. *
  854. * @package phpSNMP
  855. * @subpackage rfc1155
  856. */
  857. class rfc1155_Sequence extends rfc1155_Asn1Object
  858. {
  859. /**
  860. * Constructor
  861. *
  862. * @param array $value list of rfc1155_Asn1Object
  863. */
  864. function rfc1155_Sequence($value=array())
  865. {
  866. $this->asnTagClass = ASN_TAG_CLASS_UNIVERSAL;
  867. $this->asnTagFormat = ASN_TAG_FORMAT_CONSTRUCTED;
  868. $this->asnTagNumber = ASN_TAG_SEQUENCE;
  869. $this->value = $value;
  870. }
  871.  
  872. /**
  873. * Encode Contents
  874. *
  875. * encode into an octet stream
  876. *
  877. * @return string
  878. */
  879. function encodeContents()
  880. {
  881. // To encode a Sequence, we simply encode() each sub-object in turn.
  882. $resultlist = array();
  883. foreach($this->value as $elem)
  884. $resultlist[] = $elem->encode();
  885. return join('', $resultlist);
  886. }
  887.  
  888. /**
  889. * Decode Contents
  890. *
  891. * Decode octet stream
  892. *
  893. * @param string $stream
  894. * @return rfc1155_Sequence
  895. */
  896. function decodeContents($stream)
  897. {
  898. $this->value = $this->decode($stream);
  899. return $this;
  900. }
  901.  
  902. /**
  903. * toString
  904. *
  905. * @return string
  906. */
  907. function toString()
  908. {
  909. $vals = array();
  910. foreach($this->value as $v) $vals[] = get_class($v) . '(' . $v->toString() . ')';
  911. $vals = join(',', $vals);
  912. return get_class($this) . "($vals)";
  913. }
  914. }
  915.  
  916. /**
  917. * rfc1155 SequenceOf
  918. *
  919. * An ASN.1 SequenceOf type
  920. *
  921. * A Sequence is basically a list of name, value pairs with the name being an object Type and the
  922. * value being an instance of an Asn1Object of that Type.
  923. *
  924. * @package phpSNMP
  925. * @subpackage rfc1155
  926. */
  927. class rfc1155_SequenceOf extends rfc1155_Sequence
  928. {
  929. // A SequenceOf is a special kind of sequence that places a constraint on the kind of objects it can contain. It is variable in length.
  930.  
  931.  
  932. var $componentType;
  933.  
  934. /**
  935. * Constructor
  936. *
  937. * @param string $componentType name of object type used
  938. * @param array $value list of rfc1155_Asn1Object of type $componentType
  939. */
  940. function rfc1155_SequenceOf($componentType='rfc1155_asn1Object', $value=array())
  941. {
  942. parent::rfc1155_Sequence($value);
  943. $this->asnTagClass = ASN_TAG_CLASS_UNIVERSAL;
  944. $this->asnTagFormat = ASN_TAG_FORMAT_CONSTRUCTED;
  945. $this->asnTagNumber = ASN_TAG_SEQUENCE;
  946.  
  947. $this->componentType = $componentType;
  948.  
  949. // Add each item in the list to ourselves, which automatically checks each one to ensure it is of the correct type.
  950. $this->value = array();
  951.  
  952. foreach($value as $item)
  953. $this->append($item);
  954. }
  955.  
  956. /**
  957. * Append
  958. *
  959. * Add an object to this sequence
  960. *
  961. * @param rfc1155_Asn1Object object to add
  962. */
  963. function append($value)
  964. {
  965. if(!is_a($value, $this->componentType))
  966. {
  967. if(is_subclass_of(new $this->componentType(), get_class($value)))
  968. {
  969.  
  970. // broken way of doing this!
  971. $v = $value->value;
  972. $value = new $this->componentType();
  973. $value->value = $v;
  974. }
  975. else
  976. trigger_error(get_class($this) . ' cannot contain components of type: ' . get_class($value), E_USER_WARNING);
  977. }
  978. $this->value[] = $value;
  979. }
  980. }
  981.  
  982. /**
  983. * rfc1155 IPAddress
  984. *
  985. * An ASN.1 IPAddress type
  986. *
  987. * An IpAddress is a special type of OctetString. It represents a 32-bit internet address as an OctetString of length 4, in network byte order.
  988. *
  989. * @package phpSNMP
  990. * @subpackage rfc1155
  991. */
  992. class rfc1155_IPAddress extends rfc1155_OctetString
  993. {
  994. /**
  995. * Constructor
  996. *
  997. * @param mixed $value (can be array, long, hostname or ip address)
  998. */
  999. function rfc1155_IPAddress($value='0.0.0.0')
  1000. {
  1001. parent::rfc1155_OctetString($value);
  1002. $this->asnTagClass = ASN_TAG_CLASS_APPLICATION;
  1003. $this->asnTagFormat = ASN_TAG_FORMAT_PRIMITIVE;
  1004. $this->asnTagNumber = ASN_TAG_IPADDRESS;
  1005.  
  1006. if(is_array($value))
  1007. {
  1008. if(count($value) != 4)
  1009. trigger_error('IPAddress must be of length 4', E_USER_WARNING);
  1010. $value = join('.', $value);
  1011. }
  1012.  
  1013. if(strpos($value, '.') !== false) // string
  1014. {
  1015. $h = ip2long($value);
  1016. if($h == -1 || $h === false)
  1017. $value = ip2long(gethostbyname($value));
  1018. else
  1019. $value = $h;
  1020. }
  1021. $this->value = long2ip($value);
  1022. }
  1023.  
  1024. /**
  1025. * toString
  1026. *
  1027. * @return string
  1028. */
  1029. function toString()
  1030. {
  1031. return $this->value;
  1032. }
  1033.  
  1034. /**
  1035. * Encode Contents
  1036. *
  1037. * encode into an octet stream
  1038. *
  1039. * @return string
  1040. */
  1041. function encodeContents()
  1042. {
  1043. $ret = '';
  1044. $value = explode('.', $this->value);
  1045. for($i = 0; $i < 4; $i++)
  1046. $ret .= chr($value[$i]);
  1047. return $ret;
  1048. }
  1049.  
  1050. /**
  1051. * Decode Contents
  1052. *
  1053. * Decode octet stream
  1054. *
  1055. * @param string $stream
  1056. * @return rfc1155_IPAddress
  1057. */
  1058. function decodeContents($stream)
  1059. {
  1060. $this->value = ord($stream{0}) . '.' . ord($stream{1}) . '.' . ord($stream{2}) . '.' . ord($stream{3});
  1061. return $this;
  1062. }
  1063. }
  1064.  
  1065. /**
  1066. * rfc1155 NetworkAddress
  1067. *
  1068. * An ASN.1 NetworkAddress type
  1069. *
  1070. * A Network Address is a CHOICE with only one possible value: internet
  1071. *
  1072. * @package phpSNMP
  1073. * @subpackage rfc1155
  1074. */
  1075. class rfc1155_NetworkAddress extends rfc1155_IPAddress
  1076. {
  1077. // var $name;
  1078.  
  1079.  
  1080. /**
  1081. * Constructor
  1082. *
  1083. * @param mixed $value (can be array, long, hostname or ip address)
  1084. */
  1085. function rfc1155_NetworkAddress($value)
  1086. {
  1087. parent::rfc1155_IPAddress($value);
  1088. // $this->name = 'internet';
  1089. }
  1090. }
  1091.  
  1092. /**
  1093. * rfc1155 Counter
  1094. *
  1095. * An ASN.1 Counter type
  1096. *
  1097. * A counter starts at zero and keeps going to a maximum integer value of 2^32-1 where it wraps back to zero.
  1098. *
  1099. * @package phpSNMP
  1100. * @subpackage rfc1155
  1101. */
  1102. class rfc1155_Counter extends rfc1155_Integer
  1103. {
  1104. /**
  1105. * Constructor
  1106. *
  1107. * @param integer $value
  1108. */
  1109. function rfc1155_Counter($value=0)
  1110. {
  1111. $this->check_range($value, 0, 4294967295);
  1112. parent::rfc1155_Integer($value);
  1113. $this->asnTagClass = ASN_TAG_CLASS_APPLICATION;
  1114. $this->asnTagFormat = ASN_TAG_FORMAT_PRIMITIVE;
  1115. $this->asnTagNumber = ASN_TAG_COUNTER;
  1116. }
  1117.  
  1118. /**
  1119. * Decode Contents
  1120. *
  1121. * Decode octet stream
  1122. *
  1123. * Some SNMP stacks encode Counters incorrectly resulting in a negative value. There are two remedies:
  1124. * if you define('SNMP_ABS_COUNTER', 1), we take the absolute value of the result.
  1125. * else, we ignore the fact that the first bit is high and decode it as if it was positive.
  1126. *
  1127. * @param string $stream
  1128. * @return rfc1155_Counter
  1129. */
  1130. function decodeContents($stream)
  1131. {
  1132. if(defined('SNMP_ABS_COUNTER')) // hack to be compatible with Cisco software
  1133. {
  1134. /* Some agents encode Counters incorrectly (hello Solaris) as a negative number. I'm assuming most SNMP libraries don't
  1135. notice the problem because the are written in C and cast the result to an unsigned int - problem solved (if
  1136. accidentally). This ugly hack on their behalf flips the value over to the positive world. */
  1137. parent::decodeContents($stream);
  1138. $this->value = abs($this->value);
  1139. }
  1140. else
  1141. {
  1142. $this->value = 0;
  1143. for($i = 0; $i < strlen($stream); $i++)
  1144. $this->value = $this->value * 256 + ord($stream{$i});
  1145. }
  1146. return $this;
  1147. }
  1148. }
  1149.  
  1150. /**
  1151. * rfc1155 Guage
  1152. *
  1153. * An ASN.1 Guage type
  1154. *
  1155. * A Guage is a non negative integer. It may increase or decrease. It latches at a maximum value.
  1156. *
  1157. * @package phpSNMP
  1158. * @subpackage rfc1155
  1159. */
  1160. class rfc1155_Guage extends rfc1155_Integer
  1161. {
  1162. /**
  1163. * Constructor
  1164. *
  1165. * @param integer $value
  1166. */
  1167. function rfc1155_Guage($value=0)
  1168. {
  1169. $this->check_range($value, 0, 4294967295);
  1170. parent::rfc1155_Integer($value);
  1171. $this->asnTagClass = ASN_TAG_CLASS_APPLICATION;
  1172. $this->asnTagFormat = ASN_TAG_FORMAT_PRIMITIVE;
  1173. $this->asnTagNumber = ASN_TAG_GUAGE;
  1174. }
  1175. }
  1176.  
  1177. /**
  1178. * rfc1155 TimeTicks
  1179. *
  1180. * An ASN.1 TimeTicks type
  1181. *
  1182. * TimeTicks is the number of hundredths of a second since an epoch, specified at object creation time
  1183. *
  1184. * @package phpSNMP
  1185. * @subpackage rfc1155
  1186. */
  1187. class rfc1155_TimeTicks extends rfc1155_Integer
  1188. {
  1189. // var $epoch;
  1190.  
  1191.  
  1192. /**
  1193. * Constructor
  1194. *
  1195. * @param integer $value
  1196. */
  1197. function rfc1155_TimeTicks($value=0/*, $epoch=NULL*/)
  1198. {
  1199. $this->check_range($value, 0, 4294967295);
  1200. parent::rfc1155_Integer($value);
  1201. $this->asnTagClass = ASN_TAG_CLASS_APPLICATION;
  1202. $this->asnTagFormat = ASN_TAG_FORMAT_PRIMITIVE;
  1203. $this->asnTagNumber = ASN_TAG_TIMETICKS;
  1204. // $this->epoch = $epoch;
  1205. }
  1206. }
  1207.  
  1208. /**
  1209. * rfc1155 Opaque
  1210. *
  1211. * An ASN.1 Opaque type
  1212. *
  1213. * Opaque is a fun type that allows you to pass arbitrary ASN.1 encoded stuff in an object. The value is some ASN.1 syntax
  1214. * encoded using BER which this object encodes as an OctetString. We don't do any decoding of this object because we don't
  1215. * have to, and that makes this all much quicker.
  1216. *
  1217. * @package phpSNMP
  1218. * @subpackage rfc1155
  1219. */
  1220. class rfc1155_Opaque extends rfc1155_OctetString
  1221. {
  1222. /**
  1223. * Constructor
  1224. *
  1225. * @param string $value
  1226. */
  1227. function rfc1155_Opaque($value)
  1228. {
  1229. parent::rfc1155_OctetString($value);
  1230. }
  1231. }
  1232. ?>

Documentation generated on Mon, 14 Nov 2005 17:55:05 -0700 by phpDocumentor 1.3.0RC3