diff --git a/bob.opam b/bob.opam index 9536e84..ac80360 100644 --- a/bob.opam +++ b/bob.opam @@ -42,5 +42,5 @@ depends: [ ] pin-depends: [ - [ "socks.dev" "git+https://github.com/dinosaure/ocaml-socks.git#31399dab6812cb3fbf28b9eea5c5e4a3939abe4b" ] + [ "socks.dev" "git+https://github.com/cfcs/ocaml-socks.git#c46ed399df18307e5240457b9d5d4ff8a6739f06" ] ] diff --git a/com.opam b/com.opam index b1e46ce..ce06eb1 100644 --- a/com.opam +++ b/com.opam @@ -54,7 +54,7 @@ pin-depends: [ [ "mirage-crypto-ec.dev" "git+https://github.com/dinosaure/mirage-crypto.git#b3682240f92453c8300298ff3e197af44f155d80" ] [ "mirage-crypto-rng.dev" "git+https://github.com/dinosaure/mirage-crypto.git#b3682240f92453c8300298ff3e197af44f155d80" ] [ "mtime.dev" "git+https://github.com/dinosaure/mtime.git#d5d70f38c40da90e3e173eb60346df55b64a4a0a"] - [ "socks.dev" "git+https://github.com/dinosaure/ocaml-socks.git#31399dab6812cb3fbf28b9eea5c5e4a3939abe4b" ] + [ "socks.dev" "git+https://github.com/cfcs/ocaml-socks.git#c46ed399df18307e5240457b9d5d4ff8a6739f06" ] ] x-mirage-opam-lock-location: "com.opam.locked" diff --git a/lib/bob_socks.ml b/lib/bob_socks.ml index 4beae87..1c3a8a1 100644 --- a/lib/bob_socks.ml +++ b/lib/bob_socks.ml @@ -185,6 +185,15 @@ let finally_connect_socks5 socket payload dst = in go payload +let parse_socks5_response payload = + match (payload.[0], String.length payload >= 2) with + | '\x05', true -> + let leftover = String.sub payload 2 (String.length payload - 2) in + Ok (Socks.socks5_authentication_method_of_char payload.[1], leftover) + | '\x05', false -> Error `Incomplete_response + | _ -> Error `Invalid_response + | exception _ -> Error `Incomplete_response + let connect_socks5 ~happy_eyeballs ~credential ~addr dst = let open Fiber in Bob_happy_eyeballs.connect happy_eyeballs addr >>? fun (_sockaddr, socket) -> @@ -199,16 +208,10 @@ let connect_socks5 ~happy_eyeballs ~credential ~addr dst = >>| open_write_error >>? fun () -> let rec go payload = - match Socks.parse_socks5_username_password_response payload with - | Ok (No_acceptable_methods, _) -> - Fiber.return - (Error - (`Msg - "No acceptable authentication methods for the SOCKSv5 server")) - | Ok (No_authentication_required, leftover) when credential = None -> + match parse_socks5_response payload with + | Ok (No_authentication_required, leftover) -> Fiber.return (Ok (`No_authentication_required leftover)) - | Ok (Username_password (_username, _password), leftover) - when credential <> None -> + | Ok (Username_password _, leftover) when credential <> None -> let username_password_req = match credential with | None | Username _ -> assert false @@ -217,12 +220,13 @@ let connect_socks5 ~happy_eyeballs ~credential ~addr dst = |> Result.get_ok in Fiber.return (Ok (`Authentication (username_password_req, leftover))) - | Ok (_, _) -> + | Ok _ -> Fiber.return - (Error (`Msg "Unexpected response from the SOCKSv5 server.")) - | Error `Invalid_request -> + (error_msgf + "No acceptable authentication methods for the SOCKSv5 server") + | Error `Invalid_response -> Fiber.return (Error (`Msg "Invalid response from the SOCKSv5 server")) - | Error `Incomplete_request -> ( + | Error `Incomplete_response -> ( Fiber.read socket >>| reword_error (fun err -> `Unix err) >>? function | `End -> Fiber.return @@ -237,18 +241,20 @@ let connect_socks5 ~happy_eyeballs ~credential ~addr dst = >>| open_write_error >>? fun () -> let rec go payload = - if String.length payload < 2 then - Fiber.read socket >>| reword_error (fun err -> `Unix err) >>? function - | `End -> - Fiber.return - (Error (`Msg "Incomplete response from SOCKSv5 server")) - | `Data bs -> go (payload ^ bigstring_to_string bs) - else - match String.sub payload 0 2 with - | "\x01\x00" -> - Fiber.return - (Ok (String.sub payload 2 (String.length payload - 2))) - | _ -> Fiber.return (Error (`Msg "Invalid username/password")) + match Socks.parse_socks5_username_password_response payload with + | Ok (true, leftover) -> Fiber.return (Ok leftover) + | Ok (false, _leftover) -> + Fiber.return (Error (`Msg "Invalid username/password")) + | Error `Invalid_request -> + Fiber.return + (Error (`Msg "Invalid response from the SOCKSv5 server")) + | Error `Incomplete_request -> ( + Fiber.read socket >>| reword_error (fun err -> `Unix err) + >>? function + | `End -> + Fiber.return + (Error (`Msg "Incomplete response from SOCKSv5 server")) + | `Data bs -> go (payload ^ bigstring_to_string bs)) in go payload >>? fun payload -> finally_connect_socks5 socket payload dst | `No_authentication_required payload ->