///|
pub(all) struct SslInfo {
client_flags : Byte
verify : UInt
sub_tlvs : Array[RawTlv]
} derive(Debug)
///|
pub(all) enum ParsedTlv {
Alpn(Bytes)
Authority(String)
Crc32c(UInt)
Noop(Bytes)
UniqueId(Bytes)
Ssl(SslInfo)
Netns(String)
Custom(Byte, Bytes)
Experimental(Byte, Bytes)
FutureReserved(Byte, Bytes)
Unknown(Byte, Bytes)
} derive(Debug)
///|
fn decode_utf8_tlv(
value : Bytes,
offset : Int,
context : String,
) -> Result[String, ProxyError] {
let decoded = Some(@utf8.decode(value, ignore_bom=true)) catch { _ => None }
match decoded {
Some(text) => Ok(text)
None => Err(proxy_error(InvalidTlv, offset, context))
}
}
///|
fn decode_ascii_tlv(
value : Bytes,
offset : Int,
context : String,
) -> Result[String, ProxyError] {
for i = 0; i < value.length(); i = i + 1 {
if value[i].to_int() > 127 {
return Err(proxy_error(InvalidTlv, offset + i, context))
}
}
let chars = Array::make(0, ' ')
for byte in value {
chars.push(byte.to_int().to_char().unwrap())
}
Ok(String::from_array(chars))
}
///|
pub fn interpret_tlv(
tlv : RawTlv,
offset? : Int = 0,
) -> Result[ParsedTlv, ProxyError] {
match tlv.type_code {
TLV_ALPN => Ok(Alpn(tlv.value))
TLV_AUTHORITY =>
match
decode_utf8_tlv(tlv.value, offset + 3, "AUTHORITY must be valid UTF-8") {
Ok(text) => Ok(Authority(text))
Err(err) => Err(err)
}
TLV_CRC32C =>
if tlv.value.length() != 4 {
Err(
proxy_error(InvalidTlv, offset, "CRC32C TLV must contain four bytes"),
)
} else {
Ok(
Crc32c(
(tlv.value[0].to_uint() << 24) |
(tlv.value[1].to_uint() << 16) |
(tlv.value[2].to_uint() << 8) |
tlv.value[3].to_uint(),
),
)
}
TLV_NOOP => Ok(Noop(tlv.value))
TLV_UNIQUE_ID =>
if tlv.value.length() > 128 {
Err(
proxy_error(InvalidTlv, offset, "UNIQUE_ID must be at most 128 bytes"),
)
} else {
Ok(UniqueId(tlv.value))
}
TLV_SSL =>
match parse_ssl_tlv(tlv.value, offset=offset + 3) {
Ok(ssl) =>
Ok(
Ssl({
client_flags: ssl.client_flags,
verify: ssl.verify,
sub_tlvs: ssl.sub_tlvs,
}),
)
Err(err) => Err(err)
}
TLV_NETNS =>
match decode_ascii_tlv(tlv.value, offset + 3, "NETNS must be US-ASCII") {
Ok(text) => Ok(Netns(text))
Err(err) => Err(err)
}
code =>
match classify_tlv_range(code) {
CustomRange => Ok(Custom(code, tlv.value))
ExperimentalRange => Ok(Experimental(code, tlv.value))
FutureReservedRange => Ok(FutureReserved(code, tlv.value))
_ => Ok(Unknown(code, tlv.value))
}
}
}
///|
pub fn interpret_all_tlvs(
tlvs : Array[RawTlv],
) -> Result[Array[ParsedTlv], ProxyError] {
let parsed = Array::make(0, Unknown(b'\x00', Bytes::new(0)))
for tlv in tlvs {
match interpret_tlv(tlv) {
Ok(value) => parsed.push(value)
Err(err) => return Err(err)
}
}
Ok(parsed)
}