Skip to content

MIKROTIK: new provider for Mikrotik RouterOS' DNS server#4083

Merged
tlimoncelli merged 15 commits intoStackExchange:mainfrom
hedger:hedger/routeros
Feb 20, 2026
Merged

MIKROTIK: new provider for Mikrotik RouterOS' DNS server#4083
tlimoncelli merged 15 commits intoStackExchange:mainfrom
hedger:hedger/routeros

Conversation

@hedger
Copy link
Copy Markdown
Collaborator

@hedger hedger commented Feb 16, 2026

Summary

This PR introduces a new DNS provider for MikroTik RouterOS devices, managing DNS static entries and forwarders via the RouterOS REST API. Requires RouterOS 7.x.

I absolutely loved dnscontrol's features and the ease of management for domains it provides. However, part of my personal DNS-related infrastructure is powered by Mikrotik devices, and in order to unify configuration management I drafted this implementation. Hope others will find it an useful addition (#4013 (comment))

Changes

For the new MIKROTIK provider:

  • Supported record types: A, AAAA, CNAME, MX, NS, SRV, TXT

  • Custom record types:

    • MIKROTIK_FWD: conditional DNS forwarding with address list population
    • MIKROTIK_NXDOMAIN: respond with NXDOMAIN for matching queries
    • MIKROTIK_FORWARDER: manage /ip/dns/forwarders entries via a synthetic _forwarders.mikrotik zone
  • ROS-specific record metadata (match_subdomain, regexp, address_list, comment) exposed as dnscontrol metadata and round-tripped through the API

  • Zone detection: RouterOS has no native zone concept; zones are inferred from record names using configurable zonehints (longest match), publicsuffix, or last-two-labels fallback

  • get-zones enhancements:

    • Auto-emits {no_ns: "true"} when a provider returns no nameservers (useful for any provider without NS records, not just MikroTik)
    • Serializes MikroTik-specific metadata and custom record types into the generated DSL

Configuration

{
  "home_gateway": {
    "TYPE": "MIKROTIK",
    "host": "http://192.168.88.1:80",
    "username": "admin",
    "password": "passw0rd",
    "zonehints": "home.example.com"
  }
}

Usage Example

var DSP_MIKROTIK = NewDnsProvider("home_gateway");
var REG_NONE = NewRegistrar("none");

D("_forwarders.mikrotik", REG_NONE
	, {no_ns: "true"}
	, DnsProvider(DSP_MIKROTIK)
	, MIKROTIK_FORWARDER("site2site-fwd", "192.168.13.1")
	, MIKROTIK_FORWARDER("doh-upstream", "1.1.1.1", {doh_servers: "https://cloudflare-dns.com/dns-query", verify_doh_cert: "true"}),
)

D("home.example.com", REG_NONE
	, {no_ns: "true"}
	, DnsProvider(DSP_MIKROTIK)
	, DefaultTTL(900)
	, A("mikrotik", "192.168.10.1", TTL(86400))
	, A("srv", "192.168.10.2", TTL(86400))
	, A("pve", "192.168.10.5", TTL(86400))
	, A("galaxy-a20", "192.168.10.193", {comment: "dhcp0_lan-3C:20:F6:11:11:11"})
	, CNAME("proxmox", "srv.home.example.com.", TTL(86400))
	, CNAME("admin", "srv.home.example.com.", TTL(86400))
	, MIKROTIK_FWD("remote", "site2site-fwd", {match_subdomain: "true"}, TTL(86400))
)

D("nextdns.io", REG_NONE
	, {no_ns: "true"}
	, DnsProvider(DSP_MIKROTIK)
	, DefaultTTL(86400)
	, A("dns", "45.90.28.0")
	, A("dns", "45.90.30.0")
	, AAAA("dns", "2a07:a8c0::")
	, AAAA("dns", "2a07:a8c1::")
)

