1use std::net::{IpAddr, SocketAddr};
7
8use caret::caret_int;
9use derive_deftly::Deftly;
10use tor_bytes::{EncodeResult, Readable, Reader, Result, Writeable, Writer};
11use tor_llcrypto::pk::ed25519;
12use tor_llcrypto::pk::rsa::RsaIdentity;
13use tor_memquota::derive_deftly_template_HasMemoryCost;
14
15use crate::RelayId;
16
17#[non_exhaustive]
19#[derive(Debug, Clone, PartialEq, Eq, Deftly)]
20#[derive_deftly(HasMemoryCost)]
21pub enum LinkSpec {
22 OrPort(IpAddr, u16),
24 RsaId(RsaIdentity),
26 Ed25519Id(ed25519::Ed25519Identity),
28 Unrecognized(LinkSpecType, Vec<u8>),
30}
31
32caret_int! {
33 #[derive(Deftly)]
35 #[derive_deftly(HasMemoryCost)]
36 pub struct LinkSpecType(u8) {
37 ORPORT_V4 = 0,
39 ORPORT_V6 = 1,
41 RSAID = 2,
43 ED25519ID = 3,
45 }
46}
47
48impl Readable for LinkSpec {
49 fn take_from(b: &mut Reader<'_>) -> Result<Self> {
50 let lstype = b.take_u8()?.into();
51 b.read_nested_u8len(|r| Self::from_type_and_body(lstype, r))
52 }
53}
54impl Writeable for LinkSpec {
55 fn write_onto<B: Writer + ?Sized>(&self, w: &mut B) -> EncodeResult<()> {
56 w.write_u8(self.lstype().into());
57 {
58 let mut inner = w.write_nested_u8len();
59 self.encode_body(&mut *inner)?;
60 inner.finish()?;
61 }
62 Ok(())
63 }
64}
65
66impl From<&SocketAddr> for LinkSpec {
67 fn from(sa: &SocketAddr) -> Self {
68 LinkSpec::OrPort(sa.ip(), sa.port())
69 }
70}
71impl From<SocketAddr> for LinkSpec {
72 fn from(sa: SocketAddr) -> Self {
73 (&sa).into()
74 }
75}
76impl From<RsaIdentity> for LinkSpec {
77 fn from(id: RsaIdentity) -> Self {
78 LinkSpec::RsaId(id)
79 }
80}
81impl From<ed25519::Ed25519Identity> for LinkSpec {
82 fn from(id: ed25519::Ed25519Identity) -> Self {
83 LinkSpec::Ed25519Id(id)
84 }
85}
86impl From<ed25519::PublicKey> for LinkSpec {
87 fn from(pk: ed25519::PublicKey) -> Self {
88 LinkSpec::Ed25519Id(pk.into())
89 }
90}
91impl From<RelayId> for LinkSpec {
92 fn from(id: RelayId) -> Self {
93 match id {
94 RelayId::Ed25519(key) => LinkSpec::Ed25519Id(key),
95 RelayId::Rsa(key) => LinkSpec::RsaId(key),
96 }
97 }
98}
99
100impl LinkSpec {
101 fn sort_pos(&self) -> u8 {
104 use LinkSpec::*;
105 match self {
106 OrPort(IpAddr::V4(_), _) => 0,
107 RsaId(_) => 1,
108 Ed25519Id(_) => 2,
109 OrPort(IpAddr::V6(_), _) => 3,
110 Unrecognized(n, _) => (*n).into(),
111 }
112 }
113
114 pub fn sort_by_type(lst: &mut [Self]) {
117 lst.sort_by_key(LinkSpec::sort_pos);
118 }
119
120 fn from_type_and_body(lstype: LinkSpecType, r: &mut Reader<'_>) -> Result<Self> {
125 use LinkSpecType as LST;
126 Ok(match lstype {
127 LST::ORPORT_V4 => {
128 let addr = IpAddr::V4(r.extract()?);
129 LinkSpec::OrPort(addr, r.take_u16()?)
130 }
131 LST::ORPORT_V6 => {
132 let addr = IpAddr::V6(r.extract()?);
133 LinkSpec::OrPort(addr, r.take_u16()?)
134 }
135 LST::RSAID => LinkSpec::RsaId(r.extract()?),
136 LST::ED25519ID => LinkSpec::Ed25519Id(r.extract()?),
137 _ => LinkSpec::Unrecognized(lstype, r.take_rest().into()),
138 })
139 }
140
141 fn lstype(&self) -> LinkSpecType {
143 use LinkSpecType as LST;
144 match self {
145 LinkSpec::OrPort(IpAddr::V4(_), _) => LST::ORPORT_V4,
146 LinkSpec::OrPort(IpAddr::V6(_), _) => LST::ORPORT_V6,
147
148 LinkSpec::RsaId(_) => LST::RSAID,
149 LinkSpec::Ed25519Id(_) => LST::ED25519ID,
150 LinkSpec::Unrecognized(lstype, _) => *lstype,
151 }
152 }
153
154 fn encode_body<W: Writer + ?Sized>(&self, w: &mut W) -> EncodeResult<()> {
156 use LinkSpec::*;
157 match self {
158 OrPort(IpAddr::V4(v4), port) => {
159 w.write(v4)?;
160 w.write_u16(*port);
161 }
162 OrPort(IpAddr::V6(v6), port) => {
163 w.write(v6)?;
164 w.write_u16(*port);
165 }
166 RsaId(r) => {
167 w.write(r)?;
168 }
169 Ed25519Id(e) => {
170 w.write(e)?;
171 }
172 Unrecognized(_, vec) => {
173 w.write_all(&vec[..]);
174 }
175 }
176 Ok(())
177 }
178
179 pub fn encode(&self) -> EncodeResult<EncodedLinkSpec> {
181 let tp = self.lstype();
182 let mut body = Vec::new();
183 self.encode_body(&mut body)?;
184 Ok(EncodedLinkSpec::new(tp, body))
185 }
186}
187
188#[derive(Debug, Clone, PartialEq, Eq, Deftly)]
192#[derive_deftly(HasMemoryCost)]
193pub struct EncodedLinkSpec {
194 lstype: LinkSpecType,
196 body: Vec<u8>,
198}
199
200impl EncodedLinkSpec {
201 pub fn new(lstype: LinkSpecType, body: impl Into<Vec<u8>>) -> Self {
203 EncodedLinkSpec {
204 lstype,
205 body: body.into(),
206 }
207 }
208
209 pub fn parse(&self) -> Result<LinkSpec> {
211 let mut r = Reader::from_slice(&self.body[..]);
212 let ls = LinkSpec::from_type_and_body(self.lstype, &mut r)?;
213 r.should_be_exhausted()?;
214 Ok(ls)
215 }
216
217 pub fn lstype(&self) -> LinkSpecType {
219 self.lstype
220 }
221}
222
223impl Readable for EncodedLinkSpec {
224 fn take_from(r: &mut Reader<'_>) -> Result<Self> {
225 let lstype = r.take_u8()?.into();
226 r.read_nested_u8len(|r| {
227 let body = r.take_rest().to_vec();
228 Ok(Self { lstype, body })
229 })
230 }
231}
232impl Writeable for EncodedLinkSpec {
233 fn write_onto<B: Writer + ?Sized>(&self, w: &mut B) -> EncodeResult<()> {
234 w.write_u8(self.lstype.into());
235 let mut nested = w.write_nested_u8len();
236 nested.write_all(&self.body[..]);
237 nested.finish()
238 }
239}
240
241#[cfg(test)]
242mod test {
243 #![allow(clippy::bool_assert_comparison)]
245 #![allow(clippy::clone_on_copy)]
246 #![allow(clippy::dbg_macro)]
247 #![allow(clippy::mixed_attributes_style)]
248 #![allow(clippy::print_stderr)]
249 #![allow(clippy::print_stdout)]
250 #![allow(clippy::single_char_pattern)]
251 #![allow(clippy::unwrap_used)]
252 #![allow(clippy::unchecked_time_subtraction)]
253 #![allow(clippy::useless_vec)]
254 #![allow(clippy::needless_pass_by_value)]
255 #![allow(clippy::string_slice)] use super::*;
258 use hex_literal::hex;
259 use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
260 use tor_bytes::{Reader, Writer};
261
262 #[test]
263 fn test_parse_enc() {
264 fn t(b: &[u8], val: &LinkSpec) {
265 let mut r = Reader::from_slice_for_test(b);
266 let got: LinkSpec = r.extract().unwrap();
267 assert_eq!(r.remaining(), 0);
268 assert_eq!(&got, val);
269 let mut v = Vec::new();
270 v.write(val).expect("Encoding failure");
271 assert_eq!(&v[..], b);
272 }
273
274 t(
275 &hex!("00 06 01020304 0050"),
276 &LinkSpec::OrPort(IpAddr::V4(Ipv4Addr::new(1, 2, 3, 4)), 80),
277 );
278 t(
279 &hex!("01 12 0001 0002 0003 0004 0005 0006 0007 0008 01bb"),
280 &LinkSpec::OrPort(IpAddr::V6(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), 443),
281 );
282 t(
283 &[
284 2, 20, 104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33, 33, 33, 33, 33,
285 33, 33, 33, 33,
286 ],
287 &LinkSpec::RsaId(RsaIdentity::from_bytes(b"hello world!!!!!!!!!").unwrap()),
288 );
289 let key = ed25519::PublicKey::from_bytes(&hex!(
290 "B440EEDB32D5C89EF21D6B16BE85A658774CE5992355737411678EE1041BDFBA"
291 ))
292 .unwrap()
293 .into();
294 t(
295 &hex!("03 20 B440EEDB32D5C89EF21D6B16BE85A658774CE5992355737411678EE1041BDFBA"),
296 &LinkSpec::Ed25519Id(key),
297 );
298
299 t(
300 &[77, 7, 115, 116, 114, 97, 110, 103, 101],
301 &LinkSpec::Unrecognized(77.into(), (&b"strange"[..]).into()),
302 );
303 }
304
305 #[test]
306 fn test_parse_bad() {
307 use tor_bytes::Error;
308
309 fn t(b: &[u8]) -> Error {
310 let mut r = Reader::from_slice_for_test(b);
311 let got: Result<LinkSpec> = r.extract();
312 got.err().unwrap()
313 }
314
315 assert_eq!(t(&hex!("00 03")), Error::new_incomplete_for_test(3));
316 assert_eq!(
317 t(&hex!("00 06 01020304")),
318 Error::new_incomplete_for_test(2)
319 );
320 assert_eq!(t(&hex!("99 07 010203")), Error::new_incomplete_for_test(4));
321 }
322
323 #[test]
324 fn test_unparsed() {
325 fn t(b: &[u8], val: &EncodedLinkSpec) {
326 let mut r = Reader::from_slice_for_test(b);
327 let got: EncodedLinkSpec = r.extract().unwrap();
328 assert_eq!(r.remaining(), 0);
329 assert_eq!(&got, val);
330 let mut v = Vec::new();
331 v.write(val).expect("Encoding failure");
332 assert_eq!(&v[..], b);
333 }
334
335 t(
337 &hex!("00 00"),
338 &EncodedLinkSpec {
339 lstype: 0.into(),
340 body: vec![],
341 },
342 );
343 t(
344 &hex!("00 03 010203"),
345 &EncodedLinkSpec {
346 lstype: 0.into(),
347 body: vec![1, 2, 3],
348 },
349 );
350
351 t(
352 &hex!("99 10 000102030405060708090a0b0c0d0e0f"),
353 &EncodedLinkSpec {
354 lstype: 0x99.into(),
355 body: (0..=15).collect(),
356 },
357 );
358 }
359
360 #[test]
361 fn test_unparsed_bad() {
362 use tor_bytes::Error;
363 fn t(b: &[u8]) -> Error {
364 let mut r = Reader::from_slice_for_test(b);
365 let got: Result<EncodedLinkSpec> = r.extract();
366 got.err().unwrap()
367 }
368
369 assert_eq!(t(&hex!("00")), Error::new_incomplete_for_test(1));
370 assert_eq!(t(&hex!("00 04 010203")), Error::new_incomplete_for_test(1));
371 assert_eq!(
372 t(&hex!("00 05 01020304")),
373 Error::new_incomplete_for_test(1)
374 );
375 }
376}