google quic服务端报文解析和分发分析

2023-10-20  本文已影响0人  JeffreyLau

前言


class QUIC_EXPORT QuicRawServer : public QuicSocketEventListener {
public:
  // QuicSocketEventListener implementation.
  void OnSocketEvent(QuicEventLoop* event_loop,
                     QuicUdpSocketFd fd,
                     QuicSocketEventMask events) override;
  ....
 protected:
   ....
  // Point to a QuicPacketReader object on the heap. The reader allocates more
  // space than allowed on the stack.
  std::unique_ptr<QuicPacketReader> packet_reader_;
};
void QuicRawServer::OnSocketEvent(QuicEventLoop* /*event_loop*/,
                                  QuicUdpSocketFd fd,
                                  QuicSocketEventMask events) {
  QUICHE_DCHECK_EQ(fd, fd_);

  if (events & kSocketEventReadable) {
    QUIC_DVLOG(1) << "EPOLLIN";
    // 第一次这里是没有的,如果握手包在传输中出现了乱序或者丢包
    dispatcher_->ProcessBufferedChlos(kNumSessionsToCreatePerSocketEvent);

    bool more_to_read = true;
    while (more_to_read) {
      more_to_read = packet_reader_->ReadAndDispatchPackets(
          fd_, port_, *QuicDefaultClock::Get(), dispatcher_.get(),
          overflow_supported_ ? &packets_dropped_ : nullptr);
    }

    if (dispatcher_->HasChlosBuffered()) {
      // Register EPOLLIN event to consume buffered CHLO(s).
      bool success =
          event_loop_->ArtificiallyNotifyEvent(fd_, kSocketEventReadable);
      QUICHE_DCHECK(success);
    }
    if (!event_loop_->SupportsEdgeTriggered()) {
      bool success = event_loop_->RearmSocket(fd_, kSocketEventReadable);
      QUICHE_DCHECK(success);
    }
  }
  if (events & kSocketEventWritable) {
    dispatcher_->OnCanWrite();
    if (!event_loop_->SupportsEdgeTriggered() &&
        dispatcher_->HasPendingWrites()) {
      bool success = event_loop_->RearmSocket(fd_, kSocketEventWritable);
      QUICHE_DCHECK(success);
    }
  }
}

ReceivedPacketInfo结构公众头部信息解析

