kadcast/
peer.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4//
5// Copyright (c) DUSK NETWORK. All rights reserved.
6
7use 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}