routeros

package module
v0.0.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 23, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

README

RouterOS Go Client

A Go client library for interacting with MikroTik RouterOS devices via the REST API.

Tests Coverage Version

Features

This library provides a simple and intuitive interface for managing RouterOS devices. It includes:

  • IP Firewall Address List management
  • IP Address management
  • Tool services (like ping)
  • Easy configuration via environment variables
  • Rate limiting to prevent overwhelming the RouterOS device
  • Comprehensive test suite with mock server implementations

Implemented API Endpoints

IP Firewall Address List
  • GET /ip/firewall/address-list - Find address list entries
  • PUT /ip/firewall/address-list - Add new address list entries
IP Addresses
  • GET /ip/address - Get all IP addresses or find by ID
  • PUT /ip/address - Add new IP address
  • DELETE /ip/address - Remove IP address by ID
  • PATCH /ip/address - Update IP address by ID
Tools
  • POST /tool/ping - Ping a host

Installation

go get github.com/art-frela/routeros

Usage

Configuration

The client can be configured using environment variables:

export ROS_BASE_URL="http://192.168.88.1"
export ROS_USER="admin"
export ROS_PASSWORD="password"
export ROS_REQUEST_TIMEOUT="10s"
export ROS_PAUSE_BETWEEN_REQUESTS="100ms"
export ROS_BURST_REQ_COUNT="10"
Creating a Client
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/art-frela/routeros"
)

func main() {
    // Create client configuration from environment variables
    cfg, err := routeros.NewClientConfigFromEnv("ROS")
    if err != nil {
        log.Fatal(err)
    }

    // Create client
    client, err := routeros.NewClient(*cfg)
    if err != nil {
        log.Fatal(err)
    }

    // Use the client
    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
    defer cancel()

    // Example: Get all IP addresses
    addresses, err := client.IPService.GetAddresses(ctx)
    if err != nil {
        log.Fatal(err)
    }

    for _, addr := range addresses {
        fmt.Printf("Address: %s, Interface: %s\n", addr.Address, addr.Interface)
    }
}
IP Firewall Address List
// Find address list entries
addresses, err := client.IPFirewallAddressListService.Find(ctx, "my-list", "192.168.1.100")
if err != nil {
    log.Fatal(err)
}

// Add new address to list
newItem := types.FirewallAddressListNewItem{
    Address: "192.168.1.100",
    List:    "my-list",
}

added, err := client.IPFirewallAddressListService.Add(ctx, newItem)
if err != nil {
    log.Fatal(err)
}
IP Address Management
// Get all IP addresses
addresses, err := client.IPService.GetAddresses(ctx)
if err != nil {
    log.Fatal(err)
}

// Add new IP address
newAddr := types.IPAddressAdd{
    Address:   "192.168.2.1/24",
    Interface: "ether2",
}

added, err := client.IPService.AddAddress(ctx, newAddr)
if err != nil {
    log.Fatal(err)
}

// Update IP address
updateAddr := types.IPAddressAdd{
    Address:   "192.168.2.2/24",
    Interface: "ether2",
    Disabled:  "true",
}

updated, err := client.IPService.UpdateAddress(ctx, added.ID, updateAddr)
if err != nil {
    log.Fatal(err)
}

// Remove IP address
err = client.IPService.RemoveAddress(ctx, added.ID)
if err != nil {
    log.Fatal(err)
}
Tool Services
// Ping a host
req := types.EchoRequest{
    Address: "8.8.8.8",
    Count:   3,
}

response, err := client.ToolService.Ping(ctx, req)
if err != nil {
    log.Fatal(err)
}

for _, echo := range response {
    fmt.Printf("Reply from %s: bytes=%s time=%s TTL=%s\n",
        echo.Host, *echo.Size, *echo.Time, *echo.TTL)
}

Testing

The library includes a comprehensive test suite with mock server implementations:

go test -v ./...

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Versioning

This project follows Semantic Versioning (SemVer).

  • Tags follow SemVer format (e.g., v1.2.3).
  • Pre-v1 releases (v0.x) may include breaking changes between minor versions.
  • A future v2.0.0 release will require a Go module path change to github.com/art-frela/routeros/v2.
  • See CHANGELOG.md for version history and the GitHub tags page for all releases.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Changelog

