diff --git a/changelog.d/24838_dnstap_tcp_socket_leak.fix.md b/changelog.d/24838_dnstap_tcp_socket_leak.fix.md new file mode 100644 index 0000000000000..33d30980dcf6c --- /dev/null +++ b/changelog.d/24838_dnstap_tcp_socket_leak.fix.md @@ -0,0 +1,7 @@ +Fix TCP socket leak in `dnstap` source where sockets would accumulate in `CLOSE_WAIT` state +indefinitely. After sending a FrameStream `FINISH` frame in response to a client `STOP`, Vector +now explicitly closes the write side of the TCP connection as required by the FrameStream protocol, +preventing `CLOSE_WAIT` accumulation that previously exhausted the connection limit after extended +operation. + +authors: jpds diff --git a/src/sources/util/framestream.rs b/src/sources/util/framestream.rs index a42bae5815322..52768fc4bb19d 100644 --- a/src/sources/util/framestream.rs +++ b/src/sources/util/framestream.rs @@ -248,6 +248,11 @@ impl FrameStreamReader { self.send_control_frame(Self::make_frame(ControlHeader::Finish, None)); } self.state.control_state = ControlState::Stopped; //stream is now done + // Close the write side of the connection after STOP/FINISH. + // Per the FrameStream protocol, the server should initiate TCP close + // after sending FINISH. Without this, sockets accumulate in CLOSE_WAIT + // because the client may wait for the server to close first. + self.close_sink(); } _ => error!("Got wrong control frame, expected STOP."), } @@ -366,6 +371,15 @@ impl FrameStreamReader { error!("Encountered error '{:#?}' while sending control frame.", e); } } + + fn close_sink(&mut self) { + if let Err(e) = block_on(self.response_sink.lock().unwrap().close()) { + error!( + "Encountered error '{:#?}' while closing connection after FINISH.", + e + ); + } + } } pub trait FrameHandler {