src/Config.php
<?php
namespace RouterOS;
use RouterOS\Exceptions\ConfigException;
use RouterOS\Helpers\ArrayHelper;
use RouterOS\Helpers\TypeHelper;
use RouterOS\Interfaces\ConfigInterface;
use function gettype;
/**
* Class Config with array of parameters
*
* @package RouterOS
* @since 0.1
*/
class Config implements ConfigInterface
{
/**
* By default legacy login on RouterOS pre-6.43 is not supported
*/
public const LEGACY = false;
/**
* Default port number
*/
public const PORT = 8728;
/**
* Default ssl port number
*/
public const PORT_SSL = 8729;
/**
* If true then use API in SSL mode
*
* @see https://wiki.mikrotik.com/wiki/Manual:API-SSL
*/
public const SSL = false;
/**
* List of additional options for work with SSL context
*
* @see https://www.php.net/manual/en/context.ssl.php
*/
public const SSL_OPTIONS = [
/*
* Sets the list of available ciphers. By default, RouterOS available via 'ADH:ALL'.
*
* @example 'ADH:ALL' // Alias to ADH:ALL@SECLEVEL=1
* 'ADH:ALL@SECLEVEL=0' // Everything is permitted. This retains compatibility with previous versions of OpenSSL.
* 'ADH:ALL@SECLEVEL=1' // The security level corresponds to a minimum of 80 bits of security.
* 'ADH:ALL@SECLEVEL=2' // Security level set to 112 bits of security.
* 'ADH:ALL@SECLEVEL=3' // Security level set to 128 bits of security.
* 'ADH:ALL@SECLEVEL=4' // Security level set to 192 bits of security.
* 'ADH:ALL@SECLEVEL=5' // Security level set to 256 bits of security.
*
* @link https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_security_level.html
*/
'ciphers' => 'ADH:ALL', // ADH:ALL, ADH:ALL@SECLEVEL=0, ADH:ALL@SECLEVEL=1 ... ADH:ALL@SECLEVEL=5
// Require verification of SSL certificate used.
'verify_peer' => false,
// Require verification of peer name.
'verify_peer_name' => false,
// Allow self-signed certificates. Requires verify_peer=true.
'allow_self_signed' => false,
];
/**
* Max timeout for connecting to router (in seconds)
*/
public const TIMEOUT = 10;
/**
* Max read timeout from router (in seconds)
*/
public const SOCKET_TIMEOUT = 30;
/**
* List of options for socket context
*
* @see https://www.php.net/manual/en/context.socket.php
*/
public const SOCKET_OPTIONS = [
// Examples:
// 'bindto' => '192.168.0.100:0', // connect to the internet using the '192.168.0.100' IP
// 'bindto' => '192.168.0.100:7000', // connect to the internet using the '192.168.0.100' IP and port '7000'
// 'bindto' => '[2001:db8::1]:7000', // connect to the internet using the '2001:db8::1' IPv6 address and port '7000'
// 'bindto' => '0:7000', // connect to the internet using port '7000'
// 'bindto' => '0:0', // Forcing IPv4
// 'bindto' => '[::]:0', // Forcing IPv6
// 'tcp_nodelay' => true, // Setting this option to true will set SOL_TCP,NO_DELAY=1 appropriately, thus disabling the TCP Nagle algorithm.
];
/**
* Count of reconnect attempts
*/
public const ATTEMPTS = 10;
/**
* Delay between attempts in seconds
*/
public const ATTEMPTS_DELAY = 1;
/**
* Number of SSH port for exporting configuration
*/
public const SSH_PORT = 22;
/**
* By default stream on blocking mode
*/
public const SOCKET_BLOCKING = true;
/**
* Max read timeout from router via SSH (in seconds)
*/
public const SSH_TIMEOUT = 30;
public const SSH_PRIVATE_KEY = '~/.ssh/id_rsa';
/**
* List of allowed parameters of config
*/
public const ALLOWED = [
'host' => 'string', // Address of Mikrotik RouterOS
'user' => 'string', // Username
'pass' => 'string', // Password
'port' => 'integer', // RouterOS API port number for access (if not set use default or default with SSL if SSL enabled)
'ssl' => 'boolean', // Enable ssl support (if port is not set this parameter must change default port to ssl port)
'ssl_options' => 'array', // List of SSL options, eg.
'legacy' => 'boolean', // Support of legacy login scheme (true - pre 6.43, false - post 6.43)
'timeout' => 'integer', // Max timeout for instantiating connection with RouterOS
'socket_timeout' => 'integer', // Max timeout for read from RouterOS
'socket_blocking' => 'boolean', // Set blocking mode on a socket stream
'socket_options' => 'array', // List of socket context options
'attempts' => 'integer', // Count of attempts to establish TCP session
'delay' => 'integer', // Delay between attempts in seconds
'ssh_port' => 'integer', // Number of SSH port
'ssh_timeout' => 'integer', // Max timeout for read from RouterOS via SSH proto (for "/export" command)
'ssh_private_key' => 'string', // Max timeout for read from RouterOS via SSH proto (for "/export" command)
];
/**
* Array of parameters (with some default values)
*
* @var array
*/
private $_parameters = [
'legacy' => self::LEGACY,
'ssl' => self::SSL,
'ssl_options' => self::SSL_OPTIONS,
'timeout' => self::TIMEOUT,
'socket_timeout' => self::SOCKET_TIMEOUT,
'socket_blocking' => self::SOCKET_BLOCKING,
'socket_options' => self::SOCKET_OPTIONS,
'attempts' => self::ATTEMPTS,
'delay' => self::ATTEMPTS_DELAY,
'ssh_port' => self::SSH_PORT,
'ssh_timeout' => self::SSH_TIMEOUT,
'ssh_private_key' => self::SSH_PRIVATE_KEY,
];
/**
* Config constructor.
*
* @param array $parameters List of parameters which can be set on object creation stage
*
* @throws \RouterOS\Exceptions\ConfigException
* @since 0.6
*/
public function __construct(array $parameters = [])
{
foreach ($parameters as $key => $value) {
$this->set($key, $value);
}
}
/**
* {@inheritdoc}
*
* @throws \RouterOS\Exceptions\ConfigException when name of configuration key is invalid or not allowed
*/
public function set(string $name, $value): ConfigInterface
{
// Check of key in array
if (ArrayHelper::checkIfKeyNotExist($name, self::ALLOWED)) {
throw new ConfigException("Requested parameter '$name' not found in list [" . implode(',', array_keys(self::ALLOWED)) . ']');
}
// Check what type has this value
if (TypeHelper::checkIfTypeMismatch(gettype($value), self::ALLOWED[$name])) {
throw new ConfigException("Parameter '$name' has wrong type '" . gettype($value) . "' but should be '" . self::ALLOWED[$name] . "'");
}
// Save value to array
$this->_parameters[$name] = $value;
return $this;
}
/**
* Return port number (get from defaults if port is not set by user)
*
* @param string $parameter
*
* @return null|int
*/
private function getPort(string $parameter): ?int
{
// If client need port number and port is not set
if ('port' === $parameter && (!isset($this->_parameters['port']) || null === $this->_parameters['port'])) {
// then use default with or without ssl encryption
return (isset($this->_parameters['ssl']) && $this->_parameters['ssl'])
? self::PORT_SSL
: self::PORT;
}
return null;
}
/**
* {@inheritdoc}
*
* @throws \RouterOS\Exceptions\ConfigException when parameter is not allowed
*/
public function delete(string $parameter): ConfigInterface
{
// Check of key in array
if (ArrayHelper::checkIfKeyNotExist($parameter, self::ALLOWED)) {
$list = implode(',', array_keys(self::ALLOWED));
throw new ConfigException("Requested parameter '$parameter' not found in list [$list]");
}
// Save value to array
unset($this->_parameters[$parameter]);
return $this;
}
/**
* {@inheritdoc}
*
* @throws \RouterOS\Exceptions\ConfigException when parameter is not allowed
*/
public function get(string $parameter)
{
// Check of key in array
if (ArrayHelper::checkIfKeyNotExist($parameter, self::ALLOWED)) {
$list = implode(',', array_keys(self::ALLOWED));
throw new ConfigException("Requested parameter '$parameter' not found in list [$list]");
}
return $this->getPort($parameter) ?? $this->_parameters[$parameter];
}
/**
* {@inheritdoc}
*/
public function getParameters(): array
{
return $this->_parameters;
}
}