See CHANGELOG.md for a detailed history of changes.

Documentation

Overview

Package routeros implements a client for the MikroTik RouterOS REST API.

The entry point is a Client, created from a Config (loadable from environment variables with NewClientConfigFromEnv) that carries the base URL, credentials, request timeout, and an optional custom *http.Client. The client groups typed services covering IP firewall address lists, IP addresses, IP routes, and the ping tool.

Every request passes through a rate.Limiter before hitting the device; pacing and burst size are configured via the Config fields PauseBetweenRequests and BurstRequestCount. HTTP-level failures surface as the typed ResponseError, and invalid configuration returns the exported ErrMissBaseURL or ErrMissUserOrPass sentinels.

The upstream API is documented at https://help.mikrotik.com/docs/display/ROS/REST+API. API_COVERAGE.md in the repository tracks which endpoints are implemented and which are planned.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrMissBaseURL is returned by NewClient when Config.BaseURL is empty.
	ErrMissBaseURL = errors.New("miss baseURL")
	// ErrMissUserOrPass is returned by NewClient when Config.User
	// or Config.Password is empty.
	ErrMissUserOrPass = errors.New("miss user/password")
)

Functions

This section is empty.

Types

type Client

type Client struct {
	IPFirewallAddressListService *IPFirewallAddressListService
	ToolService                  *ToolService
	IPService                    *IPService
	IPRouteService               *IPRouteService
	// contains filtered or unexported fields
}

func NewClient

func NewClient(cfg Config) (*Client, error)
Example

ExampleNewClient builds a client from an explicitly constructed Config.

RequestTimeout is set explicitly because the zero value would expire every request context immediately at runtime.

package main

import (
	"fmt"
	"time"

	"github.com/art-frela/routeros"
)

func main() {
	cfg := routeros.Config{
		BaseURL:        "http://192.168.88.1",
		RequestTimeout: 10 * time.Second,
		User:           "admin",
		Password:       "master",
	}

	client, err := routeros.NewClient(cfg)
	if err != nil {
		fmt.Println("client error:", err)
		return
	}

	fmt.Println("client base URL:", client.BaseURL())
}

func (*Client) BaseURL added in v0.0.3

func (c *Client) BaseURL() string

type Config

type Config struct {
	BaseURL              string        `envconfig:"base_url" validate:"required"`
	RequestTimeout       time.Duration `envconfig:"request_timeout" default:"10s"`
	PauseBetweenRequests time.Duration `envconfig:"pause_between_requests" default:"100ms"`
	BurstRequestCount    int           `envconfig:"burst_req_count" default:"10"`
	User                 string        `envconfig:"user" default:"root"`
	Password             string        `envconfig:"password" default:"master"`
	// HTTPClient is an optional custom *http.Client; envconfig:"-" is required
	// because envconfig cannot derive an env key for *http.Client.
	HTTPClient *http.Client `envconfig:"-"`
}

func NewClientConfigFromEnv

func NewClientConfigFromEnv(envPrefix string) (*Config, error)
Example

ExampleNewClientConfigFromEnv loads the client configuration from environment variables prefixed with ROS_ (ROS_BASE_URL, ROS_USER and ROS_PASSWORD — see the Config documentation for the full list).

package main

import (
	"fmt"

	"github.com/art-frela/routeros"
)

func main() {
	cfg, err := routeros.NewClientConfigFromEnv("ROS")
	if err != nil {
		fmt.Println("config error:", err)
		return
	}

	client, err := routeros.NewClient(*cfg)
	if err != nil {
		fmt.Println("client error:", err)
		return
	}

	fmt.Println("client base URL:", client.BaseURL())
}

type IPFirewallAddressListService

type IPFirewallAddressListService struct {
	// contains filtered or unexported fields
}

IPFirewallAddressListService handles communication with the IP firewall address-list methods of the RouterOS REST API.

RouterOS API docs: https://manual.mikrotik.com/docs/Developer+Guides/rest-api

func (*IPFirewallAddressListService) Add

Add adds a new entry to a firewall address list.

RouterOS API docs: https://manual.mikrotik.com/docs/Developer+Guides/rest-api

Example

ExampleIPFirewallAddressListService_Add adds a new entry to a firewall address list and prints the stored item with its assigned ID.

