34777-vm/includes/routeros_api.class.php
2025-10-08 06:10:35 +00:00

215 lines
6.7 KiB
PHP

<?php
/**
* RouterOS API client implementation.
*
* @author Denis Basta
* @copyright 2008-2013 Denis Basta
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.6
*/
class RouterosAPI
{
public $debug = false; // Show debug information
public $connected = false; // Connection status
public $port = 8728; // RouterOS API port
public $timeout = 3; // Connection timeout
public $attempts = 5; // Connection attempts
public $delay = 3; // Delay between connection attempts
private $socket; // Socket resource
private $error_no; // Error number
private $error_str; // Error string
/**
* Connect to RouterOS
*
* @param string $ip Hostname (IP or domain) of the RouterOS server
* @param string $login The RouterOS username
* @param string $password The RouterOS password
*
* @return boolean Connection status
*/
public function connect($ip, $login, $password)
{
for ($ATTEMPT = 1; $ATTEMPT <= $this->attempts; $ATTEMPT++) {
$this->connected = false;
$this->debug('Connection attempt #' . $ATTEMPT . ' to ' . $ip . ':' . $this->port . '...');
$this->socket = @fsockopen($ip, $this->port, $this->error_no, $this->error_str, $this->timeout);
if ($this->socket) {
socket_set_timeout($this->socket, $this->timeout);
$this->write('/login');
$RESPONSE = $this->read(false);
if (isset($RESPONSE[0]) && $RESPONSE[0] == '!done') {
if (preg_match_all('/[^=]+/i', $RESPONSE[1], $MATCHES)) {
if ($MATCHES[0][0] == 'ret' && strlen($MATCHES[0][1]) == 32) {
$this->write('/login', false);
$this->write('=name=' . $login, false);
$this->write('=response=00' . md5(chr(0) . $password . pack('H*', $MATCHES[0][1])));
$RESPONSE = $this->read(false);
if (isset($RESPONSE[0]) && $RESPONSE[0] == '!done') {
$this->connected = true;
break;
}
}
}
}
fclose($this->socket);
}
sleep($this->delay);
}
if ($this->connected) {
$this->debug('Connected successfully to ' . $ip . ':' . $this->port);
} else {
$this->debug('Error connecting to ' . $ip . ':' . $this->port);
}
return $this->connected;
}
/**
* Disconnect from RouterOS
*/
public function disconnect()
{
fclose($this->socket);
$this->connected = false;
$this->debug('Disconnected');
}
/**
* Parse response from RouterOS
*
* @param array $response Response data
*
* @return array Parsed data
*/
public function parseResponse($response)
{
if (is_array($response)) {
$PARSED = array();
$CURRENT = null;
$singlevalue = null;
foreach ($response as $x) {
if (in_array($x, array('!fatal', '!re', '!trap'))) {
if ($x == '!re') {
$CURRENT =& $PARSED[];
} else {
$CURRENT =& $PARSED[$x][];
}
} elseif ($x != '!done') {
if (preg_match_all('/[^=]+/i', $x, $MATCHES)) {
if ($MATCHES[0][0] == 'ret') {
$singlevalue = $MATCHES[0][1];
}
$CURRENT[$MATCHES[0][0]] = (isset($MATCHES[0][1]) ? $MATCHES[0][1] : '');
}
}
}
if (empty($PARSED) && !is_null($singlevalue)) {
$PARSED = $singlevalue;
}
return $PARSED;
} else {
return array();
}
}
/**
* Read data from RouterOS
*
* @param boolean $parse Parse the data?
*
* @return array Data array
*/
public function read($parse = true)
{
$RESPONSE = array();
$line = '';
while (true) {
$BYTE = fread($this->socket, 1);
$line .= $BYTE;
if ($BYTE == "\0") {
$RESPONSE[] = $line;
if (substr($line, -5) == "!done\0") {
break;
}
$line = '';
}
}
if ($parse) {
return $this->parseResponse($RESPONSE);
} else {
return $RESPONSE;
}
}
/**
* Write (send) data to RouterOS
*
* @param string $command A string with the command to send
* @param boolean $param2 If we are sending a command, or a parameter
*
* @return void
*/
public function write($command, $param2 = true)
{
if ($command) {
$data = explode("\n", $command);
foreach ($data as $com) {
$com = trim($com);
fwrite($this->socket, $this->encodeLength(strlen($com)) . $com);
$this->debug('<<< ' . $com);
}
if (gettype($param2) == 'integer') {
fwrite($this->socket, $this->encodeLength(strlen('.tag=' . $param2)) . '.tag=' . $param2 . "\0");
$this->debug('<<< .tag=' . $param2);
} elseif (gettype($param2) == 'boolean') {
fwrite($this->socket, ($param2 ? '' : "\0"));
}
}
}
/**
* Encode length of the string
*
* @param integer $length Length of the string
*
* @return string Encoded length
*/
private function encodeLength($length)
{
if ($length < 0x80) {
return chr($length);
}
if ($length < 0x4000) {
return chr(($length >> 8) | 0x80) . chr($length & 0xFF);
}
if ($length < 0x200000) {
return chr(($length >> 16) | 0xC0) . chr(($length >> 8) & 0xFF) . chr($length & 0xFF);
}
if ($length < 0x10000000) {
return chr(($length >> 24) | 0xE0) . chr(($length >> 16) & 0xFF) . chr(($length >> 8) & 0xFF) . chr($length & 0xFF);
}
return chr(0xF0) . chr(($length >> 24) & 0xFF) . chr(($length >> 16) & 0xFF) . chr(($length >> 8) & 0xFF) . chr($length & 0xFF);
}
/**
* Print debug information
*
* @param string $text Debug text
*
* @return void
*/
private function debug($text)
{
if ($this->debug) {
echo $text . "\n";
}
}
}