1use std::sync::Arc;
16
17use bytes::Bytes;
18use chrono::Utc;
19use futures::future::BoxFuture;
20use scion_proto::{
21 address::{ScionAddr, SocketAddr},
22 packet::{ByEndpoint, ScionPacketRaw, ScionPacketScmp, ScionPacketUdp},
23 path::Path,
24 scmp::ScmpMessage,
25};
26use tracing::{debug, trace};
27
28use super::{NetworkError, UnderlaySocket};
29use crate::{
30 path::{
31 Shortest,
32 manager::{CachingPathManager, PathManager, PathWaitError},
33 },
34 scionstack::{ScionSocketReceiveError, ScionSocketSendError},
35};
36
37pub struct PathUnawareUdpScionSocket {
39 inner: Box<dyn UnderlaySocket + Sync + Send>,
40}
41
42impl std::fmt::Debug for PathUnawareUdpScionSocket {
43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 f.debug_struct("PathUnawareUdpScionSocket")
45 .field("local_addr", &self.inner.local_addr())
46 .finish()
47 }
48}
49
50impl PathUnawareUdpScionSocket {
51 pub(crate) fn new(socket: Box<dyn UnderlaySocket + Sync + Send>) -> Self {
52 Self { inner: socket }
53 }
54
55 pub fn send_to_via<'a>(
57 &'a self,
58 payload: &[u8],
59 destination: SocketAddr,
60 path: &Path<&[u8]>,
61 ) -> BoxFuture<'a, Result<(), ScionSocketSendError>> {
62 let packet = match ScionPacketUdp::new(
63 ByEndpoint {
64 source: self.inner.local_addr(),
65 destination,
66 },
67 path.data_plane_path.to_bytes_path(),
68 Bytes::copy_from_slice(payload),
69 ) {
70 Ok(packet) => packet,
71 Err(e) => {
72 return Box::pin(async move {
73 Err(ScionSocketSendError::InvalidPacket(
74 format!("Error encoding packet: {e:#}").into(),
75 ))
76 });
77 }
78 }
79 .into();
80 self.inner.send(packet)
81 }
82
83 #[allow(clippy::type_complexity)]
85 pub fn recv_from_with_path<'a>(
86 &'a self,
87 buffer: &'a mut [u8],
88 path_buffer: &'a mut [u8],
89 ) -> BoxFuture<'a, Result<(usize, SocketAddr, Path<&'a mut [u8]>), ScionSocketReceiveError>>
90 {
91 Box::pin(async move {
92 loop {
93 let packet = self.inner.recv().await?;
94 let packet: ScionPacketUdp = match packet.try_into() {
95 Ok(packet) => packet,
96 Err(e) => {
97 debug!(error = %e, "Received invalid UDP packet, skipping");
98 continue;
99 }
100 };
101 let src_addr = match packet.headers.address.source() {
102 Some(source) => SocketAddr::new(source, packet.src_port()),
103 None => {
104 debug!("Received packet without source address header, skipping");
105 continue;
106 }
107 };
108 trace!(
109 "received packet from {}, length {}",
110 src_addr,
111 packet.datagram.payload.len()
112 );
113
114 let max_read = std::cmp::min(buffer.len(), packet.datagram.payload.len());
115 buffer[..max_read].copy_from_slice(&packet.datagram.payload[..max_read]);
116
117 if path_buffer.len() < packet.headers.path.raw().len() {
118 return Err(ScionSocketReceiveError::PathBufTooSmall);
119 }
120
121 let dataplane_path = packet
122 .headers
123 .path
124 .copy_to_slice(&mut path_buffer[..packet.headers.path.raw().len()]);
125
126 let path = Path::new(dataplane_path, packet.headers.address.ia, None);
130
131 return Ok((packet.datagram.payload.len(), src_addr, path));
132 }
133 })
134 }
135
136 pub fn recv_from<'a>(
138 &'a self,
139 buffer: &'a mut [u8],
140 ) -> BoxFuture<'a, Result<(usize, SocketAddr), ScionSocketReceiveError>> {
141 Box::pin(async move {
142 loop {
143 let packet = self.inner.recv().await?;
144 let packet: ScionPacketUdp = match packet.try_into() {
145 Ok(packet) => packet,
146 Err(e) => {
147 debug!(error = %e, "Received invalid UDP packet, skipping");
148 continue;
149 }
150 };
151 let src_addr = match packet.headers.address.source() {
152 Some(source) => SocketAddr::new(source, packet.src_port()),
153 None => {
154 debug!("Received packet without source address header, skipping");
155 continue;
156 }
157 };
158
159 trace!(
160 "received packet from {}, length {}, into buffer of size {}",
161 src_addr,
162 packet.datagram.payload.len(),
163 buffer.len()
164 );
165
166 let max_read = std::cmp::min(buffer.len(), packet.datagram.payload.len());
167 buffer[..max_read].copy_from_slice(&packet.datagram.payload[..max_read]);
168
169 return Ok((packet.datagram.payload.len(), src_addr));
170 }
171 })
172 }
173
174 fn local_addr(&self) -> SocketAddr {
176 self.inner.local_addr()
177 }
178}
179
180pub struct ScmpScionSocket {
182 inner: Box<dyn UnderlaySocket + Sync + Send>,
183}
184
185impl ScmpScionSocket {
186 pub(crate) fn new(socket: Box<dyn UnderlaySocket + Sync + Send>) -> Self {
187 Self { inner: socket }
188 }
189}
190
191impl ScmpScionSocket {
192 pub fn send_to_via<'a>(
194 &'a self,
195 message: ScmpMessage,
196 destination: ScionAddr,
197 path: &Path<&[u8]>,
198 ) -> BoxFuture<'a, Result<(), ScionSocketSendError>> {
199 let packet = match ScionPacketScmp::new(
200 ByEndpoint {
201 source: self.inner.local_addr().scion_address(),
202 destination,
203 },
204 path.data_plane_path.to_bytes_path(),
205 message,
206 ) {
207 Ok(packet) => packet,
208 Err(e) => {
209 return Box::pin(async move {
210 Err(ScionSocketSendError::InvalidPacket(
211 format!("Error encoding packet: {e:#}").into(),
212 ))
213 });
214 }
215 };
216 let packet = packet.into();
217 Box::pin(async move { self.inner.send(packet).await })
218 }
219
220 #[allow(clippy::type_complexity)]
222 pub fn recv_from_with_path<'a>(
223 &'a self,
224 path_buffer: &'a mut [u8],
225 ) -> BoxFuture<'a, Result<(ScmpMessage, ScionAddr, Path<&'a mut [u8]>), ScionSocketReceiveError>>
226 {
227 Box::pin(async move {
228 loop {
229 let packet = self.inner.recv().await?;
230 let packet: ScionPacketScmp = match packet.try_into() {
231 Ok(packet) => packet,
232 Err(e) => {
233 debug!(error = %e, "Received invalid SCMP packet, skipping");
234 continue;
235 }
236 };
237 let src_addr = match packet.headers.address.source() {
238 Some(source) => source,
239 None => {
240 debug!("Received packet without source address header, skipping");
241 continue;
242 }
243 };
244
245 if path_buffer.len() < packet.headers.path.raw().len() {
246 return Err(ScionSocketReceiveError::PathBufTooSmall);
247 }
248 let dataplane_path = packet
249 .headers
250 .path
251 .copy_to_slice(&mut path_buffer[..packet.headers.path.raw().len()]);
252 let path = Path::new(dataplane_path, packet.headers.address.ia, None);
253
254 return Ok((packet.message, src_addr, path));
255 }
256 })
257 }
258
259 pub fn recv_from<'a>(
261 &'a self,
262 ) -> BoxFuture<'a, Result<(ScmpMessage, ScionAddr), ScionSocketReceiveError>> {
263 Box::pin(async move {
264 loop {
265 let packet = self.inner.recv().await?;
266 let packet: ScionPacketScmp = match packet.try_into() {
267 Ok(packet) => packet,
268 Err(e) => {
269 debug!(error = %e, "Received invalid SCMP packet, skipping");
270 continue;
271 }
272 };
273 let src_addr = match packet.headers.address.source() {
274 Some(source) => source,
275 None => {
276 debug!("Received packet without source address header, skipping");
277 continue;
278 }
279 };
280 return Ok((packet.message, src_addr));
281 }
282 })
283 }
284
285 pub fn local_addr(&self) -> SocketAddr {
287 self.inner.local_addr()
288 }
289}
290
291pub struct RawScionSocket {
293 inner: Box<dyn UnderlaySocket>,
294}
295
296impl RawScionSocket {
297 pub(crate) fn new(socket: Box<dyn UnderlaySocket + Sync + Send>) -> Self {
298 Self { inner: socket }
299 }
300}
301
302impl RawScionSocket {
303 pub fn send<'a>(
305 &'a self,
306 packet: ScionPacketRaw,
307 ) -> BoxFuture<'a, Result<(), ScionSocketSendError>> {
308 self.inner.send(packet)
309 }
310
311 pub fn recv<'a>(&'a self) -> BoxFuture<'a, Result<ScionPacketRaw, ScionSocketReceiveError>> {
313 self.inner.recv()
314 }
315
316 pub fn local_addr(&self) -> SocketAddr {
318 self.inner.local_addr()
319 }
320}
321
322pub struct UdpScionSocket<P: PathManager = CachingPathManager<Shortest>> {
324 socket: PathUnawareUdpScionSocket,
325 pather: Arc<P>,
326 remote_addr: Option<SocketAddr>,
327}
328
329impl<P: PathManager> std::fmt::Debug for UdpScionSocket<P> {
330 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
331 f.debug_struct("UdpScionSocket")
332 .field("local_addr", &self.socket.local_addr())
333 .field("remote_addr", &self.remote_addr)
334 .finish()
335 }
336}
337
338impl<P: PathManager> UdpScionSocket<P> {
339 pub fn new(
341 socket: PathUnawareUdpScionSocket,
342 pather: Arc<P>,
343 remote_addr: Option<SocketAddr>,
344 ) -> Self {
345 Self {
346 socket,
347 pather,
348 remote_addr,
349 }
350 }
351
352 pub fn connect(self, remote_addr: SocketAddr) -> Self {
354 Self {
355 remote_addr: Some(remote_addr),
356 ..self
357 }
358 }
359
360 pub async fn send(&self, payload: &[u8]) -> Result<(), ScionSocketSendError> {
362 if let Some(remote_addr) = self.remote_addr {
363 self.send_to(payload, remote_addr).await
364 } else {
365 Err(ScionSocketSendError::NotConnected)
366 }
367 }
368
369 pub async fn send_to(
371 &self,
372 payload: &[u8],
373 destination: SocketAddr,
374 ) -> Result<(), ScionSocketSendError> {
375 let path = &self
376 .pather
377 .path_wait(
378 self.socket.local_addr().isd_asn(),
379 destination.isd_asn(),
380 Utc::now(),
381 )
382 .await
383 .map_err(|e| {
384 match e {
385 PathWaitError::FetchFailed(e) => {
386 ScionSocketSendError::PathLookupError(e.into())
387 }
388 PathWaitError::NoPathFound => {
389 ScionSocketSendError::NetworkUnreachable(
390 NetworkError::DestinationUnreachable("No path found".to_string()),
391 )
392 }
393 }
394 })?;
395 self.socket
396 .send_to_via(payload, destination, &path.to_slice_path())
397 .await
398 }
399
400 pub async fn send_to_via(
402 &self,
403 payload: &[u8],
404 destination: SocketAddr,
405 path: &Path<&[u8]>,
406 ) -> Result<(), ScionSocketSendError> {
407 self.socket.send_to_via(payload, destination, path).await
408 }
409
410 pub async fn recv_from_with_path<'a>(
412 &'a self,
413 buffer: &'a mut [u8],
414 path_buffer: &'a mut [u8],
415 ) -> Result<(usize, SocketAddr, Path<&'a mut [u8]>), ScionSocketReceiveError> {
416 let (len, sender_addr, path): (usize, SocketAddr, Path<&mut [u8]>) =
417 self.socket.recv_from_with_path(buffer, path_buffer).await?;
418
419 match path.to_reversed() {
420 Ok(reversed_path) => {
421 self.pather.register_path(
423 self.socket.local_addr().isd_asn(),
424 sender_addr.isd_asn(),
425 Utc::now(),
426 reversed_path,
427 );
428 }
429 Err(e) => {
430 trace!("Failed to reverse path for registration: {e}")
431 }
432 }
433
434 trace!(
435 "Registered reverse path from {} to {}",
436 self.socket.local_addr(),
437 sender_addr
438 );
439
440 Ok((len, sender_addr, path))
441 }
442
443 pub async fn recv_from(
445 &self,
446 buffer: &mut [u8],
447 ) -> Result<(usize, SocketAddr), ScionSocketReceiveError> {
448 let mut path_buffer = [0u8; 1024]; let (len, sender_addr, _) = self.recv_from_with_path(buffer, &mut path_buffer).await?;
451 Ok((len, sender_addr))
452 }
453
454 pub async fn recv(&self, buffer: &mut [u8]) -> Result<usize, ScionSocketReceiveError> {
458 if self.remote_addr.is_none() {
459 return Err(ScionSocketReceiveError::NotConnected);
460 }
461 loop {
462 let (len, sender_addr) = self.recv_from(buffer).await?;
463 match self.remote_addr {
464 Some(remote_addr) => {
465 if sender_addr == remote_addr {
466 return Ok(len);
467 }
468 }
469 None => return Err(ScionSocketReceiveError::NotConnected),
470 }
471 }
472 }
473
474 pub fn local_addr(&self) -> SocketAddr {
476 self.socket.local_addr()
477 }
478}