package main

import (
	"context"
	"fmt"
	"time"

	"github.com/art-frela/routeros"
	"github.com/art-frela/routeros/types"
)

func main() {
	cfg := routeros.Config{
		BaseURL:        "http://192.168.88.1",
		RequestTimeout: 10 * time.Second,
		User:           "admin",
		Password:       "master",
	}

	client, err := routeros.NewClient(cfg)
	if err != nil {
		fmt.Println("client error:", err)
		return
	}

	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	item := types.FirewallAddressListNewItem{
		Address: "192.168.1.100",
		List:    "blacklist",
		Comment: "blocked by example",
	}

	added, err := client.IPFirewallAddressListService.Add(ctx, item)
	if err != nil {
		fmt.Println("request error:", err)
		return
	}

	fmt.Printf("added %s to list %s with id %s\n", added.Address, added.List, added.ID)
}

func (*IPFirewallAddressListService) Find

Find retrieves firewall address list entries optionally filtered by list name and/or address.

RouterOS API docs: https://manual.mikrotik.com/docs/Developer+Guides/rest-api

Example

ExampleIPFirewallAddressListService_Find retrieves firewall address list entries filtered by list name and address.

package main

import (
	"context"
	"fmt"
	"time"

	"github.com/art-frela/routeros"
)

func main() {
	cfg := routeros.Config{
		BaseURL:        "http://192.168.88.1",
		RequestTimeout: 10 * time.Second,
		User:           "admin",
		Password:       "master",
	}

	client, err := routeros.NewClient(cfg)
	if err != nil {
		fmt.Println("client error:", err)
		return
	}

	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	entries, err := client.IPFirewallAddressListService.Find(ctx, "blacklist", "192.168.1.100")
	if err != nil {
		fmt.Println("request error:", err)
		return
	}

	for _, entry := range entries {
		fmt.Printf("%s list=%s disabled=%s\n", entry.Address, entry.List, entry.Disabled)
	}
}

type IPRouteService added in v0.0.4

type IPRouteService struct {
	// contains filtered or unexported fields
}

IPRouteService handles communication with the IP route methods of the RouterOS REST API.

RouterOS REST API: https://manual.mikrotik.com/docs/Developer+Guides/rest-api

func (*IPRouteService) AddRoute added in v0.0.4

func (s *IPRouteService) AddRoute(ctx context.Context, item types.IPRouteAdd) (types.IPRoute, error)

AddRoute adds a new static route.

RouterOS REST API: https://manual.mikrotik.com/docs/Developer+Guides/rest-api

func (*IPRouteService) GetRouteByID added in v0.0.4

func (s *IPRouteService) GetRouteByID(ctx context.Context, id string) (types.IPRoute, error)

GetRouteByID returns a specific IP route by its ID.

RouterOS API docs: https://manual.mikrotik.com/docs/Developer+Guides/rest-api

func (*IPRouteService) GetRoutes added in v0.0.4

func (s *IPRouteService) GetRoutes(ctx context.Context) (types.IPRouteList, error)

GetRoutes returns a list of all IP routes configured on the device.

RouterOS REST API: https://manual.mikrotik.com/docs/Developer+Guides/rest-api

func (*IPRouteService) RemoveRoute added in v0.0.4

func (s *IPRouteService) RemoveRoute(ctx context.Context, id string) error

RemoveRoute removes an IP route by its ID.

RouterOS REST API: https://manual.mikrotik.com/docs/Developer+Guides/rest-api

func (*IPRouteService) UpdateRoute added in v0.0.4

func (s *IPRouteService) UpdateRoute(ctx context.Context, id string, item types.IPRouteAdd) (types.IPRoute, error)

UpdateRoute updates an existing IP route identified by its ID.

RouterOS REST API: https://manual.mikrotik.com/docs/Developer+Guides/rest-api

type IPService added in v0.0.4

type IPService struct {
	// contains filtered or unexported fields
}

IPService handles communication with the IP address methods of the RouterOS REST API.

RouterOS API docs: https://manual.mikrotik.com/docs/Developer+Guides/rest-api

func (*IPService) AddAddress added in v0.0.4

func (ips *IPService) AddAddress(ctx context.Context, item types.IPAddressAdd) (types.IPAddress, error)

