package vcaml

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file mitm_debugger.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
open! Core
open! Async



module Info = struct
  type t =
    | To_client of string
    | From_client of string

  let to_color = function
    | From_client _ -> `Red
    | To_client _ -> `Green
  ;;

  let to_string t =
    let dir_pipe_name =
      match t with
      | To_client st -> Printf.sprintf "< %s" st
      | From_client st -> Printf.sprintf "> %s" st
    in
    Console.Ansi.string_with_attr [ to_color t ] dir_pipe_name
  ;;
end

let print_with_passthrough info writer msg =
  print_endline (Info.to_string info);
  print_s ([%sexp_of: Msgpack.t] msg);
  Async.Writer.write writer (Msgpack.string_of_t_exn msg);
  return ()
;;

let debug_messages info ~to_:reader ~from:writer =
  Angstrom_async.parse_many
    Msgpack.Internal.Parser.msg
    (print_with_passthrough info writer)
    reader
  |> Deferred.ignore_m
;;

let start_server ~host_pipe ~client_pipe =
  let host_socket = Tcp.Where_to_listen.of_file host_pipe in
  let client_socket = Tcp.Where_to_connect.of_file client_pipe in
  Tcp.Server.create
    ~on_handler_error:`Raise
    host_socket
    (fun _host_addr host_reader host_writer ->
       let%bind _client_addr, client_reader, client_writer = Tcp.connect client_socket in
       let rpc =
         Msgpack_rpc.create ~on_error:(fun error ->
           error |> Msgpack_rpc.Error.to_error |> Error.raise)
       in
       let (_ : [ `connected ] Msgpack_rpc.t) =
         Msgpack_rpc.connect
           rpc
           client_reader
           client_writer
           ~close_reader_and_writer_on_disconnect:true
       in
       Deferred.all_unit
         [ debug_messages (To_client client_pipe) ~to_:client_reader ~from:host_writer
         ; debug_messages (From_client client_pipe) ~to_:host_reader ~from:client_writer
         ])
;;

let run_prog_with_fresh_pipe ~prog ~pipe =
  let tmp_dir = Filename_unix.temp_dir ~perm:0o777 "mitm" "pipe" in
  let tmp_pipe = Filename.concat tmp_dir "tmp.pipe" in
  let%bind connection = start_server ~host_pipe:tmp_pipe ~client_pipe:pipe in
  let%bind output =
    Process.run_exn
      ~prog:"bash"
      ~args:[ "-c"; prog ]
      ~env:(`Extend [ "NVIM_LISTEN_ADDRESS", tmp_pipe; "MITM_ADDRESS", tmp_pipe ])
      ()
  in
  printf "\nProcess terminated. Output:\n%s\n" output;
  Tcp.Server.close connection
;;

let main =
  Command.async
    ~summary:"debug msgpack unix sockets by serving as a man-in-the-middle"
    (let%map_open.Command () = return ()
     and original_pipe =
       flag
         "-socket"
         (optional_with_default
            (Sys.getenv_exn "NVIM_LISTEN_ADDRESS")
            Filename_unix.arg_type)
         ~doc:"the unix socket that we should intercept messages to"
     and prog =
       flag "-cmd" (required string) ~doc:"the command to run and intercept messages from"
     in
     fun () -> run_prog_with_fresh_pipe ~prog ~pipe:original_pipe)
;;
OCaml

Innovation. Community. Security.