Skip to content

Commit d6d4d10

Browse files
Dsn support set callback uri (#2104)
* fix(agent): support full DSN parsing in set_callback_uri Updates `ImixAgent::set_callback_uri` to utilize `pb::config::parse_dsn` when configuring new or existing transports. This allows the agent to dynamically process and update properties like `interval` and `jitter` provided as URL query parameters in the DSN when `set_callback_uri` is invoked. Co-authored-by: hulto <7121375+hulto@users.noreply.github.com> * fix(agent): support full DSN parsing in set_callback_uri Updates `ImixAgent::set_callback_uri` to utilize `pb::config::parse_dsn` when configuring new or existing transports. This allows the agent to dynamically process and update properties like `interval` and `jitter` provided as URL query parameters in the DSN when `set_callback_uri` is invoked. Also includes the PR reviewer's feedback about checking both uri and type when finding an existing callback. Co-authored-by: hulto <7121375+hulto@users.noreply.github.com> * fix(agent): update callback uri equality checks for transport type Adds a check in `ImixAgent::set_callback_uri` to ensure the transport `r#type` matches when searching for an existing callback to update. Co-authored-by: hulto <7121375+hulto@users.noreply.github.com> * fix(agent): update callback uri equality checks for transport type Adds a check in `ImixAgent::set_callback_uri` to ensure the transport `r#type` matches when searching for an existing callback to update. Co-authored-by: hulto <7121375+hulto@users.noreply.github.com> * fmt --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
1 parent dc09b89 commit d6d4d10

File tree

3 files changed

+26
-31
lines changed

3 files changed

+26
-31
lines changed

implants/imix/src/agent.rs

Lines changed: 15 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -654,40 +654,28 @@ impl Agent for ImixAgent {
654654

655655
fn set_callback_uri(&self, uri: String) -> Result<(), String> {
656656
self.block_on(async {
657+
// Parse the new URI to handle DSN format with query parameters
658+
let parsed_transport = pb::config::parse_dsn(&uri)
659+
.map_err(|e| format!("Failed to parse callback URI: {}", e))?;
660+
657661
let mut cfg = self.config.write().await;
658662
if let Some(info) = cfg.info.as_mut()
659663
&& let Some(available_transports) = info.available_transports.as_mut()
660664
{
661-
// Check if URI already exists
662-
if let Some(pos) = available_transports
663-
.transports
664-
.iter()
665-
.position(|t| t.uri == uri)
666-
{
665+
// Note: We compare against parsed_transport.uri because parse_dsn strips the query string
666+
if let Some(pos) = available_transports.transports.iter().position(|t| {
667+
t.uri == parsed_transport.uri && t.r#type == parsed_transport.r#type
668+
}) {
667669
// Set active_index to existing transport
668670
available_transports.active_index = pos as u32;
671+
672+
// We also want to update the settings if they were provided in the DSN
673+
// Let's replace the existing transport with the newly parsed one
674+
available_transports.transports[pos] = parsed_transport;
669675
} else {
670-
// Get current transport as template
671-
let active_idx = available_transports.active_index as usize;
672-
let template = available_transports
673-
.transports
674-
.get(active_idx)
675-
.or_else(|| available_transports.transports.first())
676-
.cloned();
677-
678-
if let Some(tmpl) = template {
679-
// Create new transport with the new URI
680-
let new_transport = pb::c2::Transport {
681-
uri,
682-
interval: tmpl.interval,
683-
r#type: tmpl.r#type,
684-
extra: tmpl.extra,
685-
jitter: tmpl.jitter,
686-
};
687-
available_transports.transports.push(new_transport);
688-
available_transports.active_index =
689-
(available_transports.transports.len() - 1) as u32;
690-
}
676+
available_transports.transports.push(parsed_transport);
677+
available_transports.active_index =
678+
(available_transports.transports.len() - 1) as u32;
691679
}
692680
}
693681
Ok(())

implants/imix/src/tests/callback_interval_test.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ async fn test_set_callback_uri_new_transport() {
102102
.set_callback_uri(new_uri.clone())
103103
.expect("Failed to set new callback URI");
104104

105+
// `set_callback_uri` uses `parse_dsn` which normalizes the URL to include a trailing slash
106+
// if it lacks a path component.
107+
let expected_new_uri = "https://new.example.com/".to_string();
108+
105109
// Verify the new URI was added and is now active
106110
let updated_uris = agent_clone
107111
.list_callback_uris()
@@ -112,14 +116,17 @@ async fn test_set_callback_uri_new_transport() {
112116
"Should have 3 URIs after adding new one"
113117
);
114118
assert!(
115-
updated_uris.contains(&new_uri),
119+
updated_uris.contains(&expected_new_uri),
116120
"New URI should be in the list"
117121
);
118122

119123
let active_uri = agent_clone
120124
.get_active_callback_uri()
121125
.expect("Failed to get active URI after update");
122-
assert_eq!(active_uri, new_uri, "New URI should be the active one");
126+
assert_eq!(
127+
active_uri, expected_new_uri,
128+
"New URI should be the active one"
129+
);
123130
})
124131
.join();
125132

implants/lib/pb/src/config.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ fn get_transport_type(uri: &str) -> crate::c2::transport::Type {
107107
*
108108
* Example: https://example.com?interval=10&extra={"key":"value"}&jitter=0.5
109109
*/
110-
fn parse_transports(uri_string: &str) -> Vec<Transport> {
110+
pub fn parse_transports(uri_string: &str) -> Vec<Transport> {
111111
uri_string
112112
.split(';')
113113
.filter(|s| !s.trim().is_empty())
@@ -122,7 +122,7 @@ fn parse_transports(uri_string: &str) -> Vec<Transport> {
122122
* Helper function to parse DSN query parameters
123123
* Returns a Transport struct
124124
*/
125-
fn parse_dsn(uri: &str) -> anyhow::Result<Transport> {
125+
pub fn parse_dsn(uri: &str) -> anyhow::Result<Transport> {
126126
// Parse as a URL to extract query parameters
127127
let parsed_url = Url::parse(uri).with_context(|| format!("Failed to parse URI '{}'", uri))?;
128128

0 commit comments

Comments
 (0)