AddAddress adds a new IP address.

RouterOS API docs: https://manual.mikrotik.com/docs/Developer+Guides/rest-api

func (*IPService) GetAddressByID added in v0.0.4

func (ips *IPService) GetAddressByID(ctx context.Context, id string) (types.IPAddress, error)

GetAddressByID returns a specific IP address by its ID.

RouterOS API docs: https://manual.mikrotik.com/docs/Developer+Guides/rest-api

func (*IPService) GetAddresses added in v0.0.4

func (ips *IPService) GetAddresses(ctx context.Context) (types.IPAddressList, error)

GetAddresses returns a list of all IP addresses configured on the device.

RouterOS API docs: https://manual.mikrotik.com/docs/Developer+Guides/rest-api

Example

ExampleIPService_GetAddresses lists all IP addresses configured on the device and prints each address with its interface.

package main

import (
	"context"
	"fmt"
	"time"

	"github.com/art-frela/routeros"
)

func main() {
	cfg := routeros.Config{
		BaseURL:        "http://192.168.88.1",
		RequestTimeout: 10 * time.Second,
		User:           "admin",
		Password:       "master",
	}

	client, err := routeros.NewClient(cfg)
	if err != nil {
		fmt.Println("client error:", err)
		return
	}

	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	addresses, err := client.IPService.GetAddresses(ctx)
	if err != nil {
		fmt.Println("request error:", err)
		return
	}

	for _, addr := range addresses {
		fmt.Printf("%s on %s\n", addr.Address, addr.Interface)
	}
}

func (*IPService) RemoveAddress added in v0.0.4

func (ips *IPService) RemoveAddress(ctx context.Context, id string) error

RemoveAddress removes an IP address by its ID.

RouterOS API docs: https://manual.mikrotik.com/docs/Developer+Guides/rest-api

func (*IPService) UpdateAddress added in v0.0.4

func (ips *IPService) UpdateAddress(ctx context.Context, id string, item types.IPAddressAdd) (types.IPAddress, error)

UpdateAddress updates an existing IP address identified by its ID.

RouterOS API docs: https://manual.mikrotik.com/docs/Developer+Guides/rest-api

type ResponseError added in v0.0.4

type ResponseError struct {
	StatusCode int
	Body       string
}

ResponseError represents a non-successful HTTP response (status >= 400) from the RouterOS REST API. Body holds the raw response payload.

func (*ResponseError) Error added in v0.0.4

func (e *ResponseError) Error() string

Error implements the error interface, preserving the legacy "status_code: %d, response: %s" format byte-identical.

type ToolService added in v0.0.2

type ToolService struct {
	// contains filtered or unexported fields
}

ToolService handles communication with the tool methods of the RouterOS REST API.

RouterOS REST API: https://manual.mikrotik.com/docs/Developer+Guides/rest-api

func (*ToolService) Ping added in v0.0.2

Ping performs a ping test to a specified host address.

RouterOS REST API: https://manual.mikrotik.com/docs/Developer+Guides/rest-api

Example

ExampleToolService_Ping pings a host from the device and prints one line per reply; timed-out replies carry a status instead of RTT fields.

package main

import (
	"context"
	"fmt"
	"time"

	"github.com/art-frela/routeros"
	"github.com/art-frela/routeros/types"
)

func main() {
	cfg := routeros.Config{
		BaseURL:        "http://192.168.88.1",
		RequestTimeout: 10 * time.Second,
		User:           "admin",
		Password:       "master",
	}

	client, err := routeros.NewClient(cfg)
	if err != nil {
		fmt.Println("client error:", err)
		return
	}

	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	req := types.EchoRequest{
		Address:  "8.8.8.8",
		Count:    3,
		Interval: 1,
	}

	replies, err := client.ToolService.Ping(ctx, req)
	if err != nil {
		fmt.Println("request error:", err)
		return
	}

	for _, echo := range replies {
		if echo.Time != nil {
			fmt.Printf("reply from %s: seq=%s time=%s\n", echo.Host, echo.Seq, *echo.Time)
			continue
		}

		fmt.Printf("reply from %s: seq=%s status=%s\n", echo.Host, echo.Seq, *echo.Status)
	}
}

Directories

Path Synopsis
pkg

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL