1use crate::connectors::{l4::BindTo, L4Connect};
18use crate::protocols::l4::socket::SocketAddr;
19use crate::protocols::tls::CaType;
20#[cfg(feature = "openssl_derived")]
21use crate::protocols::tls::HandshakeCompleteHook;
22#[cfg(feature = "s2n")]
23use crate::protocols::tls::PskType;
24#[cfg(unix)]
25use crate::protocols::ConnFdReusable;
26use crate::protocols::TcpKeepalive;
27use crate::utils::tls::{get_organization_unit, CertKey};
28use ahash::AHasher;
29use derivative::Derivative;
30use pingora_error::{
31 ErrorType::{InternalError, SocketError},
32 OrErr, Result,
33};
34#[cfg(feature = "s2n")]
35use pingora_s2n::S2NPolicy;
36use std::borrow::Cow;
37use std::collections::BTreeMap;
38use std::fmt::{Display, Formatter, Result as FmtResult};
39use std::hash::{Hash, Hasher};
40use std::net::{IpAddr, SocketAddr as InetSocketAddr, ToSocketAddrs as ToInetSocketAddrs};
41#[cfg(unix)]
42use std::os::unix::{net::SocketAddr as UnixSocketAddr, prelude::AsRawFd};
43#[cfg(windows)]
44use std::os::windows::io::AsRawSocket;
45use std::path::{Path, PathBuf};
46use std::sync::Arc;
47use std::time::Duration;
48use tokio::net::TcpSocket;
49
50pub use crate::protocols::tls::ALPN;
51
52pub type ProxyDigestUserDataHook = Arc<
60 dyn Fn(
61 &http::request::Parts, &pingora_http::ResponseHeader, ) -> Option<Box<dyn std::any::Any + Send + Sync>>
64 + Send
65 + Sync
66 + 'static,
67>;
68
69pub trait Tracing: Send + Sync + std::fmt::Debug {
71 fn on_connected(&self);
73 fn on_disconnected(&self);
75 fn boxed_clone(&self) -> Box<dyn Tracing>;
77}
78
79#[derive(Debug)]
81pub struct Tracer(pub Box<dyn Tracing>);
82
83impl Clone for Tracer {
84 fn clone(&self) -> Self {
85 Tracer(self.0.boxed_clone())
86 }
87}
88
89pub trait Peer: Display + Clone {
92 fn address(&self) -> &SocketAddr;
94 fn tls(&self) -> bool;
96 fn sni(&self) -> &str;
98 fn reuse_hash(&self) -> u64;
103 fn get_proxy(&self) -> Option<&Proxy> {
105 None
106 }
107 fn get_peer_options(&self) -> Option<&PeerOptions> {
111 None
112 }
113 fn get_mut_peer_options(&mut self) -> Option<&mut PeerOptions> {
115 None
116 }
117 fn verify_cert(&self) -> bool {
119 match self.get_peer_options() {
120 Some(opt) => opt.verify_cert,
121 None => false,
122 }
123 }
124 fn verify_hostname(&self) -> bool {
126 match self.get_peer_options() {
127 Some(opt) => opt.verify_hostname,
128 None => false,
129 }
130 }
131 #[cfg(feature = "s2n")]
133 fn use_system_certs(&self) -> bool {
134 match self.get_peer_options() {
135 Some(opt) => opt.use_system_certs,
136 None => false,
137 }
138 }
139 fn alternative_cn(&self) -> Option<&String> {
144 match self.get_peer_options() {
145 Some(opt) => opt.alternative_cn.as_ref(),
146 None => None,
147 }
148 }
149 fn bind_to(&self) -> Option<&BindTo> {
151 match self.get_peer_options() {
152 Some(opt) => opt.bind_to.as_ref(),
153 None => None,
154 }
155 }
156 fn connection_timeout(&self) -> Option<Duration> {
158 match self.get_peer_options() {
159 Some(opt) => opt.connection_timeout,
160 None => None,
161 }
162 }
163 fn total_connection_timeout(&self) -> Option<Duration> {
165 match self.get_peer_options() {
166 Some(opt) => opt.total_connection_timeout,
167 None => None,
168 }
169 }
170 fn idle_timeout(&self) -> Option<Duration> {
173 self.get_peer_options().and_then(|o| o.idle_timeout)
174 }
175
176 fn get_alpn(&self) -> Option<&ALPN> {
178 self.get_peer_options().map(|opt| &opt.alpn)
179 }
180
181 fn get_ca(&self) -> Option<&Arc<CaType>> {
185 match self.get_peer_options() {
186 Some(opt) => opt.ca.as_ref(),
187 None => None,
188 }
189 }
190
191 fn get_client_cert_key(&self) -> Option<&Arc<CertKey>> {
193 None
194 }
195
196 #[cfg(feature = "s2n")]
200 fn get_psk(&self) -> Option<&Arc<PskType>> {
201 match self.get_peer_options() {
202 Some(opt) => opt.psk.as_ref(),
203 None => None,
204 }
205 }
206
207 #[cfg(feature = "s2n")]
212 fn get_s2n_security_policy(&self) -> Option<&S2NPolicy> {
213 match self.get_peer_options() {
214 Some(opt) => opt.s2n_security_policy.as_ref(),
215 None => None,
216 }
217 }
218
219 #[cfg(feature = "s2n")]
223 fn get_max_blinding_delay(&self) -> Option<u32> {
224 match self.get_peer_options() {
225 Some(opt) => opt.max_blinding_delay,
226 None => None,
227 }
228 }
229
230 fn tcp_keepalive(&self) -> Option<&TcpKeepalive> {
232 self.get_peer_options()
233 .and_then(|o| o.tcp_keepalive.as_ref())
234 }
235
236 fn h2_ping_interval(&self) -> Option<Duration> {
238 self.get_peer_options().and_then(|o| o.h2_ping_interval)
239 }
240
241 fn tcp_recv_buf(&self) -> Option<usize> {
243 self.get_peer_options().and_then(|o| o.tcp_recv_buf)
244 }
245
246 fn dscp(&self) -> Option<u8> {
249 self.get_peer_options().and_then(|o| o.dscp)
250 }
251
252 fn tcp_fast_open(&self) -> bool {
254 self.get_peer_options()
255 .map(|o| o.tcp_fast_open)
256 .unwrap_or_default()
257 }
258
259 #[cfg(unix)]
260 fn matches_fd<V: AsRawFd>(&self, fd: V) -> bool {
261 self.address().check_fd_match(fd)
262 }
263
264 #[cfg(windows)]
265 fn matches_sock<V: AsRawSocket>(&self, sock: V) -> bool {
266 use crate::protocols::ConnSockReusable;
267 self.address().check_sock_match(sock)
268 }
269
270 fn get_tracer(&self) -> Option<Tracer> {
271 None
272 }
273
274 fn upstream_tcp_sock_tweak_hook(
278 &self,
279 ) -> Option<&Arc<dyn Fn(&TcpSocket) -> Result<()> + Send + Sync + 'static>> {
280 self.get_peer_options()?
281 .upstream_tcp_sock_tweak_hook
282 .as_ref()
283 }
284
285 fn proxy_digest_user_data_hook(&self) -> Option<&ProxyDigestUserDataHook> {
288 self.get_peer_options()?
289 .proxy_digest_user_data_hook
290 .as_ref()
291 }
292
293 #[cfg(feature = "openssl_derived")]
302 fn upstream_tls_handshake_complete_hook(&self) -> Option<&HandshakeCompleteHook> {
303 self.get_peer_options()?
304 .upstream_tls_handshake_complete_hook
305 .as_ref()
306 }
307}
308
309#[derive(Debug, Clone)]
311pub struct BasicPeer {
312 pub _address: SocketAddr,
313 pub sni: String,
314 pub options: PeerOptions,
315}
316
317impl BasicPeer {
318 pub fn new(address: &str) -> Self {
320 let addr = SocketAddr::Inet(address.parse().unwrap()); Self::new_from_sockaddr(addr)
322 }
323
324 #[cfg(unix)]
326 pub fn new_uds<P: AsRef<Path>>(path: P) -> Result<Self> {
327 let addr = SocketAddr::Unix(
328 UnixSocketAddr::from_pathname(path.as_ref())
329 .or_err(InternalError, "while creating BasicPeer")?,
330 );
331 Ok(Self::new_from_sockaddr(addr))
332 }
333
334 fn new_from_sockaddr(sockaddr: SocketAddr) -> Self {
335 BasicPeer {
336 _address: sockaddr,
337 sni: "".to_string(), options: PeerOptions::new(),
339 }
340 }
341}
342
343impl Display for BasicPeer {
344 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
345 write!(f, "{:?}", self)
346 }
347}
348
349impl Peer for BasicPeer {
350 fn address(&self) -> &SocketAddr {
351 &self._address
352 }
353
354 fn tls(&self) -> bool {
355 !self.sni.is_empty()
356 }
357
358 fn bind_to(&self) -> Option<&BindTo> {
359 None
360 }
361
362 fn sni(&self) -> &str {
363 &self.sni
364 }
365
366 fn reuse_hash(&self) -> u64 {
368 let mut hasher = AHasher::default();
369 self._address.hash(&mut hasher);
370 hasher.finish()
371 }
372
373 fn get_peer_options(&self) -> Option<&PeerOptions> {
374 Some(&self.options)
375 }
376}
377
378#[derive(Hash, Clone, Debug, PartialEq)]
380pub enum Scheme {
381 HTTP,
382 HTTPS,
383}
384
385impl Display for Scheme {
386 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
387 match self {
388 Scheme::HTTP => write!(f, "HTTP"),
389 Scheme::HTTPS => write!(f, "HTTPS"),
390 }
391 }
392}
393
394impl Scheme {
395 pub fn from_tls_bool(tls: bool) -> Self {
396 if tls {
397 Self::HTTPS
398 } else {
399 Self::HTTP
400 }
401 }
402}
403
404#[derive(Clone, Copy, Debug, Eq, PartialEq)]
409pub struct HttpUpstreamRequestPolicy {
410 pub strip_hop_by_hop: bool,
416 pub strip_connection_nominated: bool,
422 pub reject_malformed_connection_nominations: bool,
429 pub h1_upgrade: H1UpgradePolicy,
431}
432
433impl HttpUpstreamRequestPolicy {
434 pub fn standard() -> Self {
436 Self::default()
437 }
438
439 pub fn preserve() -> Self {
445 Self {
446 strip_hop_by_hop: false,
447 strip_connection_nominated: false,
448 reject_malformed_connection_nominations: false,
449 h1_upgrade: H1UpgradePolicy::Preserve,
450 }
451 }
452
453 pub fn deny_upgrades() -> Self {
455 Self {
456 h1_upgrade: H1UpgradePolicy::Deny,
457 ..Self::default()
458 }
459 }
460}
461
462impl Default for HttpUpstreamRequestPolicy {
463 fn default() -> Self {
464 Self {
465 strip_hop_by_hop: true,
466 strip_connection_nominated: true,
467 reject_malformed_connection_nominations: true,
468 h1_upgrade: H1UpgradePolicy::WebSocketOnly,
469 }
470 }
471}
472
473#[derive(Clone, Copy, Debug, Eq, PartialEq)]
475pub enum H1UpgradePolicy {
476 WebSocketOnly,
478 Preserve,
489 Deny,
491}
492
493#[non_exhaustive]
497#[derive(Clone, Derivative)]
498#[derivative(Debug)]
499pub struct PeerOptions {
500 pub bind_to: Option<BindTo>,
501 pub connection_timeout: Option<Duration>,
502 pub total_connection_timeout: Option<Duration>,
503 pub read_timeout: Option<Duration>,
504 pub idle_timeout: Option<Duration>,
505 pub write_timeout: Option<Duration>,
506 pub verify_cert: bool,
507 pub verify_hostname: bool,
508 #[cfg(feature = "s2n")]
509 pub use_system_certs: bool,
510 pub alternative_cn: Option<String>,
512 pub alpn: ALPN,
513 pub ca: Option<Arc<CaType>>,
514 pub tcp_keepalive: Option<TcpKeepalive>,
515 pub tcp_recv_buf: Option<usize>,
516 pub dscp: Option<u8>,
517 pub h2_ping_interval: Option<Duration>,
518 #[cfg(feature = "s2n")]
519 pub psk: Option<Arc<PskType>>,
520 #[cfg(feature = "s2n")]
521 pub s2n_security_policy: Option<S2NPolicy>,
522 #[cfg(feature = "s2n")]
523 pub max_blinding_delay: Option<u32>,
524 pub max_h2_streams: usize,
526 pub h2_stream_window_size: Option<u32>,
529 pub h2_connection_window_size: Option<u32>,
532 pub allow_h1_response_invalid_content_length: bool,
544 pub http_upstream_request_policy: HttpUpstreamRequestPolicy,
546 pub extra_proxy_headers: BTreeMap<String, Vec<u8>>,
547 pub curves: Option<Cow<'static, str>>,
550 pub second_keyshare: bool,
552 pub tcp_fast_open: bool,
554 pub tracer: Option<Tracer>,
556 pub custom_l4: Option<Arc<dyn L4Connect + Send + Sync>>,
558 #[derivative(Debug = "ignore")]
559 pub upstream_tcp_sock_tweak_hook:
560 Option<Arc<dyn Fn(&TcpSocket) -> Result<()> + Send + Sync + 'static>>,
561 #[derivative(Debug = "ignore")]
562 pub proxy_digest_user_data_hook: Option<ProxyDigestUserDataHook>,
563 #[cfg(feature = "openssl_derived")]
568 #[derivative(Debug = "ignore")]
569 pub upstream_tls_handshake_complete_hook: Option<HandshakeCompleteHook>,
570}
571
572impl PeerOptions {
573 pub fn new() -> Self {
575 PeerOptions {
576 bind_to: None,
577 connection_timeout: None,
578 total_connection_timeout: None,
579 read_timeout: None,
580 idle_timeout: None,
581 write_timeout: None,
582 verify_cert: true,
583 verify_hostname: true,
584 #[cfg(feature = "s2n")]
585 use_system_certs: true,
586 alternative_cn: None,
587 alpn: ALPN::H1,
588 ca: None,
589 tcp_keepalive: None,
590 tcp_recv_buf: None,
591 dscp: None,
592 h2_ping_interval: None,
593 #[cfg(feature = "s2n")]
594 psk: None,
595 #[cfg(feature = "s2n")]
596 s2n_security_policy: None,
597 #[cfg(feature = "s2n")]
598 max_blinding_delay: None,
599 max_h2_streams: 1,
600 h2_stream_window_size: None,
601 h2_connection_window_size: None,
602 allow_h1_response_invalid_content_length: false,
603 http_upstream_request_policy: HttpUpstreamRequestPolicy::default(),
604 extra_proxy_headers: BTreeMap::new(),
605 curves: None,
606 second_keyshare: true, tcp_fast_open: false,
608 tracer: None,
609 custom_l4: None,
610 upstream_tcp_sock_tweak_hook: None,
611 proxy_digest_user_data_hook: None,
612 #[cfg(feature = "openssl_derived")]
613 upstream_tls_handshake_complete_hook: None,
614 }
615 }
616
617 pub fn set_http_version(&mut self, max: u8, min: u8) {
619 self.alpn = ALPN::new(max, min);
620 }
621}
622
623impl Display for PeerOptions {
624 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
625 if let Some(b) = self.bind_to.as_ref() {
626 write!(f, "bind_to: {:?},", b)?;
627 }
628 if let Some(t) = self.connection_timeout {
629 write!(f, "conn_timeout: {:?},", t)?;
630 }
631 if let Some(t) = self.total_connection_timeout {
632 write!(f, "total_conn_timeout: {:?},", t)?;
633 }
634 if self.verify_cert {
635 write!(f, "verify_cert: true,")?;
636 }
637 if self.verify_hostname {
638 write!(f, "verify_hostname: true,")?;
639 }
640 #[cfg(feature = "s2n")]
641 if self.use_system_certs {
642 write!(f, "use_system_certs: true,")?;
643 }
644 if let Some(cn) = &self.alternative_cn {
645 write!(f, "alt_cn: {},", cn)?;
646 }
647 write!(f, "alpn: {},", self.alpn)?;
648 if let Some(cas) = &self.ca {
649 for ca in cas.iter() {
650 write!(
651 f,
652 "CA: {}, expire: {},",
653 get_organization_unit(ca).unwrap_or_default(),
654 ca.not_after()
655 )?;
656 }
657 }
658 #[cfg(feature = "s2n")]
659 if let Some(policy) = &self.s2n_security_policy {
660 write!(f, "s2n_security_policy: {:?}, ", policy)?;
661 }
662 #[cfg(feature = "s2n")]
663 if let Some(psk_config) = &self.psk {
664 for psk in &psk_config.keys {
665 write!(
666 f,
667 "psk_identity: {}",
668 String::from_utf8_lossy(psk.identity.as_slice())
669 )?;
670 }
671 }
672 if let Some(tcp_keepalive) = &self.tcp_keepalive {
673 write!(f, "tcp_keepalive: {},", tcp_keepalive)?;
674 }
675 if let Some(h2_ping_interval) = self.h2_ping_interval {
676 write!(f, "h2_ping_interval: {:?},", h2_ping_interval)?;
677 }
678 Ok(())
679 }
680}
681
682#[derive(Debug, Clone)]
684pub struct HttpPeer {
685 pub _address: SocketAddr,
686 pub scheme: Scheme,
687 pub sni: String,
688 pub proxy: Option<Proxy>,
689 pub client_cert_key: Option<Arc<CertKey>>,
690 pub group_key: u64,
693 pub options: PeerOptions,
694}
695
696impl HttpPeer {
697 pub fn is_tls(&self) -> bool {
699 match self.scheme {
700 Scheme::HTTP => false,
701 Scheme::HTTPS => true,
702 }
703 }
704
705 fn new_from_sockaddr(address: SocketAddr, tls: bool, sni: String) -> Self {
706 HttpPeer {
707 _address: address,
708 scheme: Scheme::from_tls_bool(tls),
709 sni,
710 proxy: None,
711 client_cert_key: None,
712 group_key: 0,
713 options: PeerOptions::new(),
714 }
715 }
716
717 pub fn new<A: ToInetSocketAddrs>(address: A, tls: bool, sni: String) -> Self {
719 let mut addrs_iter = address.to_socket_addrs().unwrap(); let addr = addrs_iter.next().unwrap();
721 Self::new_from_sockaddr(SocketAddr::Inet(addr), tls, sni)
722 }
723
724 #[cfg(unix)]
726 pub fn new_uds(path: &str, tls: bool, sni: String) -> Result<Self> {
727 let addr = SocketAddr::Unix(
728 UnixSocketAddr::from_pathname(Path::new(path)).or_err(SocketError, "invalid path")?,
729 );
730 Ok(Self::new_from_sockaddr(addr, tls, sni))
731 }
732
733 pub fn new_proxy(
736 next_hop: &str,
737 ip_addr: IpAddr,
738 port: u16,
739 tls: bool,
740 sni: &str,
741 headers: BTreeMap<String, Vec<u8>>,
742 ) -> Self {
743 HttpPeer {
744 _address: SocketAddr::Inet(InetSocketAddr::new(ip_addr, port)),
745 scheme: Scheme::from_tls_bool(tls),
746 sni: sni.to_string(),
747 proxy: Some(Proxy {
748 next_hop: PathBuf::from(next_hop).into(),
749 host: ip_addr.to_string(),
750 port,
751 headers,
752 }),
753 client_cert_key: None,
754 group_key: 0,
755 options: PeerOptions::new(),
756 }
757 }
758
759 pub fn new_mtls<A: ToInetSocketAddrs>(
761 address: A,
762 sni: String,
763 client_cert_key: Arc<CertKey>,
764 ) -> Self {
765 let mut peer = Self::new(address, true, sni);
766 peer.client_cert_key = Some(client_cert_key);
767 peer
768 }
769
770 fn peer_hash(&self) -> u64 {
771 let mut hasher = AHasher::default();
772 self.hash(&mut hasher);
773 hasher.finish()
774 }
775}
776
777impl Hash for HttpPeer {
778 fn hash<H: Hasher>(&self, state: &mut H) {
779 self._address.hash(state);
780 self.scheme.hash(state);
781 self.proxy.hash(state);
782 self.sni.hash(state);
783 self.client_cert_key.hash(state);
785 self.verify_cert().hash(state);
787 self.verify_hostname().hash(state);
788 self.alternative_cn().hash(state);
789 #[cfg(feature = "s2n")]
790 self.get_psk().hash(state);
791 self.group_key.hash(state);
792 self.options.max_h2_streams.hash(state);
794 self.options.curves.hash(state);
799 self.options.second_keyshare.hash(state);
800 }
801}
802
803impl Display for HttpPeer {
804 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
805 write!(f, "addr: {}, scheme: {}", self._address, self.scheme)?;
806 if !self.sni.is_empty() {
807 write!(f, ", sni: {}", self.sni)?;
808 }
809 if let Some(p) = self.proxy.as_ref() {
810 write!(f, ", proxy: {p}")?;
811 }
812 if let Some(cert) = &self.client_cert_key {
813 write!(f, ", client cert: {}", cert)?;
814 }
815 Ok(())
816 }
817}
818
819impl Peer for HttpPeer {
820 fn address(&self) -> &SocketAddr {
821 &self._address
822 }
823
824 fn tls(&self) -> bool {
825 self.is_tls()
826 }
827
828 fn sni(&self) -> &str {
829 &self.sni
830 }
831
832 fn reuse_hash(&self) -> u64 {
834 self.peer_hash()
835 }
836
837 fn get_peer_options(&self) -> Option<&PeerOptions> {
838 Some(&self.options)
839 }
840
841 fn get_mut_peer_options(&mut self) -> Option<&mut PeerOptions> {
842 Some(&mut self.options)
843 }
844
845 fn get_proxy(&self) -> Option<&Proxy> {
846 self.proxy.as_ref()
847 }
848
849 #[cfg(unix)]
850 fn matches_fd<V: AsRawFd>(&self, fd: V) -> bool {
851 if let Some(proxy) = self.get_proxy() {
852 proxy.next_hop.check_fd_match(fd)
853 } else {
854 self.address().check_fd_match(fd)
855 }
856 }
857
858 #[cfg(windows)]
859 fn matches_sock<V: AsRawSocket>(&self, sock: V) -> bool {
860 use crate::protocols::ConnSockReusable;
861
862 if let Some(proxy) = self.get_proxy() {
863 panic!("windows do not support peers with proxy")
864 } else {
865 self.address().check_sock_match(sock)
866 }
867 }
868
869 fn get_client_cert_key(&self) -> Option<&Arc<CertKey>> {
870 self.client_cert_key.as_ref()
871 }
872
873 fn get_tracer(&self) -> Option<Tracer> {
874 self.options.tracer.clone()
875 }
876}
877
878#[derive(Debug, Hash, Clone)]
880pub struct Proxy {
881 pub next_hop: Box<Path>, pub host: String, pub port: u16, pub headers: BTreeMap<String, Vec<u8>>, }
886
887impl Display for Proxy {
888 fn fmt(&self, f: &mut Formatter) -> FmtResult {
889 write!(
890 f,
891 "next_hop: {}, host: {}, port: {}",
892 self.next_hop.display(),
893 self.host,
894 self.port
895 )
896 }
897}
898
899#[cfg(test)]
900mod tests {
901 use super::*;
902
903 #[test]
904 fn default_http_upstream_request_policy_is_standards_oriented() {
905 let policy = PeerOptions::new().http_upstream_request_policy;
906 assert!(policy.strip_hop_by_hop);
907 assert!(policy.strip_connection_nominated);
908 assert!(policy.reject_malformed_connection_nominations);
909 assert_eq!(policy.h1_upgrade, H1UpgradePolicy::WebSocketOnly);
910 }
911
912 #[test]
913 fn preserve_http_upstream_request_policy_is_a_legacy_preset() {
914 let policy = HttpUpstreamRequestPolicy::preserve();
915 assert!(!policy.strip_hop_by_hop);
916 assert!(!policy.strip_connection_nominated);
917 assert!(!policy.reject_malformed_connection_nominations);
918 assert_eq!(policy.h1_upgrade, H1UpgradePolicy::Preserve);
919 }
920}