Skip to content
This repository was archived by the owner on Jun 10, 2026. It is now read-only.

Commit 3a7015f

Browse files
committed
prefer locally-known app_id when TXT record contains multiple app addresses
1 parent 14963a2 commit 3a7015f

2 files changed

Lines changed: 161 additions & 8 deletions

File tree

Cargo.lock

Lines changed: 93 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gateway/src/proxy/tls_passthough.rs

Lines changed: 68 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//
33
// SPDX-License-Identifier: BUSL-1.1
44

5+
use std::collections::{BTreeMap, BTreeSet};
56
use std::fmt::Debug;
67
use std::sync::atomic::Ordering;
78

@@ -34,8 +35,23 @@ impl AppAddress {
3435
}
3536
}
3637

38+
fn select_app_address(items: &[Box<[u8]>], known_apps: &BTreeMap<String, BTreeSet<String>>) -> Result<AppAddress> {
39+
let mut fallback = None;
40+
for data in items {
41+
if let Ok(addr) = AppAddress::parse(data) {
42+
if known_apps.contains_key(&addr.app_id) {
43+
return Ok(addr);
44+
}
45+
if fallback.is_none() {
46+
fallback = Some(addr);
47+
}
48+
}
49+
}
50+
fallback.context("no app address found in txt record")
51+
}
52+
3753
/// resolve app address by sni
38-
async fn resolve_app_address(prefix: &str, sni: &str, compat: bool) -> Result<AppAddress> {
54+
async fn resolve_app_address(prefix: &str, sni: &str, compat: bool, state: &Proxy) -> Result<AppAddress> {
3955
let txt_domain = format!("{prefix}.{sni}");
4056
let resolver = hickory_resolver::AsyncResolver::tokio_from_system_conf()
4157
.context("failed to create dns resolver")?;
@@ -65,11 +81,8 @@ async fn resolve_app_address(prefix: &str, sni: &str, compat: bool) -> Result<Ap
6581
.await
6682
.context("failed to lookup app address")?;
6783
let txt_record = lookup.iter().next().context("no txt record found")?;
68-
let data = txt_record
69-
.txt_data()
70-
.first()
71-
.context("no data in txt record")?;
72-
AppAddress::parse(data).context("failed to parse app address")
84+
let locked = state.lock();
85+
select_app_address(txt_record.txt_data(), &locked.state.apps)
7386
}
7487
}
7588

@@ -82,7 +95,7 @@ pub(crate) async fn proxy_with_sni(
8295
let ns_prefix = &state.config.proxy.app_address_ns_prefix;
8396
let compat = state.config.proxy.app_address_ns_compat;
8497
let dns_timeout = state.config.proxy.timeouts.dns_resolve;
85-
let addr = timeout(dns_timeout, resolve_app_address(ns_prefix, sni, compat))
98+
let addr = timeout(dns_timeout, resolve_app_address(ns_prefix, sni, compat, &state))
8699
.await
87100
.context("DNS TXT resolve timeout")?
88101
.context("failed to resolve app address")?;
@@ -177,17 +190,65 @@ pub(crate) async fn proxy_to_app(
177190
#[cfg(test)]
178191
mod tests {
179192
use super::*;
193+
use crate::{
194+
config::{load_config_figment, Config, MutualConfig, TlsConfig},
195+
main_service::ProxyOptions,
196+
};
197+
use tempfile::TempDir;
198+
199+
fn boxed(s: &[u8]) -> Box<[u8]> {
200+
s.to_vec().into_boxed_slice()
201+
}
202+
203+
async fn create_test_proxy() -> (Proxy, TempDir) {
204+
let figment = load_config_figment(None);
205+
let mut config = figment.focus("core").extract::<Config>().unwrap();
206+
let temp_dir = TempDir::new().expect("failed to create temp dir");
207+
config.sync.data_dir = temp_dir.path().to_string_lossy().to_string();
208+
let proxy = Proxy::new(ProxyOptions {
209+
config,
210+
my_app_id: None,
211+
tls_config: TlsConfig {
212+
certs: "".to_string(),
213+
key: "".to_string(),
214+
mutual: MutualConfig { ca_certs: "".to_string() },
215+
},
216+
})
217+
.await
218+
.expect("failed to create proxy");
219+
(proxy, temp_dir)
220+
}
180221

181222
#[tokio::test]
182223
async fn test_resolve_app_address() {
224+
let (state, _dir) = create_test_proxy().await;
183225
let app_addr = resolve_app_address(
184226
"_dstack-app-address",
185227
"3327603e03f5bd1f830812ca4a789277fc31f577.app.dstack.org",
186228
false,
229+
&state,
187230
)
188231
.await
189232
.unwrap();
190233
assert_eq!(app_addr.app_id, "3327603e03f5bd1f830812ca4a789277fc31f577");
191234
assert_eq!(app_addr.port, 8090);
192235
}
236+
237+
#[test]
238+
fn test_select_app_address_prefers_local() {
239+
let items = vec![boxed(b"aaaaaa:443"), boxed(b"bbbbbb:8080")];
240+
let mut apps = BTreeMap::new();
241+
apps.insert("bbbbbb".to_string(), BTreeSet::new());
242+
let addr = select_app_address(&items, &apps).unwrap();
243+
assert_eq!(addr.app_id, "bbbbbb");
244+
assert_eq!(addr.port, 8080);
245+
}
246+
247+
#[test]
248+
fn test_select_app_address_fallback_when_none_local() {
249+
let items = vec![boxed(b"aaaaaa:443"), boxed(b"bbbbbb:8080")];
250+
let addr = select_app_address(&items, &BTreeMap::new()).unwrap();
251+
assert_eq!(addr.app_id, "aaaaaa");
252+
assert_eq!(addr.port, 443);
253+
}
193254
}

0 commit comments

Comments
 (0)