diff --git a/Cargo.toml b/Cargo.toml index 655e4208..9f923561 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ tokio-threadpool = "0.1" flatbuffers = { version = "0.6.0", optional = true } flatbuffers-verifier = { version = "0.2.0", optional = true } multiaddr = { package = "parity-multiaddr", version = "0.4.0" } -molecule = { version = "0.2.5", optional = true } +molecule = { version = "0.3.1", optional = true } # upnp igd = "0.9" diff --git a/Makefile b/Makefile index 0b1521bb..1b9c193b 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ FLATC := flatc CFBC := cfbc MOLC := moleculec -MOLC_VERSION := 0.2.5 +MOLC_VERSION := 0.3.1 FBS_FILES := \ src/protocol_select/protocol_select.fbs \ diff --git a/protocols/discovery/Cargo.toml b/protocols/discovery/Cargo.toml index 2c6ee497..710953e9 100644 --- a/protocols/discovery/Cargo.toml +++ b/protocols/discovery/Cargo.toml @@ -24,7 +24,7 @@ log = "0.4" rand = "0.6.1" flatbuffers = { version = "0.6.0", optional = true } flatbuffers-verifier = { version = "0.2.0", optional = true } -molecule = { version = "0.2.5", optional = true } +molecule = { version = "0.3.1", optional = true } [dev-dependencies] env_logger = "0.6" diff --git a/protocols/discovery/README.md b/protocols/discovery/README.md index e40d2f3e..9050d32f 100644 --- a/protocols/discovery/README.md +++ b/protocols/discovery/README.md @@ -1,2 +1,34 @@ -# discovery +## Discovery Node discovery (mainly same with bitcoin, for blockchain project) + +### Discovery behavior + +On the current NAT forwarding network environment, whether it is self-discovery or the discovery behavior +of the other party is not completely accurate, it is certain that the address received by +the user is not 100% available. + +There are two actions in this protocol: + +- When the connection is established, the requester(Client) will actively request the responder(Server) to +request the list of available addresses that the responder has stored. **WARNING**: This behavior is only +allowed once, otherwise it will be disconnected by the other peers. + +- Each node periodically broadcasts hot address to its neighbor peers. The hot address refers to the listen +address of the neighbor peers that the node keeps communicating continuously, which means active connection. + +### Message type + +``` +/// request for address list +GetNodes { + version: Uint32, + count: Uint32, + listen_port: PortOpt, +} + +/// response address list +Nodes { + announce: Bool, + items: NodeVec, +} +``` diff --git a/protocols/discovery/src/protocol.rs b/protocols/discovery/src/protocol.rs index 17f9835b..b95ad6b1 100644 --- a/protocols/discovery/src/protocol.rs +++ b/protocols/discovery/src/protocol.rs @@ -239,7 +239,7 @@ impl DiscoveryMessage { #[cfg(feature = "molc")] #[allow(clippy::cast_ptr_alignment)] pub fn decode(data: &[u8]) -> Option { - let reader = protocol_mol::DiscoveryMessageReader::from_slice(data).ok()?; + let reader = protocol_mol::DiscoveryMessageReader::from_compatible_slice(data).ok()?; match reader.payload().to_enum() { protocol_mol::DiscoveryPayloadUnionReader::GetNodes(reader) => { let le = reader.version().raw_data().as_ptr() as *const u32; diff --git a/protocols/discovery/src/protocol_mol.rs b/protocols/discovery/src/protocol_mol.rs index 171b0a40..53b28b69 100644 --- a/protocols/discovery/src/protocol_mol.rs +++ b/protocols/discovery/src/protocol_mol.rs @@ -1,4 +1,4 @@ -// Generated by Molecule 0.2.5 +// Generated by Molecule 0.3.1 use molecule::faster_hex::hex_string; use molecule::prelude::{Entity as _, Reader as _}; @@ -62,6 +62,9 @@ impl molecule::prelude::Entity for Bytes { fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { BytesReader::from_slice(slice).map(|reader| reader.to_entity()) } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + BytesReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } fn new_builder() -> Self::Builder { ::std::default::Default::default() } @@ -113,7 +116,7 @@ impl<'r> molecule::prelude::Reader<'r> for BytesReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8]) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::error::VerificationError; let len = slice.len(); if len < 4 { @@ -280,6 +283,9 @@ impl molecule::prelude::Entity for BytesVec { fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { BytesVecReader::from_slice(slice).map(|reader| reader.to_entity()) } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + BytesVecReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } fn new_builder() -> Self::Builder { ::std::default::Default::default() } @@ -346,7 +352,7 @@ impl<'r> molecule::prelude::Reader<'r> for BytesVecReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8]) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::error::VerificationError; let len = slice.len(); if len < 4 { @@ -393,7 +399,7 @@ impl<'r> molecule::prelude::Reader<'r> for BytesVecReader<'r> { for i in 0..=(offsets.len() - 2) { let start = offsets[i]; let end = offsets[i + 1]; - BytesReader::verify(&slice[start..end])?; + BytesReader::verify(&slice[start..end], _compatible)?; } Ok(()) } @@ -600,6 +606,9 @@ impl molecule::prelude::Entity for NodeVec { fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { NodeVecReader::from_slice(slice).map(|reader| reader.to_entity()) } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + NodeVecReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } fn new_builder() -> Self::Builder { ::std::default::Default::default() } @@ -666,7 +675,7 @@ impl<'r> molecule::prelude::Reader<'r> for NodeVecReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8]) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::error::VerificationError; let len = slice.len(); if len < 4 { @@ -713,7 +722,7 @@ impl<'r> molecule::prelude::Reader<'r> for NodeVecReader<'r> { for i in 0..=(offsets.len() - 2) { let start = offsets[i]; let end = offsets[i + 1]; - NodeReader::verify(&slice[start..end])?; + NodeReader::verify(&slice[start..end], _compatible)?; } Ok(()) } @@ -923,6 +932,9 @@ impl molecule::prelude::Entity for Uint32 { fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { Uint32Reader::from_slice(slice).map(|reader| reader.to_entity()) } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + Uint32Reader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } fn new_builder() -> Self::Builder { ::std::default::Default::default() } @@ -971,7 +983,7 @@ impl<'r> molecule::prelude::Reader<'r> for Uint32Reader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8]) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::error::VerificationError; if slice.len() != 4 { let err = VerificationError::TotalSizeNotMatch(Self::NAME.to_owned(), 4, slice.len()); @@ -1108,6 +1120,9 @@ impl molecule::prelude::Entity for Uint16 { fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { Uint16Reader::from_slice(slice).map(|reader| reader.to_entity()) } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + Uint16Reader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } fn new_builder() -> Self::Builder { ::std::default::Default::default() } @@ -1150,7 +1165,7 @@ impl<'r> molecule::prelude::Reader<'r> for Uint16Reader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8]) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::error::VerificationError; if slice.len() != 2 { let err = VerificationError::TotalSizeNotMatch(Self::NAME.to_owned(), 2, slice.len()); @@ -1273,6 +1288,9 @@ impl molecule::prelude::Entity for Bool { fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { BoolReader::from_slice(slice).map(|reader| reader.to_entity()) } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + BoolReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } fn new_builder() -> Self::Builder { ::std::default::Default::default() } @@ -1312,7 +1330,7 @@ impl<'r> molecule::prelude::Reader<'r> for BoolReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8]) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::error::VerificationError; if slice.len() != 1 { let err = VerificationError::TotalSizeNotMatch(Self::NAME.to_owned(), 1, slice.len()); @@ -1421,6 +1439,9 @@ impl molecule::prelude::Entity for PortOpt { fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { PortOptReader::from_slice(slice).map(|reader| reader.to_entity()) } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + PortOptReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } fn new_builder() -> Self::Builder { ::std::default::Default::default() } @@ -1464,9 +1485,9 @@ impl<'r> molecule::prelude::Reader<'r> for PortOptReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8]) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { if !slice.is_empty() { - Uint16Reader::verify(&slice[..])?; + Uint16Reader::verify(&slice[..], compatible)?; } Ok(()) } @@ -1713,6 +1734,9 @@ impl molecule::prelude::Entity for DiscoveryPayload { fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { DiscoveryPayloadReader::from_slice(slice).map(|reader| reader.to_entity()) } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + DiscoveryPayloadReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } fn new_builder() -> Self::Builder { ::std::default::Default::default() } @@ -1756,7 +1780,7 @@ impl<'r> molecule::prelude::Reader<'r> for DiscoveryPayloadReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8]) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::error::VerificationError; if slice.len() < molecule::ITEM_ID_SIZE { let err = VerificationError::HeaderIsBroken( @@ -1768,8 +1792,8 @@ impl<'r> molecule::prelude::Reader<'r> for DiscoveryPayloadReader<'r> { } let item_id = molecule::extract_item_id(slice); match item_id { - 1 => GetNodesReader::verify(&slice[molecule::ITEM_ID_SIZE..]), - 2 => NodesReader::verify(&slice[molecule::ITEM_ID_SIZE..]), + 1 => GetNodesReader::verify(&slice[molecule::ITEM_ID_SIZE..], _compatible), + 2 => NodesReader::verify(&slice[molecule::ITEM_ID_SIZE..], _compatible), _ => { let err = VerificationError::UnknownItem(Self::NAME.to_owned(), 2, item_id); Err(err) @@ -1890,6 +1914,9 @@ impl molecule::prelude::Entity for DiscoveryMessage { fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { DiscoveryMessageReader::from_slice(slice).map(|reader| reader.to_entity()) } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + DiscoveryMessageReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } fn new_builder() -> Self::Builder { ::std::default::Default::default() } @@ -1910,6 +1937,10 @@ impl DiscoveryMessage { let count = (first - 4) / 4; (bytes_len, count, &ptr[1..]) } + pub fn has_extra_fields(&self) -> bool { + let (_, real_fields_count, _) = Self::field_offsets(self); + Self::FIELD_COUNT == real_fields_count + } pub fn payload(&self) -> DiscoveryPayload { let (_, count, offsets) = Self::field_offsets(self); let start = u32::from_le(offsets[0]) as usize; @@ -1932,7 +1963,7 @@ impl<'r> molecule::prelude::Reader<'r> for DiscoveryMessageReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8]) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::error::VerificationError; let len = slice.len(); if len < 4 { @@ -1954,21 +1985,52 @@ impl<'r> molecule::prelude::Reader<'r> for DiscoveryMessageReader<'r> { VerificationError::HeaderIsBroken(Self::NAME.to_owned(), expected, total_size); Err(err)?; } - let mut offsets: Vec = ptr[1..=1] + let offset_first = u32::from_le(ptr[1]) as usize; + if offset_first % 4 != 0 { + let err = VerificationError::FirstOffsetIsBroken(Self::NAME.to_owned(), offset_first); + Err(err)?; + } + if offset_first < expected { + let err = VerificationError::FirstOffsetIsShort( + Self::NAME.to_owned(), + expected, + offset_first, + ); + Err(err)?; + } + let real_field_count = if compatible { + let real_field_count = offset_first / 4 - 1; + let real_expected = 4 + 4 * real_field_count; + if total_size < real_expected { + let err = VerificationError::DataIsShort( + Self::NAME.to_owned(), + real_expected, + total_size, + ); + Err(err)?; + } + real_field_count + } else { + if offset_first > expected { + let err = VerificationError::FirstOffsetIsOverflow( + Self::NAME.to_owned(), + expected, + offset_first, + ); + Err(err)?; + } + 1 + }; + let mut offsets: Vec = ptr[1..=real_field_count] .iter() .map(|x| u32::from_le(*x) as usize) .collect(); - if offsets[0] != expected { - let err = - VerificationError::FirstOffsetIsShort(Self::NAME.to_owned(), expected, offsets[0]); - Err(err)?; - } offsets.push(total_size); if offsets.windows(2).any(|i| i[0] > i[1]) { let err = VerificationError::OffsetsNotMatch(Self::NAME.to_owned()); Err(err)?; } - DiscoveryPayloadReader::verify(&slice[offsets[0]..offsets[1]])?; + DiscoveryPayloadReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; Ok(()) } } @@ -1982,6 +2044,10 @@ impl<'r> DiscoveryMessageReader<'r> { let count = (first - 4) / 4; (bytes_len, count, &ptr[1..]) } + pub fn has_extra_fields(&self) -> bool { + let (_, real_fields_count, _) = Self::field_offsets(self); + Self::FIELD_COUNT == real_fields_count + } pub fn payload(&self) -> DiscoveryPayloadReader<'r> { let (_, count, offsets) = Self::field_offsets(self); let start = u32::from_le(offsets[0]) as usize; @@ -2103,6 +2169,9 @@ impl molecule::prelude::Entity for GetNodes { fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { GetNodesReader::from_slice(slice).map(|reader| reader.to_entity()) } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + GetNodesReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } fn new_builder() -> Self::Builder { ::std::default::Default::default() } @@ -2126,6 +2195,10 @@ impl GetNodes { let count = (first - 4) / 4; (bytes_len, count, &ptr[1..]) } + pub fn has_extra_fields(&self) -> bool { + let (_, real_fields_count, _) = Self::field_offsets(self); + Self::FIELD_COUNT == real_fields_count + } pub fn version(&self) -> Uint32 { let (_, _, offsets) = Self::field_offsets(self); let start = u32::from_le(offsets[0]) as usize; @@ -2160,7 +2233,7 @@ impl<'r> molecule::prelude::Reader<'r> for GetNodesReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8]) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::error::VerificationError; let len = slice.len(); if len < 4 { @@ -2182,23 +2255,54 @@ impl<'r> molecule::prelude::Reader<'r> for GetNodesReader<'r> { VerificationError::HeaderIsBroken(Self::NAME.to_owned(), expected, total_size); Err(err)?; } - let mut offsets: Vec = ptr[1..=3] + let offset_first = u32::from_le(ptr[1]) as usize; + if offset_first % 4 != 0 { + let err = VerificationError::FirstOffsetIsBroken(Self::NAME.to_owned(), offset_first); + Err(err)?; + } + if offset_first < expected { + let err = VerificationError::FirstOffsetIsShort( + Self::NAME.to_owned(), + expected, + offset_first, + ); + Err(err)?; + } + let real_field_count = if compatible { + let real_field_count = offset_first / 4 - 1; + let real_expected = 4 + 4 * real_field_count; + if total_size < real_expected { + let err = VerificationError::DataIsShort( + Self::NAME.to_owned(), + real_expected, + total_size, + ); + Err(err)?; + } + real_field_count + } else { + if offset_first > expected { + let err = VerificationError::FirstOffsetIsOverflow( + Self::NAME.to_owned(), + expected, + offset_first, + ); + Err(err)?; + } + 3 + }; + let mut offsets: Vec = ptr[1..=real_field_count] .iter() .map(|x| u32::from_le(*x) as usize) .collect(); - if offsets[0] != expected { - let err = - VerificationError::FirstOffsetIsShort(Self::NAME.to_owned(), expected, offsets[0]); - Err(err)?; - } offsets.push(total_size); if offsets.windows(2).any(|i| i[0] > i[1]) { let err = VerificationError::OffsetsNotMatch(Self::NAME.to_owned()); Err(err)?; } - Uint32Reader::verify(&slice[offsets[0]..offsets[1]])?; - Uint32Reader::verify(&slice[offsets[1]..offsets[2]])?; - PortOptReader::verify(&slice[offsets[2]..offsets[3]])?; + Uint32Reader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + Uint32Reader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + PortOptReader::verify(&slice[offsets[2]..offsets[3]], compatible)?; Ok(()) } } @@ -2212,6 +2316,10 @@ impl<'r> GetNodesReader<'r> { let count = (first - 4) / 4; (bytes_len, count, &ptr[1..]) } + pub fn has_extra_fields(&self) -> bool { + let (_, real_fields_count, _) = Self::field_offsets(self); + Self::FIELD_COUNT == real_fields_count + } pub fn version(&self) -> Uint32Reader<'r> { let (_, _, offsets) = Self::field_offsets(self); let start = u32::from_le(offsets[0]) as usize; @@ -2363,6 +2471,9 @@ impl molecule::prelude::Entity for Nodes { fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { NodesReader::from_slice(slice).map(|reader| reader.to_entity()) } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + NodesReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } fn new_builder() -> Self::Builder { ::std::default::Default::default() } @@ -2385,6 +2496,10 @@ impl Nodes { let count = (first - 4) / 4; (bytes_len, count, &ptr[1..]) } + pub fn has_extra_fields(&self) -> bool { + let (_, real_fields_count, _) = Self::field_offsets(self); + Self::FIELD_COUNT == real_fields_count + } pub fn announce(&self) -> Bool { let (_, _, offsets) = Self::field_offsets(self); let start = u32::from_le(offsets[0]) as usize; @@ -2413,7 +2528,7 @@ impl<'r> molecule::prelude::Reader<'r> for NodesReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8]) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::error::VerificationError; let len = slice.len(); if len < 4 { @@ -2435,22 +2550,53 @@ impl<'r> molecule::prelude::Reader<'r> for NodesReader<'r> { VerificationError::HeaderIsBroken(Self::NAME.to_owned(), expected, total_size); Err(err)?; } - let mut offsets: Vec = ptr[1..=2] + let offset_first = u32::from_le(ptr[1]) as usize; + if offset_first % 4 != 0 { + let err = VerificationError::FirstOffsetIsBroken(Self::NAME.to_owned(), offset_first); + Err(err)?; + } + if offset_first < expected { + let err = VerificationError::FirstOffsetIsShort( + Self::NAME.to_owned(), + expected, + offset_first, + ); + Err(err)?; + } + let real_field_count = if compatible { + let real_field_count = offset_first / 4 - 1; + let real_expected = 4 + 4 * real_field_count; + if total_size < real_expected { + let err = VerificationError::DataIsShort( + Self::NAME.to_owned(), + real_expected, + total_size, + ); + Err(err)?; + } + real_field_count + } else { + if offset_first > expected { + let err = VerificationError::FirstOffsetIsOverflow( + Self::NAME.to_owned(), + expected, + offset_first, + ); + Err(err)?; + } + 2 + }; + let mut offsets: Vec = ptr[1..=real_field_count] .iter() .map(|x| u32::from_le(*x) as usize) .collect(); - if offsets[0] != expected { - let err = - VerificationError::FirstOffsetIsShort(Self::NAME.to_owned(), expected, offsets[0]); - Err(err)?; - } offsets.push(total_size); if offsets.windows(2).any(|i| i[0] > i[1]) { let err = VerificationError::OffsetsNotMatch(Self::NAME.to_owned()); Err(err)?; } - BoolReader::verify(&slice[offsets[0]..offsets[1]])?; - NodeVecReader::verify(&slice[offsets[1]..offsets[2]])?; + BoolReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + NodeVecReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; Ok(()) } } @@ -2464,6 +2610,10 @@ impl<'r> NodesReader<'r> { let count = (first - 4) / 4; (bytes_len, count, &ptr[1..]) } + pub fn has_extra_fields(&self) -> bool { + let (_, real_fields_count, _) = Self::field_offsets(self); + Self::FIELD_COUNT == real_fields_count + } pub fn announce(&self) -> BoolReader<'r> { let (_, _, offsets) = Self::field_offsets(self); let start = u32::from_le(offsets[0]) as usize; @@ -2593,6 +2743,9 @@ impl molecule::prelude::Entity for Node { fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { NodeReader::from_slice(slice).map(|reader| reader.to_entity()) } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + NodeReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } fn new_builder() -> Self::Builder { ::std::default::Default::default() } @@ -2613,6 +2766,10 @@ impl Node { let count = (first - 4) / 4; (bytes_len, count, &ptr[1..]) } + pub fn has_extra_fields(&self) -> bool { + let (_, real_fields_count, _) = Self::field_offsets(self); + Self::FIELD_COUNT == real_fields_count + } pub fn addresses(&self) -> BytesVec { let (_, count, offsets) = Self::field_offsets(self); let start = u32::from_le(offsets[0]) as usize; @@ -2635,7 +2792,7 @@ impl<'r> molecule::prelude::Reader<'r> for NodeReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8]) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::error::VerificationError; let len = slice.len(); if len < 4 { @@ -2657,21 +2814,52 @@ impl<'r> molecule::prelude::Reader<'r> for NodeReader<'r> { VerificationError::HeaderIsBroken(Self::NAME.to_owned(), expected, total_size); Err(err)?; } - let mut offsets: Vec = ptr[1..=1] + let offset_first = u32::from_le(ptr[1]) as usize; + if offset_first % 4 != 0 { + let err = VerificationError::FirstOffsetIsBroken(Self::NAME.to_owned(), offset_first); + Err(err)?; + } + if offset_first < expected { + let err = VerificationError::FirstOffsetIsShort( + Self::NAME.to_owned(), + expected, + offset_first, + ); + Err(err)?; + } + let real_field_count = if compatible { + let real_field_count = offset_first / 4 - 1; + let real_expected = 4 + 4 * real_field_count; + if total_size < real_expected { + let err = VerificationError::DataIsShort( + Self::NAME.to_owned(), + real_expected, + total_size, + ); + Err(err)?; + } + real_field_count + } else { + if offset_first > expected { + let err = VerificationError::FirstOffsetIsOverflow( + Self::NAME.to_owned(), + expected, + offset_first, + ); + Err(err)?; + } + 1 + }; + let mut offsets: Vec = ptr[1..=real_field_count] .iter() .map(|x| u32::from_le(*x) as usize) .collect(); - if offsets[0] != expected { - let err = - VerificationError::FirstOffsetIsShort(Self::NAME.to_owned(), expected, offsets[0]); - Err(err)?; - } offsets.push(total_size); if offsets.windows(2).any(|i| i[0] > i[1]) { let err = VerificationError::OffsetsNotMatch(Self::NAME.to_owned()); Err(err)?; } - BytesVecReader::verify(&slice[offsets[0]..offsets[1]])?; + BytesVecReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; Ok(()) } } @@ -2685,6 +2873,10 @@ impl<'r> NodeReader<'r> { let count = (first - 4) / 4; (bytes_len, count, &ptr[1..]) } + pub fn has_extra_fields(&self) -> bool { + let (_, real_fields_count, _) = Self::field_offsets(self); + Self::FIELD_COUNT == real_fields_count + } pub fn addresses(&self) -> BytesVecReader<'r> { let (_, count, offsets) = Self::field_offsets(self); let start = u32::from_le(offsets[0]) as usize; diff --git a/protocols/identify/Cargo.toml b/protocols/identify/Cargo.toml index 94b65810..ce4f27b6 100644 --- a/protocols/identify/Cargo.toml +++ b/protocols/identify/Cargo.toml @@ -21,7 +21,7 @@ flatbuffers = { version = "0.6.0", optional = true } flatbuffers-verifier = { version = "0.2.0", optional = true } tokio = "0.1" log = "0.4" -molecule = { version = "0.2.5", optional = true } +molecule = { version = "0.3.1", optional = true } [dev-dependencies] env_logger = "0.6.0" diff --git a/protocols/identify/README.md b/protocols/identify/README.md new file mode 100644 index 00000000..df3106dd --- /dev/null +++ b/protocols/identify/README.md @@ -0,0 +1,28 @@ +## Identify +Node self-identifying protocol + +### Identify behavior + +Under the architecture of the Tentacle framework, if you decide to open all protocols at once, +the order of opening is undetermined. Tentacle also supports the opening of the specified protocol, +that is, control the order in which the protocols are opened by controlling the order of execution. + +In some scenarios, both parties need to confirm the capabilities of the other party before opening +the application protocol. The Identify protocol can be viewed as a general handshake protocol for +the user protocol layer, it supports passing in arbitrary data for interaction, and can customize +the next behavior based on the received message. + +At the same time, it tentatively transmits the observation address and the listening address. + +### Message type + +``` +table IdentifyMessage { + // These are the addresses on which the peer is listening as multi-addresses. + listen_addrs: AddressVec, + // Observed each other's ip + observed_addr: Address, + // Custom message to indicate self ability, such as list protocols supported + identify: Bytes, +} +``` diff --git a/protocols/identify/src/protocol.rs b/protocols/identify/src/protocol.rs index 42416b8d..58e85ebf 100644 --- a/protocols/identify/src/protocol.rs +++ b/protocols/identify/src/protocol.rs @@ -129,7 +129,7 @@ impl<'a> IdentifyMessage<'a> { #[cfg(feature = "molc")] pub(crate) fn decode(data: &'a [u8]) -> Option { - let reader = protocol_mol::IdentifyMessageReader::from_slice(data).ok()?; + let reader = protocol_mol::IdentifyMessageReader::from_compatible_slice(data).ok()?; let identify = reader.identify().raw_data(); let observed_addr = diff --git a/protocols/identify/src/protocol_mol.rs b/protocols/identify/src/protocol_mol.rs index 6109b96f..79f9115b 100644 --- a/protocols/identify/src/protocol_mol.rs +++ b/protocols/identify/src/protocol_mol.rs @@ -1,4 +1,4 @@ -// Generated by Molecule 0.2.5 +// Generated by Molecule 0.3.1 use molecule::faster_hex::hex_string; use molecule::prelude::{Entity as _, Reader as _}; @@ -62,6 +62,9 @@ impl molecule::prelude::Entity for Bytes { fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { BytesReader::from_slice(slice).map(|reader| reader.to_entity()) } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + BytesReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } fn new_builder() -> Self::Builder { ::std::default::Default::default() } @@ -113,7 +116,7 @@ impl<'r> molecule::prelude::Reader<'r> for BytesReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8]) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::error::VerificationError; let len = slice.len(); if len < 4 { @@ -280,6 +283,9 @@ impl molecule::prelude::Entity for AddressVec { fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { AddressVecReader::from_slice(slice).map(|reader| reader.to_entity()) } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + AddressVecReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } fn new_builder() -> Self::Builder { ::std::default::Default::default() } @@ -346,7 +352,7 @@ impl<'r> molecule::prelude::Reader<'r> for AddressVecReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8]) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::error::VerificationError; let len = slice.len(); if len < 4 { @@ -393,7 +399,7 @@ impl<'r> molecule::prelude::Reader<'r> for AddressVecReader<'r> { for i in 0..=(offsets.len() - 2) { let start = offsets[i]; let end = offsets[i + 1]; - AddressReader::verify(&slice[start..end])?; + AddressReader::verify(&slice[start..end], _compatible)?; } Ok(()) } @@ -604,6 +610,9 @@ impl molecule::prelude::Entity for Address { fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { AddressReader::from_slice(slice).map(|reader| reader.to_entity()) } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + AddressReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } fn new_builder() -> Self::Builder { ::std::default::Default::default() } @@ -624,6 +633,10 @@ impl Address { let count = (first - 4) / 4; (bytes_len, count, &ptr[1..]) } + pub fn has_extra_fields(&self) -> bool { + let (_, real_fields_count, _) = Self::field_offsets(self); + Self::FIELD_COUNT == real_fields_count + } pub fn bytes(&self) -> Bytes { let (_, count, offsets) = Self::field_offsets(self); let start = u32::from_le(offsets[0]) as usize; @@ -646,7 +659,7 @@ impl<'r> molecule::prelude::Reader<'r> for AddressReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8]) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::error::VerificationError; let len = slice.len(); if len < 4 { @@ -668,21 +681,52 @@ impl<'r> molecule::prelude::Reader<'r> for AddressReader<'r> { VerificationError::HeaderIsBroken(Self::NAME.to_owned(), expected, total_size); Err(err)?; } - let mut offsets: Vec = ptr[1..=1] + let offset_first = u32::from_le(ptr[1]) as usize; + if offset_first % 4 != 0 { + let err = VerificationError::FirstOffsetIsBroken(Self::NAME.to_owned(), offset_first); + Err(err)?; + } + if offset_first < expected { + let err = VerificationError::FirstOffsetIsShort( + Self::NAME.to_owned(), + expected, + offset_first, + ); + Err(err)?; + } + let real_field_count = if compatible { + let real_field_count = offset_first / 4 - 1; + let real_expected = 4 + 4 * real_field_count; + if total_size < real_expected { + let err = VerificationError::DataIsShort( + Self::NAME.to_owned(), + real_expected, + total_size, + ); + Err(err)?; + } + real_field_count + } else { + if offset_first > expected { + let err = VerificationError::FirstOffsetIsOverflow( + Self::NAME.to_owned(), + expected, + offset_first, + ); + Err(err)?; + } + 1 + }; + let mut offsets: Vec = ptr[1..=real_field_count] .iter() .map(|x| u32::from_le(*x) as usize) .collect(); - if offsets[0] != expected { - let err = - VerificationError::FirstOffsetIsShort(Self::NAME.to_owned(), expected, offsets[0]); - Err(err)?; - } offsets.push(total_size); if offsets.windows(2).any(|i| i[0] > i[1]) { let err = VerificationError::OffsetsNotMatch(Self::NAME.to_owned()); Err(err)?; } - BytesReader::verify(&slice[offsets[0]..offsets[1]])?; + BytesReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; Ok(()) } } @@ -696,6 +740,10 @@ impl<'r> AddressReader<'r> { let count = (first - 4) / 4; (bytes_len, count, &ptr[1..]) } + pub fn has_extra_fields(&self) -> bool { + let (_, real_fields_count, _) = Self::field_offsets(self); + Self::FIELD_COUNT == real_fields_count + } pub fn bytes(&self) -> BytesReader<'r> { let (_, count, offsets) = Self::field_offsets(self); let start = u32::from_le(offsets[0]) as usize; @@ -818,6 +866,9 @@ impl molecule::prelude::Entity for IdentifyMessage { fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { IdentifyMessageReader::from_slice(slice).map(|reader| reader.to_entity()) } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + IdentifyMessageReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } fn new_builder() -> Self::Builder { ::std::default::Default::default() } @@ -841,6 +892,10 @@ impl IdentifyMessage { let count = (first - 4) / 4; (bytes_len, count, &ptr[1..]) } + pub fn has_extra_fields(&self) -> bool { + let (_, real_fields_count, _) = Self::field_offsets(self); + Self::FIELD_COUNT == real_fields_count + } pub fn listen_addrs(&self) -> AddressVec { let (_, _, offsets) = Self::field_offsets(self); let start = u32::from_le(offsets[0]) as usize; @@ -875,7 +930,7 @@ impl<'r> molecule::prelude::Reader<'r> for IdentifyMessageReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8]) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::error::VerificationError; let len = slice.len(); if len < 4 { @@ -897,23 +952,54 @@ impl<'r> molecule::prelude::Reader<'r> for IdentifyMessageReader<'r> { VerificationError::HeaderIsBroken(Self::NAME.to_owned(), expected, total_size); Err(err)?; } - let mut offsets: Vec = ptr[1..=3] + let offset_first = u32::from_le(ptr[1]) as usize; + if offset_first % 4 != 0 { + let err = VerificationError::FirstOffsetIsBroken(Self::NAME.to_owned(), offset_first); + Err(err)?; + } + if offset_first < expected { + let err = VerificationError::FirstOffsetIsShort( + Self::NAME.to_owned(), + expected, + offset_first, + ); + Err(err)?; + } + let real_field_count = if compatible { + let real_field_count = offset_first / 4 - 1; + let real_expected = 4 + 4 * real_field_count; + if total_size < real_expected { + let err = VerificationError::DataIsShort( + Self::NAME.to_owned(), + real_expected, + total_size, + ); + Err(err)?; + } + real_field_count + } else { + if offset_first > expected { + let err = VerificationError::FirstOffsetIsOverflow( + Self::NAME.to_owned(), + expected, + offset_first, + ); + Err(err)?; + } + 3 + }; + let mut offsets: Vec = ptr[1..=real_field_count] .iter() .map(|x| u32::from_le(*x) as usize) .collect(); - if offsets[0] != expected { - let err = - VerificationError::FirstOffsetIsShort(Self::NAME.to_owned(), expected, offsets[0]); - Err(err)?; - } offsets.push(total_size); if offsets.windows(2).any(|i| i[0] > i[1]) { let err = VerificationError::OffsetsNotMatch(Self::NAME.to_owned()); Err(err)?; } - AddressVecReader::verify(&slice[offsets[0]..offsets[1]])?; - AddressReader::verify(&slice[offsets[1]..offsets[2]])?; - BytesReader::verify(&slice[offsets[2]..offsets[3]])?; + AddressVecReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + AddressReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + BytesReader::verify(&slice[offsets[2]..offsets[3]], compatible)?; Ok(()) } } @@ -927,6 +1013,10 @@ impl<'r> IdentifyMessageReader<'r> { let count = (first - 4) / 4; (bytes_len, count, &ptr[1..]) } + pub fn has_extra_fields(&self) -> bool { + let (_, real_fields_count, _) = Self::field_offsets(self); + Self::FIELD_COUNT == real_fields_count + } pub fn listen_addrs(&self) -> AddressVecReader<'r> { let (_, _, offsets) = Self::field_offsets(self); let start = u32::from_le(offsets[0]) as usize; diff --git a/protocols/ping/Cargo.toml b/protocols/ping/Cargo.toml index 4d22ad6e..097e32ac 100644 --- a/protocols/ping/Cargo.toml +++ b/protocols/ping/Cargo.toml @@ -21,7 +21,7 @@ flatbuffers = { version = "0.6.0", optional = true } flatbuffers-verifier = { version = "0.2.0", optional = true } generic-channel = "0.2.0" bytes = "0.4" -molecule = { version = "0.2.5", optional = true } +molecule = { version = "0.3.1", optional = true } [dev-dependencies] env_logger = "0.6.0" diff --git a/protocols/ping/src/lib.rs b/protocols/ping/src/lib.rs index a536da70..2623efe8 100644 --- a/protocols/ping/src/lib.rs +++ b/protocols/ping/src/lib.rs @@ -350,7 +350,7 @@ impl PingMessage { #[cfg(feature = "molc")] #[allow(clippy::cast_ptr_alignment)] fn decode(data: &[u8]) -> Option { - let reader = protocol_mol::PingMessageReader::from_slice(data).ok()?; + let reader = protocol_mol::PingMessageReader::from_compatible_slice(data).ok()?; match reader.payload().to_enum() { protocol_mol::PingPayloadUnionReader::Ping(reader) => { let le = reader.nonce().raw_data().as_ptr() as *const u32; diff --git a/protocols/ping/src/protocol_mol.rs b/protocols/ping/src/protocol_mol.rs index 3b0c3712..170c59ff 100644 --- a/protocols/ping/src/protocol_mol.rs +++ b/protocols/ping/src/protocol_mol.rs @@ -1,4 +1,4 @@ -// Generated by Molecule 0.2.5 +// Generated by Molecule 0.3.1 use molecule::faster_hex::hex_string; use molecule::prelude::{Entity as _, Reader as _}; @@ -71,6 +71,9 @@ impl molecule::prelude::Entity for Uint32 { fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { Uint32Reader::from_slice(slice).map(|reader| reader.to_entity()) } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + Uint32Reader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } fn new_builder() -> Self::Builder { ::std::default::Default::default() } @@ -119,7 +122,7 @@ impl<'r> molecule::prelude::Reader<'r> for Uint32Reader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8]) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::error::VerificationError; if slice.len() != 4 { let err = VerificationError::TotalSizeNotMatch(Self::NAME.to_owned(), 4, slice.len()); @@ -384,6 +387,9 @@ impl molecule::prelude::Entity for PingPayload { fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { PingPayloadReader::from_slice(slice).map(|reader| reader.to_entity()) } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + PingPayloadReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } fn new_builder() -> Self::Builder { ::std::default::Default::default() } @@ -427,7 +433,7 @@ impl<'r> molecule::prelude::Reader<'r> for PingPayloadReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8]) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::error::VerificationError; if slice.len() < molecule::ITEM_ID_SIZE { let err = VerificationError::HeaderIsBroken( @@ -439,8 +445,8 @@ impl<'r> molecule::prelude::Reader<'r> for PingPayloadReader<'r> { } let item_id = molecule::extract_item_id(slice); match item_id { - 1 => PingReader::verify(&slice[molecule::ITEM_ID_SIZE..]), - 2 => PongReader::verify(&slice[molecule::ITEM_ID_SIZE..]), + 1 => PingReader::verify(&slice[molecule::ITEM_ID_SIZE..], _compatible), + 2 => PongReader::verify(&slice[molecule::ITEM_ID_SIZE..], _compatible), _ => { let err = VerificationError::UnknownItem(Self::NAME.to_owned(), 2, item_id); Err(err) @@ -561,6 +567,9 @@ impl molecule::prelude::Entity for PingMessage { fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { PingMessageReader::from_slice(slice).map(|reader| reader.to_entity()) } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + PingMessageReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } fn new_builder() -> Self::Builder { ::std::default::Default::default() } @@ -581,6 +590,10 @@ impl PingMessage { let count = (first - 4) / 4; (bytes_len, count, &ptr[1..]) } + pub fn has_extra_fields(&self) -> bool { + let (_, real_fields_count, _) = Self::field_offsets(self); + Self::FIELD_COUNT == real_fields_count + } pub fn payload(&self) -> PingPayload { let (_, count, offsets) = Self::field_offsets(self); let start = u32::from_le(offsets[0]) as usize; @@ -603,7 +616,7 @@ impl<'r> molecule::prelude::Reader<'r> for PingMessageReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8]) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::error::VerificationError; let len = slice.len(); if len < 4 { @@ -625,21 +638,52 @@ impl<'r> molecule::prelude::Reader<'r> for PingMessageReader<'r> { VerificationError::HeaderIsBroken(Self::NAME.to_owned(), expected, total_size); Err(err)?; } - let mut offsets: Vec = ptr[1..=1] + let offset_first = u32::from_le(ptr[1]) as usize; + if offset_first % 4 != 0 { + let err = VerificationError::FirstOffsetIsBroken(Self::NAME.to_owned(), offset_first); + Err(err)?; + } + if offset_first < expected { + let err = VerificationError::FirstOffsetIsShort( + Self::NAME.to_owned(), + expected, + offset_first, + ); + Err(err)?; + } + let real_field_count = if compatible { + let real_field_count = offset_first / 4 - 1; + let real_expected = 4 + 4 * real_field_count; + if total_size < real_expected { + let err = VerificationError::DataIsShort( + Self::NAME.to_owned(), + real_expected, + total_size, + ); + Err(err)?; + } + real_field_count + } else { + if offset_first > expected { + let err = VerificationError::FirstOffsetIsOverflow( + Self::NAME.to_owned(), + expected, + offset_first, + ); + Err(err)?; + } + 1 + }; + let mut offsets: Vec = ptr[1..=real_field_count] .iter() .map(|x| u32::from_le(*x) as usize) .collect(); - if offsets[0] != expected { - let err = - VerificationError::FirstOffsetIsShort(Self::NAME.to_owned(), expected, offsets[0]); - Err(err)?; - } offsets.push(total_size); if offsets.windows(2).any(|i| i[0] > i[1]) { let err = VerificationError::OffsetsNotMatch(Self::NAME.to_owned()); Err(err)?; } - PingPayloadReader::verify(&slice[offsets[0]..offsets[1]])?; + PingPayloadReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; Ok(()) } } @@ -653,6 +697,10 @@ impl<'r> PingMessageReader<'r> { let count = (first - 4) / 4; (bytes_len, count, &ptr[1..]) } + pub fn has_extra_fields(&self) -> bool { + let (_, real_fields_count, _) = Self::field_offsets(self); + Self::FIELD_COUNT == real_fields_count + } pub fn payload(&self) -> PingPayloadReader<'r> { let (_, count, offsets) = Self::field_offsets(self); let start = u32::from_le(offsets[0]) as usize; @@ -766,6 +814,9 @@ impl molecule::prelude::Entity for Ping { fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { PingReader::from_slice(slice).map(|reader| reader.to_entity()) } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + PingReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } fn new_builder() -> Self::Builder { ::std::default::Default::default() } @@ -786,6 +837,10 @@ impl Ping { let count = (first - 4) / 4; (bytes_len, count, &ptr[1..]) } + pub fn has_extra_fields(&self) -> bool { + let (_, real_fields_count, _) = Self::field_offsets(self); + Self::FIELD_COUNT == real_fields_count + } pub fn nonce(&self) -> Uint32 { let (_, count, offsets) = Self::field_offsets(self); let start = u32::from_le(offsets[0]) as usize; @@ -808,7 +863,7 @@ impl<'r> molecule::prelude::Reader<'r> for PingReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8]) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::error::VerificationError; let len = slice.len(); if len < 4 { @@ -830,21 +885,52 @@ impl<'r> molecule::prelude::Reader<'r> for PingReader<'r> { VerificationError::HeaderIsBroken(Self::NAME.to_owned(), expected, total_size); Err(err)?; } - let mut offsets: Vec = ptr[1..=1] + let offset_first = u32::from_le(ptr[1]) as usize; + if offset_first % 4 != 0 { + let err = VerificationError::FirstOffsetIsBroken(Self::NAME.to_owned(), offset_first); + Err(err)?; + } + if offset_first < expected { + let err = VerificationError::FirstOffsetIsShort( + Self::NAME.to_owned(), + expected, + offset_first, + ); + Err(err)?; + } + let real_field_count = if compatible { + let real_field_count = offset_first / 4 - 1; + let real_expected = 4 + 4 * real_field_count; + if total_size < real_expected { + let err = VerificationError::DataIsShort( + Self::NAME.to_owned(), + real_expected, + total_size, + ); + Err(err)?; + } + real_field_count + } else { + if offset_first > expected { + let err = VerificationError::FirstOffsetIsOverflow( + Self::NAME.to_owned(), + expected, + offset_first, + ); + Err(err)?; + } + 1 + }; + let mut offsets: Vec = ptr[1..=real_field_count] .iter() .map(|x| u32::from_le(*x) as usize) .collect(); - if offsets[0] != expected { - let err = - VerificationError::FirstOffsetIsShort(Self::NAME.to_owned(), expected, offsets[0]); - Err(err)?; - } offsets.push(total_size); if offsets.windows(2).any(|i| i[0] > i[1]) { let err = VerificationError::OffsetsNotMatch(Self::NAME.to_owned()); Err(err)?; } - Uint32Reader::verify(&slice[offsets[0]..offsets[1]])?; + Uint32Reader::verify(&slice[offsets[0]..offsets[1]], compatible)?; Ok(()) } } @@ -858,6 +944,10 @@ impl<'r> PingReader<'r> { let count = (first - 4) / 4; (bytes_len, count, &ptr[1..]) } + pub fn has_extra_fields(&self) -> bool { + let (_, real_fields_count, _) = Self::field_offsets(self); + Self::FIELD_COUNT == real_fields_count + } pub fn nonce(&self) -> Uint32Reader<'r> { let (_, count, offsets) = Self::field_offsets(self); let start = u32::from_le(offsets[0]) as usize; @@ -971,6 +1061,9 @@ impl molecule::prelude::Entity for Pong { fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { PongReader::from_slice(slice).map(|reader| reader.to_entity()) } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + PongReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } fn new_builder() -> Self::Builder { ::std::default::Default::default() } @@ -991,6 +1084,10 @@ impl Pong { let count = (first - 4) / 4; (bytes_len, count, &ptr[1..]) } + pub fn has_extra_fields(&self) -> bool { + let (_, real_fields_count, _) = Self::field_offsets(self); + Self::FIELD_COUNT == real_fields_count + } pub fn nonce(&self) -> Uint32 { let (_, count, offsets) = Self::field_offsets(self); let start = u32::from_le(offsets[0]) as usize; @@ -1013,7 +1110,7 @@ impl<'r> molecule::prelude::Reader<'r> for PongReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8]) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::error::VerificationError; let len = slice.len(); if len < 4 { @@ -1035,21 +1132,52 @@ impl<'r> molecule::prelude::Reader<'r> for PongReader<'r> { VerificationError::HeaderIsBroken(Self::NAME.to_owned(), expected, total_size); Err(err)?; } - let mut offsets: Vec = ptr[1..=1] + let offset_first = u32::from_le(ptr[1]) as usize; + if offset_first % 4 != 0 { + let err = VerificationError::FirstOffsetIsBroken(Self::NAME.to_owned(), offset_first); + Err(err)?; + } + if offset_first < expected { + let err = VerificationError::FirstOffsetIsShort( + Self::NAME.to_owned(), + expected, + offset_first, + ); + Err(err)?; + } + let real_field_count = if compatible { + let real_field_count = offset_first / 4 - 1; + let real_expected = 4 + 4 * real_field_count; + if total_size < real_expected { + let err = VerificationError::DataIsShort( + Self::NAME.to_owned(), + real_expected, + total_size, + ); + Err(err)?; + } + real_field_count + } else { + if offset_first > expected { + let err = VerificationError::FirstOffsetIsOverflow( + Self::NAME.to_owned(), + expected, + offset_first, + ); + Err(err)?; + } + 1 + }; + let mut offsets: Vec = ptr[1..=real_field_count] .iter() .map(|x| u32::from_le(*x) as usize) .collect(); - if offsets[0] != expected { - let err = - VerificationError::FirstOffsetIsShort(Self::NAME.to_owned(), expected, offsets[0]); - Err(err)?; - } offsets.push(total_size); if offsets.windows(2).any(|i| i[0] > i[1]) { let err = VerificationError::OffsetsNotMatch(Self::NAME.to_owned()); Err(err)?; } - Uint32Reader::verify(&slice[offsets[0]..offsets[1]])?; + Uint32Reader::verify(&slice[offsets[0]..offsets[1]], compatible)?; Ok(()) } } @@ -1063,6 +1191,10 @@ impl<'r> PongReader<'r> { let count = (first - 4) / 4; (bytes_len, count, &ptr[1..]) } + pub fn has_extra_fields(&self) -> bool { + let (_, real_fields_count, _) = Self::field_offsets(self); + Self::FIELD_COUNT == real_fields_count + } pub fn nonce(&self) -> Uint32Reader<'r> { let (_, count, offsets) = Self::field_offsets(self); let start = u32::from_le(offsets[0]) as usize; diff --git a/secio/Cargo.toml b/secio/Cargo.toml index ef55b56f..874064ae 100644 --- a/secio/Cargo.toml +++ b/secio/Cargo.toml @@ -23,7 +23,7 @@ log = "0.4.1" flatbuffers = { version = "0.6.0", optional = true } flatbuffers-verifier = { version = "0.2.0", optional = true } -molecule = { version = "0.2.0", optional = true } +molecule = { version = "0.3.1", optional = true } secp256k1 = "0.15" hmac = "0.7.0" diff --git a/secio/src/handshake/handshake_mol.rs b/secio/src/handshake/handshake_mol.rs index ee5bd533..b14eb949 100644 --- a/secio/src/handshake/handshake_mol.rs +++ b/secio/src/handshake/handshake_mol.rs @@ -1,4 +1,4 @@ -// Generated by Molecule 0.2.5 +// Generated by Molecule 0.3.1 use molecule::faster_hex::hex_string; use molecule::prelude::{Entity as _, Reader as _}; @@ -62,6 +62,9 @@ impl molecule::prelude::Entity for Secp256k1 { fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { Secp256k1Reader::from_slice(slice).map(|reader| reader.to_entity()) } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + Secp256k1Reader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } fn new_builder() -> Self::Builder { ::std::default::Default::default() } @@ -113,7 +116,7 @@ impl<'r> molecule::prelude::Reader<'r> for Secp256k1Reader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8]) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::error::VerificationError; let len = slice.len(); if len < 4 { @@ -274,6 +277,9 @@ impl molecule::prelude::Entity for Bytes { fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { BytesReader::from_slice(slice).map(|reader| reader.to_entity()) } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + BytesReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } fn new_builder() -> Self::Builder { ::std::default::Default::default() } @@ -325,7 +331,7 @@ impl<'r> molecule::prelude::Reader<'r> for BytesReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8]) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::error::VerificationError; let len = slice.len(); if len < 4 { @@ -486,6 +492,9 @@ impl molecule::prelude::Entity for String { fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { StringReader::from_slice(slice).map(|reader| reader.to_entity()) } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + StringReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } fn new_builder() -> Self::Builder { ::std::default::Default::default() } @@ -537,7 +546,7 @@ impl<'r> molecule::prelude::Reader<'r> for StringReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8]) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::error::VerificationError; let len = slice.len(); if len < 4 { @@ -807,6 +816,9 @@ impl molecule::prelude::Entity for PublicKey { fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { PublicKeyReader::from_slice(slice).map(|reader| reader.to_entity()) } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + PublicKeyReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } fn new_builder() -> Self::Builder { ::std::default::Default::default() } @@ -849,7 +861,7 @@ impl<'r> molecule::prelude::Reader<'r> for PublicKeyReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8]) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::error::VerificationError; if slice.len() < molecule::ITEM_ID_SIZE { let err = VerificationError::HeaderIsBroken( @@ -861,7 +873,7 @@ impl<'r> molecule::prelude::Reader<'r> for PublicKeyReader<'r> { } let item_id = molecule::extract_item_id(slice); match item_id { - 1 => Secp256k1Reader::verify(&slice[molecule::ITEM_ID_SIZE..]), + 1 => Secp256k1Reader::verify(&slice[molecule::ITEM_ID_SIZE..], _compatible), _ => { let err = VerificationError::UnknownItem(Self::NAME.to_owned(), 1, item_id); Err(err) @@ -996,6 +1008,9 @@ impl molecule::prelude::Entity for Propose { fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { ProposeReader::from_slice(slice).map(|reader| reader.to_entity()) } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + ProposeReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } fn new_builder() -> Self::Builder { ::std::default::Default::default() } @@ -1021,6 +1036,10 @@ impl Propose { let count = (first - 4) / 4; (bytes_len, count, &ptr[1..]) } + pub fn has_extra_fields(&self) -> bool { + let (_, real_fields_count, _) = Self::field_offsets(self); + Self::FIELD_COUNT == real_fields_count + } pub fn rand(&self) -> Bytes { let (_, _, offsets) = Self::field_offsets(self); let start = u32::from_le(offsets[0]) as usize; @@ -1067,7 +1086,7 @@ impl<'r> molecule::prelude::Reader<'r> for ProposeReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8]) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::error::VerificationError; let len = slice.len(); if len < 4 { @@ -1089,25 +1108,56 @@ impl<'r> molecule::prelude::Reader<'r> for ProposeReader<'r> { VerificationError::HeaderIsBroken(Self::NAME.to_owned(), expected, total_size); Err(err)?; } - let mut offsets: Vec = ptr[1..=5] + let offset_first = u32::from_le(ptr[1]) as usize; + if offset_first % 4 != 0 { + let err = VerificationError::FirstOffsetIsBroken(Self::NAME.to_owned(), offset_first); + Err(err)?; + } + if offset_first < expected { + let err = VerificationError::FirstOffsetIsShort( + Self::NAME.to_owned(), + expected, + offset_first, + ); + Err(err)?; + } + let real_field_count = if compatible { + let real_field_count = offset_first / 4 - 1; + let real_expected = 4 + 4 * real_field_count; + if total_size < real_expected { + let err = VerificationError::DataIsShort( + Self::NAME.to_owned(), + real_expected, + total_size, + ); + Err(err)?; + } + real_field_count + } else { + if offset_first > expected { + let err = VerificationError::FirstOffsetIsOverflow( + Self::NAME.to_owned(), + expected, + offset_first, + ); + Err(err)?; + } + 5 + }; + let mut offsets: Vec = ptr[1..=real_field_count] .iter() .map(|x| u32::from_le(*x) as usize) .collect(); - if offsets[0] != expected { - let err = - VerificationError::FirstOffsetIsShort(Self::NAME.to_owned(), expected, offsets[0]); - Err(err)?; - } offsets.push(total_size); if offsets.windows(2).any(|i| i[0] > i[1]) { let err = VerificationError::OffsetsNotMatch(Self::NAME.to_owned()); Err(err)?; } - BytesReader::verify(&slice[offsets[0]..offsets[1]])?; - BytesReader::verify(&slice[offsets[1]..offsets[2]])?; - StringReader::verify(&slice[offsets[2]..offsets[3]])?; - StringReader::verify(&slice[offsets[3]..offsets[4]])?; - StringReader::verify(&slice[offsets[4]..offsets[5]])?; + BytesReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + BytesReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + StringReader::verify(&slice[offsets[2]..offsets[3]], compatible)?; + StringReader::verify(&slice[offsets[3]..offsets[4]], compatible)?; + StringReader::verify(&slice[offsets[4]..offsets[5]], compatible)?; Ok(()) } } @@ -1121,6 +1171,10 @@ impl<'r> ProposeReader<'r> { let count = (first - 4) / 4; (bytes_len, count, &ptr[1..]) } + pub fn has_extra_fields(&self) -> bool { + let (_, real_fields_count, _) = Self::field_offsets(self); + Self::FIELD_COUNT == real_fields_count + } pub fn rand(&self) -> BytesReader<'r> { let (_, _, offsets) = Self::field_offsets(self); let start = u32::from_le(offsets[0]) as usize; @@ -1308,6 +1362,9 @@ impl molecule::prelude::Entity for Exchange { fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { ExchangeReader::from_slice(slice).map(|reader| reader.to_entity()) } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + ExchangeReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } fn new_builder() -> Self::Builder { ::std::default::Default::default() } @@ -1330,6 +1387,10 @@ impl Exchange { let count = (first - 4) / 4; (bytes_len, count, &ptr[1..]) } + pub fn has_extra_fields(&self) -> bool { + let (_, real_fields_count, _) = Self::field_offsets(self); + Self::FIELD_COUNT == real_fields_count + } pub fn epubkey(&self) -> Bytes { let (_, _, offsets) = Self::field_offsets(self); let start = u32::from_le(offsets[0]) as usize; @@ -1358,7 +1419,7 @@ impl<'r> molecule::prelude::Reader<'r> for ExchangeReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8]) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::error::VerificationError; let len = slice.len(); if len < 4 { @@ -1380,22 +1441,53 @@ impl<'r> molecule::prelude::Reader<'r> for ExchangeReader<'r> { VerificationError::HeaderIsBroken(Self::NAME.to_owned(), expected, total_size); Err(err)?; } - let mut offsets: Vec = ptr[1..=2] + let offset_first = u32::from_le(ptr[1]) as usize; + if offset_first % 4 != 0 { + let err = VerificationError::FirstOffsetIsBroken(Self::NAME.to_owned(), offset_first); + Err(err)?; + } + if offset_first < expected { + let err = VerificationError::FirstOffsetIsShort( + Self::NAME.to_owned(), + expected, + offset_first, + ); + Err(err)?; + } + let real_field_count = if compatible { + let real_field_count = offset_first / 4 - 1; + let real_expected = 4 + 4 * real_field_count; + if total_size < real_expected { + let err = VerificationError::DataIsShort( + Self::NAME.to_owned(), + real_expected, + total_size, + ); + Err(err)?; + } + real_field_count + } else { + if offset_first > expected { + let err = VerificationError::FirstOffsetIsOverflow( + Self::NAME.to_owned(), + expected, + offset_first, + ); + Err(err)?; + } + 2 + }; + let mut offsets: Vec = ptr[1..=real_field_count] .iter() .map(|x| u32::from_le(*x) as usize) .collect(); - if offsets[0] != expected { - let err = - VerificationError::FirstOffsetIsShort(Self::NAME.to_owned(), expected, offsets[0]); - Err(err)?; - } offsets.push(total_size); if offsets.windows(2).any(|i| i[0] > i[1]) { let err = VerificationError::OffsetsNotMatch(Self::NAME.to_owned()); Err(err)?; } - BytesReader::verify(&slice[offsets[0]..offsets[1]])?; - BytesReader::verify(&slice[offsets[1]..offsets[2]])?; + BytesReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + BytesReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; Ok(()) } } @@ -1409,6 +1501,10 @@ impl<'r> ExchangeReader<'r> { let count = (first - 4) / 4; (bytes_len, count, &ptr[1..]) } + pub fn has_extra_fields(&self) -> bool { + let (_, real_fields_count, _) = Self::field_offsets(self); + Self::FIELD_COUNT == real_fields_count + } pub fn epubkey(&self) -> BytesReader<'r> { let (_, _, offsets) = Self::field_offsets(self); let start = u32::from_le(offsets[0]) as usize; diff --git a/secio/src/handshake/handshake_struct.rs b/secio/src/handshake/handshake_struct.rs index a207bfb8..a1c393dc 100644 --- a/secio/src/handshake/handshake_struct.rs +++ b/secio/src/handshake/handshake_struct.rs @@ -103,7 +103,7 @@ impl Propose { /// Decode with molecule #[cfg(feature = "molc")] pub fn decode(data: &[u8]) -> Option { - let reader = handshake_mol::ProposeReader::from_slice(data).ok()?; + let reader = handshake_mol::ProposeReader::from_compatible_slice(data).ok()?; Some(Propose { rand: reader.rand().raw_data().to_owned(), pubkey: Bytes::from(reader.pubkey().raw_data()), @@ -173,7 +173,7 @@ impl Exchange { /// Decode with molecule #[cfg(feature = "molc")] pub fn decode(data: &[u8]) -> Option { - let reader = handshake_mol::ExchangeReader::from_slice(data).ok()?; + let reader = handshake_mol::ExchangeReader::from_compatible_slice(data).ok()?; Some(Exchange { epubkey: reader.epubkey().raw_data().to_owned(), signature: reader.signature().raw_data().to_owned(), @@ -246,7 +246,7 @@ impl PublicKey { /// Decode with molecule #[cfg(feature = "molc")] pub fn decode(data: &[u8]) -> Option { - let reader = handshake_mol::PublicKeyReader::from_slice(data).ok()?; + let reader = handshake_mol::PublicKeyReader::from_compatible_slice(data).ok()?; let union = reader.to_enum(); match union { handshake_mol::PublicKeyUnionReader::Secp256k1(reader) => { diff --git a/src/protocol_select/mod.rs b/src/protocol_select/mod.rs index 59f55f84..92b714af 100644 --- a/src/protocol_select/mod.rs +++ b/src/protocol_select/mod.rs @@ -131,7 +131,7 @@ impl ProtocolInfo { /// Decode with molecule #[cfg(feature = "molc")] pub fn decode(data: &[u8]) -> Option { - let reader = protocol_select_mol::ProtocolInfoReader::from_slice(data).ok()?; + let reader = protocol_select_mol::ProtocolInfoReader::from_compatible_slice(data).ok()?; let mut supports = Vec::new(); for version in reader.support_versions().iter() { diff --git a/src/protocol_select/protocol_select_mol.rs b/src/protocol_select/protocol_select_mol.rs index 321249de..ebd60bb9 100644 --- a/src/protocol_select/protocol_select_mol.rs +++ b/src/protocol_select/protocol_select_mol.rs @@ -1,4 +1,4 @@ -// Generated by Molecule 0.2.5 +// Generated by Molecule 0.3.1 use molecule::faster_hex::hex_string; use molecule::prelude::{Entity as _, Reader as _}; @@ -62,6 +62,9 @@ impl molecule::prelude::Entity for String { fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { StringReader::from_slice(slice).map(|reader| reader.to_entity()) } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + StringReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } fn new_builder() -> Self::Builder { ::std::default::Default::default() } @@ -113,7 +116,7 @@ impl<'r> molecule::prelude::Reader<'r> for StringReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8]) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::error::VerificationError; let len = slice.len(); if len < 4 { @@ -280,6 +283,9 @@ impl molecule::prelude::Entity for StringVec { fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { StringVecReader::from_slice(slice).map(|reader| reader.to_entity()) } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + StringVecReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } fn new_builder() -> Self::Builder { ::std::default::Default::default() } @@ -346,7 +352,7 @@ impl<'r> molecule::prelude::Reader<'r> for StringVecReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8]) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::error::VerificationError; let len = slice.len(); if len < 4 { @@ -393,7 +399,7 @@ impl<'r> molecule::prelude::Reader<'r> for StringVecReader<'r> { for i in 0..=(offsets.len() - 2) { let start = offsets[i]; let end = offsets[i + 1]; - StringReader::verify(&slice[start..end])?; + StringReader::verify(&slice[start..end], _compatible)?; } Ok(()) } @@ -609,6 +615,9 @@ impl molecule::prelude::Entity for ProtocolInfo { fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { ProtocolInfoReader::from_slice(slice).map(|reader| reader.to_entity()) } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + ProtocolInfoReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } fn new_builder() -> Self::Builder { ::std::default::Default::default() } @@ -631,6 +640,10 @@ impl ProtocolInfo { let count = (first - 4) / 4; (bytes_len, count, &ptr[1..]) } + pub fn has_extra_fields(&self) -> bool { + let (_, real_fields_count, _) = Self::field_offsets(self); + Self::FIELD_COUNT == real_fields_count + } pub fn name(&self) -> String { let (_, _, offsets) = Self::field_offsets(self); let start = u32::from_le(offsets[0]) as usize; @@ -659,7 +672,7 @@ impl<'r> molecule::prelude::Reader<'r> for ProtocolInfoReader<'r> { fn as_slice(&self) -> &'r [u8] { self.0 } - fn verify(slice: &[u8]) -> molecule::error::VerificationResult<()> { + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { use molecule::error::VerificationError; let len = slice.len(); if len < 4 { @@ -681,22 +694,53 @@ impl<'r> molecule::prelude::Reader<'r> for ProtocolInfoReader<'r> { VerificationError::HeaderIsBroken(Self::NAME.to_owned(), expected, total_size); Err(err)?; } - let mut offsets: Vec = ptr[1..=2] + let offset_first = u32::from_le(ptr[1]) as usize; + if offset_first % 4 != 0 { + let err = VerificationError::FirstOffsetIsBroken(Self::NAME.to_owned(), offset_first); + Err(err)?; + } + if offset_first < expected { + let err = VerificationError::FirstOffsetIsShort( + Self::NAME.to_owned(), + expected, + offset_first, + ); + Err(err)?; + } + let real_field_count = if compatible { + let real_field_count = offset_first / 4 - 1; + let real_expected = 4 + 4 * real_field_count; + if total_size < real_expected { + let err = VerificationError::DataIsShort( + Self::NAME.to_owned(), + real_expected, + total_size, + ); + Err(err)?; + } + real_field_count + } else { + if offset_first > expected { + let err = VerificationError::FirstOffsetIsOverflow( + Self::NAME.to_owned(), + expected, + offset_first, + ); + Err(err)?; + } + 2 + }; + let mut offsets: Vec = ptr[1..=real_field_count] .iter() .map(|x| u32::from_le(*x) as usize) .collect(); - if offsets[0] != expected { - let err = - VerificationError::FirstOffsetIsShort(Self::NAME.to_owned(), expected, offsets[0]); - Err(err)?; - } offsets.push(total_size); if offsets.windows(2).any(|i| i[0] > i[1]) { let err = VerificationError::OffsetsNotMatch(Self::NAME.to_owned()); Err(err)?; } - StringReader::verify(&slice[offsets[0]..offsets[1]])?; - StringVecReader::verify(&slice[offsets[1]..offsets[2]])?; + StringReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + StringVecReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; Ok(()) } } @@ -710,6 +754,10 @@ impl<'r> ProtocolInfoReader<'r> { let count = (first - 4) / 4; (bytes_len, count, &ptr[1..]) } + pub fn has_extra_fields(&self) -> bool { + let (_, real_fields_count, _) = Self::field_offsets(self); + Self::FIELD_COUNT == real_fields_count + } pub fn name(&self) -> StringReader<'r> { let (_, _, offsets) = Self::field_offsets(self); let start = u32::from_le(offsets[0]) as usize;