xmpp-fingerprint.lua

Mon, 04 Oct 2010 02:43:59 +0100

author
Matthew Wild <mwild1@gmail.com>
date
Mon, 04 Oct 2010 02:43:59 +0100
changeset 13
9331253c2f83
parent 11
c77c5ac57156
child 15
1b59ba3e9508
permissions
-rwxr-xr-x

xmpp-fingerprint.lua: Whitespace fix

#!/usr/bin/env lua

function softreq(...) local ok, lib =  pcall(require, ...); if ok then return lib; else 
return nil, lib; end end

-- Required to be able to find packages installed with luarocks
if not softreq "luarocks.loader" then -- LuaRocks 2.x
        softreq "luarocks.require"; -- LuaRocks <1.x
end

local socket = softreq "socket";

-- Defaults --
default_port = 5222;
default_namespace = "jabber:client";
default_timeout = 1.5;

-- Print debug output --
function debug() end -- Keep debug output quiet by default

-- Command-line flag handlers --
local flags = {};
function flags.d() -- Show debug
	debug = print;
end

function flags.s() -- Use s2s
	-- Use s2s
	default_port = 5269;
	default_namespace = "jabber:server";
end

function flags.t(arg)
	default_timeout = tonumber(arg[1] or 1);
	return 1;
end

function flags.help()
	print("XMPP Server Fingerprinter");
	print("(C) 2010 Matthew Wild. Licensed under the MIT/X11 License");
	print("");
	print("Syntax: "..arg[0].." [OPTIONS] ADDRESS [PORT]");
	print("");
	print("ADDRESS must be the network address or IP to connect to, SRV lookup");
	print("is not supported.");
	print("");
	print("PORT is the port number to connect to. Defaults to 5222, or 5269 for");
	print("server-to-server testing.");
	print("");
	print("Options:");
	print("    -s:", "Server-to-server port testing (less reliable)");
	print("-t NUM:", "Set timeout to NUM seconds");
	print("    -d:", "Enable debug output (useful for adding new fingerprints)");
	print("");
end

-- Process flags --
local function process_args(arg)
	local f = arg[1] and arg[1]:match("^%-%-?(%S+)");
	if f then
		table.remove(arg, 1);
		if flags[f] then
			local used = flags[f](arg);
			if used then
				for i=1,used do
					table.remove(arg, 1);
				end
			end
		end
		return process_args(arg);
	end
end
if #arg > 0 then
	process_args(arg);
else
	flags.help();
	os.exit(1);
end

if #arg < 1 then
	io.stderr:write("ERROR: No server address specified.\n");
	os.exit(1);
end

local received_cache = {};
local function _test(server, port, question, answer)
	local received = received_cache[question];
	if not received then
		debug("||", "Connecting to "..server..":"..port.."...");
		local conn = assert(socket.connect(server, port), "Failed to connect to "..arg[1]);
		conn:send(question);
		debug(">>", tostring(question));
		conn:settimeout(default_timeout);
		local data, err, partial = conn:receive("*a");
		received = data or partial or "";
		conn:close();
		received_cache[question] = received;
		debug("<<", #received ~= "" and tostring(received) or nil);
	end
	return received ~= "" and received:match(answer);
end

function test(question, answer)
	return _test(arg[1], tonumber(arg[2]) or default_port, question, answer);
end

function server_comment(comment)
	table.insert(getfenv(2).server_comments, comment);
end

function literal(s)
	return s:gsub("%p", "%%%1");
end

-----
q_invalid_xml = "abc\n";
q_empty_message_tag = "<message/>";
q_invalid_host = "<stream:stream xmlns='"..default_namespace.."' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' id='abc' to='0.0.0.0'>";
-----

testers = {};

dofile "servers/ejabberd.lua"
dofile "servers/google_talk.lua"
dofile "servers/isode_mlink.lua"
dofile "servers/jabberd14.lua"
dofile "servers/jabberd2.lua"
dofile "servers/prosody.lua"
dofile "servers/tigase.lua"
dofile "servers/djabberd.lua"
dofile "servers/openfire.lua"
dofile "servers/jabber_xcp.lua"
dofile "servers/soapbox.lua"

function test_fingerprint(server)
	local tester = testers[server];
	local env = setmetatable({server_comments = {}}, { __index = _G });
	setfenv(tester, env);
	local ok, err = pcall(tester);
	if not ok then
		print("Error while testing for "..server..": "..err);
	end
	return env;
end

------------------------------------------------------------------

local results = {};
for server in pairs(testers) do
	local res = test_fingerprint(server);
	if res.server_name then
		table.insert(results, res);
	end
end

if #results > 1 then
	print("Note... multiple matches, could be any:");
end

for _, result in ipairs(results) do
	io.write(result.server_name);
	if result.server_min_version then
		io.write(", version "..result.server_min_version.." or later");
	elseif result.server_version then
		io.write(", version "..result.server_version);
	end
	io.write("\n");
	if #result.server_comments > 0 then
		print("   Notes:\n", table.concat(result.server_comments, "\n      "));
	end
end

mercurial