Skip to content

Commit

Permalink
Sensible prompt defaults and optional SNI (#1844)
Browse files Browse the repository at this point in the history
* Make SNI optional with --omit-sni argument

* Add sensible defaults to additional HEADER prompts
  • Loading branch information
evanrittenhouse authored Sep 11, 2024
1 parent 767974f commit 7de2921
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 17 deletions.
17 changes: 8 additions & 9 deletions h3i/src/client/sync_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,11 @@ pub fn connect(
let mut events = mio::Events::with_capacity(1024);

// We'll only connect to one server.
let connect_url = args.host_port.split(':').next().unwrap();
let connect_url = if !args.omit_sni {
args.host_port.split(':').next()
} else {
None
};

// Resolve server address.
let peer_addr = if let Some(addr) = &args.connect_to {
Expand Down Expand Up @@ -148,14 +152,9 @@ pub fn connect(
let local_addr = socket.local_addr().unwrap();

// Create a QUIC connection and initiate handshake.
let mut conn = quiche::connect(
Some(connect_url),
&scid,
local_addr,
peer_addr,
&mut config,
)
.unwrap();
let mut conn =
quiche::connect(connect_url, &scid, local_addr, peer_addr, &mut config)
.unwrap();

if let Some(keylog) = &mut keylog {
if let Ok(keylog) = keylog.try_clone() {
Expand Down
8 changes: 8 additions & 0 deletions h3i/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ pub struct Config {
/// A string representing the host and port to connect to using the format
/// `<host>:<port>`.
pub host_port: String,
/// If the SNI should be omitted during the TLS handshake.
pub omit_sni: bool,
/// Set a specific IP address to connect to, rather than use DNS resolution.
pub connect_to: Option<String>,
/// The source port to use when connecting to a server.
Expand Down Expand Up @@ -72,6 +74,11 @@ impl Config {
self
}

pub fn omit_sni(mut self) -> Self {
self.omit_sni = true;
self
}

pub fn with_connect_to(mut self, connect_to: String) -> Self {
self.connect_to = Some(connect_to);
self
Expand Down Expand Up @@ -146,6 +153,7 @@ impl Config {

Ok(Config {
host_port: self.host_port,
omit_sni: self.omit_sni,
connect_to: self.connect_to,
source_port: self.source_port,
verify_peer: self.verify_peer,
Expand Down
9 changes: 9 additions & 0 deletions h3i/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,13 @@ fn config_from_clap() -> std::result::Result<Config, String> {
.required(true)
.index(1),
)
.arg(
Arg::with_name("omit-sni")
.long("omit-sni")
.help("Omit the SNI from the TLS handshake")
// Requires an OsStr, so we can parse to empty later on
.takes_value(false)
)
.arg(
Arg::with_name("connect-to")
.long("connect-to")
Expand Down Expand Up @@ -184,6 +191,7 @@ fn config_from_clap() -> std::result::Result<Config, String> {
.get_matches();

let host_port = matches.value_of("host:port").unwrap().to_string();
let omit_sni = matches.is_present("omit-sni");
let connect_to: Option<String> =
matches.value_of("connect-to").map(|s| s.to_string());
let verify_peer = !matches.is_present("no-verify");
Expand Down Expand Up @@ -252,6 +260,7 @@ fn config_from_clap() -> std::result::Result<Config, String> {

let library_config = h3i::config::Config {
host_port,
omit_sni,
connect_to,
source_port: 0,
verify_peer,
Expand Down
27 changes: 27 additions & 0 deletions h3i/src/prompts/h3/errors.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,30 @@
// Copyright (C) 2024, Cloudflare, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

//! QUIC and HTTP/3 errors for the h3i client.
use inquire::error::InquireResult;
use inquire::validator::Validation;
use inquire::CustomUserError;
Expand Down
11 changes: 3 additions & 8 deletions h3i/src/prompts/h3/headers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ pub fn prompt_push_promise() -> InquireResult<Action> {
fn pseudo_headers(host_port: &str) -> InquireResult<Vec<quiche::h3::Header>> {
let method = Text::new("method:")
.with_autocomplete(&method_suggester)
.with_default("GET")
.with_help_message(ESC_TO_RET)
.prompt()?;

Expand All @@ -126,10 +127,10 @@ fn pseudo_headers(host_port: &str) -> InquireResult<Vec<quiche::h3::Header>> {
.with_help_message(&help)
.prompt()?;

let path = Text::new("path:").prompt()?;
let path = Text::new("path:").with_default("/").prompt()?;

let scheme = Text::new("scheme:")
.with_autocomplete(&scheme_suggester)
.with_default("https")
.with_help_message(ESC_TO_RET)
.prompt()?;

Expand Down Expand Up @@ -170,12 +171,6 @@ fn method_suggester(val: &str) -> SuggestionResult<Vec<String>> {
squish_suggester(&suggestions, val)
}

fn scheme_suggester(val: &str) -> SuggestionResult<Vec<String>> {
let suggestions = ["https"];

squish_suggester(&suggestions, val)
}

fn validate_stream_id(id: &str) -> SuggestionResult<Validation> {
if id.is_empty() {
return Ok(Validation::Valid);
Expand Down

0 comments on commit 7de2921

Please sign in to comment.