Flow 2.0.0
Flow project: Full implementation reference.
seq_num.cpp
Go to the documentation of this file.
1/* Flow
2 * Copyright 2023 Akamai Technologies, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the
5 * "License"); you may not use this file except in
6 * compliance with the License. You may obtain a copy
7 * of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in
12 * writing, software distributed under the License is
13 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
14 * CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing
16 * permissions and limitations under the License. */
17
18/// @file
20#include "flow/util/random.hpp"
21#include <boost/functional/hash/hash.hpp>
22#include <boost/random.hpp>
23#include <boost/random/random_device.hpp>
24#include <limits>
25#include <cmath>
26
27namespace flow::net_flow
28{
29
30// Static initializations.
31
32/* Pick max ISN to be in the first half of the numeric range of sequence numbers (NOTE: not
33 * half the bits, but half the numeric range); i.e., about (2^64) / 2. This is a huge range of
34 * possible ISN, and if the ISN = <this value>, then at gigabit speeds and 1 sequence number per
35 * byte it would take many centuries for the sequence numbers to overflow seq_num_t. */
37 = std::numeric_limits<seq_num_t>::max() / 2;
38
39// Implementations.
40
42 log::Log_context(logger_ptr, Flow_log_component::S_NET_FLOW)
43{
44 // Nothing.
45}
46
48{
49 using boost::random::random_device;
50 using boost::random::uniform_int_distribution;
51
52 /* Generate each ISN independently from a CSPRNG.
53 *
54 * Historically (RFC 793: original TCP spec) this was done with a clock-based scheme (new sequence number every N
55 * usec, with N defined by the RFC). This code formerly (written circa 2011) implemented this; however
56 * clock-based ISN generation is predictable to off-path attackers. Hence for a full-on secure implementation
57 * we'd perhaps want the full RFC 6528 keyed-hash scheme used by modern production TCP stacks. @todo Do that.
58 *
59 * For the time being (2026), we will do a per-call CSPRNG pull instead. This is simpler and equally
60 * unpredictable for this context. */
61
62 random_device rnd_dev; // Setting this up, in Linux at least, is microseconds per connection. No prob.
63 uniform_int_distribution<seq_num_t> range{1, S_MAX_INIT_SEQ_NUM}; // 0 is a reserved number; do not use.
64
65 Sequence_number result;
66 result.m_num = range(rnd_dev);
67
68 FLOW_LOG_TRACE("Generated ISN [" << result << "].");
69
70 return result;
71} // Sequence_number::Generator::generate_init_seq_num()
72
75{
76 // Nothing.
77}
78
80
82
84{
85 return m_num != 0;
86}
87
89{
90 /* This can technically overflow (since seq_num_delta_t is a signed int64_t, while the raw #s are
91 * unsigned). This is advertised in the method comment and should not usually be a concern. */
92 return seq_num_delta_t(m_num - rhs.m_num);
93}
94
96{
97 m_num += delta; // Can be negative.
98 return *this;
99}
100
102{
103 return operator+=(-delta);
104}
105
107{
108 return Sequence_number{*this} += delta;
109}
110
112{
113 return operator+(-delta);
114}
115
117{
118 return m_num == rhs.m_num;
119}
120
122{
123 return !(*this == rhs);
124}
125
127{
128 return m_num < rhs.m_num;
129}
130
132{
133 return rhs < *this;
134}
135
137{
138 return !(*this < rhs);
139}
140
142{
143 return rhs >= *this;
144}
145
146std::ostream& operator<<(std::ostream& os, const Sequence_number& seq_num)
147{
148 // First the number line ID if any; 0 means unknown so just omit it.
149 if (seq_num.m_num_line_id != 0)
150 {
151 os << seq_num.m_num_line_id;
152 }
153
154 const bool use_multiple = seq_num.m_multiple_size != 0; // Multiples (segmentation) is in use.
155 const bool non_zero_offset = seq_num.m_zero_point_num != 0; // Magnitude is non-zero.
156
157 /* First assume the magnitude is non-zero. Then we show the sign, - or +. However, if the zero point is itself 0
158 * then any non-zero magnitude is positive; so simply omit the sign. Next, show the magnitude (m_num offset by
159 * m_zero_point). If `use_multiple`, then much as we omitted the zero point value itself and just showed the sign
160 * in its place, show the 'x' multiplication sign here; then show the multiple count, then "%R"; where R is the
161 * remainder beyond the multiples, omitted if R = 0. Finally, if `use_multiple`, then simply show the magnitude
162 * (can think it of it as a multiple of 1, for which R = 0 always, and the 'x' is omitted). Examples:
163 * -x3 (3B to left of zero), +x2%5 (2B+5 to right of zero), x454324123 (454324123B absolute),
164 * 454324123123 (454324123 absolute).
165 *
166 * Finally, what if magnitude IS zero? For convenience to help interpret other numbers on the same line we use
167 * this opportunity to print out the metadata set; and a simple indication that THIS value has magnitude 0.
168 * Think of the format as a non-zero-magnitude value, with the "implied" (omitted) values in the previous paragraph
169 * explicitly written out. So, first is the sign, written as the zero point followed by the sign.
170 * Next is the multiple, as the multiple followed by 'x'. The coup de grace, is, simply '0', since that's what this
171 * value is. Finally, each of the two segments mentioned is omitted in the degenerate cases (zero point = 0,
172 * no multiple used). Examples: 0 (!use_multiple, !non_zero_offset), 342342342+1024x0 (use_multiple, non_zero_offset),
173 * 342342342+0 (!use_multiple, !non_zero_offset).
174 *
175 * The above is hair/formal, but try to correlate the examples in the 2 paragraphs to see how the practical output
176 * makes some sense. */
177
178 Sequence_number::seq_num_t magnitude = seq_num.m_num;
179 if (magnitude == seq_num.m_zero_point_num)
180 {
181 // No sign => show reference values and the constant 0.
182 if (non_zero_offset)
183 {
184 os << seq_num.m_zero_point_num << '+';
185 }
186 if (use_multiple)
187 {
188 os << seq_num.m_multiple_size << 'x';
189 }
190 os << '0';
191 }
192 else
193 {
194 // Yes sign => show NO reference values; show the offset vs. zero pt., possibly as a count of multiples + remainder.
195 if (non_zero_offset)
196 {
197 // (Subtlety: avoid any underflow situation by only performing (A - B) when A > B.)
198 if (magnitude > seq_num.m_zero_point_num)
199 {
200 os << '+';
201 magnitude -= seq_num.m_zero_point_num;
202 }
203 else
204 {
205 assert(magnitude < seq_num.m_zero_point_num);
206 os << '-';
207 magnitude = seq_num.m_zero_point_num - magnitude;
208 }
209 }
210
211 if (use_multiple)
212 {
213 os << 'x' << (magnitude / seq_num.m_multiple_size);
214 const auto rem = magnitude % seq_num.m_multiple_size;
215 if (rem != 0)
216 {
217 os << '%' << rem;
218 }
219 }
220 else
221 {
222 os << magnitude;
223 }
224 }
225
226 return os;
227}
228
230{
231 using boost::hash_value;
232 return hash_value(m_num);
233}
234
236{
237 return m_num;
238}
239
241{
242 m_num = num;
243}
244
245void Sequence_number::set_metadata(char num_line_id, const Sequence_number& zero_point, seq_num_delta_t multiple_size)
246{
247 m_num_line_id = num_line_id;
248 m_zero_point_num = zero_point.m_num;
249 m_multiple_size = multiple_size;
250}
251
252size_t hash_value(const Sequence_number& seq_num)
253{
254 return seq_num.hash();
255}
256
257} // namespace flow::net_flow
Interface that the user should implement, passing the implementing Logger into logging classes (Flow'...
Definition: log.hpp:1286
Sequence_number generate_init_seq_num()
Returns an initial sequence number (ISN) for use in a new connection.
Definition: seq_num.cpp:47
Generator(log::Logger *logger)
Constructs Generator.
Definition: seq_num.cpp:41
static const seq_num_t S_MAX_INIT_SEQ_NUM
The maximum allowed value for the initial sequence number (ISN) for a given Flow-protocol connection ...
Definition: seq_num.hpp:416
An internal net_flow sequence number identifying a piece of data.
Definition: seq_num.hpp:126
seq_num_delta_t m_multiple_size
Expected size of a full contiguous "block" of these numbers; 0 = unknown/blocks not expected....
Definition: seq_num.hpp:356
bool valid() const
Returns true if and only if *this != Sequence_number{} (i.e., is non-zero).
Definition: seq_num.cpp:83
bool operator==(const Sequence_number &rhs) const
Whether *this is the same sequence number as rhs.
Definition: seq_num.cpp:116
Sequence_number operator+(seq_num_delta_t delta) const
Returns new sequence number that is *this advanced (or reversed) by the given distance.
Definition: seq_num.cpp:106
seq_num_delta_t operator-(const Sequence_number &rhs) const
Returns the distance from *this to rhs.
Definition: seq_num.cpp:88
bool operator<(const Sequence_number &rhs) const
Whether *this is less than rhs.
Definition: seq_num.cpp:126
bool operator<=(const Sequence_number &rhs) const
Return !(*this > rhs).
Definition: seq_num.cpp:141
Sequence_number & operator+=(seq_num_delta_t delta)
Advances (or reverses) this sequence number by the given distance.
Definition: seq_num.cpp:95
size_t hash_value(const Sequence_number &seq_num)
Free function that returns seq_num.hash(); has to be a free function named hash_value for boost....
Definition: seq_num.cpp:252
size_t hash() const
Hash value of this Sequence_number for unordered_*<>.
Definition: seq_num.cpp:229
void set_raw_num(seq_num_t num)
Sets the raw sequence number.
Definition: seq_num.cpp:240
Sequence_number & operator-=(seq_num_delta_t delta)
Equivalent to: operator+=(-delta).
Definition: seq_num.cpp:101
Sequence_number & operator=(const Sequence_number &source)
Copy operator.
uint64_t seq_num_t
Raw sequence number type.
Definition: seq_num.hpp:138
int64_t seq_num_delta_t
Integer type used to express differences (distances) between Sequence_numbers.
Definition: seq_num.hpp:150
const seq_num_t & raw_num_ref() const
Provides the raw sequence number.
Definition: seq_num.cpp:235
seq_num_t m_num
The raw sequence number. This is the only datum used in algorithms. The others are only for logging a...
Definition: seq_num.hpp:347
void set_metadata(char num_line_id=0, const Sequence_number &zero_point=Sequence_number{}, seq_num_delta_t multiple_size=0)
Updates the full set of metadata (used at least for convenient convention-based logging but not actua...
Definition: seq_num.cpp:245
Sequence_number()
Constructs sequence number that is zero (not a valid sequence number; less than all others).
Definition: seq_num.cpp:73
seq_num_t m_zero_point_num
Value for m_num such that the magnitude is zero. See set_metadata().
Definition: seq_num.hpp:353
char m_num_line_id
Identifies the owner number line; char(0) = unknown/none. See set_metadata().
Definition: seq_num.hpp:350
bool operator>(const Sequence_number &rhs) const
Return rhs < *this.
Definition: seq_num.cpp:131
bool operator!=(const Sequence_number &rhs) const
Return !(*this == rhs).
Definition: seq_num.cpp:121
bool operator>=(const Sequence_number &rhs) const
Return rhs <= *this.
Definition: seq_num.cpp:136
#define FLOW_LOG_TRACE(ARG_stream_fragment)
Logs a TRACE message into flow::log::Logger *get_logger() with flow::log::Component get_log_component...
Definition: log.hpp:227
Flow module containing the API and implementation of the Flow network protocol, a TCP-inspired stream...
Definition: node.cpp:25
size_t hash_value(const Sequence_number &seq_num)
Free function that returns seq_num.hash(); has to be a free function named hash_value for boost....
Definition: seq_num.cpp:252
std::ostream & operator<<(std::ostream &os, const Congestion_control_selector::Strategy_choice &strategy_choice)
Serializes a Peer_socket_options::Congestion_control_strategy_choice enum to a standard ostream – the...
Definition: cong_ctl.cpp:146
Flow_log_component
The flow::log::Component payload enumeration comprising various log components used by Flow's own int...
Definition: common.hpp:627