1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
// Copyright 2024 Saorsa Labs Ltd.
//
// This Saorsa Network Software is licensed under the General Public License (GPL), version 3.
// Please see the file LICENSE-GPL, or visit <http://www.gnu.org/licenses/> for the full text.
//
// Full details available at https://saorsalabs.com/licenses
#[cfg(test)]
mod observed_address_sequence_validation {
use crate::frame::ObservedAddress;
use crate::coding::BufExt;
use crate::VarInt;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::time::Instant;
#[test]
fn test_sequence_number_validation_in_frame_processing() {
// This test validates that the OBSERVED_ADDRESS frame sequence number
// validation works according to RFC draft-ietf-quic-address-discovery-00
// Create a test connection with address discovery enabled
let _now = Instant::now();
let _config = crate::transport_parameters::AddressDiscoveryConfig::SendAndReceive;
// Create frames with different sequence numbers
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 100)), 5000);
let frame1 = ObservedAddress {
sequence_number: VarInt::from_u32(1),
address: addr,
};
let frame2 = ObservedAddress {
sequence_number: VarInt::from_u32(2),
address: addr,
};
let frame3_duplicate = ObservedAddress {
sequence_number: VarInt::from_u32(2), // Duplicate sequence
address: addr,
};
let frame4_stale = ObservedAddress {
sequence_number: VarInt::from_u32(1), // Stale sequence
address: addr,
};
let frame5 = ObservedAddress {
sequence_number: VarInt::from_u32(5), // Jump in sequence (allowed)
address: addr,
};
// TODO: Once we have a proper test harness for Connection,
// we should process these frames and verify:
// 1. frame1 is accepted (first frame)
// 2. frame2 is accepted (higher sequence)
// 3. frame3_duplicate is ignored (equal sequence)
// 4. frame4_stale is ignored (lower sequence)
// 5. frame5 is accepted (higher sequence, gaps are allowed)
// For now, just verify the frames encode/decode correctly
for (i, frame) in [frame1, frame2, frame3_duplicate, frame4_stale, frame5].iter().enumerate() {
let mut buf = Vec::new();
frame.encode(&mut buf);
assert!(!buf.is_empty(), "Frame {i} should encode to non-empty buffer");
// Verify we can decode it back
let mut reader = &buf[4..]; // Skip frame type
let decoded = ObservedAddress::decode(&mut reader, false).unwrap();
assert_eq!(decoded.sequence_number, frame.sequence_number);
assert_eq!(decoded.address, frame.address);
}
}
#[test]
fn test_sequence_number_monotonicity_per_path() {
// Test that sequence numbers are tracked per path
// In a multi-path scenario, each path should have independent sequence tracking
let path0_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)), 1234);
let path1_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 0, 0, 2)), 5678);
// Path 0 frames
let path0_frame1 = ObservedAddress {
sequence_number: VarInt::from_u32(1),
address: path0_addr,
};
let path0_frame2 = ObservedAddress {
sequence_number: VarInt::from_u32(3),
address: path0_addr,
};
// Path 1 frames (can reuse sequence numbers)
let path1_frame1 = ObservedAddress {
sequence_number: VarInt::from_u32(1), // Same as path0, but different path
address: path1_addr,
};
let path1_frame2 = ObservedAddress {
sequence_number: VarInt::from_u32(2),
address: path1_addr,
};
// TODO: When multi-path support is added, verify that:
// 1. path0_frame1 and path0_frame2 are both accepted for path 0
// 2. path1_frame1 and path1_frame2 are both accepted for path 1
// 3. Sequence numbers are tracked independently per path
// For now, verify encoding/decoding
for frame in [path0_frame1, path0_frame2, path1_frame1, path1_frame2] {
let mut buf = Vec::new();
frame.encode(&mut buf);
let mut reader = &buf[4..];
let decoded = ObservedAddress::decode(&mut reader, false).unwrap();
assert_eq!(decoded.sequence_number, frame.sequence_number);
assert_eq!(decoded.address, frame.address);
}
}
#[test]
fn test_sequence_number_edge_cases_validation() {
// Test edge cases for sequence numbers
// Maximum sequence number
let max_frame = ObservedAddress {
sequence_number: VarInt::MAX,
address: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 65535),
};
// After max, we should handle wraparound gracefully
// Per RFC, sequence numbers are monotonically increasing,
// but implementation should handle VarInt::MAX edge case
let mut buf = Vec::new();
max_frame.encode(&mut buf);
let mut reader = &buf[4..];
let decoded = ObservedAddress::decode(&mut reader, false).unwrap();
assert_eq!(decoded.sequence_number, VarInt::MAX);
// Zero sequence number (valid as first frame)
let zero_frame = ObservedAddress {
sequence_number: VarInt::from_u32(0),
address: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 80),
};
let mut buf = Vec::new();
zero_frame.encode(&mut buf);
let mut reader = &buf[4..];
let decoded = ObservedAddress::decode(&mut reader, false).unwrap();
assert_eq!(decoded.sequence_number, VarInt::from_u32(0));
}
#[test]
fn test_sequence_validation_integration() {
// Integration test showing the complete flow
use bytes::BytesMut;
// Simulate receiving multiple OBSERVED_ADDRESS frames in order
let frames = vec![
ObservedAddress {
sequence_number: VarInt::from_u32(1),
address: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(93, 184, 216, 34)), 443),
},
ObservedAddress {
sequence_number: VarInt::from_u32(2),
address: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(93, 184, 216, 34)), 443),
},
ObservedAddress {
sequence_number: VarInt::from_u32(5), // Gap is OK
address: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(93, 184, 216, 35)), 443),
},
];
// Encode all frames
let mut buf = BytesMut::new();
for frame in &frames {
frame.encode(&mut buf);
}
// Now decode and verify we get all frames back with correct sequences
let mut decoded_frames = Vec::new();
let mut offset = 0;
while offset < buf.len() {
// Read frame type
let _frame_type_start = offset;
let mut reader = &buf[offset..];
let frame_type = match reader.get_var() {
Ok(val) => val,
Err(_) => break,
};
let frame_type_len = buf[offset..].len() - reader.len();
offset += frame_type_len;
// Check if it's OBSERVED_ADDRESS
if frame_type == crate::frame::FrameType::OBSERVED_ADDRESS_IPV4.0 ||
frame_type == crate::frame::FrameType::OBSERVED_ADDRESS_IPV6.0 {
let mut reader = &buf[offset..];
let is_ipv6 = frame_type == crate::frame::FrameType::OBSERVED_ADDRESS_IPV6.0;
if let Ok(decoded) = ObservedAddress::decode(&mut reader, is_ipv6) {
let frame_len = buf[offset..].len() - reader.len();
decoded_frames.push(decoded);
offset += frame_len;
} else {
break;
}
} else {
break;
}
}
// Verify we decoded all frames
assert_eq!(decoded_frames.len(), frames.len());
// Verify sequence numbers are preserved
for (original, decoded) in frames.iter().zip(decoded_frames.iter()) {
assert_eq!(original.sequence_number, decoded.sequence_number);
assert_eq!(original.address, decoded.address);
}
// Verify sequence numbers are in expected order
assert_eq!(decoded_frames[0].sequence_number, VarInt::from_u32(1));
assert_eq!(decoded_frames[1].sequence_number, VarInt::from_u32(2));
assert_eq!(decoded_frames[2].sequence_number, VarInt::from_u32(5));
}
}