Skip to content

Commit 135b00a

Browse files
author
Damir Zainullin
committed
++
1 parent aebf994 commit 135b00a

File tree

9 files changed

+310
-171
lines changed

9 files changed

+310
-171
lines changed

process-plugin-api/process/common/tlsParser/tlsExtensionType.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ enum class TLSExtensionType : uint16_t
1212
ELLIPTIC_CURVE_POINT_FORMATS = 11,
1313
SIGNATURE_ALGORITHMS = 13,
1414
ALPN = 16,
15-
SUPPORTED_VERSION = 43
15+
SUPPORTED_VERSION = 43,
16+
QUIC_TRANSPORT_PARAMETERS = 0xffa5,
17+
QUIC_TRANSPORT_PARAMETERS_V1 = 0x39,
18+
QUIC_TRANSPORT_PARAMETERS_V2 = 0x26
1619
}
1720

1821
} // namespace ipxp::tls

process-plugin-api/process/quic/src/quic.cpp

Lines changed: 189 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,154 @@ QUICPlugin::QUICPlugin([[maybe_unused]]const std::string& params, FieldManager&
6767
}
6868
}
6969

70+
constexpr
71+
void QUICPlugin::tryToSetOCCIDandSCID(
72+
const QUICDirection quicDirection,
73+
std::span<const uint8_t> sourceConnectionId,
74+
std::span<const uint8_t> destinationConnectionId
75+
) noexcept
76+
{
77+
const DirectionalField<std::span<const uint8_t>> currentIds;
78+
currentIds[QUICDirection::CLIENT_TO_SERVER] = destinationConnectionId;
79+
currentIds[QUICDirection::SERVER_TO_CLIENT] = sourceConnectionId;
80+
81+
ConnectionId serverId = m_temporalCIDStorage.getServerCID(quicDirection);
82+
if (!serverId.empty() && m_exportData.serverConnectionId.empty()) {
83+
m_exportData.serverConnectionId = serverId;
84+
}
85+
if (!currentIds[quicDirection].empty() &&
86+
m_exportData.serverConnectionId.empty()) {
87+
m_exportData.serverConnectionId = currentIds[quicDirection];
88+
}
89+
90+
ConnectionId originalClientId = m_temporalCIDStorage.getClientCID(quicDirection);
91+
if (!originalClientId.empty() && m_exportData.clientConnectionId.empty()) {
92+
m_exportData.clientConnectionId = originalClientId;
93+
}
94+
if (!currentIds[!quicDirection].empty() &&
95+
m_exportData.clientConnectionId.empty()) {
96+
m_exportData.clientConnectionId = currentIds[!quicDirection];
97+
}
98+
}
99+
100+
constexpr
101+
void QUICPlugin::saveConnectionIdsToTemporalBuffer(
102+
const Direction direction,
103+
std::span<const uint8_t> sourceConnectionId,
104+
std::span<const uint8_t> destinationConnectionId
105+
) noexcept
106+
{
107+
108+
}
109+
110+
111+
constexpr
112+
void QUICPlugin::processInitial(
113+
const Direction flowDirection,
114+
const HeaderView& headerView,
115+
const InitialHeaderView& initialHeaderView,
116+
std::optional<QUICDirection> quicDirection) noexcept
117+
{
118+
m_initialConnectionId = initialHeaderView.destinationConnectionId;
119+
if (!quicDirection.has_value()) {
120+
// Server is still not revealed, so we store those values to emplace them
121+
// when directions are known
122+
m_temporalCIDStorage.storeConnectionIds(
123+
flowDirection,
124+
headerView.sourceConnectionId,
125+
headerView.destinationConnectionId);
126+
return;
127+
}
128+
129+
tryToSetOCCIDandSCID(...);
130+
131+
if (initialHeaderView.tlsHandshake.type != TLSHeader::Type::CLIENT_HELLO) {
132+
return;
133+
}
134+
135+
if (initialHeaderView.tokenLength.has_value()) {
136+
m_exportData.tokenLength = *initialHeaderView.tokenLength;
137+
}
138+
139+
if (initialHeaderView.tokenLength.has_value() &&
140+
*initialHeaderView.tokenLength > 0 &&
141+
std::ranges::equal(
142+
m_exportData.retrySCID, m_exportData.destinationConnectionId)) {
143+
return;
144+
}
145+
146+
//process multiplexing
147+
const bool hasMultiplexing =
148+
(std::ranges::equal(m_exportData.serverCID, destinationConnectionId) ||
149+
std::ranges::equal(m_exportData.sourceCID, destinationConnectionId)) &&
150+
std::ranges::equal(m_exportData.sni, initialHeaderView.sni);
151+
if (hasMultiplexing) {
152+
multiplexedCount = std::min<uint16_t>(
153+
multiplexedCount + 1, std::numeric_limits<uint8_t>::max());
154+
return;
155+
}
156+
157+
m_exportData.userAgent = initialHeaderView.userAgent;
158+
if (m_exportData.serverCID.empty()) {
159+
m_exportData.serverCID = destinationConnectionId;
160+
}
161+
if (m_exportData.clientCID.empty()) {
162+
m_exportData.clientCID = sourceConnectionId;
163+
}
164+
if (m_exportData.quicVersion == 0 ) {
165+
m_exportData.quicVersion = headerView.version;
166+
}
167+
168+
if (m_exportData.tlsExtensionTypes.empty()) {
169+
std::ranges::copy(initialHeaderView |
170+
std::views::transform([](const TLSExtension& extension) {
171+
return extension.type;
172+
}) |
173+
std::views::take(m_exportData.tlsExtensionTypes.capacity()),
174+
std::back_inserter(m_exportData.tlsExtensionTypes));
175+
}
176+
177+
if (m_exportData.tlsExtensionLengths.empty()) {
178+
std::ranges::copy(initialHeaderView |
179+
std::views::transform([](const TLSExtension& extension) {
180+
return extension.length;
181+
}) |
182+
std::views::take(m_exportData.tlsExtensionLengths.capacity()),
183+
std::back_inserter(m_exportData.tlsExtensionLengths));
184+
}
185+
186+
if (m_exportData.extensionsPayload.empty()) {
187+
std::ranges::copy(initialHeaderView.extensionsPayload |
188+
std::views::take(QUICExport::MAX_BUFFER_SIZE),
189+
std::back_inserter(m_exportData.extensionsPayload));
190+
}
191+
192+
193+
194+
}
195+
196+
constexpr
197+
void QUICPlugin::parseRetry() noexcept
198+
{
199+
m_retryPacketCount++;
200+
/*
201+
* A client MUST accept and process at most one Retry packet for each connection
202+
* attempt. After the client has received and processed an Initial or Retry packet from
203+
* the server, it MUST discard any subsequent Retry packets that it receives.
204+
*/
205+
if (m_retryPacketCount == 1) {
206+
// Additionally set token len
207+
m_exportData.retryCID = sourceConnectionId;
208+
m_initialCID = destinationConnectionId;
209+
m_exportData.tokenLength = 16; // ?????????
210+
}
211+
212+
if (m_exportData.clientCID.empty()) {
213+
m_exportData.clientCID = destinationConnectionId;
214+
}
215+
}
216+
217+
70218
int QUICPlugin::process_quic(
71219
RecordExtQUIC* quic_data,
72220
Flow& rec,
@@ -75,7 +223,11 @@ int QUICPlugin::process_quic(
75223
{
76224
QUICParser quicParser;
77225

78-
quicParser.parse(payload, initialDestConnectionId);
226+
if (!quicParser.parse(payload, initialDestConnectionId)) {
227+
/// ??????????????????????
228+
m_exportData.packets.push_back(packetTypeCumulativeWithQUICBitSet);
229+
return QUIC_NOT_DETECTED;
230+
}
79231

80232
if (quicParser.headerView.has_value() &&
81233
quicParser.packetTypesCumulative.bits.zeroRTT) {
@@ -89,114 +241,56 @@ int QUICPlugin::process_quic(
89241

90242
// TODO get direction ?
91243

92-
m_exportData.zeroRTTPacket = std::min<uint16_t>(
93-
m_exportData.zeroRTTPacket + quicParser.zeroRTTPackets,
94-
std::numeric_limits<uint8_t>::max()
95-
);
244+
if (version == QUICVersionId::version_negotiation) {
245+
set_cid_fields(quic_data, rec, &process_quic, toServer, new_quic_flow, pkt);
246+
return FlowAction::Flush;
247+
}
248+
249+
if (quicParser.packetTypesCumulative.bits.zeroRTT) {
250+
m_exportData.zeroRTTPacket = std::min<uint16_t>(
251+
m_exportData.zeroRTTPacket + quicParser.zeroRTTPackets,
252+
std::numeric_limits<uint8_t>::max()
253+
);
254+
}
255+
256+
96257

97258
if (quicParser.initialHeaderView.has_value()) {
98259
m_exportData.clientHelloParsed
99260
= quicParser.initialHeaderView->clientHelloParsed;
100261
}
101262

102-
switch (quicParser.packetType) {
103-
case QUICParser::PACKET_TYPE::INITIAL:
104-
if (!quicParser.initialHeaderView.has_value()) {
105-
break; //??
106-
}
107-
process_quic.quic_get_parsed_initial(parsed_initial);
108-
m_initialDestinationConnectionId.clear();
109-
std::ranges::copy(quicParser.initialHeaderView->destinationConnectionId |
110-
std::views::take(m_initialDestinationConnectionId.capacity()),
111-
std::back_inserter(m_initialDestinationConnectionId));
112-
// Store DCID from first observed Initial packet. This is used in the crypto operations.
113-
// Check length works because the first Initial must have a non-zero DCID.
114-
if (quic_data->initial_dcid_length == 0) {
115-
process_quic.quic_get_dcid_len(quic_data->initial_dcid_length);
116-
process_quic.quic_get_dcid(quic_data->initial_dcid);
117-
// Once established it can only be changed by a retry packet.
118-
}
119-
if (quicParser.initialHeaderView.has_value() &&
120-
quicParser.initialHeaderView->clientHelloParsed) {
121-
122-
if (m_exportData.sourceConnectionId.empty() &&
123-
quicParser.packetDirection.has_value() &&
124-
m_tempConnectionIdBuffer[*quicParser.packetDirection].has_value()) {
125-
std::ranges::copy(
126-
m_tempConnectionIdBuffer[*quicParser.packetDirection].destinationConnectionId |
127-
std::views::take(m_exportData.sourceConnectionId.capacity()),
128-
std::back_inserter(m_exportData.sourceConnectionId)
129-
);
130-
}
131-
set_stored_cid_fields(quic_data, new_quic_flow);
132-
set_client_hello_fields(&process_quic, rec, quic_data, pkt, new_quic_flow);
133-
quic_data->client_hello_seen = true;
134-
135-
if (!quic_data->tls_ext_type_set) {
136-
process_quic.quic_get_tls_ext_type(quic_data->tls_ext_type);
137-
process_quic.quic_get_tls_ext_type_len(quic_data->tls_ext_type_len);
138-
quic_data->tls_ext_type_set = true;
139-
}
140-
141-
if (!quic_data->tls_ext_len_set) {
142-
process_quic.quic_get_tls_extension_lengths(quic_data->tls_ext_len);
143-
process_quic.quic_get_tls_extension_lengths_len(quic_data->tls_ext_len_len);
144-
quic_data->tls_ext_len_set = true;
145-
}
263+
if (!m_temporalCIDStorage.directionIsRevealed() &&
264+
quicParser.quicDirection.has_value()) {
265+
m_temporalCIDStorage.pairDirections(
266+
*quicParser.quicDirection, packet.direction);
267+
}
146268

147-
if (!quic_data->tls_ext_set) {
148-
process_quic.quic_get_tls_ext(quic_data->tls_ext);
149-
process_quic.quic_get_tls_ext_len(quic_data->tls_ext_length);
150-
quic_data->tls_ext_set = true;
151-
}
269+
switch (quicParser.packetType) {
270+
case QUICParser::PACKET_TYPE::INITIAL: {
271+
processInitial(...);
272+
break;
273+
}
274+
case QUICParser::PACKET_TYPE::HANDSHAKE:{
275+
if (!quicDirection.has_value()) {
276+
m_temporalCIDStorage.storeConnectionIds(
277+
flowDirection,
278+
headerView.sourceConnectionId,
279+
headerView.destinationConnectionId);
152280
break;
153281
}
154-
155-
// Update accounting for information from CH, SH.
156-
toServer = get_direction_to_server_and_set_port(
157-
&process_quic,
158-
quic_data,
159-
process_quic.quic_get_server_port(),
160-
pkt,
161-
new_quic_flow);
162-
// fallthrough to set cids
163-
[[fallthrough]];
164-
case QUICParser::PACKET_TYPE::HANDSHAKE:
165-
// -1 sets stores intermediately.
166-
set_cid_fields(quic_data, rec, &process_quic, toServer, new_quic_flow, pkt);
282+
tryToSetOCCIDandSCID(...);
167283
break;
168-
case QUICParser::PACKET_TYPE::RETRY:
169-
quic_data->cnt_retry_packets += 1;
170-
/*
171-
* A client MUST accept and process at most one Retry packet for each connection
172-
* attempt. After the client has received and processed an Initial or Retry packet from
173-
* the server, it MUST discard any subsequent Retry packets that it receives.
174-
*/
175-
if (quic_data->cnt_retry_packets == 1) {
176-
// Additionally set token len
177-
process_quic.quic_get_scid(quic_data->retry_scid);
178-
process_quic.quic_get_scid_len(quic_data->retry_scid_length);
179-
// Update DCID for decryption
180-
process_quic.quic_get_dcid_len(quic_data->initial_dcid_length);
181-
process_quic.quic_get_scid(quic_data->initial_dcid);
182-
183-
process_quic.quic_get_token_length(quic_data->quic_token_length);
184-
}
185-
186-
if (!quic_data->occid_set) {
187-
process_quic.quic_get_dcid(quic_data->occid);
188-
process_quic.quic_get_dcid_len(quic_data->occid_length);
189-
quic_data->occid_set = true;
190-
}
191-
284+
}
285+
case QUICParser::PACKET_TYPE::RETRY: {
286+
parseRetry(...);
192287
break;
288+
}
193289
case QUICParser::PACKET_TYPE::ZERO_RTT:
194290
// Connection IDs are identical to Client Initial CH. The DCID might be OSCID at first
195291
// and change to SCID later. We ignore the DCID.
196-
if (!quic_data->occid_set) {
197-
process_quic.quic_get_scid(quic_data->occid);
198-
process_quic.quic_get_scid_len(quic_data->occid_length);
199-
quic_data->occid_set = true;
292+
if (m_exportData.clientCID.empty()) {
293+
m_exportData.clientCID = sourceConnectionId;
200294
}
201295
break;
202296
}

process-plugin-api/process/quic/src/quic.hpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include "quicExport.hpp"
2121
#include "quicFields.hpp"
22+
#include "quicTemporalStorage.hpp"
2223

2324
namespace ipxp {
2425

@@ -50,12 +51,9 @@ class QUICPlugin : public ProcessPlugin {
5051
QUICExport m_exportData;
5152
FieldHandlers<QUICFields> m_fieldHandlers;
5253

53-
struct TemporaryConnectionIdBuffer {
54-
boost::static_string<QUICExport::MAX_CONNECTION_ID_LENGTH> sourceConnectionId;
55-
boost::static_string<QUICExport::MAX_CONNECTION_ID_LENGTH> destinationConnectionId;
56-
};
54+
QUICTemporalStorage m_temporalCIDStorage;
55+
bool m_firstRetryPacketReceived = false;
5756

58-
DirectionalField<std::optional<TemporaryConnectionIdBuffer>> m_tempConnectionIdBuffer;
5957
boost::static_string<QUICExport::MAX_CONNECTION_ID_LENGTH> m_initialConnectionId;
6058
};
6159

process-plugin-api/process/quic/src/quicExport.hpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,25 @@ struct QUICExport {
1717
constexpr static std::size_t MAX_CONNECTION_ID_LENGTH = 20;
1818
constexpr static std::size_t MAX_PACKETS = 30;
1919
constexpr static std::size_t MAX_TLS_EXTENSIONS = 30;
20+
constexpr static std::size_t MAX_BUFFER_SIZE = 1500;
2021

2122
boost::static_string<BUFFER_SIZE> sni;
2223
boost::static_string<BUFFER_SIZE> userAgent;
2324
uint32_t quicVersion;
2425
uint32_t quicClientVersion;
2526
uint64_t quicTokenLength;
26-
boost::static_string<MAX_CONNECTION_ID_LENGTH> occid;
27-
boost::static_string<MAX_CONNECTION_ID_LENGTH> oscid;
28-
boost::static_string<MAX_CONNECTION_ID_LENGTH> scid;
27+
boost::static_string<MAX_CONNECTION_ID_LENGTH> originalClientId;
28+
boost::static_string<MAX_CONNECTION_ID_LENGTH> originalServerId;
29+
boost::static_string<MAX_CONNECTION_ID_LENGTH> serverId;
2930
boost::static_string<MAX_CONNECTION_ID_LENGTH> retryScid;
30-
uint8_t quicMultiplexed;
31+
uint8_t multiplexedCount;
3132
uint8_t quicZeroRTTCount;
3233
uint8_t clientHelloParsed;
3334
uint16_t serverPort;
3435
boost::container::static_vector<uint8_t, MAX_PACKETS> packetTypes;
3536
boost::container::static_vector<uint16_t, MAX_TLS_EXTENSIONS> tlsExtensionTypes;
3637
boost::container::static_vector<uint16_t, MAX_TLS_EXTENSIONS> tlsExtensionLengths;
38+
boost::container::static_vector<std::byte, MAX_BUFFER_SIZE> extensionsPayload;
3739

3840

3941

@@ -62,7 +64,6 @@ struct QUICExport {
6264
uint8_t tls_ext_len_len;
6365
bool tls_ext_len_set;
6466

65-
char tls_ext[CURRENT_BUFFER_SIZE];
6667
uint16_t tls_ext_length;
6768
bool tls_ext_set;
6869

0 commit comments

Comments
 (0)