Electroneum
i2p_address.cpp
Go to the documentation of this file.
1 // Copyright (c) 2019, The Monero Project
2 //
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without modification, are
6 // permitted provided that the following conditions are met:
7 //
8 // 1. Redistributions of source code must retain the above copyright notice, this list of
9 // conditions and the following disclaimer.
10 //
11 // 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 // of conditions and the following disclaimer in the documentation and/or other
13 // materials provided with the distribution.
14 //
15 // 3. Neither the name of the copyright holder nor the names of its contributors may be
16 // used to endorse or promote products derived from this software without specific
17 // prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
20 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
22 // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
27 // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 
29 #include "i2p_address.h"
30 
31 #include <algorithm>
32 #include <boost/spirit/include/karma_generate.hpp>
33 #include <boost/spirit/include/karma_uint.hpp>
34 #include <cassert>
35 #include <cstring>
36 #include <limits>
37 
38 #include "net/error.h"
41 #include "string_tools.h"
42 
43 namespace net
44 {
45  namespace
46  {
47  // !TODO only b32 addresses right now
48  constexpr const char tld[] = u8".b32.i2p";
49  constexpr const char unknown_host[] = "<unknown i2p host>";
50 
51  constexpr const unsigned b32_length = 52;
52 
53  constexpr const char base32_alphabet[] =
54  u8"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz234567";
55 
56  expect<void> host_check(boost::string_ref host) noexcept
57  {
58  if (!host.ends_with(tld))
59  return {net::error::expected_tld};
60 
61  host.remove_suffix(sizeof(tld) - 1);
62 
63  if (host.size() != b32_length)
65  if (host.find_first_not_of(base32_alphabet) != boost::string_ref::npos)
67 
68  return success();
69  }
70 
71  struct i2p_serialized
72  {
73  std::string host;
75 
77  KV_SERIALIZE(host)
80  };
81  }
82 
83  i2p_address::i2p_address(const boost::string_ref host, const std::uint16_t port) noexcept
84  : port_(port)
85  {
86  // this is a private constructor, throw if moved to public
87  assert(host.size() < sizeof(host_));
88 
89  const std::size_t length = std::min(sizeof(host_) - 1, host.size());
90  std::memcpy(host_, host.data(), length);
91  std::memset(host_ + length, 0, sizeof(host_) - length);
92  }
93 
94  const char* i2p_address::unknown_str() noexcept
95  {
96  return unknown_host;
97  }
98 
100  : port_(0)
101  {
102  static_assert(sizeof(unknown_host) <= sizeof(host_), "bad buffer size");
103  std::memcpy(host_, unknown_host, sizeof(unknown_host));
104  std::memset(host_ + sizeof(unknown_host), 0, sizeof(host_) - sizeof(unknown_host));
105  }
106 
107  expect<i2p_address> i2p_address::make(const boost::string_ref address, const std::uint16_t default_port)
108  {
109  boost::string_ref host = address.substr(0, address.rfind(':'));
110  const boost::string_ref port =
111  address.substr(host.size() + (host.size() == address.size() ? 0 : 1));
112 
113  ELECTRONEUM_CHECK(host_check(host));
114 
115  std::uint16_t porti = default_port;
117  return {net::error::invalid_port};
118 
119  static_assert(b32_length + sizeof(tld) == sizeof(i2p_address::host_), "bad internal host size");
120  return i2p_address{host, porti};
121  }
122 
124  {
125  i2p_serialized in{};
126  if (in._load(src, hparent) && in.host.size() < sizeof(host_) && (in.host == unknown_host || !host_check(in.host).has_error()))
127  {
128  std::memcpy(host_, in.host.data(), in.host.size());
129  std::memset(host_ + in.host.size(), 0, sizeof(host_) - in.host.size());
130  port_ = in.port;
131  return true;
132  }
133  static_assert(sizeof(unknown_host) <= sizeof(host_), "bad buffer size");
134  std::memcpy(host_, unknown_host, sizeof(unknown_host)); // include null terminator
135  port_ = 0;
136  return false;
137  }
138 
140  {
141  const i2p_serialized out{std::string{host_}, port_};
142  return out.store(dest, hparent);
143  }
144 
146  : port_(rhs.port_)
147  {
148  std::memcpy(host_, rhs.host_, sizeof(host_));
149  }
150 
152  {
153  if (this != std::addressof(rhs))
154  {
155  port_ = rhs.port_;
156  std::memcpy(host_, rhs.host_, sizeof(host_));
157  }
158  return *this;
159  }
160 
161  bool i2p_address::is_unknown() const noexcept
162  {
163  static_assert(1 <= sizeof(host_), "host size too small");
164  return host_[0] == '<'; // character is not allowed otherwise
165  }
166 
167  bool i2p_address::equal(const i2p_address& rhs) const noexcept
168  {
169  return port_ == rhs.port_ && is_same_host(rhs);
170  }
171 
172  bool i2p_address::less(const i2p_address& rhs) const noexcept
173  {
174  return std::strcmp(host_str(), rhs.host_str()) < 0 || port() < rhs.port();
175  }
176 
177  bool i2p_address::is_same_host(const i2p_address& rhs) const noexcept
178  {
179  return std::strcmp(host_str(), rhs.host_str()) == 0;
180  }
181 
183  {
184  const std::size_t host_length = std::strlen(host_str());
185  const std::size_t port_length =
186  port_ == 0 ? 0 : std::numeric_limits<std::uint16_t>::digits10 + 2;
187 
188  std::string out{};
189  out.reserve(host_length + port_length);
190  out.assign(host_str(), host_length);
191 
192  if (port_ != 0)
193  {
194  out.push_back(':');
195  namespace karma = boost::spirit::karma;
196  karma::generate(std::back_inserter(out), karma::ushort_, port());
197  }
198  return out;
199  }
200 }
i2p_address & operator=(const i2p_address &rhs) noexcept
b32 i2p address; internal format not condensed/decoded.
Definition: i2p_address.h:51
::std::string string
Definition: gtest-port.h:1097
CXA_THROW_INFO_T void(* dest)(void *))
Definition: stack_trace.cpp:91
bool equal(const i2p_address &rhs) const noexcept
static const char * unknown_str() noexcept
Definition: i2p_address.cpp:94
bool _load(epee::serialization::portable_storage &src, epee::serialization::section *hparent)
Load from epee p2p format, and.
STL namespace.
unsigned short uint16_t
Definition: stdint.h:125
#define KV_SERIALIZE(varialble)
bool is_same_host(const i2p_address &rhs) const noexcept
Definition: expect.h:70
#define ELECTRONEUM_CHECK(...)
Check expect<void> and return errors in current scope.
Definition: expect.h:47
bool is_unknown() const noexcept
boost::endian::big_uint16_t port
Definition: socks.cpp:60
i2p_address() noexcept
An object with port() == 0 and host_str() == unknown_str().
Definition: i2p_address.cpp:99
expect< void > success() noexcept
Definition: expect.h:397
void * memcpy(void *a, const void *b, size_t c)
std::string str() const
const char * address
Definition: multisig.cpp:37
static expect< i2p_address > make(boost::string_ref address, std::uint16_t default_port=0)
#define END_KV_SERIALIZE_MAP()
Outside of 0-65535 range.
PUSH_WARNINGS bool get_xtype_from_string(OUT XType &val, const std::string &str_id)
Definition: string_tools.h:125
bool less(const i2p_address &rhs) const noexcept
Expected a tld.
unsigned char u8
Definition: chacha_private.h:9
bool store(epee::serialization::portable_storage &dest, epee::serialization::section *hparent) const
Store in epee p2p format.
#define BEGIN_KV_SERIALIZE_MAP()