Skip to content

Commit

Permalink
Address Discovery Support
Browse files Browse the repository at this point in the history
  • Loading branch information
nibanks committed Nov 6, 2024
1 parent 9587f74 commit c9d4186
Show file tree
Hide file tree
Showing 16 changed files with 349 additions and 27 deletions.
28 changes: 27 additions & 1 deletion src/core/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -2263,7 +2263,8 @@ QuicConnGenerateLocalTransportParameters(
QUIC_TP_FLAG_MAX_UDP_PAYLOAD_SIZE |
QUIC_TP_FLAG_MAX_ACK_DELAY |
QUIC_TP_FLAG_MIN_ACK_DELAY |
QUIC_TP_FLAG_ACTIVE_CONNECTION_ID_LIMIT;
QUIC_TP_FLAG_ACTIVE_CONNECTION_ID_LIMIT |
QUIC_TP_FLAG_OBSERVED_ADDRESS;

if (Connection->Settings.IdleTimeoutMs != 0) {
LocalTP->Flags |= QUIC_TP_FLAG_IDLE_TIMEOUT;
Expand Down Expand Up @@ -2891,6 +2892,10 @@ QuicConnProcessPeerTransportParameters(
Connection->SourceCidLimit = QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT_DEFAULT;
}

if (Connection->PeerTransportParams.Flags & QUIC_TP_FLAG_OBSERVED_ADDRESS) {
Connection->State.ObservedAddressNegotiated = TRUE;
}

if (!FromResumptionTicket) {
if (Connection->Settings.VersionNegotiationExtEnabled &&
Connection->PeerTransportParams.Flags & QUIC_TP_FLAG_VERSION_NEGOTIATION) {
Expand Down Expand Up @@ -5284,6 +5289,23 @@ QuicConnRecvFrames(
break;
}

case QUIC_FRAME_OBSERVED_ADDRESS_V4:
case QUIC_FRAME_OBSERVED_ADDRESS_V6: { // Always accept the frame, because we always enable support.
QUIC_OBSERVED_ADDRESS_EX Frame;
if (!QuicObservedAddressFrameDecode(FrameType, PayloadLength, Payload, &Offset, &Frame)) {
QuicTraceEvent(
ConnError,
"[conn][%p] ERROR, %s.",
Connection,
"Decoding OBSERVED_ADDRESS frame");
QuicConnTransportError(Connection, QUIC_ERROR_FRAME_ENCODING_ERROR);
return FALSE;
}

// TODO - Do something with this.
break;
}

default:
//
// No default case necessary, as we have already validated the frame
Expand Down Expand Up @@ -7342,6 +7364,10 @@ QuicConnApplyNewSettings(
QuicConnIndicateEvent(Connection, &Event);
}

if (QuicConnIsServer(Connection) && Connection->PeerTransportParams.Flags & QUIC_TP_FLAG_OBSERVED_ADDRESS) {
Connection->State.ObservedAddressNegotiated = TRUE;
}

if (Connection->Settings.EcnEnabled) {
QUIC_PATH* Path = &Connection->Paths[0];
Path->EcnValidationState = ECN_VALIDATION_TESTING;
Expand Down
10 changes: 10 additions & 0 deletions src/core/connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,11 @@ typedef union QUIC_CONNECTION_STATE {
//
BOOLEAN TimestampRecvNegotiated : 1;

//
// Indicates that the peer supports the Observed Address feature.
//
BOOLEAN ObservedAddressNegotiated : 1;

//
// Indicates we received APPLICATION_ERROR transport error and are checking also
// later packets in case they contain CONNECTION_CLOSE frame with application-layer error.
Expand Down Expand Up @@ -467,6 +472,11 @@ typedef struct QUIC_CONNECTION {
//
QUIC_VAR_INT NextSourceCidSequenceNumber;

//
// The sequence number to use for sending a new observed address.
//
QUIC_VAR_INT ObservedAddressSequenceNumber;

//
// The most recent Retire Prior To field received in a NEW_CONNECTION_ID
// frame.
Expand Down
3 changes: 2 additions & 1 deletion src/core/crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -2181,7 +2181,8 @@ QuicCryptoEncodeServerTicket(
QUIC_TP_FLAG_INITIAL_MAX_STRM_DATA_BIDI_REMOTE |
QUIC_TP_FLAG_INITIAL_MAX_STRM_DATA_UNI |
QUIC_TP_FLAG_INITIAL_MAX_STRMS_BIDI |
QUIC_TP_FLAG_INITIAL_MAX_STRMS_UNI);
QUIC_TP_FLAG_INITIAL_MAX_STRMS_UNI |
QUIC_TP_FLAG_OBSERVED_ADDRESS);

EncodedHSTP =
QuicCryptoTlsEncodeTransportParameters(
Expand Down
47 changes: 47 additions & 0 deletions src/core/crypto_tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ typedef enum eSniNameType {
#define QUIC_TP_ID_GREASE_QUIC_BIT 0x2AB2 // N/A
#define QUIC_TP_ID_RELIABLE_RESET_ENABLED 0x17f7586d2cb570 // varint
#define QUIC_TP_ID_ENABLE_TIMESTAMP 0x7158 // varint
#define QUIC_TP_ID_OBSERVED_ADDRESS 0x9f81a176 // varint

BOOLEAN
QuicTpIdIsReserved(
Expand Down Expand Up @@ -904,6 +905,12 @@ QuicCryptoTlsEncodeTransportParameters(
QUIC_TP_ID_ENABLE_TIMESTAMP,
QuicVarIntSize(value));
}
if (TransportParams->Flags & QUIC_TP_FLAG_OBSERVED_ADDRESS) {
RequiredTPLen +=
TlsTransportParamLength(
QUIC_TP_ID_OBSERVED_ADDRESS,
QuicVarIntSize(2)); // Hardcode for now
}
if (TestParam != NULL) {
RequiredTPLen +=
TlsTransportParamLength(
Expand Down Expand Up @@ -1246,6 +1253,18 @@ QuicCryptoTlsEncodeTransportParameters(
"TP: Timestamp (%u)",
value);
}
if (TransportParams->Flags & QUIC_TP_FLAG_OBSERVED_ADDRESS) {
TPBuf =
TlsWriteTransportParamVarInt(
QUIC_TP_ID_OBSERVED_ADDRESS,
2,
TPBuf);
QuicTraceLogConnVerbose(
EncodeTPObservedAddress,
Connection,
"TP: Observed Address (%u)",
2);
}
if (TestParam != NULL) {
TPBuf =
TlsWriteTransportParam(
Expand Down Expand Up @@ -1953,6 +1972,34 @@ QuicCryptoTlsDecodeTransportParameters( // NOLINT(readability-function-size, goo
break;
}

case QUIC_TP_ID_OBSERVED_ADDRESS: {
QUIC_VAR_INT value = 0;
if (!TRY_READ_VAR_INT(value)) {
QuicTraceEvent(
ConnErrorStatus,
"[conn][%p] ERROR, %u, %s.",
Connection,
Length,
"Invalid length of QUIC_TP_ID_OBSERVED_ADDRESS");
goto Exit;
}
if (value > 2) {
QuicTraceEvent(
ConnError,
"[conn][%p] ERROR, %s.",
Connection,
"Invalid value of QUIC_TP_ID_OBSERVED_ADDRESS");
goto Exit;
}
QuicTraceLogConnVerbose(
DecodeTPObservedAddress,
Connection,
"TP: Observed Address (%u)",
(uint32_t)value);
TransportParams->Flags |= QUIC_TP_FLAG_OBSERVED_ADDRESS; // TODO - Pass value?
break;
}

default:
if (QuicTpIdIsReserved(Id)) {
QuicTraceLogConnWarning(
Expand Down
146 changes: 132 additions & 14 deletions src/core/frame.c
Original file line number Diff line number Diff line change
Expand Up @@ -1334,7 +1334,7 @@ QuicTimestampFrameEncode(

_Success_(return != FALSE)
BOOLEAN
QuicTimestampFrameDecode(
(
_In_ uint16_t BufferLength,
_In_reads_bytes_(BufferLength)
const uint8_t * const Buffer,
Expand All @@ -1349,6 +1349,101 @@ QuicTimestampFrameDecode(
return TRUE;
}

_Success_(return != FALSE)
BOOLEAN
QuicObservedAddressFrameEncode(
_In_ const QUIC_OBSERVED_ADDRESS_EX * const Frame,
_Inout_ uint16_t* Offset,
_In_ uint16_t BufferLength,
_Out_writes_to_(BufferLength, *Offset)
uint8_t* Buffer
)
{
if (QuicAddrGetFamily(&Frame->Address) == QUIC_ADDRESS_FAMILY_INET) {
const uint16_t RequiredLength =
QuicVarIntSize(QUIC_FRAME_OBSERVED_ADDRESS_V4) +
QuicVarIntSize(Frame->SequenceNumber) +
sizeof(Frame->Address.Ipv4.sin_addr) +
sizeof(Frame->Address.Ipv4.sin_port);

if (BufferLength < *Offset + RequiredLength) {
return FALSE;
}

Buffer = Buffer + *Offset;
Buffer = QuicVarIntEncode(QUIC_FRAME_OBSERVED_ADDRESS_V4, Buffer);
Buffer = QuicVarIntEncode(Frame->SequenceNumber, Buffer);
CxPlatCopyMemory(Buffer, &Frame->Address.Ipv4.sin_addr, sizeof(Frame->Address.Ipv4.sin_addr));
Buffer += sizeof(Frame->Address.Ipv4.sin_addr);
CxPlatCopyMemory(Buffer, &Frame->Address.Ipv4.sin_port, sizeof(Frame->Address.Ipv4.sin_port));
Buffer += sizeof(Frame->Address.Ipv4.sin_port);
*Offset += RequiredLength;

} else {
const uint16_t RequiredLength =
QuicVarIntSize(QUIC_FRAME_OBSERVED_ADDRESS_V4) +
QuicVarIntSize(Frame->SequenceNumber) +
sizeof(Frame->Address.Ipv6.sin6_addr) +
sizeof(Frame->Address.Ipv6.sin6_port);

if (BufferLength < *Offset + RequiredLength) {
return FALSE;
}

Buffer = Buffer + *Offset;
Buffer = QuicVarIntEncode(QUIC_FRAME_OBSERVED_ADDRESS_V6, Buffer);
Buffer = QuicVarIntEncode(Frame->SequenceNumber, Buffer);
CxPlatCopyMemory(Buffer, &Frame->Address.Ipv6.sin6_addr, sizeof(Frame->Address.Ipv6.sin6_addr));
Buffer += sizeof(Frame->Address.Ipv6.sin6_addr);
CxPlatCopyMemory(Buffer, &Frame->Address.Ipv6.sin6_port, sizeof(Frame->Address.Ipv6.sin6_port));
Buffer += sizeof(Frame->Address.Ipv6.sin6_port);
*Offset += RequiredLength;
}

return TRUE;
}

_Success_(return != FALSE)
BOOLEAN
QuicObservedAddressFrameDecode(
_In_ QUIC_FRAME_TYPE FrameType,
_In_ uint16_t BufferLength,
_In_reads_bytes_(BufferLength)
const uint8_t * const Buffer,
_Inout_ uint16_t* Offset,
_Out_ QUIC_OBSERVED_ADDRESS_EX* Frame
)
{
if (!QuicVarIntDecode(BufferLength, Buffer, Offset, &Frame->SequenceNumber)) {
return FALSE;
}

if (FrameType == QUIC_FRAME_OBSERVED_ADDRESS_V4) {
if (BufferLength < *Offset + sizeof(Frame->Address.Ipv4)) {
return FALSE;
}
CxPlatZeroMemory(&Frame->Address.Ipv4, sizeof(Frame->Address.Ipv4));
Frame->Address.Ipv4.sin_family = QUIC_ADDRESS_FAMILY_INET6;
CxPlatCopyMemory(&Frame->Address.Ipv4.sin_addr, Buffer + *Offset, sizeof(Frame->Address.Ipv4.sin_addr));
*Offset += sizeof(Frame->Address.Ipv4.sin_addr);
CxPlatCopyMemory(&Frame->Address.Ipv4.sin_port, Buffer + *Offset, sizeof(Frame->Address.Ipv4.sin_port));
*Offset += sizeof(Frame->Address.Ipv4.sin_port);

} else {
if (BufferLength < *Offset + sizeof(Frame->Address.Ipv6)) {
return FALSE;
}
CxPlatZeroMemory(&Frame->Address.Ipv6, sizeof(Frame->Address.Ipv6));
Frame->Address.Ipv6.sin6_family = QUIC_ADDRESS_FAMILY_INET6;
CxPlatCopyMemory(&Frame->Address.Ipv6.sin6_addr, Buffer + *Offset, sizeof(Frame->Address.Ipv6.sin6_addr));
*Offset += sizeof(Frame->Address.Ipv6.sin6_addr);
CxPlatCopyMemory(&Frame->Address.Ipv6.sin6_port, Buffer + *Offset, sizeof(Frame->Address.Ipv6.sin6_port));
*Offset += sizeof(Frame->Address.Ipv6.sin6_port);
}

return TRUE;
}

_IRQL_requires_max_(DISPATCH_LEVEL)
BOOLEAN
QuicFrameLog(
Expand Down Expand Up @@ -1927,6 +2022,31 @@ QuicFrameLog(
break;
}

case QUIC_FRAME_RELIABLE_RESET_STREAM: {
QUIC_RELIABLE_RESET_STREAM_EX Frame;
if (!QuicReliableResetFrameDecode(PacketLength, Packet, Offset, &Frame)) {
QuicTraceLogVerbose(
FrameLogReliableResetStreamInvalid,
"[%c][%cX][%llu] RELIABLE_RESET_STREAM [Invalid]",
PtkConnPre(Connection),
PktRxPre(Rx),
PacketNumber);
return FALSE;
}

QuicTraceLogVerbose(
FrameLogReliableResetStream,
"[%c][%cX][%llu] RELIABLE_RESET_STREAM ID:%llu ErrorCode:0x%llX FinalSize:%llu ReliableSize:%llu",
PtkConnPre(Connection),
PktRxPre(Rx),
PacketNumber,
Frame.StreamID,
Frame.ErrorCode,
Frame.FinalSize,
Frame.ReliableSize);
break;
}

case QUIC_FRAME_DATAGRAM:
case QUIC_FRAME_DATAGRAM_1: {
QUIC_DATAGRAM_EX Frame;
Expand Down Expand Up @@ -1987,7 +2107,7 @@ QuicFrameLog(

case QUIC_FRAME_TIMESTAMP: {
QUIC_TIMESTAMP_EX Frame;
if (!QuicTimestampFrameDecode(PacketLength, Packet, Offset, &Frame)) {
if (!(PacketLength, Packet, Offset, &Frame)) {
QuicTraceLogVerbose(
FrameLogTimestampInvalid,
"[%c][%cX][%llu] TIMESTAMP [Invalid]",
Expand All @@ -2006,29 +2126,27 @@ QuicFrameLog(
Frame.Timestamp);
break;
}

case QUIC_FRAME_RELIABLE_RESET_STREAM: {
QUIC_RELIABLE_RESET_STREAM_EX Frame;
if (!QuicReliableResetFrameDecode(PacketLength, Packet, Offset, &Frame)) {

case QUIC_FRAME_OBSERVED_ADDRESS_V4:
case QUIC_FRAME_OBSERVED_ADDRESS_V6: {
QUIC_OBSERVED_ADDRESS_EX Frame;
if (!QuicObservedAddressFrameDecode(FrameType, PacketLength, Packet, Offset, &Frame)) {
QuicTraceLogVerbose(
FrameLogReliableResetStreamInvalid,
"[%c][%cX][%llu] RELIABLE_RESET_STREAM [Invalid]",
FrameLogObservedAddressInvalid,
"[%c][%cX][%llu] OBSERVED_ADDRESS [Invalid]",
PtkConnPre(Connection),
PktRxPre(Rx),
PacketNumber);
return FALSE;
}

QuicTraceLogVerbose(
FrameLogReliableResetStream,
"[%c][%cX][%llu] RELIABLE_RESET_STREAM ID:%llu ErrorCode:0x%llX FinalSize:%llu ReliableSize:%llu",
FrameLogObservedAddress,
"[%c][%cX][%llu] OBSERVED_ADDRESS %llu", // TODO - Address
PtkConnPre(Connection),
PktRxPre(Rx),
PacketNumber,
Frame.StreamID,
Frame.ErrorCode,
Frame.FinalSize,
Frame.ReliableSize);
Frame.SequenceNumber);
break;
}

Expand Down
Loading

0 comments on commit c9d4186

Please sign in to comment.