1use std::{
13 cell::RefCell,
14 collections::{BTreeMap, HashMap, hash_map::Entry},
15 io::ErrorKind,
16 net::{Shutdown, SocketAddr as StdSocketAddr},
17 os::unix::io::AsRawFd,
18 rc::{Rc, Weak},
19 str::{from_utf8, from_utf8_unchecked},
20 sync::Arc,
21 time::{Duration, Instant},
22};
23
24use mio::{
25 Interest, Registry, Token,
26 net::{TcpListener as MioTcpListener, TcpStream as MioTcpStream},
27 unix::SourceFd,
28};
29use rustls::{
30 CipherSuite, ProtocolVersion, ServerConfig as RustlsServerConfig, ServerConnection,
31 SupportedCipherSuite, crypto::CryptoProvider,
32};
33use rusty_ulid::Ulid;
34use sozu_command::{
35 certificate::Fingerprint,
36 config::{DEFAULT_ALPN_PROTOCOLS, DEFAULT_CIPHER_LIST},
37 proto::command::{
38 AddCertificate, CertificateSummary, CertificatesByAddress, Cluster, HttpsListenerConfig,
39 ListOfCertificatesByAddress, ListenerType, RemoveCertificate, RemoveListener,
40 ReplaceCertificate, RequestHttpFrontend, ResponseContent, TlsVersion,
41 UpdateHttpsListenerConfig, WorkerRequest, WorkerResponse, request::RequestType,
42 response_content::ContentType,
43 },
44 ready::Ready,
45 response::HttpFrontend,
46 state::{
47 ClusterId, validate_alpn_protocols, validate_h2_flood_knobs_https, validate_sozu_id_header,
48 },
49};
50
51use crate::metrics::names;
52use crate::{
53 AcceptError, CachedTags, FrontendFromRequestError, L7ListenerHandler, L7Proxy, ListenerError,
54 ListenerHandler, Protocol, ProxyConfiguration, ProxyError, ProxySession, SessionIsToBeClosed,
55 SessionMetrics, SessionResult, StateMachineBuilder, StateResult,
56 backends::BackendMap,
57 crypto::{cipher_suite_by_name, default_provider, kx_group_by_name},
58 pool::Pool,
59 protocol::{
60 Pipe, SessionState,
61 http::answers::HttpAnswers,
62 http::parser::{Method, hostname_and_port},
63 mux::{self, Mux, MuxTls},
64 proxy_protocol::expect::ExpectProxyProtocol,
65 rustls::TlsHandshake,
66 },
67 router::{RouteResult, Router},
68 server::{ListenToken, SessionManager},
69 socket::{FrontRustls, server_bind},
70 timer::TimeoutContainer,
71 tls::MutexCertificateResolver,
72 util::UnwrapLog,
73};
74
75StateMachineBuilder! {
76 enum HttpsStateMachine impl SessionState {
83 Expect(ExpectProxyProtocol<MioTcpStream>, ServerConnection),
84 Handshake(TlsHandshake),
85 Mux(MuxTls),
86 WebSocket(Pipe<FrontRustls, HttpsListener>),
87 }
88}
89
90enum AlpnProtocol {
91 H2,
92 Http11,
93}
94
95#[cfg(debug_assertions)]
100fn https_stage_rank(marker: StateMarker) -> u8 {
101 match marker {
102 StateMarker::Expect => 0,
103 StateMarker::Handshake => 1,
104 StateMarker::Mux => 2,
105 StateMarker::WebSocket => 3,
106 }
107}
108
109macro_rules! log_module_context {
116 () => {{
117 let (open, reset, _, _, _) = sozu_command::logging::ansi_palette();
118 format!("{open}HTTPS{reset}\t >>>", open = open, reset = reset)
119 }};
120}
121
122macro_rules! log_context {
128 ($self:expr) => {{
129 let (open, reset, grey, gray, white) = sozu_command::logging::ansi_palette();
130 format!(
131 "{open}HTTPS{reset}\t{grey}Session{reset}({gray}frontend{reset}={white}{frontend}{reset}, {gray}peer{reset}={white}{peer}{reset})\t >>>",
132 open = open,
133 reset = reset,
134 grey = grey,
135 gray = gray,
136 white = white,
137 frontend = $self.frontend_token.0,
138 peer = $self.peer_address.map(|a| a.to_string()).unwrap_or_else(|| "<none>".to_string()),
139 )
140 }};
141}
142
143pub struct HttpsSession {
144 configured_backend_timeout: Duration,
145 configured_connect_timeout: Duration,
146 configured_frontend_timeout: Duration,
147 frontend_token: Token,
148 has_been_closed: bool,
149 last_event: Instant,
150 listener: Rc<RefCell<HttpsListener>>,
151 metrics: SessionMetrics,
152 peer_address: Option<StdSocketAddr>,
153 pool: Weak<RefCell<Pool>>,
154 proxy: Rc<RefCell<HttpsProxy>>,
155 public_address: StdSocketAddr,
156 state: HttpsStateMachine,
157}
158
159impl HttpsSession {
160 #[allow(clippy::too_many_arguments)]
161 pub fn new(
162 configured_backend_timeout: Duration,
163 configured_connect_timeout: Duration,
164 configured_frontend_timeout: Duration,
165 configured_request_timeout: Duration,
166 expect_proxy: bool,
167 listener: Rc<RefCell<HttpsListener>>,
168 pool: Weak<RefCell<Pool>>,
169 proxy: Rc<RefCell<HttpsProxy>>,
170 public_address: StdSocketAddr,
171 rustls_details: ServerConnection,
172 sock: MioTcpStream,
173 token: Token,
174 wait_time: Duration,
175 ) -> HttpsSession {
176 debug_assert!(
181 !configured_request_timeout.is_zero(),
182 "HTTPS session request timeout must be non-zero (would arm an immediate deadline)"
183 );
184 debug_assert!(
185 !configured_frontend_timeout.is_zero() && !configured_backend_timeout.is_zero(),
186 "HTTPS session front/back timeouts must be non-zero"
187 );
188
189 let peer_address = if expect_proxy {
190 None
192 } else {
193 sock.peer_addr().ok()
194 };
195
196 let request_id = Ulid::generate();
197 let container_frontend_timeout = TimeoutContainer::new(configured_request_timeout, token);
198
199 let state = if expect_proxy {
200 trace!("{} starting in expect proxy state", log_module_context!());
201 gauge_add!(names::protocol::PROXY_EXPECT, 1);
202 HttpsStateMachine::Expect(
203 ExpectProxyProtocol::new(container_frontend_timeout, sock, token, request_id),
204 rustls_details,
205 )
206 } else {
207 gauge_add!(names::protocol::TLS_HANDSHAKE, 1);
208 HttpsStateMachine::Handshake(TlsHandshake::new(
209 container_frontend_timeout,
210 rustls_details,
211 sock,
212 token,
213 request_id,
214 peer_address,
215 ))
216 };
217
218 debug_assert_eq!(
223 matches!(state, HttpsStateMachine::Expect(..)),
224 expect_proxy,
225 "fresh HTTPS session must start in Expect iff expect_proxy is set"
226 );
227 debug_assert!(
228 expect_proxy || matches!(state, HttpsStateMachine::Handshake(_)),
229 "non-expect-proxy HTTPS session must start in the TLS Handshake state"
230 );
231 debug_assert!(
232 !expect_proxy || peer_address.is_none(),
233 "expect-proxy peer address is only known after the PROXY header is parsed"
234 );
235
236 let metrics = SessionMetrics::new(Some(wait_time));
237 HttpsSession {
238 configured_backend_timeout,
239 configured_connect_timeout,
240 configured_frontend_timeout,
241 frontend_token: token,
242 has_been_closed: false,
243 last_event: Instant::now(),
244 listener,
245 metrics,
246 peer_address,
247 pool,
248 proxy,
249 public_address,
250 state,
251 }
252 }
253
254 pub fn upgrade(&mut self) -> SessionIsToBeClosed {
255 debug!("{} upgrade", log_context!(self));
256 #[cfg(debug_assertions)]
262 let from_marker = self.state.marker();
263 let new_state = match self.state.take() {
264 HttpsStateMachine::Expect(expect, ssl) => self.upgrade_expect(expect, ssl),
265 HttpsStateMachine::Handshake(handshake) => self.upgrade_handshake(handshake),
266 HttpsStateMachine::Mux(mux) => self.upgrade_mux(mux),
267 HttpsStateMachine::WebSocket(wss) => self.upgrade_websocket(wss),
268 HttpsStateMachine::FailedUpgrade(_) => {
269 error!(
273 "{} upgrade called on FailedUpgrade state; closing session",
274 log_context!(self)
275 );
276 None
277 }
278 };
279
280 match new_state {
281 Some(state) => {
282 #[cfg(debug_assertions)]
292 debug_assert!(
293 https_stage_rank(state.marker()) > https_stage_rank(from_marker)
294 || matches!(from_marker, StateMarker::WebSocket),
295 "HTTPS upgrade must advance the lifecycle (from {:?} to {:?})",
296 from_marker,
297 state.marker()
298 );
299 debug_assert!(
300 !state.failed(),
301 "a successful HTTPS upgrade must not yield a FailedUpgrade state"
302 );
303 self.state = state;
304 false
305 }
306 None => {
308 debug_assert!(
312 self.state.failed(),
313 "a refused HTTPS upgrade must leave the state in FailedUpgrade"
314 );
315 #[cfg(debug_assertions)]
317 debug_assert!(
318 https_stage_rank(self.state.marker()) == https_stage_rank(from_marker),
319 "FailedUpgrade must retain the origin stage marker for gauge restoration"
320 );
321 true
322 }
323 }
324 }
325
326 fn upgrade_expect(
327 &mut self,
328 mut expect: ExpectProxyProtocol<MioTcpStream>,
329 ssl: ServerConnection,
330 ) -> Option<HttpsStateMachine> {
331 if let Some(ref addresses) = expect.addresses {
332 if let (Some(public_address), Some(session_address)) =
333 (addresses.destination(), addresses.source())
334 {
335 self.public_address = public_address;
336 self.peer_address = Some(session_address);
337
338 let ExpectProxyProtocol {
339 container_frontend_timeout,
340 frontend,
341 frontend_readiness: readiness,
342 request_id,
343 ..
344 } = expect;
345
346 let mut handshake = TlsHandshake::new(
347 container_frontend_timeout,
348 ssl,
349 frontend,
350 self.frontend_token,
351 request_id,
352 self.peer_address,
353 );
354 handshake.frontend_readiness = readiness;
357 handshake.frontend_readiness.event.insert(Ready::READABLE);
358
359 debug_assert_eq!(
363 self.peer_address,
364 Some(session_address),
365 "expect upgrade must adopt the PROXY-advertised source as the peer address"
366 );
367 debug_assert!(
368 handshake.frontend_readiness.event.is_readable(),
369 "handshake handed off from expect must be armed for READABLE"
370 );
371
372 gauge_add!(names::protocol::PROXY_EXPECT, -1);
373 gauge_add!(names::protocol::TLS_HANDSHAKE, 1);
374 return Some(HttpsStateMachine::Handshake(handshake));
375 }
376 }
377
378 if !expect.container_frontend_timeout.cancel() {
380 error!(
381 "{} failed to cancel request timeout on expect upgrade phase for 'expect proxy protocol with AF_UNSPEC address'",
382 log_context!(self)
383 );
384 }
385
386 None
387 }
388
389 fn upgrade_handshake(&mut self, handshake: TlsHandshake) -> Option<HttpsStateMachine> {
390 let sni_owned: Option<String> = handshake
402 .session
403 .server_name()
404 .map(|s| s.to_ascii_lowercase())
405 .map(|mut s| {
406 if s.ends_with('.') {
407 s.pop();
408 }
409 s
410 });
411 let alpn = handshake.session.alpn_protocol();
412 let alpn = alpn.and_then(|alpn| from_utf8(alpn).ok());
413 debug!(
414 "{} successful TLS handshake with, received: {:?} {:?}",
415 log_context!(self),
416 sni_owned,
417 alpn
418 );
419
420 let disable_http11 = self.listener.borrow().is_http11_disabled();
425 let (alpn, alpn_label): (AlpnProtocol, Option<&'static str>) = match alpn {
430 Some("http/1.1") => {
431 if disable_http11 {
432 incr!(names::https::ALPN_REJECTED_HTTP11_DISABLED);
433 warn!(
434 "{} rejecting TLS connection: listener is H2-only but client negotiated http/1.1",
435 log_context!(self)
436 );
437 return None;
438 }
439 (AlpnProtocol::Http11, Some("http/1.1"))
440 }
441 Some("h2") => (AlpnProtocol::H2, Some("h2")),
442 Some(other) => {
443 incr!(names::https::ALPN_REJECTED_UNSUPPORTED);
450 error!(
451 "{} unsupported ALPN protocol: {}",
452 log_context!(self),
453 other
454 );
455 return None;
456 }
457 None => {
461 if disable_http11 {
462 incr!(names::https::ALPN_REJECTED_HTTP11_DISABLED);
463 warn!(
464 "{} rejecting TLS connection: listener is H2-only but client did not negotiate ALPN",
465 log_context!(self)
466 );
467 return None;
468 }
469 (AlpnProtocol::Http11, None)
470 }
471 };
472
473 debug_assert!(
479 !disable_http11 || matches!(alpn, AlpnProtocol::H2),
480 "H2-only listener must not dispatch an HTTP/1.1 session past ALPN"
481 );
482 debug_assert!(
483 match (&alpn, alpn_label) {
484 (AlpnProtocol::H2, Some(l)) => l == "h2",
485 (AlpnProtocol::Http11, Some(l)) => l == "http/1.1",
486 (AlpnProtocol::Http11, None) => true,
488 (AlpnProtocol::H2, None) => false,
489 },
490 "negotiated ALPN protocol and its wire label must agree"
491 );
492
493 let tls_version_label = handshake
498 .session
499 .protocol_version()
500 .and_then(rustls_version_label);
501 let tls_cipher_label = handshake
502 .session
503 .negotiated_cipher_suite()
504 .and_then(rustls_ciphersuite_label);
505 if let Some(version) = handshake.session.protocol_version() {
506 incr!(rustls_version_str(version));
507 };
508 if let Some(cipher) = handshake.session.negotiated_cipher_suite() {
509 incr!(rustls_ciphersuite_str(cipher));
510 };
511
512 gauge_add!(names::protocol::TLS_HANDSHAKE, -1);
513
514 let session_ulid = rusty_ulid::Ulid::generate();
515 let front_stream = FrontRustls {
516 stream: handshake.stream,
517 session: handshake.session,
518 peer_disconnected: false,
519 peer_reset: false,
520 session_ulid,
521 };
522 let router = mux::Router::new(
523 self.configured_backend_timeout,
524 self.configured_connect_timeout,
525 );
526 let mut context = mux::Context::new(
527 session_ulid,
528 self.pool.clone(),
529 self.listener.clone(),
530 self.peer_address,
531 self.public_address,
532 );
533 let tls_cert_names: Option<Arc<Vec<String>>> = match sni_owned.as_deref() {
588 Some(sni) => self
589 .listener
590 .borrow()
591 .resolver()
592 .names_for_sni(sni.as_bytes())
593 .and_then(|names| {
594 let mut snapshot: Vec<String> = names
595 .into_iter()
596 .map(|mut name| {
597 name.make_ascii_lowercase();
598 if name.ends_with('.') {
599 name.pop();
600 }
601 name
602 })
603 .collect();
604 snapshot.sort();
605 snapshot.dedup();
606 if snapshot.is_empty() {
607 None
608 } else {
609 Some(Arc::new(snapshot))
610 }
611 }),
612 None => None,
613 };
614 debug_assert!(
622 tls_cert_names.is_none() || sni_owned.is_some(),
623 "cert-name snapshot must not exist without an SNI to key it"
624 );
625 debug_assert!(
626 tls_cert_names
627 .as_ref()
628 .is_none_or(|names| { !names.is_empty() && names.windows(2).all(|w| w[0] < w[1]) }),
629 "cert-name snapshot must be non-empty and strictly sorted (sorted + deduped)"
630 );
631
632 context.tls_server_name = sni_owned;
636 context.tls_cert_names = tls_cert_names;
637 context.tls_version = tls_version_label;
641 context.tls_cipher = tls_cipher_label;
642 context.tls_alpn = alpn_label;
643 let mut frontend = match alpn {
644 AlpnProtocol::Http11 => {
645 incr!(names::http::ALPN_HTTP11);
646 context.create_stream(handshake.request_id, 1 << 16)?;
647 mux::Connection::new_h1_server(
648 session_ulid,
649 front_stream,
650 handshake.container_frontend_timeout,
651 )
652 }
653 AlpnProtocol::H2 => {
654 incr!(names::http::ALPN_H2);
655 let flood_config = self.listener.borrow().get_h2_flood_config();
656 let connection_config = self.listener.borrow().get_h2_connection_config();
657 let stream_idle_timeout = self.listener.borrow().get_h2_stream_idle_timeout();
658 let graceful_shutdown_deadline =
659 self.listener.borrow().get_h2_graceful_shutdown_deadline();
660 mux::Connection::new_h2_server(
661 session_ulid,
662 front_stream,
663 self.pool.clone(),
664 handshake.container_frontend_timeout,
665 flood_config,
666 connection_config,
667 stream_idle_timeout,
668 graceful_shutdown_deadline,
669 )?
670 }
671 };
672 frontend
681 .readiness_mut()
682 .event
683 .insert(Ready::READABLE | Ready::WRITABLE);
684
685 debug_assert!(
689 frontend.readiness_mut().event.is_readable()
690 && frontend.readiness_mut().event.is_writable(),
691 "post-handshake mux frontend must be armed for READABLE and WRITABLE"
692 );
693 debug_assert_eq!(
697 context.session_ulid, session_ulid,
698 "mux context and connection must share the handshake-derived session ulid"
699 );
700
701 gauge_add!(names::protocol::HTTPS, 1);
702 Some(HttpsStateMachine::Mux(Mux {
703 configured_frontend_timeout: self.configured_frontend_timeout,
704 frontend_token: self.frontend_token,
705 frontend,
706 context,
707 router,
708 session_ulid,
709 }))
710 }
711
712 fn upgrade_mux(&self, mut mux: MuxTls) -> Option<HttpsStateMachine> {
713 debug!("{} mux switching to wss", log_context!(self));
714 let Some(stream) = mux.context.streams.pop() else {
715 error!(
716 "{} upgrade_mux: no stream attached to the TLS mux session, closing",
717 log_context!(self)
718 );
719 return None;
720 };
721 let (frontend_readiness, frontend_socket, mut container_frontend_timeout) =
725 match mux.frontend {
726 mux::Connection::H1(mux::ConnectionH1 {
727 readiness,
728 socket,
729 timeout_container,
730 ..
731 }) => (readiness, socket, timeout_container),
732 mux::Connection::H2(_) => {
733 error!(
734 "{} only h1<->h1 connections can upgrade to websocket",
735 log_context!(self)
736 );
737 return None;
738 }
739 };
740
741 let mux::StreamState::Linked(back_token) = stream.state else {
742 error!(
743 "{} upgrading stream should be linked to a backend",
744 log_context!(self)
745 );
746 return None;
747 };
748 let Some(backend) = mux.router.backends.remove(&back_token) else {
749 error!(
750 "{} upgrade_mux: backend for token {:?} is missing (already disconnected?), closing",
751 log_context!(self),
752 back_token
753 );
754 return None;
755 };
756 let (cluster_id, backend, backend_readiness, backend_socket, mut container_backend_timeout) =
757 match backend {
758 mux::Connection::H1(mux::ConnectionH1 {
759 position:
760 mux::Position::Client(cluster_id, backend, mux::BackendStatus::Connected),
761 readiness,
762 socket,
763 timeout_container,
764 ..
765 }) => (cluster_id, backend, readiness, socket, timeout_container),
766 mux::Connection::H1(_) => {
767 error!(
768 "{} the backend disconnected just after upgrade, abort",
769 log_context!(self)
770 );
771 return None;
772 }
773 mux::Connection::H2(_) => {
774 error!(
775 "{} only h1<->h1 connections can upgrade to websocket",
776 log_context!(self)
777 );
778 return None;
779 }
780 };
781
782 let ws_context = stream.context.websocket_context();
783
784 container_frontend_timeout.reset();
785 container_backend_timeout.reset();
786
787 let backend_id = backend.borrow().backend_id.clone();
788 let backend_socket = backend_socket.stream;
791 let mut pipe = Pipe::new(
792 stream.back.storage.buffer,
793 Some(backend_id),
794 Some(backend_socket),
795 Some(backend),
796 Some(container_backend_timeout),
797 Some(container_frontend_timeout),
798 Some(cluster_id),
799 stream.front.storage.buffer,
800 self.frontend_token,
801 frontend_socket,
802 self.listener.clone(),
803 Protocol::HTTPS,
804 stream.context.session_id,
805 stream.context.id,
806 stream.context.session_address,
807 ws_context,
808 );
809
810 pipe.frontend_readiness.event = frontend_readiness.event;
811 pipe.backend_readiness.event = backend_readiness.event;
812 pipe.set_back_token(back_token);
813 debug_assert!(
818 pipe.back_token().contains(&back_token),
819 "WSS pipe back token must be the connected backend token carried from the mux"
820 );
821 pipe.set_tls_metadata(
827 stream.context.tls_version,
828 stream.context.tls_cipher,
829 stream.context.tls_server_name.clone(),
830 stream.context.tls_alpn,
831 );
832
833 debug_assert_eq!(
839 pipe.frontend_readiness.event, frontend_readiness.event,
840 "WSS pipe must inherit the mux frontend readiness event verbatim"
841 );
842 debug_assert_eq!(
843 pipe.backend_readiness.event, backend_readiness.event,
844 "WSS pipe must inherit the mux backend readiness event verbatim"
845 );
846
847 gauge_add!(names::protocol::HTTPS, -1);
850 gauge_add!(names::protocol::WSS, 1);
851 gauge_add!(names::websocket::ACTIVE_REQUESTS, 1);
852 Some(HttpsStateMachine::WebSocket(pipe))
853 }
854
855 fn upgrade_websocket(
856 &self,
857 wss: Pipe<FrontRustls, HttpsListener>,
858 ) -> Option<HttpsStateMachine> {
859 error!(
861 "{} upgrade called on WSS, this should not happen",
862 log_context!(self)
863 );
864 Some(HttpsStateMachine::WebSocket(wss))
865 }
866
867 #[cfg(debug_assertions)]
873 fn check_invariants(&self) {
874 debug_assert!(
878 !self.configured_frontend_timeout.is_zero()
879 && !self.configured_backend_timeout.is_zero()
880 && !self.configured_connect_timeout.is_zero(),
881 "HTTPS session timeouts must stay non-zero for the session lifetime"
882 );
883 if self.state.failed() {
888 debug_assert!(
889 matches!(
890 self.state.marker(),
891 StateMarker::Expect
892 | StateMarker::Handshake
893 | StateMarker::Mux
894 | StateMarker::WebSocket
895 ),
896 "FailedUpgrade must retain a valid origin-stage marker"
897 );
898 } else {
899 debug_assert!(
900 !self.state.failed(),
901 "a non-failed session must not also report FailedUpgrade"
902 );
903 }
904 debug_assert!(
910 !matches!(self.state.marker(), StateMarker::Expect)
911 || self.peer_address.is_none()
912 || self.state.failed(),
913 "a live Expect-stage session has no resolved peer address yet"
914 );
915 }
916}
917
918impl ProxySession for HttpsSession {
919 fn close(&mut self) {
920 if self.has_been_closed {
921 return;
922 }
923 debug_assert!(
928 !self.has_been_closed,
929 "close() body must run only on a not-yet-closed session"
930 );
931
932 trace!("{} closing HTTPS session", log_context!(self));
933 self.metrics.service_stop();
934
935 match self.state.marker() {
937 StateMarker::Expect => gauge_add!(names::protocol::PROXY_EXPECT, -1),
938 StateMarker::Handshake => gauge_add!(names::protocol::TLS_HANDSHAKE, -1),
939 StateMarker::Mux => gauge_add!(names::protocol::HTTPS, -1),
940 StateMarker::WebSocket => {
941 gauge_add!(names::protocol::WSS, -1);
942 gauge_add!(names::websocket::ACTIVE_REQUESTS, -1);
943 }
944 }
945
946 if self.state.failed() {
947 match self.state.marker() {
948 StateMarker::Expect => incr!(names::https::UPGRADE_EXPECT_FAILED),
949 StateMarker::Handshake => incr!(names::https::UPGRADE_HANDSHAKE_FAILED),
950 StateMarker::Mux => incr!(names::https::UPGRADE_MUX_FAILED),
951 StateMarker::WebSocket => incr!(names::https::UPGRADE_WSS_FAILED),
952 }
953 self.state.close(self.proxy.clone(), &mut self.metrics);
957 self.proxy.borrow().remove_session(self.frontend_token);
958 self.has_been_closed = true;
959 return;
960 }
961
962 self.state.cancel_timeouts();
963 self.state.close(self.proxy.clone(), &mut self.metrics);
966
967 let front_socket = self.state.front_socket();
974 if let Err(e) = front_socket.shutdown(Shutdown::Write) {
975 if e.kind() != ErrorKind::NotConnected {
977 error!(
978 "{} error shutting down front socket({:?}): {:?}",
979 log_context!(self),
980 front_socket,
981 e
982 );
983 }
984 }
985
986 let proxy = self.proxy.borrow();
988 let fd = front_socket.as_raw_fd();
989 if let Err(e) = proxy.registry.deregister(&mut SourceFd(&fd)) {
990 error!(
991 "{} error deregistering front socket({:?}) while closing HTTPS session: {:?}",
992 log_context!(self),
993 fd,
994 e
995 );
996 }
997 proxy.remove_session(self.frontend_token);
998
999 self.has_been_closed = true;
1000 debug_assert!(
1004 self.has_been_closed,
1005 "close() must leave the session marked closed"
1006 );
1007 }
1008
1009 fn timeout(&mut self, token: Token) -> SessionIsToBeClosed {
1010 let session_result = self.state.timeout(token, &mut self.metrics);
1011 if session_result == StateResult::CloseSession {
1012 debug!(
1013 "{} HTTPS timeout requested close: token={:?}, marker={:?}",
1014 log_context!(self),
1015 token,
1016 self.state.marker()
1017 );
1018 }
1019 session_result == StateResult::CloseSession
1020 }
1021
1022 fn protocol(&self) -> Protocol {
1023 Protocol::HTTPS
1024 }
1025
1026 fn update_readiness(&mut self, token: Token, events: Ready) {
1027 trace!(
1028 "{} token {:?} got event {}",
1029 log_context!(self),
1030 token,
1031 super::ready_to_string(events)
1032 );
1033 self.last_event = Instant::now();
1034 self.metrics.wait_start();
1035 self.state.update_readiness(token, events);
1036 }
1037
1038 fn ready(&mut self, session: Rc<RefCell<dyn ProxySession>>) -> SessionIsToBeClosed {
1039 self.metrics.service_start();
1040
1041 let session_result =
1042 self.state
1043 .ready(session.clone(), self.proxy.clone(), &mut self.metrics);
1044
1045 let to_be_closed = match session_result {
1046 SessionResult::Close => true,
1047 SessionResult::Continue => false,
1048 SessionResult::Upgrade => match self.upgrade() {
1049 false => self.ready(session),
1050 true => true,
1051 },
1052 };
1053 if to_be_closed {
1054 debug!(
1055 "{} HTTPS ready requested close: marker={:?}",
1056 log_context!(self),
1057 self.state.marker()
1058 );
1059 }
1060
1061 #[cfg(debug_assertions)]
1065 self.check_invariants();
1066
1067 self.metrics.service_stop();
1068 to_be_closed
1069 }
1070
1071 fn shutting_down(&mut self) -> SessionIsToBeClosed {
1072 self.state.shutting_down()
1073 }
1074
1075 fn last_event(&self) -> Instant {
1076 self.last_event
1077 }
1078
1079 fn print_session(&self) {
1080 self.state.print_state("HTTPS");
1081 error!("{} Metrics: {:?}", log_context!(self), self.metrics);
1082 }
1083
1084 fn frontend_token(&self) -> Token {
1085 self.frontend_token
1086 }
1087}
1088
1089pub type HostName = String;
1090pub type PathBegin = String;
1091
1092pub struct HttpsListener {
1093 active: bool,
1094 address: StdSocketAddr,
1095 answers: Rc<RefCell<HttpAnswers>>,
1096 config: HttpsListenerConfig,
1097 fronts: Router,
1098 listener: Option<MioTcpListener>,
1099 resolver: Arc<MutexCertificateResolver>,
1100 rustls_details: Arc<RustlsServerConfig>,
1101 tags: BTreeMap<String, CachedTags>,
1102 token: Token,
1103}
1104
1105impl ListenerHandler for HttpsListener {
1106 fn get_addr(&self) -> &StdSocketAddr {
1107 &self.address
1108 }
1109
1110 fn get_tags(&self, key: &str) -> Option<&CachedTags> {
1111 self.tags.get(key)
1112 }
1113
1114 fn set_tags(&mut self, key: String, tags: Option<BTreeMap<String, String>>) {
1115 match tags {
1116 Some(tags) => self.tags.insert(key, CachedTags::new(tags)),
1117 None => self.tags.remove(&key),
1118 };
1119 }
1120
1121 fn protocol(&self) -> Protocol {
1122 Protocol::HTTPS
1123 }
1124
1125 fn public_address(&self) -> StdSocketAddr {
1126 self.config
1127 .public_address
1128 .map(|addr| addr.into())
1129 .unwrap_or(self.address)
1130 }
1131}
1132
1133impl L7ListenerHandler for HttpsListener {
1134 fn get_sticky_name(&self) -> &str {
1135 &self.config.sticky_name
1136 }
1137
1138 fn get_sozu_id_header(&self) -> &str {
1139 self.config
1140 .sozu_id_header
1141 .as_deref()
1142 .filter(|s| !s.is_empty())
1143 .unwrap_or("Sozu-Id")
1144 }
1145
1146 fn get_connect_timeout(&self) -> u32 {
1147 self.config.connect_timeout
1148 }
1149
1150 fn frontend_from_request(
1151 &self,
1152 host: &str,
1153 uri: &str,
1154 method: &Method,
1155 ) -> Result<RouteResult, FrontendFromRequestError> {
1156 let start = Instant::now();
1157 let (remaining_input, (hostname, _)) = match hostname_and_port(host.as_bytes()) {
1158 Ok(tuple) => tuple,
1159 Err(parse_error) => {
1160 return Err(FrontendFromRequestError::HostParse {
1162 host: host.to_owned(),
1163 error: parse_error.to_string(),
1164 });
1165 }
1166 };
1167
1168 if remaining_input != &b""[..] {
1169 return Err(FrontendFromRequestError::InvalidCharsAfterHost(
1170 host.to_owned(),
1171 ));
1172 }
1173
1174 let host = unsafe { from_utf8_unchecked(hostname) };
1183
1184 let route = self.fronts.lookup(host, uri, method).map_err(|e| {
1185 incr!(names::http::FAILED_BACKEND_MATCHING);
1186 FrontendFromRequestError::NoClusterFound(e)
1187 })?;
1188
1189 let now = Instant::now();
1190
1191 if let Some(cluster) = route.cluster_id.as_deref() {
1192 time!(
1193 names::event_loop::FRONTEND_MATCHING_TIME,
1194 cluster,
1195 (now - start).as_millis()
1196 );
1197 }
1198
1199 Ok(route)
1200 }
1201
1202 fn get_answers(&self) -> &Rc<RefCell<HttpAnswers>> {
1203 &self.answers
1204 }
1205
1206 fn get_h2_flood_config(&self) -> crate::protocol::mux::H2FloodConfig {
1207 let defaults = crate::protocol::mux::H2FloodConfig::default();
1208 crate::protocol::mux::H2FloodConfig {
1209 max_rst_stream_per_window: self
1210 .config
1211 .h2_max_rst_stream_per_window
1212 .unwrap_or(defaults.max_rst_stream_per_window),
1213 max_ping_per_window: self
1214 .config
1215 .h2_max_ping_per_window
1216 .unwrap_or(defaults.max_ping_per_window),
1217 max_settings_per_window: self
1218 .config
1219 .h2_max_settings_per_window
1220 .unwrap_or(defaults.max_settings_per_window),
1221 max_empty_data_per_window: self
1222 .config
1223 .h2_max_empty_data_per_window
1224 .unwrap_or(defaults.max_empty_data_per_window),
1225 max_window_update_stream0_per_window: self
1226 .config
1227 .h2_max_window_update_stream0_per_window
1228 .unwrap_or(defaults.max_window_update_stream0_per_window),
1229 max_continuation_frames: self
1230 .config
1231 .h2_max_continuation_frames
1232 .unwrap_or(defaults.max_continuation_frames),
1233 max_glitch_count: self
1234 .config
1235 .h2_max_glitch_count
1236 .unwrap_or(defaults.max_glitch_count),
1237 max_rst_stream_lifetime: self
1238 .config
1239 .h2_max_rst_stream_lifetime
1240 .unwrap_or(defaults.max_rst_stream_lifetime),
1241 max_rst_stream_abusive_lifetime: self
1242 .config
1243 .h2_max_rst_stream_abusive_lifetime
1244 .unwrap_or(defaults.max_rst_stream_abusive_lifetime),
1245 max_rst_stream_emitted_lifetime: self
1246 .config
1247 .h2_max_rst_stream_emitted_lifetime
1248 .unwrap_or(defaults.max_rst_stream_emitted_lifetime),
1249 max_header_list_size: self
1250 .config
1251 .h2_max_header_list_size
1252 .unwrap_or(defaults.max_header_list_size),
1253 max_header_table_size: self
1254 .config
1255 .h2_max_header_table_size
1256 .unwrap_or(defaults.max_header_table_size),
1257 max_header_fields: self
1258 .config
1259 .h2_max_header_fields
1260 .unwrap_or(defaults.max_header_fields),
1261 }
1262 }
1263
1264 fn get_h2_connection_config(&self) -> crate::protocol::mux::H2ConnectionConfig {
1265 crate::protocol::mux::H2ConnectionConfig::from_optional(
1266 self.config.h2_initial_connection_window,
1267 self.config.h2_max_concurrent_streams,
1268 self.config.h2_stream_shrink_ratio,
1269 )
1270 }
1271
1272 fn get_strict_sni_binding(&self) -> bool {
1273 self.config.strict_sni_binding.unwrap_or(true)
1288 }
1289
1290 fn get_elide_x_real_ip(&self) -> bool {
1291 self.config.elide_x_real_ip.unwrap_or(false)
1292 }
1293
1294 fn get_send_x_real_ip(&self) -> bool {
1295 self.config.send_x_real_ip.unwrap_or(false)
1296 }
1297
1298 fn get_h2_stream_idle_timeout(&self) -> std::time::Duration {
1299 let seconds = self
1306 .config
1307 .h2_stream_idle_timeout_seconds
1308 .map(|s| u64::from(s.max(1)))
1309 .unwrap_or_else(|| u64::from(self.config.back_timeout).max(30));
1310 std::time::Duration::from_secs(seconds)
1311 }
1312
1313 fn get_h2_graceful_shutdown_deadline(&self) -> Option<std::time::Duration> {
1314 match self.config.h2_graceful_shutdown_deadline_seconds {
1315 None => Some(std::time::Duration::from_secs(5)),
1316 Some(0) => None,
1317 Some(s) => Some(std::time::Duration::from_secs(u64::from(s))),
1318 }
1319 }
1320}
1321
1322impl HttpsListener {
1323 pub fn is_http11_disabled(&self) -> bool {
1329 self.config.disable_http11.unwrap_or(false)
1330 }
1331
1332 pub fn resolver(&self) -> &Arc<MutexCertificateResolver> {
1338 &self.resolver
1339 }
1340
1341 pub fn try_new(
1342 config: HttpsListenerConfig,
1343 token: Token,
1344 ) -> Result<HttpsListener, ListenerError> {
1345 let resolver = Arc::new(MutexCertificateResolver::default());
1346
1347 let server_config = Arc::new(Self::create_rustls_context(&config, resolver.to_owned())?);
1348
1349 let answers = {
1350 let mut answers_map = config.answers.clone();
1355 if let Some(ref legacy) = config.http_answers {
1356 crate::protocol::http::answers::merge_legacy_into_map(&mut answers_map, legacy);
1357 }
1358 HttpAnswers::new(&answers_map)
1359 .map_err(|(name, error)| ListenerError::TemplateParse(name, error))?
1360 };
1361
1362 Ok(HttpsListener {
1363 listener: None,
1364 address: config.address.into(),
1365 resolver,
1366 rustls_details: server_config,
1367 active: false,
1368 fronts: Router::new(),
1369 answers: Rc::new(RefCell::new(answers)),
1370 config,
1371 token,
1372 tags: BTreeMap::new(),
1373 })
1374 }
1375
1376 pub fn activate(
1377 &mut self,
1378 registry: &Registry,
1379 tcp_listener: Option<MioTcpListener>,
1380 ) -> Result<Token, ListenerError> {
1381 if self.active {
1382 return Ok(self.token);
1383 }
1384 let address: StdSocketAddr = self.config.address.into();
1385
1386 let mut listener = match tcp_listener {
1387 Some(tcp_listener) => tcp_listener,
1388 None => {
1389 server_bind(address).map_err(|server_bind_error| ListenerError::Activation {
1390 address,
1391 error: server_bind_error.to_string(),
1392 })?
1393 }
1394 };
1395
1396 registry
1397 .register(&mut listener, self.token, Interest::READABLE)
1398 .map_err(ListenerError::SocketRegistration)?;
1399
1400 self.listener = Some(listener);
1401 self.active = true;
1402 debug_assert!(
1408 self.active && self.listener.is_some(),
1409 "an activated HTTPS listener must hold a bound socket and be flagged active"
1410 );
1411 Ok(self.token)
1412 }
1413
1414 pub fn create_rustls_context(
1415 config: &HttpsListenerConfig,
1416 resolver: Arc<MutexCertificateResolver>,
1417 ) -> Result<RustlsServerConfig, ListenerError> {
1418 let cipher_names = if config.cipher_list.is_empty() {
1419 DEFAULT_CIPHER_LIST.to_vec()
1420 } else {
1421 config
1422 .cipher_list
1423 .iter()
1424 .map(|s| s.as_str())
1425 .collect::<Vec<_>>()
1426 };
1427
1428 let ciphers = cipher_names
1429 .into_iter()
1430 .filter_map(|cipher| {
1431 cipher_suite_by_name(cipher).or_else(|| {
1432 error!(
1433 "{} unknown or unsupported cipher: {:?}",
1434 log_module_context!(),
1435 cipher
1436 );
1437 None
1438 })
1439 })
1440 .collect::<Vec<_>>();
1441
1442 let versions = config
1443 .versions
1444 .iter()
1445 .filter_map(|version| match TlsVersion::try_from(*version) {
1446 Ok(TlsVersion::TlsV12) => Some(&rustls::version::TLS12),
1447 Ok(TlsVersion::TlsV13) => Some(&rustls::version::TLS13),
1448 Ok(other_version) => {
1449 error!(
1450 "{} unsupported TLS version {:?}",
1451 log_module_context!(),
1452 other_version
1453 );
1454 None
1455 }
1456 Err(_) => {
1457 error!("{} unsupported TLS version", log_module_context!());
1458 None
1459 }
1460 })
1461 .collect::<Vec<_>>();
1462
1463 let kx_groups = if config.groups_list.is_empty() {
1464 default_provider().kx_groups
1465 } else {
1466 config
1467 .groups_list
1468 .iter()
1469 .filter_map(|group| match kx_group_by_name(group) {
1470 Some(kx) => Some(kx),
1471 None => {
1472 debug!("key exchange group {:?} not supported by the compiled crypto provider, skipping", group);
1473 None
1474 }
1475 })
1476 .collect::<Vec<_>>()
1477 };
1478
1479 let provider = CryptoProvider {
1480 cipher_suites: ciphers,
1481 kx_groups,
1482 ..default_provider()
1483 };
1484
1485 let mut server_config = RustlsServerConfig::builder_with_provider(provider.into())
1486 .with_protocol_versions(&versions[..])
1487 .map_err(|err| ListenerError::BuildRustls(err.to_string()))?
1488 .with_no_client_auth()
1489 .with_cert_resolver(resolver);
1490 server_config.send_tls13_tickets = config.send_tls13_tickets as usize;
1491
1492 server_config.alpn_protocols = if config.alpn_protocols.is_empty() {
1493 DEFAULT_ALPN_PROTOCOLS
1494 .iter()
1495 .map(|p| p.as_bytes().to_vec())
1496 .collect()
1497 } else {
1498 config
1499 .alpn_protocols
1500 .iter()
1501 .map(|p| p.as_bytes().to_vec())
1502 .collect()
1503 };
1504
1505 Ok(server_config)
1506 }
1507
1508 pub fn update_config(
1516 &mut self,
1517 patch: &UpdateHttpsListenerConfig,
1518 ) -> Result<(), ListenerError> {
1519 validate_h2_flood_knobs_https(patch)?;
1524 if let Some(ref alpn) = patch.alpn_protocols {
1525 validate_alpn_protocols(&alpn.values)?;
1526 }
1527 if let Some(ref hdr) = patch.sozu_id_header {
1528 validate_sozu_id_header(hdr)?;
1529 }
1530
1531 if let Some(v) = patch.public_address {
1533 self.config.public_address = Some(v);
1534 }
1535 if let Some(v) = patch.expect_proxy {
1536 self.config.expect_proxy = v;
1537 }
1538 if let Some(ref v) = patch.sticky_name {
1539 self.config.sticky_name = v.to_owned();
1540 }
1541 if let Some(v) = patch.front_timeout {
1542 self.config.front_timeout = v;
1543 }
1544 if let Some(v) = patch.back_timeout {
1545 self.config.back_timeout = v;
1546 }
1547 if let Some(v) = patch.connect_timeout {
1548 self.config.connect_timeout = v;
1549 }
1550 if let Some(v) = patch.request_timeout {
1551 self.config.request_timeout = v;
1552 }
1553 if let Some(v) = patch.strict_sni_binding {
1554 self.config.strict_sni_binding = Some(v);
1555 }
1556 if let Some(v) = patch.disable_http11 {
1557 self.config.disable_http11 = Some(v);
1558 }
1559 if let Some(ref v) = patch.sozu_id_header {
1560 self.config.sozu_id_header = Some(v.to_owned());
1561 }
1562 if let Some(v) = patch.elide_x_real_ip {
1563 self.config.elide_x_real_ip = Some(v);
1564 }
1565 if let Some(v) = patch.send_x_real_ip {
1566 self.config.send_x_real_ip = Some(v);
1567 }
1568
1569 if let Some(v) = patch.h2_max_rst_stream_per_window {
1571 self.config.h2_max_rst_stream_per_window = Some(v);
1572 }
1573 if let Some(v) = patch.h2_max_ping_per_window {
1574 self.config.h2_max_ping_per_window = Some(v);
1575 }
1576 if let Some(v) = patch.h2_max_settings_per_window {
1577 self.config.h2_max_settings_per_window = Some(v);
1578 }
1579 if let Some(v) = patch.h2_max_empty_data_per_window {
1580 self.config.h2_max_empty_data_per_window = Some(v);
1581 }
1582 if let Some(v) = patch.h2_max_continuation_frames {
1583 self.config.h2_max_continuation_frames = Some(v);
1584 }
1585 if let Some(v) = patch.h2_max_glitch_count {
1586 self.config.h2_max_glitch_count = Some(v);
1587 }
1588 if let Some(v) = patch.h2_initial_connection_window {
1589 self.config.h2_initial_connection_window = Some(v);
1590 }
1591 if let Some(v) = patch.h2_max_concurrent_streams {
1592 self.config.h2_max_concurrent_streams = Some(v);
1593 }
1594 if let Some(v) = patch.h2_stream_shrink_ratio {
1595 self.config.h2_stream_shrink_ratio = Some(v);
1596 }
1597 if let Some(v) = patch.h2_max_rst_stream_lifetime {
1598 self.config.h2_max_rst_stream_lifetime = Some(v);
1599 }
1600 if let Some(v) = patch.h2_max_rst_stream_abusive_lifetime {
1601 self.config.h2_max_rst_stream_abusive_lifetime = Some(v);
1602 }
1603 if let Some(v) = patch.h2_max_rst_stream_emitted_lifetime {
1604 self.config.h2_max_rst_stream_emitted_lifetime = Some(v);
1605 }
1606 if let Some(v) = patch.h2_max_header_list_size {
1607 self.config.h2_max_header_list_size = Some(v);
1608 }
1609 if let Some(v) = patch.h2_max_header_table_size {
1610 self.config.h2_max_header_table_size = Some(v);
1611 }
1612 if let Some(v) = patch.h2_max_header_fields {
1613 self.config.h2_max_header_fields = Some(v);
1614 }
1615 if let Some(v) = patch.h2_stream_idle_timeout_seconds {
1616 self.config.h2_stream_idle_timeout_seconds = Some(v);
1617 }
1618 if let Some(v) = patch.h2_graceful_shutdown_deadline_seconds {
1619 self.config.h2_graceful_shutdown_deadline_seconds = Some(v);
1620 }
1621 if let Some(v) = patch.h2_max_window_update_stream0_per_window {
1622 self.config.h2_max_window_update_stream0_per_window = Some(v);
1623 }
1624
1625 if let Some(ref alpn_wrapper) = patch.alpn_protocols {
1635 let mut candidate = self.config.clone();
1636 candidate.alpn_protocols = alpn_wrapper.values.clone();
1637 let new_rustls = Arc::new(Self::create_rustls_context(
1638 &candidate,
1639 self.resolver.clone(),
1640 )?);
1641 self.config.alpn_protocols = alpn_wrapper.values.clone();
1643 self.rustls_details = new_rustls;
1644 debug_assert_eq!(
1649 self.config.alpn_protocols, alpn_wrapper.values,
1650 "committed ALPN config must match the patch values exactly"
1651 );
1652 }
1653
1654 let answers_changed = patch.http_answers.is_some() || !patch.answers.is_empty();
1659 if answers_changed {
1660 if let Some(ref new_answers) = patch.http_answers {
1661 crate::sozu_command::state::merge_custom_http_answers(
1662 &mut self.config.http_answers,
1663 new_answers,
1664 );
1665 }
1666 for (code, body) in &patch.answers {
1667 if !body.is_empty() {
1668 self.config.answers.insert(code.clone(), body.clone());
1669 }
1670 }
1671
1672 let mut answers_map = self.config.answers.clone();
1673 if let Some(ref legacy) = self.config.http_answers {
1674 crate::protocol::http::answers::merge_legacy_into_map(&mut answers_map, legacy);
1675 }
1676 let mut rebuilt = HttpAnswers::new(&answers_map)
1677 .map_err(|(name, error)| ListenerError::TemplateParse(name, error))?;
1678 let preserved = std::mem::take(&mut self.answers.borrow_mut().cluster_answers);
1679 rebuilt.cluster_answers = preserved;
1680 *self.answers.borrow_mut() = rebuilt;
1681 }
1682
1683 if let Some(new_hsts) = patch.hsts {
1702 if new_hsts.enabled.is_none() {
1703 return Err(ListenerError::HstsEnabledRequired);
1704 }
1705 self.config.hsts = Some(new_hsts);
1706 let refreshed = self
1707 .fronts
1708 .refresh_inheriting_hsts(self.config.hsts.as_ref());
1709 for _ in 0..refreshed {
1710 crate::incr!(names::http::HSTS_FRONTEND_REFRESHED);
1711 }
1712 info!(
1713 "{} HTTPS listener {:?} HSTS default patched; refreshed {} inheriting \
1714 frontend(s). Explicit per-frontend overrides untouched.",
1715 log_module_context!(),
1716 self.config.address,
1717 refreshed,
1718 );
1719 crate::incr!(names::http::HSTS_LISTENER_DEFAULT_PATCHED);
1720 }
1721
1722 Ok(())
1723 }
1724
1725 pub fn add_https_front(&mut self, tls_front: HttpFrontend) -> Result<(), ListenerError> {
1726 self.add_https_front_with_hsts_origin(tls_front, crate::router::HstsOrigin::Explicit)
1727 }
1728
1729 pub fn add_https_front_with_hsts_origin(
1736 &mut self,
1737 tls_front: HttpFrontend,
1738 hsts_origin: crate::router::HstsOrigin,
1739 ) -> Result<(), ListenerError> {
1740 self.fronts
1741 .add_http_front_with_hsts_origin(&tls_front, hsts_origin)
1742 .map_err(ListenerError::AddFrontend)
1743 }
1744
1745 pub fn remove_https_front(&mut self, tls_front: HttpFrontend) -> Result<(), ListenerError> {
1746 debug!(
1747 "{} removing tls_front {:?}",
1748 log_module_context!(),
1749 tls_front
1750 );
1751 self.fronts
1752 .remove_http_front(&tls_front)
1753 .map_err(ListenerError::RemoveFrontend)
1754 }
1755
1756 fn accept(&mut self) -> Result<MioTcpStream, AcceptError> {
1757 if let Some(ref sock) = self.listener {
1758 sock.accept()
1759 .map_err(|e| match e.kind() {
1760 ErrorKind::WouldBlock => AcceptError::WouldBlock,
1761 _ => {
1762 error!("{} accept() IO error: {:?}", log_module_context!(), e);
1763 AcceptError::IoError
1764 }
1765 })
1766 .map(|(sock, _)| sock)
1767 } else {
1768 error!(
1769 "{} cannot accept connections, no listening socket available",
1770 log_module_context!()
1771 );
1772 Err(AcceptError::IoError)
1773 }
1774 }
1775}
1776
1777pub struct HttpsProxy {
1778 listeners: HashMap<Token, Rc<RefCell<HttpsListener>>>,
1779 clusters: HashMap<ClusterId, Cluster>,
1780 backends: Rc<RefCell<BackendMap>>,
1781 pool: Rc<RefCell<Pool>>,
1782 registry: Registry,
1783 sessions: Rc<RefCell<SessionManager>>,
1784}
1785
1786impl HttpsProxy {
1787 pub fn new(
1788 registry: Registry,
1789 sessions: Rc<RefCell<SessionManager>>,
1790 pool: Rc<RefCell<Pool>>,
1791 backends: Rc<RefCell<BackendMap>>,
1792 ) -> HttpsProxy {
1793 HttpsProxy {
1794 listeners: HashMap::new(),
1795 clusters: HashMap::new(),
1796 backends,
1797 pool,
1798 registry,
1799 sessions,
1800 }
1801 }
1802
1803 pub fn add_listener(
1804 &mut self,
1805 config: HttpsListenerConfig,
1806 token: Token,
1807 ) -> Result<Token, ProxyError> {
1808 match self.listeners.entry(token) {
1809 Entry::Vacant(entry) => {
1810 let https_listener =
1811 HttpsListener::try_new(config, token).map_err(ProxyError::AddListener)?;
1812 entry.insert(Rc::new(RefCell::new(https_listener)));
1813 Ok(token)
1814 }
1815 _ => Err(ProxyError::ListenerAlreadyPresent),
1816 }
1817 }
1818
1819 pub fn remove_listener(
1820 &mut self,
1821 remove: RemoveListener,
1822 ) -> Result<Option<ResponseContent>, ProxyError> {
1823 let len = self.listeners.len();
1824
1825 let remove_address = remove.address.into();
1826 self.listeners
1827 .retain(|_, listener| listener.borrow().address != remove_address);
1828
1829 if !self.listeners.len() < len {
1830 info!(
1831 "{} no HTTPS listener to remove at address {}",
1832 log_module_context!(),
1833 remove_address
1834 )
1835 }
1836 Ok(None)
1837 }
1838
1839 pub fn soft_stop(&mut self) -> Result<(), ProxyError> {
1840 let listeners: HashMap<_, _> = self.listeners.drain().collect();
1841 let mut socket_errors = vec![];
1842 for (_, l) in listeners.iter() {
1843 if let Some(mut sock) = l.borrow_mut().listener.take() {
1844 debug!("{} deregistering socket {:?}", log_module_context!(), sock);
1845 if let Err(e) = self.registry.deregister(&mut sock) {
1846 let error = format!("socket {sock:?}: {e:?}");
1847 socket_errors.push(error);
1848 }
1849 }
1850 }
1851
1852 if !socket_errors.is_empty() {
1853 return Err(ProxyError::SoftStop {
1854 proxy_protocol: "HTTPS".to_string(),
1855 error: format!("Error deregistering listen sockets: {socket_errors:?}"),
1856 });
1857 }
1858
1859 Ok(())
1860 }
1861
1862 pub fn hard_stop(&mut self) -> Result<(), ProxyError> {
1863 let mut listeners: HashMap<_, _> = self.listeners.drain().collect();
1864 let mut socket_errors = vec![];
1865 for (_, l) in listeners.drain() {
1866 if let Some(mut sock) = l.borrow_mut().listener.take() {
1867 debug!("{} deregistering socket {:?}", log_module_context!(), sock);
1868 if let Err(e) = self.registry.deregister(&mut sock) {
1869 let error = format!("socket {sock:?}: {e:?}");
1870 socket_errors.push(error);
1871 }
1872 }
1873 }
1874
1875 if !socket_errors.is_empty() {
1876 return Err(ProxyError::HardStop {
1877 proxy_protocol: "HTTPS".to_string(),
1878 error: format!("Error deregistering listen sockets: {socket_errors:?}"),
1879 });
1880 }
1881
1882 Ok(())
1883 }
1884
1885 pub fn query_all_certificates(&mut self) -> Result<Option<ResponseContent>, ProxyError> {
1886 let certificates = self
1887 .listeners
1888 .values()
1889 .map(|listener| {
1890 let owned = listener.borrow();
1891 let resolver = unwrap_msg!(owned.resolver.0.lock());
1892 let certificate_summaries = resolver
1893 .domains
1894 .to_hashmap()
1895 .drain()
1896 .map(|(k, fingerprint)| CertificateSummary {
1897 domain: String::from_utf8(k).unwrap(),
1898 fingerprint: fingerprint.to_string(),
1899 })
1900 .collect();
1901
1902 CertificatesByAddress {
1903 address: owned.address.into(),
1904 certificate_summaries,
1905 }
1906 })
1907 .collect();
1908
1909 info!(
1910 "{} got Certificates::All query, answering with {:?}",
1911 log_module_context!(),
1912 certificates
1913 );
1914
1915 Ok(Some(
1916 ContentType::CertificatesByAddress(ListOfCertificatesByAddress { certificates }).into(),
1917 ))
1918 }
1919
1920 pub fn query_certificate_for_domain(
1921 &mut self,
1922 domain: String,
1923 ) -> Result<Option<ResponseContent>, ProxyError> {
1924 let certificates = self
1925 .listeners
1926 .values()
1927 .map(|listener| {
1928 let owned = listener.borrow();
1929 let resolver = unwrap_msg!(owned.resolver.0.lock());
1930 let mut certificate_summaries = vec![];
1931
1932 if let Some((k, fingerprint)) = resolver.domain_lookup(domain.as_bytes(), true) {
1933 certificate_summaries.push(CertificateSummary {
1934 domain: String::from_utf8(k.to_vec()).unwrap(),
1935 fingerprint: fingerprint.to_string(),
1936 });
1937 }
1938 CertificatesByAddress {
1939 address: owned.address.into(),
1940 certificate_summaries,
1941 }
1942 })
1943 .collect();
1944
1945 info!(
1946 "{} got Certificates::Domain({}) query, answering with {:?}",
1947 log_module_context!(),
1948 domain,
1949 certificates
1950 );
1951
1952 Ok(Some(
1953 ContentType::CertificatesByAddress(ListOfCertificatesByAddress { certificates }).into(),
1954 ))
1955 }
1956
1957 pub fn activate_listener(
1958 &mut self,
1959 addr: &StdSocketAddr,
1960 tcp_listener: Option<MioTcpListener>,
1961 ) -> Result<Token, ProxyError> {
1962 let listener = self
1963 .listeners
1964 .values()
1965 .find(|listener| listener.borrow().address == *addr)
1966 .ok_or(ProxyError::NoListenerFound(addr.to_owned()))?;
1967
1968 listener
1969 .borrow_mut()
1970 .activate(&self.registry, tcp_listener)
1971 .map_err(|listener_error| ProxyError::ListenerActivation {
1972 address: *addr,
1973 listener_error,
1974 })
1975 }
1976
1977 pub fn give_back_listeners(&mut self) -> Vec<(StdSocketAddr, MioTcpListener)> {
1978 self.listeners
1979 .values()
1980 .filter_map(|listener| {
1981 let mut owned = listener.borrow_mut();
1982 if let Some(listener) = owned.listener.take() {
1983 owned.active = false;
1986 return Some((owned.address, listener));
1987 }
1988
1989 None
1990 })
1991 .collect()
1992 }
1993
1994 pub fn give_back_listener(
1995 &mut self,
1996 address: StdSocketAddr,
1997 ) -> Result<(Token, MioTcpListener), ProxyError> {
1998 let listener = self
1999 .listeners
2000 .values()
2001 .find(|listener| listener.borrow().address == address)
2002 .ok_or(ProxyError::NoListenerFound(address))?;
2003
2004 let mut owned = listener.borrow_mut();
2005
2006 let taken_listener = owned
2007 .listener
2008 .take()
2009 .ok_or(ProxyError::UnactivatedListener)?;
2010
2011 owned.active = false;
2014
2015 Ok((owned.token, taken_listener))
2016 }
2017
2018 pub fn update_listener(&mut self, patch: UpdateHttpsListenerConfig) -> Result<(), ProxyError> {
2020 let address: std::net::SocketAddr = patch.address.into();
2021 let listener = self
2022 .listeners
2023 .values()
2024 .find(|l| l.borrow().address == address)
2025 .ok_or(ProxyError::NoListenerFound(address))?;
2026 listener
2027 .borrow_mut()
2028 .update_config(&patch)
2029 .map_err(|listener_error| ProxyError::ListenerActivation {
2030 address,
2031 listener_error,
2032 })
2033 }
2034
2035 pub fn add_cluster(
2036 &mut self,
2037 mut cluster: Cluster,
2038 ) -> Result<Option<ResponseContent>, ProxyError> {
2039 let mut cluster_overrides = cluster.answers.clone();
2040 if let Some(answer_503) = cluster.answer_503.take() {
2041 cluster_overrides
2042 .entry("503".to_owned())
2043 .or_insert(answer_503);
2044 }
2045 if !cluster_overrides.is_empty() {
2046 for listener in self.listeners.values() {
2047 listener
2048 .borrow()
2049 .answers
2050 .borrow_mut()
2051 .add_cluster_answers(&cluster.cluster_id, &cluster_overrides)
2052 .map_err(|(status, error)| {
2053 ProxyError::AddCluster(ListenerError::TemplateParse(status, error))
2054 })?;
2055 }
2056 }
2057 self.clusters.insert(cluster.cluster_id.clone(), cluster);
2058 Ok(None)
2059 }
2060
2061 pub fn remove_cluster(
2062 &mut self,
2063 cluster_id: &str,
2064 ) -> Result<Option<ResponseContent>, ProxyError> {
2065 self.clusters.remove(cluster_id);
2066 for listener in self.listeners.values() {
2067 listener
2068 .borrow()
2069 .answers
2070 .borrow_mut()
2071 .remove_cluster_answers(cluster_id);
2072 }
2073
2074 Ok(None)
2075 }
2076
2077 pub fn add_https_frontend(
2078 &mut self,
2079 front: RequestHttpFrontend,
2080 ) -> Result<Option<ResponseContent>, ProxyError> {
2081 let mut front = front.clone().to_frontend().map_err(|request_error| {
2082 ProxyError::WrongInputFrontend {
2083 front: Box::new(front),
2084 error: request_error.to_string(),
2085 }
2086 })?;
2087
2088 let mut listener = self
2089 .listeners
2090 .values()
2091 .find(|l| l.borrow().address == front.address)
2092 .ok_or(ProxyError::NoListenerFound(front.address))?
2093 .borrow_mut();
2094
2095 let hsts_origin = if front.hsts.is_none() && listener.config.hsts.is_some() {
2108 front.hsts = listener.config.hsts;
2109 crate::router::HstsOrigin::InheritedFromListenerDefault
2110 } else {
2111 crate::router::HstsOrigin::Explicit
2112 };
2113
2114 listener.set_tags(front.hostname.to_owned(), front.tags.to_owned());
2115 listener
2116 .add_https_front_with_hsts_origin(front, hsts_origin)
2117 .map_err(ProxyError::AddFrontend)?;
2118 Ok(None)
2119 }
2120
2121 pub fn remove_https_frontend(
2122 &mut self,
2123 front: RequestHttpFrontend,
2124 ) -> Result<Option<ResponseContent>, ProxyError> {
2125 let front = front.clone().to_frontend().map_err(|request_error| {
2126 ProxyError::WrongInputFrontend {
2127 front: Box::new(front),
2128 error: request_error.to_string(),
2129 }
2130 })?;
2131
2132 let mut listener = self
2133 .listeners
2134 .values()
2135 .find(|l| l.borrow().address == front.address)
2136 .ok_or(ProxyError::NoListenerFound(front.address))?
2137 .borrow_mut();
2138
2139 let hostname = front.hostname.to_owned();
2140
2141 listener
2142 .remove_https_front(front)
2143 .map_err(ProxyError::RemoveFrontend)?;
2144
2145 if !listener.fronts.has_hostname(&hostname) {
2146 listener.set_tags(hostname, None);
2147 }
2148 Ok(None)
2149 }
2150
2151 pub fn add_certificate(
2152 &mut self,
2153 add_certificate: AddCertificate,
2154 ) -> Result<Option<ResponseContent>, ProxyError> {
2155 let address = add_certificate.address.into();
2156
2157 let listener = self
2158 .listeners
2159 .values()
2160 .find(|l| l.borrow().address == address)
2161 .ok_or(ProxyError::NoListenerFound(address))?
2162 .borrow_mut();
2163
2164 let mut resolver = listener
2165 .resolver
2166 .0
2167 .lock()
2168 .map_err(|e| ProxyError::Lock(e.to_string()))?;
2169
2170 resolver
2171 .add_certificate(&add_certificate)
2172 .map_err(ProxyError::AddCertificate)?;
2173
2174 Ok(None)
2175 }
2176
2177 pub fn remove_certificate(
2179 &mut self,
2180 remove_certificate: RemoveCertificate,
2181 ) -> Result<Option<ResponseContent>, ProxyError> {
2182 let address = remove_certificate.address.into();
2183
2184 let fingerprint = Fingerprint(
2185 hex::decode(&remove_certificate.fingerprint)
2186 .map_err(ProxyError::WrongCertificateFingerprint)?,
2187 );
2188
2189 let listener = self
2190 .listeners
2191 .values()
2192 .find(|l| l.borrow().address == address)
2193 .ok_or(ProxyError::NoListenerFound(address))?
2194 .borrow_mut();
2195
2196 let mut resolver = listener
2197 .resolver
2198 .0
2199 .lock()
2200 .map_err(|e| ProxyError::Lock(e.to_string()))?;
2201
2202 resolver
2203 .remove_certificate(&fingerprint)
2204 .map_err(ProxyError::RemoveCertificate)?;
2205
2206 Ok(None)
2207 }
2208
2209 pub fn replace_certificate(
2211 &mut self,
2212 replace_certificate: ReplaceCertificate,
2213 ) -> Result<Option<ResponseContent>, ProxyError> {
2214 let address = replace_certificate.address.into();
2215
2216 let listener = self
2217 .listeners
2218 .values()
2219 .find(|l| l.borrow().address == address)
2220 .ok_or(ProxyError::NoListenerFound(address))?
2221 .borrow_mut();
2222
2223 let mut resolver = listener
2224 .resolver
2225 .0
2226 .lock()
2227 .map_err(|e| ProxyError::Lock(e.to_string()))?;
2228
2229 resolver
2230 .replace_certificate(&replace_certificate)
2231 .map_err(ProxyError::ReplaceCertificate)?;
2232
2233 Ok(None)
2234 }
2235}
2236
2237impl ProxyConfiguration for HttpsProxy {
2238 fn accept(&mut self, token: ListenToken) -> Result<MioTcpStream, AcceptError> {
2239 match self.listeners.get(&Token(token.0)) {
2240 Some(listener) => listener.borrow_mut().accept(),
2241 None => Err(AcceptError::IoError),
2242 }
2243 }
2244
2245 fn create_session(
2246 &mut self,
2247 mut frontend_sock: MioTcpStream,
2248 token: ListenToken,
2249 wait_time: Duration,
2250 proxy: Rc<RefCell<Self>>,
2251 ) -> Result<(), AcceptError> {
2252 let listener = self
2253 .listeners
2254 .get(&Token(token.0))
2255 .ok_or(AcceptError::IoError)?;
2256 if let Err(e) = frontend_sock.set_nodelay(true) {
2257 error!(
2258 "{} error setting nodelay on front socket({:?}): {:?}",
2259 log_module_context!(),
2260 frontend_sock,
2261 e
2262 );
2263 }
2264
2265 let owned = listener.borrow();
2266 let rustls_details = ServerConnection::new(owned.rustls_details.clone()).map_err(|e| {
2267 error!(
2268 "{} failed to create server session: {:?}",
2269 log_module_context!(),
2270 e
2271 );
2272 AcceptError::IoError
2273 })?;
2274
2275 let mut session_manager = self.sessions.borrow_mut();
2276 let entry = session_manager.slab.vacant_entry();
2277 let session_token = Token(entry.key());
2278 debug_assert_eq!(
2283 session_token.0,
2284 entry.key(),
2285 "HTTPS session token must equal its slab key"
2286 );
2287
2288 self.registry
2289 .register(
2290 &mut frontend_sock,
2291 session_token,
2292 Interest::READABLE | Interest::WRITABLE,
2293 )
2294 .map_err(|register_error| {
2295 error!(
2296 "{} error registering front socket({:?}): {:?}",
2297 log_module_context!(),
2298 frontend_sock,
2299 register_error
2300 );
2301 AcceptError::RegisterError
2302 })?;
2303
2304 let public_address: StdSocketAddr = match owned.config.public_address {
2305 Some(pub_addr) => pub_addr.into(),
2306 None => owned.config.address.into(),
2307 };
2308
2309 let session = Rc::new(RefCell::new(HttpsSession::new(
2310 Duration::from_secs(owned.config.back_timeout as u64),
2311 Duration::from_secs(owned.config.connect_timeout as u64),
2312 Duration::from_secs(owned.config.front_timeout as u64),
2313 Duration::from_secs(owned.config.request_timeout as u64),
2314 owned.config.expect_proxy,
2315 listener.clone(),
2316 Rc::downgrade(&self.pool),
2317 proxy,
2318 public_address,
2319 rustls_details,
2320 frontend_sock,
2321 session_token,
2322 wait_time,
2323 )));
2324 debug_assert_eq!(
2328 session.borrow().frontend_token(),
2329 session_token,
2330 "stored HTTPS session must report the slab token as its frontend token"
2331 );
2332 entry.insert(session);
2333
2334 Ok(())
2335 }
2336
2337 fn notify(&mut self, request: WorkerRequest) -> WorkerResponse {
2338 let request_id = request.id.clone();
2339
2340 let request_type = match request.content.request_type {
2341 Some(t) => t,
2342 None => return WorkerResponse::error(request_id, "Empty request"),
2343 };
2344
2345 let content_result = match request_type {
2346 RequestType::AddCluster(cluster) => {
2347 debug!(
2348 "{} {} add cluster {:?}",
2349 log_module_context!(),
2350 request_id,
2351 cluster
2352 );
2353 self.add_cluster(cluster)
2354 }
2355 RequestType::RemoveCluster(cluster_id) => {
2356 debug!(
2357 "{} {} remove cluster {:?}",
2358 log_module_context!(),
2359 request_id,
2360 cluster_id
2361 );
2362 self.remove_cluster(&cluster_id)
2363 }
2364 RequestType::AddHttpsFrontend(front) => {
2365 debug!(
2366 "{} {} add https front {:?}",
2367 log_module_context!(),
2368 request_id,
2369 front
2370 );
2371 self.add_https_frontend(front)
2372 }
2373 RequestType::RemoveHttpsFrontend(front) => {
2374 debug!(
2375 "{} {} remove https front {:?}",
2376 log_module_context!(),
2377 request_id,
2378 front
2379 );
2380 self.remove_https_frontend(front)
2381 }
2382 RequestType::AddCertificate(add_certificate) => {
2383 debug!(
2384 "{} {} add certificate: {:?}",
2385 log_module_context!(),
2386 request_id,
2387 add_certificate
2388 );
2389 self.add_certificate(add_certificate)
2390 }
2391 RequestType::RemoveCertificate(remove_certificate) => {
2392 debug!(
2393 "{} {} remove certificate: {:?}",
2394 log_module_context!(),
2395 request_id,
2396 remove_certificate
2397 );
2398 self.remove_certificate(remove_certificate)
2399 }
2400 RequestType::ReplaceCertificate(replace_certificate) => {
2401 debug!(
2402 "{} {} replace certificate: {:?}",
2403 log_module_context!(),
2404 request_id,
2405 replace_certificate
2406 );
2407 self.replace_certificate(replace_certificate)
2408 }
2409 RequestType::RemoveListener(remove) => {
2410 debug!(
2411 "{} removing HTTPS listener at address {:?}",
2412 log_module_context!(),
2413 remove.address
2414 );
2415 self.remove_listener(remove)
2416 }
2417 RequestType::SoftStop(_) => {
2418 debug!(
2419 "{} {} processing soft shutdown",
2420 log_module_context!(),
2421 request_id
2422 );
2423 match self.soft_stop() {
2424 Ok(_) => {
2425 info!(
2426 "{} {} soft stop successful",
2427 log_module_context!(),
2428 request_id
2429 );
2430 return WorkerResponse::processing(request.id);
2431 }
2432 Err(e) => Err(e),
2433 }
2434 }
2435 RequestType::HardStop(_) => {
2436 debug!(
2437 "{} {} processing hard shutdown",
2438 log_module_context!(),
2439 request_id
2440 );
2441 match self.hard_stop() {
2442 Ok(_) => {
2443 debug!(
2444 "{} {} hard stop successful",
2445 log_module_context!(),
2446 request_id
2447 );
2448 return WorkerResponse::processing(request.id);
2449 }
2450 Err(e) => Err(e),
2451 }
2452 }
2453 RequestType::Status(_) => {
2454 debug!("{} {} status", log_module_context!(), request_id);
2455 Ok(None)
2456 }
2457 RequestType::QueryCertificatesFromWorkers(filters) => {
2458 if let Some(domain) = filters.domain {
2459 debug!(
2460 "{} {} query certificate for domain {}",
2461 log_module_context!(),
2462 request_id,
2463 domain
2464 );
2465 self.query_certificate_for_domain(domain)
2466 } else {
2467 debug!(
2468 "{} {} query all certificates",
2469 log_module_context!(),
2470 request_id
2471 );
2472 self.query_all_certificates()
2473 }
2474 }
2475 other_request => {
2476 debug!(
2477 "{} {} unsupported message for HTTPS proxy, ignoring {:?}",
2478 log_module_context!(),
2479 request.id,
2480 other_request
2481 );
2482 Err(ProxyError::UnsupportedMessage)
2483 }
2484 };
2485
2486 match content_result {
2487 Ok(content) => {
2488 debug!("{} {} successful", log_module_context!(), request_id);
2489 match content {
2490 Some(content) => WorkerResponse::ok_with_content(request_id, content),
2491 None => WorkerResponse::ok(request_id),
2492 }
2493 }
2494 Err(proxy_error) => {
2495 debug!(
2496 "{} {} unsuccessful: {}",
2497 log_module_context!(),
2498 request_id,
2499 proxy_error
2500 );
2501 WorkerResponse::error(request_id, proxy_error)
2502 }
2503 }
2504 }
2505}
2506impl L7Proxy for HttpsProxy {
2507 fn kind(&self) -> ListenerType {
2508 ListenerType::Https
2509 }
2510
2511 fn register_socket(
2512 &self,
2513 socket: &mut MioTcpStream,
2514 token: Token,
2515 interest: Interest,
2516 ) -> Result<(), std::io::Error> {
2517 self.registry.register(socket, token, interest)
2518 }
2519
2520 fn deregister_socket(&self, tcp_stream: &mut MioTcpStream) -> Result<(), std::io::Error> {
2521 self.registry.deregister(tcp_stream)
2522 }
2523
2524 fn add_session(&self, session: Rc<RefCell<dyn ProxySession>>) -> Token {
2525 let mut session_manager = self.sessions.borrow_mut();
2526 let entry = session_manager.slab.vacant_entry();
2527 let token = Token(entry.key());
2528 let _entry = entry.insert(session);
2529 token
2530 }
2531
2532 fn remove_session(&self, token: Token) -> bool {
2533 let mut sessions = self.sessions.borrow_mut();
2534 sessions.untrack_all_cluster_ip(token);
2537 sessions.slab.try_remove(token.0).is_some()
2538 }
2539
2540 fn backends(&self) -> Rc<RefCell<BackendMap>> {
2541 self.backends.clone()
2542 }
2543
2544 fn clusters(&self) -> &HashMap<ClusterId, Cluster> {
2545 &self.clusters
2546 }
2547
2548 fn sessions(&self) -> Rc<RefCell<SessionManager>> {
2549 self.sessions.clone()
2550 }
2551}
2552
2553fn rustls_version_str(version: ProtocolVersion) -> &'static str {
2555 match version {
2556 ProtocolVersion::SSLv2 => "tls.version.SSLv2",
2557 ProtocolVersion::SSLv3 => "tls.version.SSLv3",
2558 ProtocolVersion::TLSv1_0 => "tls.version.TLSv1_0",
2559 ProtocolVersion::TLSv1_1 => "tls.version.TLSv1_1",
2560 ProtocolVersion::TLSv1_2 => "tls.version.TLSv1_2",
2561 ProtocolVersion::TLSv1_3 => "tls.version.TLSv1_3",
2562 ProtocolVersion::DTLSv1_0 => "tls.version.DTLSv1_0",
2563 ProtocolVersion::DTLSv1_2 => "tls.version.DTLSv1_2",
2564 ProtocolVersion::DTLSv1_3 => "tls.version.DTLSv1_3",
2565 ProtocolVersion::Unknown(_) => "tls.version.Unknown",
2566 _ => "tls.version.unimplemented",
2567 }
2568}
2569
2570pub(crate) fn rustls_version_label(version: ProtocolVersion) -> Option<&'static str> {
2577 match version {
2578 ProtocolVersion::SSLv2 => Some("SSLv2"),
2579 ProtocolVersion::SSLv3 => Some("SSLv3"),
2580 ProtocolVersion::TLSv1_0 => Some("TLSv1.0"),
2581 ProtocolVersion::TLSv1_1 => Some("TLSv1.1"),
2582 ProtocolVersion::TLSv1_2 => Some("TLSv1.2"),
2583 ProtocolVersion::TLSv1_3 => Some("TLSv1.3"),
2584 ProtocolVersion::DTLSv1_0 => Some("DTLSv1.0"),
2585 ProtocolVersion::DTLSv1_2 => Some("DTLSv1.2"),
2586 ProtocolVersion::DTLSv1_3 => Some("DTLSv1.3"),
2587 _ => None,
2588 }
2589}
2590
2591fn rustls_ciphersuite_str(cipher: SupportedCipherSuite) -> &'static str {
2593 match cipher.suite() {
2594 CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 => {
2595 "tls.cipher.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256"
2596 }
2597 CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 => {
2598 "tls.cipher.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"
2599 }
2600 CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 => {
2601 "tls.cipher.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
2602 }
2603 CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 => {
2604 "tls.cipher.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
2605 }
2606 CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 => {
2607 "tls.cipher.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
2608 }
2609 CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 => {
2610 "tls.cipher.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
2611 }
2612 CipherSuite::TLS13_CHACHA20_POLY1305_SHA256 => "tls.cipher.TLS13_CHACHA20_POLY1305_SHA256",
2613 CipherSuite::TLS13_AES_256_GCM_SHA384 => "tls.cipher.TLS13_AES_256_GCM_SHA384",
2614 CipherSuite::TLS13_AES_128_GCM_SHA256 => "tls.cipher.TLS13_AES_128_GCM_SHA256",
2615 _ => "tls.cipher.Unsupported",
2616 }
2617}
2618
2619pub(crate) fn rustls_ciphersuite_label(cipher: SupportedCipherSuite) -> Option<&'static str> {
2626 match cipher.suite() {
2627 CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 => {
2628 Some("TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256")
2629 }
2630 CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 => {
2631 Some("TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256")
2632 }
2633 CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 => {
2634 Some("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256")
2635 }
2636 CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 => {
2637 Some("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384")
2638 }
2639 CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 => {
2640 Some("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256")
2641 }
2642 CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 => {
2643 Some("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384")
2644 }
2645 CipherSuite::TLS13_CHACHA20_POLY1305_SHA256 => Some("TLS13_CHACHA20_POLY1305_SHA256"),
2646 CipherSuite::TLS13_AES_256_GCM_SHA384 => Some("TLS13_AES_256_GCM_SHA384"),
2647 CipherSuite::TLS13_AES_128_GCM_SHA256 => Some("TLS13_AES_128_GCM_SHA256"),
2648 _ => None,
2649 }
2650}
2651
2652pub mod testing {
2653 use crate::testing::*;
2654
2655 pub fn start_https_worker(
2657 config: HttpsListenerConfig,
2658 channel: ProxyChannel,
2659 max_buffers: usize,
2660 buffer_size: usize,
2661 ) -> anyhow::Result<()> {
2662 let address = config.address.into();
2663
2664 let ServerParts {
2665 event_loop,
2666 registry,
2667 sessions,
2668 pool,
2669 backends,
2670 client_scm_socket: _,
2671 server_scm_socket,
2672 server_config,
2673 } = prebuild_server(max_buffers, buffer_size, true)?;
2674
2675 let token = {
2676 let mut sessions = sessions.borrow_mut();
2677 let entry = sessions.slab.vacant_entry();
2678 let key = entry.key();
2679 let _ = entry.insert(Rc::new(RefCell::new(ListenSession {
2680 protocol: Protocol::HTTPSListen,
2681 })));
2682 Token(key)
2683 };
2684
2685 let mut proxy = HttpsProxy::new(registry, sessions.clone(), pool.clone(), backends.clone());
2686 proxy
2687 .add_listener(config, token)
2688 .with_context(|| "Failed at creating adding the listener")?;
2689 proxy
2690 .activate_listener(&address, None)
2691 .with_context(|| "Failed at creating activating the listener")?;
2692
2693 let mut server = Server::new(
2694 event_loop,
2695 channel,
2696 server_scm_socket,
2697 sessions,
2698 pool,
2699 backends,
2700 None,
2701 Some(proxy),
2702 None,
2703 server_config,
2704 None,
2705 false,
2706 )
2707 .with_context(|| "Failed at creating server")?;
2708
2709 debug!("{} starting event loop", log_module_context!());
2710 server.run();
2711 debug!("{} ending event loop", log_module_context!());
2712 Ok(())
2713 }
2714}
2715
2716#[cfg(test)]
2717mod tests {
2718 use std::sync::Arc;
2719
2720 use sozu_command::{config::ListenerBuilder, proto::command::SocketAddress};
2721
2722 use super::*;
2723 use crate::router::{MethodRule, PathRule, Route, Router, pattern_trie::TrieNode};
2724
2725 #[test]
2743 fn frontend_from_request_test() {
2744 let cluster_id1 = "cluster_1".to_owned();
2745 let cluster_id2 = "cluster_2".to_owned();
2746 let cluster_id3 = "cluster_3".to_owned();
2747 let uri1 = "/".to_owned();
2748 let uri2 = "/yolo".to_owned();
2749 let uri3 = "/yolo/swag".to_owned();
2750
2751 let mut fronts = Router::new();
2752 assert!(fronts.add_tree_rule(
2753 "lolcatho.st".as_bytes(),
2754 &PathRule::Prefix(uri1),
2755 &MethodRule::new(None),
2756 &Route::ClusterId(cluster_id1.clone())
2757 ));
2758 assert!(fronts.add_tree_rule(
2759 "lolcatho.st".as_bytes(),
2760 &PathRule::Prefix(uri2),
2761 &MethodRule::new(None),
2762 &Route::ClusterId(cluster_id2)
2763 ));
2764 assert!(fronts.add_tree_rule(
2765 "lolcatho.st".as_bytes(),
2766 &PathRule::Prefix(uri3),
2767 &MethodRule::new(None),
2768 &Route::ClusterId(cluster_id3)
2769 ));
2770 assert!(fronts.add_tree_rule(
2771 "other.domain".as_bytes(),
2772 &PathRule::Prefix("test".to_string()),
2773 &MethodRule::new(None),
2774 &Route::ClusterId(cluster_id1)
2775 ));
2776
2777 let address = SocketAddress::new_v4(127, 0, 0, 1, 1032);
2778 let resolver = Arc::new(MutexCertificateResolver::default());
2779
2780 let crypto_provider = Arc::new(default_provider());
2781
2782 let server_config = RustlsServerConfig::builder_with_provider(crypto_provider)
2783 .with_protocol_versions(&[&rustls::version::TLS12, &rustls::version::TLS13])
2784 .expect("could not create rustls config server")
2785 .with_no_client_auth()
2786 .with_cert_resolver(resolver.clone());
2787
2788 let rustls_details = Arc::new(server_config);
2789
2790 let default_config = ListenerBuilder::new_https(address)
2791 .to_tls(None)
2792 .expect("Could not create default HTTPS listener config");
2793
2794 println!("it doesn't even matter");
2795
2796 let listener = HttpsListener {
2797 listener: None,
2798 address: address.into(),
2799 fronts,
2800 rustls_details,
2801 resolver,
2802 answers: Rc::new(RefCell::new(
2803 HttpAnswers::new(&std::collections::BTreeMap::new()).unwrap(),
2804 )),
2805 config: default_config,
2806 token: Token(0),
2807 active: true,
2808 tags: BTreeMap::new(),
2809 };
2810
2811 println!("TEST {}", line!());
2812 let frontend1 = listener.frontend_from_request("lolcatho.st", "/", &Method::Get);
2813 assert_eq!(
2814 frontend1
2815 .expect("should find a frontend")
2816 .cluster_id
2817 .as_deref(),
2818 Some("cluster_1")
2819 );
2820 println!("TEST {}", line!());
2821 let frontend2 = listener.frontend_from_request("lolcatho.st", "/test", &Method::Get);
2822 assert_eq!(
2823 frontend2
2824 .expect("should find a frontend")
2825 .cluster_id
2826 .as_deref(),
2827 Some("cluster_1")
2828 );
2829 println!("TEST {}", line!());
2830 let frontend3 = listener.frontend_from_request("lolcatho.st", "/yolo/test", &Method::Get);
2831 assert_eq!(
2832 frontend3
2833 .expect("should find a frontend")
2834 .cluster_id
2835 .as_deref(),
2836 Some("cluster_2")
2837 );
2838 println!("TEST {}", line!());
2839 let frontend4 = listener.frontend_from_request("lolcatho.st", "/yolo/swag", &Method::Get);
2840 assert_eq!(
2841 frontend4
2842 .expect("should find a frontend")
2843 .cluster_id
2844 .as_deref(),
2845 Some("cluster_3")
2846 );
2847 println!("TEST {}", line!());
2848 let frontend5 = listener.frontend_from_request("domain", "/", &Method::Get);
2849 assert!(frontend5.is_err());
2850 }
2852
2853 #[test]
2854 fn wildcard_certificate_names() {
2855 let mut trie = TrieNode::root();
2856
2857 trie.domain_insert("*.services.clever-cloud.com".as_bytes().to_vec(), 1u8);
2858 trie.domain_insert("*.clever-cloud.com".as_bytes().to_vec(), 2u8);
2859 trie.domain_insert("services.clever-cloud.com".as_bytes().to_vec(), 0u8);
2860 trie.domain_insert(
2861 "abprefix.services.clever-cloud.com".as_bytes().to_vec(),
2862 3u8,
2863 );
2864 trie.domain_insert(
2865 "cdprefix.services.clever-cloud.com".as_bytes().to_vec(),
2866 4u8,
2867 );
2868
2869 let res = trie.domain_lookup(b"test.services.clever-cloud.com", true);
2870 println!("query result: {res:?}");
2871
2872 assert_eq!(
2873 trie.domain_lookup(b"pgstudio.services.clever-cloud.com", true),
2874 Some(&("*.services.clever-cloud.com".as_bytes().to_vec(), 1u8))
2875 );
2876 assert_eq!(
2877 trie.domain_lookup(b"test-prefix.services.clever-cloud.com", true),
2878 Some(&("*.services.clever-cloud.com".as_bytes().to_vec(), 1u8))
2879 );
2880 }
2881
2882 #[test]
2883 fn wildcard_with_subdomains() {
2884 let mut trie = TrieNode::root();
2885
2886 trie.domain_insert("*.test.example.com".as_bytes().to_vec(), 1u8);
2887 trie.domain_insert("hello.sub.test.example.com".as_bytes().to_vec(), 2u8);
2888
2889 let res = trie.domain_lookup(b"sub.test.example.com", true);
2890 println!("query result: {res:?}");
2891
2892 assert_eq!(
2893 trie.domain_lookup(b"sub.test.example.com", true),
2894 Some(&("*.test.example.com".as_bytes().to_vec(), 1u8))
2895 );
2896 assert_eq!(
2897 trie.domain_lookup(b"hello.sub.test.example.com", true),
2898 Some(&("hello.sub.test.example.com".as_bytes().to_vec(), 2u8))
2899 );
2900
2901 let mut trie = TrieNode::root();
2903
2904 trie.domain_insert("hello.sub.test.example.com".as_bytes().to_vec(), 2u8);
2905 trie.domain_insert("*.test.example.com".as_bytes().to_vec(), 1u8);
2906
2907 let res = trie.domain_lookup(b"sub.test.example.com", true);
2908 println!("query result: {res:?}");
2909
2910 assert_eq!(
2911 trie.domain_lookup(b"sub.test.example.com", true),
2912 Some(&("*.test.example.com".as_bytes().to_vec(), 1u8))
2913 );
2914 assert_eq!(
2915 trie.domain_lookup(b"hello.sub.test.example.com", true),
2916 Some(&("hello.sub.test.example.com".as_bytes().to_vec(), 2u8))
2917 );
2918 }
2919
2920 #[test]
2921 fn h2_stream_idle_timeout_inherits_back_timeout() {
2922 use std::time::Duration;
2923
2924 let address = SocketAddress::new_v4(127, 0, 0, 1, 1041);
2925 let build = |back_timeout: u32, explicit: Option<u32>| -> HttpsListener {
2926 let mut cfg = ListenerBuilder::new_https(address)
2927 .to_tls(None)
2928 .expect("default HTTPS listener config");
2929 cfg.back_timeout = back_timeout;
2930 cfg.h2_stream_idle_timeout_seconds = explicit;
2931 HttpsListener::try_new(cfg, Token(0)).expect("build listener")
2932 };
2933
2934 assert_eq!(
2936 build(180, None).get_h2_stream_idle_timeout(),
2937 Duration::from_secs(180)
2938 );
2939
2940 assert_eq!(
2942 build(5, None).get_h2_stream_idle_timeout(),
2943 Duration::from_secs(30)
2944 );
2945
2946 assert_eq!(
2948 build(180, Some(10)).get_h2_stream_idle_timeout(),
2949 Duration::from_secs(10)
2950 );
2951 assert_eq!(
2952 build(5, Some(600)).get_h2_stream_idle_timeout(),
2953 Duration::from_secs(600)
2954 );
2955
2956 assert_eq!(
2958 build(180, Some(0)).get_h2_stream_idle_timeout(),
2959 Duration::from_secs(1)
2960 );
2961 }
2962}