Coverage Report

Created: 2025-10-31 09:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/node/src/node_sockaddr.h
Line
Count
Source
1
#ifndef SRC_NODE_SOCKADDR_H_
2
#define SRC_NODE_SOCKADDR_H_
3
4
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5
6
#include "env.h"
7
#include "memory_tracker.h"
8
#include "base_object.h"
9
#include "node.h"
10
#include "node_worker.h"
11
#include "uv.h"
12
#include "v8.h"
13
14
#include <compare>
15
#include <list>
16
#include <memory>
17
#include <string>
18
#include <unordered_map>
19
20
namespace node {
21
22
class Environment;
23
24
class SocketAddress : public MemoryRetainer {
25
 public:
26
  struct Hash {
27
    size_t operator()(const SocketAddress& addr) const;
28
  };
29
30
  inline bool operator==(const SocketAddress& other) const;
31
  inline bool operator!=(const SocketAddress& other) const;
32
33
  inline std::partial_ordering operator<=>(const SocketAddress& other) const;
34
35
  inline static bool is_numeric_host(const char* hostname);
36
  inline static bool is_numeric_host(const char* hostname, int family);
37
38
  // Returns true if converting {family, host, port} to *addr succeeded.
39
  static bool ToSockAddr(
40
      int32_t family,
41
      const char* host,
42
      uint32_t port,
43
      sockaddr_storage* addr);
44
45
  // Returns true if converting {family, host, port} to *addr succeeded.
46
  static bool New(
47
      int32_t family,
48
      const char* host,
49
      uint32_t port,
50
      SocketAddress* addr);
51
52
  static bool New(
53
      const char* host,
54
      uint32_t port,
55
      SocketAddress* addr);
56
57
  // Returns the port for an IPv4 or IPv6 address.
58
  inline static int GetPort(const sockaddr* addr);
59
  inline static int GetPort(const sockaddr_storage* addr);
60
61
  // Returns the numeric host as a string for an IPv4 or IPv6 address.
62
  inline static std::string GetAddress(const sockaddr* addr);
63
  inline static std::string GetAddress(const sockaddr_storage* addr);
64
65
  // Returns the struct length for an IPv4, IPv6 or UNIX domain.
66
  inline static size_t GetLength(const sockaddr* addr);
67
  inline static size_t GetLength(const sockaddr_storage* addr);
68
69
0
  SocketAddress() = default;
70
71
  inline explicit SocketAddress(const sockaddr* addr);
72
  inline SocketAddress(const SocketAddress& addr);
73
  inline SocketAddress& operator=(const sockaddr* other);
74
  inline SocketAddress& operator=(const SocketAddress& other);
75
76
  inline const sockaddr& operator*() const;
77
  inline const sockaddr* operator->() const;
78
79
  inline const sockaddr* data() const;
80
  inline const uint8_t* raw() const;
81
  inline sockaddr* storage();
82
  inline size_t length() const;
83
84
  inline int family() const;
85
  inline std::string address() const;
86
  inline int port() const;
87
88
  // Returns true if the given other SocketAddress is a match
89
  // for this one. The addresses are a match if:
90
  // 1. They are the same family and match identically
91
  // 2. They are different family but match semantically (
92
  //     for instance, an IPv4 address in IPv6 notation)
93
  bool is_match(const SocketAddress& other) const;
94
95
  // Compares this SocketAddress to the given other SocketAddress.
96
  std::partial_ordering compare(const SocketAddress& other) const;
97
98
  // Returns true if this SocketAddress is within the subnet
99
  // identified by the given network address and CIDR prefix.
100
  bool is_in_network(const SocketAddress& network, int prefix) const;
101
102
  // If the SocketAddress is an IPv6 address, returns the
103
  // current value of the IPv6 flow label, if set. Otherwise
104
  // returns 0.
105
  inline uint32_t flow_label() const;
106
107
  // If the SocketAddress is an IPv6 address, sets the
108
  // current value of the IPv6 flow label. If not an
109
  // IPv6 address, set_flow_label is a non-op. It
110
  // is important to note that the flow label,
111
  // while represented as an uint32_t, the flow
112
  // label is strictly limited to 20 bits, and
113
  // this will assert if any value larger than
114
  // 20-bits is specified.
115
  inline void set_flow_label(uint32_t label = 0);
116
117
  inline void Update(uint8_t* data, size_t len);
118
  inline void Update(const sockaddr* data, size_t len);
119
120
  static SocketAddress FromSockName(const uv_udp_t& handle);
121
  static SocketAddress FromSockName(const uv_tcp_t& handle);
122
  static SocketAddress FromPeerName(const uv_udp_t& handle);
123
  static SocketAddress FromPeerName(const uv_tcp_t& handle);
124
125
  inline v8::MaybeLocal<v8::Object> ToJS(
126
      Environment* env,
127
      v8::Local<v8::Object> obj = v8::Local<v8::Object>()) const;
128
129
  inline std::string ToString() const;
130
131
  SET_NO_MEMORY_INFO()
132
  SET_MEMORY_INFO_NAME(SocketAddress)
133
  SET_SELF_SIZE(SocketAddress)
134
135
  template <typename T>
136
  using Map = std::unordered_map<SocketAddress, T, Hash>;
137
138
 private:
139
  sockaddr_storage address_;
140
};
141
142
class SocketAddressBase : public BaseObject {
143
 public:
144
  static bool HasInstance(Environment* env, v8::Local<v8::Value> value);
145
  static v8::Local<v8::FunctionTemplate> GetConstructorTemplate(
146
      Environment* env);
147
  static void Initialize(Environment* env, v8::Local<v8::Object> target);
148
  static BaseObjectPtr<SocketAddressBase> Create(
149
      Environment* env,
150
      std::shared_ptr<SocketAddress> address);
151
152
  static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
153
  static void Detail(const v8::FunctionCallbackInfo<v8::Value>& args);
154
  static void LegacyDetail(const v8::FunctionCallbackInfo<v8::Value>& args);
155
  static void GetFlowLabel(const v8::FunctionCallbackInfo<v8::Value>& args);
156
157
  SocketAddressBase(
158
    Environment* env,
159
    v8::Local<v8::Object> wrap,
160
    std::shared_ptr<SocketAddress> address);
161
162
0
  inline const std::shared_ptr<SocketAddress>& address() const {
163
0
    return address_;
164
0
  }
165
166
  void MemoryInfo(MemoryTracker* tracker) const override;
167
  SET_MEMORY_INFO_NAME(SocketAddressBase)
168
  SET_SELF_SIZE(SocketAddressBase)
169
170
0
  BaseObject::TransferMode GetTransferMode() const override {
171
0
    return TransferMode::kCloneable;
172
0
  }
173
  std::unique_ptr<worker::TransferData> CloneForMessaging() const override;
174
175
  class TransferData : public worker::TransferData {
176
   public:
177
    inline explicit TransferData(const SocketAddressBase* wrap)
178
0
        : address_(wrap->address_) {}
179
180
    inline explicit TransferData(std::shared_ptr<SocketAddress> address)
181
0
        : address_(std::move(address)) {}
182
183
    BaseObjectPtr<BaseObject> Deserialize(
184
        Environment* env,
185
        v8::Local<v8::Context> context,
186
        std::unique_ptr<worker::TransferData> self) override;
187
188
    void MemoryInfo(MemoryTracker* tracker) const override;
189
    SET_MEMORY_INFO_NAME(SocketAddressBase::TransferData)
190
    SET_SELF_SIZE(TransferData)
191
192
   private:
193
    std::shared_ptr<SocketAddress> address_;
194
  };
195
196
 private:
197
  std::shared_ptr<SocketAddress> address_;
198
};
199
200
template <typename T>
201
class SocketAddressLRU : public MemoryRetainer {
202
 public:
203
  using Type = typename T::Type;
204
205
  inline explicit SocketAddressLRU(size_t max_size);
206
207
  // If the item already exists, returns a reference to
208
  // the existing item, adjusting items position in the
209
  // LRU. If the item does not exist, emplaces the item
210
  // and returns the new item.
211
  Type* Upsert(const SocketAddress& address);
212
213
  // Returns a reference to the item if it exists, or
214
  // nullptr. The position in the LRU is not modified.
215
  Type* Peek(const SocketAddress& address) const;
216
217
0
  size_t size() const { return map_.size(); }
218
  size_t max_size() const { return max_size_; }
219
220
  void MemoryInfo(MemoryTracker* tracker) const override;
221
  SET_MEMORY_INFO_NAME(SocketAddressLRU)
222
  SET_SELF_SIZE(SocketAddressLRU)
223
224
 private:
225
  using Pair = std::pair<SocketAddress, Type>;
226
  using Iterator = typename std::list<Pair>::iterator;
227
228
  void CheckExpired();
229
230
  std::list<Pair> list_;
231
  SocketAddress::Map<Iterator> map_;
232
  size_t max_size_;
233
};
234
235
// A BlockList is used to evaluate whether a given
236
// SocketAddress should be accepted for inbound or
237
// outbound network activity.
238
class SocketAddressBlockList : public MemoryRetainer {
239
 public:
240
  explicit SocketAddressBlockList(
241
      std::shared_ptr<SocketAddressBlockList> parent = {});
242
0
  ~SocketAddressBlockList() = default;
243
244
  void AddSocketAddress(const std::shared_ptr<SocketAddress>& address);
245
246
  void RemoveSocketAddress(const std::shared_ptr<SocketAddress>& address);
247
248
  void AddSocketAddressRange(
249
      const std::shared_ptr<SocketAddress>& start,
250
      const std::shared_ptr<SocketAddress>& end);
251
252
  void AddSocketAddressMask(
253
      const std::shared_ptr<SocketAddress>& address,
254
      int prefix);
255
256
  bool Apply(const std::shared_ptr<SocketAddress>& address);
257
258
0
  size_t size() const { return rules_.size(); }
259
260
  v8::MaybeLocal<v8::Array> ListRules(Environment* env);
261
262
  struct Rule : public MemoryRetainer {
263
    virtual bool Apply(const std::shared_ptr<SocketAddress>& address) = 0;
264
    inline v8::MaybeLocal<v8::Value> ToV8String(Environment* env);
265
    virtual std::string ToString() = 0;
266
  };
267
268
  struct SocketAddressRule final : Rule {
269
    std::shared_ptr<SocketAddress> address;
270
271
    explicit SocketAddressRule(const std::shared_ptr<SocketAddress>& address);
272
273
    bool Apply(const std::shared_ptr<SocketAddress>& address) override;
274
    std::string ToString() override;
275
276
    void MemoryInfo(node::MemoryTracker* tracker) const override;
277
    SET_MEMORY_INFO_NAME(SocketAddressRule)
278
    SET_SELF_SIZE(SocketAddressRule)
279
  };
280
281
  struct SocketAddressRangeRule final : Rule {
282
    std::shared_ptr<SocketAddress> start;
283
    std::shared_ptr<SocketAddress> end;
284
285
    SocketAddressRangeRule(
286
        const std::shared_ptr<SocketAddress>& start,
287
        const std::shared_ptr<SocketAddress>& end);
288
289
    bool Apply(const std::shared_ptr<SocketAddress>& address) override;
290
    std::string ToString() override;
291
292
    void MemoryInfo(node::MemoryTracker* tracker) const override;
293
    SET_MEMORY_INFO_NAME(SocketAddressRangeRule)
294
    SET_SELF_SIZE(SocketAddressRangeRule)
295
  };
296
297
  struct SocketAddressMaskRule final : Rule {
298
    std::shared_ptr<SocketAddress> network;
299
    int prefix;
300
301
    SocketAddressMaskRule(
302
        const std::shared_ptr<SocketAddress>& address,
303
        int prefix);
304
305
    bool Apply(const std::shared_ptr<SocketAddress>& address) override;
306
    std::string ToString() override;
307
308
    void MemoryInfo(node::MemoryTracker* tracker) const override;
309
    SET_MEMORY_INFO_NAME(SocketAddressMaskRule)
310
    SET_SELF_SIZE(SocketAddressMaskRule)
311
  };
312
313
  void MemoryInfo(node::MemoryTracker* tracker) const override;
314
  SET_MEMORY_INFO_NAME(SocketAddressBlockList)
315
  SET_SELF_SIZE(SocketAddressBlockList)
316
317
 private:
318
  bool ListRules(Environment* env, v8::LocalVector<v8::Value>* vec);
319
320
  std::shared_ptr<SocketAddressBlockList> parent_;
321
  std::list<std::unique_ptr<Rule>> rules_;
322
  SocketAddress::Map<std::list<std::unique_ptr<Rule>>::iterator> address_rules_;
323
324
  Mutex mutex_;
325
};
326
327
class SocketAddressBlockListWrap : public BaseObject {
328
 public:
329
  static bool HasInstance(Environment* env, v8::Local<v8::Value> value);
330
  static v8::Local<v8::FunctionTemplate> GetConstructorTemplate(
331
      Environment* env);
332
  static void Initialize(v8::Local<v8::Object> target,
333
                         v8::Local<v8::Value> unused,
334
                         v8::Local<v8::Context> context,
335
                         void* priv);
336
337
  static BaseObjectPtr<SocketAddressBlockListWrap> New(Environment* env);
338
  static BaseObjectPtr<SocketAddressBlockListWrap> New(
339
      Environment* env,
340
      std::shared_ptr<SocketAddressBlockList> blocklist);
341
342
  static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
343
  static void AddAddress(const v8::FunctionCallbackInfo<v8::Value>& args);
344
  static void AddRange(const v8::FunctionCallbackInfo<v8::Value>& args);
345
  static void AddSubnet(const v8::FunctionCallbackInfo<v8::Value>& args);
346
  static void Check(const v8::FunctionCallbackInfo<v8::Value>& args);
347
  static void GetRules(const v8::FunctionCallbackInfo<v8::Value>& args);
348
349
  SocketAddressBlockListWrap(
350
      Environment* env,
351
      v8::Local<v8::Object> wrap,
352
      std::shared_ptr<SocketAddressBlockList> blocklist =
353
          std::make_shared<SocketAddressBlockList>());
354
355
  void MemoryInfo(node::MemoryTracker* tracker) const override;
356
  SET_MEMORY_INFO_NAME(SocketAddressBlockListWrap)
357
  SET_SELF_SIZE(SocketAddressBlockListWrap)
358
359
0
  BaseObject::TransferMode GetTransferMode() const override {
360
0
    return TransferMode::kCloneable;
361
0
  }
362
  std::unique_ptr<worker::TransferData> CloneForMessaging() const override;
363
364
  class TransferData : public worker::TransferData {
365
   public:
366
    inline explicit TransferData(const SocketAddressBlockListWrap* wrap)
367
0
        : blocklist_(wrap->blocklist_) {}
368
369
    inline explicit TransferData(
370
        std::shared_ptr<SocketAddressBlockList> blocklist)
371
0
        : blocklist_(std::move(blocklist)) {}
372
373
    BaseObjectPtr<BaseObject> Deserialize(
374
        Environment* env,
375
        v8::Local<v8::Context> context,
376
        std::unique_ptr<worker::TransferData> self) override;
377
378
    void MemoryInfo(MemoryTracker* tracker) const override;
379
    SET_MEMORY_INFO_NAME(SocketAddressBlockListWrap::TransferData)
380
    SET_SELF_SIZE(TransferData)
381
382
   private:
383
    std::shared_ptr<SocketAddressBlockList> blocklist_;
384
  };
385
386
 private:
387
  std::shared_ptr<SocketAddressBlockList> blocklist_;
388
};
389
390
}  // namespace node
391
392
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
393
394
#endif  // SRC_NODE_SOCKADDR_H_