Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sanitize user-agent in access logs #1063

Merged
merged 1 commit into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 39 additions & 29 deletions lib/src/logs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,11 @@ pub struct RequestRecord<'a> {
pub client_rtt: Option<Duration>,
pub server_rtt: Option<Duration>,
pub metrics: &'a SessionMetrics,
pub user_agent: Option<&'a str>,
pub user_agent: Option<String>,
}

impl RequestRecord<'_> {
pub fn log(&self) {
pub fn log(self) {
let context = &self.context;
let cluster_id = context.cluster_id;
let tags = self.tags;
Expand All @@ -151,7 +151,7 @@ impl RequestRecord<'_> {
let session_address = self.session_address;
let backend_address = self.backend_address;
let endpoint = &self.endpoint;
let user_agent = &self.user_agent;
let mut user_agent = self.user_agent;

let metrics = self.metrics;
// let backend_response_time = metrics.backend_response_time();
Expand Down Expand Up @@ -192,10 +192,23 @@ impl RequestRecord<'_> {
}
}

let (tags, ua_sep, user_agent) = match (tags, &mut user_agent) {
(None, None) => ("-", "", ""),
(Some(tags), None) => (tags, "", ""),
(None, Some(ua)) => {
prepare_user_agent(ua);
("", "user-agent=", ua.as_str())
}
(Some(tags), Some(ua)) => {
prepare_user_agent(ua);
(tags, ", user-agent=", ua.as_str())
}
};

match self.error {
None => {
info_access!(
"{}{} -> {} \t{}/{}/{}/{} \t{} -> {} \t {}{} {} {}",
"{}{} -> {} \t{}/{}/{}/{} \t{} -> {} \t {}{}{} {} {}",
context,
session_address.as_str_or("X"),
backend_address.as_str_or("X"),
Expand All @@ -205,18 +218,9 @@ impl RequestRecord<'_> {
LogDuration(server_rtt),
metrics.bin,
metrics.bout,
match user_agent {
Some(_) => tags.as_str_or(""),
None => tags.as_str_or("-"),
},
match tags {
Some(tags) if !tags.is_empty() => user_agent
.map(|ua| format!(", user-agent={ua}"))
.unwrap_or_default(),
Some(_) | None => user_agent
.map(|ua| format!("user-agent={ua}"))
.unwrap_or_default(),
},
tags,
ua_sep,
user_agent,
protocol,
endpoint
);
Expand All @@ -227,7 +231,7 @@ impl RequestRecord<'_> {
);
}
Some(message) => error_access!(
"{}{} -> {} \t{}/{}/{}/{} \t{} -> {} \t {}{} {} {} | {}",
"{}{} -> {} \t{}/{}/{}/{} \t{} -> {} \t {}{}{} {} {} | {}",
context,
session_address.as_str_or("X"),
backend_address.as_str_or("X"),
Expand All @@ -237,22 +241,28 @@ impl RequestRecord<'_> {
LogDuration(server_rtt),
metrics.bin,
metrics.bout,
match user_agent {
Some(_) => tags.as_str_or(""),
None => tags.as_str_or("-"),
},
match tags {
Some(tags) if !tags.is_empty() => user_agent
.map(|ua| format!(", user-agent={ua}"))
.unwrap_or_default(),
Some(_) | None => user_agent
.map(|ua| format!("user-agent={ua}"))
.unwrap_or_default(),
},
tags,
ua_sep,
user_agent,
protocol,
endpoint,
message
),
}
}
}

fn prepare_user_agent(ua: &mut String) {
let mut ua_bytes = std::mem::take(ua).into_bytes();
for c in &mut ua_bytes {
if *c == b' ' {
*c = b'_';
}
}
if let Some(last) = ua_bytes.last_mut() {
if *last == b',' {
*last = b'!'
}
}
*ua = unsafe { String::from_utf8_unchecked(ua_bytes) };
}
9 changes: 5 additions & 4 deletions lib/src/protocol/kawa_h1/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -809,7 +809,7 @@ impl<Front: SocketHandler, L: ListenerHandler + L7ListenerHandler> Http<Front, L
)
}

pub fn log_request(&self, metrics: &SessionMetrics, message: Option<&str>) {
pub fn log_request(&mut self, metrics: &SessionMetrics, message: Option<&str>) {
let listener = self.listener.borrow();
let tags = self.context.authority.as_ref().and_then(|host| {
let hostname = match host.split_once(':') {
Expand All @@ -823,6 +823,7 @@ impl<Front: SocketHandler, L: ListenerHandler + L7ListenerHandler> Http<Front, L
SessionStatus::DefaultAnswer(answers, ..) => Some(answers.into()),
};

let user_agent = self.context.user_agent.take();
RequestRecord {
error: message,
context: self.log_context(),
Expand All @@ -840,15 +841,15 @@ impl<Front: SocketHandler, L: ListenerHandler + L7ListenerHandler> Http<Front, L
client_rtt: socket_rtt(self.front_socket()),
server_rtt: self.backend_socket.as_ref().and_then(socket_rtt),
metrics,
user_agent: self.context.user_agent.as_deref(),
user_agent,
}
.log();
}

pub fn log_request_success(&self, metrics: &SessionMetrics) {
pub fn log_request_success(&mut self, metrics: &SessionMetrics) {
self.log_request(metrics, None);
}
pub fn log_default_answer_success(&self, metrics: &SessionMetrics) {
pub fn log_default_answer_success(&mut self, metrics: &SessionMetrics) {
self.log_request(metrics, None);
}
pub fn log_request_error(&mut self, metrics: &mut SessionMetrics, message: &str) {
Expand Down
Loading