Those of you who are playing with SNMP under PHP can thank me later
Sunday, December 28, 2008 8:24:14 PM
Requirements
- PHP >= 5.2.0
- PHP Socket Support
class snmp_Trap
{
/**
* The 'group' to which the message is relevant
*
* @var string
*/
public $community = 'public';
/**
* The SNMP message type (6 for custom)
*
* @var int
*/
public $genericType = 6;
/**
* The SNMP message sub-type (for custom, this is application specific)
*
* @var int
*/
public $specificType = 1;
/**
* A message to go along with this Trap
*
* @var string
*/
public $message;
/**
* An Object Identifier for this Trap
*
* @var string
*/
public $oid = '.1.3.1';
/**
* How long the service this Trap relates to has been operational (in seconds)
*
* @var int
*/
public $uptime;
/**
* The IP address from which this request should be said to originate
*
* @var string
*/
public $ip;
/**
* Uses the SNMP core to send this message
*
*/
public function send()
{
snmp_Core::sendTrap($this);
}
public function __construct()
{
$this->ip = $_SERVER['SERVER_ADDR'];
}
}
# ----
class snmp_Container
{
public $type = 48;
public $children = array();
private $length_cache;
public function getLength()
{
return $this->getChildLength() + strlen($this->getLengthData()) + 1;
}
private function getLengthData()
{
if( $this->length_cache )
return $this->length_cache;
return $this->length_cache = snmp_Core::getIntegerHigh($this->getChildLength());
}
private function getChildLength()
{
$length = 0;
foreach( $this->children as $child )
$length += $child->getLength();
return $length;
}
private function getChildData()
{
$data = '';
foreach( $this->children as $child )
$data .= $child->getData();
return $data;
}
public function getData()
{
return pack('c', $this->type) . $this->getLengthData() . $this->getChildData();
}
# ----
/**
* Adds a container, and returns it for modification
*
* @param int $type
* @return snmp_Container
*/
public function addContainer( $type = 48 )
{
$container = new snmp_Container();
$container->type = $type;
$this->children[] = $container;
return $container;
}
public function addTime( $seconds )
{
$majorUnits = min((int)($seconds / 167772.1647), 255);
$majorUnitRemainder = $seconds % 167772.1647;
$mediumUnits = min((int)($majorUnitRemainder / 655.3647), 255);
$mediumUnitRemainder = $majorUnitRemainder % 655.3647;
$minorUnits = min((int)($mediumUnitRemainder / 2.5647), 255);
$data = new snmp_Data();
$data->type = 0x42;
$data->data = pack('cccc', $majorUnits, $mediumUnits, $minorUnits, 0x83);
$this->children[] = $data;
}
public function addOid( $version )
{
$versions = explode('.', $version);
// -- Unset the first one if empty (OIDs usually start with a period)
if( $versions[0] == '' )
unset($versions[0]);
$majorVersion = (int)array_shift($versions);
$minorVersion = (int)array_shift($versions);
$data = new snmp_Data(6);
$data->data = pack('c', min((40 * $majorVersion) + $minorVersion, 255));
$versionsCount = count($versions);
$versionsKeys = array_keys($versions);
for( $i = 0; $i < $versionsCount; $i++ )
$data->data .= snmp_Core::getIntegerLow($versions[$versionsKeys[$i]]);
$this->children[] = $data;
}
public function addString( $string )
{
$data = new snmp_Data(4);
$data->data = pack('H*', bin2hex($string));
$this->children[] = $data;
}
public function addInteger( $int )
{
$data = new snmp_Data(2);
$data->data = snmp_Core::getIntegerHigh($int);
$this->children[] = $data;
}
public function addIpAddress( $ip )
{
$segments = explode('.', $ip);
$data = new snmp_Data(64);
$data->data = pack('cccc', (int)$segments[0], (int)$segments[1], (int)$segments[2], (int)$segments[3]);
$this->children[] = $data;
}
}
class snmp_Data
{
public $type;
public $data = '';
private $data_cache;
private $length_cache;
public function __construct( $type )
{
$this->type = $type;
}
public function getLength()
{
return $this->getDataLength() + strlen($this->getLengthData()) + 1;
}
private function getDataLength()
{
return strlen($this->data);
}
private function getLengthData()
{
if( $this->length_cache )
return $this->length_cache;
return $this->length_cache = snmp_Core::getIntegerHigh($this->getDataLength());
}
public function getData()
{
if( $this->data_cache )
return $this->data_cache;
return $this->data_cache = pack('c', $this->type) . $this->getLengthData() . $this->data;
}
}
# ----
class snmp_Core
{
public static function sendTrap( snmp_Trap $Trap )
{
$request = new snmp_Container();
$container = $request->addContainer();
$container->addInteger(0);
$container->addString($Trap->community);
$mainContainer = $container->addContainer(0xA4);
$mainContainer->addOid($Trap->oid);
$mainContainer->addIpAddress($Trap->ip);
$mainContainer->addInteger($Trap->genericType);
$mainContainer->addInteger($Trap->specificType);
$mainContainer->addTime($Trap->uptime);
$extraContainer = $mainContainer->addContainer();
/**
* Special case - attached message
*/
if( $Trap->message )
{
$messageContainer = $extraContainer->addContainer();
$messageContainer->addOid($Trap->oid);
$messageContainer->addString($Trap->message);
}
// -- Prepare the data
$broadcastString = $container->getData();
// -- Transmit the data
$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_set_option($sock, SOL_SOCKET, SO_BROADCAST, 1);
socket_sendto($sock, $broadcastString, strlen($broadcastString), 0, '255.255.255.255', 162); // -- SNMP port
}
public static function getIntegerHigh( $value )
{
if( $value >= 256 )
return pack('ccc', floor($value / 256) + 128, floor($value / 256), (int)$value % 256);
elseif( $value >= 128 )
return pack('cc', floor($value / 128) + 128, $value);
else
return pack('c', $value);
}
public static function getIntegerLow( $value )
{
if( $value >= 128 )
return pack('cc', floor($value / 128) + 128, $value % 128);
else
return pack('c', $value);
}
}
$trap = new snmp_Trap();
$trap->message = "This is a test of a character size restriction which seems to be placed on large messages. There must be a way around it, I hope anyway ... time will tell ...";
$trap->oid = ".1.3.4.7.2000.2.1";
$trap->ip = '192.168.2.20';
$trap->send();









