Spicy
network.h
1 // Copyright (c) 2020-2021 by the Zeek Project. See LICENSE for details.
2 
3 #pragma once
4 
5 #include <arpa/inet.h>
6 
7 #include <string>
8 #include <variant>
9 
10 #include <hilti/rt/exception.h>
11 #include <hilti/rt/extension-points.h>
12 #include <hilti/rt/types/address.h>
13 #include <hilti/rt/util.h>
14 
15 namespace hilti::rt {
16 
20 class Network {
21 public:
31  Network(const Address& prefix, int length) : _prefix(prefix), _length(length) {
32  switch ( _prefix.family() ) {
33  case AddressFamily::IPv4:
34  if ( _length < 0 || _length > 32 )
35  throw InvalidArgument(fmt("prefix length %s is invalid for IPv4 networks", _length));
36  break;
37  case AddressFamily::IPv6:
38  if ( _length < 0 || _length > 128 )
39  throw InvalidArgument(fmt("prefix length %s is invalid for IPv6 networks", _length));
40  break;
41  case AddressFamily::Undef:
42  throw InvalidArgument(
43  fmt("Network can only be constructed from either IPv4 or IPv6 addresses, not %s", prefix));
44  }
45 
46  _mask();
47  }
48 
58  Network(const std::string& prefix, int length) : _prefix(prefix), _length(length) { _mask(); }
59  Network(const Network&) = default;
60  Network() = default;
61  Network(Network&&) noexcept = default;
62  ~Network() = default;
63 
64  Network& operator=(const Network&) = default;
65  Network& operator=(Network&&) noexcept = default;
66 
68  const auto& prefix() const { return _prefix; }
69 
71  auto family() const { return _prefix.family(); }
72 
77  auto length() const { return (family() == AddressFamily::IPv4 ? _length - 96 : _length); }
78 
80  bool contains(const Address& x) const { return x.mask(_length) == _prefix; }
81 
82  bool operator==(const Network& other) const { return _prefix == other._prefix && _length == other._length; }
83  bool operator!=(const Network& other) const { return ! (*this == other); }
84 
89  operator std::string() const {
90  if ( _prefix.family() == AddressFamily::Undef )
91  return "<bad network>";
92 
93  return fmt("%s/%u", _prefix, length());
94  }
95 
96 private:
97  void _mask() {
98  if ( _prefix.family() == AddressFamily::IPv4 )
99  _length += 96;
100 
101  _prefix = _prefix.mask(_length);
102  }
103 
104  Address _prefix;
105  int _length = 0;
106 };
107 
108 namespace detail::adl {
109 inline std::string to_string(const Network& x, adl::tag /*unused*/) { return x; }
110 } // namespace detail::adl
111 
112 inline std::ostream& operator<<(std::ostream& out, const Network& x) {
113  out << to_string(x);
114  return out;
115 }
116 
117 } // namespace hilti::rt
Definition: network.h:20
std::string to_string(T &&x)
Definition: extension-points.h:26
Network(const std::string &prefix, int length)
Definition: network.h:58
Definition: any.h:7
bool contains(const Address &x) const
Definition: network.h:80
Network(const Address &prefix, int length)
Definition: network.h:31
auto length() const
Definition: network.h:77
Address mask(unsigned int width) const
Definition: address.cc:55
Definition: address.h:24
AddressFamily family() const
Definition: address.cc:53
auto family() const
Definition: network.h:71
std::string fmt(const char *fmt, const Args &... args)
Definition: fmt.h:13
const auto & prefix() const
Definition: network.h:68