Compare commits

...

3 commits

Author SHA1 Message Date
7a8adad529 Add my DNS to IPv6 Subnet resolver to my custom scripts repo 2026-01-04 02:02:32 +01:00
9d98352e65 Update template 2026-01-04 02:01:52 +01:00
2f94600859 fix typo 2026-01-03 20:12:42 +01:00
5 changed files with 238 additions and 18 deletions

View file

@ -0,0 +1,78 @@
# -------------------------------------------------------------------------------
# Script to grab IPv6 Addresses from DNS an converting them to subnets
#
# by Philip 'ShokiNN' Henning <mail@philip-henning.com>
# RouterOS compatibility: 7+
# Version 1.1
# last update: 03.01.2026
# https://git.s1q.dev/phg/routeros-scripts-custom/about/doc/dns-to-ipv6-subnet-resolver.md
# -------------------------------------------------------------------------------
:local ExitOK false;
onerror Err {
:global GlobalConfigReady; :global GlobalFunctionsReady; :global GlobalFunctionsCustomPhgReady;
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true || $GlobalFunctionsCustomPhgReady != true) \
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
:local ScriptName [ :jobname ];
:global LogPrint;
:global ParseKeyValueStore;
:global ScriptLock;
:global SafeResolve;
:global PhgDomainToIpv6Subnet;
:global PhgIpv6AddressList;
:global PhgIpv6AddressListCommentPrefix;
:if ([ $ScriptLock $ScriptName ] = false) do={
:set ExitOK true;
:error false;
}
:if ([:typeof $PhgDomainToIpv6Subnet ] != "array" || ([:len $PhgDomainToIpv6Subnet ] = 0)) do={
$LogPrint error $ScriptName ("Variable 'PhgDomainToIpv6Subnet' is not set or not of type 'array'. Please set it to an array of domain/subnet-length/comment tuples.");
:error true;
}
:if ([:typeof $PhgIpv6AddressList ] != "str" || $PhgIpv6AddressList = "") do={
$LogPrint error $ScriptName ("Variable 'PhgIpv6AddressList' is not set or not of type 'string'. Please set it to the name of the IPv6 address list to use.");
:error true;
}
# Log "run of script"
$LogPrint info $ScriptName ("running");
:local index 0;
:foreach i in=$PhgDomainToIpv6Subnet do={
onerror SubnetErr {
:local configDomain ("$($i->0)");
:local configSubnetLength ("$($i->1)");
:local configComment "";
if ([:typeof $PhgIpv6AddressListCommentPrefix ] != "str" || $PhgIpv6AddressListCommentPrefix = "") do={
:set configComment ("$($i->2)");
} else={
:set configComment ("$PhgIpv6AddressListCommentPrefix" . " " . "$($i->2)");
}
:local dnsIp "";
$LogPrint info $ScriptName ("Start configuring domain: $configDomain");
/ipv6/firewall/address-list/remove [/ipv6/firewall/address-list/find list="$PhgIpv6AddressList" comment="$configComment"];
:set dnsIp [$SafeResolve $configDomain ipv6];
:if ($dnsIp != false) do={
/ipv6/firewall/address-list/add list="$PhgIpv6AddressList" address="$dnsIp/$configSubnetLength" comment="$configComment";
:local addedSubnet [:pick [/ipv6/firewall/address-list/get [/ipv6/firewall/address-list/find list="$PhgIpv6AddressList" comment="$configComment"]] 1];
$LogPrint info $ScriptName ("domain: $configDomain - Set to: $addedSubnet");
}
$LogPrint info $ScriptName ("Finished configuring domain: $configDomain");
} do={
#TODO Send error via Notification system
$LogPrint error $ScriptName ("Error processing entry index $index: $i - $SubnetErr");
}
};
:set index;
$LogPrint info $ScriptName ("finished");
} do={
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
}

View file

