Coverage Report

Created: 2026-01-07 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/poco/Net/src/IPAddress.cpp
Line
Count
Source
1
//
2
// IPAddress.cpp
3
//
4
// Library: Net
5
// Package: NetCore
6
// Module:  IPAddress
7
//
8
// Copyright (c) 2005-2011, Applied Informatics Software Engineering GmbH.
9
// and Contributors.
10
//
11
// SPDX-License-Identifier: BSL-1.0
12
//
13
14
15
#include "Poco/Net/IPAddress.h"
16
#include "Poco/Net/NetException.h"
17
#include "Poco/RefCountedObject.h"
18
#include "Poco/NumberFormatter.h"
19
#include "Poco/BinaryReader.h"
20
#include "Poco/BinaryWriter.h"
21
#include "Poco/String.h"
22
#include "Poco/Format.h"
23
#include "Poco/Types.h"
24
25
26
using Poco::RefCountedObject;
27
using Poco::NumberFormatter;
28
using Poco::BinaryReader;
29
using Poco::BinaryWriter;
30
using Poco::toLower;
31
using Poco::trim;
32
using Poco::UInt8;
33
using Poco::UInt16;
34
using Poco::UInt32;
35
using Poco::Net::Impl::IPAddressImpl;
36
using Poco::Net::Impl::IPv4AddressImpl;
37
#if defined(POCO_HAVE_IPv6)
38
using Poco::Net::Impl::IPv6AddressImpl;
39
#endif
40
41
42
namespace Poco {
43
namespace Net {
44
45
46
#if !defined(_MSC_VER) || defined(__STDC__)
47
// Go home MSVC, you're drunk...
48
// See http://stackoverflow.com/questions/5899857/multiple-definition-error-for-static-const-class-members
49
const IPAddress::Family IPAddress::IPv4;
50
#if defined(POCO_HAVE_IPv6)
51
const IPAddress::Family IPAddress::IPv6;
52
#endif
53
#endif
54
55
56
IPAddress::IPAddress()
57
0
{
58
0
  newIPv4();
59
0
}
60
61
62
IPAddress::IPAddress(const IPAddress& addr)
63
0
{
64
0
  if (addr.family() == IPv4)
65
0
    newIPv4(addr.addr());
66
0
#if defined(POCO_HAVE_IPv6)
67
0
  else
68
0
    newIPv6(addr.addr(), addr.scope());
69
0
#endif
70
0
}
71
72
73
0
IPAddress::IPAddress(IPAddress&& addr): _pImpl(std::move(addr._pImpl))
74
0
{
75
0
}
76
77
78
IPAddress::IPAddress(Family family)
79
0
{
80
0
  if (family == IPv4)
81
0
    newIPv4();
82
0
#if defined(POCO_HAVE_IPv6)
83
0
  else if (family == IPv6)
84
0
    newIPv6();
85
0
#endif
86
0
  else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()");
87
0
}
88
89
90
IPAddress::IPAddress(const std::string& addr)
91
0
{
92
0
  IPv4AddressImpl empty4 = IPv4AddressImpl();
93
0
  if (addr.empty() || trim(addr) == "0.0.0.0")
94
0
  {
95
0
    newIPv4(empty4.addr());
96
0
    return;
97
0
  }
98
99
0
  IPv4AddressImpl addr4(IPv4AddressImpl::parse(addr));
100
0
  if (addr4 != empty4)
101
0
  {
102
0
    newIPv4(addr4.addr());
103
0
    return;
104
0
  }
105
106
0
#if defined(POCO_HAVE_IPv6)
107
0
  IPv6AddressImpl empty6 = IPv6AddressImpl();
108
0
  if (addr.empty() || trimIPv6(addr) == "::")
109
0
  {
110
0
    newIPv6(empty6.addr());
111
0
    return;
112
0
  }
113
114
0
  IPv6AddressImpl addr6(IPv6AddressImpl::parse(addr));
115
0
  if (addr6 != IPv6AddressImpl())
116
0
  {
117
0
    newIPv6(addr6.addr(), addr6.scope());
118
0
    return;
119
0
  }
120
0
#endif
121
122
0
  throw InvalidAddressException(addr);
123
0
}
124
125
126
IPAddress::IPAddress(const std::string& addr, Family family)
127
0
{
128
0
  if (family == IPv4)
129
0
  {
130
0
    IPv4AddressImpl addr4(IPv4AddressImpl::parse(addr));
131
0
    newIPv4(addr4.addr());
132
0
    return;
133
0
  }
134
0
#if defined(POCO_HAVE_IPv6)
135
0
  else if (family == IPv6)
136
0
  {
137
0
    IPv6AddressImpl addr6(IPv6AddressImpl::parse(addr));
138
0
    newIPv6(addr6.addr(), addr6.scope());
139
0
    return;
140
0
  }
141
0
#endif
142
0
  else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()");
143
0
}
144
145
146
IPAddress::IPAddress(const void* addr, poco_socklen_t length)
147
0
  : _pImpl(nullptr)
148
0
{
149
0
  if (length == sizeof(struct in_addr))
150
0
    newIPv4(addr);
151
0
#if defined(POCO_HAVE_IPv6)
152
0
  else if (length == sizeof(struct in6_addr))
153
0
    newIPv6(addr);
154
0
#endif
155
0
  else throw Poco::InvalidArgumentException("Invalid address length passed to IPAddress()");
156
0
}
157
158
159
IPAddress::IPAddress(const void* addr, poco_socklen_t length, Poco::UInt32 scope)
160
0
{
161
0
  if (length == sizeof(struct in_addr))
162
0
    newIPv4(addr);
163
0
#if defined(POCO_HAVE_IPv6)
164
0
  else if (length == sizeof(struct in6_addr))
165
0
    newIPv6(addr, scope);
166
0
#endif
167
0
  else throw Poco::InvalidArgumentException("Invalid address length passed to IPAddress()");
168
0
}
169
170
171
IPAddress::IPAddress(unsigned prefix, Family family)
172
0
{
173
0
  if (family == IPv4)
174
0
  {
175
0
    if (prefix <= 32)
176
0
      newIPv4(prefix);
177
0
    else
178
0
      throw Poco::InvalidArgumentException("Invalid prefix length passed to IPAddress()");
179
0
  }
180
0
#if defined(POCO_HAVE_IPv6)
181
0
  else if (family == IPv6)
182
0
  {
183
0
    if (prefix <= 128)
184
0
      newIPv6(prefix);
185
0
    else
186
0
      throw Poco::InvalidArgumentException("Invalid prefix length passed to IPAddress()");
187
0
  }
188
0
#endif
189
0
  else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()");
190
0
}
191
192
193
#if defined(_WIN32)
194
IPAddress::IPAddress(const SOCKET_ADDRESS& socket_address)
195
  : _pImpl(nullptr)
196
{
197
  ADDRESS_FAMILY family = socket_address.lpSockaddr->sa_family;
198
  if (family == AF_INET)
199
    newIPv4(&reinterpret_cast<const struct sockaddr_in*>(socket_address.lpSockaddr)->sin_addr);
200
#if defined(POCO_HAVE_IPv6)
201
  else if (family == AF_INET6)
202
    newIPv6(&reinterpret_cast<const struct sockaddr_in6*>(socket_address.lpSockaddr)->sin6_addr,
203
      reinterpret_cast<const struct sockaddr_in6*>(socket_address.lpSockaddr)->sin6_scope_id);
204
#endif
205
  else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()");
206
}
207
#endif
208
209
210
IPAddress::IPAddress(const struct sockaddr& sockaddr)
211
0
{
212
0
  unsigned short family = sockaddr.sa_family;
213
0
  if (family == AF_INET)
214
0
    newIPv4(&reinterpret_cast<const struct sockaddr_in*>(&sockaddr)->sin_addr);
215
0
#if defined(POCO_HAVE_IPv6)
216
0
  else if (family == AF_INET6)
217
0
    newIPv6(&reinterpret_cast<const struct sockaddr_in6*>(&sockaddr)->sin6_addr,
218
0
      reinterpret_cast<const struct sockaddr_in6*>(&sockaddr)->sin6_scope_id);
219
0
#endif
220
0
  else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()");
221
0
}
222
223
224
IPAddress::~IPAddress()
225
0
{
226
0
}
227
228
229
IPAddress& IPAddress::operator = (const IPAddress& addr)
230
0
{
231
0
  if (&addr != this)
232
0
  {
233
0
    if (addr.family() == IPAddress::IPv4)
234
0
      newIPv4(addr.addr());
235
0
#if defined(POCO_HAVE_IPv6)
236
0
    else if (addr.family() == IPAddress::IPv6)
237
0
      newIPv6(addr.addr(), addr.scope());
238
0
#endif
239
0
    else
240
0
      throw Poco::InvalidArgumentException("Invalid or unsupported address family");
241
0
  }
242
0
  return *this;
243
0
}
244
245
246
IPAddress& IPAddress::operator = (IPAddress&& addr)
247
0
{
248
0
  _pImpl = std::move(addr._pImpl);
249
0
  return *this;
250
0
}
251
252
253
IPAddress::Family IPAddress::family() const
254
0
{
255
0
  return pImpl()->family();
256
0
}
257
258
259
Poco::UInt32 IPAddress::scope() const
260
0
{
261
0
  return pImpl()->scope();
262
0
}
263
264
265
std::string IPAddress::toString() const
266
0
{
267
0
  return pImpl()->toString();
268
0
}
269
270
271
bool IPAddress::isWildcard() const
272
0
{
273
0
  return pImpl()->isWildcard();
274
0
}
275
276
277
bool IPAddress::isBroadcast() const
278
0
{
279
0
  return pImpl()->isBroadcast();
280
0
}
281
282
283
bool IPAddress::isLoopback() const
284
0
{
285
0
  return pImpl()->isLoopback();
286
0
}
287
288
289
bool IPAddress::isMulticast() const
290
0
{
291
0
  return pImpl()->isMulticast();
292
0
}
293
294
295
bool IPAddress::isUnicast() const
296
0
{
297
0
  return !isWildcard() && !isBroadcast() && !isMulticast();
298
0
}
299
300
301
bool IPAddress::isLinkLocal() const
302
0
{
303
0
  return pImpl()->isLinkLocal();
304
0
}
305
306
307
bool IPAddress::isSiteLocal() const
308
0
{
309
0
  return pImpl()->isSiteLocal();
310
0
}
311
312
313
bool IPAddress::isIPv4Compatible() const
314
0
{
315
0
  return pImpl()->isIPv4Compatible();
316
0
}
317
318
319
bool IPAddress::isIPv4Mapped() const
320
0
{
321
0
  return pImpl()->isIPv4Mapped();
322
0
}
323
324
325
bool IPAddress::isWellKnownMC() const
326
0
{
327
0
  return pImpl()->isWellKnownMC();
328
0
}
329
330
331
bool IPAddress::isNodeLocalMC() const
332
0
{
333
0
  return pImpl()->isNodeLocalMC();
334
0
}
335
336
337
bool IPAddress::isLinkLocalMC() const
338
0
{
339
0
  return pImpl()->isLinkLocalMC();
340
0
}
341
342
343
bool IPAddress::isSiteLocalMC() const
344
0
{
345
0
  return pImpl()->isSiteLocalMC();
346
0
}
347
348
349
bool IPAddress::isOrgLocalMC() const
350
0
{
351
0
  return pImpl()->isOrgLocalMC();
352
0
}
353
354
355
bool IPAddress::isGlobalMC() const
356
0
{
357
0
  return pImpl()->isGlobalMC();
358
0
}
359
360
361
bool IPAddress::operator == (const IPAddress& a) const
362
0
{
363
0
  poco_socklen_t l1 = length();
364
0
  poco_socklen_t l2 = a.length();
365
0
  if (l1 == l2)
366
0
  {
367
0
#if defined(POCO_HAVE_IPv6)
368
0
    if ( scope() != a.scope() )
369
0
      return false;
370
0
#endif
371
0
    return std::memcmp(addr(), a.addr(), l1) == 0;
372
0
  }
373
0
  else return false;
374
0
}
375
376
377
bool IPAddress::operator != (const IPAddress& a) const
378
0
{
379
0
  return !(*this == a);
380
0
}
381
382
383
bool IPAddress::operator < (const IPAddress& a) const
384
0
{
385
0
  poco_socklen_t l1 = length();
386
0
  poco_socklen_t l2 = a.length();
387
0
  if (l1 == l2)
388
0
  {
389
0
#if defined(POCO_HAVE_IPv6)
390
0
    if ( scope() != a.scope() )
391
0
      return scope() < a.scope();
392
0
#endif
393
0
    return std::memcmp(addr(), a.addr(), l1) < 0;
394
0
  }
395
0
  else return l1 < l2;
396
0
}
397
398
399
bool IPAddress::operator <= (const IPAddress& a) const
400
0
{
401
0
  return !(a < *this);
402
0
}
403
404
405
bool IPAddress::operator > (const IPAddress& a) const
406
0
{
407
0
  return a < *this;
408
0
}
409
410
411
bool IPAddress::operator >= (const IPAddress& a) const
412
0
{
413
0
  return !(*this < a);
414
0
}
415
416
417
IPAddress IPAddress::operator & (const IPAddress& other) const
418
0
{
419
0
  if (family() == other.family())
420
0
  {
421
0
    if (family() == IPv4)
422
0
    {
423
0
      IPv4AddressImpl t(pImpl()->addr());
424
0
      IPv4AddressImpl o(other.pImpl()->addr());
425
0
      return IPAddress((t & o).addr(), sizeof(struct in_addr));
426
0
    }
427
0
#if defined(POCO_HAVE_IPv6)
428
0
    else if (family() == IPv6)
429
0
    {
430
0
      const IPv6AddressImpl t(pImpl()->addr(), pImpl()->scope());
431
0
      const IPv6AddressImpl o(other.pImpl()->addr(), other.pImpl()->scope());
432
0
      const IPv6AddressImpl r = t & o;
433
0
      return IPAddress(r.addr(), sizeof(struct in6_addr), r.scope());
434
0
    }
435
0
#endif
436
0
    else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()");
437
0
  }
438
0
  else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()");
439
0
}
440
441
442
IPAddress IPAddress::operator | (const IPAddress& other) const
443
0
{
444
0
  if (family() == other.family())
445
0
  {
446
0
    if (family() == IPv4)
447
0
    {
448
0
      IPv4AddressImpl t(pImpl()->addr());
449
0
      IPv4AddressImpl o(other.pImpl()->addr());
450
0
      return IPAddress((t | o).addr(), sizeof(struct in_addr));
451
0
    }
452
0
#if defined(POCO_HAVE_IPv6)
453
0
    else if (family() == IPv6)
454
0
    {
455
0
      const IPv6AddressImpl t(pImpl()->addr(), pImpl()->scope());
456
0
      const IPv6AddressImpl o(other.pImpl()->addr(), other.pImpl()->scope());
457
0
      const IPv6AddressImpl r = t | o;
458
0
      return IPAddress(r.addr(), sizeof(struct in6_addr), r.scope());
459
0
    }
460
0
#endif
461
0
    else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()");
462
0
  }
463
0
  else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()");
464
0
}
465
466
467
IPAddress IPAddress::operator ^ (const IPAddress& other) const
468
0
{
469
0
  if (family() == other.family())
470
0
  {
471
0
    if (family() == IPv4)
472
0
    {
473
0
      IPv4AddressImpl t(pImpl()->addr());
474
0
      IPv4AddressImpl o(other.pImpl()->addr());
475
0
      return IPAddress((t ^ o).addr(), sizeof(struct in_addr));
476
0
    }
477
0
#if defined(POCO_HAVE_IPv6)
478
0
    else if (family() == IPv6)
479
0
    {
480
0
      const IPv6AddressImpl t(pImpl()->addr(), pImpl()->scope());
481
0
      const IPv6AddressImpl o(other.pImpl()->addr(), other.pImpl()->scope());
482
0
      const IPv6AddressImpl r = t ^ o;
483
0
      return IPAddress(r.addr(), sizeof(struct in6_addr), r.scope());
484
0
    }
485
0
#endif
486
0
    else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()");
487
0
  }
488
0
  else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()");
489
0
}
490
491
492
IPAddress IPAddress::operator ~ () const
493
0
{
494
0
  if (family() == IPv4)
495
0
  {
496
0
    IPv4AddressImpl self(this->pImpl()->addr());
497
0
    return IPAddress((~self).addr(), sizeof(struct in_addr));
498
0
  }
499
0
#if defined(POCO_HAVE_IPv6)
500
0
  else if (family() == IPv6)
501
0
  {
502
0
    const IPv6AddressImpl self(pImpl()->addr(), pImpl()->scope());
503
0
    const IPv6AddressImpl r = ~self;
504
0
    return IPAddress(r.addr(), sizeof(struct in6_addr), r.scope());
505
0
  }
506
0
#endif
507
0
  else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()");
508
0
}
509
510
511
poco_socklen_t IPAddress::length() const
512
0
{
513
0
  return pImpl()->length();
514
0
}
515
516
517
const void* IPAddress::addr() const
518
0
{
519
0
  return pImpl()->addr();
520
0
}
521
522
523
int IPAddress::af() const
524
0
{
525
0
  return pImpl()->af();
526
0
}
527
528
529
unsigned IPAddress::prefixLength() const
530
0
{
531
0
  return pImpl()->prefixLength();
532
0
}
533
534
535
std::string& IPAddress::compressV6(std::string& v6addr)
536
0
{
537
  // get rid of leading zeros at the beginning
538
0
  while (v6addr.size() && v6addr[0] == '0') v6addr.erase(v6addr.begin());
539
540
  // get rid of leading zeros in the middle
541
0
  while (v6addr.find(":0") != std::string::npos)
542
0
    Poco::replaceInPlace(v6addr, ":0", ":");
543
544
  // get rid of extraneous colons
545
0
  while (v6addr.find(":::") != std::string::npos)
546
0
    Poco::replaceInPlace(v6addr, ":::", "::");
547
548
0
  return v6addr;
549
0
}
550
551
552
std::string IPAddress::trimIPv6(const std::string& v6Addr)
553
0
{
554
0
  std::string v6addr(v6Addr);
555
0
  std::string::size_type len = v6addr.length();
556
0
  int dblColOcc = 0;
557
0
  auto pos = v6addr.find("::");
558
0
  while ((pos <= len-2) && (pos != std::string::npos))
559
0
  {
560
0
    ++dblColOcc;
561
0
    pos = v6addr.find("::", pos + 2);
562
0
  }
563
564
0
  if ((dblColOcc > 1) ||
565
0
    (std::count(v6addr.begin(), v6addr.end(), ':') > 8) ||
566
0
    (v6addr.find(":::") != std::string::npos) ||
567
0
    ((len >= 2) && ((v6addr[len-1] == ':') && v6addr[len-2] != ':')))
568
0
  {
569
0
    return v6addr;
570
0
  }
571
572
0
  return compressV6(v6addr);
573
0
}
574
575
576
IPAddress IPAddress::parse(const std::string& addr)
577
0
{
578
0
  return IPAddress(addr);
579
0
}
580
581
582
bool IPAddress::tryParse(const std::string& addr, IPAddress& result)
583
0
{
584
0
  IPv4AddressImpl impl4(IPv4AddressImpl::parse(addr));
585
0
  if (impl4 != IPv4AddressImpl() || trim(addr) == "0.0.0.0")
586
0
  {
587
0
    result.newIPv4(impl4.addr());
588
0
    return true;
589
0
  }
590
0
#if defined(POCO_HAVE_IPv6)
591
0
  IPv6AddressImpl impl6(IPv6AddressImpl::parse(addr));
592
0
  if (impl6 != IPv6AddressImpl() || trimIPv6(addr) == "::")
593
0
  {
594
0
    result.newIPv6(impl6.addr(), impl6.scope());
595
0
    return true;
596
0
  }
597
0
#endif
598
0
  return false;
599
0
}
600
601
602
void IPAddress::mask(const IPAddress& mask)
603
0
{
604
0
  IPAddress null;
605
0
  pImpl()->mask(mask.pImpl(), null.pImpl());
606
0
}
607
608
609
void IPAddress::mask(const IPAddress& mask, const IPAddress& set)
610
0
{
611
0
  pImpl()->mask(mask.pImpl(), set.pImpl());
612
0
}
613
614
615
IPAddress IPAddress::wildcard(Family family)
616
0
{
617
0
  return IPAddress(family);
618
0
}
619
620
621
IPAddress IPAddress::broadcast()
622
0
{
623
0
  struct in_addr ia;
624
0
  ia.s_addr = INADDR_NONE;
625
0
  return IPAddress(&ia, sizeof(ia));
626
0
}
627
628
629
IPAddress::RawIPv4 IPAddress::toV4Bytes() const
630
0
{
631
0
  if (family() != IPv4)
632
0
    throw Poco::InvalidAccessException(Poco::format("IPAddress::toV4Bytes(%d)", (int)family()));
633
634
0
  RawIPv4 bytes;
635
0
  std::memcpy(&bytes[0], addr(), IPv4Size);
636
0
  return bytes;
637
0
}
638
639
640
IPAddress::RawIPv6 IPAddress::toV6Bytes() const
641
0
{
642
0
  if (family() != IPv6)
643
0
    throw Poco::InvalidAccessException(Poco::format("IPAddress::toV6Bytes(%d)", (int)family()));
644
645
0
  RawIPv6 bytes;
646
0
  std::memcpy(&bytes[0], addr(), IPv6Size);
647
0
  return bytes;
648
0
}
649
650
651
std::vector<unsigned char> IPAddress::toBytes() const
652
0
{
653
0
  std::size_t sz = 0;
654
0
  std::vector<unsigned char> bytes;
655
0
  const void* ptr = nullptr;
656
0
  switch (family())
657
0
  {
658
0
    case IPv4:
659
0
      sz = sizeof(in_addr);
660
0
      ptr = addr();
661
0
      break;
662
0
#if defined(POCO_HAVE_IPv6)
663
0
    case IPv6:
664
0
      sz = sizeof(in6_addr);
665
0
      ptr = addr();
666
0
      break;
667
0
#endif
668
0
    default:
669
0
      throw Poco::IllegalStateException(Poco::format("IPAddress::toBytes(%d)", (int)family()));
670
0
  }
671
0
  bytes.resize(sz);
672
0
  std::memcpy(&bytes[0], ptr, sz);
673
0
  return bytes;
674
0
}
675
676
677
Poco::BinaryWriter& operator << (Poco::BinaryWriter& writer, const Poco::Net::IPAddress& value)
678
0
{
679
0
  writer << static_cast<Poco::UInt8>(value.length());
680
0
  writer.writeRaw(reinterpret_cast<const char*>(value.addr()), value.length());
681
0
  return writer;
682
0
}
683
684
685
Poco::BinaryReader& operator >> (Poco::BinaryReader& reader, Poco::Net::IPAddress& value)
686
0
{
687
0
  char buf[Poco::Net::IPAddress::MAX_ADDRESS_LENGTH];
688
0
  Poco::UInt8 length;
689
0
  reader >> length;
690
0
  reader.readRaw(buf, length);
691
0
  value = Poco::Net::IPAddress(buf, length);
692
0
  return reader;
693
0
}
694
695
696
std::ostream& operator << (std::ostream& ostr, const Poco::Net::IPAddress& addr)
697
0
{
698
0
  ostr << addr.toString();
699
0
  return ostr;
700
0
}
701
702
703
} } // namespace Poco::Net
704