Files
cacti/lib/mib_parser.php
T

486 lines
15 KiB
PHP

<?php
/*
+-------------------------------------------------------------------------+
| Copyright (C) 2004-2017 The Cacti Group |
| |
| This program is free software; you can redistribute it and/or |
| modify it under the terms of the GNU General Public License |
| as published by the Free Software Foundation; either version 2 |
| of the License, or (at your option) any later version. |
| |
| This program is snmpagent in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
+-------------------------------------------------------------------------+
| Cacti: The Complete RRDTool-based Graphing Solution |
+-------------------------------------------------------------------------+
| This code is designed, written, and maintained by the Cacti Group. See |
| about.php and/or the AUTHORS file for specific developer information. |
+-------------------------------------------------------------------------+
| http://www.cacti.net/ |
+-------------------------------------------------------------------------+
*/
/* This mib parser bases on the PHP mib_compiler script of David Eder for
phpsnmp which bases itself on libsnmp. Both scripts are licensed under the
GNU Lesser General Public License.
/**
* phpsnmp - a PHP SNMP library
* Copyright (C) 2004 David Eder <david@eder,us>
*
* Based on snmp - a Python SNMP library
* Copyright (C) 2003 Unicity Pty Ltd <libsnmp@unicity.com.au>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
class MibParser extends MibCache {
protected $parsed = array();
protected $oids = array();
/**
* Constructor
*/
function __construct(){
set_time_limit(0);
ini_set('memory_limit', '256M');
error_reporting(E_ALL);
}
function add_mib($filename, $mib_name){
MibParser::parse_mib(file_get_contents($filename), $mib_name, true);
}
/**
* Get Tokens
*
* @param string $text
* @return array
*/
function get_tokens($text)
{
$in_quote = false;
$in_comment = false;
$token = '';
$tokens = array();
$length = strlen($text);
for($i = 0; $i < $length; $i++)
{
if($in_quote)
{
if($text{$i} == '"')
{
$in_quote = false;
if($token != '')
{
/* strip whitespaces from the end of the beginning of every object description row */
$lines = preg_split( '/\r\n|\r|\n/', $token);
$token = '';
foreach($lines as $line) {
$token .= trim($line) . "\r\n";
}
$tokens[] = $token;
$token = '';
}
}
else
$token .= $text{$i};
}
elseif($in_comment)
{
if($text{$i} == "\n" || $text{$i} == "\r")
$in_comment = false;
}
else
{
switch($text{$i})
{
case ':':
if($text{$i+1} == ':' && $text{$i+2} == '=')
{
if($token != '')
{
$tokens[] = $token;
$token = '';
}
$tokens[] = '::=';
$i += 2;
}
else
$token .= $text{$i};
break;
case '.':
if($text{$i+1} == '.')
{
if($token != '')
{
$tokens[] = $token;
$token = '';
}
$tokens[] = '..';
$i++;
}
else
$token .= $text{$i};
break;
case ',':
case ';':
case '{':
case '}':
case '(':
case ')':
case '|':
if($token != '')
{
$tokens[] = $token;
$token = '';
}
$tokens[] = $text{$i};
break;
case ' ':
case "\t":
case "\n":
case "\r":
if($token != '')
{
$tokens[] = $token;
$token = '';
}
break;
case '-':
if($text{$i+1} == '-')
$in_comment = true;
else
$token .= $text{$i};
break;
case '"';
$in_quote = true;
break;
default:
$token .= $text{$i};
}
}
}
if($token != '')
$tokens[] = $token;
return $tokens;
}
/**
* Parse simple token
*
* @param array $tokens
* @param integer $index
* @param array $allowed
* @return array
*/
function parse_simple_token($tokens, &$index, $allowed=NULL)
{
$index++;
if(is_array($allowed))
{
if(in_array(strtolower($tokens[$index]), $allowed))
return $tokens[$index];
}
elseif(is_null($allowed))
{
if($tokens[$index] == '{')
return MibParser::parse_bracket_token($tokens, $index, '{', '}');
else
return $tokens[$index];
}
trigger_error("unknown token {$tokens[$index]} {$tokens[$index]}", E_USER_ERROR);
return $tokens[$index];
}
/**
* Parse SYNTAX token
*
* @param array $tokens
* @param integer $index
* @return array
*/
function parse_SYNTAX_token($tokens, &$index)
{
$ret = NULL;
switch($tokens[$index+1])
{
case 'SEQUENCE':
if($tokens[$index+2] == 'OF')
{
$index += 3;
if($tokens[$index] == '{')
$ret = array('SEQUENCE OF'=>MibParser::parse_bracket_token($tokens, $index, '{', '}'));
else
$ret = array('SEQUENCE OF'=>$tokens[$index]);
}
break;
case 'OCTET':
if($tokens[$index+2] == 'STRING')
{
$index += 3;
if($tokens[$index] == '{')
$ret = array('OCTET STRING'=>MibParser::parse_bracket_token($tokens, $index, '{', '}'));
elseif($tokens[$index] == '(')
$ret = array('OCTET STRING'=>MibParser::parse_bracket_token($tokens, $index, '(', ')'));
else
$ret = 'OCTET STRING';
}
break;
case 'OBJECT':
if($tokens[$index+2] == 'IDENTIFIER') {
$index++;
$ret = $tokens[$index] . ' ' . $tokens[$index+1];
$index++;
}else {
trigger_error("unknown token {$tokens[$index+1]} {$tokens[$index+2]}", E_USER_ERROR);
}
break;
case 'INTEGER':
case 'Counter':
case 'Counter32':
case 'Counter64':
case 'Integer32':
case 'Gauge':
case 'Gauge32':
case 'TimeStamp':
case 'TimeTicks':
case 'PhysAddress':
case 'IpAddress':
case 'DateAndTime':
case 'TimeInterval':
case 'Unsigned32':
case 'DisplayString':
$index++;
$ret = $tokens[$index];
if($tokens[$index+1] == '{') {
$index++;
$ret = array($ret=>MibParser::parse_bracket_token($tokens, $index, '{', '}'));
} elseif($tokens[$index+1] == '(') {
$index++;
$ret = array($ret=>MibParser::parse_bracket_token($tokens, $index, '(', ')'));
}
break;
default:
$index++;
$ret = $tokens[$index];
if($tokens[$index+1] == '{') {
$index++;
$ret = array($ret=>MibParser::parse_bracket_token($tokens, $index, '{', '}'));
} elseif($tokens[$index+1] == '(') {
$index++;
$ret = array($ret=>MibParser::parse_bracket_token($tokens, $index, '(', ')'));
}
break;
}
return $ret;
}
/**
* Parse bracket token
*
* @param array $tokens
* @param integer $index
* @param integer $start
* @param integer $end
* @return array
*/
function parse_bracket_token($tokens, &$index, $start, $end)
{
$begin = $index + 1;
while($index + 1 < count($tokens) && $tokens[$index] != $end)
{
$index++;
if($tokens[$index] == $start)
{
MibParser::parse_bracket_token($tokens, $index, $start, $end);
$index++;
}
}
return array_slice($tokens, $begin, $index - $begin);
}
/**
* Parse a MIB file
*
* @param string $mibtext
* @param boolean $full
*/
function parse_mib($mibtext, $mib_name, $full=false)
{
$tokens = MibParser::get_tokens($mibtext);
$cnt = count($tokens);
$rec = array();
for($index = 0; $index < $cnt; $index++)
{
if($tokens[$index] == 'DEFINITIONS' && $tokens[$index+1] == "::=" && $tokens[$index+2] == "BEGIN"){
$mib_name = $tokens[$index-1];
$this->mib = $mib_name;
}
else if(in_array($tokens[$index], array('OBJECT-IDENTITY', 'OBJECT-TYPE', 'OBJECT-GROUP', 'NOTIFICATION-GROUP', 'MODULE-IDENTITY', 'NOTIFICATION-TYPE')) )
{
if($tokens[$index-1] != ',' && $tokens[$index+1] != 'FROM' && $tokens[$index+1] != 'MACRO')
{
if(isset($rec['NAME']) && isset($rec['VALUE'])) $this->parsed[] = $rec;
$rec = array('NAME'=>$tokens[$index-1], 'MIB'=>$mib_name , 'TYPE' => $tokens[$index]);
}
}
elseif( $tokens[$index] == "TEXTUAL-CONVENTION")
{
if($tokens[$index-1] == '::=') {
if(isset($rec['NAME']) && isset($rec['VALUE'])) $this->parsed[] = $rec;
$rec = array('NAME'=>$tokens[$index-2], 'MIB'=>$mib_name, 'TYPE' => $tokens[$index], 'VALUE' => "TEXTUAL-CONVENTION");
}
}
elseif($tokens[$index] == 'OBJECT')
{
if($tokens[$index+1] == 'IDENTIFIER' && $tokens[$index-1] != '(' && $tokens[$index-1] != '::=' && $tokens[$index-1] != 'SYNTAX' && $tokens[$index-2] != '(')
{
if(isset($rec['NAME']) && isset($rec['VALUE'])) $this->parsed[] = $rec;
$rec = array('NAME'=>$tokens[$index-1], 'MIB'=>$mib_name, 'TYPE' => $tokens[$index]);
}
}
elseif($tokens[$index] == '{')
MibParser::parse_bracket_token($tokens, $index, '{', '}');
elseif(isset($rec['NAME']))
{
if($tokens[$index] == '::=' && $tokens[$index+1] != "TEXTUAL-CONVENTION")
{
$rec['VALUE'] = MibParser::parse_simple_token($tokens, $index);
$this->parsed[] = $rec;
$rec = array();
}
elseif($full)
{
if($tokens[$index] == 'ACCESS')
$rec['ACCESS'] = MibParser::parse_simple_token($tokens, $index, array('read-only', 'not-accessible', 'read-write'));
elseif($tokens[$index] == 'OBJECTS')
$rec['OBJECTS'] = MibParser::parse_simple_token($tokens, $index);
elseif($tokens[$index] == 'NOTIFICATIONS')
$rec['NOTIFICATIONS'] = MibParser::parse_simple_token($tokens, $index);
elseif($tokens[$index] == 'DEFVAL')
$rec['DEFVAL'] = MibParser::parse_simple_token($tokens, $index);
elseif($tokens[$index] == 'DESCRIPTION')
{
$rec['DESCRIPTION'] = MibParser::parse_simple_token($tokens, $index);
} elseif($tokens[$index] == 'INDEX')
$rec['INDEX'] = MibParser::parse_simple_token($tokens, $index);
elseif($tokens[$index] == 'MAX-ACCESS')
$rec['MAX-ACCESS'] = MibParser::parse_simple_token($tokens, $index, array('read-only', 'not-accessible', 'read-write', 'read-create', 'accessible-for-notify'));
elseif($tokens[$index] == 'REFERENCE')
$rec['REFERENCE'] = MibParser::parse_simple_token($tokens, $index);
elseif($tokens[$index] == 'STATUS')
$rec['STATUS'] = MibParser::parse_simple_token($tokens, $index, array('current', 'deprecated', 'obsolete', 'mandatory'));
elseif($tokens[$index] == 'SYNTAX')
$rec['SYNTAX'] = MibParser::parse_SYNTAX_token($tokens, $index);
elseif($tokens[$index] == 'UNITS')
$rec['UNITS'] = MibParser::parse_simple_token($tokens, $index);
}
}
}
if(isset($rec['NAME']) && isset($rec['VALUE'])) $this->parsed[] = $rec;
}
function generate(){
$this->oids['enterprises'] = array('oid' => '.1.3.6.1.4.1');
foreach($this->parsed as $object) {
if(isset($object['VALUE'][0]) && !is_numeric($object['VALUE'][0])) {
if(isset($object['VALUE'][1]) && is_numeric($object['VALUE'][1])) {
if(isset($this->oids[$object['VALUE'][0]]['oid'])) {
$oid = $this->oids[$object['VALUE'][0]]['oid'] . "." . $object['VALUE'][1];
}else {
$oid = db_fetch_cell("SELECT `oid` FROM snmpagent_cache WHERE name = '" . $object['VALUE'][0] . "' LIMIT 1");
$oid .= "." . $object['VALUE'][1];
}
$syntax = NULL;
if(isset($object['SYNTAX'])) {
$syntax = is_array($object['SYNTAX']) ? key($object['SYNTAX']) : $object['SYNTAX'];
}
$parent_otype = strtoupper(substr($object['VALUE'][0], -5));
$otype = $object['TYPE'];
if($otype == "OBJECT-TYPE" && $syntax !== NULL && !in_array(strtoupper(substr($object['NAME'], -5)), array("TABLE", "ENTRY")) && !in_array($parent_otype, array("TABLE", "ENTRY")) ) {
$oid .= ".0";
$otype = "DATA";
}
$kind ="unknown";
if(in_array($otype, array("MODULE-IDENTITY", "OBJECT-IDENTITY"))) {
$kind = "Node";
}else if(in_array($otype, array("NOTIFICATION-GROUP", "OBJECT-GROUP"))) {
$kind = "Group";
}else if($otype == "OBJECT-TYPE" && strtoupper(substr($object['NAME'], -5)) == "TABLE" && $syntax == "SEQUENCE OF") {
$kind = "Table";
}else if($otype == "OBJECT-TYPE" && strtoupper(substr($object['NAME'], -5)) == "ENTRY" && $parent_otype == "TABLE") {
$kind = "Row";
}else if($otype == "OBJECT-TYPE" && $parent_otype == "ENTRY") {
$kind = "Column";
}else if($otype == "DATA") {
$kind = "Scalar";
}else if($otype == "NOTIFICATION-TYPE") {
$kind = "Notification";
}
$this->oids[$object['NAME']] = array(
'oid' => $oid,
'max-access' => (isset($object['MAX-ACCESS'])? $object['MAX-ACCESS'] : 'not-accessible'),
'syntax' => $syntax,
'otype' => $otype,
'kind' => $kind,
'mib' => $object['MIB'],
'description' => $object['DESCRIPTION']
);
if($otype == "OBJECT-GROUP" && isset($object['OBJECTS'])) {
$this->oids[$object['NAME']]['objects'] = array_diff($object['OBJECTS'], array(','));
} elseif($otype == "NOTIFICATION-GROUP" && isset($object['NOTIFICATIONS'])) {
$this->oids[$object['NAME']]['notifications'] = array_diff($object['NOTIFICATIONS'], array(','));
} elseif($otype == "NOTIFICATION-TYPE" && isset($object['OBJECTS'])) {
$this->oids[$object['NAME']]['objects'] = array_diff($object['OBJECTS'], array(','));
}
} elseif($object["VALUE"] == "TEXTUAL-CONVENTION") {
$syntax = NULL;
if(isset($object['SYNTAX'])) {
$syntax = is_array($object['SYNTAX']) ? key($object['SYNTAX']) : $object['SYNTAX'];
}
$kind = "Textual-Convention";
$otype = "TEXTUAL-CONVENTION";
$this->oids[$object['NAME']] = array(
'oid' => "",
'max-access' => "",
'syntax' => $syntax,
'otype' => $otype,
'kind' => $kind,
'mib' => $object['MIB'],
'description' => $object['DESCRIPTION']
);
}
}
}
unset($this->oids['enterprises']);
unset($this->parsed);
}
}