asport/protocol/
mod.rs

1use std::{
2    fmt::{Display, Formatter, Result as FmtResult},
3    mem,
4    net::SocketAddr,
5};
6
7#[allow(unused_imports)]
8pub use self::{
9    client_hello::{ClientHello, Flags, InvalidFlags},
10    connect::Connect,
11    dissociate::Dissociate,
12    heartbeat::Heartbeat,
13    packet::Packet,
14    server_hello::ServerHello,
15};
16
17mod client_hello;
18mod connect;
19mod dissociate;
20mod heartbeat;
21mod packet;
22mod server_hello;
23
24pub const VERSION: u8 = 0x00;
25
26#[non_exhaustive]
27#[derive(Clone, Debug)]
28pub enum Header {
29    ClientHello(ClientHello),
30    ServerHello(ServerHello),
31    Connect(Connect),
32    Packet(Packet),
33    Dissociate(Dissociate),
34    Heartbeat(Heartbeat),
35}
36
37impl Header {
38    pub const TYPE_CODE_CLIENT_HELLO: u8 = ClientHello::type_code();
39    pub const TYPE_CODE_SERVER_HELLO: u8 = ServerHello::type_code();
40    pub const TYPE_CODE_CONNECT: u8 = Connect::type_code();
41    pub const TYPE_CODE_PACKET: u8 = Packet::type_code();
42    pub const TYPE_CODE_DISSOCIATE: u8 = Dissociate::type_code();
43    pub const TYPE_CODE_HEARTBEAT: u8 = Heartbeat::type_code();
44
45    /// Returns the command type code
46    pub const fn type_code(&self) -> u8 {
47        match self {
48            Self::ClientHello(_) => Self::TYPE_CODE_CLIENT_HELLO,
49            Self::ServerHello(_) => Self::TYPE_CODE_SERVER_HELLO,
50            Self::Connect(_) => Self::TYPE_CODE_CONNECT,
51            Self::Packet(_) => Self::TYPE_CODE_PACKET,
52            Self::Dissociate(_) => Self::TYPE_CODE_DISSOCIATE,
53            Self::Heartbeat(_) => Self::TYPE_CODE_HEARTBEAT,
54        }
55    }
56
57    /// Returns the serialized length of the command
58    #[allow(clippy::len_without_is_empty)]
59    pub fn len(&self) -> usize {
60        2 + match self {
61            Self::ClientHello(client_hello) => client_hello.len(),
62            Self::ServerHello(server_hello) => server_hello.len(),
63            Self::Connect(connect) => connect.len(),
64            Self::Packet(packet) => packet.len(),
65            Self::Dissociate(dissociate) => dissociate.len(),
66            Self::Heartbeat(heartbeat) => heartbeat.len(),
67        }
68    }
69}
70
71/// Socks5-like variable-length field that encodes the network address
72/// Domain is not supported because it not possible that the remote address is a domain.
73///
74/// ```plain
75/// +------+----------+----------+
76/// | ATYP |   ADDR   |   PORT   |
77/// +------+----------+----------+
78/// |  1   | Variable |    2     |
79/// +------+----------+----------+
80/// ```
81///
82/// where:
83///
84/// - `ATYP` - the address type
85/// - `ADDR` - the address
86/// - `PORT` - the port
87///
88/// The address type can be one of the following:
89///
90/// - `0xff`: None
91/// - `0x01`: IPv4 address
92/// - `0x04`: IPv6 address
93///
94/// Address type `None` is used in `Packet` commands that is not the first fragment of a UDP packet.
95///
96/// The port number is encoded in 2 bytes after the Domain name / IP address.
97#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
98pub enum Address {
99    None,
100    SocketAddress(SocketAddr),
101}
102
103impl Address {
104    pub const TYPE_CODE_NONE: u8 = 0xff;
105    pub const TYPE_CODE_IPV4: u8 = 0x01;
106    pub const TYPE_CODE_IPV6: u8 = 0x04;
107
108    /// Returns the address type code
109    pub const fn type_code(&self) -> u8 {
110        match self {
111            Self::None => Self::TYPE_CODE_NONE,
112            Self::SocketAddress(addr) => match addr {
113                SocketAddr::V4(_) => Self::TYPE_CODE_IPV4,
114                SocketAddr::V6(_) => Self::TYPE_CODE_IPV6,
115            },
116        }
117    }
118
119    /// Returns the serialized length of the address
120    #[allow(clippy::len_without_is_empty)]
121    pub fn len(&self) -> usize {
122        1 + match self {
123            Address::None => 0,
124            Address::SocketAddress(SocketAddr::V4(_)) => 4 + 2,
125            Address::SocketAddress(SocketAddr::V6(_)) => 16 + 2,
126        }
127    }
128
129    /// Takes the address out, leaving a `None` in its place
130    pub fn take(&mut self) -> Self {
131        mem::take(self)
132    }
133
134    /// Returns `true` if the address is `None`
135    pub fn is_none(&self) -> bool {
136        matches!(self, Self::None)
137    }
138
139    /// Returns `true` if the address is an IPv4 address
140    pub fn is_ipv4(&self) -> bool {
141        matches!(self, Self::SocketAddress(SocketAddr::V4(_)))
142    }
143
144    /// Returns `true` if the address is an IPv6 address
145    pub fn is_ipv6(&self) -> bool {
146        matches!(self, Self::SocketAddress(SocketAddr::V6(_)))
147    }
148}
149
150impl Display for Address {
151    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
152        match self {
153            Self::None => write!(f, "none"),
154            Self::SocketAddress(addr) => write!(f, "{addr}"),
155        }
156    }
157}
158
159impl Default for Address {
160    fn default() -> Self {
161        Self::None
162    }
163}