diff --git a/modoh-lib/src/constants.rs b/modoh-lib/src/constants.rs index 929cbf7..1e6cfa6 100644 --- a/modoh-lib/src/constants.rs +++ b/modoh-lib/src/constants.rs @@ -18,8 +18,12 @@ pub const UPSTREAM: &str = "8.8.8.8:53"; pub const ERROR_TTL: u32 = 2; pub const MAX_TTL: u32 = 604800; pub const MIN_TTL: u32 = 10; -pub const STALE_IF_ERROR_SECS: u32 = 86400; -pub const STALE_WHILE_REVALIDATE_SECS: u32 = 60; +pub const STALE_IF_ERROR_SECS: u32 = 300; +pub const STALE_WHILE_REVALIDATE_SECS: u32 = 5; +/// ODoH Config cache is expired after at least 10 seconds +pub const MAX_ODOH_CONFIG_TTL_SECS: u64 = 10; +/// HTTPSig Config cache is expired after at least 10 seconds +pub const MAX_HTTPSIG_CONFIG_TTL_SECS: u64 = 10; /// Maximum ratio of TCP sessions to UDP sessions pub const TARGET_UDP_TCP_RATIO: usize = 8; diff --git a/modoh-lib/src/target/target_main.rs b/modoh-lib/src/target/target_main.rs index 56b035c..ec8ccc8 100644 --- a/modoh-lib/src/target/target_main.rs +++ b/modoh-lib/src/target/target_main.rs @@ -1,18 +1,19 @@ use super::odoh::ODoHPublicKey; use crate::{ constants::{ - HTTPSIG_CONFIGS_PATH, ODOH_CONFIGS_PATH, ODOH_KEY_ROTATION_SECS, STALE_IF_ERROR_SECS, STALE_WHILE_REVALIDATE_SECS, + HTTPSIG_CONFIGS_PATH, MAX_HTTPSIG_CONFIG_TTL_SECS, MAX_ODOH_CONFIG_TTL_SECS, ODOH_CONFIGS_PATH, ODOH_KEY_ROTATION_SECS, + STALE_IF_ERROR_SECS, STALE_WHILE_REVALIDATE_SECS, }, count::RequestCount, error::*, globals::Globals, httpsig_handler::HttpSigKeyRotationState, - hyper_body::{full, BoxBody}, + hyper_body::{BoxBody, full}, message_util::inspect_host, trace::*, }; -use futures::{select, FutureExt}; -use http::{header, Method, Request, Response}; +use futures::{FutureExt, select}; +use http::{Method, Request, Response, header}; use hyper::body::Bytes; use std::{net::SocketAddr, sync::Arc, time::Duration}; use tokio::{ @@ -21,6 +22,23 @@ use tokio::{ }; use tracing::instrument; +#[instrument(level = "debug", skip_all)] +/// build http response from given packet +pub(super) fn build_http_response_no_store(packet: &[u8], content_type: &str, cors: bool) -> HttpResult> { + let packet_len = packet.len(); + let mut response_builder = Response::builder() + .header(header::CONTENT_LENGTH, packet_len) + .header(header::CONTENT_TYPE, content_type) + .header(header::CACHE_CONTROL, "no-store, no-cache, must-revalidate, max-age=0") + .header(header::PRAGMA, "no-cache") + .header(header::EXPIRES, "0"); + if cors { + response_builder = response_builder.header(hyper::header::ACCESS_CONTROL_ALLOW_ORIGIN, "*"); + } + let body = full(Bytes::copy_from_slice(packet)); + response_builder.body(body).map_err(|_| HttpError::InvalidODoHConfig) +} + #[instrument(level = "debug", skip_all)] /// build http response from given packet pub(super) fn build_http_response(packet: &[u8], ttl: u64, content_type: &str, cors: bool) -> HttpResult> { @@ -30,8 +48,7 @@ pub(super) fn build_http_response(packet: &[u8], ttl: u64, content_type: &str, c .header(header::CONTENT_TYPE, content_type) .header( header::CACHE_CONTROL, - format!("max-age={ttl}, stale-if-error={STALE_IF_ERROR_SECS}, stale-while-revalidate={STALE_WHILE_REVALIDATE_SECS}") - .as_str(), + format!("max-age={ttl}, stale-if-error={STALE_IF_ERROR_SECS}, stale-while-revalidate={STALE_WHILE_REVALIDATE_SECS}, must-revalidate").as_str(), ); if cors { response_builder = response_builder.header(hyper::header::ACCESS_CONTROL_ALLOW_ORIGIN, "*"); @@ -98,7 +115,12 @@ impl InnerTarget { let lock = self.odoh_configs.read().await; let configs = lock.as_config().to_owned(); drop(lock); - build_http_response(&configs, ODOH_KEY_ROTATION_SECS, "application/octet-stream", true) + build_http_response( + &configs, + ODOH_KEY_ROTATION_SECS.min(MAX_ODOH_CONFIG_TTL_SECS), + "application/octet-stream", + true, + ) } /// Serve httpsig config via GET method @@ -123,7 +145,12 @@ impl InnerTarget { let configs = lock.as_config().to_owned(); let rotation_period = httpsig_state.rotation_period.as_secs(); drop(lock); - build_http_response(&configs, rotation_period, "application/octet-stream", true) + build_http_response( + &configs, + rotation_period.min(MAX_HTTPSIG_CONFIG_TTL_SECS), + "application/octet-stream", + true, + ) } /// Start odoh config rotation service diff --git a/modoh-lib/src/target/target_serve_query.rs b/modoh-lib/src/target/target_serve_query.rs index 98f62dd..0c10fa8 100644 --- a/modoh-lib/src/target/target_serve_query.rs +++ b/modoh-lib/src/target/target_serve_query.rs @@ -1,4 +1,4 @@ -use super::{target_main::build_http_response, InnerTarget}; +use super::{InnerTarget, target_main::build_http_response}; use crate::{ constants::{ DNS_QUERY_PARAM, DOH_CONTENT_TYPE, MAX_DNS_QUESTION_LEN, MAX_DNS_RESPONSE_LEN, MIN_DNS_PACKET_LEN, ODOH_CONTENT_TYPE, @@ -7,10 +7,11 @@ use crate::{ dns, error::*, hyper_body::BoxBody, - message_util::{check_content_type, inspect_host, read_request_body, RequestType}, + message_util::{RequestType, check_content_type, inspect_host, read_request_body}, + target::target_main::build_http_response_no_store, trace::*, }; -use base64::{engine::general_purpose, Engine as _}; +use base64::{Engine as _, engine::general_purpose}; use byteorder::{BigEndian, ByteOrder}; use futures::TryFutureExt; use http::{Method, Request, Response}; @@ -21,7 +22,7 @@ use tokio::{ net::{TcpSocket, UdpSocket}, time::timeout, }; -use tracing::{instrument, Instrument as _}; +use tracing::{Instrument as _, instrument}; #[derive(Debug)] /// Dns response object @@ -96,7 +97,7 @@ impl InnerTarget { self.log_dns_message(_peer_addr, &res.packet, &req_headers); let encrypted_body = context.encrypt_response(res.packet)?; - let resp = build_http_response(&encrypted_body, 0u64, ODOH_CONTENT_TYPE, false)?; + let resp = build_http_response_no_store(&encrypted_body, ODOH_CONTENT_TYPE, false)?; Ok(resp) } }