• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #if HAVE_OPENSSL && NODE_OPENSSL_HAS_QUIC
2 
3 #include "transportparams.h"
4 #include <env-inl.h>
5 #include <memory_tracker-inl.h>
6 #include <node_sockaddr-inl.h>
7 #include <util-inl.h>
8 #include <v8.h>
9 #include "bindingdata.h"
10 #include "defs.h"
11 #include "tokens.h"
12 
13 namespace node {
14 
15 using v8::ArrayBuffer;
16 using v8::Just;
17 using v8::Local;
18 using v8::Maybe;
19 using v8::Nothing;
20 using v8::Object;
21 using v8::Value;
22 
23 namespace quic {
Config(Side side,const CID & ocid,const CID & retry_scid)24 TransportParams::Config::Config(Side side,
25                                 const CID& ocid,
26                                 const CID& retry_scid)
27     : side(side), ocid(ocid), retry_scid(retry_scid) {}
28 
From(Environment * env,Local<Value> value)29 Maybe<const TransportParams::Options> TransportParams::Options::From(
30     Environment* env, Local<Value> value) {
31   if (value.IsEmpty() || !value->IsObject()) {
32     return Nothing<const Options>();
33   }
34 
35   auto& state = BindingData::Get(env);
36   auto params = value.As<Object>();
37   Options options;
38 
39 #define SET(name)                                                              \
40   SetOption<TransportParams::Options, &TransportParams::Options::name>(        \
41       env, &options, params, state.name##_string())
42 
43   if (!SET(initial_max_stream_data_bidi_local) ||
44       !SET(initial_max_stream_data_bidi_remote) ||
45       !SET(initial_max_stream_data_uni) || !SET(initial_max_data) ||
46       !SET(initial_max_streams_bidi) || !SET(initial_max_streams_uni) ||
47       !SET(max_idle_timeout) || !SET(active_connection_id_limit) ||
48       !SET(ack_delay_exponent) || !SET(max_ack_delay) ||
49       !SET(max_datagram_frame_size) || !SET(disable_active_migration)) {
50     return Nothing<const Options>();
51   }
52 
53 #undef SET
54 
55   return Just<const Options>(options);
56 }
57 
TransportParams(Type type)58 TransportParams::TransportParams(Type type) : type_(type), ptr_(&params_) {}
59 
TransportParams(Type type,const ngtcp2_transport_params * ptr)60 TransportParams::TransportParams(Type type, const ngtcp2_transport_params* ptr)
61     : type_(type), ptr_(ptr) {}
62 
TransportParams(const Config & config,const Options & options)63 TransportParams::TransportParams(const Config& config, const Options& options)
64     : TransportParams(Type::ENCRYPTED_EXTENSIONS) {
65   ngtcp2_transport_params_default(&params_);
66   params_.active_connection_id_limit = options.active_connection_id_limit;
67   params_.initial_max_stream_data_bidi_local =
68       options.initial_max_stream_data_bidi_local;
69   params_.initial_max_stream_data_bidi_remote =
70       options.initial_max_stream_data_bidi_remote;
71   params_.initial_max_stream_data_uni = options.initial_max_stream_data_uni;
72   params_.initial_max_streams_bidi = options.initial_max_streams_bidi;
73   params_.initial_max_streams_uni = options.initial_max_streams_uni;
74   params_.initial_max_data = options.initial_max_data;
75   params_.max_idle_timeout = options.max_idle_timeout * NGTCP2_SECONDS;
76   params_.max_ack_delay = options.max_ack_delay;
77   params_.ack_delay_exponent = options.ack_delay_exponent;
78   params_.max_datagram_frame_size = options.max_datagram_frame_size;
79   params_.disable_active_migration = options.disable_active_migration ? 1 : 0;
80   params_.preferred_address_present = 0;
81   params_.stateless_reset_token_present = 0;
82   params_.retry_scid_present = 0;
83 
84   if (config.side == Side::SERVER) {
85     // For the server side, the original dcid is always set.
86     CHECK(config.ocid);
87     params_.original_dcid = config.ocid;
88 
89     // The retry_scid is only set if the server validated a retry token.
90     if (config.retry_scid) {
91       params_.retry_scid = config.retry_scid;
92       params_.retry_scid_present = 1;
93     }
94   }
95 
96   if (options.preferred_address_ipv4.has_value())
97     SetPreferredAddress(options.preferred_address_ipv4.value());
98 
99   if (options.preferred_address_ipv6.has_value())
100     SetPreferredAddress(options.preferred_address_ipv6.value());
101 }
102 
TransportParams(Type type,const ngtcp2_vec & vec)103 TransportParams::TransportParams(Type type, const ngtcp2_vec& vec)
104     : TransportParams(type) {
105   int ret = ngtcp2_decode_transport_params(
106       &params_,
107       static_cast<ngtcp2_transport_params_type>(type),
108       vec.base,
109       vec.len);
110 
111   if (ret != 0) {
112     ptr_ = nullptr;
113     error_ = QuicError::ForNgtcp2Error(ret);
114   }
115 }
116 
Encode(Environment * env)117 Store TransportParams::Encode(Environment* env) {
118   if (ptr_ == nullptr) {
119     error_ = QuicError::ForNgtcp2Error(NGTCP2_INTERNAL_ERROR);
120     return Store();
121   }
122 
123   // Preflight to see how much storage we'll need.
124   ssize_t size = ngtcp2_encode_transport_params(
125       nullptr, 0, static_cast<ngtcp2_transport_params_type>(type_), &params_);
126 
127   DCHECK_GT(size, 0);
128 
129   auto result = ArrayBuffer::NewBackingStore(env->isolate(), size);
130 
131   auto ret = ngtcp2_encode_transport_params(
132       static_cast<uint8_t*>(result->Data()),
133       size,
134       static_cast<ngtcp2_transport_params_type>(type_),
135       &params_);
136 
137   if (ret != 0) {
138     error_ = QuicError::ForNgtcp2Error(ret);
139     return Store();
140   }
141 
142   return Store(std::move(result), static_cast<size_t>(size));
143 }
144 
SetPreferredAddress(const SocketAddress & address)145 void TransportParams::SetPreferredAddress(const SocketAddress& address) {
146   DCHECK(ptr_ == &params_);
147   params_.preferred_address_present = 1;
148   switch (address.family()) {
149     case AF_INET: {
150       const sockaddr_in* src =
151           reinterpret_cast<const sockaddr_in*>(address.data());
152       memcpy(params_.preferred_address.ipv4_addr,
153              &src->sin_addr,
154              sizeof(params_.preferred_address.ipv4_addr));
155       params_.preferred_address.ipv4_port = address.port();
156       return;
157     }
158     case AF_INET6: {
159       const sockaddr_in6* src =
160           reinterpret_cast<const sockaddr_in6*>(address.data());
161       memcpy(params_.preferred_address.ipv6_addr,
162              &src->sin6_addr,
163              sizeof(params_.preferred_address.ipv6_addr));
164       params_.preferred_address.ipv6_port = address.port();
165       return;
166     }
167   }
168   UNREACHABLE();
169 }
170 
GenerateStatelessResetToken(const TokenSecret & token_secret,const CID & cid)171 void TransportParams::GenerateStatelessResetToken(
172     const TokenSecret& token_secret, const CID& cid) {
173   DCHECK(ptr_ == &params_);
174   DCHECK(cid);
175   params_.stateless_reset_token_present = 1;
176 
177   StatelessResetToken token(params_.stateless_reset_token, token_secret, cid);
178 }
179 
GeneratePreferredAddressToken(const Session & session)180 CID TransportParams::GeneratePreferredAddressToken(const Session& session) {
181   DCHECK(ptr_ == &params_);
182   // DCHECK(pscid);
183   // TODO(@jasnell): To be implemented when Session is implemented
184   // *pscid = session->cid_factory_.Generate();
185   // params_.preferred_address.cid = *pscid;
186   // session->endpoint_->AssociateStatelessResetToken(
187   //     session->endpoint().GenerateNewStatelessResetToken(
188   //       params_.preferred_address.stateless_reset_token, *pscid),
189   //     session);
190   return CID::kInvalid;
191 }
192 
type() const193 TransportParams::Type TransportParams::type() const {
194   return type_;
195 }
196 
operator const ngtcp2_transport_params&() const197 TransportParams::operator const ngtcp2_transport_params&() const {
198   DCHECK_NOT_NULL(ptr_);
199   return *ptr_;
200 }
201 
operator const ngtcp2_transport_params*() const202 TransportParams::operator const ngtcp2_transport_params*() const {
203   DCHECK_NOT_NULL(ptr_);
204   return ptr_;
205 }
206 
operator bool() const207 TransportParams::operator bool() const {
208   return ptr_ != nullptr;
209 }
210 
error() const211 const QuicError& TransportParams::error() const {
212   return error_;
213 }
214 
215 }  // namespace quic
216 }  // namespace node
217 
218 #endif  // HAVE_OPENSSL && NODE_OPENSSL_HAS_QUIC
219