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_duration_subtraction)]
253 #![allow(clippy::useless_vec)]
254 #![allow(clippy::needless_pass_by_value)]
255 use super::*;
257 use hex_literal::hex;
258 use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
259 use tor_bytes::{Reader, Writer};
260
261 #[test]
262 fn test_parse_enc() {
263 fn t(b: &[u8], val: &LinkSpec) {
264 let mut r = Reader::from_slice_for_test(b);
265 let got: LinkSpec = r.extract().unwrap();
266 assert_eq!(r.remaining(), 0);
267 assert_eq!(&got, val);
268 let mut v = Vec::new();
269 v.write(val).expect("Encoding failure");
270 assert_eq!(&v[..], b);
271 }
272
273 t(
274 &hex!("00 06 01020304 0050"),
275 &LinkSpec::OrPort(IpAddr::V4(Ipv4Addr::new(1, 2, 3, 4)), 80),
276 );
277 t(
278 &hex!("01 12 0001 0002 0003 0004 0005 0006 0007 0008 01bb"),
279 &LinkSpec::OrPort(IpAddr::V6(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), 443),
280 );
281 t(
282 &[
283 2, 20, 104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33, 33, 33, 33, 33,
284 33, 33, 33, 33,
285 ],
286 &LinkSpec::RsaId(RsaIdentity::from_bytes(b"hello world!!!!!!!!!").unwrap()),
287 );
288 let key = ed25519::PublicKey::from_bytes(&hex!(
289 "B440EEDB32D5C89EF21D6B16BE85A658774CE5992355737411678EE1041BDFBA"
290 ))
291 .unwrap()
292 .into();
293 t(
294 &hex!("03 20 B440EEDB32D5C89EF21D6B16BE85A658774CE5992355737411678EE1041BDFBA"),
295 &LinkSpec::Ed25519Id(key),
296 );
297
298 t(
299 &[77, 7, 115, 116, 114, 97, 110, 103, 101],
300 &LinkSpec::Unrecognized(77.into(), (&b"strange"[..]).into()),
301 );
302 }
303
304 #[test]
305 fn test_parse_bad() {
306 use tor_bytes::Error;
307
308 fn t(b: &[u8]) -> Error {
309 let mut r = Reader::from_slice_for_test(b);
310 let got: Result<LinkSpec> = r.extract();
311 got.err().unwrap()
312 }
313
314 assert_eq!(t(&hex!("00 03")), Error::new_incomplete_for_test(3));
315 assert_eq!(
316 t(&hex!("00 06 01020304")),
317 Error::new_incomplete_for_test(2)
318 );
319 assert_eq!(t(&hex!("99 07 010203")), Error::new_incomplete_for_test(4));
320 }
321
322 #[test]
323 fn test_unparsed() {
324 fn t(b: &[u8], val: &EncodedLinkSpec) {
325 let mut r = Reader::from_slice_for_test(b);
326 let got: EncodedLinkSpec = r.extract().unwrap();
327 assert_eq!(r.remaining(), 0);
328 assert_eq!(&got, val);
329 let mut v = Vec::new();
330 v.write(val).expect("Encoding failure");
331 assert_eq!(&v[..], b);
332 }
333
334 t(
336 &hex!("00 00"),
337 &EncodedLinkSpec {
338 lstype: 0.into(),
339 body: vec![],
340 },
341 );
342 t(
343 &hex!("00 03 010203"),
344 &EncodedLinkSpec {
345 lstype: 0.into(),
346 body: vec![1, 2, 3],
347 },
348 );
349
350 t(
351 &hex!("99 10 000102030405060708090a0b0c0d0e0f"),
352 &EncodedLinkSpec {
353 lstype: 0x99.into(),
354 body: (0..=15).collect(),
355 },
356 );
357 }
358
359 #[test]
360 fn test_unparsed_bad() {
361 use tor_bytes::Error;
362 fn t(b: &[u8]) -> Error {
363 let mut r = Reader::from_slice_for_test(b);
364 let got: Result<EncodedLinkSpec> = r.extract();
365 got.err().unwrap()
366 }
367
368 assert_eq!(t(&hex!("00")), Error::new_incomplete_for_test(1));
369 assert_eq!(t(&hex!("00 04 010203")), Error::new_incomplete_for_test(1));
370 assert_eq!(
371 t(&hex!("00 05 01020304")),
372 Error::new_incomplete_for_test(1)
373 );
374 }
375}