zebra_network/protocol/external/addr/
v2.rs

1//! Zcash `addrv2` message node address serialization.
2//!
3//! Zebra parses received IPv4 and IPv6 addresses in the [`AddrV2`] format.
4//! But it ignores all other address types.
5//!
6//! Zebra never sends `addrv2` messages, because peers still accept `addr` (v1) messages.
7
8use std::{
9    io::Read,
10    net::{IpAddr, SocketAddr},
11};
12
13use byteorder::{BigEndian, ReadBytesExt};
14use thiserror::Error;
15
16use zebra_chain::serialization::{
17    zcash_deserialize_bytes_external_count, CompactSize64, CompactSizeMessage, DateTime32,
18    SerializationError, TrustedPreallocate, ZcashDeserialize, ZcashDeserializeInto,
19};
20
21use crate::{
22    meta_addr::MetaAddr,
23    protocol::external::{types::PeerServices, MAX_PROTOCOL_MESSAGE_LEN},
24    PeerSocketAddr,
25};
26
27use super::canonical_peer_addr;
28
29#[cfg(any(test, feature = "proptest-impl"))]
30use proptest_derive::Arbitrary;
31
32#[cfg(test)]
33use byteorder::WriteBytesExt;
34#[cfg(test)]
35use std::io::Write;
36#[cfg(test)]
37use zebra_chain::serialization::{zcash_serialize_bytes, ZcashSerialize};
38
39/// The maximum permitted size of the `addr` field in `addrv2` messages.
40///
41/// > Field addr has a variable length, with a maximum of 512 bytes (4096 bits).
42/// > Clients MUST reject messages with a longer addr field, irrespective of the network ID.
43///
44/// <https://zips.z.cash/zip-0155#specification>
45pub const MAX_ADDR_V2_ADDR_SIZE: usize = 512;
46
47/// The network ID of [`Ipv4Addr`]s in `addrv2` messages.
48///
49/// > 0x01  IPV4  4   IPv4 address (globally routed internet)
50///
51/// <https://zips.z.cash/zip-0155#specification>
52///
53/// [`Ipv4Addr`]: std::net::Ipv4Addr
54pub const ADDR_V2_IPV4_NETWORK_ID: u8 = 0x01;
55
56/// The size of [`Ipv4Addr`]s in `addrv2` messages.
57///
58/// <https://zips.z.cash/zip-0155#specification>
59///
60/// [`Ipv4Addr`]: std::net::Ipv4Addr
61pub const ADDR_V2_IPV4_ADDR_SIZE: usize = 4;
62
63/// The network ID of [`Ipv6Addr`]s in `addrv2` messages.
64///
65/// > 0x02  IPV6  16  IPv6 address (globally routed internet)
66///
67/// <https://zips.z.cash/zip-0155#specification>
68///
69/// [`Ipv6Addr`]: std::net::Ipv6Addr
70pub const ADDR_V2_IPV6_NETWORK_ID: u8 = 0x02;
71
72/// The size of [`Ipv6Addr`]s in `addrv2` messages.
73///
74/// <https://zips.z.cash/zip-0155#specification>
75///
76/// [`Ipv6Addr`]: std::net::Ipv6Addr
77pub const ADDR_V2_IPV6_ADDR_SIZE: usize = 16;
78
79/// The second format used for Bitcoin node addresses.
80/// Contains a node address, its advertised services, and last-seen time.
81/// This struct is serialized and deserialized into `addrv2` messages.
82///
83/// [ZIP 155](https://zips.z.cash/zip-0155#specification)
84#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
85#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
86pub(in super::super) enum AddrV2 {
87    /// An IPv4 or IPv6 node address, in `addrv2` format.
88    IpAddr {
89        /// The unverified "last seen time" gossiped by the remote peer that sent us
90        /// this address.
91        ///
92        /// See the [`MetaAddr::last_seen`] method for details.
93        untrusted_last_seen: DateTime32,
94
95        /// The unverified services for the peer at `ip_addr`:`port`.
96        ///
97        /// These services were advertised by the peer at that address,
98        /// then gossiped via another peer.
99        ///
100        /// ## Security
101        ///
102        /// `untrusted_services` on gossiped peers may be invalid due to outdated
103        /// records, older peer versions, or buggy or malicious peers.
104        untrusted_services: PeerServices,
105
106        /// The peer's canonical IP address and port.
107        ///
108        /// Unlike [`AddrV1`], this can be an IPv4 or IPv6 address.
109        ///
110        /// [`AddrV1`]: super::v1::AddrV1
111        addr: PeerSocketAddr,
112    },
113
114    /// A node address with an unsupported `networkID`, in `addrv2` format.
115    //
116    // TODO: when we add more address types, make sure their addresses aren't logged,
117    //       in a similar way to `PeerSocketAddr`
118    Unsupported,
119}
120
121// Just serialize in the tests for now.
122//
123// We can't guarantee that peers support addrv2 until it activates,
124// and outdated peers are excluded from the network by a network upgrade.
125// (Likely NU5 on mainnet, and NU6 on testnet.)
126// https://zips.z.cash/zip-0155#deployment
127//
128// And Zebra doesn't use different codecs for different peer versions.
129#[cfg(test)]
130impl From<MetaAddr> for AddrV2 {
131    fn from(meta_addr: MetaAddr) -> Self {
132        let untrusted_services = meta_addr.services.expect(
133            "unexpected MetaAddr with missing peer services: \
134             MetaAddrs should be sanitized before serialization",
135        );
136        let untrusted_last_seen = meta_addr.last_seen().expect(
137            "unexpected MetaAddr with missing last seen time: \
138             MetaAddrs should be sanitized before serialization",
139        );
140
141        AddrV2::IpAddr {
142            untrusted_last_seen,
143            untrusted_services,
144            addr: canonical_peer_addr(meta_addr.addr()),
145        }
146    }
147}
148
149/// The error returned when converting `AddrV2::Unsupported` fails.
150#[derive(Error, Copy, Clone, Debug, Eq, PartialEq, Hash)]
151#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
152#[error("can not parse this addrv2 variant: unimplemented or unrecognised AddrV2 network ID")]
153pub struct UnsupportedAddrV2NetworkIdError;
154
155impl TryFrom<AddrV2> for MetaAddr {
156    type Error = UnsupportedAddrV2NetworkIdError;
157
158    fn try_from(addr: AddrV2) -> Result<MetaAddr, UnsupportedAddrV2NetworkIdError> {
159        if let AddrV2::IpAddr {
160            untrusted_last_seen,
161            untrusted_services,
162            addr,
163        } = addr
164        {
165            Ok(MetaAddr::new_gossiped_meta_addr(
166                addr,
167                untrusted_services,
168                untrusted_last_seen,
169            ))
170        } else {
171            Err(UnsupportedAddrV2NetworkIdError)
172        }
173    }
174}
175
176impl AddrV2 {
177    /// Deserialize `addr_bytes` as an IPv4 or IPv6 address, using the `addrv2` format.
178    /// Returns the corresponding [`IpAddr`].
179    ///
180    /// The returned IP version is chosen based on `IP_ADDR_SIZE`,
181    /// which should be [`ADDR_V2_IPV4_ADDR_SIZE`] or [`ADDR_V2_IPV6_ADDR_SIZE`].
182    #[allow(clippy::unwrap_in_result)]
183    fn ip_addr_from_bytes<const IP_ADDR_SIZE: usize>(
184        addr_bytes: Vec<u8>,
185    ) -> Result<IpAddr, SerializationError>
186    where
187        IpAddr: From<[u8; IP_ADDR_SIZE]>,
188    {
189        // > Clients MUST reject messages that contain addresses that have
190        // > a different length than specified in this table for a specific network ID,
191        // > as these are meaningless.
192        if addr_bytes.len() != IP_ADDR_SIZE {
193            let error_msg = if IP_ADDR_SIZE == ADDR_V2_IPV4_ADDR_SIZE {
194                "IP address field length did not match expected IPv4 address size in addrv2 message"
195            } else if IP_ADDR_SIZE == ADDR_V2_IPV6_ADDR_SIZE {
196                "IP address field length did not match expected IPv6 address size in addrv2 message"
197            } else {
198                unreachable!("unexpected IP address size when converting from bytes");
199            };
200
201            return Err(SerializationError::Parse(error_msg));
202        };
203
204        // > The IPV4 and IPV6 network IDs use addresses encoded in the usual way
205        // > for binary IPv4 and IPv6 addresses in network byte order (big endian).
206        let ip: [u8; IP_ADDR_SIZE] = addr_bytes.try_into().expect("just checked length");
207
208        Ok(IpAddr::from(ip))
209    }
210}
211
212// Just serialize in the tests for now.
213//
214// See the detailed note about ZIP-155 activation above.
215#[cfg(test)]
216impl ZcashSerialize for AddrV2 {
217    fn zcash_serialize<W: Write>(&self, mut writer: W) -> Result<(), std::io::Error> {
218        if let AddrV2::IpAddr {
219            untrusted_last_seen,
220            untrusted_services,
221            addr,
222        } = self
223        {
224            // > uint32  Time that this node was last seen as connected to the network.
225            untrusted_last_seen.zcash_serialize(&mut writer)?;
226
227            // > Service bits. A CompactSize-encoded bit field that is 64 bits wide.
228            let untrusted_services: CompactSize64 = untrusted_services.bits().into();
229            untrusted_services.zcash_serialize(&mut writer)?;
230
231            match addr.ip() {
232                IpAddr::V4(ip) => {
233                    // > Network identifier. An 8-bit value that specifies which network is addressed.
234                    writer.write_u8(ADDR_V2_IPV4_NETWORK_ID)?;
235
236                    // > The IPV4 and IPV6 network IDs use addresses encoded in the usual way
237                    // > for binary IPv4 and IPv6 addresses in network byte order (big endian).
238                    let ip: [u8; ADDR_V2_IPV4_ADDR_SIZE] = ip.octets();
239                    // > CompactSize      The length in bytes of addr.
240                    // > uint8[sizeAddr]  Network address. The interpretation depends on networkID.
241                    zcash_serialize_bytes(&ip.to_vec(), &mut writer)?;
242
243                    // > uint16  Network port. If not relevant for the network this MUST be 0.
244                    writer.write_u16::<BigEndian>(addr.port())?;
245                }
246                IpAddr::V6(ip) => {
247                    writer.write_u8(ADDR_V2_IPV6_NETWORK_ID)?;
248
249                    let ip: [u8; ADDR_V2_IPV6_ADDR_SIZE] = ip.octets();
250                    zcash_serialize_bytes(&ip.to_vec(), &mut writer)?;
251
252                    writer.write_u16::<BigEndian>(addr.port())?;
253                }
254            }
255        } else {
256            unreachable!("unexpected AddrV2 variant: {:?}", self);
257        }
258
259        Ok(())
260    }
261}
262
263/// Deserialize an `addrv2` entry according to:
264/// <https://zips.z.cash/zip-0155#specification>
265///
266/// Unimplemented and unrecognised addresses are deserialized as [`AddrV2::Unsupported`].
267/// (Deserialization consumes the correct number of bytes for unsupported addresses.)
268impl ZcashDeserialize for AddrV2 {
269    fn zcash_deserialize<R: Read>(mut reader: R) -> Result<Self, SerializationError> {
270        // > uint32  Time that this node was last seen as connected to the network.
271        let untrusted_last_seen = (&mut reader).zcash_deserialize_into()?;
272
273        // > Service bits. A CompactSize-encoded bit field that is 64 bits wide.
274        let untrusted_services: CompactSize64 = (&mut reader).zcash_deserialize_into()?;
275        let untrusted_services = PeerServices::from_bits_truncate(untrusted_services.into());
276
277        // > Network identifier. An 8-bit value that specifies which network is addressed.
278        //
279        // See the list of reserved network IDs in ZIP 155.
280        let network_id = reader.read_u8()?;
281
282        // > CompactSize  The length in bytes of addr.
283        let addr_len: CompactSizeMessage = (&mut reader).zcash_deserialize_into()?;
284        let addr_len: usize = addr_len.into();
285        if addr_len > MAX_ADDR_V2_ADDR_SIZE {
286            return Err(SerializationError::Parse(
287                "addr field longer than MAX_ADDR_V2_ADDR_SIZE in addrv2 message",
288            ));
289        }
290
291        // > uint8[sizeAddr]  Network address. The interpretation depends on networkID.
292        let addr: Vec<u8> = zcash_deserialize_bytes_external_count(addr_len, &mut reader)?;
293
294        // > uint16  Network port. If not relevant for the network this MUST be 0.
295        let port = reader.read_u16::<BigEndian>()?;
296
297        let ip = if network_id == ADDR_V2_IPV4_NETWORK_ID {
298            AddrV2::ip_addr_from_bytes::<ADDR_V2_IPV4_ADDR_SIZE>(addr)?
299        } else if network_id == ADDR_V2_IPV6_NETWORK_ID {
300            AddrV2::ip_addr_from_bytes::<ADDR_V2_IPV6_ADDR_SIZE>(addr)?
301        } else {
302            // unimplemented or unrecognised network ID, just consume the bytes
303            //
304            // > Clients MUST NOT gossip addresses from unknown networks,
305            // > because they have no means to validate those addresses
306            // > and so can be tricked to gossip invalid addresses.
307
308            return Ok(AddrV2::Unsupported);
309        };
310
311        Ok(AddrV2::IpAddr {
312            untrusted_last_seen,
313            untrusted_services,
314            addr: canonical_peer_addr(SocketAddr::new(ip, port)),
315        })
316    }
317}
318
319/// A serialized `addrv2` has:
320/// * 4 byte time,
321/// * 1-9 byte services,
322/// * 1 byte networkID,
323/// * 1-9 byte sizeAddr,
324/// * 0-512 bytes addr,
325/// * 2 bytes port.
326#[allow(clippy::identity_op)]
327pub(in super::super) const ADDR_V2_MIN_SIZE: usize = 4 + 1 + 1 + 1 + 0 + 2;
328
329impl TrustedPreallocate for AddrV2 {
330    fn max_allocation() -> u64 {
331        // Since ADDR_V2_MIN_SIZE is less than 2^5, the length of the largest list takes up 5 bytes.
332        ((MAX_PROTOCOL_MESSAGE_LEN - 5) / ADDR_V2_MIN_SIZE) as u64
333    }
334}