void QuicDispatcher::ProcessPacket(const QuicSocketAddress& self_address,
                                   const QuicSocketAddress& peer_address,
                                   const QuicReceivedPacket& packet) {
  ReceivedPacketInfo packet_info(self_address, peer_address, packet);
  std::string detailed_error;
  QuicErrorCode error;
  error = QuicFramer::ParsePublicHeaderDispatcherShortHeaderLengthUnknown(
      packet, &packet_info.form, &packet_info.long_packet_type,
      &packet_info.version_flag, &packet_info.use_length_prefix,
      &packet_info.version_label, &packet_info.version,
      &packet_info.destination_connection_id, &packet_info.source_connection_id,
      &packet_info.retry_token, &detailed_error, connection_id_generator_);
  .....
}
// static
QuicErrorCode QuicFramer::ParsePublicHeaderDispatcherShortHeaderLengthUnknown(
    const QuicEncryptedPacket& packet, PacketHeaderFormat* format,
    QuicLongHeaderType* long_packet_type, bool* version_present,
    bool* has_length_prefix, QuicVersionLabel* version_label,
    ParsedQuicVersion* parsed_version,
    QuicConnectionId* destination_connection_id,
    QuicConnectionId* source_connection_id,
    absl::optional<absl::string_view>* retry_token, std::string* detailed_error,
    ConnectionIdGeneratorInterface& generator) {
  QuicDataReader reader(packet.data(), packet.length());
  // Get the first two bytes.
  if (reader.BytesRemaining() < 2) {
    *detailed_error = "Unable to read first two bytes.";
    return QUIC_INVALID_PACKET_HEADER;
  }
  uint8_t two_bytes[2];
  reader.ReadBytes(two_bytes, 2);
  // 如果长类型格式头部这个值为0
  uint8_t expected_destination_connection_id_length =
      (!QuicUtils::IsIetfPacketHeader(two_bytes[0]) ||
       two_bytes[0] & FLAGS_LONG_HEADER)
          ? 0
          : generator.ConnectionIdLength(two_bytes[1]);
  return ParsePublicHeaderDispatcher(
      packet, expected_destination_connection_id_length, format,
      long_packet_type, version_present, has_length_prefix, version_label,
      parsed_version, destination_connection_id, source_connection_id,
      retry_token, detailed_error);
}
// static
QuicErrorCode QuicFramer::ParsePublicHeaderDispatcher(
    const QuicEncryptedPacket& packet,
    uint8_t expected_destination_connection_id_length,
    PacketHeaderFormat* format, QuicLongHeaderType* long_packet_type,
    bool* version_present, bool* has_length_prefix,
    QuicVersionLabel* version_label, ParsedQuicVersion* parsed_version,
    QuicConnectionId* destination_connection_id,
    QuicConnectionId* source_connection_id,
    absl::optional<absl::string_view>* retry_token,
    std::string* detailed_error) {
  QuicDataReader reader(packet.data(), packet.length());
  if (reader.IsDoneReading()) {
    *detailed_error = "Unable to read first byte.";
    return QUIC_INVALID_PACKET_HEADER;
  }
  //1) 报文有效性判断
  const uint8_t first_byte = reader.PeekByte();
  if ((first_byte & FLAGS_LONG_HEADER) == 0 &&
      (first_byte & FLAGS_FIXED_BIT) == 0 &&
      (first_byte & FLAGS_DEMULTIPLEXING_BIT) == 0) {
    // All versions of Google QUIC up to and including Q043 set
    // FLAGS_DEMULTIPLEXING_BIT to one on all client-to-server packets. Q044
    // and Q045 were never default-enabled in production. All subsequent
    // versions of Google QUIC (starting with Q046) require FLAGS_FIXED_BIT to
    // be set to one on all packets. All versions of IETF QUIC (since
    // draft-ietf-quic-transport-17 which was earlier than the first IETF QUIC
    // version that was deployed in production by any implementation) also
    // require FLAGS_FIXED_BIT to be set to one on all packets. If a packet
    // has the FLAGS_LONG_HEADER bit set to one, it could be a first flight
    // from an unknown future version that allows the other two bits to be set
    // to zero. Based on this, packets that have all three of those bits set
    // to zero are known to be invalid.
    *detailed_error = "Invalid flags.";
    return QUIC_INVALID_PACKET_HEADER;
  }
  //2) ietf格式判断,也就是判断是走google 标准还是RFC ietf标准的包,默认都是走ietf的
  const bool ietf_format = QuicUtils::IsIetfPacketHeader(first_byte);
  uint8_t unused_first_byte;
  quiche::QuicheVariableLengthIntegerLength retry_token_length_length;
  absl::string_view maybe_retry_token;
  //3 )解析头部信息
  QuicErrorCode error_code = ParsePublicHeader(
      &reader, expected_destination_connection_id_length, ietf_format,
      &unused_first_byte, format, version_present, has_length_prefix,
      version_label, parsed_version, destination_connection_id,
      source_connection_id, long_packet_type, &retry_token_length_length,
      &maybe_retry_token, detailed_error);
  if (retry_token_length_length != quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0) {
    *retry_token = maybe_retry_token;
  } else {
    retry_token->reset();
  }
  return error_code;
}
Initial Packet {
  Header Form (1) = 1,
  Fixed Bit (1) = 1,
  Long Packet Type (2) = 0,
  Reserved Bits (2),
  Packet Number Length (2),
  Version (32),
  Destination Connection ID Length (8),
  Destination Connection ID (0..160),
  Source Connection ID Length (8),
  Source Connection ID (0..160),
  Token Length (i),
  Token (..),
  Length (i),
  Packet Number (8..32),
  Packet Payload (8..),
}

Figure 15: Initial Packet

