passes through concrete QUIC connection errors up the call stack (#31168)

This commit is contained in:
behzad nouri 2023-04-12 19:53:25 +00:00 committed by GitHub
parent 602297e29f
commit 34da001cda
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 24 additions and 23 deletions

2
Cargo.lock generated
View File

@ -5449,6 +5449,7 @@ dependencies = [
"rand 0.7.3", "rand 0.7.3",
"rand_chacha 0.2.2", "rand_chacha 0.2.2",
"rayon", "rayon",
"rcgen",
"solana-logger 1.16.0", "solana-logger 1.16.0",
"solana-measure", "solana-measure",
"solana-metrics", "solana-metrics",
@ -6430,6 +6431,7 @@ dependencies = [
"quinn", "quinn",
"quinn-proto", "quinn-proto",
"quinn-udp", "quinn-udp",
"rcgen",
"rustls 0.20.6", "rustls 0.20.6",
"solana-connection-cache", "solana-connection-cache",
"solana-logger 1.16.0", "solana-logger 1.16.0",

View File

@ -18,6 +18,7 @@ indicatif = { workspace = true, optional = true }
log = { workspace = true } log = { workspace = true }
rand = { workspace = true } rand = { workspace = true }
rayon = { workspace = true } rayon = { workspace = true }
rcgen = { workspace = true }
solana-measure = { workspace = true } solana-measure = { workspace = true }
solana-metrics = { workspace = true } solana-metrics = { workspace = true }
solana-sdk = { workspace = true } solana-sdk = { workspace = true }

View File

@ -287,7 +287,7 @@ pub enum ConnectionPoolError {
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum ClientError { pub enum ClientError {
#[error("Certificate error: {0}")] #[error("Certificate error: {0}")]
CertificateError(String), CertificateError(#[from] rcgen::RcgenError),
#[error("IO error: {0:?}")] #[error("IO error: {0:?}")]
IoError(#[from] std::io::Error), IoError(#[from] std::io::Error),

View File

@ -4725,6 +4725,7 @@ dependencies = [
"log", "log",
"rand 0.7.3", "rand 0.7.3",
"rayon", "rayon",
"rcgen",
"solana-measure", "solana-measure",
"solana-metrics", "solana-metrics",
"solana-sdk 1.16.0", "solana-sdk 1.16.0",
@ -5392,6 +5393,7 @@ dependencies = [
"quinn", "quinn",
"quinn-proto", "quinn-proto",
"quinn-udp", "quinn-udp",
"rcgen",
"rustls 0.20.6", "rustls 0.20.6",
"solana-connection-cache", "solana-connection-cache",
"solana-measure", "solana-measure",

View File

@ -19,6 +19,7 @@ log = { workspace = true }
quinn = { workspace = true } quinn = { workspace = true }
quinn-proto = { workspace = true } quinn-proto = { workspace = true }
quinn-udp = { workspace = true } quinn-udp = { workspace = true }
rcgen = { workspace = true }
rustls = { workspace = true, features = ["dangerous_configuration"] } rustls = { workspace = true, features = ["dangerous_configuration"] }
solana-connection-cache = { workspace = true } solana-connection-cache = { workspace = true }
solana-measure = { workspace = true } solana-measure = { workspace = true }

View File

@ -15,6 +15,7 @@ use {
quic_client::QuicClientConnection as BlockingQuicClientConnection, quic_client::QuicClientConnection as BlockingQuicClientConnection,
}, },
quinn::Endpoint, quinn::Endpoint,
rcgen::RcgenError,
solana_connection_cache::{ solana_connection_cache::{
connection_cache::{ connection_cache::{
BaseClientConnection, ClientError, ConnectionManager, ConnectionPool, BaseClientConnection, ClientError, ConnectionManager, ConnectionPool,
@ -29,7 +30,6 @@ use {
tls_certificates::new_self_signed_tls_certificate, tls_certificates::new_self_signed_tls_certificate,
}, },
std::{ std::{
error::Error,
net::{IpAddr, Ipv4Addr, SocketAddr}, net::{IpAddr, Ipv4Addr, SocketAddr},
sync::{Arc, RwLock}, sync::{Arc, RwLock},
}, },
@ -39,7 +39,7 @@ use {
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum QuicClientError { pub enum QuicClientError {
#[error("Certificate error: {0}")] #[error("Certificate error: {0}")]
CertificateError(String), CertificateError(#[from] RcgenError),
} }
pub struct QuicPool { pub struct QuicPool {
@ -92,8 +92,7 @@ pub struct QuicConfig {
impl NewConnectionConfig for QuicConfig { impl NewConnectionConfig for QuicConfig {
fn new() -> Result<Self, ClientError> { fn new() -> Result<Self, ClientError> {
let (cert, priv_key) = let (cert, priv_key) =
new_self_signed_tls_certificate(&Keypair::new(), IpAddr::V4(Ipv4Addr::UNSPECIFIED)) new_self_signed_tls_certificate(&Keypair::new(), IpAddr::V4(Ipv4Addr::UNSPECIFIED))?;
.map_err(|err| ClientError::CertificateError(err.to_string()))?;
Ok(Self { Ok(Self {
client_certificate: Arc::new(QuicClientCertificate { client_certificate: Arc::new(QuicClientCertificate {
certificate: cert, certificate: cert,
@ -136,7 +135,7 @@ impl QuicConfig {
&mut self, &mut self,
keypair: &Keypair, keypair: &Keypair,
ipaddr: IpAddr, ipaddr: IpAddr,
) -> Result<(), Box<dyn Error>> { ) -> Result<(), RcgenError> {
let (cert, priv_key) = new_self_signed_tls_certificate(keypair, ipaddr)?; let (cert, priv_key) = new_self_signed_tls_certificate(keypair, ipaddr)?;
self.client_certificate = Arc::new(QuicClientCertificate { self.client_certificate = Arc::new(QuicClientCertificate {
certificate: cert, certificate: cert,

View File

@ -101,11 +101,8 @@ pub fn spawn_server(
info!("Start quic server on {:?}", sock); info!("Start quic server on {:?}", sock);
let (config, _cert) = configure_server(keypair, gossip_host)?; let (config, _cert) = configure_server(keypair, gossip_host)?;
let endpoint = { let endpoint = Endpoint::new(EndpointConfig::default(), Some(config), sock, TokioRuntime)
Endpoint::new(EndpointConfig::default(), Some(config), sock, TokioRuntime) .map_err(QuicServerError::EndpointFailed)?;
.map_err(|_e| QuicServerError::EndpointFailed)?
};
let handle = tokio::spawn(run_server( let handle = tokio::spawn(run_server(
endpoint.clone(), endpoint.clone(),
packet_sender, packet_sender,

View File

@ -57,8 +57,7 @@ pub(crate) fn configure_server(
identity_keypair: &Keypair, identity_keypair: &Keypair,
gossip_host: IpAddr, gossip_host: IpAddr,
) -> Result<(ServerConfig, String), QuicServerError> { ) -> Result<(ServerConfig, String), QuicServerError> {
let (cert, priv_key) = new_self_signed_tls_certificate(identity_keypair, gossip_host) let (cert, priv_key) = new_self_signed_tls_certificate(identity_keypair, gossip_host)?;
.map_err(|_e| QuicServerError::ConfigureFailed)?;
let cert_chain_pem_parts = vec![Pem { let cert_chain_pem_parts = vec![Pem {
tag: "CERTIFICATE".to_string(), tag: "CERTIFICATE".to_string(),
contents: cert.0.clone(), contents: cert.0.clone(),
@ -68,8 +67,7 @@ pub(crate) fn configure_server(
let mut server_tls_config = rustls::ServerConfig::builder() let mut server_tls_config = rustls::ServerConfig::builder()
.with_safe_defaults() .with_safe_defaults()
.with_client_cert_verifier(SkipClientVerification::new()) .with_client_cert_verifier(SkipClientVerification::new())
.with_single_cert(vec![cert], priv_key) .with_single_cert(vec![cert], priv_key)?;
.map_err(|_e| QuicServerError::ConfigureFailed)?;
server_tls_config.alpn_protocols = vec![ALPN_TPU_PROTOCOL_ID.to_vec()]; server_tls_config.alpn_protocols = vec![ALPN_TPU_PROTOCOL_ID.to_vec()];
let mut server_config = ServerConfig::with_crypto(Arc::new(server_tls_config)); let mut server_config = ServerConfig::with_crypto(Arc::new(server_tls_config));
@ -106,11 +104,12 @@ fn rt() -> Runtime {
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
pub enum QuicServerError { pub enum QuicServerError {
#[error("Server configure failed")] #[error("Endpoint creation failed: {0}")]
ConfigureFailed, EndpointFailed(std::io::Error),
#[error("Certificate error: {0}")]
#[error("Endpoint creation failed")] CertificateError(#[from] rcgen::RcgenError),
EndpointFailed, #[error("TLS error: {0}")]
TlsError(#[from] rustls::Error),
} }
#[derive(Default)] #[derive(Default)]

View File

@ -1,15 +1,15 @@
use { use {
pkcs8::{der::Document, AlgorithmIdentifier, ObjectIdentifier}, pkcs8::{der::Document, AlgorithmIdentifier, ObjectIdentifier},
rcgen::{CertificateParams, DistinguishedName, DnType, SanType}, rcgen::{CertificateParams, DistinguishedName, DnType, RcgenError, SanType},
solana_sdk::{pubkey::Pubkey, signature::Keypair}, solana_sdk::{pubkey::Pubkey, signature::Keypair},
std::{error::Error, net::IpAddr}, std::net::IpAddr,
x509_parser::{prelude::*, public_key::PublicKey}, x509_parser::{prelude::*, public_key::PublicKey},
}; };
pub fn new_self_signed_tls_certificate( pub fn new_self_signed_tls_certificate(
keypair: &Keypair, keypair: &Keypair,
san: IpAddr, san: IpAddr,
) -> Result<(rustls::Certificate, rustls::PrivateKey), Box<dyn Error>> { ) -> Result<(rustls::Certificate, rustls::PrivateKey), RcgenError> {
// TODO(terorie): Is it safe to sign the TLS cert with the identity private key? // TODO(terorie): Is it safe to sign the TLS cert with the identity private key?
// Unfortunately, rcgen does not accept a "raw" Ed25519 key. // Unfortunately, rcgen does not accept a "raw" Ed25519 key.