scion_stack/scionstack/
scmp_handler.rs

1// Copyright 2025 Anapaya Systems
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//   http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//! SCION stack SCMP handler.
15
16use std::{pin::Pin, sync::Arc};
17
18use scion_proto::{
19    packet::{ByEndpoint, ScionPacketScmp},
20    scmp::{ScmpEchoReply, ScmpMessage},
21    wire_encoding::WireEncodeVec as _,
22};
23use tracing::debug;
24
25use crate::snap_tunnel::SnapTunnel;
26
27/// A trait for handling SCMP packets when they are received.
28/// It will be called with all SCMP packets that are received irrespective
29/// whether a destination port is specified or not.
30pub trait ScmpHandler: Send + Sync {
31    /// Handle a received SCMP packet.
32    fn handle_packet(
33        &self,
34        packet: ScionPacketScmp,
35    ) -> Pin<Box<dyn Future<Output = ()> + Send + '_>>;
36}
37
38/// Default SCMP handller.
39pub struct DefaultScmpHandler {
40    tunnel_sender: Arc<SnapTunnel>,
41}
42
43impl Clone for DefaultScmpHandler {
44    fn clone(&self) -> Self {
45        Self {
46            tunnel_sender: self.tunnel_sender.clone(),
47        }
48    }
49}
50
51impl DefaultScmpHandler {
52    /// Creates a new default SCMP handler.
53    pub fn new(tunnel_sender: Arc<SnapTunnel>) -> Self {
54        Self { tunnel_sender }
55    }
56}
57
58impl ScmpHandler for DefaultScmpHandler {
59    fn handle_packet(&self, p: ScionPacketScmp) -> Pin<Box<dyn Future<Output = ()> + Send + '_>> {
60        Box::pin(async move {
61            let reply = match p.message {
62                ScmpMessage::EchoRequest(r) => {
63                    debug!("echo request received, sending echo reply");
64                    ScmpMessage::EchoReply(ScmpEchoReply::new(
65                        r.identifier,
66                        r.sequence_number,
67                        r.data,
68                    ))
69                }
70                _ => return,
71            };
72
73            let reply_path = match p.headers.reversed_path(None) {
74                Ok(path) => path.data_plane_path,
75                Err(e) => {
76                    debug!("error reversing path of scmp packet: {}", e);
77                    return;
78                }
79            };
80
81            let src = match p.headers.address.source() {
82                Some(src) => src,
83                None => {
84                    debug!("error decoding source address of scmp packet");
85                    return;
86                }
87            };
88            let dst = match p.headers.address.destination() {
89                Some(dst) => dst,
90                None => {
91                    debug!("error decoding destination address of scmp packet");
92                    return;
93                }
94            };
95
96            let reply_packet = match ScionPacketScmp::new(
97                ByEndpoint {
98                    source: dst,
99                    destination: src,
100                },
101                reply_path,
102                reply,
103            ) {
104                Ok(packet) => packet,
105                Err(e) => {
106                    debug!("error encoding scmp reply: {}", e);
107                    return;
108                }
109            };
110            match self
111                .tunnel_sender
112                .send_datagram(reply_packet.encode_to_bytes_vec().concat().into())
113            {
114                Ok(_) => {}
115                Err(e) => {
116                    debug!("error sending scmp reply: {}", e);
117                }
118            }
119        })
120    }
121}