1use std::{collections::BTreeSet, fmt, net::SocketAddr};
10
11use data_encoding::HEXLOWER;
12use n0_error::stack_error;
13use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
14
15use crate::{EndpointId, PublicKey, RelayUrl};
16
17#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
42pub struct EndpointAddr {
43 pub id: EndpointId,
45 pub addrs: BTreeSet<TransportAddr>,
47}
48
49#[derive(
51 derive_more::Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash,
52)]
53#[non_exhaustive]
54pub enum TransportAddr {
55 #[debug("Relay({_0})")]
57 Relay(RelayUrl),
58 Ip(SocketAddr),
60 Custom(CustomAddr),
62}
63
64impl TransportAddr {
65 pub fn is_relay(&self) -> bool {
67 matches!(self, Self::Relay(_))
68 }
69
70 pub fn is_ip(&self) -> bool {
72 matches!(self, Self::Ip(_))
73 }
74
75 pub fn is_custom(&self) -> bool {
77 matches!(self, Self::Custom(_))
78 }
79}
80
81impl fmt::Display for TransportAddr {
82 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83 match self {
84 Self::Relay(url) => write!(f, "relay:{url}"),
85 Self::Ip(addr) => write!(f, "ip:{addr}"),
86 Self::Custom(addr) => write!(f, "custom:{addr}"),
87 }
88 }
89}
90
91impl EndpointAddr {
92 pub fn new(id: PublicKey) -> Self {
97 EndpointAddr {
98 id,
99 addrs: Default::default(),
100 }
101 }
102
103 pub fn from_parts(id: PublicKey, addrs: impl IntoIterator<Item = TransportAddr>) -> Self {
105 Self {
106 id,
107 addrs: addrs.into_iter().collect(),
108 }
109 }
110
111 pub fn with_relay_url(mut self, relay_url: RelayUrl) -> Self {
113 self.addrs.insert(TransportAddr::Relay(relay_url));
114 self
115 }
116
117 pub fn with_ip_addr(mut self, addr: SocketAddr) -> Self {
119 self.addrs.insert(TransportAddr::Ip(addr));
120 self
121 }
122
123 pub fn with_addrs(mut self, addrs: impl IntoIterator<Item = TransportAddr>) -> Self {
125 for addr in addrs.into_iter() {
126 self.addrs.insert(addr);
127 }
128 self
129 }
130
131 pub fn is_empty(&self) -> bool {
133 self.addrs.is_empty()
134 }
135
136 pub fn ip_addrs(&self) -> impl Iterator<Item = &SocketAddr> {
138 self.addrs.iter().filter_map(|addr| match addr {
139 TransportAddr::Ip(addr) => Some(addr),
140 _ => None,
141 })
142 }
143
144 pub fn relay_urls(&self) -> impl Iterator<Item = &RelayUrl> {
148 self.addrs.iter().filter_map(|addr| match addr {
149 TransportAddr::Relay(url) => Some(url),
150 _ => None,
151 })
152 }
153}
154
155impl From<EndpointId> for EndpointAddr {
156 fn from(endpoint_id: EndpointId) -> Self {
157 EndpointAddr::new(endpoint_id)
158 }
159}
160
161#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
186pub struct CustomAddr {
187 id: u64,
189 data: CustomAddrBytes,
191}
192
193impl fmt::Display for CustomAddr {
194 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195 write!(f, "{:x}_{}", self.id, HEXLOWER.encode(self.data.as_bytes()))
196 }
197}
198
199impl std::str::FromStr for CustomAddr {
200 type Err = CustomAddrParseError;
201
202 fn from_str(s: &str) -> Result<Self, Self::Err> {
203 let Some((id_str, data_str)) = s.split_once('_') else {
204 return Err(CustomAddrParseError::MissingSeparator);
205 };
206 let Ok(id) = u64::from_str_radix(id_str, 16) else {
207 return Err(CustomAddrParseError::InvalidId);
208 };
209 let Ok(data) = HEXLOWER.decode(data_str.as_bytes()) else {
210 return Err(CustomAddrParseError::InvalidData);
211 };
212 Ok(Self::from_parts(id, &data))
213 }
214}
215
216#[stack_error(derive)]
222#[allow(missing_docs)]
223pub enum CustomAddrParseError {
224 #[error("missing '_' separator")]
226 MissingSeparator,
227 #[error("invalid id")]
229 InvalidId,
230 #[error("invalid data")]
232 InvalidData,
233}
234
235#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
238enum CustomAddrBytes {
239 Inline { size: u8, data: [u8; 30] },
240 Heap(Box<[u8]>),
241}
242
243impl Serialize for CustomAddrBytes {
244 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
245 serializer.serialize_bytes(self.as_bytes())
246 }
247}
248
249impl<'de> Deserialize<'de> for CustomAddrBytes {
250 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
251 struct BytesVisitor;
252
253 impl<'de> de::Visitor<'de> for BytesVisitor {
254 type Value = CustomAddrBytes;
255
256 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
257 f.write_str("custom transport address bytes")
258 }
259
260 fn visit_bytes<E: de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
261 Ok(CustomAddrBytes::copy_from_slice(v))
262 }
263
264 fn visit_byte_buf<E: de::Error>(self, v: Vec<u8>) -> Result<Self::Value, E> {
265 Ok(CustomAddrBytes::copy_from_slice(&v))
266 }
267
268 fn visit_seq<A: de::SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
271 let mut data = Vec::new();
273 while let Some(byte) = seq.next_element::<u8>()? {
274 data.push(byte);
275 }
276 Ok(CustomAddrBytes::copy_from_slice(&data))
277 }
278 }
279
280 deserializer.deserialize_bytes(BytesVisitor)
281 }
282}
283
284impl fmt::Debug for CustomAddrBytes {
285 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
286 if !f.alternate() {
287 write!(f, "[{}]", HEXLOWER.encode(self.as_bytes()))
288 } else {
289 let bytes = self.as_bytes();
290 match self {
291 Self::Inline { .. } => write!(f, "Inline[{}]", HEXLOWER.encode(bytes)),
292 Self::Heap(_) => write!(f, "Heap[{}]", HEXLOWER.encode(bytes)),
293 }
294 }
295 }
296}
297
298impl From<(u64, &[u8])> for CustomAddr {
299 fn from((id, data): (u64, &[u8])) -> Self {
300 Self::from_parts(id, data)
301 }
302}
303
304impl CustomAddrBytes {
305 fn len(&self) -> usize {
306 match self {
307 Self::Inline { size, .. } => *size as usize,
308 Self::Heap(data) => data.len(),
309 }
310 }
311
312 fn as_bytes(&self) -> &[u8] {
313 match self {
314 Self::Inline { size, data } => &data[..*size as usize],
315 Self::Heap(data) => data,
316 }
317 }
318
319 fn copy_from_slice(data: &[u8]) -> Self {
320 if data.len() <= 30 {
321 let mut inline = [0u8; 30];
322 inline[..data.len()].copy_from_slice(data);
323 Self::Inline {
324 size: data.len() as u8,
325 data: inline,
326 }
327 } else {
328 Self::Heap(data.to_vec().into_boxed_slice())
329 }
330 }
331}
332
333impl CustomAddr {
334 pub fn from_parts(id: u64, data: &[u8]) -> Self {
336 Self {
337 id,
338 data: CustomAddrBytes::copy_from_slice(data),
339 }
340 }
341
342 pub fn id(&self) -> u64 {
350 self.id
351 }
352
353 pub fn data(&self) -> &[u8] {
360 self.data.as_bytes()
361 }
362
363 pub fn to_vec(&self) -> Vec<u8> {
367 let mut out = vec![0u8; 8 + self.data.len()];
368 out[..8].copy_from_slice(&self.id().to_le_bytes());
369 out[8..].copy_from_slice(self.data());
370 out
371 }
372
373 pub fn from_bytes(data: &[u8]) -> Result<Self, &'static str> {
377 if data.len() < 8 {
378 return Err("data too short");
379 }
380 let id = u64::from_le_bytes(data[..8].try_into().expect("data length checked above"));
381 let data = &data[8..];
382 Ok(Self::from_parts(id, data))
383 }
384}
385
386#[cfg(test)]
387mod tests {
388 use super::*;
389
390 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
391 #[non_exhaustive]
392 enum NewAddrType {
393 Relay(RelayUrl),
395 Ip(SocketAddr),
397 Cool(u16),
399 }
400
401 #[test]
402 fn test_roundtrip_new_addr_type() {
403 let old = vec![
404 TransportAddr::Ip("127.0.0.1:9".parse().unwrap()),
405 TransportAddr::Relay("https://example.com".parse().unwrap()),
406 ];
407 let old_ser = postcard::to_stdvec(&old).unwrap();
408 let old_back: Vec<TransportAddr> = postcard::from_bytes(&old_ser).unwrap();
409 assert_eq!(old, old_back);
410
411 let new = vec![
412 NewAddrType::Ip("127.0.0.1:9".parse().unwrap()),
413 NewAddrType::Relay("https://example.com".parse().unwrap()),
414 NewAddrType::Cool(4),
415 ];
416 let new_ser = postcard::to_stdvec(&new).unwrap();
417 let new_back: Vec<NewAddrType> = postcard::from_bytes(&new_ser).unwrap();
418
419 assert_eq!(new, new_back);
420
421 let old_new_back: Vec<NewAddrType> = postcard::from_bytes(&old_ser).unwrap();
423
424 assert_eq!(
425 old_new_back,
426 vec![
427 NewAddrType::Ip("127.0.0.1:9".parse().unwrap()),
428 NewAddrType::Relay("https://example.com".parse().unwrap()),
429 ]
430 );
431 }
432
433 #[test]
434 fn test_custom_addr_roundtrip() {
435 let addr = CustomAddr::from_parts(1, &[0xa1, 0xb2, 0xc3, 0xd4, 0xe5, 0xf6]);
437 let s = addr.to_string();
438 assert_eq!(s, "1_a1b2c3d4e5f6");
439 let parsed: CustomAddr = s.parse().unwrap();
440 assert_eq!(addr, parsed);
441
442 let addr = CustomAddr::from_parts(42, &[0xab; 32]);
444 let s = addr.to_string();
445 assert_eq!(
446 s,
447 "2a_abababababababababababababababababababababababababababababababab"
448 );
449 let parsed: CustomAddr = s.parse().unwrap();
450 assert_eq!(addr, parsed);
451
452 let addr = CustomAddr::from_parts(0, &[]);
454 let s = addr.to_string();
455 assert_eq!(s, "0_");
456 let parsed: CustomAddr = s.parse().unwrap();
457 assert_eq!(addr, parsed);
458
459 let addr = CustomAddr::from_parts(0xdeadbeef, &[0x01, 0x02]);
461 let s = addr.to_string();
462 assert_eq!(s, "deadbeef_0102");
463 let parsed: CustomAddr = s.parse().unwrap();
464 assert_eq!(addr, parsed);
465 }
466
467 #[test]
469 fn test_custom_addr_serde_roundtrip() {
470 for len in [0usize, 1, 29, 30, 31, 32, 255] {
471 let data: Vec<u8> = (0..len).map(|i| i as u8).collect();
472 let addr = CustomAddr::from_parts(0x544f52, &data);
473 let ser = postcard::to_stdvec(&addr).unwrap();
474 let back: CustomAddr = postcard::from_bytes(&ser).unwrap();
475 assert_eq!(addr, back);
476 assert_eq!(back.data(), &data[..]);
477
478 let expected = postcard::to_stdvec(&(0x544f52u64, &data)).unwrap();
480 assert_eq!(ser, expected);
481
482 let json = serde_json::to_string(&addr).unwrap();
484 let back: CustomAddr = serde_json::from_str(&json).unwrap();
485 assert_eq!(addr, back);
486 }
487 }
488
489 #[test]
491 fn test_custom_addr_deserialize_is_canonical() {
492 for len in [5usize, 30, 31] {
493 let data = vec![9u8; len];
494 let addr = CustomAddr::from_parts(0x544f52, &data);
495 let ser = postcard::to_stdvec(&addr).unwrap();
496 let back: CustomAddr = postcard::from_bytes(&ser).unwrap();
497
498 assert_eq!(back.data(), addr.data());
499 assert_eq!(back, addr);
500 let set: BTreeSet<CustomAddr> = [back, addr].into_iter().collect();
501 assert_eq!(set.len(), 1);
502 }
503 }
504
505 #[test]
508 fn test_custom_addr_deserialize_oversized_inline() {
509 let mut crafted = postcard::to_stdvec(&(0x544f52u64, 0u32, 30u8, [9u8; 30])).unwrap();
511 let idx = crafted.len() - 31;
512 assert_eq!(crafted[idx], 30);
513 crafted[idx] = 255;
514
515 if let Ok(addr) = postcard::from_bytes::<CustomAddr>(&crafted) {
516 assert_eq!(addr.data().len(), addr.to_vec().len() - 8);
517 let _ = format!("{addr:?}");
518 let _ = format!("{addr:#?}");
519 let _ = addr.to_string();
520 }
521 }
522
523 #[test]
525 fn test_endpoint_addr_deserialize_arbitrary_bytes() {
526 let id = PublicKey::from_bytes(&[0; 32]).unwrap();
527 let addr = EndpointAddr {
528 id,
529 addrs: [TransportAddr::Custom(CustomAddr::from_parts(
530 0x544f52, &[9u8; 30],
531 ))]
532 .into_iter()
533 .collect(),
534 };
535 let ser = postcard::to_stdvec(&addr).unwrap();
536
537 for idx in 0..ser.len() {
539 for bit in 0..8 {
540 let mut crafted = ser.clone();
541 crafted[idx] ^= 1 << bit;
542 if let Ok(evil) = postcard::from_bytes::<EndpointAddr>(&crafted) {
543 let _ = format!("{evil:?}");
544 for addr in &evil.addrs {
545 if let TransportAddr::Custom(custom) = addr {
546 let _ = custom.data();
547 let _ = custom.to_vec();
548 let _ = custom.to_string();
549 }
550 }
551 }
552 }
553 }
554 }
555
556 #[test]
557 fn test_custom_addr_parse_errors() {
558 assert!("abc123".parse::<CustomAddr>().is_err());
560
561 assert!("xyz_0102".parse::<CustomAddr>().is_err());
563
564 assert!("1_ghij".parse::<CustomAddr>().is_err());
566
567 assert!("1_abc".parse::<CustomAddr>().is_err());
569 }
570}