|
|
@ -39,13 +39,15 @@ pub struct QuicTransaction {
|
|
|
|
pub sni: Option<Vec<u8>>,
|
|
|
|
pub sni: Option<Vec<u8>>,
|
|
|
|
pub ua: Option<Vec<u8>>,
|
|
|
|
pub ua: Option<Vec<u8>>,
|
|
|
|
pub extv: Vec<QuicTlsExtension>,
|
|
|
|
pub extv: Vec<QuicTlsExtension>,
|
|
|
|
|
|
|
|
pub ja3: Option<String>,
|
|
|
|
|
|
|
|
pub client: bool,
|
|
|
|
tx_data: AppLayerTxData,
|
|
|
|
tx_data: AppLayerTxData,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl QuicTransaction {
|
|
|
|
impl QuicTransaction {
|
|
|
|
fn new(
|
|
|
|
fn new(
|
|
|
|
header: QuicHeader, data: QuicData, sni: Option<Vec<u8>>, ua: Option<Vec<u8>>,
|
|
|
|
header: QuicHeader, data: QuicData, sni: Option<Vec<u8>>, ua: Option<Vec<u8>>,
|
|
|
|
extv: Vec<QuicTlsExtension>,
|
|
|
|
extv: Vec<QuicTlsExtension>, ja3: Option<String>, client: bool,
|
|
|
|
) -> Self {
|
|
|
|
) -> Self {
|
|
|
|
let cyu = Cyu::generate(&header, &data.frames);
|
|
|
|
let cyu = Cyu::generate(&header, &data.frames);
|
|
|
|
QuicTransaction {
|
|
|
|
QuicTransaction {
|
|
|
@ -55,6 +57,8 @@ impl QuicTransaction {
|
|
|
|
sni,
|
|
|
|
sni,
|
|
|
|
ua,
|
|
|
|
ua,
|
|
|
|
extv,
|
|
|
|
extv,
|
|
|
|
|
|
|
|
ja3,
|
|
|
|
|
|
|
|
client,
|
|
|
|
tx_data: AppLayerTxData::new(),
|
|
|
|
tx_data: AppLayerTxData::new(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -102,9 +106,9 @@ impl QuicState {
|
|
|
|
|
|
|
|
|
|
|
|
fn new_tx(
|
|
|
|
fn new_tx(
|
|
|
|
&mut self, header: QuicHeader, data: QuicData, sni: Option<Vec<u8>>, ua: Option<Vec<u8>>,
|
|
|
|
&mut self, header: QuicHeader, data: QuicData, sni: Option<Vec<u8>>, ua: Option<Vec<u8>>,
|
|
|
|
extb: Vec<QuicTlsExtension>,
|
|
|
|
extb: Vec<QuicTlsExtension>, ja3: Option<String>, client: bool,
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
let mut tx = QuicTransaction::new(header, data, sni, ua, extb);
|
|
|
|
let mut tx = QuicTransaction::new(header, data, sni, ua, extb, ja3, client);
|
|
|
|
self.max_tx_id += 1;
|
|
|
|
self.max_tx_id += 1;
|
|
|
|
tx.tx_id = self.max_tx_id;
|
|
|
|
tx.tx_id = self.max_tx_id;
|
|
|
|
self.transactions.push(tx);
|
|
|
|
self.transactions.push(tx);
|
|
|
@ -181,6 +185,7 @@ impl QuicState {
|
|
|
|
fn handle_frames(&mut self, data: QuicData, header: QuicHeader, to_server: bool) {
|
|
|
|
fn handle_frames(&mut self, data: QuicData, header: QuicHeader, to_server: bool) {
|
|
|
|
let mut sni: Option<Vec<u8>> = None;
|
|
|
|
let mut sni: Option<Vec<u8>> = None;
|
|
|
|
let mut ua: Option<Vec<u8>> = None;
|
|
|
|
let mut ua: Option<Vec<u8>> = None;
|
|
|
|
|
|
|
|
let mut ja3: Option<String> = None;
|
|
|
|
let mut extv: Vec<QuicTlsExtension> = Vec::new();
|
|
|
|
let mut extv: Vec<QuicTlsExtension> = Vec::new();
|
|
|
|
for frame in &data.frames {
|
|
|
|
for frame in &data.frames {
|
|
|
|
match frame {
|
|
|
|
match frame {
|
|
|
@ -199,6 +204,7 @@ impl QuicState {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Frame::Crypto(c) => {
|
|
|
|
Frame::Crypto(c) => {
|
|
|
|
|
|
|
|
ja3 = Some(c.ja3.clone());
|
|
|
|
for e in &c.extv {
|
|
|
|
for e in &c.extv {
|
|
|
|
if e.etype == TlsExtensionType::ServerName && e.values.len() > 0 {
|
|
|
|
if e.etype == TlsExtensionType::ServerName && e.values.len() > 0 {
|
|
|
|
sni = Some(e.values[0].to_vec());
|
|
|
|
sni = Some(e.values[0].to_vec());
|
|
|
@ -214,7 +220,7 @@ impl QuicState {
|
|
|
|
_ => {}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
self.new_tx(header, data, sni, ua, extv);
|
|
|
|
self.new_tx(header, data, sni, ua, extv, ja3, to_server);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn parse(&mut self, input: &[u8], to_server: bool) -> bool {
|
|
|
|
fn parse(&mut self, input: &[u8], to_server: bool) -> bool {
|
|
|
@ -261,6 +267,8 @@ impl QuicState {
|
|
|
|
None,
|
|
|
|
None,
|
|
|
|
None,
|
|
|
|
None,
|
|
|
|
Vec::new(),
|
|
|
|
Vec::new(),
|
|
|
|
|
|
|
|
None,
|
|
|
|
|
|
|
|
to_server,
|
|
|
|
);
|
|
|
|
);
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|