Fabcoin Core  0.16.2
P2P Digital Currency
Network.cpp
Go to the documentation of this file.
1 /*
2  This file is part of cpp-ethereum.
3 
4  cpp-ethereum is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  cpp-ethereum is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
16 */
24 #include <sys/types.h>
25 #ifndef _WIN32
26 #include <ifaddrs.h>
27 #endif
28 
29 #include <boost/algorithm/string.hpp>
30 #include <boost/algorithm/string/split.hpp>
31 
32 #include <libdevcore/Common.h>
33 #include <libdevcore/Assertions.h>
34 #include <libdevcore/CommonIO.h>
35 #include <libdevcore/Exceptions.h>
36 #include "Common.h"
37 #include "UPnP.h"
38 #include "Network.h"
39 
40 using namespace std;
41 using namespace dev;
42 using namespace dev::p2p;
43 
44 static_assert(BOOST_VERSION == 106300, "Wrong boost headers version");
45 
46 std::set<bi::address> Network::getInterfaceAddresses()
47 {
48  std::set<bi::address> addresses;
49 
50 #if defined(_WIN32)
51  WSAData wsaData;
52  if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
53  BOOST_THROW_EXCEPTION(NoNetworking());
54 
55  char ac[80];
56  if (gethostname(ac, sizeof(ac)) == SOCKET_ERROR)
57  {
58  clog(NetWarn) << "Error " << WSAGetLastError() << " when getting local host name.";
59  WSACleanup();
60  BOOST_THROW_EXCEPTION(NoNetworking());
61  }
62 
63  struct hostent* phe = gethostbyname(ac);
64  if (phe == 0)
65  {
66  clog(NetWarn) << "Bad host lookup.";
67  WSACleanup();
68  BOOST_THROW_EXCEPTION(NoNetworking());
69  }
70 
71  for (int i = 0; phe->h_addr_list[i] != 0; ++i)
72  {
73  struct in_addr addr;
74  memcpy(&addr, phe->h_addr_list[i], sizeof(struct in_addr));
75  char *addrStr = inet_ntoa(addr);
76  bi::address address(bi::address::from_string(addrStr));
77  if (!isLocalHostAddress(address))
78  addresses.insert(address.to_v4());
79  }
80 
81  WSACleanup();
82 #else
83  ifaddrs* ifaddr;
84  if (getifaddrs(&ifaddr) == -1)
85  BOOST_THROW_EXCEPTION(NoNetworking());
86 
87  for (auto ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
88  {
89  if (!ifa->ifa_addr || string(ifa->ifa_name) == "lo0" || !(ifa->ifa_flags & IFF_UP))
90  continue;
91 
92  if (ifa->ifa_addr->sa_family == AF_INET)
93  {
94  in_addr addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
95  boost::asio::ip::address_v4 address(boost::asio::detail::socket_ops::network_to_host_long(addr.s_addr));
96  if (!isLocalHostAddress(address))
97  addresses.insert(address);
98  }
99  else if (ifa->ifa_addr->sa_family == AF_INET6)
100  {
101  sockaddr_in6* sockaddr = ((struct sockaddr_in6 *)ifa->ifa_addr);
102  in6_addr addr = sockaddr->sin6_addr;
103  boost::asio::ip::address_v6::bytes_type bytes;
104  memcpy(&bytes[0], addr.s6_addr, 16);
105  boost::asio::ip::address_v6 address(bytes, sockaddr->sin6_scope_id);
106  if (!isLocalHostAddress(address))
107  addresses.insert(address);
108  }
109  }
110 
111  if (ifaddr!=NULL)
112  freeifaddrs(ifaddr);
113 
114 #endif
115 
116  return addresses;
117 }
118 
119 int Network::tcp4Listen(bi::tcp::acceptor& _acceptor, NetworkPreferences const& _netPrefs)
120 {
121  // Due to the complexities of NAT and network environments (multiple NICs, tunnels, etc)
122  // and security concerns automation is the enemy of network configuration.
123  // If a preference cannot be accommodate the network must fail to start.
124  //
125  // Preferred IP: Attempt if set, else, try 0.0.0.0 (all interfaces)
126  // Preferred Port: Attempt if set, else, try c_defaultListenPort or 0 (random)
127  // TODO: throw instead of returning -1 and rename NetworkPreferences to NetworkConfig
128 
129  bi::address listenIP;
130  try
131  {
132  listenIP = _netPrefs.listenIPAddress.empty() ? bi::address_v4() : bi::address::from_string(_netPrefs.listenIPAddress);
133  }
134  catch (...)
135  {
136  cwarn << "Couldn't start accepting connections on host. Failed to accept socket on " << listenIP << ":" << _netPrefs.listenPort << ".\n" << boost::current_exception_diagnostic_information();
137  return -1;
138  }
139  bool requirePort = (bool)_netPrefs.listenPort;
140 
141  for (unsigned i = 0; i < 2; ++i)
142  {
143  bi::tcp::endpoint endpoint(listenIP, requirePort ? _netPrefs.listenPort : (i ? 0 : c_defaultListenPort));
144  try
145  {
146 #if defined(_WIN32)
147  bool reuse = false;
148 #else
149  bool reuse = true;
150 #endif
151  _acceptor.open(endpoint.protocol());
152  _acceptor.set_option(ba::socket_base::reuse_address(reuse));
153  _acceptor.bind(endpoint);
154  _acceptor.listen();
155  return _acceptor.local_endpoint().port();
156  }
157  catch (...)
158  {
159  // bail if this is first attempt && port was specificed, or second attempt failed (random port)
160  if (i || requirePort)
161  {
162  // both attempts failed
163  cwarn << "Couldn't start accepting connections on host. Failed to accept socket on " << listenIP << ":" << _netPrefs.listenPort << ".\n" << boost::current_exception_diagnostic_information();
164  _acceptor.close();
165  return -1;
166  }
167 
168  _acceptor.close();
169  continue;
170  }
171  }
172 
173  return -1;
174 }
175 
176 bi::tcp::endpoint Network::traverseNAT(std::set<bi::address> const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpInterfaceAddr)
177 {
178  asserts(_listenPort != 0);
179 
180  unique_ptr<UPnP> upnp;
181  try
182  {
183  upnp.reset(new UPnP);
184  }
185  // let m_upnp continue as null - we handle it properly.
186  catch (...) {}
187 
188  bi::tcp::endpoint upnpEP;
189  if (upnp && upnp->isValid())
190  {
191  bi::address pAddr;
192  int extPort = 0;
193  for (auto const& addr: _ifAddresses)
194  if (addr.is_v4() && isPrivateAddress(addr) && (extPort = upnp->addRedirect(addr.to_string().c_str(), _listenPort)))
195  {
196  pAddr = addr;
197  break;
198  }
199 
200  auto eIP = upnp->externalIP();
201  bi::address eIPAddr(bi::address::from_string(eIP));
202  if (extPort && eIP != string("0.0.0.0") && !isPrivateAddress(eIPAddr))
203  {
204  clog(NetNote) << "Punched through NAT and mapped local port" << _listenPort << "onto external port" << extPort << ".";
205  clog(NetNote) << "External addr:" << eIP;
206  o_upnpInterfaceAddr = pAddr;
207  upnpEP = bi::tcp::endpoint(eIPAddr, (unsigned short)extPort);
208  }
209  else
210  clog(NetWarn) << "Couldn't punch through NAT (or no NAT in place).";
211  }
212 
213  return upnpEP;
214 }
215 
216 bi::tcp::endpoint Network::resolveHost(string const& _addr)
217 {
218  static boost::asio::io_service s_resolverIoService;
219 
220  vector<string> split;
221  boost::split(split, _addr, boost::is_any_of(":"));
222  unsigned port = dev::p2p::c_defaultIPPort;
223 
224  try
225  {
226  if (split.size() > 1)
227  port = static_cast<unsigned>(stoi(split.at(1)));
228  }
229  catch(...) {}
230 
231  boost::system::error_code ec;
232  bi::address address = bi::address::from_string(split[0], ec);
233  bi::tcp::endpoint ep(bi::address(), port);
234  if (!ec)
235  ep.address(address);
236  else
237  {
238  boost::system::error_code ec;
239  // resolve returns an iterator (host can resolve to multiple addresses)
240  bi::tcp::resolver r(s_resolverIoService);
241  auto it = r.resolve({bi::tcp::v4(), split[0], toString(port)}, ec);
242  if (ec)
243  {
244  clog(NetWarn) << "Error resolving host address..." << LogTag::Url << _addr << ":" << LogTag::Error << ec.message();
245  return bi::tcp::endpoint();
246  }
247  else
248  ep = *it;
249  }
250  return ep;
251 }
252 
std::string listenIPAddress
Definition: Network.h:56
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
Definition: Arith256.cpp:15
bool isPrivateAddress(bi::address const &_addressToCheck)
Definition: Common.cpp:84
#define asserts(A)
Definition: Assertions.h:41
bool isLocalHostAddress(bi::address const &_addressToCheck)
Definition: Common.cpp:116
for(size_t i=trim;i< len;i++) hash[i-trim]
std::hash for asio::adress
Definition: Common.h:323
std::string toString(string32 const &_s)
Make normal string from fixed-length string.
Definition: CommonData.cpp:141
#define WSAGetLastError()
Definition: compat.h:53
#define SOCKET_ERROR
Definition: compat.h:63
unsigned short listenPort
Definition: Network.h:57
std::vector< byte > bytes
Definition: Common.h:75
#define cwarn
Definition: Log.h:304
const unsigned c_defaultIPPort
Definition: Common.cpp:29
void * memcpy(void *a, const void *b, size_t c)
#define clog(X)
Definition: Log.h:295
struct evm_uint160be address(struct evm_env *env)
Definition: capi.c:13