1use std::convert::TryInto;
8use std::net::{AddrParseError, IpAddr, SocketAddr};
9
10use blake2::{Blake2s256, Digest};
11
12use crate::kbucket::{BinaryID, BinaryKey};
13pub type PeerNode = Node<PeerInfo>;
14use crate::encoding::message::Header;
15use crate::encoding::payload::{IpInfo, PeerEncodedInfo};
16use crate::kbucket::Node;
17use crate::K_ID_LEN_BYTES;
18#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
19pub struct PeerInfo {
20 address: SocketAddr,
21}
22
23impl PeerInfo {
24 pub fn address(&self) -> &SocketAddr {
25 &self.address
26 }
27}
28
29impl PeerNode {
30 pub fn generate(
31 address: impl AsRef<str>,
32 network_id: u8,
33 ) -> Result<Self, AddrParseError> {
34 let address: SocketAddr = address.as_ref().parse()?;
35 let info = PeerInfo { address };
36 let binary =
37 PeerNode::compute_id(&info.address.ip(), info.address.port());
38 let id = BinaryID::generate(binary);
39 Ok(Node::new(id, info, network_id))
40 }
41
42 pub fn from_socket(
43 address: SocketAddr,
44 id: BinaryID,
45 network_id: u8,
46 ) -> Self {
47 let info = PeerInfo { address };
48 Node::new(id, info, network_id)
49 }
50
51 pub(crate) fn verify_header(header: &Header, ip: &IpAddr) -> bool {
52 header.binary_id().as_binary()
53 == &PeerNode::compute_id(ip, header.sender_port)
54 }
55
56 pub(crate) fn compute_id(ip: &IpAddr, port: u16) -> BinaryKey {
57 let mut hasher = Blake2s256::new();
58 hasher.update(port.to_le_bytes());
59 match ip {
60 IpAddr::V4(ip) => hasher.update(ip.octets()),
61 IpAddr::V6(ip) => hasher.update(ip.octets()),
62 };
63 let hash = hasher.finalize();
64 hash[..K_ID_LEN_BYTES]
65 .try_into()
66 .expect("compute_id length = K_ID_LEN_BYTES")
67 }
68
69 pub(crate) fn to_header(&self) -> Header {
70 Header {
71 binary_id: *self.id(),
72 sender_port: self.value().address.port(),
73 reserved: [0; 2],
74 network_id: self.network_id,
75 }
76 }
77
78 pub(crate) fn as_peer_info(&self) -> PeerEncodedInfo {
79 PeerEncodedInfo {
80 id: *self.id().as_binary(),
81 ip: match self.value().address.ip() {
82 IpAddr::V4(ip) => IpInfo::IPv4(ip.octets()),
83 IpAddr::V6(ip) => IpInfo::IPv6(ip.octets()),
84 },
85 port: self.value().address.port(),
86 }
87 }
88}
89
90#[cfg(test)]
91mod tests {
92
93 use crate::peer::PeerNode;
94 use crate::tests::Result;
95 #[test]
96 fn test_verify_header() -> Result<()> {
97 let wrong_header = PeerNode::generate("10.0.0.1:333", 0)?.to_header();
98 let wrong_header_sameport =
99 PeerNode::generate("10.0.0.1:666", 0)?.to_header();
100 vec![
101 PeerNode::generate("192.168.1.1:666", 0)?,
102 PeerNode::generate(
103 "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:666",
104 0,
105 )?,
106 ]
107 .iter()
108 .for_each(|n| {
109 let ip = &n.value().address.ip();
110 PeerNode::verify_header(&n.to_header(), ip);
111 assert!(PeerNode::verify_header(&n.to_header(), ip));
112 assert!(!PeerNode::verify_header(&wrong_header, ip));
113 assert!(!PeerNode::verify_header(&wrong_header_sameport, ip));
114 });
115 Ok(())
116 }
117}