xref: /third_party/node/src/quic/packet.cc (revision 1cb0ef41)
11cb0ef41Sopenharmony_ci#if HAVE_OPENSSL && NODE_OPENSSL_HAS_QUIC
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ci#include "packet.h"
41cb0ef41Sopenharmony_ci#include <base_object-inl.h>
51cb0ef41Sopenharmony_ci#include <crypto/crypto_util.h>
61cb0ef41Sopenharmony_ci#include <env-inl.h>
71cb0ef41Sopenharmony_ci#include <ngtcp2/ngtcp2.h>
81cb0ef41Sopenharmony_ci#include <ngtcp2/ngtcp2_crypto.h>
91cb0ef41Sopenharmony_ci#include <node_sockaddr-inl.h>
101cb0ef41Sopenharmony_ci#include <req_wrap-inl.h>
111cb0ef41Sopenharmony_ci#include <uv.h>
121cb0ef41Sopenharmony_ci#include <v8.h>
131cb0ef41Sopenharmony_ci#include <string>
141cb0ef41Sopenharmony_ci#include "bindingdata.h"
151cb0ef41Sopenharmony_ci#include "cid.h"
161cb0ef41Sopenharmony_ci#include "tokens.h"
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_cinamespace node {
191cb0ef41Sopenharmony_ci
201cb0ef41Sopenharmony_ciusing v8::FunctionTemplate;
211cb0ef41Sopenharmony_ciusing v8::Local;
221cb0ef41Sopenharmony_ciusing v8::Object;
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_cinamespace quic {
251cb0ef41Sopenharmony_ci
261cb0ef41Sopenharmony_cinamespace {
271cb0ef41Sopenharmony_cistatic constexpr size_t kRandlen = NGTCP2_MIN_STATELESS_RESET_RANDLEN * 5;
281cb0ef41Sopenharmony_cistatic constexpr size_t kMinStatelessResetLen = 41;
291cb0ef41Sopenharmony_cistatic constexpr size_t kMaxFreeList = 100;
301cb0ef41Sopenharmony_ci}  // namespace
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_cistruct Packet::Data final : public MemoryRetainer {
331cb0ef41Sopenharmony_ci  MaybeStackBuffer<uint8_t, kDefaultMaxPacketLength> data_;
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_ci  // The diagnostic_label_ is used only as a debugging tool when
361cb0ef41Sopenharmony_ci  // logging debug information about the packet. It identifies
371cb0ef41Sopenharmony_ci  // the purpose of the packet.
381cb0ef41Sopenharmony_ci  const std::string diagnostic_label_;
391cb0ef41Sopenharmony_ci
401cb0ef41Sopenharmony_ci  void MemoryInfo(MemoryTracker* tracker) const override {
411cb0ef41Sopenharmony_ci    tracker->TrackFieldWithSize("data", data_.length());
421cb0ef41Sopenharmony_ci  }
431cb0ef41Sopenharmony_ci  SET_MEMORY_INFO_NAME(Data)
441cb0ef41Sopenharmony_ci  SET_SELF_SIZE(Data)
451cb0ef41Sopenharmony_ci
461cb0ef41Sopenharmony_ci  Data(size_t length, std::string_view diagnostic_label)
471cb0ef41Sopenharmony_ci      : diagnostic_label_(diagnostic_label) {
481cb0ef41Sopenharmony_ci    data_.AllocateSufficientStorage(length);
491cb0ef41Sopenharmony_ci  }
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_ci  size_t length() const { return data_.length(); }
521cb0ef41Sopenharmony_ci  operator uv_buf_t() {
531cb0ef41Sopenharmony_ci    return uv_buf_init(reinterpret_cast<char*>(data_.out()), data_.length());
541cb0ef41Sopenharmony_ci  }
551cb0ef41Sopenharmony_ci  operator ngtcp2_vec() { return ngtcp2_vec{data_.out(), data_.length()}; }
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_ci  std::string ToString() const {
581cb0ef41Sopenharmony_ci    return diagnostic_label_ + ", " + std::to_string(length());
591cb0ef41Sopenharmony_ci  }
601cb0ef41Sopenharmony_ci};
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ciconst SocketAddress& Packet::destination() const {
631cb0ef41Sopenharmony_ci  return destination_;
641cb0ef41Sopenharmony_ci}
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_cibool Packet::is_sending() const {
671cb0ef41Sopenharmony_ci  return !!handle_;
681cb0ef41Sopenharmony_ci}
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_cisize_t Packet::length() const {
711cb0ef41Sopenharmony_ci  return data_ ? data_->length() : 0;
721cb0ef41Sopenharmony_ci}
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_ciPacket::operator uv_buf_t() const {
751cb0ef41Sopenharmony_ci  return !data_ ? uv_buf_init(nullptr, 0) : *data_;
761cb0ef41Sopenharmony_ci}
771cb0ef41Sopenharmony_ci
781cb0ef41Sopenharmony_ciPacket::operator ngtcp2_vec() const {
791cb0ef41Sopenharmony_ci  return !data_ ? ngtcp2_vec{nullptr, 0} : *data_;
801cb0ef41Sopenharmony_ci}
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_civoid Packet::Truncate(size_t len) {
831cb0ef41Sopenharmony_ci  DCHECK(data_);
841cb0ef41Sopenharmony_ci  DCHECK_LE(len, data_->length());
851cb0ef41Sopenharmony_ci  data_->data_.SetLength(len);
861cb0ef41Sopenharmony_ci}
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_ciLocal<FunctionTemplate> Packet::GetConstructorTemplate(Environment* env) {
891cb0ef41Sopenharmony_ci  auto& state = BindingData::Get(env);
901cb0ef41Sopenharmony_ci  Local<FunctionTemplate> tmpl = state.packet_constructor_template();
911cb0ef41Sopenharmony_ci  if (tmpl.IsEmpty()) {
921cb0ef41Sopenharmony_ci    tmpl = NewFunctionTemplate(env->isolate(), IllegalConstructor);
931cb0ef41Sopenharmony_ci    tmpl->Inherit(ReqWrap<uv_udp_send_t>::GetConstructorTemplate(env));
941cb0ef41Sopenharmony_ci    tmpl->InstanceTemplate()->SetInternalFieldCount(
951cb0ef41Sopenharmony_ci        Packet::kInternalFieldCount);
961cb0ef41Sopenharmony_ci    tmpl->SetClassName(state.packetwrap_string());
971cb0ef41Sopenharmony_ci    state.set_packet_constructor_template(tmpl);
981cb0ef41Sopenharmony_ci  }
991cb0ef41Sopenharmony_ci  return tmpl;
1001cb0ef41Sopenharmony_ci}
1011cb0ef41Sopenharmony_ci
1021cb0ef41Sopenharmony_ciBaseObjectPtr<Packet> Packet::Create(Environment* env,
1031cb0ef41Sopenharmony_ci                                     Listener* listener,
1041cb0ef41Sopenharmony_ci                                     const SocketAddress& destination,
1051cb0ef41Sopenharmony_ci                                     size_t length,
1061cb0ef41Sopenharmony_ci                                     const char* diagnostic_label) {
1071cb0ef41Sopenharmony_ci  auto& binding = BindingData::Get(env);
1081cb0ef41Sopenharmony_ci  if (binding.packet_freelist.empty()) {
1091cb0ef41Sopenharmony_ci    Local<Object> obj;
1101cb0ef41Sopenharmony_ci    if (UNLIKELY(!GetConstructorTemplate(env)
1111cb0ef41Sopenharmony_ci                      ->InstanceTemplate()
1121cb0ef41Sopenharmony_ci                      ->NewInstance(env->context())
1131cb0ef41Sopenharmony_ci                      .ToLocal(&obj))) {
1141cb0ef41Sopenharmony_ci      return BaseObjectPtr<Packet>();
1151cb0ef41Sopenharmony_ci    }
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ci    return MakeBaseObject<Packet>(
1181cb0ef41Sopenharmony_ci        env, listener, obj, destination, length, diagnostic_label);
1191cb0ef41Sopenharmony_ci  }
1201cb0ef41Sopenharmony_ci
1211cb0ef41Sopenharmony_ci  return FromFreeList(env,
1221cb0ef41Sopenharmony_ci                      std::make_shared<Data>(length, diagnostic_label),
1231cb0ef41Sopenharmony_ci                      listener,
1241cb0ef41Sopenharmony_ci                      destination);
1251cb0ef41Sopenharmony_ci}
1261cb0ef41Sopenharmony_ci
1271cb0ef41Sopenharmony_ciBaseObjectPtr<Packet> Packet::Clone() const {
1281cb0ef41Sopenharmony_ci  auto& binding = BindingData::Get(env());
1291cb0ef41Sopenharmony_ci  if (binding.packet_freelist.empty()) {
1301cb0ef41Sopenharmony_ci    Local<Object> obj;
1311cb0ef41Sopenharmony_ci    if (UNLIKELY(!GetConstructorTemplate(env())
1321cb0ef41Sopenharmony_ci                      ->InstanceTemplate()
1331cb0ef41Sopenharmony_ci                      ->NewInstance(env()->context())
1341cb0ef41Sopenharmony_ci                      .ToLocal(&obj))) {
1351cb0ef41Sopenharmony_ci      return BaseObjectPtr<Packet>();
1361cb0ef41Sopenharmony_ci    }
1371cb0ef41Sopenharmony_ci
1381cb0ef41Sopenharmony_ci    return MakeBaseObject<Packet>(env(), listener_, obj, destination_, data_);
1391cb0ef41Sopenharmony_ci  }
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_ci  return FromFreeList(env(), data_, listener_, destination_);
1421cb0ef41Sopenharmony_ci}
1431cb0ef41Sopenharmony_ci
1441cb0ef41Sopenharmony_ciBaseObjectPtr<Packet> Packet::FromFreeList(Environment* env,
1451cb0ef41Sopenharmony_ci                                           std::shared_ptr<Data> data,
1461cb0ef41Sopenharmony_ci                                           Listener* listener,
1471cb0ef41Sopenharmony_ci                                           const SocketAddress& destination) {
1481cb0ef41Sopenharmony_ci  auto& binding = BindingData::Get(env);
1491cb0ef41Sopenharmony_ci  auto obj = binding.packet_freelist.back();
1501cb0ef41Sopenharmony_ci  binding.packet_freelist.pop_back();
1511cb0ef41Sopenharmony_ci  DCHECK_EQ(env, obj->env());
1521cb0ef41Sopenharmony_ci  auto packet = static_cast<Packet*>(obj.get());
1531cb0ef41Sopenharmony_ci  packet->data_ = std::move(data);
1541cb0ef41Sopenharmony_ci  packet->destination_ = destination;
1551cb0ef41Sopenharmony_ci  packet->listener_ = listener;
1561cb0ef41Sopenharmony_ci  return BaseObjectPtr<Packet>(packet);
1571cb0ef41Sopenharmony_ci}
1581cb0ef41Sopenharmony_ci
1591cb0ef41Sopenharmony_ciPacket::Packet(Environment* env,
1601cb0ef41Sopenharmony_ci               Listener* listener,
1611cb0ef41Sopenharmony_ci               Local<Object> object,
1621cb0ef41Sopenharmony_ci               const SocketAddress& destination,
1631cb0ef41Sopenharmony_ci               std::shared_ptr<Data> data)
1641cb0ef41Sopenharmony_ci    : ReqWrap<uv_udp_send_t>(env, object, AsyncWrap::PROVIDER_QUIC_PACKET),
1651cb0ef41Sopenharmony_ci      listener_(listener),
1661cb0ef41Sopenharmony_ci      destination_(destination),
1671cb0ef41Sopenharmony_ci      data_(std::move(data)) {}
1681cb0ef41Sopenharmony_ci
1691cb0ef41Sopenharmony_ciPacket::Packet(Environment* env,
1701cb0ef41Sopenharmony_ci               Listener* listener,
1711cb0ef41Sopenharmony_ci               Local<Object> object,
1721cb0ef41Sopenharmony_ci               const SocketAddress& destination,
1731cb0ef41Sopenharmony_ci               size_t length,
1741cb0ef41Sopenharmony_ci               const char* diagnostic_label)
1751cb0ef41Sopenharmony_ci    : Packet(env,
1761cb0ef41Sopenharmony_ci             listener,
1771cb0ef41Sopenharmony_ci             object,
1781cb0ef41Sopenharmony_ci             destination,
1791cb0ef41Sopenharmony_ci             std::make_shared<Data>(length, diagnostic_label)) {}
1801cb0ef41Sopenharmony_ci
1811cb0ef41Sopenharmony_ciint Packet::Send(uv_udp_t* handle, BaseObjectPtr<BaseObject> ref) {
1821cb0ef41Sopenharmony_ci  if (is_sending()) return UV_EALREADY;
1831cb0ef41Sopenharmony_ci  if (data_ == nullptr) return UV_EINVAL;
1841cb0ef41Sopenharmony_ci  DCHECK(!is_sending());
1851cb0ef41Sopenharmony_ci  handle_ = std::move(ref);
1861cb0ef41Sopenharmony_ci  uv_buf_t buf = *this;
1871cb0ef41Sopenharmony_ci  return Dispatch(
1881cb0ef41Sopenharmony_ci      uv_udp_send,
1891cb0ef41Sopenharmony_ci      handle,
1901cb0ef41Sopenharmony_ci      &buf,
1911cb0ef41Sopenharmony_ci      1,
1921cb0ef41Sopenharmony_ci      destination().data(),
1931cb0ef41Sopenharmony_ci      uv_udp_send_cb{[](uv_udp_send_t* req, int status) {
1941cb0ef41Sopenharmony_ci        auto ptr = static_cast<Packet*>(ReqWrap<uv_udp_send_t>::from_req(req));
1951cb0ef41Sopenharmony_ci        ptr->Done(status);
1961cb0ef41Sopenharmony_ci        // Do not try accessing ptr after this. We don't know if it
1971cb0ef41Sopenharmony_ci        // was freelisted or destroyed. Either way, done means done.
1981cb0ef41Sopenharmony_ci      }});
1991cb0ef41Sopenharmony_ci}
2001cb0ef41Sopenharmony_ci
2011cb0ef41Sopenharmony_civoid Packet::Done(int status) {
2021cb0ef41Sopenharmony_ci  DCHECK_NOT_NULL(listener_);
2031cb0ef41Sopenharmony_ci  listener_->PacketDone(status);
2041cb0ef41Sopenharmony_ci  handle_.reset();
2051cb0ef41Sopenharmony_ci  data_.reset();
2061cb0ef41Sopenharmony_ci  listener_ = nullptr;
2071cb0ef41Sopenharmony_ci  Reset();
2081cb0ef41Sopenharmony_ci
2091cb0ef41Sopenharmony_ci  // As a performance optimization, we add this packet to a freelist
2101cb0ef41Sopenharmony_ci  // rather than deleting it but only if the freelist isn't too
2111cb0ef41Sopenharmony_ci  // big, we don't want to accumulate these things forever.
2121cb0ef41Sopenharmony_ci  auto& binding = BindingData::Get(env());
2131cb0ef41Sopenharmony_ci  if (binding.packet_freelist.size() < kMaxFreeList) {
2141cb0ef41Sopenharmony_ci    binding.packet_freelist.emplace_back(this);
2151cb0ef41Sopenharmony_ci  } else {
2161cb0ef41Sopenharmony_ci    delete this;
2171cb0ef41Sopenharmony_ci  }
2181cb0ef41Sopenharmony_ci}
2191cb0ef41Sopenharmony_ci
2201cb0ef41Sopenharmony_cistd::string Packet::ToString() const {
2211cb0ef41Sopenharmony_ci  if (!data_) return "Packet (<empty>)";
2221cb0ef41Sopenharmony_ci  return "Packet (" + data_->ToString() + ")";
2231cb0ef41Sopenharmony_ci}
2241cb0ef41Sopenharmony_ci
2251cb0ef41Sopenharmony_civoid Packet::MemoryInfo(MemoryTracker* tracker) const {
2261cb0ef41Sopenharmony_ci  tracker->TrackField("destination", destination_);
2271cb0ef41Sopenharmony_ci  tracker->TrackField("data", data_);
2281cb0ef41Sopenharmony_ci  tracker->TrackField("handle", handle_);
2291cb0ef41Sopenharmony_ci}
2301cb0ef41Sopenharmony_ci
2311cb0ef41Sopenharmony_ciBaseObjectPtr<Packet> Packet::CreateRetryPacket(
2321cb0ef41Sopenharmony_ci    Environment* env,
2331cb0ef41Sopenharmony_ci    Listener* listener,
2341cb0ef41Sopenharmony_ci    const PathDescriptor& path_descriptor,
2351cb0ef41Sopenharmony_ci    const TokenSecret& token_secret) {
2361cb0ef41Sopenharmony_ci  auto& random = CID::Factory::random();
2371cb0ef41Sopenharmony_ci  CID cid = random.Generate();
2381cb0ef41Sopenharmony_ci  RetryToken token(path_descriptor.version,
2391cb0ef41Sopenharmony_ci                   path_descriptor.remote_address,
2401cb0ef41Sopenharmony_ci                   cid,
2411cb0ef41Sopenharmony_ci                   path_descriptor.dcid,
2421cb0ef41Sopenharmony_ci                   token_secret);
2431cb0ef41Sopenharmony_ci  if (!token) return BaseObjectPtr<Packet>();
2441cb0ef41Sopenharmony_ci
2451cb0ef41Sopenharmony_ci  const ngtcp2_vec& vec = token;
2461cb0ef41Sopenharmony_ci
2471cb0ef41Sopenharmony_ci  size_t pktlen =
2481cb0ef41Sopenharmony_ci      vec.len + (2 * NGTCP2_MAX_CIDLEN) + path_descriptor.scid.length() + 8;
2491cb0ef41Sopenharmony_ci
2501cb0ef41Sopenharmony_ci  auto packet =
2511cb0ef41Sopenharmony_ci      Create(env, listener, path_descriptor.remote_address, pktlen, "retry");
2521cb0ef41Sopenharmony_ci  if (!packet) return BaseObjectPtr<Packet>();
2531cb0ef41Sopenharmony_ci
2541cb0ef41Sopenharmony_ci  ngtcp2_vec dest = *packet;
2551cb0ef41Sopenharmony_ci
2561cb0ef41Sopenharmony_ci  ssize_t nwrite = ngtcp2_crypto_write_retry(dest.base,
2571cb0ef41Sopenharmony_ci                                             pktlen,
2581cb0ef41Sopenharmony_ci                                             path_descriptor.version,
2591cb0ef41Sopenharmony_ci                                             path_descriptor.scid,
2601cb0ef41Sopenharmony_ci                                             cid,
2611cb0ef41Sopenharmony_ci                                             path_descriptor.dcid,
2621cb0ef41Sopenharmony_ci                                             vec.base,
2631cb0ef41Sopenharmony_ci                                             vec.len);
2641cb0ef41Sopenharmony_ci  if (nwrite <= 0) return BaseObjectPtr<Packet>();
2651cb0ef41Sopenharmony_ci  packet->Truncate(static_cast<size_t>(nwrite));
2661cb0ef41Sopenharmony_ci  return packet;
2671cb0ef41Sopenharmony_ci}
2681cb0ef41Sopenharmony_ci
2691cb0ef41Sopenharmony_ciBaseObjectPtr<Packet> Packet::CreateConnectionClosePacket(
2701cb0ef41Sopenharmony_ci    Environment* env,
2711cb0ef41Sopenharmony_ci    Listener* listener,
2721cb0ef41Sopenharmony_ci    const SocketAddress& destination,
2731cb0ef41Sopenharmony_ci    ngtcp2_conn* conn,
2741cb0ef41Sopenharmony_ci    const QuicError& error) {
2751cb0ef41Sopenharmony_ci  auto packet = Packet::Create(
2761cb0ef41Sopenharmony_ci      env, listener, destination, kDefaultMaxPacketLength, "connection close");
2771cb0ef41Sopenharmony_ci  ngtcp2_vec vec = *packet;
2781cb0ef41Sopenharmony_ci
2791cb0ef41Sopenharmony_ci  ssize_t nwrite = ngtcp2_conn_write_connection_close(
2801cb0ef41Sopenharmony_ci      conn, nullptr, nullptr, vec.base, vec.len, error, uv_hrtime());
2811cb0ef41Sopenharmony_ci  if (nwrite < 0) return BaseObjectPtr<Packet>();
2821cb0ef41Sopenharmony_ci  packet->Truncate(static_cast<size_t>(nwrite));
2831cb0ef41Sopenharmony_ci  return packet;
2841cb0ef41Sopenharmony_ci}
2851cb0ef41Sopenharmony_ci
2861cb0ef41Sopenharmony_ciBaseObjectPtr<Packet> Packet::CreateImmediateConnectionClosePacket(
2871cb0ef41Sopenharmony_ci    Environment* env,
2881cb0ef41Sopenharmony_ci    Listener* listener,
2891cb0ef41Sopenharmony_ci    const SocketAddress& destination,
2901cb0ef41Sopenharmony_ci    const PathDescriptor& path_descriptor,
2911cb0ef41Sopenharmony_ci    const QuicError& reason) {
2921cb0ef41Sopenharmony_ci  auto packet = Packet::Create(env,
2931cb0ef41Sopenharmony_ci                               listener,
2941cb0ef41Sopenharmony_ci                               path_descriptor.remote_address,
2951cb0ef41Sopenharmony_ci                               kDefaultMaxPacketLength,
2961cb0ef41Sopenharmony_ci                               "immediate connection close (endpoint)");
2971cb0ef41Sopenharmony_ci  ngtcp2_vec vec = *packet;
2981cb0ef41Sopenharmony_ci  ssize_t nwrite = ngtcp2_crypto_write_connection_close(
2991cb0ef41Sopenharmony_ci      vec.base,
3001cb0ef41Sopenharmony_ci      vec.len,
3011cb0ef41Sopenharmony_ci      path_descriptor.version,
3021cb0ef41Sopenharmony_ci      path_descriptor.dcid,
3031cb0ef41Sopenharmony_ci      path_descriptor.scid,
3041cb0ef41Sopenharmony_ci      reason.code(),
3051cb0ef41Sopenharmony_ci      // We do not bother sending a reason string here, even if
3061cb0ef41Sopenharmony_ci      // there is one in the QuicError
3071cb0ef41Sopenharmony_ci      nullptr,
3081cb0ef41Sopenharmony_ci      0);
3091cb0ef41Sopenharmony_ci  if (nwrite <= 0) return BaseObjectPtr<Packet>();
3101cb0ef41Sopenharmony_ci  packet->Truncate(static_cast<size_t>(nwrite));
3111cb0ef41Sopenharmony_ci  return packet;
3121cb0ef41Sopenharmony_ci}
3131cb0ef41Sopenharmony_ci
3141cb0ef41Sopenharmony_ciBaseObjectPtr<Packet> Packet::CreateStatelessResetPacket(
3151cb0ef41Sopenharmony_ci    Environment* env,
3161cb0ef41Sopenharmony_ci    Listener* listener,
3171cb0ef41Sopenharmony_ci    const PathDescriptor& path_descriptor,
3181cb0ef41Sopenharmony_ci    const TokenSecret& token_secret,
3191cb0ef41Sopenharmony_ci    size_t source_len) {
3201cb0ef41Sopenharmony_ci  // Per the QUIC spec, a stateless reset token must be strictly smaller than
3211cb0ef41Sopenharmony_ci  // the packet that triggered it. This is one of the mechanisms to prevent
3221cb0ef41Sopenharmony_ci  // infinite looping exchange of stateless tokens with the peer. An endpoint
3231cb0ef41Sopenharmony_ci  // should never send a stateless reset token smaller than 41 bytes per the
3241cb0ef41Sopenharmony_ci  // QUIC spec. The reason is that packets less than 41 bytes may allow an
3251cb0ef41Sopenharmony_ci  // observer to reliably determine that it's a stateless reset.
3261cb0ef41Sopenharmony_ci  size_t pktlen = source_len - 1;
3271cb0ef41Sopenharmony_ci  if (pktlen < kMinStatelessResetLen) return BaseObjectPtr<Packet>();
3281cb0ef41Sopenharmony_ci
3291cb0ef41Sopenharmony_ci  StatelessResetToken token(token_secret, path_descriptor.dcid);
3301cb0ef41Sopenharmony_ci  uint8_t random[kRandlen];
3311cb0ef41Sopenharmony_ci  CHECK(crypto::CSPRNG(random, kRandlen).is_ok());
3321cb0ef41Sopenharmony_ci
3331cb0ef41Sopenharmony_ci  auto packet = Packet::Create(env,
3341cb0ef41Sopenharmony_ci                               listener,
3351cb0ef41Sopenharmony_ci                               path_descriptor.remote_address,
3361cb0ef41Sopenharmony_ci                               kDefaultMaxPacketLength,
3371cb0ef41Sopenharmony_ci                               "stateless reset");
3381cb0ef41Sopenharmony_ci  ngtcp2_vec vec = *packet;
3391cb0ef41Sopenharmony_ci
3401cb0ef41Sopenharmony_ci  ssize_t nwrite = ngtcp2_pkt_write_stateless_reset(
3411cb0ef41Sopenharmony_ci      vec.base, pktlen, token, random, kRandlen);
3421cb0ef41Sopenharmony_ci  if (nwrite <= static_cast<ssize_t>(kMinStatelessResetLen)) {
3431cb0ef41Sopenharmony_ci    return BaseObjectPtr<Packet>();
3441cb0ef41Sopenharmony_ci  }
3451cb0ef41Sopenharmony_ci
3461cb0ef41Sopenharmony_ci  packet->Truncate(static_cast<size_t>(nwrite));
3471cb0ef41Sopenharmony_ci  return packet;
3481cb0ef41Sopenharmony_ci}
3491cb0ef41Sopenharmony_ci
3501cb0ef41Sopenharmony_ciBaseObjectPtr<Packet> Packet::CreateVersionNegotiationPacket(
3511cb0ef41Sopenharmony_ci    Environment* env,
3521cb0ef41Sopenharmony_ci    Listener* listener,
3531cb0ef41Sopenharmony_ci    const PathDescriptor& path_descriptor) {
3541cb0ef41Sopenharmony_ci  const auto generateReservedVersion = [&] {
3551cb0ef41Sopenharmony_ci    socklen_t addrlen = path_descriptor.remote_address.length();
3561cb0ef41Sopenharmony_ci    uint32_t h = 0x811C9DC5u;
3571cb0ef41Sopenharmony_ci    uint32_t ver = htonl(path_descriptor.version);
3581cb0ef41Sopenharmony_ci    const uint8_t* p = path_descriptor.remote_address.raw();
3591cb0ef41Sopenharmony_ci    const uint8_t* ep = p + addrlen;
3601cb0ef41Sopenharmony_ci    for (; p != ep; ++p) {
3611cb0ef41Sopenharmony_ci      h ^= *p;
3621cb0ef41Sopenharmony_ci      h *= 0x01000193u;
3631cb0ef41Sopenharmony_ci    }
3641cb0ef41Sopenharmony_ci    p = reinterpret_cast<const uint8_t*>(&ver);
3651cb0ef41Sopenharmony_ci    ep = p + sizeof(path_descriptor.version);
3661cb0ef41Sopenharmony_ci    for (; p != ep; ++p) {
3671cb0ef41Sopenharmony_ci      h ^= *p;
3681cb0ef41Sopenharmony_ci      h *= 0x01000193u;
3691cb0ef41Sopenharmony_ci    }
3701cb0ef41Sopenharmony_ci    h &= 0xf0f0f0f0u;
3711cb0ef41Sopenharmony_ci    h |= NGTCP2_RESERVED_VERSION_MASK;
3721cb0ef41Sopenharmony_ci    return h;
3731cb0ef41Sopenharmony_ci  };
3741cb0ef41Sopenharmony_ci
3751cb0ef41Sopenharmony_ci  uint32_t sv[3] = {
3761cb0ef41Sopenharmony_ci      generateReservedVersion(), NGTCP2_PROTO_VER_MIN, NGTCP2_PROTO_VER_MAX};
3771cb0ef41Sopenharmony_ci
3781cb0ef41Sopenharmony_ci  size_t pktlen = path_descriptor.dcid.length() +
3791cb0ef41Sopenharmony_ci                  path_descriptor.scid.length() + (sizeof(sv)) + 7;
3801cb0ef41Sopenharmony_ci
3811cb0ef41Sopenharmony_ci  auto packet = Packet::Create(env,
3821cb0ef41Sopenharmony_ci                               listener,
3831cb0ef41Sopenharmony_ci                               path_descriptor.remote_address,
3841cb0ef41Sopenharmony_ci                               kDefaultMaxPacketLength,
3851cb0ef41Sopenharmony_ci                               "version negotiation");
3861cb0ef41Sopenharmony_ci  ngtcp2_vec vec = *packet;
3871cb0ef41Sopenharmony_ci
3881cb0ef41Sopenharmony_ci  ssize_t nwrite =
3891cb0ef41Sopenharmony_ci      ngtcp2_pkt_write_version_negotiation(vec.base,
3901cb0ef41Sopenharmony_ci                                           pktlen,
3911cb0ef41Sopenharmony_ci                                           0,
3921cb0ef41Sopenharmony_ci                                           path_descriptor.dcid,
3931cb0ef41Sopenharmony_ci                                           path_descriptor.dcid.length(),
3941cb0ef41Sopenharmony_ci                                           path_descriptor.scid,
3951cb0ef41Sopenharmony_ci                                           path_descriptor.scid.length(),
3961cb0ef41Sopenharmony_ci                                           sv,
3971cb0ef41Sopenharmony_ci                                           arraysize(sv));
3981cb0ef41Sopenharmony_ci  if (nwrite <= 0) return BaseObjectPtr<Packet>();
3991cb0ef41Sopenharmony_ci  packet->Truncate(static_cast<size_t>(nwrite));
4001cb0ef41Sopenharmony_ci  return packet;
4011cb0ef41Sopenharmony_ci}
4021cb0ef41Sopenharmony_ci
4031cb0ef41Sopenharmony_ci}  // namespace quic
4041cb0ef41Sopenharmony_ci}  // namespace node
4051cb0ef41Sopenharmony_ci
4061cb0ef41Sopenharmony_ci#endif  // HAVE_OPENSSL && NODE_OPENSSL_HAS_QUIC
407