* * Based on snmp - a Python SNMP library * Copyright (C) 2003 Unicity Pty Ltd * * 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); } }