Skip to content

Instantly share code, notes, and snippets.

@jmsdnns
Created February 3, 2025 00:14
Show Gist options
  • Save jmsdnns/bc5edf4c2ef319f35d511d58c4988325 to your computer and use it in GitHub Desktop.
Save jmsdnns/bc5edf4c2ef319f35d511d58c4988325 to your computer and use it in GitHub Desktop.
A port scanner in Ocaml. Rudimentary form done to learn how Ocaml does networking.
module Scanner = struct
(* attempt to open a port and return an option *)
let open_port host port timeout = fun () ->
let open Lwt.Infix in
let sockaddr = Unix.ADDR_INET (Unix.inet_addr_of_string host, port) in
let socket = Lwt_unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in
Lwt.catch
(* Port is open *)
(fun () ->
Lwt_unix.connect socket sockaddr >>= fun () ->
Lwt_unix.close socket >>= fun () ->
Lwt.return (Some port)
)
(* Port is closed *)
(fun _ ->
Lwt_unix.close socket >>= fun () ->
Lwt.return None
)
(* scans a port by trying to open it or timing out *)
let scan_port host port timeout =
let open Lwt.Infix in
let connect_task = open_port host port timeout in
let timeout_task = Lwt_unix.sleep timeout >>= fun () -> Lwt.fail Lwt_unix.Timeout in
Lwt.pick [connect_task (); timeout_task] >>= function
| Some port -> Lwt.return (Some port)
| None -> Lwt.return None
(* scans a range of port *)
let scan_ports host start_port end_port timeout =
let open Lwt.Infix in
let ports = List.init (end_port - start_port + 1) (fun i -> start_port + i) in
let scan_results =
List.map (fun port ->
scan_port host port timeout >>= function
| Some port -> Printf.printf "Port %d is open\n" port; Lwt.return ()
| None -> Printf.printf "Port %d is closed\n" port; Lwt.return ()
) ports
in
Lwt.join scan_results
end
let () =
let host = "127.0.0.1" in
let start_port = 8000 in
let end_port = 8090 in
let timeout = 2.0 in
let open Lwt.Infix in
Lwt_main.run (
Scanner.scan_ports host start_port end_port timeout >>= fun () -> Lwt.return ()
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment