1313 *)
1414(* Copyright (C) 2007 XenSource Inc *)
1515
16- module D = Debug. Make (struct let name = " stunnel" end )
16+ (* module D = Debug.Make (struct let name = "stunnel" end) *)
17+ module D = struct
18+ let debug fmt = Printf. ksprintf (fun s -> Printf. printf " %s\n " s) fmt
19+
20+ let error fmt = Printf. ksprintf (fun s -> Printf. printf " %s\n " s) fmt
21+ end
1722
1823open Printf
1924open Xapi_stdext_unix
@@ -135,11 +140,6 @@ type t = {
135140 ; verified : verification_config option
136141}
137142
138- type stunnel_error =
139- | Certificate_verify of string list
140- | Stunnel of string
141- | Unknown of string
142-
143143let appliance =
144144 {
145145 sni= None
@@ -501,134 +501,21 @@ let with_client_proxy_systemd_service ~verify_cert ~remote_host ~remote_port
501501 )
502502 (fun () -> Unixext. unlink_safe conf_path)
503503
504- type log_line_status = Continue | LineFound | LineError of stunnel_error
505-
506- type log_scan_result =
507- | End of int
508- | ScanError of stunnel_error * int
509- | ScanFound of int
510-
511- let try_iter f lst =
512- let rec aux = function
513- | [] ->
514- Continue
515- | x :: xs -> (
516- match f x with Continue -> aux xs | other -> other
517- )
518- in
519- aux lst
520-
521- (* * Monadic bind for log_line_status composition *)
522- let ( >>= ) check1 check2 line =
523- match check1 line with Continue -> check2 line | other -> other
524-
525- let check_stunnel_error line =
526- [
527- " Configuration failed"
528- ; " Connection refused"
529- ; " No host resolved"
530- ; " No route to host"
531- ; " Invalid argument"
532- ; " Address already in use"
533- ]
534- |> try_iter (fun s ->
535- if Astring.String. is_infix ~affix: s line then
536- LineError (Stunnel s)
537- else
538- Continue
539- )
540-
541- let check_verify_error cert_errors line =
542- (* When verified with a mismatched certificate, one line of log from stunnel
543- * would look like:
544- SSL_connect: ssl/statem/statem_clnt.c:1889: error:0A000086:SSL routines::certificate verify failed
545- * in this case, Stunnel_verify_error can be raised with detailed error as
546- * reason if it can found in the log *)
547- if Astring.String. is_infix ~affix: " certificate verify failed" line then
548- LineError (Certificate_verify cert_errors)
549- else
550- Continue
551-
552- (* * Stream through lines from a specific position, applying function to each.
553- Returns new_position. Stops early on Error. *)
554- let stream_from_position (filepath : string ) (start_pos : int )
555- (f : string -> log_line_status ) : log_scan_result =
556- try
557- let fd = Unix. openfile filepath [Unix. O_RDONLY ] 0 in
558- let finally = Xapi_stdext_pervasives.Pervasiveext. finally in
559- finally
560- (fun () ->
561- let _ = Unix. lseek fd start_pos Unix. SEEK_SET in
562- let ic = Unix. in_channel_of_descr fd in
563- let rec loop () =
564- match input_line ic with
565- | exception End_of_file ->
566- let end_pos = (Unix. fstat fd).Unix. st_size in
567- End end_pos
568- | line -> (
569- match f line with
570- | Continue ->
571- loop ()
572- | LineError e ->
573- let pos = Unix. lseek fd 0 Unix. SEEK_CUR in
574- ScanError (e, pos)
575- | LineFound ->
576- let pos = Unix. lseek fd 0 Unix. SEEK_CUR in
577- ScanFound pos
578- )
579- in
580- loop ()
581- )
582- (fun () -> Unix. close fd)
583- with
584- | Unix. Unix_error (err , fn , arg ) ->
585- ScanError
586- ( Stunnel (Printf. sprintf " %s: %s(%s)" (Unix. error_message err) fn arg)
587- , start_pos )
588- | e ->
589- ScanError (Stunnel (Printexc. to_string e), start_pos)
590-
591- let check_stunnel_logfile_from_position logfile start_pos =
592- let cert_errors = ref [] in
593- let check_line line =
594- ! stunnel_logger line ;
595- Astring.String. cut ~rev: true ~sep: " CERT: " line
596- |> Option. iter (fun (_ , cert_error ) ->
597- cert_errors := cert_error :: ! cert_errors
598- ) ;
599- match check_verify_error ! cert_errors line with
600- | Continue ->
601- check_stunnel_error line
602- | other ->
603- other
604- in
605- stream_from_position logfile start_pos check_line
606-
607504let diagnose_failure st_proc =
608- match check_stunnel_logfile_from_position st_proc.logfile 0 with
505+ let open Stunnel_log_scanner in
506+ match
507+ check_stunnel_logfile_from_position
508+ (fun s -> ! stunnel_logger s)
509+ st_proc.logfile 0
510+ with
609511 | End _ | ScanFound _ ->
610512 ()
611- | ScanError (Certificate_verify reasons , _pos ) ->
513+ | ScanError (Stunnel_error. Certificate_verify reasons , _pos ) ->
612514 raise (Stunnel_verify_error reasons)
613- | ScanError (Stunnel reason , _pos ) | ScanError (Unknown reason , _pos ) ->
515+ | ScanError (Stunnel_error. Stunnel reason, _pos)
516+ | ScanError (Stunnel_error. Unknown reason , _pos ) ->
614517 raise (Stunnel_error reason)
615518
616- (* check stunnel log, until *)
617- let check_stunnel_log_until logfile check_line interval count start_pos =
618- let rec check ~max_retries cnt start_pos =
619- Thread. delay interval ;
620- match stream_from_position logfile start_pos check_line with
621- | End new_pos when cnt < = max_retries ->
622- check ~max_retries (cnt + 1 ) new_pos
623- | ScanError (e , _pos ) ->
624- Error e
625- | ScanFound new_pos ->
626- Ok new_pos
627- | End _ ->
628- Error (Stunnel " Timed out waiting for stunnel condition" )
629- in
630- check ~max_retries: count 0 start_pos
631-
632519module UnixSocketProxy = struct
633520 (* * Handle for a long-running stunnel proxy *)
634521 type t = {
@@ -653,7 +540,7 @@ module UnixSocketProxy = struct
653540 let diagnose handle =
654541 let start_pos = handle.last_checked_position in
655542 let current_size = (Unix. stat handle.proxy_logfile).Unix. st_size in
656-
543+ let open Stunnel_log_scanner in
657544 if current_size < = start_pos then (
658545 D. debug " %s: no new log entries (position %d)" __FUNCTION__ start_pos ;
659546 Ok ()
@@ -675,7 +562,9 @@ module UnixSocketProxy = struct
675562 )
676563 (fun () -> Unix. close fd) ;
677564 match
678- check_stunnel_logfile_from_position handle.proxy_logfile start_pos
565+ check_stunnel_logfile_from_position
566+ (fun s -> ! stunnel_logger s)
567+ handle.proxy_logfile start_pos
679568 with
680569 | End pos | ScanFound pos ->
681570 handle.last_checked_position < - pos ;
@@ -686,24 +575,18 @@ module UnixSocketProxy = struct
686575 )
687576
688577 let wait_for_init_done logfile =
689- let check_init_success line =
690- if Astring.String. is_infix ~affix: " Configuration successful" line then
691- LineFound
692- else
693- Continue
694- in
695- let check_line = check_init_success >> = check_stunnel_error in
578+ let open Stunnel_log_scanner in
579+ let check_line = check_configuration_success >> = check_stunnel_error in
696580 check_stunnel_log_until logfile check_line 1.0 3 0
697581
698582 let wait_for_connection_done logfile start_pos =
699- let certs = ref [] in
700- let connected line =
701- if Astring.String. is_infix ~affix: " connected remote server from " line then
702- LineFound
703- else
704- Continue
583+ let open Stunnel_log_scanner in
584+ let check_verify_error = make_check_verify_error () in
585+ let check_line =
586+ check_connection_established
587+ >> = check_verify_error
588+ >> = check_stunnel_error
705589 in
706- let check_line = connected >> = check_verify_error ! certs in
707590 check_stunnel_log_until logfile check_line 1.0 10 start_pos
708591
709592 (* * Start a long-running stunnel proxy listening on a UNIX socket.
@@ -719,8 +602,9 @@ module UnixSocketProxy = struct
719602 is not started. If successful, subsequent connections by stubs will also
720603 be verified automatically by stunnel. *)
721604 let start ~verify_cert ~remote_host ~remote_port ?unix_socket_path
722- ?socket_mode () =
605+ ?socket_mode ?( test_connection = true ) () =
723606 let ( let * ) = Result. bind in
607+ let open Stunnel_error in
724608 let unix_socket_path =
725609 match unix_socket_path with
726610 | Some path ->
@@ -781,22 +665,28 @@ module UnixSocketProxy = struct
781665 D. debug " %s: started stunnel proxy (pid:%d):%s -> %s:%d log: %s"
782666 __FUNCTION__ (getpid pid) unix_socket_path remote_host remote_port logfile ;
783667
784- (* Make initial connection to verify certificate *)
785- let sock = Unix. socket Unix. PF_UNIX Unix. SOCK_STREAM 0 in
786- let finally = Xapi_stdext_pervasives.Pervasiveext. finally in
668+ (* Optionally make initial connection to verify certificate *)
787669 let * pos =
788- finally
789- (fun () ->
790- Unix. connect sock (Unix. ADDR_UNIX unix_socket_path) ;
791- (* Wait for TLS handshake and certificate verification *)
792- wait_for_connection_done logfile pos
793- |> Result. map_error (fun e ->
794- D. error " %s: stunnel connection failed" __FUNCTION__ ;
795- clean_up () ;
796- e
670+ if test_connection then (
671+ D. debug " %s: performing initial connection test" __FUNCTION__ ;
672+ let sock = Unix. socket Unix. PF_UNIX Unix. SOCK_STREAM 0 in
673+ let finally = Xapi_stdext_pervasives.Pervasiveext. finally in
674+ finally
675+ (fun () ->
676+ Unix. connect sock (Unix. ADDR_UNIX unix_socket_path) ;
677+ (* Wait for TLS handshake and certificate verification *)
678+ wait_for_connection_done logfile pos
679+ |> Result. map_error (fun e ->
680+ D. error " %s: stunnel connection failed" __FUNCTION__ ;
681+ clean_up () ;
682+ e
683+ )
797684 )
798- )
799- (fun () -> Unix. close sock)
685+ (fun () -> Unix. close sock)
686+ ) else (
687+ D. debug " %s: skipping initial connection test" __FUNCTION__ ;
688+ Ok pos
689+ )
800690 in
801691
802692 let handle =
@@ -829,10 +719,10 @@ module UnixSocketProxy = struct
829719 If [socket_mode] is provided, stunnel will set the socket file permissions.
830720 This is the preferred way to use the proxy for most use cases. *)
831721 let with_proxy ~verify_cert ~remote_host ~remote_port ?unix_socket_path
832- ?socket_mode f =
722+ ?socket_mode ? test_connection f =
833723 match
834724 start ~verify_cert ~remote_host ~remote_port ?unix_socket_path
835- ?socket_mode ()
725+ ?socket_mode ?test_connection ()
836726 with
837727 | Error _ as e ->
838728 e
0 commit comments