use crate::error::{InvalidReason, ParseError};
use crate::types::{SslClientFlags, SslInfo, Tlvs};
fn bytes_to_string(bytes: &[u8]) -> String {
match std::str::from_utf8(bytes) {
Ok(s) => s.to_owned(),
Err(_) => String::from_utf8_lossy(bytes).into_owned(),
}
}
pub(crate) fn parse_tlvs(mut data: &[u8]) -> Result<Tlvs, ParseError> {
let mut tlvs = Tlvs::default();
let mut offset = 0;
while !data.is_empty() {
if data.len() < 3 {
return Err(ParseError::Invalid(InvalidReason::MalformedTlv { offset }));
}
let tlv_type = data[0];
let tlv_len = u16::from_be_bytes([data[1], data[2]]) as usize;
if data.len() < 3 + tlv_len {
return Err(ParseError::Invalid(InvalidReason::MalformedTlv { offset }));
}
let value = &data[3..3 + tlv_len];
tlvs.raw.push((tlv_type, value.to_vec()));
match tlv_type {
0x01 => {
tlvs.alpn = Some(value.to_vec());
}
0x02 => {
tlvs.authority = Some(bytes_to_string(value));
}
0x03 => {
if tlv_len != 4 {
return Err(ParseError::Invalid(InvalidReason::MalformedTlv { offset }));
}
let bytes = <[u8; 4]>::try_from(value).unwrap();
tlvs.crc32c = Some(u32::from_be_bytes(bytes));
}
0x04 => {}
0x05 => {
if tlv_len > 128 {
return Err(ParseError::Invalid(InvalidReason::MalformedTlv { offset }));
}
tlvs.unique_id = Some(value.to_vec());
}
0x20 => {
if tlv_len < 5 {
return Err(ParseError::Invalid(InvalidReason::MalformedTlv { offset }));
}
tlvs.ssl = Some(parse_ssl(value, offset + 3)?);
}
0x30 => {
tlvs.netns = Some(bytes_to_string(value));
}
_ => {}
}
data = &data[3 + tlv_len..];
offset += 3 + tlv_len;
}
Ok(tlvs)
}
fn parse_ssl(data: &[u8], outer_offset: usize) -> Result<SslInfo, ParseError> {
let client_byte = data[0];
let verify = u32::from_be_bytes([data[1], data[2], data[3], data[4]]);
let client_flags = SslClientFlags::from_bits_truncate(client_byte);
let verified = verify == 0;
let mut ssl = SslInfo {
client_flags,
verified,
..Default::default()
};
let mut sub_data = &data[5..];
let mut sub_offset = outer_offset + 5;
while !sub_data.is_empty() {
if sub_data.len() < 3 {
return Err(ParseError::Invalid(InvalidReason::MalformedTlv {
offset: sub_offset,
}));
}
let sub_type = sub_data[0];
let sub_len = u16::from_be_bytes([sub_data[1], sub_data[2]]) as usize;
if sub_data.len() < 3 + sub_len {
return Err(ParseError::Invalid(InvalidReason::MalformedTlv {
offset: sub_offset,
}));
}
let sub_value = &sub_data[3..3 + sub_len];
match sub_type {
0x21 => ssl.version = Some(bytes_to_string(sub_value)),
0x22 => ssl.cn = Some(bytes_to_string(sub_value)),
0x23 => ssl.cipher = Some(bytes_to_string(sub_value)),
0x24 => ssl.sig_alg = Some(bytes_to_string(sub_value)),
0x25 => ssl.key_alg = Some(bytes_to_string(sub_value)),
0x26 => ssl.group = Some(bytes_to_string(sub_value)),
0x27 => ssl.sig_scheme = Some(bytes_to_string(sub_value)),
0x28 => ssl.client_cert = Some(sub_value.to_vec()),
_ => {}
}
sub_data = &sub_data[3 + sub_len..];
sub_offset += 3 + sub_len;
}
Ok(ssl)
}