D("twimg.com", REG_NONE
	, {no_ns: "true"}
	, DnsProvider(DSP_MIKROTIK)
	, DefaultTTL(86400)
	// Needed for dynamic routing with address lists based on queries to the resolver
	, MIKROTIK_FWD("@", "8.8.8.8", {match_subdomain: "true", address_list: "dst-to-vpn-list"})

D("example.com", REG_NONE
	, {no_ns: "true"}
	, DnsProvider(DSP_MIKROTIK)
	, MIKROTIK_FWD("@", "doh-upstream", {match_subdomain: "true"})
)

Potential improvements

  • Implement access using api service with proprietary protocol on port 8728/8729 (with TLS), instead of REST API relying on the www service

Tests

Integration tests verified against a physical RouterOS 7.21.3 device, hap ax3
PASS
ok      github.com/StackExchange/dnscontrol/v4/integrationTest  39.183s
=== RUN   TestDNSProviders/example.com/103:final:final
    helpers_integration_test.go:196: 
        + CREATE final.example.com TXT "TestDNSProviders was successful!" ttl=300
--- PASS: TestDNSProviders (38.64s)
    --- PASS: TestDNSProviders/example.com (38.64s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty (4.13s)
        --- PASS: TestDNSProviders/example.com/00:A:Create_A (0.06s)
        --- PASS: TestDNSProviders/example.com/00:A:Change_A_target (0.07s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#01 (0.03s)
        --- PASS: TestDNSProviders/example.com/01:Apex:Create_A (0.05s)
        --- PASS: TestDNSProviders/example.com/01:Apex:Change_A_target (0.16s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#02 (0.03s)
        --- PASS: TestDNSProviders/example.com/02:Protocol-Wildcard:Create_wildcard (0.09s)
        --- PASS: TestDNSProviders/example.com/02:Protocol-Wildcard:Delete_wildcard (0.05s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#03 (0.03s)
        --- PASS: TestDNSProviders/example.com/03:AAAA:Create_AAAA (0.06s)
        --- PASS: TestDNSProviders/example.com/03:AAAA:Change_AAAA_target (0.08s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#04 (0.03s)
        --- PASS: TestDNSProviders/example.com/04:CNAME:Create_a_CNAME (0.07s)
        --- PASS: TestDNSProviders/example.com/04:CNAME:Change_CNAME_target (0.06s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#05 (0.03s)
        --- PASS: TestDNSProviders/example.com/05:CNAME-short:Create_a_CNAME (0.08s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#06 (0.06s)
        --- PASS: TestDNSProviders/example.com/06:MX:Create_MX_apex (0.07s)
        --- PASS: TestDNSProviders/example.com/06:MX:Change_MX_apex (0.07s)
        --- PASS: TestDNSProviders/example.com/06:MX:Create_MX (0.09s)
        --- PASS: TestDNSProviders/example.com/06:MX:Change_MX_target (0.15s)
        --- PASS: TestDNSProviders/example.com/06:MX:Change_MX_p (0.06s)
        --- PASS: TestDNSProviders/example.com/07:RP_***SKIPPED(CanUseRP_not_supported)***:Empty (0.04s)
        --- PASS: TestDNSProviders/example.com/08:RP_***SKIPPED(CanUseRP_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#07 (0.01s)
        --- PASS: TestDNSProviders/example.com/09:TXT:Create_TXT (0.05s)
        --- PASS: TestDNSProviders/example.com/09:TXT:Change_TXT_target (0.06s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#08 (0.03s)
        --- PASS: TestDNSProviders/example.com/10:ManyAtOnce:CreateManyAtLabel (0.17s)
        --- PASS: TestDNSProviders/example.com/10:ManyAtOnce:Empty (0.07s)
        --- PASS: TestDNSProviders/example.com/10:ManyAtOnce:Create_an_A_record (0.05s)
        --- PASS: TestDNSProviders/example.com/10:ManyAtOnce:Add_at_label1 (0.07s)
        --- PASS: TestDNSProviders/example.com/10:ManyAtOnce:Add_at_label2 (0.07s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#09 (0.06s)
        --- PASS: TestDNSProviders/example.com/11:manyTypesAtOnce:CreateManyTypesAtLabel (0.13s)
        --- PASS: TestDNSProviders/example.com/11:manyTypesAtOnce:Empty (0.15s)
        --- PASS: TestDNSProviders/example.com/11:manyTypesAtOnce:Create_an_A_record (0.05s)
        --- PASS: TestDNSProviders/example.com/11:manyTypesAtOnce:Add_Type_At_Label (0.06s)
        --- PASS: TestDNSProviders/example.com/11:manyTypesAtOnce:Add_Type_At_Label#01 (0.10s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#10 (0.07s)
        --- PASS: TestDNSProviders/example.com/12:Attl:Create_Arc (0.05s)
        --- PASS: TestDNSProviders/example.com/12:Attl:Change_TTL (0.09s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#11 (0.07s)
        --- PASS: TestDNSProviders/example.com/13:TTL:Start (0.15s)
        --- PASS: TestDNSProviders/example.com/13:TTL:Change_a_ttl (0.17s)
        --- PASS: TestDNSProviders/example.com/13:TTL:Change_single_target_from_set (0.07s)
        --- PASS: TestDNSProviders/example.com/13:TTL:Change_all_ttls (0.21s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#12 (0.09s)
        --- PASS: TestDNSProviders/example.com/14:add_to_label_and_change_orig_ttl:Setup (0.06s)
        --- PASS: TestDNSProviders/example.com/14:add_to_label_and_change_orig_ttl:Add_at_same_label,_new_ttl (0.09s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#13 (0.11s)
        --- PASS: TestDNSProviders/example.com/15:TypeChange:Create_A (0.08s)
        --- PASS: TestDNSProviders/example.com/15:TypeChange:Change_to_MX (0.08s)
        --- PASS: TestDNSProviders/example.com/15:TypeChange:Change_back_to_A (0.10s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#14 (0.03s)
        --- PASS: TestDNSProviders/example.com/16:TypeChangeHard:Create_a_CNAME (0.06s)
        --- PASS: TestDNSProviders/example.com/16:TypeChangeHard:Change_to_A_record (0.07s)
        --- PASS: TestDNSProviders/example.com/16:TypeChangeHard:Change_back_to_CNAME (0.20s)
        --- PASS: TestDNSProviders/example.com/17:HTTPS_***SKIPPED(CanUseHTTPS_not_supported)***:Empty (0.05s)
        --- PASS: TestDNSProviders/example.com/18:Ech_***SKIPPED(CanUseHTTPS_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/19:SVCB_***SKIPPED(CanUseSVCB_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#15 (0.01s)
        --- PASS: TestDNSProviders/example.com/20:CNAME:Record_pointing_to_@ (0.56s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#16 (0.05s)
        --- PASS: TestDNSProviders/example.com/21:ApexMX:Record_pointing_to_@ (0.12s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#17 (0.05s)
        --- SKIP: TestDNSProviders/example.com/22:NullMX:create (0.00s)
        --- PASS: TestDNSProviders/example.com/22:NullMX:unnull (0.26s)
        --- SKIP: TestDNSProviders/example.com/22:NullMX:renull (0.00s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#18 (0.11s)
        --- SKIP: TestDNSProviders/example.com/23:NullMXApex:create (0.00s)
        --- PASS: TestDNSProviders/example.com/23:NullMXApex:unnull (0.21s)
        --- SKIP: TestDNSProviders/example.com/23:NullMXApex:renull (0.00s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#19 (0.10s)
        --- PASS: TestDNSProviders/example.com/24:NS:NS_for_subdomain (0.07s)
        --- PASS: TestDNSProviders/example.com/24:NS:Dual_NS_for_subdomain (0.11s)
        --- PASS: TestDNSProviders/example.com/24:NS:NS_Record_pointing_to_@ (0.13s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#20 (0.07s)
        --- PASS: TestDNSProviders/example.com/25:NS_only_APEX:Single_NS_at_apex (0.06s)
        --- PASS: TestDNSProviders/example.com/25:NS_only_APEX:Dual_NS_at_apex (0.21s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#21 (0.06s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:a_0-byte_TXT (0.12s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:a_254-byte_TXT (0.09s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:a_255-byte_TXT (0.11s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:a_256-byte_TXT (0.09s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:a_509-byte_TXT (0.20s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:a_510-byte_TXT (0.11s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:a_511-byte_TXT (0.08s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:a_764-byte_TXT (0.19s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:a_765-byte_TXT (0.10s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:a_766-byte_TXT (0.10s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:TXT_with_1_single-quote (0.09s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:TXT_with_1_backtick (0.09s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:TXT_with_1_dq-1interior (0.09s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:TXT_with_2_dq-2interior (0.07s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:TXT_with_1_dq-left (0.06s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:TXT_with_1_dq-right (0.06s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:TXT_with_semicolon (0.07s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:TXT_with_semicolon_ws (0.09s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:TXT_interior_ws (0.17s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:TXT_trailing_ws (0.08s)
        --- PASS: TestDNSProviders/example.com/26:complex_TXT:Create_a_TXT/SPF (0.11s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#22 (0.03s)
        --- PASS: TestDNSProviders/example.com/27:TXT_backslashes:TXT_with_backslashs (0.19s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#23 (0.11s)
        --- PASS: TestDNSProviders/example.com/28:Case_Sensitivity:Create_CAPS (0.08s)
        --- PASS: TestDNSProviders/example.com/28:Case_Sensitivity:Downcase_label (0.29s)
        --- PASS: TestDNSProviders/example.com/28:Case_Sensitivity:Downcase_target (0.16s)
        --- PASS: TestDNSProviders/example.com/28:Case_Sensitivity:Upcase_both (0.07s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#24 (0.05s)
        --- PASS: TestDNSProviders/example.com/29:testByLabel:initial (0.11s)
        --- PASS: TestDNSProviders/example.com/29:testByLabel:changeOne (0.07s)
        --- PASS: TestDNSProviders/example.com/29:testByLabel:deleteOne (0.16s)
        --- PASS: TestDNSProviders/example.com/29:testByLabel:addOne (0.11s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#25 (0.05s)
        --- PASS: TestDNSProviders/example.com/30:testByRecordSet:initial (0.22s)
        --- PASS: TestDNSProviders/example.com/30:testByRecordSet:changeOne (0.20s)
        --- PASS: TestDNSProviders/example.com/30:testByRecordSet:deleteOne (0.09s)
        --- PASS: TestDNSProviders/example.com/30:testByRecordSet:addOne (0.08s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#26 (0.14s)
        --- PASS: TestDNSProviders/example.com/31:IDNA:Internationalized_name (0.06s)
        --- PASS: TestDNSProviders/example.com/31:IDNA:Change_IDN (0.06s)
        --- PASS: TestDNSProviders/example.com/31:IDNA:Chinese_label (0.12s)
        --- PASS: TestDNSProviders/example.com/31:IDNA:Internationalized_CNAME_Target (0.07s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#27 (0.03s)
        --- PASS: TestDNSProviders/example.com/32:IDNAs_in_CNAME_targets:IDN_CNAME_AND_Target (0.07s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#28 (0.03s)
        --- PASS: TestDNSProviders/example.com/33:pager101:99_records (7.55s)
        --- PASS: TestDNSProviders/example.com/33:pager101:100_records (0.75s)
        --- PASS: TestDNSProviders/example.com/33:pager101:101_records (0.61s)
        --- PASS: TestDNSProviders/example.com/34:pager601_***SKIPPED(disabled_by_only)***:Empty (3.46s)
        --- PASS: TestDNSProviders/example.com/35:pager1201_***SKIPPED(disabled_by_only)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/36:batchRecordswithOthers_***SKIPPED(disabled_by_only)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/37:CAA_***SKIPPED(CanUseCAA_not_supported)***:Empty (0.02s)
        --- PASS: TestDNSProviders/example.com/38:LOC_***SKIPPED(CanUseLOC_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/39:NAPTR_***SKIPPED(CanUseNAPTR_not_supported)***:Empty (0.03s)
        --- PASS: TestDNSProviders/example.com/40:PTR_***SKIPPED(CanUsePTR_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/41:SOA_***SKIPPED(CanUseSOA_not_supported)***:Empty (0.02s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#29 (0.02s)
        --- PASS: TestDNSProviders/example.com/42:SRV:SRV_record (0.06s)
        --- PASS: TestDNSProviders/example.com/42:SRV:Second_SRV_record,_same_prio (0.07s)
        --- PASS: TestDNSProviders/example.com/42:SRV:3_SRV (0.10s)
        --- PASS: TestDNSProviders/example.com/42:SRV:Delete_one (0.05s)
        --- PASS: TestDNSProviders/example.com/42:SRV:Change_Target (0.14s)
        --- PASS: TestDNSProviders/example.com/42:SRV:Change_Priority (0.10s)
        --- PASS: TestDNSProviders/example.com/42:SRV:Change_Weight (0.07s)
        --- PASS: TestDNSProviders/example.com/42:SRV:Change_Port (0.26s)
        --- PASS: TestDNSProviders/example.com/42:SRV:Empty (0.42s)
        --- SKIP: TestDNSProviders/example.com/42:SRV:Null_Target (0.00s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#30 (0.02s)
        --- PASS: TestDNSProviders/example.com/43:SRV:Create_SRV333 (0.15s)
        --- PASS: TestDNSProviders/example.com/43:SRV:Change_TTL999 (0.06s)
        --- PASS: TestDNSProviders/example.com/44:SSHFP_***SKIPPED(CanUseSSHFP_not_supported)***:Empty (0.03s)
        --- PASS: TestDNSProviders/example.com/45:TLSA_***SKIPPED(CanUseTLSA_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/46:DS_***SKIPPED(CanUseDS_not_supported)***:Empty (0.02s)
        --- PASS: TestDNSProviders/example.com/47:DS_(children_only)_***SKIPPED(CanUseDSForChildren_not_supported)***:Empty (0.02s)
        --- PASS: TestDNSProviders/example.com/48:DS_(children_only)_CLOUDNS_***SKIPPED(CanUseDSForChildren_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/49:DHCID_***SKIPPED(CanUseDHCID_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/50:DNAME_***SKIPPED(CanUseDNAME_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/51:DNSKEY_***SKIPPED(CanUseDNSKEY_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/52:ALIAS_on_apex_***SKIPPED(CanUseAlias_not_supported)***:Empty (0.03s)
        --- PASS: TestDNSProviders/example.com/53:ALIAS_to_nonfqdn_***SKIPPED(CanUseAlias_not_supported)***:Empty (0.02s)
        --- PASS: TestDNSProviders/example.com/54:ALIAS_on_subdomain_***SKIPPED(CanUseAlias_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/55:AZURE_ALIAS_A_***SKIPPED(CanUseAzureAlias_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/56:AZURE_ALIAS_CNAME_***SKIPPED(CanUseAzureAlias_not_supported)***:Empty (0.02s)
        --- PASS: TestDNSProviders/example.com/57:R53_ALIAS2_***SKIPPED(CanUseRoute53Alias_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/58:R53_ALIAS_ORDER_***SKIPPED(CanUseRoute53Alias_not_supported)***:Empty (0.02s)
        --- PASS: TestDNSProviders/example.com/59:R53_ALIAS_CNAME_***SKIPPED(CanUseRoute53Alias_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/60:R53_ALIAS_Loop_***SKIPPED(CanUseRoute53Alias_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/61:R53_alias_pre-existing_***SKIPPED(CanUseRoute53Alias_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/62:R53_alias_evaluate_target_health_***SKIPPED(CanUseRoute53Alias_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/63:R53_B3493_***SKIPPED(CanUseRoute53Alias_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/64:R53_B3493_REV_***SKIPPED(CanUseRoute53Alias_not_supported)***:Empty (0.03s)
        --- PASS: TestDNSProviders/example.com/65:CF_REDIRECT_CONVERT_***SKIPPED(excluded_by_alltrue([false]))***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/66:CLOUDFLAREAPI_SINGLE_REDIRECT_***SKIPPED(excluded_by_alltrue([false]))***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/67:CF_PROXY_A_create_***SKIPPED(disabled_by_only)***:Empty (0.02s)
        --- PASS: TestDNSProviders/example.com/68:CF_PROXY_A_off_to_on_***SKIPPED(disabled_by_only)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/69:CF_PROXY_A_on_to_off_***SKIPPED(disabled_by_only)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/70:CF_PROXY_CNAME_create_***SKIPPED(disabled_by_only)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/71:CF_PROXY_CNAME_off_to_on_***SKIPPED(disabled_by_only)***:Empty (0.03s)
        --- PASS: TestDNSProviders/example.com/72:CF_PROXY_CNAME_on_to_off_***SKIPPED(disabled_by_only)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/73:CF_CNAME_FLATTEN_create_***SKIPPED(excluded_by_alltrue([false]))***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/74:CF_CNAME_FLATTEN_off_to_on_***SKIPPED(excluded_by_alltrue([false]))***:Empty (0.02s)
        --- PASS: TestDNSProviders/example.com/75:CF_CNAME_FLATTEN_on_to_off_***SKIPPED(excluded_by_alltrue([false]))***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/76:CF_COMMENT_create_***SKIPPED(disabled_by_only)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/77:CF_TAGS_create_***SKIPPED(excluded_by_alltrue([false]))***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/78:CF_WORKER_ROUTE_***SKIPPED(disabled_by_only)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/79:ADGUARDHOME_A_PASSTHROUGH_***SKIPPED(disabled_by_only)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/80:ADGUARDHOME_AAAA_PASSTHROUGH_***SKIPPED(disabled_by_only)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#31 (0.01s)
        --- PASS: TestDNSProviders/example.com/81:MIKROTIK_FWD:create_FWD_record (0.10s)
        --- PASS: TestDNSProviders/example.com/81:MIKROTIK_FWD:change_FWD_target (0.06s)
        --- PASS: TestDNSProviders/example.com/81:MIKROTIK_FWD:FWD_with_match_subdomain (0.07s)
        --- PASS: TestDNSProviders/example.com/81:MIKROTIK_FWD:FWD_with_address_list (0.06s)
        --- PASS: TestDNSProviders/example.com/81:MIKROTIK_FWD:FWD_with_comment (0.12s)
        --- PASS: TestDNSProviders/example.com/81:MIKROTIK_FWD:multiple_FWD_records (0.11s)
        --- PASS: TestDNSProviders/example.com/81:MIKROTIK_FWD:delete_one_FWD (0.05s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#32 (0.03s)
        --- PASS: TestDNSProviders/example.com/82:MIKROTIK_NXDOMAIN:create_NXDOMAIN (0.06s)
        --- PASS: TestDNSProviders/example.com/82:MIKROTIK_NXDOMAIN:multiple_NXDOMAIN (0.09s)
        --- PASS: TestDNSProviders/example.com/82:MIKROTIK_NXDOMAIN:delete_one_NXDOMAIN (0.18s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#33 (0.03s)
        --- PASS: TestDNSProviders/example.com/83:MIKROTIK_METADATA:A_record_with_comment (0.07s)
        --- PASS: TestDNSProviders/example.com/83:MIKROTIK_METADATA:change_comment (0.25s)
        --- PASS: TestDNSProviders/example.com/83:MIKROTIK_METADATA:A_with_match_subdomain (0.08s)
        --- PASS: TestDNSProviders/example.com/84:VERCEL_CAA_whitespace_-_cansignhttpexchanges_***SKIPPED(disabled_by_only)***:Empty (0.13s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#34 (0.02s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:Create_some_records (0.19s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:ignore_label (0.05s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:VERIFY_PREVIOUS (0.05s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:ignore_label,type (0.06s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:VERIFY_PREVIOUS#01 (0.05s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:ignore_label,type,target (0.06s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:VERIFY_PREVIOUS#02 (0.05s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:ignore_type (0.05s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:VERIFY_PREVIOUS#03 (0.07s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:ignore_type,target (0.05s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:VERIFY_PREVIOUS#04 (0.05s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:ignore_target (0.04s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:VERIFY_PREVIOUS#05 (0.04s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:ignore_manytypes (0.05s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:VERIFY_PREVIOUS#06 (0.15s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:ignore_label,type,target=* (0.06s)
        --- PASS: TestDNSProviders/example.com/85:IGNORE_main:VERIFY_PREVIOUS#07 (0.05s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#35 (0.13s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_apex:Create_some_records (0.27s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_apex:apex_label (0.05s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_apex:VERIFY_PREVIOUS (0.04s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_apex:apex_label,type (0.05s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_apex:VERIFY_PREVIOUS#01 (0.05s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_apex:apex_label,type,target (0.05s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_apex:VERIFY_PREVIOUS#02 (0.08s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_apex:apex_type (0.05s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_apex:VERIFY_PREVIOUS#03 (0.04s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_apex:apex_type,target (0.12s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_apex:VERIFY_PREVIOUS#04 (0.06s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_apex:apex_target (0.06s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_apex:VERIFY_PREVIOUS#05 (0.06s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_apex:apex_manytypes (0.05s)
        --- PASS: TestDNSProviders/example.com/86:IGNORE_apex:VERIFY_PREVIOUS#06 (0.05s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#36 (0.14s)
        --- PASS: TestDNSProviders/example.com/87:IGNORE_unsafe:Create_some_records (0.19s)
        --- PASS: TestDNSProviders/example.com/87:IGNORE_unsafe:ignore_unsafe_apex (0.04s)
        --- PASS: TestDNSProviders/example.com/87:IGNORE_unsafe:VERIFY_PREVIOUS (0.06s)
        --- PASS: TestDNSProviders/example.com/87:IGNORE_unsafe:ignore_unsafe_label (0.04s)
        --- PASS: TestDNSProviders/example.com/87:IGNORE_unsafe:VERIFY_PREVIOUS#01 (0.05s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#37 (0.11s)
        --- PASS: TestDNSProviders/example.com/88:IGNORE_wilds:Create_some_records (0.30s)
        --- PASS: TestDNSProviders/example.com/88:IGNORE_wilds:ignore_label=foo.* (0.05s)
        --- PASS: TestDNSProviders/example.com/88:IGNORE_wilds:VERIFY_PREVIOUS (0.06s)
        --- PASS: TestDNSProviders/example.com/88:IGNORE_wilds:ignore_label=foo.bat,type (0.05s)
        --- PASS: TestDNSProviders/example.com/88:IGNORE_wilds:VERIFY_PREVIOUS#01 (0.05s)
        --- PASS: TestDNSProviders/example.com/88:IGNORE_wilds:ignore_target=*.domain (0.05s)
        --- PASS: TestDNSProviders/example.com/88:IGNORE_wilds:VERIFY_PREVIOUS#02 (0.05s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#38 (0.16s)
        --- PASS: TestDNSProviders/example.com/89:IGNORE_with_modify:Create_some_records (0.42s)
        --- PASS: TestDNSProviders/example.com/89:IGNORE_with_modify:IGNORE_change_ByZone (0.12s)
        --- PASS: TestDNSProviders/example.com/89:IGNORE_with_modify:VERIFY_PREVIOUS (0.08s)
        --- PASS: TestDNSProviders/example.com/89:IGNORE_with_modify:IGNORE_change_ByLabel (0.10s)
        --- PASS: TestDNSProviders/example.com/89:IGNORE_with_modify:VERIFY_PREVIOUS#01 (0.11s)
        --- PASS: TestDNSProviders/example.com/89:IGNORE_with_modify:IGNORE_change_ByRecordSet (0.09s)
        --- PASS: TestDNSProviders/example.com/89:IGNORE_with_modify:VERIFY_PREVIOUS#02 (0.09s)
        --- PASS: TestDNSProviders/example.com/89:IGNORE_with_modify:IGNORE_change_ByRecord (0.11s)
        --- PASS: TestDNSProviders/example.com/89:IGNORE_with_modify:VERIFY_PREVIOUS#03 (0.07s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#39 (0.27s)
        --- PASS: TestDNSProviders/example.com/90:IGNORE_TARGET_b2285:Create_some_records (0.09s)
        --- PASS: TestDNSProviders/example.com/90:IGNORE_TARGET_b2285:Add_a_new_record_-_ignoring_test.foo.com. (0.02s)
        --- PASS: TestDNSProviders/example.com/90:IGNORE_TARGET_b2285:VERIFY_PREVIOUS (0.04s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#40 (0.09s)
        --- PASS: TestDNSProviders/example.com/91:IGNORE_everything_b2822:Create_some_records (0.18s)
        --- PASS: TestDNSProviders/example.com/91:IGNORE_everything_b2822:ignore_them_all (0.05s)
        --- PASS: TestDNSProviders/example.com/91:IGNORE_everything_b2822:VERIFY_PREVIOUS (0.07s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#41 (0.23s)
        --- PASS: TestDNSProviders/example.com/92:IGNORE_w/change_b3227:Create_some_records (0.10s)
        --- PASS: TestDNSProviders/example.com/92:IGNORE_w/change_b3227:ignore (0.05s)
        --- PASS: TestDNSProviders/example.com/92:IGNORE_w/change_b3227:VERIFY_PREVIOUS (0.04s)
        --- PASS: TestDNSProviders/example.com/92:IGNORE_w/change_b3227:Verify_nothing_changed (0.15s)
        --- PASS: TestDNSProviders/example.com/92:IGNORE_w/change_b3227:VERIFY_PREVIOUS#01 (0.03s)
        --- PASS: TestDNSProviders/example.com/92:IGNORE_w/change_b3227:ignore_with_change (0.07s)
        --- PASS: TestDNSProviders/example.com/92:IGNORE_w/change_b3227:VERIFY_PREVIOUS#02 (0.03s)
        --- PASS: TestDNSProviders/example.com/93:structured_TXT_***SKIPPED(disabled_by_only)***:Empty (0.08s)
        --- PASS: TestDNSProviders/example.com/94:structured_TXT_as_native_records_***SKIPPED(disabled_by_only)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/95:CLOUDNS_geodns_tests_***SKIPPED(disabled_by_only)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/96:PORKBUN_URLFWD_tests_***SKIPPED(disabled_by_only)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/97:GCORE_metadata_tests_***SKIPPED(disabled_by_only)***:Empty (0.05s)
        --- PASS: TestDNSProviders/example.com/98:NAMECHEAP_url_redirect_records_***SKIPPED(disabled_by_only)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/99:OPENPGPKEY_***SKIPPED(CanUseOPENPGPKEY_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/100:SMIMEA_***SKIPPED(CanUseSMIMEA_not_supported)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/101:Bunny_DNS_Pull_Zone_***SKIPPED(disabled_by_only)***:Empty (0.01s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#42 (0.01s)
        --- PASS: TestDNSProviders/example.com/102:final:final (0.05s)
        --- PASS: TestDNSProviders/example.com/Clean_Slate:Empty#43 (0.06s)
        --- PASS: TestDNSProviders/example.com/103:final:final (0.07s)
=== RUN   TestDualProviders
Testing Profile="MIKROTIK" (TYPE="MIKROTIK")
    provider_test.go:29: Skipping.  DocDualHost == Cannot
--- SKIP: TestDualProviders (0.00s)
=== RUN   TestNameserverDots
Testing Profile="MIKROTIK" (TYPE="MIKROTIK")
    provider_test.go:108: Skipping.  DocDualHost == Cannot
--- SKIP: TestNameserverDots (0.00s)
=== RUN   TestDuplicateNameservers
Testing Profile="MIKROTIK" (TYPE="MIKROTIK")
    provider_test.go:140: Skipping.  DocDualHost == Cannot
--- SKIP: TestDuplicateNameservers (0.00s)
PASS
ok      github.com/StackExchange/dnscontrol/v4/integrationTest  39.183s

@hedger
Copy link
Copy Markdown
Collaborator Author

hedger commented Feb 19, 2026

Hello @tlimoncelli! An idea that came to my mind - Mikrotik supplies an image of RouterOS that can be (comparatively) easily ran in virtualised environments (called CHR, cloud hosted router). While I haven't tried it out myself, I think I can host it somewhere and contribute the credentials for accessing it to include the MIKROTIK provider into the general CI test suite.

Anyway, I'm looking foward to hearing just any feedback on the provider implementation and its relevance to the project goals. Thank you!

@tlimoncelli
Copy link
Copy Markdown
Contributor

Hello friend!

It's been a busy week but I hope to review this soon. Looks good so far! (and I love the idea of testing against a CHR!)

Tom

@tlimoncelli
Copy link
Copy Markdown
Contributor

Thank you for contributing this new provider, @hedger !

Two notes:

  1. @fm: Faisal Misle is our “liaison to maintainers”. He'll reach out to you soon. He'll be requesting your email address so that we have a more direct way to contact you. I promise he's not a spammer!
  2. By now you should have received a Github invite to have the "triage" role for this repo. Please accept the invite so we can assign bugs to you.

Thanks again!
Tom

@tlimoncelli tlimoncelli merged commit d681623 into StackExchange:main Feb 20, 2026
2 checks passed
@fm
Copy link
Copy Markdown

fm commented Feb 23, 2026

Hi @hedger,

Apologies for the delay, I thought I had already posted here. As Tom mentioned I am the Maintainer Liaison. Would you be able to send your contact email to us? You can reach me at dnscontrol at faisal dot fm and Tom at tlimoncelli at stack over flow dot com

Your email will not be public and will only be used the the project team to send out maintainer communications.

As a maintainer, we’d like to remind you of your role and expectations we have so that everyone has a positive experience using dnscontrol:

  • Maintainers are expected to support their provider. If a maintainer is no longer able to maintain a provider, they should suggest a replacement or if no replacement is available, the maintainer shall let the maintainer liaison know so they can put out a call for volunteers.
  • Maintainers must be responsible to bug reports and PRs for their provider.
  • Maintainers should set up test accounts and periodically verify that all tests pass (pkg/js/parse_tests and integrationTest), especially when new features are added or changed in the core product.
  • Contributors are encouraged to add new tests and refine old ones. (Test-driven development is encouraged.)

Thank you!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants