Skip to main content

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