mirror of
https://github.com/n0-computer/noq.git
synced 2026-09-20 02:04:07 +00:00
Factor out common connection ID encode/decode logic
This commit is contained in:
committed by
Dirkjan Ochtman
parent
47dad2292e
commit
f2178ff91c
+15
-36
@@ -5,9 +5,7 @@ use err_derive::Error;
|
||||
|
||||
use crate::{
|
||||
coding::{self, BufExt, BufMutExt},
|
||||
crypto,
|
||||
shared::ConnectionId,
|
||||
MAX_CID_SIZE, VERSION,
|
||||
crypto, ConnectionId, VERSION,
|
||||
};
|
||||
|
||||
// Due to packet number encryption, it is impossible to fully decode a header
|
||||
@@ -261,7 +259,8 @@ impl Header {
|
||||
} => {
|
||||
w.write(u8::from(LongHeaderType::Initial) | number.tag());
|
||||
w.write(VERSION);
|
||||
Self::encode_cids(w, dst_cid, src_cid);
|
||||
dst_cid.encode_long(w);
|
||||
src_cid.encode_long(w);
|
||||
w.write_var(token.len() as u64);
|
||||
w.put_slice(token);
|
||||
w.write::<u16>(0); // Placeholder for payload length; see `set_payload_length`
|
||||
@@ -280,7 +279,8 @@ impl Header {
|
||||
} => {
|
||||
w.write(u8::from(LongHeaderType::Standard(ty)) | number.tag());
|
||||
w.write(VERSION);
|
||||
Self::encode_cids(w, dst_cid, src_cid);
|
||||
dst_cid.encode_long(w);
|
||||
src_cid.encode_long(w);
|
||||
w.write::<u16>(0); // Placeholder for payload length; see `set_payload_length`
|
||||
number.encode(w);
|
||||
PartialEncode {
|
||||
@@ -295,7 +295,8 @@ impl Header {
|
||||
} => {
|
||||
w.write(u8::from(LongHeaderType::Retry));
|
||||
w.write(VERSION);
|
||||
Self::encode_cids(w, dst_cid, src_cid);
|
||||
dst_cid.encode_long(w);
|
||||
src_cid.encode_long(w);
|
||||
PartialEncode {
|
||||
start,
|
||||
header_len: w.len() - start,
|
||||
@@ -329,7 +330,8 @@ impl Header {
|
||||
} => {
|
||||
w.write(0x80u8 | random);
|
||||
w.write::<u32>(0);
|
||||
Self::encode_cids(w, dst_cid, src_cid);
|
||||
dst_cid.encode_long(w);
|
||||
src_cid.encode_long(w);
|
||||
PartialEncode {
|
||||
start,
|
||||
header_len: w.len() - start,
|
||||
@@ -339,13 +341,6 @@ impl Header {
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_cids<W: BufMut>(w: &mut W, dst_cid: &ConnectionId, src_cid: &ConnectionId) {
|
||||
w.put_u8(dst_cid.len() as u8);
|
||||
w.put_slice(dst_cid);
|
||||
w.put_u8(src_cid.len() as u8);
|
||||
w.put_slice(src_cid);
|
||||
}
|
||||
|
||||
/// Whether the packet is encrypted on the wire
|
||||
pub(crate) fn is_protected(&self) -> bool {
|
||||
match *self {
|
||||
@@ -519,7 +514,8 @@ impl PlainHeader {
|
||||
let first = buf.get::<u8>()?;
|
||||
if first & LONG_HEADER_FORM == 0 {
|
||||
let spin = first & SPIN_BIT != 0;
|
||||
let dst_cid = Self::get_cid(buf, local_cid_len)?;
|
||||
let dst_cid = ConnectionId::new(&buf.bytes()[..local_cid_len]);
|
||||
buf.advance(local_cid_len);
|
||||
|
||||
Ok(PlainHeader::Short {
|
||||
first,
|
||||
@@ -529,11 +525,10 @@ impl PlainHeader {
|
||||
} else {
|
||||
let version = buf.get::<u32>()?;
|
||||
|
||||
let dcil = buf.get::<u8>()? as usize;
|
||||
let dst_cid = Self::get_cid(buf, dcil)?;
|
||||
|
||||
let scil = buf.get::<u8>()? as usize;
|
||||
let src_cid = Self::get_cid(buf, scil)?;
|
||||
let dst_cid = ConnectionId::decode_long(buf)
|
||||
.ok_or(PacketDecodeError::InvalidHeader("malformed cid"))?;
|
||||
let src_cid = ConnectionId::decode_long(buf)
|
||||
.ok_or(PacketDecodeError::InvalidHeader("malformed cid"))?;
|
||||
|
||||
// TODO: Support long CIDs for compatibility with future QUIC versions
|
||||
if version == 0 {
|
||||
@@ -576,22 +571,6 @@ impl PlainHeader {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_cid<R: Buf>(buf: &mut R, len: usize) -> Result<ConnectionId, PacketDecodeError> {
|
||||
if len > MAX_CID_SIZE {
|
||||
return Err(PacketDecodeError::InvalidHeader(
|
||||
"illegal connection ID length",
|
||||
));
|
||||
}
|
||||
if buf.remaining() < len {
|
||||
return Err(PacketDecodeError::InvalidHeader(
|
||||
"connection ID longer than packet",
|
||||
));
|
||||
}
|
||||
let cid = ConnectionId::new(&buf.bytes()[..len]);
|
||||
buf.advance(len);
|
||||
Ok(cid)
|
||||
}
|
||||
}
|
||||
|
||||
// An encoded packet number
|
||||
|
||||
@@ -4,13 +4,12 @@ use std::{
|
||||
time::{Duration, SystemTime, UNIX_EPOCH},
|
||||
};
|
||||
|
||||
use bytes::{Buf, BufMut};
|
||||
use bytes::BufMut;
|
||||
|
||||
use crate::{
|
||||
coding::{BufExt, BufMutExt},
|
||||
crypto::HmacKey,
|
||||
shared::ConnectionId,
|
||||
MAX_CID_SIZE,
|
||||
};
|
||||
|
||||
// TODO: Use AEAD to hide token details from clients for better stability guarantees:
|
||||
@@ -29,18 +28,15 @@ impl RetryToken {
|
||||
pub fn encode(&self, key: &impl HmacKey, address: &SocketAddr) -> Vec<u8> {
|
||||
let mut buf = Vec::new();
|
||||
|
||||
buf.write(self.src_cid.len() as u8);
|
||||
buf.put_slice(&self.src_cid);
|
||||
|
||||
buf.write(self.dst_cid.len() as u8);
|
||||
buf.put_slice(&self.dst_cid);
|
||||
|
||||
self.src_cid.encode_long(&mut buf);
|
||||
self.dst_cid.encode_long(&mut buf);
|
||||
buf.write::<u64>(
|
||||
self.issued
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.map(|x| x.as_secs())
|
||||
.unwrap_or(0),
|
||||
);
|
||||
|
||||
let signature_pos = buf.len();
|
||||
match address.ip() {
|
||||
IpAddr::V4(x) => buf.put_slice(&x.octets()),
|
||||
@@ -56,23 +52,12 @@ impl RetryToken {
|
||||
|
||||
pub fn from_bytes(key: &impl HmacKey, address: &SocketAddr, data: &[u8]) -> Result<Self, ()> {
|
||||
let mut reader = io::Cursor::new(data);
|
||||
let src_cid_len = reader.get::<u8>().map_err(|_| ())? as usize;
|
||||
if src_cid_len > reader.remaining() || src_cid_len > MAX_CID_SIZE {
|
||||
return Err(());
|
||||
}
|
||||
let src_cid = ConnectionId::new(&reader.bytes()[..src_cid_len]);
|
||||
reader.advance(src_cid_len);
|
||||
|
||||
let dst_cid_len = reader.get::<u8>().map_err(|_| ())? as usize;
|
||||
if dst_cid_len > reader.remaining() || dst_cid_len > MAX_CID_SIZE {
|
||||
return Err(());
|
||||
}
|
||||
let dst_cid = ConnectionId::new(&reader.bytes()[..dst_cid_len]);
|
||||
reader.advance(dst_cid_len);
|
||||
|
||||
let src_cid = ConnectionId::decode_long(&mut reader).ok_or(())?;
|
||||
let dst_cid = ConnectionId::decode_long(&mut reader).ok_or(())?;
|
||||
let issued = UNIX_EPOCH + Duration::new(reader.get::<u64>().map_err(|_| ())?, 0);
|
||||
let signature_start = reader.position() as usize;
|
||||
|
||||
let signature_start = reader.position() as usize;
|
||||
let mut buf = Vec::new();
|
||||
buf.put_slice(&data[0..signature_start]);
|
||||
match address.ip() {
|
||||
@@ -96,6 +81,7 @@ mod test {
|
||||
#[test]
|
||||
fn token_sanity() {
|
||||
use super::*;
|
||||
use crate::MAX_CID_SIZE;
|
||||
use rand::RngCore;
|
||||
use ring::hmac;
|
||||
use std::{
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use std::{cmp, fmt, net::SocketAddr, time::Instant};
|
||||
|
||||
use bytes::BytesMut;
|
||||
use bytes::{Buf, BufMut, BytesMut};
|
||||
use rand::Rng;
|
||||
|
||||
use crate::{packet::PartialDecode, MAX_CID_SIZE, RESET_TOKEN_SIZE};
|
||||
use crate::{coding::BufExt, packet::PartialDecode, MAX_CID_SIZE, RESET_TOKEN_SIZE};
|
||||
|
||||
/// Events sent from an Endpoint to a Connection
|
||||
#[derive(Debug)]
|
||||
@@ -87,6 +87,23 @@ impl ConnectionId {
|
||||
res.bytes[..len].clone_from_slice(&rng_bytes[..len]);
|
||||
res
|
||||
}
|
||||
|
||||
/// Decode from long header format
|
||||
pub(crate) fn decode_long(buf: &mut impl Buf) -> Option<Self> {
|
||||
let len = buf.get::<u8>().ok()? as usize;
|
||||
if len > MAX_CID_SIZE || buf.remaining() < len {
|
||||
return None;
|
||||
}
|
||||
let cid = ConnectionId::new(&buf.bytes()[..len]);
|
||||
buf.advance(len);
|
||||
Some(cid)
|
||||
}
|
||||
|
||||
/// Encode in long header format
|
||||
pub(crate) fn encode_long(&self, buf: &mut impl BufMut) {
|
||||
buf.put_u8(self.len() as u8);
|
||||
buf.put_slice(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::Deref for ConnectionId {
|
||||
|
||||
Reference in New Issue
Block a user