snap_tun/
lib.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//! SNAP tunnel library.
15
16pub mod client;
17pub mod metrics;
18pub mod requests;
19pub mod server;
20
21use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
22
23use ipnet::{IpNet, Ipv4Net, Ipv6Net};
24use scion_proto::address::{EndhostAddr, IsdAsn};
25
26/// The address assign connect RPC endpoint.
27pub(crate) const PATH_ADDR_ASSIGNMENT: &str = "/connectrpc.v1.snaptun/assign_addresses";
28/// The session renewal connect RPC endpoint.
29pub(crate) const PATH_SESSION_RENEWAL: &str = "/connectrpc.v1.snaptun/renew_session";
30pub(crate) const AUTH_HEADER: &str = "Authorization";
31
32/// Placeholder IPv4-Address that should be used by callers to
33/// [AddressAllocator::allocate] if the caller wants to request any of the
34/// available IPv4-addresses.
35pub const IPV4_WILDCARD: IpNet = IpNet::V4(Ipv4Net::new_assert(Ipv4Addr::UNSPECIFIED, 32));
36/// Placeholder IPv6-Address that should be used by callers to
37/// [AddressAllocator::allocate] if the caller wants to request any of the
38/// available IPv4-addresses.
39pub const IPV6_WILDCARD: IpNet = IpNet::V6(Ipv6Net::new_assert(Ipv6Addr::UNSPECIFIED, 128));
40
41/// Address allocation identifier.
42#[derive(Debug, Clone, PartialEq, Eq, Hash)]
43pub struct AddressAllocationId {
44    /// ISD-AS.
45    pub isd_as: IsdAsn,
46    /// Unique identifier.
47    pub id: String,
48}
49
50/// Address allocation.
51#[derive(Debug, Clone, PartialEq, Eq, Hash)]
52pub struct AddressAllocation {
53    /// Address allocation identifier.
54    pub id: AddressAllocationId,
55    /// Allocated endhost address.
56    pub address: EndhostAddr,
57}
58
59/// Address allocator trait.
60pub trait AddressAllocator<Token>: Send + Sync {
61    /// Allocate an address to a client.
62    ///
63    /// * The implementation SHOULD renew existing allocation, if the token claims matches an
64    ///   existing allocation and return the corresponding address.
65    ///
66    /// * The implementation MUST attempt to return a concrete address if either [IPV4_WILDCARD] or
67    ///   [IPV6_WILDCARD] is provided.
68    fn allocate(
69        &self,
70        isd_as: IsdAsn,
71        prefix: IpNet,
72        claims: Token,
73    ) -> Result<AddressAllocation, AddressAllocationError>;
74
75    /// Sets an address on hold
76    ///
77    /// The hold prevents the address from being reallocated for a certain period of time.
78    fn put_on_hold(&self, id: AddressAllocationId) -> bool;
79
80    /// Immediately deallocates an address
81    ///
82    /// Returns `true` if allocation was found and removed, `false` if allocation was not found
83    fn deallocate(&self, id: AddressAllocationId) -> bool;
84}
85
86/// Address allocation error.
87#[derive(Debug, thiserror::Error)]
88pub enum AddressAllocationError {
89    /// No address manager for the given ISD-AS.
90    #[error("no address registry for ISD-AS {0}")]
91    NoAddressManagerForIsdAs(IsdAsn),
92    /// Address already registered.
93    #[error("address {0} already registered")]
94    AddressAlreadyRegistered(EndhostAddr),
95    /// Address not in allocation range.
96    #[error("address {0} not in allocation range")]
97    AddressNotInAllocationRange(IpAddr),
98    /// IA not in allocation range.
99    #[error("address {0} not in allocation ISD-AS {1}")]
100    IaNotInAllocationRange(IsdAsn, IsdAsn),
101    /// No addresses available.
102    #[error("no addresses available")]
103    NoAddressesAvailable,
104    /// Prefix allocation rejected.
105    #[error("prefix allocation rejected")]
106    AddressAllocationRejected,
107}