Software /
code /
prosody
Comparison
util/prosodyctl/check.lua @ 12362:0fd58f54d653
Merge config-updates+check-turn from timber
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Fri, 04 Mar 2022 16:33:41 +0000 |
parent | 12320:f0be98bab9dd |
parent | 12357:cd11d7c4af8b |
child | 12372:1ba451c10f41 |
comparison
equal
deleted
inserted
replaced
12320:f0be98bab9dd | 12362:0fd58f54d653 |
---|---|
58 end | 58 end |
59 end | 59 end |
60 return false, "Probe endpoint did not return a success status"; | 60 return false, "Probe endpoint did not return a success status"; |
61 end | 61 end |
62 | 62 |
63 local function check_turn_service(turn_service) | |
64 local stun = require "net.stun"; | |
65 | |
66 -- Create UDP socket for communication with the server | |
67 local sock = assert(require "socket".udp()); | |
68 sock:setsockname("*", 0); | |
69 sock:setpeername(turn_service.host, turn_service.port); | |
70 sock:settimeout(10); | |
71 | |
72 -- Helper function to receive a packet | |
73 local function receive_packet() | |
74 local raw_packet, err = sock:receive(); | |
75 if not raw_packet then | |
76 return nil, err; | |
77 end | |
78 return stun.new_packet():deserialize(raw_packet); | |
79 end | |
80 | |
81 local result = { warnings = {} }; | |
82 | |
83 -- Send a "binding" query, i.e. a request for our external IP/port | |
84 local bind_query = stun.new_packet("binding", "request"); | |
85 bind_query:add_attribute("software", "prosodyctl check turn"); | |
86 sock:send(bind_query:serialize()); | |
87 | |
88 local bind_result, err = receive_packet(); | |
89 if not bind_result then | |
90 result.error = "No STUN response: "..err; | |
91 return result; | |
92 elseif bind_result:is_err_resp() then | |
93 result.error = ("STUN server returned error: %d (%s)"):format(bind_result:get_error()); | |
94 return result; | |
95 elseif not bind_result:is_success_resp() then | |
96 result.error = ("Unexpected STUN response: %d (%s)"):format(bind_result:get_type()); | |
97 return result; | |
98 end | |
99 | |
100 result.external_ip = bind_result:get_xor_mapped_address(); | |
101 if not result.external_ip then | |
102 result.error = "STUN server did not return an address"; | |
103 return result; | |
104 end | |
105 | |
106 -- Send a TURN "allocate" request. Expected to fail due to auth, but | |
107 -- necessary to obtain a valid realm/nonce from the server. | |
108 local pre_request = stun.new_packet("allocate", "request"); | |
109 sock:send(pre_request:serialize()); | |
110 | |
111 local pre_result, err = receive_packet(); | |
112 if not pre_result then | |
113 result.error = "No initial TURN response: "..err; | |
114 return result; | |
115 elseif pre_result:is_success_resp() then | |
116 result.error = "TURN server does not have authentication enabled"; | |
117 return result; | |
118 end | |
119 | |
120 local realm = pre_result:get_attribute("realm"); | |
121 local nonce = pre_result:get_attribute("nonce"); | |
122 | |
123 if not realm then | |
124 table.insert(result.warnings, "TURN server did not return an authentication realm"); | |
125 end | |
126 if not nonce then | |
127 table.insert(result.warnings, "TURN server did not return a nonce"); | |
128 end | |
129 | |
130 -- Use the configured secret to obtain temporary user/pass credentials | |
131 local turn_user, turn_pass = stun.get_user_pass_from_secret(turn_service.secret); | |
132 | |
133 -- Send a TURN allocate request, will fail if auth is wrong | |
134 local alloc_request = stun.new_packet("allocate", "request"); | |
135 alloc_request:add_requested_transport("udp"); | |
136 alloc_request:add_attribute("username", turn_user); | |
137 if realm then | |
138 alloc_request:add_attribute("realm", realm); | |
139 end | |
140 if nonce then | |
141 alloc_request:add_attribute("nonce", nonce); | |
142 end | |
143 local key = stun.get_long_term_auth_key(realm or turn_service.host, turn_user, turn_pass); | |
144 alloc_request:add_message_integrity(key); | |
145 sock:send(alloc_request:serialize()); | |
146 | |
147 -- Check the response | |
148 local alloc_response, err = receive_packet(); | |
149 if not alloc_response then | |
150 result.error = "TURN server did not response to allocation request: "..err; | |
151 return; | |
152 elseif alloc_response:is_err_resp() then | |
153 result.error = ("TURN allocation failed: %d (%s)"):format(alloc_response:get_error()); | |
154 return result; | |
155 elseif not alloc_response:is_success_resp() then | |
156 result.error = ("Unexpected TURN response: %d (%s)"):format(alloc_response:get_type()); | |
157 return result; | |
158 end | |
159 | |
160 -- No errors? Ok! | |
161 | |
162 return result; | |
163 end | |
164 | |
63 local function skip_bare_jid_hosts(host) | 165 local function skip_bare_jid_hosts(host) |
64 if jid_split(host) then | 166 if jid_split(host) then |
65 -- See issue #779 | 167 -- See issue #779 |
66 return false; | 168 return false; |
67 end | 169 end |
78 local set = require "util.set"; | 180 local set = require "util.set"; |
79 local it = require "util.iterators"; | 181 local it = require "util.iterators"; |
80 local ok = true; | 182 local ok = true; |
81 local function disabled_hosts(host, conf) return host ~= "*" and conf.enabled ~= false; end | 183 local function disabled_hosts(host, conf) return host ~= "*" and conf.enabled ~= false; end |
82 local function enabled_hosts() return it.filter(disabled_hosts, pairs(configmanager.getconfig())); end | 184 local function enabled_hosts() return it.filter(disabled_hosts, pairs(configmanager.getconfig())); end |
83 if not (what == nil or what == "disabled" or what == "config" or what == "dns" or what == "certs" or what == "connectivity") then | 185 if not (what == nil or what == "disabled" or what == "config" or what == "dns" or what == "certs" or what == "connectivity" or what == "turn") then |
84 show_warning("Don't know how to check '%s'. Try one of 'config', 'dns', 'certs', 'disabled' or 'connectivity'.", what); | 186 show_warning("Don't know how to check '%s'. Try one of 'config', 'dns', 'certs', 'disabled', 'turn' or 'connectivity'.", what); |
85 show_warning("Note: The connectivity check will connect to a remote server."); | 187 show_warning("Note: The connectivity check will connect to a remote server."); |
86 return 1; | 188 return 1; |
87 end | 189 end |
88 if not what or what == "disabled" then | 190 if not what or what == "disabled" then |
89 local disabled_hosts_set = set.new(); | 191 local disabled_hosts_set = set.new(); |
1002 print() | 1104 print() |
1003 end | 1105 end |
1004 print("Note: The connectivity check only checks the reachability of the domain.") | 1106 print("Note: The connectivity check only checks the reachability of the domain.") |
1005 print("Note: It does not ensure that the check actually reaches this specific prosody instance.") | 1107 print("Note: It does not ensure that the check actually reaches this specific prosody instance.") |
1006 end | 1108 end |
1109 | |
1110 if what == "turn" then | |
1111 local turn_enabled_hosts = {}; | |
1112 local turn_services = {}; | |
1113 | |
1114 for host in enabled_hosts() do | |
1115 local has_external_turn = modulemanager.get_modules_for_host(host):contains("turn_external"); | |
1116 if has_external_turn then | |
1117 table.insert(turn_enabled_hosts, host); | |
1118 local turn_host = configmanager.get(host, "turn_external_host") or host; | |
1119 local turn_port = configmanager.get(host, "turn_external_port") or 3478; | |
1120 local turn_secret = configmanager.get(host, "turn_external_secret"); | |
1121 if not turn_secret then | |
1122 print("Error: Your configuration is missing a turn_external_secret for "..host); | |
1123 print("Error: TURN will not be advertised for this host."); | |
1124 ok = false; | |
1125 else | |
1126 local turn_id = ("%s:%d"):format(turn_host, turn_port); | |
1127 if turn_services[turn_id] and turn_services[turn_id].secret ~= turn_secret then | |
1128 print("Error: Your configuration contains multiple differing secrets"); | |
1129 print(" for the TURN service at "..turn_id.." - we will only test one."); | |
1130 elseif not turn_services[turn_id] then | |
1131 turn_services[turn_id] = { | |
1132 host = turn_host; | |
1133 port = turn_port; | |
1134 secret = turn_secret; | |
1135 }; | |
1136 end | |
1137 end | |
1138 end | |
1139 end | |
1140 | |
1141 if what == "turn" then | |
1142 local count = it.count(pairs(turn_services)); | |
1143 if count == 0 then | |
1144 print("Error: Unable to find any TURN services configured. Enable mod_turn_external!"); | |
1145 else | |
1146 print("Identified "..tostring(count).." TURN services."); | |
1147 print(""); | |
1148 end | |
1149 end | |
1150 | |
1151 for turn_id, turn_service in pairs(turn_services) do | |
1152 print("Testing "..turn_id.."..."); | |
1153 | |
1154 local result = check_turn_service(turn_service); | |
1155 if #result.warnings > 0 then | |
1156 print(("%d warnings:\n\n "):format(#result.warnings)); | |
1157 print(table.concat(result.warnings, "\n ")); | |
1158 end | |
1159 if result.error then | |
1160 print("Error: "..result.error.."\n"); | |
1161 ok = false; | |
1162 else | |
1163 print("Success!\n"); | |
1164 end | |
1165 end | |
1166 end | |
1167 | |
1007 if not ok then | 1168 if not ok then |
1008 print("Problems found, see above."); | 1169 print("Problems found, see above."); |
1009 else | 1170 else |
1010 print("All checks passed, congratulations!"); | 1171 print("All checks passed, congratulations!"); |
1011 end | 1172 end |