// static
QuicErrorCode QuicFramer::ParsePublicHeader(
    QuicDataReader* reader, uint8_t expected_destination_connection_id_length,
    bool ietf_format, uint8_t* first_byte, PacketHeaderFormat* format,
    bool* version_present, bool* has_length_prefix,
    QuicVersionLabel* version_label, ParsedQuicVersion* parsed_version,
    QuicConnectionId* destination_connection_id,
    QuicConnectionId* source_connection_id,
    QuicLongHeaderType* long_packet_type,
    quiche::QuicheVariableLengthIntegerLength* retry_token_length_length,
    absl::string_view* retry_token, std::string* detailed_error) {
  *version_present = false;
  *has_length_prefix = false;
  *version_label = 0;
  *parsed_version = UnsupportedQuicVersion();
  *source_connection_id = EmptyQuicConnectionId();
  *long_packet_type = INVALID_PACKET_TYPE;
  *retry_token_length_length = quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0;
  *retry_token = absl::string_view();
  *detailed_error = "";

  if (!reader->ReadUInt8(first_byte)) {
    *detailed_error = "Unable to read first byte.";
    return QUIC_INVALID_PACKET_HEADER;
  }

  if (!ietf_format) {
    return ParsePublicHeaderGoogleQuic(
        reader, first_byte, format, version_present, version_label,
        parsed_version, destination_connection_id, detailed_error);
  }
  //1) 第一个字节
  *format = GetIetfPacketHeaderFormat(*first_byte);

  if (*format == IETF_QUIC_SHORT_HEADER_PACKET) {
    if (!reader->ReadConnectionId(destination_connection_id,
                                  expected_destination_connection_id_length)) {
      *detailed_error = "Unable to read destination connection ID.";
      return QUIC_INVALID_PACKET_HEADER;
    }
    return QUIC_NO_ERROR;
  }
  //2) Version字段
  QUICHE_DCHECK_EQ(IETF_QUIC_LONG_HEADER_PACKET, *format);
  *version_present = true;
  if (!ProcessVersionLabel(reader, version_label)) {
    *detailed_error = "Unable to read protocol version.";
    return QUIC_INVALID_PACKET_HEADER;
  }

  if (*version_label == 0) {
    *long_packet_type = VERSION_NEGOTIATION;
  }

  // Parse version.
  *parsed_version = ParseQuicVersionLabel(*version_label);

  // Figure out which IETF QUIC invariants this packet follows.
  //3) Destination/Source Connection ID legth和id相关解析
  // 大于QUIC 46的版本都是固定长度,其中80代表RFC9000也就是QUIC V1
  *has_length_prefix = PacketHasLengthPrefixedConnectionIds(
      *reader, *parsed_version, *version_label, *first_byte);

  // Parse connection IDs.
  if (!ParseLongHeaderConnectionIds(*reader, *has_length_prefix, *version_label,
                                    *destination_connection_id,
                                    *source_connection_id, *detailed_error)) {
    return QUIC_INVALID_PACKET_HEADER;
  }

  if (!parsed_version->IsKnown()) {
    // Skip parsing of long packet type and retry token for unknown versions.
    return QUIC_NO_ERROR;
  }
  //4) INITIAL、ZERO_RTT、HANDSHAKE还是RETRY
  // Parse long packet type.
  *long_packet_type = GetLongHeaderType(*first_byte, *parsed_version);

  switch (*long_packet_type) {
    case INVALID_PACKET_TYPE:
      *detailed_error = "Unable to parse long packet type.";
      return QUIC_INVALID_PACKET_HEADER;
    case INITIAL:
      if (!parsed_version->SupportsRetry()) {
        // Retry token is only present on initial packets for some versions.
        return QUIC_NO_ERROR;
      }
      break;
    default:
      return QUIC_NO_ERROR;
  }
  //5) 获取token长度这里使用可变长度编码规则,8个字节,高两位为11
  *retry_token_length_length = reader->PeekVarInt62Length();
  uint64_t retry_token_length;
  if (!reader->ReadVarInt62(&retry_token_length)) {
    *retry_token_length_length = quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0;
    *detailed_error = "Unable to read retry token length.";
    return QUIC_INVALID_PACKET_HEADER;
  }
  //获取token
  if (!reader->ReadStringPiece(retry_token, retry_token_length)) {
    *detailed_error = "Unable to read retry token.";
    return QUIC_INVALID_PACKET_HEADER;
  }

  return QUIC_NO_ERROR;
}

QuicDispatcher::MaybeDispatchPacket(...)尝试分发报文

