Packages
Elixir client for MikroTik RouterOS binary API with connection pooling, telemetry, and helper functions. Supports RouterOS 6.x and 7.x with both MD5 and plain text authentication over TCP and TLS.
Current section
Files
Jump to
Current section
Files
lib/routeros_api.ex
defmodule RouterosApi do
@moduledoc """
Elixir client for MikroTik RouterOS binary API.
This module provides the main public API for connecting to and
communicating with MikroTik RouterOS devices.
## Features
- Plain TCP connections (port 8728)
- TLS/SSL connections (port 8729)
- MD5 challenge-response authentication
- Response parsing to Elixir maps
- Synchronous command execution
## Quick Start
# Connect to router
{:ok, conn} = RouterosApi.connect(%{
host: "192.168.88.1",
username: "admin",
password: "password"
})
# Execute a command
{:ok, interfaces} = RouterosApi.command(conn, ["/interface/print"])
# Disconnect
RouterosApi.disconnect(conn)
## Configuration
Connection configuration accepts the following options:
- `:host` - Router hostname or IP address (required)
- `:port` - Port number (optional, defaults to 8728 for plain, 8729 for TLS)
- `:username` - RouterOS username (required)
- `:password` - RouterOS password (required)
- `:ssl` - Boolean, use TLS connection (optional, auto-detected from port)
- `:ssl_opts` - SSL options (optional, e.g., `[verify: :verify_peer]`)
- `:timeout` - Connection timeout in milliseconds (optional, default: 5000)
## Examples
### Plain TCP Connection
{:ok, conn} = RouterosApi.connect(%{
host: "192.168.88.1",
port: 8728,
username: "admin",
password: "password"
})
### TLS Connection
{:ok, conn} = RouterosApi.connect_tls(%{
host: "192.168.88.1",
port: 8729,
username: "admin",
password: "password",
ssl_opts: [verify: :verify_peer]
})
### Execute Commands
# List interfaces
{:ok, interfaces} = RouterosApi.command(conn, ["/interface/print"])
# Add IP address
{:ok, _} = RouterosApi.command(conn, [
"/ip/address/add",
"=address=192.168.88.2/24",
"=interface=bridge"
])
# Query with filter
{:ok, [interface]} = RouterosApi.command(conn, [
"/interface/print",
"?name=ether1"
])
"""
alias RouterosApi.{Connection, Pool}
@type connection :: pid() | atom()
@type config :: %{
required(:host) => String.t(),
required(:username) => String.t(),
required(:password) => String.t(),
optional(:port) => non_neg_integer(),
optional(:ssl) => boolean(),
optional(:ssl_opts) => keyword(),
optional(:timeout) => non_neg_integer()
}
@doc """
Connects to a MikroTik RouterOS device.
Auto-detects whether to use TLS based on the port number.
Port 8729 will use TLS, all other ports will use plain TCP.
Returns `{:ok, connection}` on success or `{:error, reason}` on failure.
## Examples
# Plain TCP (auto-detected)
{:ok, conn} = RouterosApi.connect(%{
host: "192.168.88.1",
username: "admin",
password: "password"
})
# TLS (auto-detected from port)
{:ok, conn} = RouterosApi.connect(%{
host: "192.168.88.1",
port: 8729,
username: "admin",
password: "password"
})
"""
@spec connect(config()) :: {:ok, connection()} | {:error, term()}
def connect(config) when is_map(config) do
Connection.start_link(config)
end
@doc """
Connects to a MikroTik RouterOS device using plain TCP.
Forces a plain TCP connection regardless of port number.
Returns `{:ok, connection}` on success or `{:error, reason}` on failure.
## Examples
{:ok, conn} = RouterosApi.connect_plain(%{
host: "192.168.88.1",
port: 8728,
username: "admin",
password: "password"
})
"""
@spec connect_plain(config()) :: {:ok, connection()} | {:error, term()}
def connect_plain(config) when is_map(config) do
config = Map.put(config, :ssl, false)
Connection.start_link(config)
end
@doc """
Connects to a MikroTik RouterOS device using TLS.
Forces a TLS connection regardless of port number.
Returns `{:ok, connection}` on success or `{:error, reason}` on failure.
## Examples
{:ok, conn} = RouterosApi.connect_tls(%{
host: "192.168.88.1",
port: 8729,
username: "admin",
password: "password",
ssl_opts: [verify: :verify_peer]
})
"""
@spec connect_tls(config()) :: {:ok, connection()} | {:error, term()}
def connect_tls(config) when is_map(config) do
config = Map.put(config, :ssl, true)
Connection.start_link(config)
end
@doc """
Disconnects from the RouterOS device.
Returns `:ok`.
## Examples
RouterosApi.disconnect(conn)
"""
@spec disconnect(connection()) :: :ok
def disconnect(conn) do
Connection.stop(conn)
end
@doc """
Executes a command on the RouterOS device.
Commands are specified as a list of words (strings).
Returns `{:ok, data}` on success or `{:error, reason}` on failure.
Accepts either a connection PID or a pool name (atom).
## Examples
# With direct connection
{:ok, conn} = RouterosApi.connect(%{...})
{:ok, interfaces} = RouterosApi.command(conn, ["/interface/print"])
# With connection pool
{:ok, interfaces} = RouterosApi.command(:my_pool, ["/interface/print"])
# Get specific interface
{:ok, [interface]} = RouterosApi.command(conn, [
"/interface/print",
"?name=ether1"
])
# Add IP address
{:ok, _} = RouterosApi.command(conn, [
"/ip/address/add",
"=address=192.168.88.2/24",
"=interface=bridge"
])
"""
@spec command(connection(), [String.t()]) :: {:ok, [map()]} | {:error, term()}
def command(conn, words) when is_pid(conn) and is_list(words) do
Connection.command(conn, words)
end
def command(pool_name, words) when is_atom(pool_name) and is_list(words) do
Pool.command(pool_name, words)
end
@doc """
Executes a command on the RouterOS device, raising on error.
Similar to `command/2` but raises a `RouterosApi.Error` exception
on failure instead of returning an error tuple.
Returns the data directly on success.
## Examples
interfaces = RouterosApi.command!(conn, ["/interface/print"])
"""
@spec command!(connection(), [String.t()]) :: [map()]
def command!(conn, words) when is_list(words) do
case command(conn, words) do
{:ok, data} -> data
{:error, error} -> raise error
end
end
end