Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 54e80164 authored by Mike Yu's avatar Mike Yu Committed by Automerger Merge Worker
Browse files

Merge "DoH: Support Early Data" am: 51d62156

parents b803fce3 51d62156
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -63,6 +63,7 @@ class Experiments {
            "dot_validation_latency_factor",
            "dot_validation_latency_factor",
            "dot_validation_latency_offset_ms",
            "dot_validation_latency_offset_ms",
            "doh",
            "doh",
            "doh_early_data",
            "doh_query_timeout_ms",
            "doh_query_timeout_ms",
            "doh_probe_timeout_ms",
            "doh_probe_timeout_ms",
            "doh_idle_timeout_ms",
            "doh_idle_timeout_ms",
+3 −1
Original line number Original line Diff line number Diff line
@@ -510,10 +510,12 @@ int PrivateDnsConfiguration::setDoh(int32_t netId, uint32_t mark,
                        getTimeoutFromFlag("doh_idle_timeout_ms", kDohIdleDefaultTimeoutMs),
                        getTimeoutFromFlag("doh_idle_timeout_ms", kDohIdleDefaultTimeoutMs),
                .use_session_resumption =
                .use_session_resumption =
                        Experiments::getInstance()->getFlag("doh_session_resumption", 0) == 1,
                        Experiments::getInstance()->getFlag("doh_session_resumption", 0) == 1,
                .enable_early_data = Experiments::getInstance()->getFlag("doh_early_data", 0) == 1,
        };
        };
        LOG(DEBUG) << __func__ << ": probe_timeout_ms=" << flags.probe_timeout_ms
        LOG(DEBUG) << __func__ << ": probe_timeout_ms=" << flags.probe_timeout_ms
                   << ", idle_timeout_ms=" << flags.idle_timeout_ms
                   << ", idle_timeout_ms=" << flags.idle_timeout_ms
                   << ", use_session_resumption=" << flags.use_session_resumption;
                   << ", use_session_resumption=" << flags.use_session_resumption
                   << ", enable_early_data=" << flags.enable_early_data;


        return doh_net_new(mDohDispatcher, netId, dohId.httpsTemplate.c_str(), dohId.host.c_str(),
        return doh_net_new(mDohDispatcher, netId, dohId.httpsTemplate.c_str(), dohId.host.c_str(),
                           dohId.ipAddr.c_str(), mark, caCert.c_str(), &flags);
                           dohId.ipAddr.c_str(), mark, caCert.c_str(), &flags);
+1 −0
Original line number Original line Diff line number Diff line
@@ -54,6 +54,7 @@ struct FeatureFlags {
    uint64_t probe_timeout_ms;
    uint64_t probe_timeout_ms;
    uint64_t idle_timeout_ms;
    uint64_t idle_timeout_ms;
    bool use_session_resumption;
    bool use_session_resumption;
    bool enable_early_data;
};
};


using ValidationCallback = void (*)(uint32_t net_id, bool success, const char* ip_addr,
using ValidationCallback = void (*)(uint32_t net_id, bool success, const char* ip_addr,
+36 −13
Original line number Original line Diff line number Diff line
@@ -63,6 +63,9 @@ impl Config {
            }
            }
            None => config.verify_peer(false),
            None => config.verify_peer(false),
        }
        }
        if key.enable_early_data {
            config.enable_early_data();
        }


        // Some of these configs are necessary, or the server can't respond the HTTP/3 request.
        // Some of these configs are necessary, or the server can't respond the HTTP/3 request.
        config.set_max_idle_timeout(key.max_idle_timeout);
        config.set_max_idle_timeout(key.max_idle_timeout);