@ -0,0 +1,94 @@
# DNS to IPv6 subnet resolver
[⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base
> installation. See [main README](../README.md) for details.
## Table of Contents
- [DNS to IPv6 subnet resolver](#dns-to-ipv6-subnet-resolver)
- [Table of Contents](#table-of-contents)
- [Description](#description)
- [Requirements and installation](#requirements-and-installation)
- [Configuration](#configuration)
- [`PhgIpv6AddressList`](#phgipv6addresslist)
- [`PhgDomainToIpv6Subnet`](#phgdomaintoipv6subnet)
- [`PhgIpv6AddressListCommentPrefix`](#phgipv6addresslistcommentprefix)
- [Usage and invocation](#usage-and-invocation)
## Description
This script resolved IPv6 addresses from a domain and calculates the Subnet from the configured subnet length.
## Requirements and installation
Just install the script:
```rsc
$ScriptInstallUpdate dns-to-ipv6-subnet-resolver "base-url=https://git.s1q.dev/phg/routeros-scripts-custom/raw/branch/main/";
/system/script/set [find name="dns-to-ipv6-subnet-resolver"] policy=read,write,test
```
## Configuration
Edit `global-config-overlay` and Add the following variables.
| Variable name | Required | Data type | Example | Description |
| :-------------------------------- | :------- | :-------- | :---------------------------------- | :--------------------------------------------------------------------------- |
| `PhgIpv6AddressList` | true | String | `resolved_ipv6_subnets` | IPv6 address list (address list which will contain the resolved subnets) |
| `PhgDomainToIpv6Subnet` | true | tuple | `{"example.com";64;"example.com"};` | Object containing a domain, a prefix length and a comment for the List entry |
| `PhgIpv6AddressListCommentPrefix` | false | String | `Resolved subnet for` | If set, prefixes the comment for the address list |
### `PhgIpv6AddressList`
Example:
```rsc
:global PhgIpv6AddressList "resolved_ipv6_subnets";
```
### `PhgDomainToIpv6Subnet`
Example:
```rsc
:global PhgDomainToIpv6Subnet {
{"example.com";64;"example.com"};
{"example.net";56;"example.net - Home IP of John Doe"};
};
```
`PhgDomainToIpv6Subnet` tuple variables:
| Object variable | Data type | Example | Description |
| :-------------- | :-------- | :-------------- | :------------------------------------------------------------------------------------ |
| Domain | String | `"example.com"` | The domain which the IPv6 address should be resolved |
| Prefix length | Integer | `64` | The prefix length for the resolved IPv6 address. Used to calculate the subnet address |
| Comment | String | `"example.com"` | Comment for the list entry |
### `PhgIpv6AddressListCommentPrefix`
Example:
```rsc
:global PhgIpv6AddressListCommentPrefix "Resolved subnet for";
```
## Usage and invocation
How to run the script manually:
```rsc
/system/script/run dns-to-ipv6-subnet-resolver;
```
Setup a Scheduler to run the script regularly:
```rsc
/system/scheduler/add name="dns-to-ipv6-subnet-resolver" interval="00:05:00" policy="read,write,test" on-event="/system/script/run dns-to-ipv6-subnet-resolver;";
```
---
[⬅️ Go back to main README](../README.md)
[⬆️ Go back to top](#top)

48
doc/template.md Normal file
View file

@ -0,0 +1,48 @@
# Script name
[⬅️ Go back to main README](../README.md)
> **Info**: This script can not be used on its own but requires the base
> installation. See [main README](../README.md) for details.
## Table of Contents
- [Script name](#script-name)
- [Table of Contents](#table-of-contents)
- [Description](#description)
- [Requirements and installation](#requirements-and-installation)
- [Configuration](#configuration)
- [Usage and invocation](#usage-and-invocation)
- [See also](#see-also)
## Description
Function description of the script and which goal it should achieve.
## Requirements and installation
Just install the script:
```rsc
$ScriptInstallUpdate script-file-name-without-filename-extension "base-url=https://git.s1q.dev/phg/routeros-scripts-custom/raw/branch/main/";
```
## Configuration
What to configure to run the script
## Usage and invocation
How to run the script:
```rsc
/system/script/run script-file-name-without-filename-extension;
```
## See also
* ...
---
[⬅️ Go back to main README](../README.md)
[⬆️ Go back to top](#top)

View file

@ -19,7 +19,7 @@
# Function: safelyResolve
# - Takes a DNS string (e.g. "example.com")
# - Takes an IP type [ipv4, ipv6]
# - Returns a string of and IP address or false if it can't be resolved
# - Returns a string of an IP address or false if it can't be resolved
:set SafeResolve do={
:do {
:local DomainName [ :tostr $1 ];

View file

@ -8,26 +8,26 @@
# <short script description>
# https://git.s1q.dev/phg/routeros-scripts-custom/about/doc/<script-filename>.md
:global GlobalFunctionsReady;
:while ($GlobalFunctionsReady != true) do={ :delay 500ms; }
:local ExitOK false;
:do {
onerror Err {
:global GlobalConfigReady; :global GlobalFunctionsReady;
:retry { :if ($GlobalConfigReady != true || $GlobalFunctionsReady != true) \
do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
:local ScriptName [ :jobname ];
:global LogPrint;
:global ParseKeyValueStore;
:global ScriptLock;
:global ScriptFromTerminal;
:global SendNotification2;
# Local/global script specific variables
:if ([ $ScriptLock $ScriptName ] = false) do={
:set ExitOK true;
:error false;
# Log notifications locally, or send them via email/pushover etc. when not run from terminal
# Usually used for important notifications only
:if ([ $ScriptFromTerminal $ScriptName ] = true) do={
# Add Script from here for running from terminal:
$LogPrint info $ScriptName ("Hello world!");
} else={
# Add Script from here for running as scheduled script:
$SendNotification2 ({ origin=$ScriptName; subject="Hello..."; message="... world!" });
}
# Add Script from here:
} on-error={
:global ExitError; $ExitError $ExitOK [ :jobname ];
}
} do={
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
}