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