Skip to content

Commit f1def08

Browse files
committed
add fragment_buffer and test
update code
1 parent 0c7a877 commit f1def08

File tree

6 files changed

+309
-19
lines changed

6 files changed

+309
-19
lines changed

dtls/src/fragment_buffer.rs

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
#[cfg(test)]
2+
mod fragment_buffer_test;
3+
4+
use crate::content::*;
5+
use crate::handshake::handshake_header::*;
6+
use crate::record_layer::record_layer_header::*;
7+
8+
use util::Error;
9+
10+
use std::collections::HashMap;
11+
use std::io::{BufWriter, Cursor};
12+
13+
pub(crate) struct Fragment {
14+
record_layer_header: RecordLayerHeader,
15+
handshake_header: HandshakeHeader,
16+
data: Vec<u8>,
17+
}
18+
19+
pub(crate) struct FragmentBuffer {
20+
// map of MessageSequenceNumbers that hold slices of fragments
21+
cache: HashMap<u16, Vec<Fragment>>,
22+
23+
current_message_sequence_number: u16,
24+
}
25+
26+
impl FragmentBuffer {
27+
pub fn new() -> Self {
28+
FragmentBuffer {
29+
cache: HashMap::new(),
30+
current_message_sequence_number: 0,
31+
}
32+
}
33+
34+
// Attempts to push a DTLS packet to the FragmentBuffer
35+
// when it returns true it means the FragmentBuffer has inserted and the buffer shouldn't be handled
36+
// when an error returns it is fatal, and the DTLS connection should be stopped
37+
pub fn push(&mut self, mut buf: &[u8]) -> Result<bool, Error> {
38+
let mut reader = Cursor::new(buf);
39+
let record_layer_header = RecordLayerHeader::unmarshal(&mut reader)?;
40+
41+
// Fragment isn't a handshake, we don't need to handle it
42+
if record_layer_header.content_type != ContentType::Handshake {
43+
return Ok(false);
44+
}
45+
46+
buf = &buf[RECORD_LAYER_HEADER_SIZE..];
47+
while buf.len() != 0 {
48+
let mut reader = Cursor::new(buf);
49+
let handshake_header = HandshakeHeader::unmarshal(&mut reader)?;
50+
51+
if !self.cache.contains_key(&handshake_header.message_sequence) {
52+
self.cache.insert(handshake_header.message_sequence, vec![]);
53+
}
54+
55+
// end index should be the length of handshake header but if the handshake
56+
// was fragmented, we should keep them all
57+
let mut end = HANDSHAKE_HEADER_LENGTH + handshake_header.length as usize;
58+
if end > buf.len() {
59+
end = buf.len();
60+
}
61+
62+
// Discard all headers, when rebuilding the packet we will re-build
63+
let data = buf[HANDSHAKE_HEADER_LENGTH..end].to_vec();
64+
65+
if let Some(x) = self.cache.get_mut(&handshake_header.message_sequence) {
66+
x.push(Fragment {
67+
record_layer_header,
68+
handshake_header,
69+
data,
70+
});
71+
}
72+
buf = &buf[end..];
73+
}
74+
75+
Ok(true)
76+
}
77+
78+
pub fn pop(&mut self) -> (Vec<u8>, u16) {
79+
let seq_num = self.current_message_sequence_number;
80+
if !self.cache.contains_key(&seq_num) {
81+
return (vec![], 0);
82+
}
83+
84+
let (content, epoch) = if let Some(frags) = self.cache.get_mut(&seq_num) {
85+
let mut raw_message = vec![];
86+
// Recursively collect up
87+
if !append_message(0, frags, &mut raw_message) {
88+
return (vec![], 0);
89+
}
90+
91+
let mut first_header = frags[0].handshake_header;
92+
first_header.fragment_offset = 0;
93+
first_header.fragment_length = first_header.length;
94+
95+
let mut raw_header = vec![];
96+
{
97+
let mut writer = BufWriter::<&mut Vec<u8>>::new(raw_header.as_mut());
98+
match first_header.marshal(&mut writer) {
99+
Err(_) => return (vec![], 0),
100+
Ok(_) => {}
101+
};
102+
}
103+
104+
let message_epoch = frags[0].record_layer_header.epoch;
105+
106+
raw_header.extend_from_slice(&raw_message);
107+
108+
(raw_header, message_epoch)
109+
} else {
110+
(vec![], 0)
111+
};
112+
113+
self.cache.remove(&seq_num);
114+
self.current_message_sequence_number += 1;
115+
116+
(content, epoch)
117+
}
118+
}
119+
120+
fn append_message(target_offset: u32, frags: &[Fragment], raw_message: &mut Vec<u8>) -> bool {
121+
for f in frags {
122+
if f.handshake_header.fragment_offset == target_offset {
123+
let fragment_end =
124+
f.handshake_header.fragment_offset + f.handshake_header.fragment_length;
125+
if fragment_end != f.handshake_header.length {
126+
if !append_message(fragment_end, frags, raw_message) {
127+
return false;
128+
}
129+
}
130+
131+
let mut message = vec![];
132+
message.extend_from_slice(&f.data);
133+
message.extend_from_slice(raw_message);
134+
*raw_message = message;
135+
return true;
136+
}
137+
}
138+
139+
false
140+
}
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
use super::*;
2+
3+
use util::Error;
4+
5+
#[test]
6+
fn test_fragment_buffer() -> Result<(), Error> {
7+
let tests = vec![
8+
(
9+
"Single Fragment",
10+
vec![vec![
11+
0x16, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x03,
12+
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfe, 0xff, 0x00,
13+
]],
14+
vec![vec![
15+
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfe, 0xff,
16+
0x00,
17+
]],
18+
0,
19+
),
20+
(
21+
"Single Fragment Epoch 3",
22+
vec![vec![
23+
0x16, 0xfe, 0xff, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x03,
24+
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfe, 0xff, 0x00,
25+
]],
26+
vec![vec![
27+
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfe, 0xff,
28+
0x00,
29+
]],
30+
3,
31+
),
32+
(
33+
"Multiple Fragments",
34+
vec![
35+
vec![
36+
0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81,
37+
0x0b, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00,
38+
0x01, 0x02, 0x03, 0x04,
39+
],
40+
vec![
41+
0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81,
42+
0x0b, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x05, 0x05,
43+
0x06, 0x07, 0x08, 0x09,
44+
],
45+
vec![
46+
0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81,
47+
0x0b, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x05, 0x0A,
48+
0x0B, 0x0C, 0x0D, 0x0E,
49+
],
50+
],
51+
vec![vec![
52+
0x0b, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x01,
53+
0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
54+
]],
55+
0,
56+
),
57+
(
58+
"Multiple Unordered Fragments",
59+
vec![
60+
vec![
61+
0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81,
62+
0x0b, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00,
63+
0x01, 0x02, 0x03, 0x04,
64+
],
65+
vec![
66+
0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81,
67+
0x0b, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x05, 0x0A,
68+
0x0B, 0x0C, 0x0D, 0x0E,
69+
],
70+
vec![
71+
0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x81,
72+
0x0b, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x05, 0x05,
73+
0x06, 0x07, 0x08, 0x09,
74+
],
75+
],
76+
vec![vec![
77+
0x0b, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x01,
78+
0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
79+
]],
80+
0,
81+
),
82+
(
83+
"Multiple Handshakes in Signle Fragment",
84+
vec![vec![
85+
0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
86+
0x30, /* record header */
87+
0x03, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xfe, 0xff,
88+
0x01, 0x01, /*handshake msg 1*/
89+
0x03, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xfe, 0xff,
90+
0x01, 0x01, /*handshake msg 2*/
91+
0x03, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xfe, 0xff,
92+
0x01, 0x01, /*handshake msg 3*/
93+
]],
94+
vec![
95+
vec![
96+
0x03, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xfe,
97+
0xff, 0x01, 0x01,
98+
],
99+
vec![
100+
0x03, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xfe,
101+
0xff, 0x01, 0x01,
102+
],
103+
vec![
104+
0x03, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xfe,
105+
0xff, 0x01, 0x01,
106+
],
107+
],
108+
0,
109+
),
110+
];
111+
112+
for (name, inputs, expects, expected_epoch) in tests {
113+
let mut fragment_buffer = FragmentBuffer::new();
114+
for frag in inputs {
115+
let status = fragment_buffer.push(&frag)?;
116+
assert_eq!(
117+
true, status,
118+
"fragment_buffer didn't accept fragments for '{}'",
119+
name
120+
);
121+
}
122+
123+
for expected in expects {
124+
let (out, epoch) = fragment_buffer.pop();
125+
assert_eq!(
126+
out, expected,
127+
"fragment_buffer '{}' push/pop: got {:?}, want {:?}",
128+
name, out, expected
129+
);
130+
131+
assert_eq!(
132+
epoch, expected_epoch,
133+
"fragment_buffer returned wrong epoch: got {}, want {}",
134+
epoch, expected_epoch
135+
);
136+
}
137+
138+
let (frag, _) = fragment_buffer.pop();
139+
assert_eq!(
140+
frag.len(),
141+
0,
142+
"fragment_buffer popped single buffer multiple times for '{}'",
143+
name
144+
);
145+
}
146+
147+
Ok(())
148+
}

