-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Quic ietf 4967 v3 #7095
Quic ietf 4967 v3 #7095
Changes from all commits
e2fa104
be45f19
b1a67ff
f96956f
a24304b
0c9d9e1
d5ba17e
f9a89f5
065f1ae
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,7 @@ | |
*/ | ||
|
||
use super::error::QuicError; | ||
use crate::quic::parser::quic_var_uint; | ||
use nom::bytes::complete::take; | ||
use nom::combinator::{all_consuming, complete}; | ||
use nom::multi::{count, many0}; | ||
|
@@ -24,6 +25,13 @@ use nom::sequence::pair; | |
use nom::IResult; | ||
use num::FromPrimitive; | ||
use std::fmt; | ||
use std::fmt::Write; | ||
use tls_parser::TlsMessage::Handshake; | ||
use tls_parser::TlsMessageHandshake::{ClientHello, ServerHello}; | ||
use tls_parser::{ | ||
parse_tls_extensions, parse_tls_message_handshake, TlsCipherSuiteID, TlsExtension, | ||
TlsExtensionType, | ||
}; | ||
|
||
/// Tuple of StreamTag and offset | ||
type TagOffset = (StreamTag, u32); | ||
|
@@ -115,13 +123,210 @@ impl fmt::Display for StreamTag { | |
} | ||
} | ||
|
||
#[derive(Debug, PartialEq)] | ||
pub(crate) struct Ack { | ||
pub largest_acknowledged: u64, | ||
pub ack_delay: u64, | ||
pub ack_range_count: u64, | ||
pub first_ack_range: u64, | ||
} | ||
|
||
#[derive(Debug, PartialEq)] | ||
pub(crate) struct Crypto { | ||
pub ciphers: Vec<TlsCipherSuiteID>, | ||
pub extv: Vec<QuicTlsExtension>, | ||
//does not work, because of lifetime due to references to the slice used for parsing | ||
//and cannot manage to create a stucture with the Vector the slices refer to... | ||
//pub exts: Vec<TlsExtension>, | ||
pub ja3: String, | ||
} | ||
|
||
#[derive(Debug, PartialEq)] | ||
pub(crate) enum Frame { | ||
Padding, | ||
Ack(Ack), | ||
Crypto(Crypto), | ||
Stream(Stream), | ||
Unknown(Vec<u8>), | ||
} | ||
|
||
fn parse_ack_frame(input: &[u8]) -> IResult<&[u8], Frame, QuicError> { | ||
let (rest, largest_acknowledged) = quic_var_uint(input)?; | ||
let (rest, ack_delay) = quic_var_uint(rest)?; | ||
let (rest, ack_range_count) = quic_var_uint(rest)?; | ||
let (rest, first_ack_range) = quic_var_uint(rest)?; | ||
|
||
if ack_range_count != 0 { | ||
//TODO RFC9000 section 19.3.1. ACK Ranges | ||
return Err(nom::Err::Error(QuicError::NotSupported)); | ||
} | ||
|
||
Ok(( | ||
rest, | ||
Frame::Ack(Ack { | ||
largest_acknowledged, | ||
ack_delay, | ||
ack_range_count, | ||
first_ack_range, | ||
}), | ||
)) | ||
} | ||
|
||
#[derive(Clone, Debug, PartialEq)] | ||
pub struct QuicTlsExtension { | ||
pub etype: TlsExtensionType, | ||
pub values: Vec<Vec<u8>>, | ||
} | ||
|
||
// get interesting stuff out of parsed tls extensions | ||
fn quic_get_tls_extensions( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could this func be done in a more compact way? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. more compact with Jason advice |
||
input: Option<&[u8]>, ja3: &mut String, client: bool, | ||
) -> Vec<QuicTlsExtension> { | ||
let mut extv = Vec::new(); | ||
if let Some(extr) = input { | ||
if let Ok((_, exts)) = parse_tls_extensions(extr) { | ||
let mut dash = false; | ||
for e in &exts { | ||
let etype = TlsExtensionType::from(e); | ||
if dash { | ||
match write!(ja3, "-") { | ||
_ => {} | ||
} | ||
} else { | ||
dash = true; | ||
} | ||
match write!(ja3, "{}", u16::from(etype)) { | ||
_ => {} | ||
} | ||
Comment on lines
+198
to
+200
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The idiomatic way to avoid the result warning is:
|
||
let mut values = Vec::new(); | ||
match e { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can this be broken out into a util func? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jasonish is there a better rustier way to build a string and write integer into it ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You could do
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you Jason, looks better indeed |
||
TlsExtension::SNI(x) => { | ||
for sni in x { | ||
let mut value = Vec::new(); | ||
value.extend_from_slice(sni.1); | ||
values.push(value); | ||
} | ||
} | ||
TlsExtension::ALPN(x) => { | ||
for alpn in x { | ||
let mut value = Vec::new(); | ||
value.extend_from_slice(alpn); | ||
values.push(value); | ||
} | ||
} | ||
_ => {} | ||
} | ||
extv.push(QuicTlsExtension { etype, values }) | ||
} | ||
if client { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. perhaps move this into a client specific util func There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok |
||
match write!(ja3, ",") { | ||
_ => {} | ||
} | ||
dash = false; | ||
for e in &exts { | ||
match e { | ||
TlsExtension::EllipticCurves(x) => { | ||
for ec in x { | ||
if dash { | ||
match write!(ja3, "-") { | ||
_ => {} | ||
} | ||
} else { | ||
dash = true; | ||
} | ||
match write!(ja3, "{}", ec.0) { | ||
_ => {} | ||
} | ||
} | ||
} | ||
_ => {} | ||
} | ||
} | ||
match write!(ja3, ",") { | ||
_ => {} | ||
} | ||
dash = false; | ||
for e in &exts { | ||
match e { | ||
TlsExtension::EcPointFormats(x) => { | ||
for ec in *x { | ||
if dash { | ||
match write!(ja3, "-") { | ||
_ => {} | ||
} | ||
} else { | ||
dash = true; | ||
} | ||
match write!(ja3, "{}", ec) { | ||
_ => {} | ||
} | ||
} | ||
} | ||
_ => {} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
return extv; | ||
} | ||
|
||
fn parse_crypto_frame(input: &[u8]) -> IResult<&[u8], Frame, QuicError> { | ||
let (rest, offset) = quic_var_uint(input)?; | ||
let (rest, length) = quic_var_uint(rest)?; | ||
let (rest, _) = take(offset as usize)(rest)?; | ||
let (_, data) = take(length as usize)(rest)?; | ||
|
||
if let Ok((rest, msg)) = parse_tls_message_handshake(data) { | ||
if let Handshake(hs) = msg { | ||
match hs { | ||
ClientHello(ch) => { | ||
let mut ja3 = String::with_capacity(256); | ||
match write!(&mut ja3, "{},", u16::from(ch.version)) { | ||
_ => {} | ||
} | ||
let mut dash = false; | ||
for c in &ch.ciphers { | ||
if dash { | ||
match write!(&mut ja3, "-") { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. these kinds of statements are taking 3 lines each for no good reason. Can these be made more compact? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
(noted above already) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
_ => {} | ||
} | ||
} else { | ||
dash = true; | ||
} | ||
match write!(&mut ja3, "{}", u16::from(*c)) { | ||
_ => {} | ||
} | ||
} | ||
match write!(&mut ja3, ",") { | ||
_ => {} | ||
} | ||
let ciphers = ch.ciphers; | ||
let extv = quic_get_tls_extensions(ch.ext, &mut ja3, true); | ||
return Ok((rest, Frame::Crypto(Crypto { ciphers, extv, ja3 }))); | ||
} | ||
ServerHello(sh) => { | ||
let mut ja3 = String::with_capacity(256); | ||
match write!(&mut ja3, "{},", u16::from(sh.version)) { | ||
_ => {} | ||
} | ||
match write!(&mut ja3, "{}", u16::from(sh.cipher)) { | ||
_ => {} | ||
} | ||
match write!(&mut ja3, ",") { | ||
_ => {} | ||
} | ||
let ciphers = vec![sh.cipher]; | ||
let extv = quic_get_tls_extensions(sh.ext, &mut ja3, false); | ||
return Ok((rest, Frame::Crypto(Crypto { ciphers, extv, ja3 }))); | ||
} | ||
_ => {} | ||
} | ||
} | ||
} | ||
return Err(nom::Err::Error(QuicError::InvalidPacket)); | ||
} | ||
|
||
fn parse_tag(input: &[u8]) -> IResult<&[u8], StreamTag, QuicError> { | ||
let (rest, tag) = be_u32(input)?; | ||
|
||
|
@@ -164,8 +369,6 @@ fn parse_crypto_stream(input: &[u8]) -> IResult<&[u8], Vec<TagValue>, QuicError> | |
} | ||
|
||
fn parse_stream_frame(input: &[u8], frame_ty: u8) -> IResult<&[u8], Frame, QuicError> { | ||
let rest = input; | ||
|
||
// 0b1_f_d_ooo_ss | ||
let fin = frame_ty & 0x40 == 0x40; | ||
let has_data_length = frame_ty & 0x20 == 0x20; | ||
|
@@ -180,7 +383,7 @@ fn parse_stream_frame(input: &[u8], frame_ty: u8) -> IResult<&[u8], Frame, QuicE | |
|
||
let stream_id_hdr_length = usize::from((frame_ty & 0x03) + 1); | ||
|
||
let (rest, stream_id) = take(stream_id_hdr_length)(rest)?; | ||
let (rest, stream_id) = take(stream_id_hdr_length)(input)?; | ||
let (rest, offset) = take(offset_hdr_length)(rest)?; | ||
|
||
let (rest, data_length) = if has_data_length { | ||
|
@@ -221,6 +424,8 @@ impl Frame { | |
} else { | ||
match frame_ty { | ||
0x00 => (rest, Frame::Padding), | ||
0x02 => parse_ack_frame(rest)?, | ||
0x06 => parse_crypto_frame(rest)?, | ||
_ => ([].as_ref(), Frame::Unknown(rest.to_vec())), | ||
} | ||
}; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can this comment move to
extv
just above and explain why it is like this instead of usingVec<TlsExtension>
? Comments about why code that is in use are like they are, are more useful than comments explaining commented out things, I think.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok