use clap::Parser; use futures::{
future::{select, select_all, Either},
FutureExt,
}; use neqo_common::{qdebug, qerror, qinfo, qwarn, Datagram}; use neqo_crypto::{
constants::{TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256},
init_db, AntiReplay, Cipher,
}; use neqo_transport::{Output, RandomConnectionIdGenerator, Version}; use tokio::time::Sleep;
#[arg(short = 'k', long, default_value = "key")] /// Name of key from NSS database.
key: String,
#[arg(name = "retry", long)] /// Force a retry
retry: bool,
#[arg(name = "ech", long)] /// Enable encrypted client hello (ECH). /// This generates a new set of ECH keys when it is invoked. /// The resulting configuration is printed to stdout in hexadecimal format.
ech: bool,
}
fn now(&self) -> Instant { ifself.shared.qns_test.is_some() { // When NSS starts its anti-replay it blocks any acceptance of 0-RTT for a // single period. This ensures that an attacker that is able to force a // server to reboot is unable to use that to flush the anti-replay buffers // and have something replayed. // // However, this is a massive inconvenience for us when we are testing. // As we can't initialize `AntiReplay` in the past (see `neqo_common::time` // for why), fast forward time here so that the connections get times from // in the future. // // This is NOT SAFE. Don't do this.
Instant::now() + ANTI_REPLAY_WINDOW
} else {
Instant::now()
}
}
/// Tries to find a socket, but then just falls back to sending from the first. fn find_socket(
sockets: &mut [(SocketAddr, crate::udp::Socket)],
addr: SocketAddr,
) -> &mutcrate::udp::Socket { let ((_host, first_socket), rest) = sockets.split_first_mut().unwrap();
rest.iter_mut()
.map(|(_host, socket)| socket)
.find(|socket| socket.local_addr().is_ok_and(|a| a == addr))
.unwrap_or(first_socket)
}
// Free function (i.e. not taking `&mut self: ServerRunner`) to be callable by // `ServerRunner::read_and_process` while holding a reference to // `ServerRunner::recv_buf`. asyncfn process_inner(
server: &mutBox<dyn HttpServer>,
timeout: &mut Option<Pin<Box<Sleep>>>,
sockets: &mut [(SocketAddr, crate::udp::Socket)],
now: &dynFn() -> Instant, mut input_dgram: Option<Datagram<&[u8]>>,
) -> Result<(), io::Error> { loop { match server.process(input_dgram.take(), now()) {
Output::Datagram(dgram) => { let socket = Self::find_socket(sockets, dgram.source());
socket.writable().await?;
socket.send(&dgram)?;
}
Output::Callback(new_timeout) => {
qdebug!("Setting timeout of {:?}", new_timeout);
*timeout = Some(Box::pin(tokio::time::sleep(new_timeout))); break;
}
Output::None => break,
}
}
Ok(())
}
// Wait for any of the sockets to be readable or the timeout to fire. asyncfn ready(&mutself) -> Result<Ready, io::Error> { let sockets_ready = select_all( self.sockets
.iter()
.map(|(_host, socket)| Box::pin(socket.readable())),
)
.map(|(res, inx, _)| match res {
Ok(()) => Ok(Ready::Socket(inx)),
Err(e) => Err(e),
}); let timeout_ready = self
.timeout
.as_mut()
.map_or_else(|| Either::Right(futures::future::pending()), Either::Left)
.map(|()| Ok(Ready::Timeout));
select(sockets_ready, timeout_ready).await.factor_first().0
}
neqo_common::log::init(
args.shared
.verbose
.as_ref()
.map(clap_verbosity_flag::Verbosity::log_level_filter),
);
assert!(!args.key.is_empty(), "Need at least one key");
init_db(args.db.clone())?;
iflet Some(testcase) = args.shared.qns_test.as_ref() { if args.shared.quic_parameters.quic_version.is_empty() { // Quic Interop Runner expects the server to support `Version1` // only. Exceptions are testcases `versionnegotiation` (not yet // implemented) and `v2`. if testcase != "v2" {
args.shared.quic_parameters.quic_version = vec![Version::Version1];
}
} else {
qwarn!("Both -V and --qns-test were set. Ignoring testcase specific versions.");
}
// These are the default for all tests except http3.
args.shared.use_old_http = true;
args.shared.alpn = String::from(HQ_INTEROP); // TODO: More options to deduplicate with client? match testcase.as_str() { "http3" => {
args.shared.use_old_http = false;
args.shared.alpn = "h3".into();
} "zerortt" => args.shared.quic_parameters.max_streams_bidi = 100, "handshake" | "transfer" | "resumption" | "multiconnect" | "v2" | "ecn" => {} "connectionmigration" => { if args.shared.quic_parameters.preferred_address().is_none() {
qerror!("No preferred addresses set for connectionmigration test");
exit(127);
}
} "chacha20" => {
args.shared.ciphers.clear();
args.shared
.ciphers
.extend_from_slice(&[String::from("TLS_CHACHA20_POLY1305_SHA256")]);
} "retry" => args.retry = true,
_ => exit(127),
}
}
let hosts = args.listen_addresses(); if hosts.is_empty() {
qerror!("No valid hosts defined");
Err(io::Error::new(io::ErrorKind::InvalidInput, "No hosts"))?;
} let sockets = hosts
.into_iter()
.map(|host| { let socket = crate::udp::Socket::bind(host)?; let local_addr = socket.local_addr()?;
qinfo!("Server waiting for connection on: {local_addr:?}");
// Note: this is the exception to the case where we use `Args::now`. let anti_replay = AntiReplay::new(Instant::now(), ANTI_REPLAY_WINDOW, 7, 14)
.expect("unable to setup anti-replay"); let cid_mgr = Rc::new(RefCell::new(RandomConnectionIdGenerator::new(10)));
let server: Box<dyn HttpServer> = if args.shared.use_old_http { Box::new(
http09::HttpServer::new(&args, anti_replay, cid_mgr).expect("We cannot make a server!"),
)
} else { Box::new(http3::HttpServer::new(&args, anti_replay, cid_mgr))
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.