commit
6efa84fa37
@ -32,17 +32,53 @@ type error += Rejected
|
|||||||
type error += Decoding_error
|
type error += Decoding_error
|
||||||
type error += Myself of Id_point.t
|
type error += Myself of Id_point.t
|
||||||
type error += Not_enough_proof_of_work of Gid.t
|
type error += Not_enough_proof_of_work of Gid.t
|
||||||
|
type error += Invalid_auth
|
||||||
|
|
||||||
type cryptobox_data = {
|
module Crypto = struct
|
||||||
|
|
||||||
|
let header_length = 2
|
||||||
|
let crypto_overhead = 18 (* FIXME import from Sodium.Box. *)
|
||||||
|
let max_content_length =
|
||||||
|
1 lsl (header_length * 8) - crypto_overhead
|
||||||
|
|
||||||
|
type data = {
|
||||||
channel_key : Crypto_box.channel_key ;
|
channel_key : Crypto_box.channel_key ;
|
||||||
mutable local_nonce : Crypto_box.nonce ;
|
mutable local_nonce : Crypto_box.nonce ;
|
||||||
mutable remote_nonce : Crypto_box.nonce ;
|
mutable remote_nonce : Crypto_box.nonce ;
|
||||||
}
|
}
|
||||||
|
|
||||||
let header_length = 2
|
let write_chunk fd cryptobox_data buf =
|
||||||
let crypto_overhead = 18 (* FIXME import from Sodium.Box. *)
|
let header_buf = MBytes.create header_length in
|
||||||
let max_content_length =
|
let local_nonce = cryptobox_data.local_nonce in
|
||||||
1 lsl (header_length * 8) - crypto_overhead
|
cryptobox_data.local_nonce <- Crypto_box.increment_nonce local_nonce ;
|
||||||
|
let encrypted_message =
|
||||||
|
Crypto_box.fast_box cryptobox_data.channel_key buf local_nonce in
|
||||||
|
let encrypted_len = MBytes.length encrypted_message in
|
||||||
|
fail_unless
|
||||||
|
(encrypted_len < max_content_length)
|
||||||
|
Invalid_message_size >>=? fun () ->
|
||||||
|
MBytes.set_int16 header_buf 0 encrypted_len ;
|
||||||
|
P2p_io_scheduler.write fd header_buf >>=? fun () ->
|
||||||
|
P2p_io_scheduler.write fd encrypted_message >>=? fun () ->
|
||||||
|
return ()
|
||||||
|
|
||||||
|
let read_chunk fd cryptobox_data =
|
||||||
|
let header_buf = MBytes.create header_length in
|
||||||
|
P2p_io_scheduler.read_full ~len:header_length fd header_buf >>=? fun () ->
|
||||||
|
let len = MBytes.get_uint16 header_buf 0 in
|
||||||
|
let buf = MBytes.create len in
|
||||||
|
P2p_io_scheduler.read_full ~len fd buf >>=? fun () ->
|
||||||
|
let remote_nonce = cryptobox_data.remote_nonce in
|
||||||
|
cryptobox_data.remote_nonce <- Crypto_box.increment_nonce remote_nonce ;
|
||||||
|
match
|
||||||
|
Crypto_box.fast_box_open cryptobox_data.channel_key buf remote_nonce
|
||||||
|
with
|
||||||
|
| None ->
|
||||||
|
fail Decipher_error
|
||||||
|
| Some buf ->
|
||||||
|
return buf
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
module Connection_message = struct
|
module Connection_message = struct
|
||||||
|
|
||||||
@ -78,11 +114,12 @@ module Connection_message = struct
|
|||||||
let encoded_message_len =
|
let encoded_message_len =
|
||||||
Data_encoding.Binary.length encoding message in
|
Data_encoding.Binary.length encoding message in
|
||||||
fail_unless
|
fail_unless
|
||||||
(encoded_message_len < max_content_length)
|
(encoded_message_len < Crypto.max_content_length)
|
||||||
Encoding_error >>=? fun () ->
|
Encoding_error >>=? fun () ->
|
||||||
let len = header_length + encoded_message_len in
|
let len = Crypto.header_length + encoded_message_len in
|
||||||
let buf = MBytes.create len in
|
let buf = MBytes.create len in
|
||||||
match Data_encoding.Binary.write encoding message buf header_length with
|
match Data_encoding.Binary.write
|
||||||
|
encoding message buf Crypto.header_length with
|
||||||
| None ->
|
| None ->
|
||||||
fail Encoding_error
|
fail Encoding_error
|
||||||
| Some last ->
|
| Some last ->
|
||||||
@ -91,8 +128,9 @@ module Connection_message = struct
|
|||||||
P2p_io_scheduler.write fd buf
|
P2p_io_scheduler.write fd buf
|
||||||
|
|
||||||
let read fd =
|
let read fd =
|
||||||
let header_buf = MBytes.create header_length in
|
let header_buf = MBytes.create Crypto.header_length in
|
||||||
P2p_io_scheduler.read_full ~len:header_length fd header_buf >>=? fun () ->
|
P2p_io_scheduler.read_full
|
||||||
|
~len:Crypto.header_length fd header_buf >>=? fun () ->
|
||||||
let len = MBytes.get_uint16 header_buf 0 in
|
let len = MBytes.get_uint16 header_buf 0 in
|
||||||
let buf = MBytes.create len in
|
let buf = MBytes.create len in
|
||||||
P2p_io_scheduler.read_full ~len fd buf >>=? fun () ->
|
P2p_io_scheduler.read_full ~len fd buf >>=? fun () ->
|
||||||
@ -109,29 +147,25 @@ end
|
|||||||
|
|
||||||
module Ack = struct
|
module Ack = struct
|
||||||
|
|
||||||
type t = bool
|
type t = Ack | Nack
|
||||||
let ack = MBytes.of_string "\255"
|
let ack = MBytes.of_string "\255"
|
||||||
let nack = MBytes.of_string "\000"
|
let nack = MBytes.of_string "\000"
|
||||||
|
|
||||||
let write fd b =
|
let write cryptobox_data fd b =
|
||||||
match b with
|
Crypto.write_chunk cryptobox_data fd
|
||||||
| true ->
|
(match b with Ack -> ack | Nack -> nack)
|
||||||
P2p_io_scheduler.write fd ack
|
|
||||||
| false ->
|
|
||||||
P2p_io_scheduler.write fd nack
|
|
||||||
|
|
||||||
let read fd =
|
let read fd cryptobox_data =
|
||||||
let buf = MBytes.create 1 in
|
Crypto.read_chunk fd cryptobox_data >>=? fun buf ->
|
||||||
P2p_io_scheduler.read_full fd buf >>=? fun () ->
|
|
||||||
return (buf <> nack)
|
return (buf <> nack)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
type authenticated_fd =
|
type authenticated_fd =
|
||||||
P2p_io_scheduler.connection * Connection_info.t * cryptobox_data
|
P2p_io_scheduler.connection * Connection_info.t * Crypto.data
|
||||||
|
|
||||||
let kick (fd, _ , _) =
|
let kick (fd, _ , cryptobox_data) =
|
||||||
Ack.write fd false >>= fun _ ->
|
Ack.write fd cryptobox_data Nack >>= fun _ ->
|
||||||
P2p_io_scheduler.close fd >>= fun _ ->
|
P2p_io_scheduler.close fd >>= fun _ ->
|
||||||
Lwt.return_unit
|
Lwt.return_unit
|
||||||
|
|
||||||
@ -168,14 +202,14 @@ let authenticate
|
|||||||
{ Connection_info.gid = remote_gid ; versions = msg.versions ; incoming ;
|
{ Connection_info.gid = remote_gid ; versions = msg.versions ; incoming ;
|
||||||
id_point ; remote_socket_port ;} in
|
id_point ; remote_socket_port ;} in
|
||||||
let cryptobox_data =
|
let cryptobox_data =
|
||||||
{ channel_key ; local_nonce ;
|
{ Crypto.channel_key ; local_nonce ;
|
||||||
remote_nonce = msg.message_nonce } in
|
remote_nonce = msg.message_nonce } in
|
||||||
return (info, (fd, info, cryptobox_data))
|
return (info, (fd, info, cryptobox_data))
|
||||||
|
|
||||||
type connection = {
|
type connection = {
|
||||||
info : Connection_info.t ;
|
info : Connection_info.t ;
|
||||||
fd : P2p_io_scheduler.connection ;
|
fd : P2p_io_scheduler.connection ;
|
||||||
cryptobox_data : cryptobox_data ;
|
cryptobox_data : Crypto.data ;
|
||||||
}
|
}
|
||||||
|
|
||||||
module Reader = struct
|
module Reader = struct
|
||||||
@ -188,29 +222,13 @@ module Reader = struct
|
|||||||
mutable worker: unit Lwt.t ;
|
mutable worker: unit Lwt.t ;
|
||||||
}
|
}
|
||||||
|
|
||||||
let read_chunk { fd ; cryptobox_data } =
|
|
||||||
let header_buf = MBytes.create header_length in
|
|
||||||
P2p_io_scheduler.read_full ~len:header_length fd header_buf >>=? fun () ->
|
|
||||||
let len = MBytes.get_uint16 header_buf 0 in
|
|
||||||
let buf = MBytes.create len in
|
|
||||||
P2p_io_scheduler.read_full ~len fd buf >>=? fun () ->
|
|
||||||
let remote_nonce = cryptobox_data.remote_nonce in
|
|
||||||
cryptobox_data.remote_nonce <- Crypto_box.increment_nonce remote_nonce ;
|
|
||||||
match
|
|
||||||
Crypto_box.fast_box_open cryptobox_data.channel_key buf remote_nonce
|
|
||||||
with
|
|
||||||
| None ->
|
|
||||||
fail Decipher_error
|
|
||||||
| Some buf ->
|
|
||||||
return buf
|
|
||||||
|
|
||||||
let rec read_message st buf =
|
let rec read_message st buf =
|
||||||
return (Data_encoding.Binary.of_bytes st.encoding buf)
|
return (Data_encoding.Binary.of_bytes st.encoding buf)
|
||||||
|
|
||||||
let rec worker_loop st =
|
let rec worker_loop st =
|
||||||
Lwt_unix.yield () >>= fun () ->
|
Lwt_unix.yield () >>= fun () ->
|
||||||
Lwt_utils.protect ~canceler:st.canceler begin fun () ->
|
Lwt_utils.protect ~canceler:st.canceler begin fun () ->
|
||||||
read_chunk st.conn >>=? fun buf ->
|
Crypto.read_chunk st.conn.fd st.conn.cryptobox_data >>=? fun buf ->
|
||||||
read_message st buf
|
read_message st buf
|
||||||
end >>= function
|
end >>= function
|
||||||
| Ok None ->
|
| Ok None ->
|
||||||
@ -258,21 +276,6 @@ module Writer = struct
|
|||||||
mutable worker: unit Lwt.t ;
|
mutable worker: unit Lwt.t ;
|
||||||
}
|
}
|
||||||
|
|
||||||
let write_chunk { cryptobox_data ; fd } buf =
|
|
||||||
let header_buf = MBytes.create header_length in
|
|
||||||
let local_nonce = cryptobox_data.local_nonce in
|
|
||||||
cryptobox_data.local_nonce <- Crypto_box.increment_nonce local_nonce ;
|
|
||||||
let encrypted_message =
|
|
||||||
Crypto_box.fast_box cryptobox_data.channel_key buf local_nonce in
|
|
||||||
let encrypted_len = MBytes.length encrypted_message in
|
|
||||||
fail_unless
|
|
||||||
(encrypted_len < max_content_length)
|
|
||||||
Invalid_message_size >>=? fun () ->
|
|
||||||
MBytes.set_int16 header_buf 0 encrypted_len ;
|
|
||||||
P2p_io_scheduler.write fd header_buf >>=? fun () ->
|
|
||||||
P2p_io_scheduler.write fd encrypted_message >>=? fun () ->
|
|
||||||
return ()
|
|
||||||
|
|
||||||
let encode_message st msg =
|
let encode_message st msg =
|
||||||
try return (Data_encoding.Binary.to_bytes st.encoding msg)
|
try return (Data_encoding.Binary.to_bytes st.encoding msg)
|
||||||
with _ -> fail Encoding_error
|
with _ -> fail Encoding_error
|
||||||
@ -282,7 +285,7 @@ module Writer = struct
|
|||||||
Lwt_utils.protect ~canceler:st.canceler begin fun () ->
|
Lwt_utils.protect ~canceler:st.canceler begin fun () ->
|
||||||
Lwt_pipe.pop st.messages >>= fun (msg, wakener) ->
|
Lwt_pipe.pop st.messages >>= fun (msg, wakener) ->
|
||||||
encode_message st msg >>=? fun buf ->
|
encode_message st msg >>=? fun buf ->
|
||||||
write_chunk st.conn buf >>= fun res ->
|
Crypto.write_chunk st.conn.fd st.conn.cryptobox_data buf >>= fun res ->
|
||||||
iter_option wakener ~f:(fun u -> Lwt.wakeup_later u res) ;
|
iter_option wakener ~f:(fun u -> Lwt.wakeup_later u res) ;
|
||||||
Lwt.return res
|
Lwt.return res
|
||||||
end >>= function
|
end >>= function
|
||||||
@ -332,11 +335,14 @@ let accept
|
|||||||
?incoming_message_queue_size ?outgoing_message_queue_size
|
?incoming_message_queue_size ?outgoing_message_queue_size
|
||||||
(fd, info, cryptobox_data) encoding =
|
(fd, info, cryptobox_data) encoding =
|
||||||
Lwt_utils.protect begin fun () ->
|
Lwt_utils.protect begin fun () ->
|
||||||
Ack.write fd true >>=? fun () ->
|
Ack.write fd cryptobox_data Ack >>=? fun () ->
|
||||||
Ack.read fd
|
Ack.read fd cryptobox_data
|
||||||
end ~on_error:begin fun err ->
|
end ~on_error:begin fun err ->
|
||||||
P2p_io_scheduler.close fd >>= fun _ ->
|
P2p_io_scheduler.close fd >>= fun _ ->
|
||||||
Lwt.return (Error err)
|
match err with
|
||||||
|
| [ P2p_io_scheduler.Connection_closed ] -> fail Rejected
|
||||||
|
| [ Decipher_error ] -> fail Invalid_auth
|
||||||
|
| err -> Lwt.return (Error err)
|
||||||
end >>=? fun accepted ->
|
end >>=? fun accepted ->
|
||||||
fail_unless accepted Rejected >>=? fun () ->
|
fail_unless accepted Rejected >>=? fun () ->
|
||||||
let canceler = Canceler.create () in
|
let canceler = Canceler.create () in
|
||||||
|
@ -26,6 +26,7 @@ type error += Decoding_error
|
|||||||
type error += Rejected
|
type error += Rejected
|
||||||
type error += Myself of Id_point.t
|
type error += Myself of Id_point.t
|
||||||
type error += Not_enough_proof_of_work of Gid.t
|
type error += Not_enough_proof_of_work of Gid.t
|
||||||
|
type error += Invalid_auth
|
||||||
|
|
||||||
type authenticated_fd
|
type authenticated_fd
|
||||||
(** Type of a connection that successfully passed the authentication
|
(** Type of a connection that successfully passed the authentication
|
||||||
|
@ -83,11 +83,17 @@ let simple_msg =
|
|||||||
|
|
||||||
let is_rejected = function
|
let is_rejected = function
|
||||||
| Error [P2p_connection.Rejected] -> true
|
| Error [P2p_connection.Rejected] -> true
|
||||||
| Ok _ | Error _ -> false
|
| Ok _ -> false
|
||||||
|
| Error err ->
|
||||||
|
log_notice "Error: %a" pp_print_error err ;
|
||||||
|
false
|
||||||
|
|
||||||
let is_connection_closed = function
|
let is_connection_closed = function
|
||||||
| Error [P2p_io_scheduler.Connection_closed] -> true
|
| Error [P2p_io_scheduler.Connection_closed] -> true
|
||||||
| Ok _ | Error _ -> false
|
| Ok _ -> false
|
||||||
|
| Error err ->
|
||||||
|
log_notice "Error: %a" pp_print_error err ;
|
||||||
|
false
|
||||||
|
|
||||||
let bytes_encoding = Data_encoding.Variable.bytes
|
let bytes_encoding = Data_encoding.Variable.bytes
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user