void QuicDispatcher::ProcessPacket(const QuicSocketAddress& self_address,
                                   const QuicSocketAddress& peer_address,
                                   const QuicReceivedPacket& packet) {
  ReceivedPacketInfo packet_info(self_address, peer_address, packet);
  (解析头部信息)
  ....
  if (MaybeDispatchPacket(packet_info)) {
    // Packet has been dropped or successfully dispatched, stop processing.
    return;
  }
  ....
}
bool QuicDispatcher::MaybeDispatchPacket(
    const ReceivedPacketInfo& packet_info) {
  .....
  const QuicConnectionId server_connection_id =
      packet_info.destination_connection_id;

  //(此处省略对包头 QUIC 版本号等信息进行校验,如果校验通过继续往下走)

  // Packets with connection IDs for active connections are processed
  // immediately.
  auto it = reference_counted_session_map_.find(server_connection_id);
  if (it != reference_counted_session_map_.end()) {
    QUICHE_DCHECK(!buffered_packets_.HasBufferedPackets(server_connection_id));
    it->second->ProcessUdpPacket(packet_info.self_address,
                                 packet_info.peer_address, packet_info.packet);
    return true;
  }
  
  // 如果initial丢失、或者乱序、再或者由于initial包超过一个MTU,那么会使用这个Buffer缓存
  if (buffered_packets_.HasChloForConnection(server_connection_id)) {
    BufferEarlyPacket(packet_info);
    return true;
  }
  .....

  return false;
}

QuicDispatcher::ProcessHeader报文头部处理


void QuicDispatcher::ProcessHeader(ReceivedPacketInfo* packet_info) {
  QuicConnectionId server_connection_id =
      packet_info->destination_connection_id;
  // 包宿命检测,是kFateProcess、kFateTimeWait还是kFateDrop
  // Packet's connection ID is unknown.  Apply the validity checks.
  //1) 
  QuicPacketFate fate = ValidityChecks(*packet_info);

  // |connection_close_error_code| is used if the final packet fate is
  // kFateTimeWait.
  QuicErrorCode connection_close_error_code = QUIC_HANDSHAKE_FAILED;

  // If a fatal TLS alert was received when extracting Client Hello,
  // |tls_alert_error_detail| will be set and will be used as the error_details
  // of the connection close.
  std::string tls_alert_error_detail;
  //2) 
  if (fate == kFateProcess) {
    ExtractChloResult extract_chlo_result =
        TryExtractChloOrBufferEarlyPacket(*packet_info);
    auto& parsed_chlo = extract_chlo_result.parsed_chlo;

    if (extract_chlo_result.tls_alert.has_value()) {
        ....
    } else if (!parsed_chlo.has_value()) {
      // Client Hello incomplete. Packet has been buffered or (rarely) dropped.
      return;
    } else {
      // 2) 
      // Client Hello fully received.
      fate = ValidityChecksOnFullChlo(*packet_info, *parsed_chlo);

      if (fate == kFateProcess) {
        // 3)
        ProcessChlo(*std::move(parsed_chlo), packet_info);
        return;
      }
    }
  }
  ... 
}
void QuicDispatcher::ProcessChlo(ParsedClientHello parsed_chlo,
                                 ReceivedPacketInfo* packet_info) {
  ....
  //1)
  auto session_ptr = QuicDispatcher::CreateSessionFromChlo(
      packet_info->destination_connection_id, parsed_chlo, packet_info->version,
      packet_info->self_address, packet_info->peer_address);
  if (session_ptr == nullptr) {
    return;
  }
  // 假设乱序了,有报文在Initial报文之前达到,会存到该列表当中
  std::list<BufferedPacket> packets =
      buffered_packets_.DeliverPackets(packet_info->destination_connection_id)
          .buffered_packets;
  if (packet_info->destination_connection_id != session_ptr->connection_id()) {
    // Provide the calling function with access to the new connection ID.
    packet_info->destination_connection_id = session_ptr->connection_id();
    if (!packets.empty()) {
      QUIC_CODE_COUNT(
          quic_delivered_buffered_packets_to_connection_with_replaced_id);
    }
  }
  // 2)
  // Process CHLO at first.
  session_ptr->ProcessUdpPacket(packet_info->self_address,
                                packet_info->peer_address, packet_info->packet);
  // Deliver queued-up packets in the same order as they arrived.
  // Do this even when flag is off because there might be still some packets
  // buffered in the store before flag is turned off.
  DeliverPacketsToSession(packets, session_ptr.get());
  --new_sessions_allowed_per_event_loop_;
}

总结:

参考文献

上一篇 下一篇

猜你喜欢

热点阅读