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}