util/prosodyctl/check.lua
changeset 12376 1ba451c10f41
parent 12366 0fd58f54d653
child 12377 5417ec7e2ee8
equal deleted inserted replaced
12375:9a8b0c5b4b14 12376:1ba451c10f41
     1 local configmanager = require "core.configmanager";
     1 local configmanager = require "core.configmanager";
     2 local show_usage = require "util.prosodyctl".show_usage;
     2 local show_usage = require "util.prosodyctl".show_usage;
     3 local show_warning = require "util.prosodyctl".show_warning;
     3 local show_warning = require "util.prosodyctl".show_warning;
     4 local is_prosody_running = require "util.prosodyctl".isrunning;
     4 local is_prosody_running = require "util.prosodyctl".isrunning;
       
     5 local parse_args = require "util.argparse".parse;
     5 local dependencies = require "util.dependencies";
     6 local dependencies = require "util.dependencies";
     6 local socket = require "socket";
     7 local socket = require "socket";
     7 local socket_url = require "socket.url";
     8 local socket_url = require "socket.url";
     8 local jid_split = require "util.jid".prepped_split;
     9 local jid_split = require "util.jid".prepped_split;
     9 local modulemanager = require "core.modulemanager";
    10 local modulemanager = require "core.modulemanager";
    58 		end
    59 		end
    59 	end
    60 	end
    60 	return false, "Probe endpoint did not return a success status";
    61 	return false, "Probe endpoint did not return a success status";
    61 end
    62 end
    62 
    63 
    63 local function check_turn_service(turn_service)
    64 local function check_turn_service(turn_service, ping_service)
    64 	local stun = require "net.stun";
    65 	local stun = require "net.stun";
    65 
    66 
    66 	-- Create UDP socket for communication with the server
    67 	-- Create UDP socket for communication with the server
    67 	local sock = assert(require "socket".udp());
    68 	local sock = assert(require "socket".udp());
    68 	sock:setsockname("*", 0);
    69 	sock:setsockname("*", 0);
   155 	elseif not alloc_response:is_success_resp() then
   156 	elseif not alloc_response:is_success_resp() then
   156 		result.error = ("Unexpected TURN response: %d (%s)"):format(alloc_response:get_type());
   157 		result.error = ("Unexpected TURN response: %d (%s)"):format(alloc_response:get_type());
   157 		return result;
   158 		return result;
   158 	end
   159 	end
   159 
   160 
   160 	-- No errors? Ok!
   161 	if not ping_service then
       
   162 		-- Success! We won't be running the relay test.
       
   163 		return result;
       
   164 	end
       
   165 
       
   166 	-- Run the relay test - i.e. send a binding request to ping_service
       
   167 	-- and receive a response.
       
   168 
       
   169 	-- Resolve the IP of the ping service
       
   170 	local ping_service_ip, err = socket.dns.toip(ping_service);
       
   171 	if not ping_service_ip then
       
   172 		result.error = "Unable to resolve external service: "..err;
       
   173 		return result;
       
   174 	end
       
   175 
       
   176 	-- Ask the TURN server to allow packets from the ping service IP
       
   177 	local perm_request = stun.new_packet("create-permission");
       
   178 	perm_request:add_xor_peer_address(ping_service_ip);
       
   179 	perm_request:add_attribute("username", turn_user);
       
   180 	perm_request:add_attribute("realm", realm);
       
   181 	perm_request:add_attribute("nonce", nonce);
       
   182 	perm_request:add_message_integrity(key);
       
   183 	sock:send(perm_request:serialize());
       
   184 
       
   185 	local perm_response, err = receive_packet();
       
   186 	if not perm_response then
       
   187 		result.error = "No response from TURN server when requesting peer permission: "..err;
       
   188 		return result;
       
   189 	elseif perm_response:is_err_resp() then
       
   190 		result.error = ("TURN permission request failed: %d (%s)"):format(perm_response:get_error());
       
   191 		return result;
       
   192 	elseif not perm_response:is_success_resp() then
       
   193 		result.error = ("Unexpected TURN response: %d (%s)"):format(perm_response:get_type());
       
   194 		return result;
       
   195 	end
       
   196 
       
   197 	-- Ask the TURN server to relay a STUN binding request to the ping server
       
   198 	local ping_data = stun.new_packet("binding"):serialize();
       
   199 
       
   200 	local ping_request = stun.new_packet("send", "indication");
       
   201 	ping_request:add_xor_peer_address(ping_service_ip, 3478);
       
   202 	ping_request:add_attribute("data", ping_data);
       
   203 	ping_request:add_attribute("username", turn_user);
       
   204 	ping_request:add_attribute("realm", realm);
       
   205 	ping_request:add_attribute("nonce", nonce);
       
   206 	ping_request:add_message_integrity(key);
       
   207 	sock:send(ping_request:serialize());
       
   208 
       
   209 	local ping_response, err = receive_packet();
       
   210 	if not ping_response then
       
   211 		result.error = "No response from ping server ("..ping_service_ip.."): "..err;
       
   212 		return result;
       
   213 	elseif not ping_response:is_indication() or select(2, ping_response:get_method()) ~= "data" then
       
   214 		result.error = ("Unexpected TURN response: %s %s"):format(select(2, ping_response:get_method()), select(2, ping_response:get_type()));
       
   215 		return result;
       
   216 	end
       
   217 
       
   218 	local pong_data = ping_response:get_attribute("data");
       
   219 	if not pong_data then
       
   220 		result.error = "No data relayed from remote server";
       
   221 		return;
       
   222 	end
       
   223 	local pong = stun.new_packet():deserialize(pong_data);
       
   224 
       
   225 	result.external_ip_pong = pong:get_xor_mapped_address();
       
   226 	if not result.external_ip_pong then
       
   227 		result.error = "Ping server did not return an address";
       
   228 		return result;
       
   229 	end
       
   230 
       
   231 	--
   161 
   232 
   162 	return result;
   233 	return result;
   163 end
   234 end
   164 
   235 
   165 local function skip_bare_jid_hosts(host)
   236 local function skip_bare_jid_hosts(host)
   168 		return false;
   239 		return false;
   169 	end
   240 	end
   170 	return true;
   241 	return true;
   171 end
   242 end
   172 
   243 
       
   244 local check_opts = {
       
   245 	short_params = {
       
   246 		h = "help", v = "verbose";
       
   247 	};
       
   248 };
       
   249 
   173 local function check(arg)
   250 local function check(arg)
   174 	if arg[1] == "--help" then
   251 	if arg[1] == "help" or arg[1] == "--help" then
   175 		show_usage([[check]], [[Perform basic checks on your Prosody installation]]);
   252 		show_usage([[check]], [[Perform basic checks on your Prosody installation]]);
   176 		return 1;
   253 		return 1;
   177 	end
   254 	end
   178 	local what = table.remove(arg, 1);
   255 	local what = table.remove(arg, 1);
       
   256 	local opts = assert(parse_args(arg, check_opts));
   179 	local array = require "util.array";
   257 	local array = require "util.array";
   180 	local set = require "util.set";
   258 	local set = require "util.set";
   181 	local it = require "util.iterators";
   259 	local it = require "util.iterators";
   182 	local ok = true;
   260 	local ok = true;
   183 	local function disabled_hosts(host, conf) return host ~= "*" and conf.enabled ~= false; end
   261 	local function disabled_hosts(host, conf) return host ~= "*" and conf.enabled ~= false; end
  1149 		end
  1227 		end
  1150 
  1228 
  1151 		for turn_id, turn_service in pairs(turn_services) do
  1229 		for turn_id, turn_service in pairs(turn_services) do
  1152 			print("Testing "..turn_id.."...");
  1230 			print("Testing "..turn_id.."...");
  1153 
  1231 
  1154 			local result = check_turn_service(turn_service);
  1232 			local result = check_turn_service(turn_service, opts.ping);
  1155 			if #result.warnings > 0 then
  1233 			if #result.warnings > 0 then
  1156 				print(("%d warnings:\n\n    "):format(#result.warnings));
  1234 				print(("%d warnings:\n\n    "):format(#result.warnings));
  1157 				print(table.concat(result.warnings, "\n    "));
  1235 				print(table.concat(result.warnings, "\n    "));
  1158 			end
  1236 			end
  1159 			if result.error then
  1237 			if result.error then
  1160 				print("Error: "..result.error.."\n");
  1238 				print("Error: "..result.error.."\n");
  1161 				ok = false;
  1239 				ok = false;
  1162 			else
  1240 			else
       
  1241 				if opts.verbose then
       
  1242 					print(("External IP: %s"):format(result.external_ip.address));
       
  1243 					if result.external_ip_pong then
       
  1244 						print(("TURN external IP: %s"):format(result.external_ip_pong.address));
       
  1245 					end
       
  1246 				end
  1163 				print("Success!\n");
  1247 				print("Success!\n");
  1164 			end
  1248 			end
  1165 		end
  1249 		end
  1166 	end
  1250 	end
  1167 
  1251