actix_proxy_protocol/
tlv.rs1use std::{borrow::Cow, convert::TryFrom, str};
2
3const PP2_TYPE_ALPN: u8 = 0x01; const PP2_TYPE_AUTHORITY: u8 = 0x02; const PP2_TYPE_CRC32C: u8 = 0x03; const PP2_TYPE_NOOP: u8 = 0x04; const PP2_TYPE_UNIQUE_ID: u8 = 0x05; const PP2_TYPE_SSL: u8 = 0x20;
9const PP2_SUBTYPE_SSL_VERSION: u8 = 0x21;
10const PP2_SUBTYPE_SSL_CN: u8 = 0x22;
11const PP2_SUBTYPE_SSL_CIPHER: u8 = 0x23;
12const PP2_SUBTYPE_SSL_SIG_ALG: u8 = 0x24;
13const PP2_SUBTYPE_SSL_KEY_ALG: u8 = 0x25;
14const PP2_TYPE_NETNS: u8 = 0x30;
15
16pub trait Tlv: Sized {
17 const TYPE: u8;
18
19 fn try_from_value(value: &[u8]) -> Option<Self>;
20
21 fn value_bytes(&self) -> Cow<'_, [u8]>;
22
23 fn try_from_parts(typ: u8, value: &[u8]) -> Option<Self> {
24 if typ != Self::TYPE {
25 return None;
26 }
27
28 Self::try_from_value(value)
29 }
30}
31
32#[derive(Debug, Clone, PartialEq, Eq)]
37pub struct Alpn {
38 alpn: Vec<u8>,
39}
40
41impl Alpn {
42 pub fn new(alpn: impl Into<Vec<u8>>) -> Self {
47 let alpn = alpn.into();
48
49 assert!(!alpn.is_empty(), "ALPN TLV value cannot be empty");
50
51 Self { alpn }
52 }
53}
54
55impl Tlv for Alpn {
56 const TYPE: u8 = PP2_TYPE_ALPN;
57
58 fn try_from_value(value: &[u8]) -> Option<Self> {
59 Some(Self {
60 alpn: value.to_owned(),
61 })
62 }
63
64 fn value_bytes(&self) -> Cow<'_, [u8]> {
65 Cow::Borrowed(&self.alpn)
66 }
67}
68
69#[derive(Debug, Clone, PartialEq, Eq)]
75pub struct Authority {
76 authority: String,
77}
78
79impl Authority {
80 pub fn new(authority: impl Into<String>) -> Self {
85 let authority = authority.into();
86
87 assert!(!authority.is_empty(), "Authority TLV value cannot be empty");
88
89 Self { authority }
90 }
91}
92
93impl Tlv for Authority {
94 const TYPE: u8 = PP2_TYPE_AUTHORITY;
95
96 fn try_from_value(value: &[u8]) -> Option<Self> {
97 Some(Self {
98 authority: str::from_utf8(value).ok()?.to_owned(),
99 })
100 }
101
102 fn value_bytes(&self) -> Cow<'_, [u8]> {
103 Cow::Borrowed(self.authority.as_bytes())
104 }
105}
106
107#[derive(Debug, Clone, Default, PartialEq, Eq)]
110pub struct Crc32c {
111 pub(crate) checksum: u32,
112}
113
114impl Tlv for Crc32c {
115 const TYPE: u8 = PP2_TYPE_CRC32C;
116
117 fn try_from_value(value: &[u8]) -> Option<Self> {
118 let checksum_bytes = <[u8; 4]>::try_from(value).ok()?;
119
120 Some(Self {
121 checksum: u32::from_be_bytes(checksum_bytes),
122 })
123 }
124
125 fn value_bytes(&self) -> Cow<'_, [u8]> {
126 Cow::Owned(self.checksum.to_be_bytes().to_vec())
127 }
128}
129
130#[derive(Debug, Clone, PartialEq, Eq)]
134pub struct Noop {
135 value: Vec<u8>,
136}
137
138impl Noop {
139 pub fn new(value: impl Into<Vec<u8>>) -> Self {
144 let value = value.into();
145
146 assert!(!value.is_empty(), "Noop TLV `value` cannot be empty");
147
148 Self { value }
149 }
150}
151
152impl Tlv for Noop {
153 const TYPE: u8 = PP2_TYPE_NOOP;
154
155 fn try_from_value(value: &[u8]) -> Option<Self> {
156 Some(Self {
157 value: value.to_owned(),
158 })
159 }
160
161 fn value_bytes(&self) -> Cow<'_, [u8]> {
162 Cow::Borrowed(&self.value)
163 }
164}
165
166#[derive(Debug, Clone, PartialEq, Eq)]
173pub struct UniqueId {
174 value: Vec<u8>,
175}
176
177impl UniqueId {
178 pub fn new(id: impl Into<Vec<u8>>) -> Self {
183 let value = id.into();
184
185 assert!(!value.is_empty(), "UniqueId TLV `value` cannot be empty");
186 assert!(
187 value.len() < 128,
188 "UniqueId TLV `value` cannot be larger than 128 bytes"
189 );
190
191 Self { value }
192 }
193}
194
195impl Tlv for UniqueId {
196 const TYPE: u8 = PP2_TYPE_UNIQUE_ID;
197
198 fn try_from_value(value: &[u8]) -> Option<Self> {
199 Some(Self {
200 value: value.to_owned(),
201 })
202 }
203
204 fn value_bytes(&self) -> Cow<'_, [u8]> {
205 Cow::Borrowed(&self.value)
206 }
207}
208
209bitflags::bitflags! {
210 #[derive(Debug, Clone, PartialEq, Eq)]
211 struct SslClientFlags: u8 {
212 const PP2_CLIENT_SSL = 0x01;
213 const PP2_CLIENT_CERT_CONN = 0x02;
214 const PP2_CLIENT_CERT_SESS = 0x04;
215 }
216}
217
218#[derive(Debug, Clone, PartialEq, Eq)]
222pub struct Ssl {
223 client: SslClientFlags,
230
231 verify: bool,
234
235 tlvs: Vec<SslTlv>,
237}
238
239impl Tlv for Ssl {
240 const TYPE: u8 = PP2_TYPE_SSL;
241
242 fn try_from_value(_value: &[u8]) -> Option<Self> {
243 const PP2_CLIENT_SSL: u8 = 0x01;
248
249 const PP2_CLIENT_CERT_CONN: u8 = 0x02;
252
253 const PP2_CLIENT_CERT_SESS: u8 = 0x04;
256
257 None
260 }
261
262 fn value_bytes(&self) -> Cow<'_, [u8]> {
263 Cow::Borrowed(&[])
264 }
265}
266
267#[derive(Debug, Clone, PartialEq, Eq)]
268struct SslTlv {}
269
270#[cfg(test)]
271mod tests {
272 use super::*;
273
274 #[test]
281 fn tlv_as_crc32c() {
282 assert_eq!(Crc32c::try_from_parts(0x04, &[0x00]), None);
284
285 assert_eq!(
286 Crc32c::try_from_parts(0x03, &[0x08, 0x70, 0x17, 0x7b]),
287 Some(Crc32c {
288 checksum: 141563771
289 })
290 );
291 }
292}