Skip to content

Commit 1e3c9e5

Browse files
committed
Add a test exe for debug
Signed-off-by: Changlei Li <changlei.li@cloud.com>
1 parent a6ecddd commit 1e3c9e5

3 files changed

Lines changed: 164 additions & 0 deletions

File tree

ocaml/libs/stunnel/test/dune

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
(executable
2+
(name test_stunnel)
3+
(libraries
4+
astring
5+
stunnel
6+
threads.posix
7+
unix
8+
xapi-stdext-pervasives
9+
xapi-stdext-unix
10+
uuidm))
11+
12+
(rule
13+
(alias runtest)
14+
(package stunnel)
15+
(action
16+
(run %{exe:test_stunnel.exe})))
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
(*
2+
* Copyright (C) 2025 Cloud Software Group
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU Lesser General Public License as published
6+
* by the Free Software Foundation; version 2.1 only. with the special
7+
* exception on linking described in file LICENSE.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU Lesser General Public License for more details.
13+
*)
14+
15+
let test_unix_socket_path remote_host remote_port verify_cert timeout =
16+
let socket_path = "/tmp/test_stunnel_socket.sock" in
17+
Printf.printf "→ Connecting to %s:%d via unix socket %s\n" remote_host
18+
remote_port socket_path ;
19+
( match verify_cert with
20+
| None ->
21+
Printf.printf "→ Certificate verification: DISABLED\n"
22+
| Some {Stunnel.sni; verify; cert_bundle_path} ->
23+
Printf.printf "→ Certificate verification: ENABLED\n" ;
24+
Printf.printf " - SNI: %s\n"
25+
(match sni with Some s -> s | None -> "(none)") ;
26+
Printf.printf " - Mode: %s\n"
27+
( match verify with
28+
| Stunnel.VerifyPeer ->
29+
"VerifyPeer (pinning)"
30+
| Stunnel.CheckHost ->
31+
"CheckHost (chain validation)"
32+
) ;
33+
Printf.printf " - Cert bundle: %s\n" cert_bundle_path
34+
) ;
35+
36+
try
37+
Stunnel.with_client_proxy_unix_socket ~verify_cert ~remote_host ~remote_port
38+
~unix_socket_path:socket_path (fun ~diagnose_stunnel ->
39+
Printf.printf "✓ Stunnel proxy started successfully\n" ;
40+
41+
(* Try to send data through the socket *)
42+
if Sys.file_exists socket_path then (
43+
Printf.printf "→ Sending 'hello' through unix socket...\n" ;
44+
try
45+
let sock = Unix.socket Unix.PF_UNIX Unix.SOCK_STREAM 0 in
46+
Unix.connect sock (Unix.ADDR_UNIX socket_path) ;
47+
let msg = "hello\n" in
48+
let sent = Unix.send_substring sock msg 0 (String.length msg) [] in
49+
Printf.printf "✓ Sent %d bytes through socket\n" sent ;
50+
51+
(* Try to read response *)
52+
let buf = Bytes.create 1024 in
53+
let _ = Unix.setsockopt_float sock Unix.SO_RCVTIMEO timeout in
54+
( try
55+
let n = Unix.recv sock buf 0 1024 [] in
56+
if n > 0 then
57+
Printf.printf "✓ Received %d bytes: %s\n" n
58+
(Bytes.sub_string buf 0 n)
59+
else
60+
Printf.printf "→ Connection closed by remote\n"
61+
with
62+
| Unix.Unix_error (Unix.EAGAIN, _, _)
63+
| Unix.Unix_error (Unix.EWOULDBLOCK, _, _)
64+
->
65+
Printf.printf "→ No response received (timeout)\n"
66+
) ;
67+
Unix.close sock
68+
with e ->
69+
Printf.printf "✗ Socket communication error: %s\n"
70+
(Printexc.to_string e)
71+
) ;
72+
match diagnose_stunnel () with
73+
| Ok () ->
74+
Printf.printf "✓ Stunnel operation completed successfully\n"
75+
| Error (Stunnel.Certificate_verify reason) ->
76+
Printf.printf "✗ Certificate verification failed: %s\n" reason
77+
| Error (Stunnel.Stunnel reason) ->
78+
Printf.printf "✗ Stunnel error: %s\n" reason
79+
| Error (Stunnel.Unknown reason) ->
80+
Printf.printf "✗ Unknown error: %s\n" reason
81+
)
82+
with e -> Printf.printf "✗ Exception: %s\n" (Printexc.to_string e)
83+
84+
let () =
85+
let remote_host = ref "example.com" in
86+
let remote_port = ref 443 in
87+
let cert_bundle = ref None in
88+
let verify_mode = ref "none" in
89+
let sni = ref None in
90+
let timeout = ref 10.0 in
91+
92+
let usage_msg =
93+
"test_stunnel [options]\n\
94+
Test stunnel unix socket proxy with optional certificate verification"
95+
in
96+
let speclist =
97+
[
98+
( "--host"
99+
, Arg.Set_string remote_host
100+
, "Remote host (default: example.com)"
101+
)
102+
; ("--port", Arg.Set_int remote_port, "Remote port (default: 443)")
103+
; ( "--cert-bundle"
104+
, Arg.String (fun s -> cert_bundle := Some s)
105+
, "Path to PEM certificate bundle file"
106+
)
107+
; ( "--verify"
108+
, Arg.Symbol (["none"; "peer"; "chain"], fun s -> verify_mode := s)
109+
, "Verification mode: none (default), peer (pinning), chain (with \
110+
--check-host)"
111+
)
112+
; ( "--sni"
113+
, Arg.String (fun s -> sni := Some s)
114+
, "Server Name Indication hostname"
115+
)
116+
; ( "--timeout"
117+
, Arg.Set_float timeout
118+
, "Socket receive timeout in seconds (default: 10.0)"
119+
)
120+
]
121+
in
122+
123+
Arg.parse speclist (fun _ -> ()) usage_msg ;
124+
125+
let verify_cert =
126+
match (!verify_mode, !cert_bundle) with
127+
| "none", _ ->
128+
None
129+
| _, None ->
130+
Printf.eprintf
131+
"Error: --cert-bundle required when verification is enabled\n" ;
132+
exit 1
133+
| "peer", Some path ->
134+
Some
135+
{
136+
Stunnel.sni= !sni
137+
; verify= Stunnel.VerifyPeer
138+
; cert_bundle_path= path
139+
}
140+
| "chain", Some path ->
141+
Some
142+
{Stunnel.sni= !sni; verify= Stunnel.CheckHost; cert_bundle_path= path}
143+
| _ ->
144+
Printf.eprintf "Error: invalid verify mode\n" ;
145+
exit 1
146+
in
147+
148+
test_unix_socket_path !remote_host !remote_port verify_cert !timeout

ocaml/libs/stunnel/test/test_stunnel.mli

Whitespace-only changes.

0 commit comments

Comments
 (0)