Skip to main content

vector/sources/socket/
udp.rs

1use std::net::{Ipv4Addr, SocketAddr};
2
3use bytes::BytesMut;
4use chrono::Utc;
5use futures::StreamExt;
6use listenfd::ListenFd;
7use vector_lib::{
8    EstimatedJsonEncodedSizeOf,
9    codecs::{
10        DecoderFramedRead, StreamDecodingError,
11        decoding::{DeserializerConfig, FramingConfig},
12    },
13    config::{LegacyKey, LogNamespace},
14    configurable::configurable_component,
15    internal_event::{ByteSize, BytesReceived, InternalEventHandle as _, Protocol},
16    lookup::{lookup_v2::OptionalValuePath, owned_value_path, path},
17};
18
19use super::default_host_key;
20use crate::{
21    SourceSender,
22    codecs::Decoder,
23    event::Event,
24    internal_events::{
25        SocketBindError, SocketEventsReceived, SocketMode, SocketMulticastGroupJoinError,
26        SocketReceiveError, StreamClosedError,
27    },
28    net,
29    serde::default_decoding,
30    shutdown::ShutdownSignal,
31    sources::{
32        Source,
33        socket::SocketConfig,
34        util::net::{SocketListenAddr, try_bind_udp_socket},
35    },
36};
37
38/// UDP configuration for the `socket` source.
39#[configurable_component]
40#[serde(deny_unknown_fields)]
41#[derive(Clone, Debug)]
42pub struct UdpConfig {
43    #[configurable(derived)]
44    address: SocketListenAddr,
45
46    /// List of IPv4 multicast groups to join on socket's binding process.
47    ///
48    /// In order to read multicast packets, this source's listening address should be set to `0.0.0.0`.
49    /// If any other address is used (such as `127.0.0.1` or an specific interface address), the
50    /// listening interface will filter out all multicast packets received,
51    /// as their target IP would be the one of the multicast group
52    /// and it will not match the socket's bound IP.
53    ///
54    /// Note that this setting will only work if the source's address
55    /// is an IPv4 address (IPv6 and systemd file descriptor as source's address are not supported
56    /// with multicast groups).
57    #[serde(default)]
58    #[configurable(metadata(docs::examples = "['224.0.0.2', '224.0.0.4']"))]
59    pub(super) multicast_groups: Vec<Ipv4Addr>,
60
61    /// The IPv4 interface address used when joining multicast groups.
62    ///
63    /// Specifies which local network interface to use for receiving multicast traffic.
64    /// When not set, defaults to the socket's binding address.
65    ///
66    /// Set this explicitly when the host has multiple interfaces and you need to control
67    /// which one receives multicast traffic. For example, `127.0.0.1` restricts multicast
68    /// reception to the loopback interface.
69    ///
70    /// On macOS, specifying `0.0.0.0` only joins on the default network interface (typically
71    /// the primary Ethernet or Wi-Fi interface), unlike Linux, which joins on all interfaces.
72    /// If multicast traffic is expected on a specific interface (including loopback), set this
73    /// field explicitly.
74    #[serde(default)]
75    pub(super) multicast_interface: Option<Ipv4Addr>,
76
77    /// The maximum buffer size of incoming messages.
78    ///
79    /// Messages larger than this are truncated.
80    #[serde(default = "default_max_length")]
81    #[configurable(metadata(docs::type_unit = "bytes"))]
82    pub(super) max_length: usize,
83
84    /// Overrides the name of the log field used to add the peer host to each event.
85    ///
86    /// The value will be the peer host's address, including the port i.e. `1.2.3.4:9000`.
87    ///
88    /// By default, the [global `log_schema.host_key` option][global_host_key] is used.
89    ///
90    /// Set to `""` to suppress this key.
91    ///
92    /// [global_host_key]: https://vector.dev/docs/reference/configuration/global-options/#log_schema.host_key
93    host_key: Option<OptionalValuePath>,
94
95    /// Overrides the name of the log field used to add the peer host's port to each event.
96    ///
97    /// The value will be the peer host's port i.e. `9000`.
98    ///
99    /// By default, `"port"` is used.
100    ///
101    /// Set to `""` to suppress this key.
102    #[serde(default = "default_port_key")]
103    port_key: OptionalValuePath,
104
105    /// The size of the receive buffer used for the listening socket.
106    #[configurable(metadata(docs::type_unit = "bytes"))]
107    receive_buffer_bytes: Option<usize>,
108
109    #[configurable(derived)]
110    pub(super) framing: Option<FramingConfig>,
111
112    #[configurable(derived)]
113    #[serde(default = "default_decoding")]
114    pub(super) decoding: DeserializerConfig,
115
116    /// The namespace to use for logs. This overrides the global setting.
117    #[serde(default)]
118    #[configurable(metadata(docs::hidden))]
119    pub log_namespace: Option<bool>,
120}
121
122fn default_port_key() -> OptionalValuePath {
123    OptionalValuePath::from(owned_value_path!("port"))
124}
125
126fn default_max_length() -> usize {
127    crate::serde::default_max_length()
128}
129
130impl UdpConfig {
131    pub(super) fn host_key(&self) -> OptionalValuePath {
132        self.host_key.clone().unwrap_or(default_host_key())
133    }
134
135    pub const fn port_key(&self) -> &OptionalValuePath {
136        &self.port_key
137    }
138
139    pub(super) const fn framing(&self) -> &Option<FramingConfig> {
140        &self.framing
141    }
142
143    pub(super) const fn decoding(&self) -> &DeserializerConfig {
144        &self.decoding
145    }
146
147    pub(super) const fn address(&self) -> SocketListenAddr {
148        self.address
149    }
150
151    pub fn from_address(address: SocketListenAddr) -> Self {
152        Self {
153            address,
154            multicast_groups: Vec::new(),
155            multicast_interface: None,
156            max_length: default_max_length(),
157            host_key: None,
158            port_key: default_port_key(),
159            receive_buffer_bytes: None,
160            framing: None,
161            decoding: default_decoding(),
162            log_namespace: None,
163        }
164    }
165
166    pub const fn set_log_namespace(&mut self, val: Option<bool>) -> &mut Self {
167        self.log_namespace = val;
168        self
169    }
170}
171
172pub(super) fn udp(
173    config: UdpConfig,
174    decoder: Decoder,
175    mut shutdown: ShutdownSignal,
176    mut out: SourceSender,
177    log_namespace: LogNamespace,
178) -> Source {
179    Box::pin(async move {
180        let listenfd = ListenFd::from_env();
181        let socket = try_bind_udp_socket(config.address, listenfd)
182            .await
183            .map_err(|error| {
184                emit!(SocketBindError {
185                    mode: SocketMode::Udp,
186                    error,
187                })
188            })?;
189
190        if !config.multicast_groups.is_empty() {
191            socket.set_multicast_loop_v4(true).unwrap();
192            let listen_addr = match config.address() {
193                SocketListenAddr::SocketAddr(SocketAddr::V4(addr)) => addr,
194                SocketListenAddr::SocketAddr(SocketAddr::V6(_)) => {
195                    // We could support Ipv6 multicast with the
196                    // https://doc.rust-lang.org/std/net/struct.UdpSocket.html#method.join_multicast_v6 method
197                    // and specifying the interface index as `0`, in order to bind all interfaces.
198                    unimplemented!("IPv6 multicast is not supported")
199                }
200                SocketListenAddr::SystemdFd(_) => {
201                    unimplemented!("Multicast for systemd fd sockets is not supported")
202                }
203            };
204            for group_addr in config.multicast_groups {
205                let interface = config.multicast_interface.unwrap_or(*listen_addr.ip());
206                socket
207                    .join_multicast_v4(group_addr, interface)
208                    .map_err(|error| {
209                        emit!(SocketMulticastGroupJoinError {
210                            error,
211                            group_addr,
212                            interface,
213                        })
214                    })?;
215                info!(message = "Joined multicast group.", group = %group_addr);
216            }
217        }
218
219        if let Some(receive_buffer_bytes) = config.receive_buffer_bytes
220            && let Err(error) = net::set_receive_buffer_size(&socket, receive_buffer_bytes)
221        {
222            warn!(message = "Failed configuring receive buffer size on UDP socket.", %error);
223        }
224
225        let mut max_length = config.max_length;
226
227        if let Some(receive_buffer_bytes) = config.receive_buffer_bytes {
228            max_length = std::cmp::min(max_length, receive_buffer_bytes);
229        }
230
231        let bytes_received = register!(BytesReceived::from(Protocol::UDP));
232
233        info!(message = "Listening.", address = %config.address);
234        // We add 1 to the max_length in order to determine if the received data has been truncated.
235        let mut buf = BytesMut::with_capacity(max_length + 1);
236        loop {
237            buf.resize(max_length + 1, 0);
238            tokio::select! {
239                recv = socket.recv_from(&mut buf) => {
240                    let (byte_size, address) = match recv {
241                        Ok(res) => res,
242                        Err(error) => {
243                            #[cfg(windows)]
244                            if let Some(err) = error.raw_os_error() {
245                                if err == 10040 {
246                                    // 10040 is the Windows error that the Udp message has exceeded max_length
247                                    warn!(
248                                        message = "Discarding frame larger than max_length.",
249                                        max_length = max_length
250                                    );
251                                    continue;
252                                }
253                            }
254
255                            return Err(emit!(SocketReceiveError {
256                                mode: SocketMode::Udp,
257                                error
258                            }));
259                       }
260                    };
261
262                    bytes_received.emit(ByteSize(byte_size));
263                    let payload = buf.split_to(byte_size);
264                    let truncated = byte_size == max_length + 1;
265                    let mut stream =
266                        DecoderFramedRead::new(payload.as_ref(), decoder.clone()).peekable();
267
268                    while let Some(result) = stream.next().await {
269                        let last = Pin::new(&mut stream).peek().await.is_none();
270                        match result {
271                            Ok((mut events, _byte_size)) => {
272                                if last && truncated {
273                                    // The last event in this payload was truncated, so we want to drop it.
274                                    _ = events.pop();
275                                    warn!(
276                                        message = "Discarding frame larger than max_length.",
277                                        max_length = max_length
278                                    );
279                                }
280
281                                if events.is_empty() {
282                                    continue;
283                                }
284
285                                let count = events.len();
286                                emit!(SocketEventsReceived {
287                                    mode: SocketMode::Udp,
288                                    byte_size: events.estimated_json_encoded_size_of(),
289                                    count,
290                                });
291
292                                let now = Utc::now();
293
294                                for event in &mut events {
295                                    if let Event::Log(log) = event {
296                                        log_namespace.insert_standard_vector_source_metadata(
297                                            log,
298                                            SocketConfig::NAME,
299                                            now,
300                                        );
301
302                                        let legacy_host_key = config
303                                            .host_key
304                                            .clone()
305                                            .unwrap_or(default_host_key())
306                                            .path;
307
308                                        log_namespace.insert_source_metadata(
309                                            SocketConfig::NAME,
310                                            log,
311                                            legacy_host_key.as_ref().map(LegacyKey::InsertIfEmpty),
312                                            path!("host"),
313                                            address.ip().to_string()
314                                        );
315
316                                        let legacy_port_key = config.port_key.clone().path;
317
318                                        log_namespace.insert_source_metadata(
319                                            SocketConfig::NAME,
320                                            log,
321                                            legacy_port_key.as_ref().map(LegacyKey::InsertIfEmpty),
322                                            path!("port"),
323                                            address.port()
324                                        );
325                                    }
326                                }
327
328                                tokio::select!{
329                                    result = out.send_batch(events) => {
330                                        if result.is_err() {
331                                            emit!(StreamClosedError { count });
332                                            return Ok(())
333                                        }
334                                    }
335                                    _ = &mut shutdown => return Ok(()),
336                                }
337                            }
338                            Err(error) => {
339                                // Error is logged by `vector_lib::codecs::Decoder`, no
340                                // further handling is needed here.
341                                if !error.can_continue() {
342                                    break;
343                                }
344                            }
345                        }
346                    }
347                }
348                _ = &mut shutdown => return Ok(()),
349            }
350        }
351    })
352}