Skip to content

Commit 0e32b41

Browse files
committed
(feat/webrtc-sniffer): parse dtls handshake messages
1 parent db7206c commit 0e32b41

File tree

7 files changed

+557
-66
lines changed

7 files changed

+557
-66
lines changed

tools/webrtc-sniffer/src/bin/sniffer.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ fn main() {
109109
if let Some(device) = selected {
110110
log::info!("will use: {device:?}");
111111
let res = Ok(()).and_then(|()| {
112-
let mut capture = Capture::from_device(device)?.open()?;
112+
let mut capture = Capture::from_device(device)?.immediate_mode(true).open()?;
113113
capture
114114
.filter(&filter.unwrap_or_default(), true)
115115
.expect("Failed to apply filter");
@@ -126,7 +126,10 @@ fn main() {
126126
} else {
127127
log::info!("use file");
128128
let res = Ok(()).and_then(|()| {
129-
let capture = Capture::from_file(&path)?;
129+
let mut capture = Capture::from_file(&path)?;
130+
capture
131+
.filter(&filter.unwrap_or_default(), true)
132+
.expect("Failed to apply filter");
130133
webrtc_sniffer::run(capture, None, secret_key)
131134
});
132135
if let Err(err) = res {
Lines changed: 346 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,346 @@
1+
use std::fmt;
2+
3+
use nom::{
4+
bytes::complete::take,
5+
combinator::map,
6+
error::{Error, ErrorKind},
7+
multi::many0,
8+
number::complete::{be_u16, be_u24, be_u8},
9+
Err, IResult, Parser,
10+
};
11+
12+
pub struct HandshakeMessage {
13+
pub length: u32,
14+
pub message_seq: u16,
15+
pub fragment_offset: u32,
16+
pub fragment_length: u32,
17+
pub inner: HandshakeInner,
18+
}
19+
20+
pub enum HandshakeInner {
21+
ClientHello(ClientHello),
22+
ServerHello(ServerHello),
23+
HelloVerifyRequest(HelloVerifyRequest),
24+
Certificates(Certificates),
25+
ServerKeyExchange(ServerKeyExchange),
26+
CertificateRequest(u8),
27+
ServerHelloDone,
28+
CertificateVerify(u8),
29+
ClientKeyExchange(ClientKeyExchange),
30+
Finished,
31+
}
32+
33+
impl fmt::Display for HandshakeInner {
34+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35+
match self {
36+
Self::ClientHello(msg) => write!(f, "ClientHello({msg})"),
37+
Self::ServerHello(msg) => write!(f, "ServerHello({msg})"),
38+
Self::HelloVerifyRequest(msg) => write!(f, "HelloVerifyRequest({msg})"),
39+
Self::Certificates(msg) => write!(f, "Certificates({msg})"),
40+
Self::ServerKeyExchange(msg) => write!(f, "ServerKeyExchange({msg})"),
41+
Self::CertificateRequest(msg) => write!(f, "CertificateRequest({msg})"),
42+
Self::ServerHelloDone => write!(f, "ServerHelloDone"),
43+
Self::CertificateVerify(msg) => write!(f, "CertificateVerify({msg})"),
44+
Self::ClientKeyExchange(msg) => write!(f, "ClientKeyExchange({msg})"),
45+
Self::Finished => write!(f, "Finished"),
46+
}
47+
}
48+
}
49+
50+
impl HandshakeMessage {
51+
pub fn parse(input: &[u8]) -> IResult<&[u8], Self> {
52+
let (input, discriminant) = be_u8(input)?;
53+
let (input, length) = be_u24(input)?;
54+
let (input, message_seq) = be_u16(input)?;
55+
let (input, fragment_offset) = be_u24(input)?;
56+
let (input, fragment_length) = be_u24(input)?;
57+
let (input, inner) = match discriminant {
58+
1 => map(ClientHello::parse, HandshakeInner::ClientHello).parse(input),
59+
2 => map(ServerHello::parse, HandshakeInner::ServerHello).parse(input),
60+
3 => map(
61+
HelloVerifyRequest::parse,
62+
HandshakeInner::HelloVerifyRequest,
63+
)
64+
.parse(input),
65+
11 => map(Certificates::parse, HandshakeInner::Certificates).parse(input),
66+
12 => map(ServerKeyExchange::parse, HandshakeInner::ServerKeyExchange).parse(input),
67+
13 => Ok((input, HandshakeInner::CertificateRequest(0))),
68+
14 => Ok((input, HandshakeInner::ServerHelloDone)),
69+
15 => Ok((input, HandshakeInner::CertificateVerify(0))),
70+
16 => map(ClientKeyExchange::parse, HandshakeInner::ClientKeyExchange).parse(input),
71+
20 => Ok((input, HandshakeInner::Finished)),
72+
_ => Err(Err::Error(Error::new(input, ErrorKind::Alt))),
73+
}?;
74+
Ok((
75+
input,
76+
HandshakeMessage {
77+
length,
78+
message_seq,
79+
fragment_offset,
80+
fragment_length,
81+
inner,
82+
},
83+
))
84+
}
85+
}
86+
87+
pub struct ClientHello {
88+
pub random: [u8; 32],
89+
pub session_id: Vec<u8>,
90+
pub cookie: Vec<u8>,
91+
pub cipher_suites: Vec<u16>,
92+
pub compression_methods: Vec<u8>,
93+
pub extensions: Vec<Extension>,
94+
}
95+
96+
impl fmt::Display for ClientHello {
97+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98+
write!(
99+
f,
100+
"random={}, session_id=\"{}\", cookie=\"{}\", cipher_suites={:?}, compression_methods={:?}",
101+
hex::encode(&self.random),
102+
hex::encode(&self.session_id),
103+
hex::encode(&self.cookie),
104+
self.cipher_suites,
105+
self.compression_methods,
106+
)
107+
}
108+
}
109+
110+
impl ClientHello {
111+
fn parse(input: &[u8]) -> IResult<&[u8], Self> {
112+
let (input, legacy_record_version) = be_u16(input)?;
113+
if legacy_record_version != 0xFEFD {
114+
return Err(Err::Error(Error::new(input, ErrorKind::Alt)));
115+
}
116+
let (input, random) = take(32usize)(input)?;
117+
let random = <[u8; 32]>::try_from(random).expect("cannot fail");
118+
let (input, l) = be_u8(input)?;
119+
let (input, bytes) = take(l as usize)(input)?;
120+
let session_id = bytes.to_vec();
121+
let (input, l) = be_u8(input)?;
122+
let (input, bytes) = take(l as usize)(input)?;
123+
let cookie = bytes.to_vec();
124+
let (input, l) = be_u16(input)?;
125+
let (input, bytes) = take(l as usize)(input)?;
126+
let (_, cipher_suites) = many0(be_u16).parse(bytes)?;
127+
let (input, compression_methods_len) = be_u8(input)?;
128+
let (input, bytes) = take(compression_methods_len as usize)(input)?;
129+
let compression_methods = bytes.to_vec();
130+
let (input, l) = be_u16(input)?;
131+
let (input, bytes) = take(l as usize)(input)?;
132+
let (_, extensions) = many0(Extension::parse).parse(bytes)?;
133+
134+
Ok((
135+
input,
136+
ClientHello {
137+
random,
138+
session_id,
139+
cookie,
140+
cipher_suites,
141+
compression_methods,
142+
extensions,
143+
},
144+
))
145+
}
146+
}
147+
148+
pub struct ServerHello {
149+
pub random: [u8; 32],
150+
pub session_id: Vec<u8>,
151+
pub cipher_suite: u16,
152+
pub compression_method: u8,
153+
pub extensions: Vec<Extension>,
154+
}
155+
156+
impl fmt::Display for ServerHello {
157+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158+
write!(
159+
f,
160+
"random={}, session_id=\"{}\", cipher_suite={}, compression_method={}",
161+
hex::encode(&self.random),
162+
hex::encode(&self.session_id),
163+
self.cipher_suite,
164+
self.compression_method,
165+
)
166+
}
167+
}
168+
169+
impl ServerHello {
170+
fn parse(input: &[u8]) -> IResult<&[u8], Self> {
171+
let (input, legacy_record_version) = be_u16(input)?;
172+
if legacy_record_version != 0xFEFD {
173+
return Err(Err::Error(Error::new(input, ErrorKind::Alt)));
174+
}
175+
let (input, random) = take(32usize)(input)?;
176+
let random = <[u8; 32]>::try_from(random).expect("cannot fail");
177+
let (input, l) = be_u8(input)?;
178+
let (input, bytes) = take(l as usize)(input)?;
179+
let session_id = bytes.to_vec();
180+
let (input, cipher_suite) = be_u16(input)?;
181+
let (input, compression_method) = be_u8(input)?;
182+
let (input, l) = be_u16(input)?;
183+
let (input, bytes) = take(l as usize)(input)?;
184+
let (_, extensions) = many0(Extension::parse).parse(bytes)?;
185+
186+
Ok((
187+
input,
188+
ServerHello {
189+
random,
190+
session_id,
191+
cipher_suite,
192+
compression_method,
193+
extensions,
194+
},
195+
))
196+
}
197+
}
198+
199+
pub struct HelloVerifyRequest {
200+
pub cookie: Vec<u8>,
201+
}
202+
203+
impl fmt::Display for HelloVerifyRequest {
204+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
205+
write!(f, "cookie={}", hex::encode(&self.cookie),)
206+
}
207+
}
208+
209+
impl HelloVerifyRequest {
210+
fn parse(input: &[u8]) -> IResult<&[u8], Self> {
211+
let (input, legacy_record_version) = be_u16(input)?;
212+
if legacy_record_version != 0xFEFD {
213+
return Err(Err::Error(Error::new(input, ErrorKind::Alt)));
214+
}
215+
216+
let (input, l) = be_u8(input)?;
217+
let (input, bytes) = take(l as usize)(input)?;
218+
let cookie = bytes.to_vec();
219+
220+
Ok((input, HelloVerifyRequest { cookie }))
221+
}
222+
}
223+
224+
pub struct Extension {}
225+
226+
impl Extension {
227+
fn parse(input: &[u8]) -> IResult<&[u8], Self> {
228+
let _ = be_u8(input)?;
229+
Ok((&[], Extension {}))
230+
}
231+
}
232+
233+
pub struct Certificates(pub Vec<Certificate>);
234+
235+
impl fmt::Display for Certificates {
236+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
237+
for certificate in &self.0 {
238+
write!(f, "certificate({certificate})")?;
239+
}
240+
Ok(())
241+
}
242+
}
243+
244+
impl Certificates {
245+
fn parse(input: &[u8]) -> IResult<&[u8], Self> {
246+
let (input, length) = be_u24(input)?;
247+
let (input, bytes) = take(length as usize)(input)?;
248+
let (_, certificates) = many0(Certificate::parse).parse(bytes)?;
249+
Ok((input, Certificates(certificates)))
250+
}
251+
}
252+
253+
pub struct Certificate {
254+
pub data: Vec<u8>,
255+
}
256+
257+
impl fmt::Display for Certificate {
258+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
259+
write!(f, "{}", hex::encode(&self.data))
260+
}
261+
}
262+
263+
impl Certificate {
264+
fn parse(input: &[u8]) -> IResult<&[u8], Self> {
265+
let (input, length) = be_u24(input)?;
266+
let (input, bytes) = take(length as usize)(input)?;
267+
let data = bytes.to_vec();
268+
269+
Ok((input, Certificate { data }))
270+
}
271+
}
272+
273+
pub struct ServerKeyExchange {
274+
// pub curve_type: u8,
275+
pub curve_name: u16,
276+
pub public_key: Vec<u8>,
277+
pub signature_hash_algorithm: u8,
278+
pub signature_algorithm: u8,
279+
pub signature: Vec<u8>,
280+
}
281+
282+
impl fmt::Display for ServerKeyExchange {
283+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
284+
write!(
285+
f,
286+
"curve_name={}, pk={}, sig_alg=({},{}), sig={}",
287+
self.curve_name,
288+
hex::encode(&self.public_key),
289+
self.signature_hash_algorithm,
290+
self.signature_algorithm,
291+
hex::encode(&self.signature)
292+
)
293+
}
294+
}
295+
296+
impl ServerKeyExchange {
297+
fn parse(input: &[u8]) -> IResult<&[u8], Self> {
298+
let (input, curve_type) = be_u8(input)?;
299+
if curve_type != 3 {
300+
return Err(Err::Failure(Error::new(input, ErrorKind::Alt)));
301+
}
302+
let (input, curve_name) = be_u16(input)?;
303+
304+
let (input, l) = be_u8(input)?;
305+
let (input, bytes) = take(l as usize)(input)?;
306+
let public_key = bytes.to_vec();
307+
308+
let (input, signature_hash_algorithm) = be_u8(input)?;
309+
let (input, signature_algorithm) = be_u8(input)?;
310+
311+
let (input, l) = be_u16(input)?;
312+
let (input, bytes) = take(l as usize)(input)?;
313+
let signature = bytes.to_vec();
314+
315+
Ok((
316+
input,
317+
ServerKeyExchange {
318+
curve_name,
319+
public_key,
320+
signature_hash_algorithm,
321+
signature_algorithm,
322+
signature,
323+
},
324+
))
325+
}
326+
}
327+
328+
pub struct ClientKeyExchange {
329+
pub public_key: Vec<u8>,
330+
}
331+
332+
impl fmt::Display for ClientKeyExchange {
333+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
334+
write!(f, "pk={}", hex::encode(&self.public_key),)
335+
}
336+
}
337+
338+
impl ClientKeyExchange {
339+
fn parse(input: &[u8]) -> IResult<&[u8], Self> {
340+
let (input, l) = be_u8(input)?;
341+
let (input, bytes) = take(l as usize)(input)?;
342+
let public_key = bytes.to_vec();
343+
344+
Ok((input, ClientKeyExchange { public_key }))
345+
}
346+
}

0 commit comments

Comments
 (0)