dtls/src/handshake.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
mod handshake_header;
2-
mod handshake_message_certificate;
3-
mod handshake_message_certificate_request;
4-
mod handshake_message_certificate_verify;
5-
mod handshake_message_client_hello;
6-
mod handshake_message_client_key_exchange;
7-
mod handshake_message_finished;
8-
mod handshake_message_hello_verify_request;
9-
mod handshake_message_server_hello;
10-
mod handshake_message_server_hello_done;
11-
mod handshake_message_server_key_exchange;
12-
mod handshake_random;
1+
pub mod handshake_header;
2+
pub mod handshake_message_certificate;
3+
pub mod handshake_message_certificate_request;
4+
pub mod handshake_message_certificate_verify;
5+
pub mod handshake_message_client_hello;
6+
pub mod handshake_message_client_key_exchange;
7+
pub mod handshake_message_finished;
8+
pub mod handshake_message_hello_verify_request;
9+
pub mod handshake_message_server_hello;
10+
pub mod handshake_message_server_hello_done;
11+
pub mod handshake_message_server_key_exchange;
12+
pub mod handshake_random;
1313

1414
use std::fmt;
1515
use std::io::{Read, Write};

dtls/src/handshake/handshake_header.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,16 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
77
use util::Error;
88

99
// msg_len for Handshake messages assumes an extra 12 bytes for
10-
// sequence, fragment and version information
11-
const HANDSHAKE_HEADER_LENGTH: usize = 12;
10+
// sequence, Fragment and version information
11+
pub(crate) const HANDSHAKE_HEADER_LENGTH: usize = 12;
1212

13-
#[derive(Clone, PartialEq, Debug)]
13+
#[derive(Copy, Clone, PartialEq, Debug)]
1414
pub struct HandshakeHeader {
1515
pub handshake_type: HandshakeType,
16-
length: u32, // uint24 in spec
17-
message_sequence: u16,
18-
fragment_offset: u32, // uint24 in spec
19-
fragment_length: u32, // uint24 in spec
16+
pub(crate) length: u32, // uint24 in spec
17+
pub message_sequence: u16,
18+
pub(crate) fragment_offset: u32, // uint24 in spec
19+
pub(crate) fragment_length: u32, // uint24 in spec
2020
}
2121

2222
impl HandshakeHeader {

dtls/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ pub mod crypto;
1616
pub mod curve;
1717
pub mod errors;
1818
pub mod extension;
19+
pub mod fragment_buffer;
1920
pub mod handshake;
2021
pub mod prf;
2122
pub mod record_layer;
2223
pub mod signature_hash_algorithm;
24+
pub mod state;

dtls/src/state.rs

Whitespace-only changes.

0 commit comments

Comments
 (0)