1use std::{
2 cell::RefCell,
3 collections::{BTreeMap, HashMap, hash_map::Entry},
4 io::ErrorKind,
5 net::{Shutdown, SocketAddr as StdSocketAddr},
6 os::unix::io::AsRawFd,
7 rc::{Rc, Weak},
8 str::{from_utf8, from_utf8_unchecked},
9 sync::Arc,
10 time::{Duration, Instant},
11};
12
13use mio::{
14 Interest, Registry, Token,
15 net::{TcpListener as MioTcpListener, TcpStream as MioTcpStream},
16 unix::SourceFd,
17};
18use rustls::{
19 CipherSuite, ProtocolVersion, ServerConfig as RustlsServerConfig, ServerConnection,
20 SupportedCipherSuite,
21 crypto::{
22 CryptoProvider,
23 ring::{
24 self,
25 cipher_suite::{
26 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
27 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
28 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
29 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, TLS13_AES_128_GCM_SHA256,
30 TLS13_AES_256_GCM_SHA384, TLS13_CHACHA20_POLY1305_SHA256,
31 },
32 },
33 },
34};
35use rusty_ulid::Ulid;
36use sozu_command::{
37 certificate::Fingerprint,
38 config::DEFAULT_CIPHER_SUITES,
39 proto::command::{
40 AddCertificate, CertificateSummary, CertificatesByAddress, Cluster, HttpsListenerConfig,
41 ListOfCertificatesByAddress, ListenerType, RemoveCertificate, RemoveListener,
42 ReplaceCertificate, RequestHttpFrontend, ResponseContent, TlsVersion, WorkerRequest,
43 WorkerResponse, request::RequestType, response_content::ContentType,
44 },
45 ready::Ready,
46 response::HttpFrontend,
47 state::ClusterId,
48};
49
50use crate::{
51 AcceptError, CachedTags, FrontendFromRequestError, L7ListenerHandler, L7Proxy, ListenerError,
52 ListenerHandler, Protocol, ProxyConfiguration, ProxyError, ProxySession, SessionIsToBeClosed,
53 SessionMetrics, SessionResult, StateMachineBuilder, StateResult,
54 backends::BackendMap,
55 pool::Pool,
56 protocol::{
57 Http, Pipe, SessionState,
58 h2::Http2,
59 http::{
60 ResponseStream,
61 answers::HttpAnswers,
62 parser::{Method, hostname_and_port},
63 },
64 proxy_protocol::expect::ExpectProxyProtocol,
65 rustls::TlsHandshake,
66 },
67 router::{Route, Router},
68 server::{ListenToken, SessionManager},
69 socket::{FrontRustls, server_bind},
70 timer::TimeoutContainer,
71 tls::MutexCertificateResolver,
72 util::UnwrapLog,
73};
74
75const SERVER_PROTOS: &[&str] = &["http/1.1"];
77
78StateMachineBuilder! {
79 enum HttpsStateMachine impl SessionState {
86 Expect(ExpectProxyProtocol<MioTcpStream>, ServerConnection),
87 Handshake(TlsHandshake),
88 Http(Http<FrontRustls, HttpsListener>),
89 WebSocket(Pipe<FrontRustls, HttpsListener>),
90 Http2(Http2<FrontRustls>) -> todo!("H2"),
91 }
92}
93
94pub enum AlpnProtocols {
95 H2,
96 Http11,
97}
98
99pub struct HttpsSession {
100 answers: Rc<RefCell<HttpAnswers>>,
101 configured_backend_timeout: Duration,
102 configured_connect_timeout: Duration,
103 configured_frontend_timeout: Duration,
104 frontend_token: Token,
105 has_been_closed: bool,
106 last_event: Instant,
107 listener: Rc<RefCell<HttpsListener>>,
108 metrics: SessionMetrics,
109 peer_address: Option<StdSocketAddr>,
110 pool: Weak<RefCell<Pool>>,
111 proxy: Rc<RefCell<HttpsProxy>>,
112 public_address: StdSocketAddr,
113 state: HttpsStateMachine,
114 sticky_name: String,
115}
116
117impl HttpsSession {
118 #[allow(clippy::too_many_arguments)]
119 pub fn new(
120 answers: Rc<RefCell<HttpAnswers>>,
121 configured_backend_timeout: Duration,
122 configured_connect_timeout: Duration,
123 configured_frontend_timeout: Duration,
124 configured_request_timeout: Duration,
125 expect_proxy: bool,
126 listener: Rc<RefCell<HttpsListener>>,
127 pool: Weak<RefCell<Pool>>,
128 proxy: Rc<RefCell<HttpsProxy>>,
129 public_address: StdSocketAddr,
130 rustls_details: ServerConnection,
131 sock: MioTcpStream,
132 sticky_name: String,
133 token: Token,
134 wait_time: Duration,
135 ) -> HttpsSession {
136 let peer_address = if expect_proxy {
137 None
139 } else {
140 sock.peer_addr().ok()
141 };
142
143 let request_id = Ulid::generate();
144 let container_frontend_timeout = TimeoutContainer::new(configured_request_timeout, token);
145
146 let state = if expect_proxy {
147 trace!("starting in expect proxy state");
148 gauge_add!("protocol.proxy.expect", 1);
149 HttpsStateMachine::Expect(
150 ExpectProxyProtocol::new(container_frontend_timeout, sock, token, request_id),
151 rustls_details,
152 )
153 } else {
154 gauge_add!("protocol.tls.handshake", 1);
155 HttpsStateMachine::Handshake(TlsHandshake::new(
156 container_frontend_timeout,
157 rustls_details,
158 sock,
159 token,
160 request_id,
161 peer_address,
162 ))
163 };
164
165 let metrics = SessionMetrics::new(Some(wait_time));
166 HttpsSession {
167 answers,
168 configured_backend_timeout,
169 configured_connect_timeout,
170 configured_frontend_timeout,
171 frontend_token: token,
172 has_been_closed: false,
173 last_event: Instant::now(),
174 listener,
175 metrics,
176 peer_address,
177 pool,
178 proxy,
179 public_address,
180 state,
181 sticky_name,
182 }
183 }
184
185 pub fn upgrade(&mut self) -> SessionIsToBeClosed {
186 debug!("HTTP::upgrade");
187 let new_state = match self.state.take() {
188 HttpsStateMachine::Expect(expect, ssl) => self.upgrade_expect(expect, ssl),
189 HttpsStateMachine::Handshake(handshake) => self.upgrade_handshake(handshake),
190 HttpsStateMachine::Http(http) => self.upgrade_http(http),
191 HttpsStateMachine::Http2(_) => self.upgrade_http2(),
192 HttpsStateMachine::WebSocket(wss) => self.upgrade_websocket(wss),
193 HttpsStateMachine::FailedUpgrade(_) => unreachable!(),
194 };
195
196 match new_state {
197 Some(state) => {
198 self.state = state;
199 false
200 }
201 None => true,
203 }
204 }
205
206 fn upgrade_expect(
207 &mut self,
208 mut expect: ExpectProxyProtocol<MioTcpStream>,
209 ssl: ServerConnection,
210 ) -> Option<HttpsStateMachine> {
211 if let Some(ref addresses) = expect.addresses {
212 if let (Some(public_address), Some(session_address)) =
213 (addresses.destination(), addresses.source())
214 {
215 self.public_address = public_address;
216 self.peer_address = Some(session_address);
217
218 let ExpectProxyProtocol {
219 container_frontend_timeout,
220 frontend,
221 frontend_readiness: readiness,
222 request_id,
223 ..
224 } = expect;
225
226 let mut handshake = TlsHandshake::new(
227 container_frontend_timeout,
228 ssl,
229 frontend,
230 self.frontend_token,
231 request_id,
232 self.peer_address,
233 );
234 handshake.frontend_readiness.event = readiness.event;
235 handshake.frontend_readiness.event.insert(Ready::READABLE);
238
239 gauge_add!("protocol.proxy.expect", -1);
240 gauge_add!("protocol.tls.handshake", 1);
241 return Some(HttpsStateMachine::Handshake(handshake));
242 }
243 }
244
245 if !expect.container_frontend_timeout.cancel() {
247 error!(
248 "failed to cancel request timeout on expect upgrade phase for 'expect proxy protocol with AF_UNSPEC address'"
249 );
250 }
251
252 None
253 }
254
255 fn upgrade_handshake(&mut self, handshake: TlsHandshake) -> Option<HttpsStateMachine> {
256 let sni = handshake.session.server_name();
263 let alpn = handshake.session.alpn_protocol();
264 let alpn = alpn.and_then(|alpn| from_utf8(alpn).ok());
265 debug!(
266 "Successful TLS Handshake with, received: {:?} {:?}",
267 sni, alpn
268 );
269
270 let alpn = match alpn {
271 Some("http/1.1") => AlpnProtocols::Http11,
272 Some("h2") => AlpnProtocols::H2,
273 Some(other) => {
274 error!("Unsupported ALPN protocol: {}", other);
275 return None;
276 }
277 None => AlpnProtocols::Http11,
279 };
280
281 if let Some(version) = handshake.session.protocol_version() {
282 incr!(rustls_version_str(version));
283 };
284 if let Some(cipher) = handshake.session.negotiated_cipher_suite() {
285 incr!(rustls_ciphersuite_str(cipher));
286 };
287
288 let front_stream = FrontRustls {
289 stream: handshake.stream,
290 session: handshake.session,
291 };
292
293 gauge_add!("protocol.tls.handshake", -1);
294 match alpn {
295 AlpnProtocols::Http11 => {
296 let mut http = Http::new(
297 self.answers.clone(),
298 self.configured_backend_timeout,
299 self.configured_connect_timeout,
300 self.configured_frontend_timeout,
301 handshake.container_frontend_timeout,
302 front_stream,
303 self.frontend_token,
304 self.listener.clone(),
305 self.pool.clone(),
306 Protocol::HTTPS,
307 self.public_address,
308 handshake.request_id,
309 self.peer_address,
310 self.sticky_name.clone(),
311 )
312 .ok()?;
313
314 http.frontend_readiness.event = handshake.frontend_readiness.event;
315
316 gauge_add!("protocol.https", 1);
317 Some(HttpsStateMachine::Http(http))
318 }
319 AlpnProtocols::H2 => {
320 let mut http = Http2::new(
321 front_stream,
322 self.frontend_token,
323 self.pool.clone(),
324 Some(self.public_address),
325 None,
326 self.sticky_name.clone(),
327 );
328
329 http.frontend.readiness.event = handshake.frontend_readiness.event;
330
331 gauge_add!("protocol.http2", 1);
332 Some(HttpsStateMachine::Http2(http))
333 }
334 }
335 }
336
337 fn upgrade_http(&self, http: Http<FrontRustls, HttpsListener>) -> Option<HttpsStateMachine> {
338 debug!("https switching to wss");
339 let front_token = self.frontend_token;
340 let back_token = match http.backend_token {
341 Some(back_token) => back_token,
342 None => {
343 warn!(
344 "Could not upgrade https request on cluster '{:?}' ({:?}) using backend '{:?}' into secure websocket for request '{}'",
345 http.context.cluster_id,
346 self.frontend_token,
347 http.context.backend_id,
348 http.context.id
349 );
350 return None;
351 }
352 };
353
354 let ws_context = http.websocket_context();
355 let mut container_frontend_timeout = http.container_frontend_timeout;
356 let mut container_backend_timeout = http.container_backend_timeout;
357 container_frontend_timeout.reset();
358 container_backend_timeout.reset();
359
360 let backend_buffer = if let ResponseStream::BackendAnswer(kawa) = http.response_stream {
361 kawa.storage.buffer
362 } else {
363 return None;
364 };
365
366 let mut pipe = Pipe::new(
367 backend_buffer,
368 http.context.backend_id,
369 http.backend_socket,
370 http.backend,
371 Some(container_backend_timeout),
372 Some(container_frontend_timeout),
373 http.context.cluster_id,
374 http.request_stream.storage.buffer,
375 front_token,
376 http.frontend_socket,
377 self.listener.clone(),
378 Protocol::HTTP,
379 http.context.id,
380 http.context.session_address,
381 ws_context,
382 );
383
384 pipe.frontend_readiness.event = http.frontend_readiness.event;
385 pipe.backend_readiness.event = http.backend_readiness.event;
386 pipe.set_back_token(back_token);
387
388 gauge_add!("protocol.https", -1);
389 gauge_add!("protocol.wss", 1);
390 gauge_add!("http.active_requests", -1);
391 gauge_add!("websocket.active_requests", 1);
392 Some(HttpsStateMachine::WebSocket(pipe))
393 }
394
395 fn upgrade_http2(&self) -> Option<HttpsStateMachine> {
396 todo!()
397 }
398
399 fn upgrade_websocket(
400 &self,
401 wss: Pipe<FrontRustls, HttpsListener>,
402 ) -> Option<HttpsStateMachine> {
403 error!("Upgrade called on WSS, this should not happen");
405 Some(HttpsStateMachine::WebSocket(wss))
406 }
407}
408
409impl ProxySession for HttpsSession {
410 fn close(&mut self) {
411 if self.has_been_closed {
412 return;
413 }
414
415 trace!("Closing HTTPS session");
416 self.metrics.service_stop();
417
418 match self.state.marker() {
420 StateMarker::Expect => gauge_add!("protocol.proxy.expect", -1),
421 StateMarker::Handshake => gauge_add!("protocol.tls.handshake", -1),
422 StateMarker::Http => gauge_add!("protocol.https", -1),
423 StateMarker::WebSocket => {
424 gauge_add!("protocol.wss", -1);
425 gauge_add!("websocket.active_requests", -1);
426 }
427 StateMarker::Http2 => gauge_add!("protocol.http2", -1),
428 }
429
430 if self.state.failed() {
431 match self.state.marker() {
432 StateMarker::Expect => incr!("https.upgrade.expect.failed"),
433 StateMarker::Handshake => incr!("https.upgrade.handshake.failed"),
434 StateMarker::Http => incr!("https.upgrade.http.failed"),
435 StateMarker::WebSocket => incr!("https.upgrade.wss.failed"),
436 StateMarker::Http2 => incr!("https.upgrade.http2.failed"),
437 }
438 return;
439 }
440
441 self.state.cancel_timeouts();
442 self.state.close(self.proxy.clone(), &mut self.metrics);
445
446 let front_socket = self.state.front_socket();
447 if let Err(e) = front_socket.shutdown(Shutdown::Both) {
448 if e.kind() != ErrorKind::NotConnected {
450 error!(
451 "error shutting down front socket({:?}): {:?}",
452 front_socket, e
453 );
454 }
455 }
456
457 let proxy = self.proxy.borrow();
459 let fd = front_socket.as_raw_fd();
460 if let Err(e) = proxy.registry.deregister(&mut SourceFd(&fd)) {
461 error!(
462 "error deregistering front socket({:?}) while closing HTTPS session: {:?}",
463 fd, e
464 );
465 }
466 proxy.remove_session(self.frontend_token);
467
468 self.has_been_closed = true;
469 }
470
471 fn timeout(&mut self, token: Token) -> SessionIsToBeClosed {
472 let session_result = self.state.timeout(token, &mut self.metrics);
473 session_result == StateResult::CloseSession
474 }
475
476 fn protocol(&self) -> Protocol {
477 Protocol::HTTPS
478 }
479
480 fn update_readiness(&mut self, token: Token, events: Ready) {
481 trace!(
482 "token {:?} got event {}",
483 token,
484 super::ready_to_string(events)
485 );
486 self.last_event = Instant::now();
487 self.metrics.wait_start();
488 self.state.update_readiness(token, events);
489 }
490
491 fn ready(&mut self, session: Rc<RefCell<dyn ProxySession>>) -> SessionIsToBeClosed {
492 self.metrics.service_start();
493
494 let session_result =
495 self.state
496 .ready(session.clone(), self.proxy.clone(), &mut self.metrics);
497
498 let to_be_closed = match session_result {
499 SessionResult::Close => true,
500 SessionResult::Continue => false,
501 SessionResult::Upgrade => match self.upgrade() {
502 false => self.ready(session),
503 true => true,
504 },
505 };
506
507 self.metrics.service_stop();
508 to_be_closed
509 }
510
511 fn shutting_down(&mut self) -> SessionIsToBeClosed {
512 self.state.shutting_down()
513 }
514
515 fn last_event(&self) -> Instant {
516 self.last_event
517 }
518
519 fn print_session(&self) {
520 self.state.print_state("HTTPS");
521 error!("Metrics: {:?}", self.metrics);
522 }
523
524 fn frontend_token(&self) -> Token {
525 self.frontend_token
526 }
527}
528
529pub type HostName = String;
530pub type PathBegin = String;
531
532pub struct HttpsListener {
533 active: bool,
534 address: StdSocketAddr,
535 answers: Rc<RefCell<HttpAnswers>>,
536 config: HttpsListenerConfig,
537 fronts: Router,
538 listener: Option<MioTcpListener>,
539 resolver: Arc<MutexCertificateResolver>,
540 rustls_details: Arc<RustlsServerConfig>,
541 tags: BTreeMap<String, CachedTags>,
542 token: Token,
543}
544
545impl ListenerHandler for HttpsListener {
546 fn get_addr(&self) -> &StdSocketAddr {
547 &self.address
548 }
549
550 fn get_tags(&self, key: &str) -> Option<&CachedTags> {
551 self.tags.get(key)
552 }
553
554 fn set_tags(&mut self, key: String, tags: Option<BTreeMap<String, String>>) {
555 match tags {
556 Some(tags) => self.tags.insert(key, CachedTags::new(tags)),
557 None => self.tags.remove(&key),
558 };
559 }
560}
561
562impl L7ListenerHandler for HttpsListener {
563 fn get_sticky_name(&self) -> &str {
564 &self.config.sticky_name
565 }
566
567 fn get_connect_timeout(&self) -> u32 {
568 self.config.connect_timeout
569 }
570
571 fn frontend_from_request(
572 &self,
573 host: &str,
574 uri: &str,
575 method: &Method,
576 ) -> Result<Route, FrontendFromRequestError> {
577 let start = Instant::now();
578 let (remaining_input, (hostname, _)) = match hostname_and_port(host.as_bytes()) {
579 Ok(tuple) => tuple,
580 Err(parse_error) => {
581 return Err(FrontendFromRequestError::HostParse {
583 host: host.to_owned(),
584 error: parse_error.to_string(),
585 });
586 }
587 };
588
589 if remaining_input != &b""[..] {
590 return Err(FrontendFromRequestError::InvalidCharsAfterHost(
591 host.to_owned(),
592 ));
593 }
594
595 let host = unsafe { from_utf8_unchecked(hostname) };
599
600 let route = self.fronts.lookup(host, uri, method).map_err(|e| {
601 incr!("http.failed_backend_matching");
602 FrontendFromRequestError::NoClusterFound(e)
603 })?;
604
605 let now = Instant::now();
606
607 if let Route::ClusterId(cluster) = &route {
608 time!("frontend_matching_time", cluster, (now - start).as_millis());
609 }
610
611 Ok(route)
612 }
613}
614
615impl HttpsListener {
616 pub fn try_new(
617 config: HttpsListenerConfig,
618 token: Token,
619 ) -> Result<HttpsListener, ListenerError> {
620 let resolver = Arc::new(MutexCertificateResolver::default());
621
622 let server_config = Arc::new(Self::create_rustls_context(&config, resolver.to_owned())?);
623
624 Ok(HttpsListener {
625 listener: None,
626 address: config.address.into(),
627 resolver,
628 rustls_details: server_config,
629 active: false,
630 fronts: Router::new(),
631 answers: Rc::new(RefCell::new(
632 HttpAnswers::new(&config.http_answers)
633 .map_err(|(status, error)| ListenerError::TemplateParse(status, error))?,
634 )),
635 config,
636 token,
637 tags: BTreeMap::new(),
638 })
639 }
640
641 pub fn activate(
642 &mut self,
643 registry: &Registry,
644 tcp_listener: Option<MioTcpListener>,
645 ) -> Result<Token, ListenerError> {
646 if self.active {
647 return Ok(self.token);
648 }
649 let address: StdSocketAddr = self.config.address.into();
650
651 let mut listener = match tcp_listener {
652 Some(tcp_listener) => tcp_listener,
653 None => {
654 server_bind(address).map_err(|server_bind_error| ListenerError::Activation {
655 address,
656 error: server_bind_error.to_string(),
657 })?
658 }
659 };
660
661 registry
662 .register(&mut listener, self.token, Interest::READABLE)
663 .map_err(ListenerError::SocketRegistration)?;
664
665 self.listener = Some(listener);
666 self.active = true;
667 Ok(self.token)
668 }
669
670 pub fn create_rustls_context(
671 config: &HttpsListenerConfig,
672 resolver: Arc<MutexCertificateResolver>,
673 ) -> Result<RustlsServerConfig, ListenerError> {
674 let cipher_names = if config.cipher_list.is_empty() {
675 DEFAULT_CIPHER_SUITES.to_vec()
676 } else {
677 config
678 .cipher_list
679 .iter()
680 .map(|s| s.as_str())
681 .collect::<Vec<_>>()
682 };
683
684 #[rustfmt::skip]
685 let ciphers = cipher_names
686 .into_iter()
687 .filter_map(|cipher| match cipher {
688 "TLS13_CHACHA20_POLY1305_SHA256" => Some(TLS13_CHACHA20_POLY1305_SHA256),
689 "TLS13_AES_256_GCM_SHA384" => Some(TLS13_AES_256_GCM_SHA384),
690 "TLS13_AES_128_GCM_SHA256" => Some(TLS13_AES_128_GCM_SHA256),
691 "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256" => Some(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256),
692 "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" => Some(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256),
693 "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384" => Some(TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384),
694 "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" => Some(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256),
695 "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" => Some(TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384),
696 "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" => Some(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256),
697 other_cipher => {
698 error!("unknown cipher: {:?}", other_cipher);
699 None
700 }
701 })
702 .collect::<Vec<_>>();
703
704 let versions = config
705 .versions
706 .iter()
707 .filter_map(|version| match TlsVersion::try_from(*version) {
708 Ok(TlsVersion::TlsV12) => Some(&rustls::version::TLS12),
709 Ok(TlsVersion::TlsV13) => Some(&rustls::version::TLS13),
710 Ok(other_version) => {
711 error!("unsupported TLS version {:?}", other_version);
712 None
713 }
714 Err(_) => {
715 error!("unsupported TLS version");
716 None
717 }
718 })
719 .collect::<Vec<_>>();
720
721 let provider = CryptoProvider {
722 cipher_suites: ciphers,
723 ..ring::default_provider()
724 };
725
726 let mut server_config = RustlsServerConfig::builder_with_provider(provider.into())
727 .with_protocol_versions(&versions[..])
728 .map_err(|err| ListenerError::BuildRustls(err.to_string()))?
729 .with_no_client_auth()
730 .with_cert_resolver(resolver);
731 server_config.send_tls13_tickets = config.send_tls13_tickets as usize;
732
733 let mut protocols = SERVER_PROTOS
734 .iter()
735 .map(|proto| proto.as_bytes().to_vec())
736 .collect::<Vec<_>>();
737 server_config.alpn_protocols.append(&mut protocols);
738
739 Ok(server_config)
740 }
741
742 pub fn add_https_front(&mut self, tls_front: HttpFrontend) -> Result<(), ListenerError> {
743 self.fronts
744 .add_http_front(&tls_front)
745 .map_err(ListenerError::AddFrontend)
746 }
747
748 pub fn remove_https_front(&mut self, tls_front: HttpFrontend) -> Result<(), ListenerError> {
749 debug!("removing tls_front {:?}", tls_front);
750 self.fronts
751 .remove_http_front(&tls_front)
752 .map_err(ListenerError::RemoveFrontend)
753 }
754
755 fn accept(&mut self) -> Result<MioTcpStream, AcceptError> {
756 if let Some(ref sock) = self.listener {
757 sock.accept()
758 .map_err(|e| match e.kind() {
759 ErrorKind::WouldBlock => AcceptError::WouldBlock,
760 _ => {
761 error!("accept() IO error: {:?}", e);
762 AcceptError::IoError
763 }
764 })
765 .map(|(sock, _)| sock)
766 } else {
767 error!("cannot accept connections, no listening socket available");
768 Err(AcceptError::IoError)
769 }
770 }
771}
772
773pub struct HttpsProxy {
774 listeners: HashMap<Token, Rc<RefCell<HttpsListener>>>,
775 clusters: HashMap<ClusterId, Cluster>,
776 backends: Rc<RefCell<BackendMap>>,
777 pool: Rc<RefCell<Pool>>,
778 registry: Registry,
779 sessions: Rc<RefCell<SessionManager>>,
780}
781
782impl HttpsProxy {
783 pub fn new(
784 registry: Registry,
785 sessions: Rc<RefCell<SessionManager>>,
786 pool: Rc<RefCell<Pool>>,
787 backends: Rc<RefCell<BackendMap>>,
788 ) -> HttpsProxy {
789 HttpsProxy {
790 listeners: HashMap::new(),
791 clusters: HashMap::new(),
792 backends,
793 pool,
794 registry,
795 sessions,
796 }
797 }
798
799 pub fn add_listener(
800 &mut self,
801 config: HttpsListenerConfig,
802 token: Token,
803 ) -> Result<Token, ProxyError> {
804 match self.listeners.entry(token) {
805 Entry::Vacant(entry) => {
806 let https_listener =
807 HttpsListener::try_new(config, token).map_err(ProxyError::AddListener)?;
808 entry.insert(Rc::new(RefCell::new(https_listener)));
809 Ok(token)
810 }
811 _ => Err(ProxyError::ListenerAlreadyPresent),
812 }
813 }
814
815 pub fn remove_listener(
816 &mut self,
817 remove: RemoveListener,
818 ) -> Result<Option<ResponseContent>, ProxyError> {
819 let len = self.listeners.len();
820
821 let remove_address = remove.address.into();
822 self.listeners
823 .retain(|_, listener| listener.borrow().address != remove_address);
824
825 if !self.listeners.len() < len {
826 info!("no HTTPS listener to remove at address {}", remove_address)
827 }
828 Ok(None)
829 }
830
831 pub fn soft_stop(&mut self) -> Result<(), ProxyError> {
832 let listeners: HashMap<_, _> = self.listeners.drain().collect();
833 let mut socket_errors = vec![];
834 for (_, l) in listeners.iter() {
835 if let Some(mut sock) = l.borrow_mut().listener.take() {
836 debug!("Deregistering socket {:?}", sock);
837 if let Err(e) = self.registry.deregister(&mut sock) {
838 let error = format!("socket {sock:?}: {e:?}");
839 socket_errors.push(error);
840 }
841 }
842 }
843
844 if !socket_errors.is_empty() {
845 return Err(ProxyError::SoftStop {
846 proxy_protocol: "HTTPS".to_string(),
847 error: format!("Error deregistering listen sockets: {:?}", socket_errors),
848 });
849 }
850
851 Ok(())
852 }
853
854 pub fn hard_stop(&mut self) -> Result<(), ProxyError> {
855 let mut listeners: HashMap<_, _> = self.listeners.drain().collect();
856 let mut socket_errors = vec![];
857 for (_, l) in listeners.drain() {
858 if let Some(mut sock) = l.borrow_mut().listener.take() {
859 debug!("Deregistering socket {:?}", sock);
860 if let Err(e) = self.registry.deregister(&mut sock) {
861 let error = format!("socket {sock:?}: {e:?}");
862 socket_errors.push(error);
863 }
864 }
865 }
866
867 if !socket_errors.is_empty() {
868 return Err(ProxyError::HardStop {
869 proxy_protocol: "HTTPS".to_string(),
870 error: format!("Error deregistering listen sockets: {:?}", socket_errors),
871 });
872 }
873
874 Ok(())
875 }
876
877 pub fn query_all_certificates(&mut self) -> Result<Option<ResponseContent>, ProxyError> {
878 let certificates = self
879 .listeners
880 .values()
881 .map(|listener| {
882 let owned = listener.borrow();
883 let resolver = unwrap_msg!(owned.resolver.0.lock());
884 let certificate_summaries = resolver
885 .domains
886 .to_hashmap()
887 .drain()
888 .map(|(k, fingerprint)| CertificateSummary {
889 domain: String::from_utf8(k).unwrap(),
890 fingerprint: fingerprint.to_string(),
891 })
892 .collect();
893
894 CertificatesByAddress {
895 address: owned.address.into(),
896 certificate_summaries,
897 }
898 })
899 .collect();
900
901 info!(
902 "got Certificates::All query, answering with {:?}",
903 certificates
904 );
905
906 Ok(Some(
907 ContentType::CertificatesByAddress(ListOfCertificatesByAddress { certificates }).into(),
908 ))
909 }
910
911 pub fn query_certificate_for_domain(
912 &mut self,
913 domain: String,
914 ) -> Result<Option<ResponseContent>, ProxyError> {
915 let certificates = self
916 .listeners
917 .values()
918 .map(|listener| {
919 let owned = listener.borrow();
920 let resolver = unwrap_msg!(owned.resolver.0.lock());
921 let mut certificate_summaries = vec![];
922
923 if let Some((k, fingerprint)) = resolver.domain_lookup(domain.as_bytes(), true) {
924 certificate_summaries.push(CertificateSummary {
925 domain: String::from_utf8(k.to_vec()).unwrap(),
926 fingerprint: fingerprint.to_string(),
927 });
928 }
929 CertificatesByAddress {
930 address: owned.address.into(),
931 certificate_summaries,
932 }
933 })
934 .collect();
935
936 info!(
937 "got Certificates::Domain({}) query, answering with {:?}",
938 domain, certificates
939 );
940
941 Ok(Some(
942 ContentType::CertificatesByAddress(ListOfCertificatesByAddress { certificates }).into(),
943 ))
944 }
945
946 pub fn activate_listener(
947 &mut self,
948 addr: &StdSocketAddr,
949 tcp_listener: Option<MioTcpListener>,
950 ) -> Result<Token, ProxyError> {
951 let listener = self
952 .listeners
953 .values()
954 .find(|listener| listener.borrow().address == *addr)
955 .ok_or(ProxyError::NoListenerFound(addr.to_owned()))?;
956
957 listener
958 .borrow_mut()
959 .activate(&self.registry, tcp_listener)
960 .map_err(|listener_error| ProxyError::ListenerActivation {
961 address: *addr,
962 listener_error,
963 })
964 }
965
966 pub fn give_back_listeners(&mut self) -> Vec<(StdSocketAddr, MioTcpListener)> {
967 self.listeners
968 .values()
969 .filter_map(|listener| {
970 let mut owned = listener.borrow_mut();
971 if let Some(listener) = owned.listener.take() {
972 return Some((owned.address, listener));
973 }
974
975 None
976 })
977 .collect()
978 }
979
980 pub fn give_back_listener(
981 &mut self,
982 address: StdSocketAddr,
983 ) -> Result<(Token, MioTcpListener), ProxyError> {
984 let listener = self
985 .listeners
986 .values()
987 .find(|listener| listener.borrow().address == address)
988 .ok_or(ProxyError::NoListenerFound(address))?;
989
990 let mut owned = listener.borrow_mut();
991
992 let taken_listener = owned
993 .listener
994 .take()
995 .ok_or(ProxyError::UnactivatedListener)?;
996
997 Ok((owned.token, taken_listener))
998 }
999
1000 pub fn add_cluster(
1001 &mut self,
1002 mut cluster: Cluster,
1003 ) -> Result<Option<ResponseContent>, ProxyError> {
1004 if let Some(answer_503) = cluster.answer_503.take() {
1005 for listener in self.listeners.values() {
1006 listener
1007 .borrow()
1008 .answers
1009 .borrow_mut()
1010 .add_custom_answer(&cluster.cluster_id, answer_503.clone())
1011 .map_err(|(status, error)| {
1012 ProxyError::AddCluster(ListenerError::TemplateParse(status, error))
1013 })?;
1014 }
1015 }
1016 self.clusters.insert(cluster.cluster_id.clone(), cluster);
1017 Ok(None)
1018 }
1019
1020 pub fn remove_cluster(
1021 &mut self,
1022 cluster_id: &str,
1023 ) -> Result<Option<ResponseContent>, ProxyError> {
1024 self.clusters.remove(cluster_id);
1025 for listener in self.listeners.values() {
1026 listener
1027 .borrow()
1028 .answers
1029 .borrow_mut()
1030 .remove_custom_answer(cluster_id);
1031 }
1032
1033 Ok(None)
1034 }
1035
1036 pub fn add_https_frontend(
1037 &mut self,
1038 front: RequestHttpFrontend,
1039 ) -> Result<Option<ResponseContent>, ProxyError> {
1040 let front = front.clone().to_frontend().map_err(|request_error| {
1041 ProxyError::WrongInputFrontend {
1042 front,
1043 error: request_error.to_string(),
1044 }
1045 })?;
1046
1047 let mut listener = self
1048 .listeners
1049 .values()
1050 .find(|l| l.borrow().address == front.address)
1051 .ok_or(ProxyError::NoListenerFound(front.address))?
1052 .borrow_mut();
1053
1054 listener.set_tags(front.hostname.to_owned(), front.tags.to_owned());
1055 listener
1056 .add_https_front(front)
1057 .map_err(ProxyError::AddFrontend)?;
1058 Ok(None)
1059 }
1060
1061 pub fn remove_https_frontend(
1062 &mut self,
1063 front: RequestHttpFrontend,
1064 ) -> Result<Option<ResponseContent>, ProxyError> {
1065 let front = front.clone().to_frontend().map_err(|request_error| {
1066 ProxyError::WrongInputFrontend {
1067 front,
1068 error: request_error.to_string(),
1069 }
1070 })?;
1071
1072 let mut listener = self
1073 .listeners
1074 .values()
1075 .find(|l| l.borrow().address == front.address)
1076 .ok_or(ProxyError::NoListenerFound(front.address))?
1077 .borrow_mut();
1078
1079 listener.set_tags(front.hostname.to_owned(), None);
1080 listener
1081 .remove_https_front(front)
1082 .map_err(ProxyError::RemoveFrontend)?;
1083 Ok(None)
1084 }
1085
1086 pub fn add_certificate(
1087 &mut self,
1088 add_certificate: AddCertificate,
1089 ) -> Result<Option<ResponseContent>, ProxyError> {
1090 let address = add_certificate.address.into();
1091
1092 let listener = self
1093 .listeners
1094 .values()
1095 .find(|l| l.borrow().address == address)
1096 .ok_or(ProxyError::NoListenerFound(address))?
1097 .borrow_mut();
1098
1099 let mut resolver = listener
1100 .resolver
1101 .0
1102 .lock()
1103 .map_err(|e| ProxyError::Lock(e.to_string()))?;
1104
1105 resolver
1106 .add_certificate(&add_certificate)
1107 .map_err(ProxyError::AddCertificate)?;
1108
1109 Ok(None)
1110 }
1111
1112 pub fn remove_certificate(
1114 &mut self,
1115 remove_certificate: RemoveCertificate,
1116 ) -> Result<Option<ResponseContent>, ProxyError> {
1117 let address = remove_certificate.address.into();
1118
1119 let fingerprint = Fingerprint(
1120 hex::decode(&remove_certificate.fingerprint)
1121 .map_err(ProxyError::WrongCertificateFingerprint)?,
1122 );
1123
1124 let listener = self
1125 .listeners
1126 .values()
1127 .find(|l| l.borrow().address == address)
1128 .ok_or(ProxyError::NoListenerFound(address))?
1129 .borrow_mut();
1130
1131 let mut resolver = listener
1132 .resolver
1133 .0
1134 .lock()
1135 .map_err(|e| ProxyError::Lock(e.to_string()))?;
1136
1137 resolver
1138 .remove_certificate(&fingerprint)
1139 .map_err(ProxyError::RemoveCertificate)?;
1140
1141 Ok(None)
1142 }
1143
1144 pub fn replace_certificate(
1146 &mut self,
1147 replace_certificate: ReplaceCertificate,
1148 ) -> Result<Option<ResponseContent>, ProxyError> {
1149 let address = replace_certificate.address.into();
1150
1151 let listener = self
1152 .listeners
1153 .values()
1154 .find(|l| l.borrow().address == address)
1155 .ok_or(ProxyError::NoListenerFound(address))?
1156 .borrow_mut();
1157
1158 let mut resolver = listener
1159 .resolver
1160 .0
1161 .lock()
1162 .map_err(|e| ProxyError::Lock(e.to_string()))?;
1163
1164 resolver
1165 .replace_certificate(&replace_certificate)
1166 .map_err(ProxyError::ReplaceCertificate)?;
1167
1168 Ok(None)
1169 }
1170}
1171
1172impl ProxyConfiguration for HttpsProxy {
1173 fn accept(&mut self, token: ListenToken) -> Result<MioTcpStream, AcceptError> {
1174 match self.listeners.get(&Token(token.0)) {
1175 Some(listener) => listener.borrow_mut().accept(),
1176 None => Err(AcceptError::IoError),
1177 }
1178 }
1179
1180 fn create_session(
1181 &mut self,
1182 mut frontend_sock: MioTcpStream,
1183 token: ListenToken,
1184 wait_time: Duration,
1185 proxy: Rc<RefCell<Self>>,
1186 ) -> Result<(), AcceptError> {
1187 let listener = self
1188 .listeners
1189 .get(&Token(token.0))
1190 .ok_or(AcceptError::IoError)?;
1191 if let Err(e) = frontend_sock.set_nodelay(true) {
1192 error!(
1193 "error setting nodelay on front socket({:?}): {:?}",
1194 frontend_sock, e
1195 );
1196 }
1197
1198 let owned = listener.borrow();
1199 let rustls_details = ServerConnection::new(owned.rustls_details.clone()).map_err(|e| {
1200 error!("failed to create server session: {:?}", e);
1201 AcceptError::IoError
1202 })?;
1203
1204 let mut session_manager = self.sessions.borrow_mut();
1205 let entry = session_manager.slab.vacant_entry();
1206 let session_token = Token(entry.key());
1207
1208 self.registry
1209 .register(
1210 &mut frontend_sock,
1211 session_token,
1212 Interest::READABLE | Interest::WRITABLE,
1213 )
1214 .map_err(|register_error| {
1215 error!(
1216 "error registering front socket({:?}): {:?}",
1217 frontend_sock, register_error
1218 );
1219 AcceptError::RegisterError
1220 })?;
1221
1222 let public_address: StdSocketAddr = match owned.config.public_address {
1223 Some(pub_addr) => pub_addr.into(),
1224 None => owned.config.address.into(),
1225 };
1226
1227 let session = Rc::new(RefCell::new(HttpsSession::new(
1228 owned.answers.clone(),
1229 Duration::from_secs(owned.config.back_timeout as u64),
1230 Duration::from_secs(owned.config.connect_timeout as u64),
1231 Duration::from_secs(owned.config.front_timeout as u64),
1232 Duration::from_secs(owned.config.request_timeout as u64),
1233 owned.config.expect_proxy,
1234 listener.clone(),
1235 Rc::downgrade(&self.pool),
1236 proxy,
1237 public_address,
1238 rustls_details,
1239 frontend_sock,
1240 owned.config.sticky_name.clone(),
1241 session_token,
1242 wait_time,
1243 )));
1244 entry.insert(session);
1245
1246 Ok(())
1247 }
1248
1249 fn notify(&mut self, request: WorkerRequest) -> WorkerResponse {
1250 let request_id = request.id.clone();
1251
1252 let request_type = match request.content.request_type {
1253 Some(t) => t,
1254 None => return WorkerResponse::error(request_id, "Empty request"),
1255 };
1256
1257 let content_result = match request_type {
1258 RequestType::AddCluster(cluster) => {
1259 debug!("{} add cluster {:?}", request_id, cluster);
1260 self.add_cluster(cluster)
1261 }
1262 RequestType::RemoveCluster(cluster_id) => {
1263 debug!("{} remove cluster {:?}", request_id, cluster_id);
1264 self.remove_cluster(&cluster_id)
1265 }
1266 RequestType::AddHttpsFrontend(front) => {
1267 debug!("{} add https front {:?}", request_id, front);
1268 self.add_https_frontend(front)
1269 }
1270 RequestType::RemoveHttpsFrontend(front) => {
1271 debug!("{} remove https front {:?}", request_id, front);
1272 self.remove_https_frontend(front)
1273 }
1274 RequestType::AddCertificate(add_certificate) => {
1275 debug!("{} add certificate: {:?}", request_id, add_certificate);
1276 self.add_certificate(add_certificate)
1277 }
1278 RequestType::RemoveCertificate(remove_certificate) => {
1279 debug!(
1280 "{} remove certificate: {:?}",
1281 request_id, remove_certificate
1282 );
1283 self.remove_certificate(remove_certificate)
1284 }
1285 RequestType::ReplaceCertificate(replace_certificate) => {
1286 debug!(
1287 "{} replace certificate: {:?}",
1288 request_id, replace_certificate
1289 );
1290 self.replace_certificate(replace_certificate)
1291 }
1292 RequestType::RemoveListener(remove) => {
1293 debug!("removing HTTPS listener at address {:?}", remove.address);
1294 self.remove_listener(remove)
1295 }
1296 RequestType::SoftStop(_) => {
1297 debug!("{} processing soft shutdown", request_id);
1298 match self.soft_stop() {
1299 Ok(_) => {
1300 info!("{} soft stop successful", request_id);
1301 return WorkerResponse::processing(request.id);
1302 }
1303 Err(e) => Err(e),
1304 }
1305 }
1306 RequestType::HardStop(_) => {
1307 debug!("{} processing hard shutdown", request_id);
1308 match self.hard_stop() {
1309 Ok(_) => {
1310 debug!("{} hard stop successful", request_id);
1311 return WorkerResponse::processing(request.id);
1312 }
1313 Err(e) => Err(e),
1314 }
1315 }
1316 RequestType::Status(_) => {
1317 debug!("{} status", request_id);
1318 Ok(None)
1319 }
1320 RequestType::QueryCertificatesFromWorkers(filters) => {
1321 if let Some(domain) = filters.domain {
1322 debug!("{} query certificate for domain {}", request_id, domain);
1323 self.query_certificate_for_domain(domain)
1324 } else {
1325 debug!("{} query all certificates", request_id);
1326 self.query_all_certificates()
1327 }
1328 }
1329 other_request => {
1330 debug!(
1331 "{} unsupported message for HTTPS proxy, ignoring {:?}",
1332 request.id, other_request
1333 );
1334 Err(ProxyError::UnsupportedMessage)
1335 }
1336 };
1337
1338 match content_result {
1339 Ok(content) => {
1340 debug!("{} successful", request_id);
1341 match content {
1342 Some(content) => WorkerResponse::ok_with_content(request_id, content),
1343 None => WorkerResponse::ok(request_id),
1344 }
1345 }
1346 Err(proxy_error) => {
1347 debug!("{} unsuccessful: {}", request_id, proxy_error);
1348 WorkerResponse::error(request_id, proxy_error)
1349 }
1350 }
1351 }
1352}
1353impl L7Proxy for HttpsProxy {
1354 fn kind(&self) -> ListenerType {
1355 ListenerType::Https
1356 }
1357
1358 fn register_socket(
1359 &self,
1360 socket: &mut MioTcpStream,
1361 token: Token,
1362 interest: Interest,
1363 ) -> Result<(), std::io::Error> {
1364 self.registry.register(socket, token, interest)
1365 }
1366
1367 fn deregister_socket(&self, tcp_stream: &mut MioTcpStream) -> Result<(), std::io::Error> {
1368 self.registry.deregister(tcp_stream)
1369 }
1370
1371 fn add_session(&self, session: Rc<RefCell<dyn ProxySession>>) -> Token {
1372 let mut session_manager = self.sessions.borrow_mut();
1373 let entry = session_manager.slab.vacant_entry();
1374 let token = Token(entry.key());
1375 let _entry = entry.insert(session);
1376 token
1377 }
1378
1379 fn remove_session(&self, token: Token) -> bool {
1380 self.sessions
1381 .borrow_mut()
1382 .slab
1383 .try_remove(token.0)
1384 .is_some()
1385 }
1386
1387 fn backends(&self) -> Rc<RefCell<BackendMap>> {
1388 self.backends.clone()
1389 }
1390
1391 fn clusters(&self) -> &HashMap<ClusterId, Cluster> {
1392 &self.clusters
1393 }
1394}
1395
1396fn rustls_version_str(version: ProtocolVersion) -> &'static str {
1398 match version {
1399 ProtocolVersion::SSLv2 => "tls.version.SSLv2",
1400 ProtocolVersion::SSLv3 => "tls.version.SSLv3",
1401 ProtocolVersion::TLSv1_0 => "tls.version.TLSv1_0",
1402 ProtocolVersion::TLSv1_1 => "tls.version.TLSv1_1",
1403 ProtocolVersion::TLSv1_2 => "tls.version.TLSv1_2",
1404 ProtocolVersion::TLSv1_3 => "tls.version.TLSv1_3",
1405 ProtocolVersion::DTLSv1_0 => "tls.version.DTLSv1_0",
1406 ProtocolVersion::DTLSv1_2 => "tls.version.DTLSv1_2",
1407 ProtocolVersion::DTLSv1_3 => "tls.version.DTLSv1_3",
1408 ProtocolVersion::Unknown(_) => "tls.version.Unknown",
1409 _ => "tls.version.unimplemented",
1410 }
1411}
1412
1413fn rustls_ciphersuite_str(cipher: SupportedCipherSuite) -> &'static str {
1415 match cipher.suite() {
1416 CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 => {
1417 "tls.cipher.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256"
1418 }
1419 CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 => {
1420 "tls.cipher.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"
1421 }
1422 CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 => {
1423 "tls.cipher.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
1424 }
1425 CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 => {
1426 "tls.cipher.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
1427 }
1428 CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 => {
1429 "tls.cipher.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
1430 }
1431 CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 => {
1432 "tls.cipher.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
1433 }
1434 CipherSuite::TLS13_CHACHA20_POLY1305_SHA256 => "tls.cipher.TLS13_CHACHA20_POLY1305_SHA256",
1435 CipherSuite::TLS13_AES_256_GCM_SHA384 => "tls.cipher.TLS13_AES_256_GCM_SHA384",
1436 CipherSuite::TLS13_AES_128_GCM_SHA256 => "tls.cipher.TLS13_AES_128_GCM_SHA256",
1437 _ => "tls.cipher.Unsupported",
1438 }
1439}
1440
1441pub mod testing {
1442 use crate::testing::*;
1443
1444 pub fn start_https_worker(
1446 config: HttpsListenerConfig,
1447 channel: ProxyChannel,
1448 max_buffers: usize,
1449 buffer_size: usize,
1450 ) -> anyhow::Result<()> {
1451 let address = config.address.into();
1452
1453 let ServerParts {
1454 event_loop,
1455 registry,
1456 sessions,
1457 pool,
1458 backends,
1459 client_scm_socket: _,
1460 server_scm_socket,
1461 server_config,
1462 } = prebuild_server(max_buffers, buffer_size, true)?;
1463
1464 let token = {
1465 let mut sessions = sessions.borrow_mut();
1466 let entry = sessions.slab.vacant_entry();
1467 let key = entry.key();
1468 let _ = entry.insert(Rc::new(RefCell::new(ListenSession {
1469 protocol: Protocol::HTTPSListen,
1470 })));
1471 Token(key)
1472 };
1473
1474 let mut proxy = HttpsProxy::new(registry, sessions.clone(), pool.clone(), backends.clone());
1475 proxy
1476 .add_listener(config, token)
1477 .with_context(|| "Failed at creating adding the listener")?;
1478 proxy
1479 .activate_listener(&address, None)
1480 .with_context(|| "Failed at creating activating the listener")?;
1481
1482 let mut server = Server::new(
1483 event_loop,
1484 channel,
1485 server_scm_socket,
1486 sessions,
1487 pool,
1488 backends,
1489 None,
1490 Some(proxy),
1491 None,
1492 server_config,
1493 None,
1494 false,
1495 )
1496 .with_context(|| "Failed at creating server")?;
1497
1498 debug!("starting event loop");
1499 server.run();
1500 debug!("ending event loop");
1501 Ok(())
1502 }
1503}
1504
1505#[cfg(test)]
1506mod tests {
1507 use std::sync::Arc;
1508
1509 use sozu_command::{
1510 config::ListenerBuilder,
1511 proto::command::{CustomHttpAnswers, SocketAddress},
1512 };
1513
1514 use super::*;
1515 use crate::router::{MethodRule, PathRule, Route, Router, pattern_trie::TrieNode};
1516
1517 #[test]
1535 fn frontend_from_request_test() {
1536 let cluster_id1 = "cluster_1".to_owned();
1537 let cluster_id2 = "cluster_2".to_owned();
1538 let cluster_id3 = "cluster_3".to_owned();
1539 let uri1 = "/".to_owned();
1540 let uri2 = "/yolo".to_owned();
1541 let uri3 = "/yolo/swag".to_owned();
1542
1543 let mut fronts = Router::new();
1544 assert!(fronts.add_tree_rule(
1545 "lolcatho.st".as_bytes(),
1546 &PathRule::Prefix(uri1),
1547 &MethodRule::new(None),
1548 &Route::ClusterId(cluster_id1.clone())
1549 ));
1550 assert!(fronts.add_tree_rule(
1551 "lolcatho.st".as_bytes(),
1552 &PathRule::Prefix(uri2),
1553 &MethodRule::new(None),
1554 &Route::ClusterId(cluster_id2)
1555 ));
1556 assert!(fronts.add_tree_rule(
1557 "lolcatho.st".as_bytes(),
1558 &PathRule::Prefix(uri3),
1559 &MethodRule::new(None),
1560 &Route::ClusterId(cluster_id3)
1561 ));
1562 assert!(fronts.add_tree_rule(
1563 "other.domain".as_bytes(),
1564 &PathRule::Prefix("test".to_string()),
1565 &MethodRule::new(None),
1566 &Route::ClusterId(cluster_id1)
1567 ));
1568
1569 let address = SocketAddress::new_v4(127, 0, 0, 1, 1032);
1570 let resolver = Arc::new(MutexCertificateResolver::default());
1571
1572 let crypto_provider = Arc::new(ring::default_provider());
1573
1574 let server_config = RustlsServerConfig::builder_with_provider(crypto_provider)
1575 .with_protocol_versions(&[&rustls::version::TLS12, &rustls::version::TLS13])
1576 .expect("could not create rustls config server")
1577 .with_no_client_auth()
1578 .with_cert_resolver(resolver.clone());
1579
1580 let rustls_details = Arc::new(server_config);
1581
1582 let default_config = ListenerBuilder::new_https(address.clone())
1583 .to_tls(None)
1584 .expect("Could not create default HTTPS listener config");
1585
1586 println!("it doesn't even matter");
1587
1588 let listener = HttpsListener {
1589 listener: None,
1590 address: address.into(),
1591 fronts,
1592 rustls_details,
1593 resolver,
1594 answers: Rc::new(RefCell::new(
1595 HttpAnswers::new(&Some(CustomHttpAnswers::default())).unwrap(),
1596 )),
1597 config: default_config,
1598 token: Token(0),
1599 active: true,
1600 tags: BTreeMap::new(),
1601 };
1602
1603 println!("TEST {}", line!());
1604 let frontend1 = listener.frontend_from_request("lolcatho.st", "/", &Method::Get);
1605 assert_eq!(
1606 frontend1.expect("should find a frontend"),
1607 Route::ClusterId("cluster_1".to_string())
1608 );
1609 println!("TEST {}", line!());
1610 let frontend2 = listener.frontend_from_request("lolcatho.st", "/test", &Method::Get);
1611 assert_eq!(
1612 frontend2.expect("should find a frontend"),
1613 Route::ClusterId("cluster_1".to_string())
1614 );
1615 println!("TEST {}", line!());
1616 let frontend3 = listener.frontend_from_request("lolcatho.st", "/yolo/test", &Method::Get);
1617 assert_eq!(
1618 frontend3.expect("should find a frontend"),
1619 Route::ClusterId("cluster_2".to_string())
1620 );
1621 println!("TEST {}", line!());
1622 let frontend4 = listener.frontend_from_request("lolcatho.st", "/yolo/swag", &Method::Get);
1623 assert_eq!(
1624 frontend4.expect("should find a frontend"),
1625 Route::ClusterId("cluster_3".to_string())
1626 );
1627 println!("TEST {}", line!());
1628 let frontend5 = listener.frontend_from_request("domain", "/", &Method::Get);
1629 assert!(frontend5.is_err());
1630 }
1632
1633 #[test]
1634 fn wildcard_certificate_names() {
1635 let mut trie = TrieNode::root();
1636
1637 trie.domain_insert("*.services.clever-cloud.com".as_bytes().to_vec(), 1u8);
1638 trie.domain_insert("*.clever-cloud.com".as_bytes().to_vec(), 2u8);
1639 trie.domain_insert("services.clever-cloud.com".as_bytes().to_vec(), 0u8);
1640 trie.domain_insert(
1641 "abprefix.services.clever-cloud.com".as_bytes().to_vec(),
1642 3u8,
1643 );
1644 trie.domain_insert(
1645 "cdprefix.services.clever-cloud.com".as_bytes().to_vec(),
1646 4u8,
1647 );
1648
1649 let res = trie.domain_lookup(b"test.services.clever-cloud.com", true);
1650 println!("query result: {res:?}");
1651
1652 assert_eq!(
1653 trie.domain_lookup(b"pgstudio.services.clever-cloud.com", true),
1654 Some(&("*.services.clever-cloud.com".as_bytes().to_vec(), 1u8))
1655 );
1656 assert_eq!(
1657 trie.domain_lookup(b"test-prefix.services.clever-cloud.com", true),
1658 Some(&("*.services.clever-cloud.com".as_bytes().to_vec(), 1u8))
1659 );
1660 }
1661
1662 #[test]
1663 fn wildcard_with_subdomains() {
1664 let mut trie = TrieNode::root();
1665
1666 trie.domain_insert("*.test.example.com".as_bytes().to_vec(), 1u8);
1667 trie.domain_insert("hello.sub.test.example.com".as_bytes().to_vec(), 2u8);
1668
1669 let res = trie.domain_lookup(b"sub.test.example.com", true);
1670 println!("query result: {res:?}");
1671
1672 assert_eq!(
1673 trie.domain_lookup(b"sub.test.example.com", true),
1674 Some(&("*.test.example.com".as_bytes().to_vec(), 1u8))
1675 );
1676 assert_eq!(
1677 trie.domain_lookup(b"hello.sub.test.example.com", true),
1678 Some(&("hello.sub.test.example.com".as_bytes().to_vec(), 2u8))
1679 );
1680
1681 let mut trie = TrieNode::root();
1683
1684 trie.domain_insert("hello.sub.test.example.com".as_bytes().to_vec(), 2u8);
1685 trie.domain_insert("*.test.example.com".as_bytes().to_vec(), 1u8);
1686
1687 let res = trie.domain_lookup(b"sub.test.example.com", true);
1688 println!("query result: {res:?}");
1689
1690 assert_eq!(
1691 trie.domain_lookup(b"sub.test.example.com", true),
1692 Some(&("*.test.example.com".as_bytes().to_vec(), 1u8))
1693 );
1694 assert_eq!(
1695 trie.domain_lookup(b"hello.sub.test.example.com", true),
1696 Some(&("hello.sub.test.example.com".as_bytes().to_vec(), 2u8))
1697 );
1698 }
1699}