Apache Mesos
ip.hpp
Go to the documentation of this file.
1 // Licensed under the Apache License, Version 2.0 (the "License");
2 // you may not use this file except in compliance with the License.
3 // You may obtain a copy of the License at
4 //
5 // http://www.apache.org/licenses/LICENSE-2.0
6 //
7 // Unless required by applicable law or agreed to in writing, software
8 // distributed under the License is distributed on an "AS IS" BASIS,
9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 // See the License for the specific language governing permissions and
11 // limitations under the License.
12 
13 #ifndef __STOUT_IP_HPP__
14 #define __STOUT_IP_HPP__
15 
16 // For 'sockaddr'.
17 #ifndef __WINDOWS__
18 #include <arpa/inet.h>
19 #endif // __WINDOWS__
20 
21 #if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
22 #include <ifaddrs.h>
23 #endif // __linux__ || __APPLE__ || __FreeBSD__
24 #include <stdint.h>
25 #include <stdio.h>
26 #include <string.h>
27 
28 #ifdef __APPLE__
29 #include <net/if.h>
30 #include <net/if_dl.h>
31 #include <net/if_types.h>
32 #endif // __APPLE__
33 
34 // Note: Header grouping and ordering is considered before
35 // inclusion/exclusion by platform.
36 // For 'inet_pton', 'inet_ntop'.
37 #ifndef __WINDOWS__
38 #include <netinet/in.h>
39 #include <sys/socket.h>
40 #endif // __WINDOWS__
41 
42 #include <sys/types.h>
43 
44 #include <algorithm>
45 #include <iostream>
46 #include <numeric>
47 #include <string>
48 #include <vector>
49 
50 #include <boost/functional/hash.hpp>
51 
52 #include <stout/abort.hpp>
53 #include <stout/bits.hpp>
54 #include <stout/check.hpp>
55 #include <stout/error.hpp>
56 #include <stout/none.hpp>
57 #include <stout/numify.hpp>
58 #include <stout/option.hpp>
59 #include <stout/os/strerror.hpp>
60 #include <stout/result.hpp>
61 #include <stout/stringify.hpp>
62 #include <stout/strings.hpp>
63 #include <stout/try.hpp>
64 #include <stout/unreachable.hpp>
65 
66 #ifdef __WINDOWS__
67 #include <stout/windows.hpp> // For `WS2tcpip.h`.
68 #endif // __WINDOWS__
69 
70 namespace net {
71 
72 // Represents an IP.
73 class IP
74 {
75 public:
76  // Creates an IP from the given string that has the dot-decimal
77  // format. For example:
78  // 10.0.0.1
79  // 192.168.1.100
80  // 172.158.1.23
81  // 2001:db8:85a3::8a2e:370:7334
82  static Try<IP> parse(const std::string& value, int family = AF_UNSPEC);
83 
84  // Creates an IP from a struct sockaddr_storage.
85  static Try<IP> create(const struct sockaddr_storage& _storage);
86 
87  // Creates an IP from a struct sockaddr.
88  static Try<IP> create(const struct sockaddr& _storage);
89 
90  // Creates an IP from struct in_addr. Note that by standard, struct
91  // in_addr stores the IP address in network order.
92  explicit IP(const struct in_addr& _storage)
93  : family_(AF_INET)
94  {
95  clear();
96  storage_.in_ = _storage;
97  }
98 
99  // Creates an IP from struct in6_addr. Note that by standard, struct
100  // in_addr stores the IP address in network order.
101  explicit IP(const struct in6_addr& _storage)
102  : family_(AF_INET6)
103  {
104  clear();
105  storage_.in6_ = _storage;
106  }
107 
108  // Creates an IP from a 32 bit unsigned integer. Note that the
109  // integer stores the IP address in host order.
110  explicit IP(uint32_t _ip)
111  : family_(AF_INET)
112  {
113  clear();
114  storage_.in_.s_addr = htonl(_ip);
115  }
116 
117  // Returns the family type.
118  int family() const
119  {
120  return family_;
121  }
122 
123  // Returns the struct in_addr storage.
125  {
126  if (family_ == AF_INET) {
127  return storage_.in_;
128  } else {
129  return Error("Cannot create in_addr from family: " + stringify(family_));
130  }
131  }
132 
133  // Returns the struct in6_addr storage.
135  {
136  if (family_ == AF_INET6) {
137  return storage_.in6_;
138  } else {
139  return Error("Cannot create in6_addr from family: " + stringify(family_));
140  }
141  }
142 
143  // Checks if this IP is for loopback (e.g., INADDR_LOOPBACK).
144  bool isLoopback() const
145  {
146  switch (family_) {
147  case AF_INET:
148  return storage_.in_.s_addr == htonl(INADDR_LOOPBACK);
149  case AF_INET6:
150  return !memcmp(&storage_.in6_.s6_addr, &in6addr_loopback.s6_addr, 16);
151  default:
152  UNREACHABLE();
153  }
154  }
155 
156  // Checks if this IP is for any incoming address (e.g., INADDR_ANY).
157  bool isAny() const
158  {
159  switch (family_) {
160  case AF_INET:
161  return storage_.in_.s_addr == htonl(INADDR_ANY);
162  case AF_INET6:
163  return !memcmp(&storage_.in6_.s6_addr, &in6addr_any.s6_addr, 16);
164  default:
165  UNREACHABLE();
166  }
167  }
168 
169  bool operator==(const IP& that) const
170  {
171  if (family_ != that.family_) {
172  return false;
173  } else {
174  return memcmp(&storage_, &that.storage_, sizeof(storage_)) == 0;
175  }
176  }
177 
178  bool operator!=(const IP& that) const
179  {
180  return !(*this == that);
181  }
182 
183  bool operator<(const IP& that) const
184  {
185  if (family_ != that.family_) {
186  return family_ < that.family_;
187  } else {
188  return memcmp(&storage_, &that.storage_, sizeof(storage_)) < 0;
189  }
190  }
191 
192  bool operator>(const IP& that) const
193  {
194  if (family_ != that.family_) {
195  return family_ > that.family_;
196  } else {
197  return memcmp(&storage_, &that.storage_, sizeof(storage_)) > 0;
198  }
199  }
200 
201  // Represents an IP network. We store the IP address and the IP
202  // netmask which defines the subnet.
203  class Network
204  {
205  public:
206  // Returns the IPv4 network for loopback (i.e., 127.0.0.1/8).
207  //
208  // TODO(asridharan): We need to move this functionality to an
209  // `net::inet::IP::Network` class in the future.
210  static Network LOOPBACK_V4();
211 
212  // Returns the IPv6 network for loopback (i.e. ::1/128)
213  //
214  // TODO(asridharan): We need to move this functionality to an
215  // `net::inet6::IP::Network` class in the future.
216  static Network LOOPBACK_V6();
217 
218  // Creates an IP network from the given string that has the
219  // IP address in canonical format with subnet prefix.
220  // For example:
221  // 10.0.0.1/8
222  // 192.168.1.100/24
223  // fe80::3/64
224  static Try<Network> parse(
225  const std::string& value,
226  int family = AF_UNSPEC);
227 
228  // Creates an IP network from the given IP address and netmask.
229  // Returns error if the netmask is not valid (e.g., not contiguous).
230  static Try<Network> create(const IP& address, const IP& netmask);
231 
232  // Creates an IP network from an IP address and a subnet prefix.
233  // Returns error if the prefix is not valid.
234  static Try<Network> create(const IP& address, int prefix);
235 
236  // Returns the first available IP network of a given link device.
237  // The link device is specified using its name (e.g., eth0). Returns
238  // error if the link device is not found. Returns none if the link
239  // device is found, but does not have an IP network.
240  // TODO(jieyu): It is uncommon, but likely that a link device has
241  // multiple IP networks. In that case, consider returning the
242  // primary IP network instead of the first one.
243  static Result<Network> fromLinkDevice(const std::string& name, int family);
244 
245  // Need to add a copy constructor due to the presence of
246  // `unique_ptr`.
247  Network(const Network& network)
248  : address_(new IP(network.address())),
249  netmask_(new IP(network.netmask())) {}
250 
251  // Need to add a copy assignment operator due to the use of
252  // `std::unique_ptr`.
253  Network& operator=(const Network& network)
254  {
255  address_.reset(new IP(network.address()));
256  netmask_.reset(new IP(network.netmask()));
257 
258  return *this;
259  }
260 
261  IP address() const { return *address_; }
262 
263  IP netmask() const { return *netmask_; }
264 
265  // Returns the prefix of the subnet defined by the IP netmask.
266  int prefix() const
267  {
268  switch (netmask_->family()) {
269  case AF_INET: {
270  return bits::countSetBits(netmask_->in()->s_addr);
271  }
272  case AF_INET6: {
273  struct in6_addr in6 = netmask_->in6().get();
274 
275  int prefix = std::accumulate(
276  std::begin(in6.s6_addr),
277  std::end(in6.s6_addr),
278  0,
279  [](int acc, uint8_t c) {
280  return acc + bits::countSetBits(c);
281  });
282 
283  return prefix;
284  }
285  default: {
286  UNREACHABLE();
287  }
288  }
289  }
290 
291  bool operator==(const Network& that) const
292  {
293  return *(address_) == *(that.address_) &&
294  *(netmask_) == *(that.netmask_);
295  }
296 
297  bool operator!=(const Network& that) const
298  {
299  return !(*this == that);
300  }
301 
302  protected:
303  Network(const IP& _address, const IP& _netmask)
304  : address_(new IP(_address)), netmask_(new IP(_netmask)) {}
305 
306  // NOTE: The reason we need to store `std::unique_ptr` and not
307  // `net::IP` here is that since this class has a nested definition
308  // within `net::IP` `net::IP` is an incomplete type at this point.
309  // We therefore cannot store an object and can only store pointers
310  // for this incomplete type.
311  std::unique_ptr<IP> address_;
312  std::unique_ptr<IP> netmask_;
313  };
314 
315 protected:
316  // NOTE: We need to clear the union when creating an IP because the
317  // equality check uses memcmp.
318  void clear()
319  {
320  memset(&storage_, 0, sizeof(storage_));
321  }
322 
323  union Storage
324  {
325  struct in_addr in_;
326  struct in6_addr in6_;
327  };
328 
329  int family_;
331 };
332 
333 
334 class IPv4 : public IP
335 {
336 public:
337  static IPv4 LOOPBACK()
338  {
339  return IPv4(INADDR_LOOPBACK);
340  }
341 
342  static IPv4 ANY()
343  {
344  return IPv4(INADDR_ANY);
345  }
346 
347  static Try<IPv4> parse(const std::string& value)
348  {
349  in_addr in;
350 
351  if (inet_pton(AF_INET, value.c_str(), &in) == 1) {
352  return IPv4(in);
353  }
354 
355  return Error("Failed to parse IPv4: " + value);
356  }
357 
358  explicit IPv4(const in_addr& in)
359  : IP(in) {}
360 
361  explicit IPv4(uint32_t ip)
362  : IP(ip) {}
363 
364  // Returns the in_addr storage.
365  in_addr in() const
366  {
367  Try<in_addr> in = IP::in();
368 
369  // `_family` would already be set to `AF_INET` hence the above
370  // `Try` should always be successful.
371  CHECK_SOME(in);
372 
373  return in.get();
374  }
375 };
376 
377 
378 class IPv6 : public IP
379 {
380 public:
381  static IPv6 LOOPBACK()
382  {
383  return IPv6(in6addr_loopback);
384  }
385 
386  static IPv6 ANY()
387  {
388  return IPv6(in6addr_any);
389  }
390 
391  static Try<IPv6> parse(const std::string& value)
392  {
393  in6_addr in6;
394  if (inet_pton(AF_INET6, value.c_str(), &in6) == 1) {
395  return IPv6(in6);
396  }
397 
398  return Error("Failed to parse IPv6: " + value);
399  }
400 
401  explicit IPv6(const in6_addr& in6)
402  : IP(in6) {}
403 
404  in6_addr in6() const
405  {
407 
408  // `_family` would already be set to `AF_INET6` hence the above
409  // `Try` should always be successful.
410  CHECK_SOME(in6);
411 
412  return in6.get();
413  }
414 };
415 
416 
417 inline Try<IP> IP::parse(const std::string& value, int family)
418 {
419  Storage storage;
420  switch (family) {
421  case AF_INET: {
422  if (inet_pton(AF_INET, value.c_str(), &storage.in_) == 1) {
423  return IP(storage.in_);
424  }
425 
426  return Error("Failed to parse IPv4: " + value);
427  }
428  case AF_INET6: {
429  if (inet_pton(AF_INET6, value.c_str(), &storage.in6_) == 1) {
430  return IP(storage.in6_);
431  }
432 
433  return Error("Failed to parse IPv6: " + value);
434  }
435  case AF_UNSPEC: {
436  Try<IP> ip4 = parse(value, AF_INET);
437  if (ip4.isSome()) {
438  return ip4;
439  }
440 
441  Try<IP> ip6 = parse(value, AF_INET6);
442  if (ip6.isSome()) {
443  return ip6;
444  }
445 
446  return Error("Failed to parse IP as either IPv4 or IPv6:" + value);
447  }
448  default:
449  return Error("Unsupported family type: " + stringify(family));
450  }
451 }
452 
453 
454 inline Try<IP> IP::create(const struct sockaddr_storage& _storage)
455 {
456  // According to POSIX: (IEEE Std 1003.1, 2004)
457  //
458  // (1) `sockaddr_storage` is "aligned at an appropriate boundary so that
459  // pointers to it can be cast as pointers to protocol-specific address
460  // structures and used to access the fields of those structures without
461  // alignment problems."
462  //
463  // (2) "When a `sockaddr_storage` structure is cast as a `sockaddr`
464  // structure, the `ss_family` field of the `sockaddr_storage` structure
465  // shall map onto the `sa_family` field of the `sockaddr` structure."
466  //
467  // Therefore, casting from `const sockaddr_storage*` to `const sockaddr*`
468  // (then subsequently dereferencing the `const sockaddr*`) should be safe.
469  // Note that casting in the reverse direction (`const sockaddr*` to
470  // `const sockaddr_storage*`) would NOT be safe, since the former might
471  // not be aligned appropriately.
472  const struct sockaddr* addr =
473  reinterpret_cast<const struct sockaddr*>(&_storage);
474 
475  return create(*addr);
476 }
477 
478 
479 inline Try<IP> IP::create(const struct sockaddr& addr)
480 {
481  switch (addr.sa_family) {
482  case AF_INET: {
483  const struct sockaddr_in& addr4 =
484  reinterpret_cast<const struct sockaddr_in&>(addr);
485 
486  return IP(addr4.sin_addr);
487  }
488  case AF_INET6: {
489  const struct sockaddr_in6& addr6 =
490  reinterpret_cast<const struct sockaddr_in6&>(addr);
491 
492  return IP(addr6.sin6_addr);
493  }
494  default: {
495  return Error("Unsupported family type: " + stringify(addr.sa_family));
496  }
497  }
498 }
499 
500 
501 // Returns the string representation of the given IP using the
502 // canonical form, for example: "10.0.0.1" or "fe80::1".
503 inline std::ostream& operator<<(std::ostream& stream, const IP& ip)
504 {
505  switch (ip.family()) {
506  case AF_INET: {
507  char buffer[INET_ADDRSTRLEN];
508  struct in_addr in = ip.in().get();
509  if (inet_ntop(AF_INET, &in, buffer, sizeof(buffer)) == nullptr) {
510  // We do not expect inet_ntop to fail because all parameters
511  // passed in are valid.
512  ABORT("Failed to get human-readable IPv4 for " +
513  stringify(ntohl(in.s_addr)) + ": " + os::strerror(errno));
514  }
515  return stream << buffer;
516  }
517  case AF_INET6: {
518  char buffer[INET6_ADDRSTRLEN];
519  struct in6_addr in6 = ip.in6().get();
520  if (inet_ntop(AF_INET6, &in6, buffer, sizeof(buffer)) == nullptr) {
521  ABORT("Failed to get human-readable IPv6: " + os::strerror(errno));
522  }
523  return stream << buffer;
524  }
525  default: {
526  UNREACHABLE();
527  }
528  }
529 }
530 
531 
532 inline Try<IP::Network> IP::Network::parse(const std::string& value, int family)
533 {
534  std::vector<std::string> tokens = strings::split(value, "/");
535 
536  if (tokens.size() != 2) {
537  return Error(
538  "Unexpected number of '/' detected: " +
539  stringify(tokens.size()));
540  }
541 
542  // Parse the IP address.
543  Try<IP> address = IP::parse(tokens[0], family);
544  if (address.isError()) {
545  return Error("Failed to parse the IP address: " + address.error());
546  }
547 
548  // Parse the subnet prefix.
549  Try<int> prefix = numify<int>(tokens[1]);
550  if (prefix.isError()) {
551  return Error("Subnet prefix is not a number");
552  }
553 
554  return create(address.get(), prefix.get());
555 }
556 
557 
559 {
560  return parse("127.0.0.1/8", AF_INET).get();
561 }
562 
563 
565 {
566  return parse("::1/128", AF_INET6).get();
567 }
568 
569 
571  const IP& address,
572  const IP& netmask)
573 {
574  if (address.family() != netmask.family()) {
575  return Error(
576  "The network families of the IP address '" +
577  stringify(address.family()) + "' and the IP netmask '" +
578  stringify(netmask.family()) + "' do not match");
579  }
580 
581  switch (address.family()) {
582  case AF_INET: {
583  uint32_t mask = ntohl(netmask.in()->s_addr);
584  if (((~mask + 1) & (~mask)) != 0) {
585  return Error("IPv4 netmask is not valid");
586  }
587  break;
588  }
589  case AF_INET6: {
590  in6_addr mask = netmask.in6().get();
591 
592  uint8_t testMask = 0xff;
593  for (int i = 0; i < 16; i++) {
594  if (mask.s6_addr[i] != testMask) {
595  if (testMask == 0) {
596  return Error("IPv6 netmask is not valid");
597  }
598 
599  if (((uint8_t)(~mask.s6_addr[i] + 1) & (~mask.s6_addr[i])) != 0) {
600  return Error("IPv6 netmask is not valid");
601  }
602 
603  testMask = 0;
604  }
605  }
606  break;
607  }
608  default: {
609  UNREACHABLE();
610  }
611  }
612 
613  return IP::Network(address, netmask);
614 }
615 
616 
618 {
619  if (prefix < 0) {
620  return Error("Subnet prefix is negative");
621  }
622 
623  switch (address.family()) {
624  case AF_INET: {
625  if (prefix > 32) {
626  return Error("IPv4 subnet prefix is larger than 32");
627  }
628 
629  // Avoid left-shifting by 32 bits when prefix is 0.
630  uint32_t mask = 0;
631  if (prefix > 0) {
632  mask = 0xffffffff << (32 - prefix);
633  }
634 
635  return IP::Network(address, IP(mask));
636  }
637  case AF_INET6: {
638  if (prefix > 128) {
639  return Error("IPv6 subnet prefix is larger than 128");
640  }
641 
642  in6_addr mask;
643  memset(&mask, 0, sizeof(mask));
644 
645  int i = 0;
646  while (prefix >= 8) {
647  mask.s6_addr[i++] = 0xff;
648  prefix -= 8;
649  }
650 
651  if (prefix > 0) {
652  uint8_t _mask = 0xff << (8 - prefix);
653  mask.s6_addr[i] = _mask;
654  }
655 
656  return IP::Network(address, IP(mask));
657  }
658  default: {
659  UNREACHABLE();
660  }
661  }
662 }
663 
664 
665 // Returns the string representation of the given IP network using the
666 // canonical form with prefix. For example: "10.0.0.1/8".
667 inline std::ostream& operator<<(
668  std::ostream& stream,
669  const IP::Network& network)
670 {
671  stream << network.address() << "/" << network.prefix();
672 
673  return stream;
674 }
675 
676 } // namespace net {
677 
678 
679 namespace std {
680 
681 template <>
682 struct hash<net::IP>
683 {
684  typedef size_t result_type;
685 
687 
688  result_type operator()(const argument_type& ip) const
689  {
690  size_t seed = 0;
691 
692  switch (ip.family()) {
693  case AF_INET:
694  boost::hash_combine(seed, htonl(ip.in()->s_addr));
695  return seed;
696  case AF_INET6: {
697  in6_addr in6 = ip.in6().get();
698  boost::hash_range(seed, std::begin(in6.s6_addr), std::end(in6.s6_addr));
699  return seed;
700  }
701  default:
702  UNREACHABLE();
703  }
704  }
705 };
706 
707 
708 template <>
709 struct hash<net::IPv4>
710 {
711  size_t operator()(const net::IPv4& ip)
712  {
713  size_t seed = 0;
714  boost::hash_combine(seed, htonl(ip.in().s_addr));
715  return seed;
716  }
717 };
718 
719 
720 template <>
721 struct hash<net::IPv6>
722 {
723  size_t operator()(const net::IPv6& ip)
724  {
725  size_t seed = 0;
726  in6_addr in6 = ip.in6();
727  boost::hash_range(seed, std::begin(in6.s6_addr), std::end(in6.s6_addr));
728  return seed;
729  }
730 };
731 
732 } // namespace std {
733 
734 
735 // NOTE: These headers are placed here because the platform specific code
736 // requires classes defined in this file.
737 #ifdef __WINDOWS__
738 #include <stout/windows/ip.hpp>
739 #else
740 #include <stout/posix/ip.hpp>
741 #endif // __WINDOWS__
742 
743 #endif // __STOUT_IP_HPP__
size_t result_type
Definition: ip.hpp:684
int countSetBits(uint32_t value)
Definition: bits.hpp:24
std::string strerror(int errno_)
A thread-safe version of strerror.
Definition: strerror.hpp:30
static IPv6 ANY()
Definition: ip.hpp:386
result_type operator()(const argument_type &ip) const
Definition: ip.hpp:688
IP address() const
Definition: ip.hpp:261
Definition: errorbase.hpp:35
Definition: ip.hpp:334
#define ABORT(...)
Definition: abort.hpp:40
bool operator!=(const Network &that) const
Definition: ip.hpp:297
T & get()&
Definition: try.hpp:73
std::ostream & operator<<(std::ostream &stream, const IP &ip)
Definition: ip.hpp:503
in6_addr in6() const
Definition: ip.hpp:404
Try< struct in_addr > in() const
Definition: ip.hpp:124
Definition: check.hpp:33
static IPv4 ANY()
Definition: ip.hpp:342
IPv4(const in_addr &in)
Definition: ip.hpp:358
static Network LOOPBACK_V6()
Definition: ip.hpp:564
static Try< IPv6 > parse(const std::string &value)
Definition: ip.hpp:391
bool isAny() const
Definition: ip.hpp:157
Definition: type_utils.hpp:510
static Try< IP > parse(const std::string &value, int family=AF_UNSPEC)
Definition: ip.hpp:417
size_t operator()(const net::IPv6 &ip)
Definition: ip.hpp:723
Definition: check.hpp:30
Storage storage_
Definition: ip.hpp:330
struct in6_addr in6_
Definition: ip.hpp:326
Definition: ip.hpp:73
IPv4(uint32_t ip)
Definition: ip.hpp:361
Definition: ip.hpp:323
size_t operator()(const net::IPv4 &ip)
Definition: ip.hpp:711
#define CHECK_SOME(expression)
Definition: check.hpp:50
IP netmask() const
Definition: ip.hpp:263
static IPv4 LOOPBACK()
Definition: ip.hpp:337
bool isLoopback() const
Definition: ip.hpp:144
struct in_addr in_
Definition: ip.hpp:325
Definition: ip.hpp:70
in_addr in() const
Definition: ip.hpp:365
bool isSome() const
Definition: try.hpp:70
Network(const IP &_address, const IP &_netmask)
Definition: ip.hpp:303
static Result< Network > fromLinkDevice(const std::string &name, int family)
Definition: ip.hpp:30
Definition: ip.hpp:203
static Try< Network > parse(const std::string &value, int family=AF_UNSPEC)
Definition: ip.hpp:532
IP(const struct in6_addr &_storage)
Definition: ip.hpp:101
static Try error(const E &e)
Definition: try.hpp:42
static IPv6 LOOPBACK()
Definition: ip.hpp:381
Definition: ip.hpp:378
#define UNREACHABLE()
Definition: unreachable.hpp:22
static Try< Network > create(const IP &address, const IP &netmask)
Definition: ip.hpp:570
IP(const struct in_addr &_storage)
Definition: ip.hpp:92
bool operator==(const IP &that) const
Definition: ip.hpp:169
std::unique_ptr< IP > address_
Definition: ip.hpp:311
bool isError() const
Definition: try.hpp:71
Try< struct in6_addr > in6() const
Definition: ip.hpp:134
bool operator>(const IP &that) const
Definition: ip.hpp:192
Network(const Network &network)
Definition: ip.hpp:247
int family() const
Definition: ip.hpp:118
bool operator==(const Network &that) const
Definition: ip.hpp:291
bool operator<(const IP &that) const
Definition: ip.hpp:183
std::vector< std::string > split(const std::string &s, const std::string &delims, const Option< size_t > &maxTokens=None())
Definition: strings.hpp:183
int family_
Definition: ip.hpp:329
Network & operator=(const Network &network)
Definition: ip.hpp:253
net::IP argument_type
Definition: ip.hpp:686
IPv6(const in6_addr &in6)
Definition: ip.hpp:401
std::string stringify(int flags)
bool operator!=(const IP &that) const
Definition: ip.hpp:178
IP(uint32_t _ip)
Definition: ip.hpp:110
std::unique_ptr< IP > netmask_
Definition: ip.hpp:312
static Try< IPv4 > parse(const std::string &value)
Definition: ip.hpp:347
static Network LOOPBACK_V4()
Definition: ip.hpp:558
static Try< IP > create(const struct sockaddr_storage &_storage)
Definition: ip.hpp:454
constexpr const char * name
Definition: shell.hpp:43
void clear()
Definition: ip.hpp:318
int prefix() const
Definition: ip.hpp:266