Metadata-Version: 2.4
Name: octodns-routeros
Version: 0.3.0
Summary: RouterOS DHCP lease source for octoDNS
Project-URL: Homepage, https://gitlab.com/arbu/octodns-routeros
Project-URL: Source, https://gitlab.com/arbu/octodns-routeros
Project-URL: Issues, https://gitlab.com/arbu/octodns-routeros/issues
Author: Aaron Bulmahn
License-Expression: MIT
Keywords: dns,dns-as-code,mikrotik,octodns,routeros
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Internet :: Name Service (DNS)
Classifier: Topic :: System :: Systems Administration
Requires-Python: >=3.10
Requires-Dist: octodns>=1.5.0
Requires-Dist: requests>=2.27.0
Description-Content-Type: text/markdown

# octodns-routeros

RouterOS DHCP lease source for [octoDNS](https://github.com/octodns/octodns).

Fetches active (bound) DHCP leases from a MikroTik RouterOS device via
the [REST API](https://help.mikrotik.com/docs/spaces/ROS/pages/47579162/REST+API)
and provides them as DNS A/AAAA records.

## Router-side prerequisites

Enable the HTTPS API service on the router:

```
/ip service enable www-ssl
```

Or for plain HTTP (not recommended):

```
/ip service enable www
```

## Installation

```bash
pip install octodns-routeros
```

## Configuration

```yaml
providers:
  routeros:
    class: octodns_routeros.RouterOSSource
    # Required: router hostname/IP
    host: 192.0.2.1
    # Required: API user
    user: admin
    # Password: literal value, or env/<var> to pull from environment
    password: env/ROS_PASS

    # Optional settings (shown with defaults)
    scheme: https
    verify: false
    port: null           # null = default port (443/80)
    timeout: 10
    ttl: 300            # TTL for generated records

    # How to handle multiple leases sharing a host name:
    # fail | pick | disambiguate
    resolution_strategy: fail
    # Which lease wins under pick/disambiguate:
    # oldest | most_recent | lowest_ip | highest_ip
    preference: oldest

zones:
  dyn.example.com.:
    sources:
      - routeros
    targets:
      - your_dns_provider
```

Alternatively, the password can be specified directly:

```yaml
    password: your_secret_password
```

Or via a `ROS_PASS` environment variable in the shell running octoDNS.

## How it works

On each sync cycle, the source:

1. Queries the RouterOS REST API for **bound** DHCP leases from both
   `/rest/ip/dhcp-server/lease` (IPv4) and `/rest/ipv6/dhcp-server/lease`
   (IPv6).
2. Each bound lease with a non-empty `host-name` creates a record:
   - Only the **first label** of the host name is used as the record name
     (e.g. `laptop.lan` becomes `laptop`).
   - **IPv4** addresses produce **A** records.
   - **IPv6** addresses produce **AAAA** records.
3. A missing IPv6 endpoint (HTTP 404) is silently ignored — safe for
   RouterOS 6.x or routers without IPv6 DHCP.
4. If multiple leases map to the same record name, they are resolved via
   `resolution_strategy` (default `fail`):

   - `fail`: raise an error listing the conflicting leases
   - `pick`: publish a single record, selecting the lease that ranks
     first by `preference`
   - `disambiguate`: publish a record for every lease — the winner keeps
     the plain name, the rest get a MAC-address suffix
     (e.g. `laptop-aa-bb-cc-dd-ee-ff`)

   `preference` determines the winner (default `oldest`):

   - `oldest`: longest-held lease (largest `age`) — most stable, avoids
     a name switching between devices
   - `most_recent`: most recently seen (smallest `last-seen`)
   - `lowest_ip` / `highest_ip`: numerically lowest/highest address

## Development

```bash
# Install dependencies
uv sync --group dev

# Run tests
uv run pytest
```

## Releasing

1. Update `CHANGELOG.md` — move the new version's entry from `- unreleased`
   to a date and add any missing items.
2. Commit and push to `main`.
3. Tag the release: `git tag 0.2.0 && git push --tags`.

CI will run the test suite, build the package, create a GitLab Release
with the changelog section, and publish to PyPI.

## Changes

See [CHANGELOG.md](CHANGELOG.md) for release history.

## License

MIT
