# # # add_dir "tests/netsync_hook_errcodes" # # add_file "tests/netsync_hook_errcodes/__driver__.lua" # content [6e225762e3051996d2fc0b6250a575090391003f] # # patch "ChangeLog" # from [583ce8666abd871071e00cf3631b8b993ba61e40] # to [b0b3cf564ffd0112038e7d987eb42e1041e8051e] # # patch "monotone.texi" # from [18658fe14fa458d5592b1810fc8b353551d14719] # to [5145b11d5c87242af630bf8bc1b27620b4fada3a] # # patch "netsync.cc" # from [cf7c9c987e83edac5caf87e17780a2f1a4d89267] # to [5958850a81ebe84a8cd7e6d6c2107bbe46aaa839] # # patch "testsuite.lua" # from [67b5f8eb1b321452edafe257ac5f61e82c85c856] # to [bc5ad021695a5188e9cd164a8fb0bac77c1633b2] # ============================================================ --- tests/netsync_hook_errcodes/__driver__.lua 6e225762e3051996d2fc0b6250a575090391003f +++ tests/netsync_hook_errcodes/__driver__.lua 6e225762e3051996d2fc0b6250a575090391003f @@ -0,0 +1,68 @@ + +include("common/netsync.lua") +mtn_setup() +netsync.setup_with_notes() + +-- This tests *some* of the netsync error code handling. It can't test +-- reporting of interrupted connections (21x) because we don't have a +-- reliable way to kill one side halfway through the connection, +-- and can't test 5xx errors because those require that one side isn't +-- speaking the protocol correctly. + +function get_errcode(who) + local dat = readfile("testnotes-" .. who .. ".log") + local _, _, errcode = string.find(dat, "\n%d+ end: status = (%d%d%d)\n") + L("Error code for ", who, " is ", errcode) + if errcode == nil then errcode = "" end + return errcode +end + +function chk_errcode_is(errcode, which) + L("Want error code ", errcode) + errcode = string.gsub(errcode, "x", ".") + if which == nil then + local srvcode = get_errcode("server") + local clicode = get_errcode("client") + check(string.find(srvcode, errcode) ~= nil) + check(string.find(clicode, errcode) ~= nil) + else + local code = get_errcode(which) + check(string.find(code, errcode) ~= nil) + end +end + +function clearnotes() + check(remove("testnotes-client.log")) + check(remove("testnotes-server.log")) +end + + +addfile("testfile", "file contents") +commit() +addfile("otherfile", "other contents") +commit("otherbranch") + +netsync.sync("testbranch") +chk_errcode_is(200) +clearnotes() + +srv = netsync.start("testbranch") +srv:sync({"otherbranch"}, 2, 1) +srv:stop() +chk_errcode_is(412) +clearnotes() + +check(mtn2("genkey", "address@hidden"), 0, false, false, string.rep("address@hidden", 2)) +srv = netsync.start("testbranch") +srv:sync({"testbranch", "address@hidden"}, 2, 1) +srv:stop() +chk_errcode_is(422) +clearnotes() + +check(mtn("db", "set_epoch", "testbranch", string.rep("0", 40))) +check(mtn2("db", "set_epoch", "testbranch", string.rep("1", 40))) +srv = netsync.start("testbranch") +srv:push({"testbranch"}, 2, 1) +srv:stop() +chk_errcode_is(432) +clearnotes() ============================================================ --- ChangeLog 583ce8666abd871071e00cf3631b8b993ba61e40 +++ ChangeLog b0b3cf564ffd0112038e7d987eb42e1041e8051e @@ -1,3 +1,7 @@ +2006-11-17 Timothy Brownawell + + Add status code reporting to the note_netsync_{begin,end} hooks. + 2006-11-14 Richard Levitte NOTE: I bumped the Debian version number to 0.31-90.1 in this ============================================================ --- monotone.texi 18658fe14fa458d5592b1810fc8b353551d14719 +++ monotone.texi 5145b11d5c87242af630bf8bc1b27620b4fada3a @@ -7272,15 +7272,46 @@ @subsection Event Notifications and Trig commit-notification systems such as mailing lists or news services. It should not perform any security-critical operations. address@hidden note_netsync_start (@var{nonce}) address@hidden note_netsync_start (@var{session_id}, @var{my_role}, @var{sync_type}, address@hidden, @var{remote_keyname}, @var{includes}, @var{excludes}) Called by monotone before any other of the netsync notification hooks -are called. The @var{nonce} helps keep track of the current netsync +are called. The @var{session_id} helps keep track of the current netsync session in case several are happening at the same time, and is used throughout all netsync notification hooks. address@hidden note_netsync_revision_received (@var{new_id}, @var{revision}, @var{certs}, @var{nonce}) +The other arguments are: address@hidden + address@hidden @var{my_role} + +This will be either "client" or "server". + address@hidden @var{sync_type} + +This will be one of "sync", "push", or "pull". + address@hidden @var{remote_host} + +The network address of the remote host. At the client, this will be the name +it was told to connect to; at the server, this will use the numerical IP address +the connection was received from. + address@hidden @var{remote_keyname} + +The name of the key being used by the other end of the connection. This may be +set to "-unknown-" at the server if the key used by the client is not present +at the server. + address@hidden @var{includes} and @var{excludes} + +The include and exclude patterns used by the client. + address@hidden table + address@hidden note_netsync_revision_received (@var{new_id}, @var{revision}, @var{certs}, @var{session_id}) + Called by monotone after the revision @var{new_id} is received through netsync. @var{revision} is the text of the revision, what would be given by "monotone cat revision @var{new_id}". @var{certs} is a lua table @@ -7289,11 +7320,11 @@ @subsection Event Notifications and Trig named "key", "name", and "value", containing the signing key for the cert, the name of the cert, and the value of the cert. There is no default definition for this hook. address@hidden is used together with @code{note_netsync_start} and address@hidden is used together with @code{note_netsync_start} and @code{note_netsync_end}. If you're not interested in that type of tracking, you can ignore that variable entirely. address@hidden note_netsync_cert_received (@var{rev_id}, @var{key}, @var{name}, @var{value}, @var{nonce}) address@hidden note_netsync_cert_received (@var{rev_id}, @var{key}, @var{name}, @var{value}, @var{session_id}) Called by monotone after a cert is received through netsync, iff the revision that the cert is attached to was not also received in the same netsync @@ -7301,19 +7332,21 @@ @subsection Event Notifications and Trig @var{key} is the key that the cert is signed with, @var{name} is the name of the cert, and @var{value} is the cert value. There is no default definition for this hook. address@hidden is used together with @code{note_netsync_start} and address@hidden is used together with @code{note_netsync_start} and @code{note_netsync_end}. If you're not interested in that type of tracking, you can ignore that variable entirely. address@hidden note_netsync_pubkey_received (@var{keyname}, @var{nonce}) address@hidden note_netsync_pubkey_received (@var{keyname}, @var{session_id}) Called by monotone after a pubkey is received through netsync. @var{keyname} is the name of the key received. There is no default definition for this hook. address@hidden is used together with @code{note_netsync_start} and address@hidden is used together with @code{note_netsync_start} and @code{note_netsync_end}. If you're not interested in that type of tracking, you can ignore that variable entirely. address@hidden note_netsync_end (@var{nonce}) address@hidden note_netsync_end (@var{session_id}, @var{status}, address@hidden, @var{bytes_out}, @var{certs_in}, @var{certs_out}, address@hidden, @var{revs_out}, @var{keys_in}, @var{keys_out}) Called by monotone after all other the netsync notification hooks have been called. This hook would usually be used for post-netsync purposes, @@ -7322,6 +7355,54 @@ @subsection Event Notifications and Trig It could also be used to prepare parallell databases with all the data to be displayed through something like viewmtn. address@hidden is a three digit integer that tells whether there was an error, +and if so what kind of error it was: + address@hidden + address@hidden 200 + +No error, connection successful. + address@hidden 211 + +The connection was interrupted after some data may have been transferred. + address@hidden 212 + +The connection was interrupted before any data could be transferred. + address@hidden 412 + +The request is not permitted. + address@hidden 422 + +The client tried to use a key that the server doesn't know about. + address@hidden 432 + +The client and server have different epochs for a branch. + address@hidden 512 + +Protocol error (source/sink confusion). + address@hidden 521 + +Protocol error (packet received at a time when it doesn't make sense). + address@hidden 532 + +The client did not identify itself correctly. (Possible replay attack?) + address@hidden table + +In general, 2xx means there was no error, 4xx means there was a permissions +error, and 5xx means there was a protocol error. xx1 means some data may +have been transferred, xx2 means no data was transferred, and xx0 means all +data was transferred. + @end ftable @subsection User Defaults ============================================================ --- netsync.cc cf7c9c987e83edac5caf87e17780a2f1a4d89267 +++ netsync.cc 5958850a81ebe84a8cd7e6d6c2107bbe46aaa839 @@ -1520,25 +1520,6 @@ session::process_auth_cmd(protocol_role get_branches(app, branchnames); globish_matcher their_matcher(their_include_pattern, their_exclude_pattern); - // Check that they replied with the nonce we asked for. - if (!(nonce1 == this->saved_nonce)) - { - this->saved_nonce = id(""); - error(failed_identification, - F("detected replay attack in auth netcmd").str()); - } - - // Internally netsync thinks in terms of sources and sinks. users like - // thinking of repositories as "readonly", "readwrite", or "writeonly". - // - // We therefore use the read/write terminology when dealing with the UI: - // if the user asks to run a "read only" service, this means they are - // willing to be a source but not a sink. - // - // nb: The "their_role" here is the role the *client* wants to play - // so we need to check that the opposite role is allowed for us, - // in our this->role field. - if (!app.db.public_key_exists(their_key_hash)) { // If it's not in the db, it still could be in the keystore if we @@ -1546,6 +1527,11 @@ session::process_auth_cmd(protocol_role if (!app.keys.try_ensure_in_db(their_key_hash)) { this->saved_nonce = id(""); + + app.lua.hook_note_netsync_start(session_id, "server", their_role, + peer_id, rsa_keypair_id("-unknown-"), + their_include_pattern, + their_exclude_pattern); error(unknown_key, (F("remote public key hash '%s' is unknown") % their_key_hash).str()); } @@ -1560,6 +1546,25 @@ session::process_auth_cmd(protocol_role peer_id, their_id, their_include_pattern, their_exclude_pattern); + // Check that they replied with the nonce we asked for. + if (!(nonce1 == this->saved_nonce)) + { + this->saved_nonce = id(""); + error(failed_identification, + F("detected replay attack in auth netcmd").str()); + } + + // Internally netsync thinks in terms of sources and sinks. users like + // thinking of repositories as "readonly", "readwrite", or "writeonly". + // + // We therefore use the read/write terminology when dealing with the UI: + // if the user asks to run a "read only" service, this means they are + // willing to be a source but not a sink. + // + // nb: The "their_role" here is the role the *client* wants to play + // so we need to check that the opposite role is allowed for us, + // in our this->role field. + // Client as sink, server as source (reading). if (their_role == sink_role || their_role == source_and_sink_role) ============================================================ --- testsuite.lua 67b5f8eb1b321452edafe257ac5f61e82c85c856 +++ testsuite.lua bc5ad021695a5188e9cd164a8fb0bac77c1633b2 @@ -687,3 +687,4 @@ table.insert(tests, "add_ignored") table.insert(tests, "db_check_(heights)") table.insert(tests, "disapproving_with_message") table.insert(tests, "add_ignored") +table.insert(tests, "netsync_hook_errcodes")