From 4325a43d3d1476cc601b631620df89340ec4c7e2 Mon Sep 17 00:00:00 2001 From: Magnus Ahltorp Date: Mon, 20 Oct 2014 14:33:41 +0200 Subject: Added external merging support --- Makefile | 5 ++ catlfish.config | 5 +- httpd_props.conf | 2 +- storage_node.config | 19 +++++++ storage_node_httpd.conf | 21 ++++++++ tools/merge.py | 133 ++++++++++++++++++++++++++++++++++++++++++++++++ tools/testcase1.py | 13 +++++ 7 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 storage_node.config create mode 100644 storage_node_httpd.conf create mode 100755 tools/merge.py diff --git a/Makefile b/Makefile index 78f8a6b..aa96290 100644 --- a/Makefile +++ b/Makefile @@ -10,8 +10,13 @@ release: ln -s ../../plop/test .) cp httpd_props.conf rel cp catlfish.config rel + cp storage_node.config rel + cp storage_node_httpd.conf rel mkdir rel/catlfish mkdir rel/db + mkdir rel/mergedb + mkdir rel/mergedb/chains + touch rel/mergedb/logorder printf "0" > rel/db/treesize cp -r webroot rel/catlfish test -d rel/catlfish/webroot/log || mkdir rel/catlfish/webroot/log diff --git a/catlfish.config b/catlfish.config index 75d00fa..672f997 100644 --- a/catlfish.config +++ b/catlfish.config @@ -21,4 +21,7 @@ {index_path, "db/index"}, {entryhash_root_path, "db/entryhash/"}, {treesize_path, "db/treesize"}, - {indexforhash_root_path, "db/certindex/"}]}]. + {indexforhash_root_path, "db/certindex/"}, + %{storage_nodes, ["https://127.0.0.1:8081/ct/storage/"]}, + {storage_nodes_quorum, 1} + ]}]. diff --git a/httpd_props.conf b/httpd_props.conf index ae4c7be..9ea7b30 100644 --- a/httpd_props.conf +++ b/httpd_props.conf @@ -8,7 +8,7 @@ {document_root, "catlfish/webroot/docroot"}, {modules, [mod_alias, mod_auth, mod_esi, mod_get, mod_head, mod_log, mod_disk_log]}, - {erl_script_alias, {"/ct", [v1]}}, + {erl_script_alias, {"/ct", [v1, frontend]}}, {erl_script_nocache, true}, {error_log, "log/error"}, {security_log, "log/security"}, diff --git a/storage_node.config b/storage_node.config new file mode 100644 index 0000000..47a1326 --- /dev/null +++ b/storage_node.config @@ -0,0 +1,19 @@ +%% catlfish configuration file (-*- erlang -*-) +%% Start like this: +%% $ erl -boot start_sasl -config catlfish -run inets +[{sasl, + [{sasl_error_logger, false}, + {errlog_type, error}, + {error_logger_mf_dir, "log"}, + {error_logger_mf_maxbytes, 10485760}, % 10 MB + {error_logger_mf_maxfiles, 10}]}, + {inets, + [{services, + [{httpd, [{proplist_file, "storage_node_httpd.conf"}]}]}]}, + {plop, + [{entry_root_path, "db/certentries/"}, + {index_path, "db/index"}, + {newentries_path, "db/newentries"}, + {entryhash_root_path, "db/entryhash/"}, + {treesize_path, "db/treesize"}, + {indexforhash_root_path, "db/certindex/"}]}]. diff --git a/storage_node_httpd.conf b/storage_node_httpd.conf new file mode 100644 index 0000000..2f271f8 --- /dev/null +++ b/storage_node_httpd.conf @@ -0,0 +1,21 @@ +%%% Copyright (c) 2014, NORDUnet A/S. +%%% See LICENSE for licensing information. +[ + {port, 8081}, + {bind_address, {127, 0, 0, 1}}, + {server_name, "flimsy"}, + {server_root, "catlfish/webroot"}, + {document_root, "catlfish/webroot/docroot"}, + {modules, [mod_alias, mod_auth, mod_esi, mod_get, mod_head, + mod_log, mod_disk_log]}, + {erl_script_alias, {"/ct", [storage]}}, + {erl_script_nocache, true}, + {error_log, "log/error_storage"}, + {security_log, "log/security_storage"}, + {transfer_log, "log/transfer_storage"}, + {socket_type, + {essl, % See ssl(3erl) for SSL options. + [{certfile, "catlfish/webroot/certs/webcert.pem"}, + {keyfile, "catlfish/webroot/keys/webkey.pem"}, + {cacertfile, "catlfish/webroot/certs/webcert.pem"}]}} +]. diff --git a/tools/merge.py b/tools/merge.py new file mode 100755 index 0000000..7120d04 --- /dev/null +++ b/tools/merge.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (c) 2014 Kungliga Tekniska Högskolan +# (KTH Royal Institute of Technology, Stockholm, Sweden). +# See LICENSE for licensing information. + +import json +import base64 +import urllib +import urllib2 +import sys + +frontendnodes = ["https://127.0.0.1:8080/"] +storagenodes = ["https://127.0.0.1:8081/"] + +chainsdir = "../rel/mergedb/chains" +logorderfile = "../rel/mergedb/logorder" + +def parselogrow(row): + return base64.b16decode(row) + +def get_logorder(): + f = open(logorderfile, "r") + return [parselogrow(row.rstrip()) for row in f] + +def write_chain(key, value): + f = open(chainsdir + "/" + base64.b16encode(key), "w") + f.write(value) + f.close() + +def read_chain(key): + f = open(chainsdir + "/" + base64.b16encode(key), "r") + value = f.read() + f.close() + return value + +def add_to_logorder(key): + f = open(logorderfile, "a") + f.write(base64.b16encode(key) + "\n") + f.close() + +def get_new_entries(baseurl): + try: + result = urllib2.urlopen(baseurl + "ct/storage/fetchnewentries").read() + parsed_result = json.loads(result) + if parsed_result.get(u"result") == u"ok": + return parsed_result[u"entries"] + print "ERROR: fetchnewentries", parsed_result + sys.exit(1) + except urllib2.HTTPError, e: + print "ERROR: fetchnewentries", e.read() + sys.exit(1) + +def get_curpos(baseurl): + try: + result = urllib2.urlopen(baseurl + "ct/frontend/currentposition").read() + parsed_result = json.loads(result) + if parsed_result.get(u"result") == u"ok": + return parsed_result[u"position"] + print "ERROR: currentposition", parsed_result + sys.exit(1) + except urllib2.HTTPError, e: + print "ERROR: currentposition", e.read() + sys.exit(1) + +def sendlog(baseurl, submission): + try: + result = urllib2.urlopen(baseurl + "ct/frontend/sendlog", + json.dumps(submission)).read() + return json.loads(result) + except urllib2.HTTPError, e: + print "ERROR: sendlog", e.read() + sys.exit(1) + except ValueError, e: + print "==== FAILED REQUEST ====" + print submission + print "======= RESPONSE =======" + print result + print "========================" + raise e + +def sendsth(baseurl, submission): + try: + result = urllib2.urlopen(baseurl + "ct/frontend/sendsth", + json.dumps(submission)).read() + return json.loads(result) + except urllib2.HTTPError, e: + print "ERROR: sendsth", e.read() + sys.exit(1) + except ValueError, e: + print "==== FAILED REQUEST ====" + print submission + print "======= RESPONSE =======" + print result + print "========================" + raise e + +def get_missingentries(baseurl): + try: + result = urllib2.urlopen(baseurl + "ct/frontend/missingentries").read() + parsed_result = json.loads(result) + if parsed_result.get(u"result") == u"ok": + return parsed_result[u"entries"] + print "ERROR: missingentries", parsed_result + sys.exit(1) + except urllib2.HTTPError, e: + print "ERROR: missingentries", e.read() + sys.exit(1) + + +logorder = get_logorder() +certsinlog = set(logorder) + +new_entries = [entry for storagenode in storagenodes for entry in get_new_entries(storagenode)] + +for new_entry in new_entries: + hash = base64.b64decode(new_entry["hash"]) + entry = base64.b64decode(new_entry["entry"]) + if hash not in certsinlog: + write_chain(hash, entry) + add_to_logorder(hash) + logorder.append(hash) + certsinlog.add(hash) + print "added", base64.b16encode(hash) + +for frontendnode in frontendnodes: + curpos = get_curpos(frontendnode) + entries = [base64.b64encode(entry) for entry in logorder[curpos:]] + sendlog(frontendnode, {"start": curpos, "hashes": entries}) + missingentries = get_missingentries(frontendnode) + print "missing entries:", missingentries + # XXX: no test case for missing entries yet, waiting to implement + sendsth(frontendnode, {"tree_size": len(logorder)}) diff --git a/tools/testcase1.py b/tools/testcase1.py index eab6c6f..2d5e0e8 100755 --- a/tools/testcase1.py +++ b/tools/testcase1.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +# -*- coding: utf-8 -*- # Copyright (c) 2014, NORDUnet A/S. # See LICENSE for licensing information. @@ -125,12 +126,16 @@ testgroup("cert1") result1 = do_add_chain(cc1) +subprocess.call(["./merge.py"]) + print_and_check_tree_size(1) result2 = do_add_chain(cc1) assert_equal(result2["timestamp"], result1["timestamp"], "timestamp") +subprocess.call(["./merge.py"]) + print_and_check_tree_size(1) # TODO: add invalid cert and check that it generates an error @@ -142,6 +147,8 @@ testgroup("cert2") result3 = do_add_chain(cc2) +subprocess.call(["./merge.py"]) + print_and_check_tree_size(2) get_and_validate_proof(result1["timestamp"], cc1, 0, 1) @@ -151,6 +158,8 @@ testgroup("cert3") result4 = do_add_chain(cc3) +subprocess.call(["./merge.py"]) + print_and_check_tree_size(3) get_and_validate_proof(result1["timestamp"], cc1, 0, 2) @@ -161,6 +170,8 @@ testgroup("cert4") result5 = do_add_chain(cc4) +subprocess.call(["./merge.py"]) + print_and_check_tree_size(4) get_and_validate_proof(result1["timestamp"], cc1, 0, 2) @@ -172,6 +183,8 @@ testgroup("cert5") result6 = do_add_chain(cc5) +subprocess.call(["./merge.py"]) + print_and_check_tree_size(5) get_and_validate_proof(result1["timestamp"], cc1, 0, 3) -- cgit v1.1