sozu_lib/
https.rs

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
75// const SERVER_PROTOS: &[&str] = &["http/1.1", "h2"];
76const SERVER_PROTOS: &[&str] = &["http/1.1"];
77
78StateMachineBuilder! {
79    /// The various Stages of an HTTPS connection:
80    ///
81    /// - optional (ExpectProxyProtocol)
82    /// - TLS handshake
83    /// - HTTP or HTTP2
84    /// - WebSocket (passthrough), only from HTTP
85    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            // Will be defined later once the expect proxy header has been received and parsed
138            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            // The state stays FailedUpgrade, but the Session should be closed right after
202            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                // Can we remove this? If not why?
236                // Add e2e test for proto-proxy upgrades
237                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        // currently, only happens in expect proxy protocol with AF_UNSPEC address
246        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        // Add 1st routing phase
257        // - get SNI
258        // - get ALPN
259        // - find corresponding listener
260        // - determine next protocol (tcps, https ,http2)
261
262        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            // Some client don't fill in the ALPN protocol, in this case we default to Http/1.1
278            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        // what do we do here?
404        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        // Restore gauges
419        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        // defer backend closing to the state
443        // in case of https it should also send a close notify on the client before the socket is closed below
444        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            // error 107 NotConnected can happen when was never fully connected, or was already disconnected due to error
449            if e.kind() != ErrorKind::NotConnected {
450                error!(
451                    "error shutting down front socket({:?}): {:?}",
452                    front_socket, e
453                );
454            }
455        }
456
457        // deregister the frontend and remove it
458        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                // parse_error contains a slice of given_host, which should NOT escape this scope
582                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        // it is alright to call from_utf8_unchecked,
596        // we already verified that there are only ascii
597        // chars in there
598        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    //FIXME: should return an error if certificate still has fronts referencing it
1113    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    //FIXME: should return an error if certificate still has fronts referencing it
1145    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
1396/// Used for metrics keeping
1397fn 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
1413/// Used for metrics keeping
1414fn 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    /// this function is not used, but is available for example and testing purposes
1445    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    /*
1518    #[test]
1519    #[cfg(target_pointer_width = "64")]
1520    fn size_test() {
1521      assert_size!(ExpectProxyProtocol<mio::net::TcpStream>, 520);
1522      assert_size!(TlsHandshake, 240);
1523      assert_size!(Http<SslStream<mio::net::TcpStream>>, 1232);
1524      assert_size!(Pipe<SslStream<mio::net::TcpStream>>, 272);
1525      assert_size!(State, 1240);
1526      // fails depending on the platform?
1527      assert_size!(Session, 1672);
1528
1529      assert_size!(SslStream<mio::net::TcpStream>, 16);
1530      assert_size!(Ssl, 8);
1531    }
1532    */
1533
1534    #[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        // assert!(false);
1631    }
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        // now try in a different order
1682        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}