@@ -126,6 +129,7 @@ pub struct Cache {
pub struct Key {
pub struct Key {
    pub cert_path: Option<String>,
    pub cert_path: Option<String>,
    pub max_idle_timeout: u64,
    pub max_idle_timeout: u64,
    pub enable_early_data: bool,
}
}


impl Cache {
impl Cache {
@@ -174,13 +178,15 @@ impl Cache {
#[test]
#[test]
fn create_quiche_config() {
fn create_quiche_config() {
    assert!(
    assert!(
        Config::from_key(&Key { cert_path: None, max_idle_timeout: 1000 }).is_ok(),
        Config::from_key(&Key { cert_path: None, max_idle_timeout: 1000, enable_early_data: true })
            .is_ok(),
        "quiche config without cert creating failed"
        "quiche config without cert creating failed"
    );
    );
    assert!(
    assert!(
        Config::from_key(&Key {
        Config::from_key(&Key {
            cert_path: Some("data/local/tmp/".to_string()),
            cert_path: Some("data/local/tmp/".to_string()),
            max_idle_timeout: 1000
            max_idle_timeout: 1000,
            enable_early_data: true,
        })
        })
        .is_ok(),
        .is_ok(),
        "quiche config with cert creating failed"
        "quiche config with cert creating failed"
@@ -191,38 +197,53 @@ fn create_quiche_config() {
fn shared_cache() {
fn shared_cache() {
    let cache_a = Cache::new();
    let cache_a = Cache::new();
    let cache_b = cache_a.clone();
    let cache_b = cache_a.clone();
    let config_a = cache_a.get(&Key { cert_path: None, max_idle_timeout: 1000 }).unwrap();
    let config_a = cache_a
        .get(&Key { cert_path: None, max_idle_timeout: 1000, enable_early_data: true })
        .unwrap();
    assert_eq!(Arc::strong_count(&config_a.0), 2);
    assert_eq!(Arc::strong_count(&config_a.0), 2);
    let _config_b = cache_b.get(&Key { cert_path: None, max_idle_timeout: 1000 }).unwrap();
    let _config_b = cache_b
        .get(&Key { cert_path: None, max_idle_timeout: 1000, enable_early_data: true })
        .unwrap();
    assert_eq!(Arc::strong_count(&config_a.0), 3);
    assert_eq!(Arc::strong_count(&config_a.0), 3);
}
}


#[test]
#[test]
fn different_keys() {
fn different_keys() {
    let cache = Cache::new();
    let cache = Cache::new();
    let key_a = Key { cert_path: None, max_idle_timeout: 1000 };
    let key_a = Key { cert_path: None, max_idle_timeout: 1000, enable_early_data: false };
    let key_b = Key { cert_path: Some("a".to_string()), max_idle_timeout: 1000 };
    let key_b =
    let key_c = Key { cert_path: Some("a".to_string()), max_idle_timeout: 5000 };
        Key { cert_path: Some("a".to_string()), max_idle_timeout: 1000, enable_early_data: false };
    let key_c =
        Key { cert_path: Some("a".to_string()), max_idle_timeout: 5000, enable_early_data: false };
    let key_d =
        Key { cert_path: Some("a".to_string()), max_idle_timeout: 5000, enable_early_data: true };
    let config_a = cache.get(&key_a).unwrap();
    let config_a = cache.get(&key_a).unwrap();
    let config_b = cache.get(&key_b).unwrap();
    let config_b = cache.get(&key_b).unwrap();
    let _config_b = cache.get(&key_b).unwrap();
    let _config_b = cache.get(&key_b).unwrap();
    let config_c = cache.get(&key_c).unwrap();
    let config_c = cache.get(&key_c).unwrap();
    let _config_c = cache.get(&key_c).unwrap();
    let _config_c = cache.get(&key_c).unwrap();
    let config_d = cache.get(&key_d).unwrap();
    let _config_d = cache.get(&key_d).unwrap();


    assert_eq!(Arc::strong_count(&config_a.0), 1);
    assert_eq!(Arc::strong_count(&config_a.0), 1);
    assert_eq!(Arc::strong_count(&config_b.0), 2);
    assert_eq!(Arc::strong_count(&config_b.0), 2);
    assert_eq!(Arc::strong_count(&config_c.0), 2);


    // config_c was most recently created, so it should have an extra strong reference due to
    // config_d was most recently created, so it should have an extra strong reference due to
    // keep-alive in the cache.
    // keep-alive in the cache.
    assert_eq!(Arc::strong_count(&config_c.0), 3);
    assert_eq!(Arc::strong_count(&config_d.0), 3);
}
}


#[test]
#[test]
fn lifetimes() {
fn lifetimes() {
    let cache = Cache::new();
    let cache = Cache::new();
    let key_a = Key { cert_path: Some("a".to_string()), max_idle_timeout: 1000 };
    let key_a =
    let key_b = Key { cert_path: Some("b".to_string()), max_idle_timeout: 1000 };
        Key { cert_path: Some("a".to_string()), max_idle_timeout: 1000, enable_early_data: true };
    let config_none = cache.get(&Key { cert_path: None, max_idle_timeout: 1000 }).unwrap();
    let key_b =
        Key { cert_path: Some("b".to_string()), max_idle_timeout: 1000, enable_early_data: true };
    let config_none = cache
        .get(&Key { cert_path: None, max_idle_timeout: 1000, enable_early_data: true })
        .unwrap();
    let config_a = cache.get(&key_a).unwrap();
    let config_a = cache.get(&key_a).unwrap();
    let config_b = cache.get(&key_b).unwrap();
    let config_b = cache.get(&key_b).unwrap();


@@ -268,7 +289,9 @@ fn lifetimes() {
#[tokio::test]
#[tokio::test]
async fn quiche_connect() {
async fn quiche_connect() {
    use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
    use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
    let mut config = Config::from_key(&Key { cert_path: None, max_idle_timeout: 10 }).unwrap();
    let mut config =
        Config::from_key(&Key { cert_path: None, max_idle_timeout: 10, enable_early_data: true })
            .unwrap();
    let socket_addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 42));
    let socket_addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 42));
    let conn_id = quiche::ConnectionId::from_ref(&[]);
    let conn_id = quiche::ConnectionId::from_ref(&[]);
    quiche::connect(None, &conn_id, socket_addr, config.take().await.deref_mut()).unwrap();
    quiche::connect(None, &conn_id, socket_addr, config.take().await.deref_mut()).unwrap();
+17 −16
Original line number Original line Diff line number Diff line
@@ -194,6 +194,19 @@ impl Driver {
    }
    }


    async fn drive_once(mut self) -> Result<Self> {
    async fn drive_once(mut self) -> Result<Self> {
        // If the QUIC connection is live, but the HTTP/3 is not, try to bring it up
        if self.quiche_conn.is_established() || self.quiche_conn.is_in_early_data() {
            info!(
                "Connection {} established on network {}",
                self.quiche_conn.trace_id(),
                self.net_id
            );
            let h3_config = h3::Config::new()?;
            let h3_conn = h3::Connection::with_transport(&mut self.quiche_conn, &h3_config)?;
            self = H3Driver::new(self, h3_conn).drive().await?;
            let _ = self.status_tx.send(Status::QUIC);
        }

        let timer = optional_timeout(self.quiche_conn.timeout(), self.net_id);
        let timer = optional_timeout(self.quiche_conn.timeout(), self.net_id);
        select! {
        select! {
            // If a quiche timer would fire, call their callback
            // If a quiche timer would fire, call their callback
@@ -210,19 +223,6 @@ impl Driver {
        // Any of the actions in the select could require us to send packets to the peer
        // Any of the actions in the select could require us to send packets to the peer
        self.flush_tx().await?;
        self.flush_tx().await?;


        // If the QUIC connection is live, but the HTTP/3 is not, try to bring it up
        if self.quiche_conn.is_established() {
            info!(
                "Connection {} established on network {}",
                self.quiche_conn.trace_id(),
                self.net_id
            );
            let h3_config = h3::Config::new()?;
            let h3_conn = h3::Connection::with_transport(&mut self.quiche_conn, &h3_config)?;
            self = H3Driver::new(self, h3_conn).drive().await?;
            let _ = self.status_tx.send(Status::QUIC);
        }

        // If the connection has entered draining state (the server is closing the connection),
        // If the connection has entered draining state (the server is closing the connection),
        // tell the status watcher not to use the connection. Besides, per Quiche document,
        // tell the status watcher not to use the connection. Besides, per Quiche document,
        // the connection should not be dropped until is_closed() returns true.
        // the connection should not be dropped until is_closed() returns true.
@@ -285,7 +285,8 @@ impl H3Driver {
        }
        }
        select! {
        select! {
            // Only attempt to enqueue new requests if we have no buffered request and aren't
            // Only attempt to enqueue new requests if we have no buffered request and aren't
            // closing
            // closing. Maybe limit the number of in-flight queries if the handshake
            // still hasn't finished.
            msg = self.driver.request_rx.recv(), if !self.driver.closing && self.buffered_request.is_none() => {
            msg = self.driver.request_rx.recv(), if !self.driver.closing && self.buffered_request.is_none() => {
                match msg {
                match msg {
                    Some(request) => self.handle_request(request)?,
                    Some(request) => self.handle_request(request)?,
@@ -321,8 +322,8 @@ impl H3Driver {
    }
    }


    fn handle_request(&mut self, request: Request) -> Result<()> {
    fn handle_request(&mut self, request: Request) -> Result<()> {
        info!("Handling DNS request on network {}, stats=[{:?}], peer_streams_left_bidi={}, peer_streams_left_uni={}",
        info!("Handling DNS request on network {}, is_in_early_data={}, stats=[{:?}], peer_streams_left_bidi={}, peer_streams_left_uni={}",
                self.driver.net_id, self.driver.quiche_conn.stats(), self.driver.quiche_conn.peer_streams_left_bidi(), self.driver.quiche_conn.peer_streams_left_uni());
                self.driver.net_id, self.driver.quiche_conn.is_in_early_data(), self.driver.quiche_conn.stats(), self.driver.quiche_conn.peer_streams_left_bidi(), self.driver.quiche_conn.peer_streams_left_uni());
        // If the request has already timed out, don't issue it to the server.
        // If the request has already timed out, don't issue it to the server.
        if let Some(expiry) = request.expiry {
        if let Some(expiry) = request.expiry {
            if BootTime::now() > expiry {
            if BootTime::now() > expiry {
Loading