-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathscan.ml
101 lines (90 loc) · 2.71 KB
/
scan.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
97
98
99
100
101
type port_status =
| Open
| Closed
| Timed_out
| Error of Unix.error
type probe_result =
{ ipaddr : Unix.inet_addr
; port : int
; status : port_status }
let (results, push_result) = Lwt_stream.create ()
let addr_gen prefix port_min port_max =
let open BatEnum in
let enum =
cartesian_product
(from_while (Addr.network_gen prefix))
(range port_min ~until:port_max)
in
fun () -> get enum
let addrs ~slots network port_min port_max =
let generator = addr_gen network port_min port_max in
Lwt_stream.from (fun () ->
let%lwt () = Semaphore.wait slots in
Lwt.return (generator ()))
let try_connect ~timeout (ipaddr, port) =
let fd =
try Lwt_unix.(socket PF_INET SOCK_STREAM 0)
with Unix.Unix_error (Unix.EMFILE, _, _) ->
failwith "Too many open sockets"
in
try%lwt
let%lwt () =
Lwt_io.printf "Trying %s:%d\n" (Unix.string_of_inet_addr ipaddr) port
in
let%lwt () =
Lwt_unix.with_timeout timeout (fun () ->
Lwt_unix.(connect fd (ADDR_INET (ipaddr, port))))
in
let%lwt () = Lwt_unix.close fd in
Lwt.return Open
with
| Lwt_unix.Timeout ->
let%lwt () = Lwt_unix.close fd in
Lwt.return Timed_out
| Unix.Unix_error (Unix.ECONNREFUSED, _, _) ->
let%lwt () = Lwt_unix.close fd in
Lwt.return Closed
| Unix.Unix_error (e, _, _) ->
let%lwt () = Lwt_unix.close fd in
Lwt.return (Error e)
let probe ~slots ~timeout (ipaddr, port) =
let%lwt status = try_connect ~timeout (ipaddr, port) in
let%lwt () = Semaphore.post slots in
Lwt.return (push_result (Some {ipaddr; port; status}))
let string_of_status = function
| Open -> "open"
| Closed -> "closed"
| Timed_out -> "timed out"
| Error e -> Printf.sprintf "error: %s" (Unix.error_message e)
let string_of_result r =
Printf.sprintf "%s:%d -> %s"
(Unix.string_of_inet_addr r.ipaddr)
r.port
(string_of_status r.status)
let main network port_min port_max =
let slots = Semaphore.create 1000 in
Lwt.join
[ (let%lwt () =
Lwt_stream.iter_p (probe ~slots ~timeout:1.)
(addrs ~slots network port_min port_max)
in
push_result None;
Lwt.return_unit)
; Lwt_stream.iter_s
(fun r -> Lwt_io.printf "Result: %s\n" (string_of_result r))
results ]
let usage () =
Printf.printf "Usage: %s {network} {port_min} {port_max}\n" Sys.argv.(0);
exit 1
let () =
if Array.length Sys.argv < 4 then usage ();
let network =
match Addr.network_of_string Sys.argv.(1) with
| Some n -> n
| None ->
Printf.printf "Invalid network\n";
usage ()
in
let port_min = int_of_string Sys.argv.(2) in
let port_max = int_of_string Sys.argv.(3) in
Lwt_main.run (main network port_min port_max)