Mercurial > prosody-modules
comparison mod_dnsupdate/mod_dnsupdate.lua @ 6413:0703ef9f8db8
mod_dnsupdate: Support multiple hosts/components
| author | Kim Alvefur <zash@zash.se> |
|---|---|
| date | Mon, 23 Feb 2026 16:22:33 +0100 |
| parents | 3ae0d518b739 |
| children |
comparison
equal
deleted
inserted
replaced
| 6412:c25b98d42ed0 | 6413:0703ef9f8db8 |
|---|---|
| 31 local opts = argparse.parse(arg, { | 31 local opts = argparse.parse(arg, { |
| 32 short_params = { d = "domain"; p = "primary"; t = "target"; l = "ttl"; h = "help"; ["?"] = "help" }; | 32 short_params = { d = "domain"; p = "primary"; t = "target"; l = "ttl"; h = "help"; ["?"] = "help" }; |
| 33 value_params = { domain = true; primary = true; target = true; ttl = true }; | 33 value_params = { domain = true; primary = true; target = true; ttl = true }; |
| 34 }); | 34 }); |
| 35 | 35 |
| 36 if not arg[1] or arg[2] or not opts or opts.help or not opts.domain then | 36 if not arg[1] or not opts or opts.help or not opts.domain then |
| 37 local out = opts.help and io.stdout or io.stderr; | 37 local out = opts.help and io.stdout or io.stderr; |
| 38 out:write("prosodyctl mod_dnsupdate [options] virtualhost\n"); | 38 out:write("prosodyctl mod_dnsupdate [options] virtualhost\n"); |
| 39 out:write("\t-d --domain\tbase domain name *required*\n"); | 39 out:write("\t-d --domain\tbase domain name *required*\n"); |
| 40 out:write("\t-p --primary\tprimary DNS name server\n"); | 40 out:write("\t-p --primary\tprimary DNS name server\n"); |
| 41 out:write("\t-t --target\ttarget hostname for SRV\n"); | 41 out:write("\t-t --target\ttarget hostname for SRV\n"); |
| 42 out:write("\t-l --ttl\tTTL to use\n"); | 42 out:write("\t-l --ttl\tTTL to use\n"); |
| 43 out:write("\t--each\tremove and replace individual SRV records\n"); | 43 out:write("\t--each\tremove and replace individual SRV records\n"); |
| 44 out:write("\t--reset\tremove and replace all SRV records\n"); | 44 out:write("\t--reset\tremove and replace all SRV records\n"); |
| 45 out:write("\t--remove\tremove all SRV records\n"); | 45 out:write("\t--remove\tremove all SRV records\n"); |
| 46 return opts and opts.help and 0 or 1; | 46 return opts and opts.help and 0 or 1; |
| 47 end | |
| 48 | |
| 49 local vhost = nameprep(arg[1]); -- TODO loop over arg[]? | |
| 50 if not vhost then | |
| 51 module:log("error", "Host %q fails normalization", arg[1]); | |
| 52 return 1; | |
| 53 end | |
| 54 local ihost = idna_to_ascii(vhost); | |
| 55 if not ihost then | |
| 56 module:log("error", "Host %q fails IDNA", vhost); | |
| 57 return 1; | |
| 58 end | |
| 59 if not config.get(vhost, "component_module") and not config.get(vhost, "defined") then | |
| 60 module:log("error", "Host %q is not defined in the config", vhost); | |
| 61 return 1; | |
| 62 end | 47 end |
| 63 | 48 |
| 64 local domain = validate_dnsname_option(opts, "domain"); | 49 local domain = validate_dnsname_option(opts, "domain"); |
| 65 if not domain then | 50 if not domain then |
| 66 module:log("error", "--domain is required"); | 51 module:log("error", "--domain is required"); |
| 70 or async.wait_for(dns:lookup_promise(domain, "SOA"):next(function(ret) return ret[1].soa.mname; end)); | 55 or async.wait_for(dns:lookup_promise(domain, "SOA"):next(function(ret) return ret[1].soa.mname; end)); |
| 71 if not primary then | 56 if not primary then |
| 72 module:log("error", "Could not discover primary name server, specify it with --primary"); | 57 module:log("error", "Could not discover primary name server, specify it with --primary"); |
| 73 return 1; | 58 return 1; |
| 74 end | 59 end |
| 75 local target = validate_dnsname_option(opts, "target", module:context(vhost):get_option_string("xmpp_host", ihost)); | |
| 76 -- TODO validate that target has A/AAAA | |
| 77 | |
| 78 local configured_ports = { | |
| 79 ["xmpp-client"] = module:get_option_array("c2s_ports", { 5222 }); | |
| 80 ["xmpp-server"] = module:get_option_array("s2s_ports", { 5269 }); | |
| 81 ["xmpps-client"] = module:get_option_array("c2s_direct_tls_ports", {}); | |
| 82 ["xmpps-server"] = module:get_option_array("s2s_direct_tls_ports", {}); | |
| 83 }; | |
| 84 | |
| 85 local modules_enabled = modulemanager.get_modules_for_host(vhost); | |
| 86 if not modules_enabled:contains("c2s") then | |
| 87 configured_ports["xmpp-client"] = {}; | |
| 88 configured_ports["xmpps-client"] = {}; | |
| 89 end | |
| 90 if not modules_enabled:contains("s2s") then | |
| 91 configured_ports["xmpp-server"] = {}; | |
| 92 configured_ports["xmpps-server"] = {}; | |
| 93 end | |
| 94 | |
| 95 if modules_enabled:contains("net_multiplex") then | |
| 96 for opt, ports in pairs(configured_ports) do | |
| 97 ports:append(module:get_option_array(opt:sub(1, 5) == "xmpps" and "ssl_ports" or "ports", {})); | |
| 98 end | |
| 99 end | |
| 100 | |
| 101 local existing_srv = {}; | |
| 102 for _, service in ipairs(services) do | |
| 103 existing_srv[service] = dns:lookup_promise(("_%s._tcp.%s"):format(service, ihost), "SRV"); | |
| 104 end | |
| 105 | 60 |
| 106 print("zone", domain); | 61 print("zone", domain); |
| 107 print("server", primary); | 62 print("server", primary); |
| 108 print("ttl " .. tostring(opts.ttl or 60 * 60)); | 63 print("ttl " .. tostring(opts.ttl or 60 * 60)); |
| 109 | 64 |
| 110 for _, service in ipairs(services) do | 65 for _, vhost in ipairs(arg) do |
| 111 local config_ports = set.new(configured_ports[service]); | 66 if not vhost then |
| 112 local dns_ports = set.new(); | 67 module:log("error", "Host %q fails normalization", arg[1]); |
| 68 return 1; | |
| 69 end | |
| 70 local ihost = idna_to_ascii(vhost); | |
| 71 if not ihost then | |
| 72 module:log("error", "Host %q fails IDNA", vhost); | |
| 73 return 1; | |
| 74 end | |
| 75 if not config.get(vhost, "component_module") and not config.get(vhost, "defined") then | |
| 76 module:log("error", "Host %q is not defined in the config", vhost); | |
| 77 return 1; | |
| 78 end | |
| 113 | 79 |
| 114 if (opts.reset or opts.remove) and not opts.each then | 80 local target = validate_dnsname_option(opts, "target", module:context(vhost):get_option_string("xmpp_host", ihost)); |
| 115 print(("del _%s._tcp.%s IN SRV"):format(service, ihost)); | 81 -- TODO validate that target has A/AAAA |
| 116 else | 82 |
| 117 local records = (async.wait_for(existing_srv[service])); | 83 local configured_ports = { |
| 118 for _, rr in ipairs(records) do | 84 ["xmpp-client"] = module:get_option_array("c2s_ports", { 5222 }); |
| 119 if target == nameprep(rr.srv.target):gsub("%.$", "") then | 85 ["xmpp-server"] = module:get_option_array("s2s_ports", { 5269 }); |
| 120 dns_ports:add(rr.srv.port) | 86 ["xmpps-client"] = module:get_option_array("c2s_direct_tls_ports", {}); |
| 121 elseif opts.each then | 87 ["xmpps-server"] = module:get_option_array("s2s_direct_tls_ports", {}); |
| 122 print(("del _%s._tcp.%s IN SRV %s"):format(service, ihost, rr)); | 88 }; |
| 123 end | 89 |
| 90 local modules_enabled = modulemanager.get_modules_for_host(vhost); | |
| 91 if not modules_enabled:contains("c2s") then | |
| 92 configured_ports["xmpp-client"] = {}; | |
| 93 configured_ports["xmpps-client"] = {}; | |
| 94 end | |
| 95 if not modules_enabled:contains("s2s") then | |
| 96 configured_ports["xmpp-server"] = {}; | |
| 97 configured_ports["xmpps-server"] = {}; | |
| 98 end | |
| 99 | |
| 100 if modules_enabled:contains("net_multiplex") then | |
| 101 for opt, ports in pairs(configured_ports) do | |
| 102 ports:append(module:get_option_array(opt:sub(1, 5) == "xmpps" and "ssl_ports" or "ports", {})); | |
| 124 end | 103 end |
| 125 end | 104 end |
| 126 | 105 |
| 127 if not opts.remove then | 106 local existing_srv = {}; |
| 128 if config_ports:empty() then | 107 for _, service in ipairs(services) do |
| 129 print(("add _%s._tcp.%s IN SRV 0 0 0 ."):format(service, ihost)); | 108 existing_srv[service] = dns:lookup_promise(("_%s._tcp.%s"):format(service, ihost), "SRV"); |
| 109 end | |
| 110 | |
| 111 for _, service in ipairs(services) do | |
| 112 local config_ports = set.new(configured_ports[service]); | |
| 113 local dns_ports = set.new(); | |
| 114 | |
| 115 if (opts.reset or opts.remove) and not opts.each then | |
| 116 print(("del _%s._tcp.%s IN SRV"):format(service, ihost)); | |
| 130 else | 117 else |
| 131 for port in (config_ports - dns_ports) do | 118 local records = (async.wait_for(existing_srv[service])); |
| 132 print(("add _%s._tcp.%s IN SRV 1 1 %d %s"):format(service, ihost, port, target)); | 119 for _, rr in ipairs(records) do |
| 120 if target == nameprep(rr.srv.target):gsub("%.$", "") then | |
| 121 dns_ports:add(rr.srv.port) | |
| 122 elseif opts.each then | |
| 123 print(("del _%s._tcp.%s IN SRV %s"):format(service, ihost, rr)); | |
| 124 end | |
| 125 end | |
| 126 end | |
| 127 | |
| 128 if not opts.remove then | |
| 129 if config_ports:empty() then | |
| 130 print(("add _%s._tcp.%s IN SRV 0 0 0 ."):format(service, ihost)); | |
| 131 else | |
| 132 for port in (config_ports - dns_ports) do | |
| 133 print(("add _%s._tcp.%s IN SRV 1 1 %d %s"):format(service, ihost, port, target)); | |
| 134 end | |
| 133 end | 135 end |
| 134 end | 136 end |
| 135 end | 137 end |
| 136 end | 138 end |
| 137 | 139 |
