YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/Users/deen/code/yugabyte-db/src/yb/util/net/net_util.cc
Line
Count
Source (jump to first uncovered line)
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
//
18
// The following only applies to changes made to this file as part of YugaByte development.
19
//
20
// Portions Copyright (c) YugaByte, Inc.
21
//
22
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
23
// in compliance with the License.  You may obtain a copy of the License at
24
//
25
// http://www.apache.org/licenses/LICENSE-2.0
26
//
27
// Unless required by applicable law or agreed to in writing, software distributed under the License
28
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
29
// or implied.  See the License for the specific language governing permissions and limitations
30
// under the License.
31
//
32
33
#include "yb/util/net/net_util.h"
34
35
#include <ifaddrs.h>
36
#include <sys/types.h>
37
38
#include <algorithm>
39
#include <unordered_set>
40
#include <utility>
41
#include <vector>
42
43
#include <boost/algorithm/string.hpp>
44
45
#include "yb/gutil/map-util.h"
46
#include "yb/gutil/strings/join.h"
47
#include "yb/gutil/strings/numbers.h"
48
#include "yb/gutil/strings/split.h"
49
#include "yb/gutil/strings/strip.h"
50
#include "yb/gutil/strings/substitute.h"
51
52
#include "yb/util/debug/trace_event.h"
53
#include "yb/util/env.h"
54
#include "yb/util/env_util.h"
55
#include "yb/util/errno.h"
56
#include "yb/util/faststring.h"
57
#include "yb/util/flag_tags.h"
58
#include "yb/util/locks.h"
59
#include "yb/util/net/inetaddress.h"
60
#include "yb/util/net/sockaddr.h"
61
#include "yb/util/net/socket.h"
62
#include "yb/util/random_util.h"
63
#include "yb/util/result.h"
64
#include "yb/util/scope_exit.h"
65
#include "yb/util/status_format.h"
66
#include "yb/util/stopwatch.h"
67
#include "yb/util/subprocess.h"
68
69
// Mac OS 10.9 does not appear to define HOST_NAME_MAX in unistd.h
70
#ifndef HOST_NAME_MAX
71
77.2k
#define HOST_NAME_MAX 64
72
#endif
73
74
using std::unordered_set;
75
using std::vector;
76
using strings::Substitute;
77
78
DEFINE_string(
79
    net_address_filter,
80
    "ipv4_external,ipv4_all,ipv6_external,ipv6_non_link_local,ipv6_all",
81
    "Order in which to select ip addresses returned by the resolver"
82
    "Can be set to something like \"ipv4_all,ipv6_all\" to prefer IPv4 over "
83
    "IPv6 addresses."
84
    "Can be set to something like \"ipv4_external,ipv4_all,ipv6_all\" to "
85
    "prefer external IPv4 "
86
    "addresses first. Other options include ipv6_external,ipv6_non_link_local");
87
88
namespace yb {
89
90
namespace {
91
struct AddrinfoDeleter {
92
31.0k
  void operator()(struct addrinfo* info) {
93
31.0k
    freeaddrinfo(info);
94
31.0k
  }
95
};
96
}
97
98
HostPort::HostPort()
99
4.54M
    : port_(0) {
100
4.54M
}
101
102
HostPort::HostPort(Slice host, uint16_t port)
103
165
    : host_(host.cdata(), host.size()), port_(port) {}
104
105
HostPort::HostPort(std::string host, uint16_t port)
106
71.8k
    : host_(std::move(host)), port_(port) {}
107
108
HostPort::HostPort(const Endpoint& endpoint)
109
8.03k
    : host_(endpoint.address().to_string()), port_(endpoint.port()) {
110
8.03k
}
111
112
HostPort::HostPort(const char* host, uint16_t port)
113
165
    : HostPort(Slice(host), port) {
114
165
}
Unexecuted instantiation: yb::HostPort::HostPort(char const*, unsigned short)
yb::HostPort::HostPort(char const*, unsigned short)
Line
Count
Source
113
165
    : HostPort(Slice(host), port) {
114
165
}
115
116
Status HostPort::RemoveAndGetHostPortList(
117
    const Endpoint& remove,
118
    const std::vector<std::string>& multiple_server_addresses,
119
    uint16_t default_port,
120
0
    std::vector<HostPort> *res) {
121
0
  bool found = false;
122
  // Note that this outer loop is over a vector of comma-separated strings.
123
0
  for (const string& master_server_addr : multiple_server_addresses) {
124
0
    std::vector<std::string> addr_strings =
125
0
        strings::Split(master_server_addr, ",", strings::SkipEmpty());
126
0
    for (const auto& single_addr : addr_strings) {
127
0
      HostPort host_port;
128
0
      RETURN_NOT_OK(host_port.ParseString(single_addr, default_port));
129
0
      if (host_port.equals(remove)) {
130
0
        found = true;
131
0
        continue;
132
0
      } else {
133
0
        res->push_back(host_port);
134
0
      }
135
0
    }
136
0
  }
137
138
0
  if (!found) {
139
0
    std::ostringstream out;
140
0
    out.str("Current list of master addresses: ");
141
0
    for (const string& master_server_addr : multiple_server_addresses) {
142
0
      out.str(master_server_addr);
143
0
      out.str(" ");
144
0
    }
145
0
    LOG(ERROR) << out.str();
146
147
0
    return STATUS_SUBSTITUTE(NotFound,
148
0
                             "Cannot find $0 in addresses: $1",
149
0
                             yb::ToString(remove),
150
0
                             out.str());
151
0
  }
152
153
0
  return Status::OK();
154
0
}
155
156
// Accepts entries like: [::1], 127.0.0.1, [::1]:7100, 0.0.0.0:7100,
157
// f.q.d.n:7100
158
365k
Status HostPort::ParseString(const string &str_in, uint16_t default_port) {
159
365k
  uint32_t port;
160
365k
  string host;
161
162
365k
  string str(str_in);
163
365k
  StripWhiteSpace(&str);
164
365k
  size_t pos = str.rfind(':');
165
365k
  if (str[0] == '[' && 
str[str.length() - 1] == ']'8
&&
str.length() > 23
) {
166
    // The whole thing is an IPv6 address.
167
3
    host = str.substr(1, str.length() - 2);
168
3
    port = default_port;
169
365k
  } else if (pos == string::npos) {
170
    // No port was specified, the whole thing must be a host.
171
3.88k
    host = str;
172
3.88k
    port = default_port;
173
361k
  } else 
if (361k
pos > 1361k
&& pos + 1 < str.length() &&
174
361k
             
SimpleAtoi(str.substr(pos + 1), &port)361k
) {
175
176
361k
    if (port > numeric_limits<uint16_t>::max()) {
177
1
      return STATUS(InvalidArgument, "Invalid port", str);
178
1
    }
179
180
    // Got a host:port
181
361k
    host = str.substr(0, pos);
182
361k
    if (host[0] == '[' && 
host[host.length() - 1] == ']'5
&&
host.length() > 25
) {
183
      // Remove brackets if we have an IPv6 address
184
5
      host = host.substr(1, host.length() - 2);
185
5
    }
186
18.4E
  } else {
187
18.4E
    return STATUS(InvalidArgument,
188
18.4E
                  Format(
189
18.4E
                      "Invalid port: expected port after ':' "
190
18.4E
                      "at position $0 in $1",
191
18.4E
                      pos, str));
192
18.4E
  }
193
194
365k
  host_ = host;
195
365k
  port_ = port;
196
365k
  return Status::OK();
197
365k
}
198
199
62.1k
Result<HostPort> HostPort::FromString(const std::string& str, uint16_t default_port) {
200
62.1k
  HostPort result;
201
62.1k
  RETURN_NOT_OK(result.ParseString(str, default_port));
202
62.1k
  return result;
203
62.1k
}
204
205
Result<std::vector<HostPort>> HostPort::ParseStrings(
206
    const std::string& comma_sep_addrs, uint16_t default_port,
207
4.01k
    const char* separator) {
208
4.01k
  std::vector<HostPort> result;
209
4.01k
  RETURN_NOT_OK(ParseStrings(comma_sep_addrs, default_port, &result, separator));
210
4.01k
  return result;
211
4.01k
}
212
213
37.7M
size_t HostPortHash::operator()(const HostPort& hostPort) const {
214
37.7M
  return GStringPiece(std::to_string(hostPort.port()) + hostPort.host()).hash();
215
37.7M
}
216
217
namespace {
218
345
const string getaddrinfo_rc_to_string(int rc) {
219
345
  const char* s = nullptr;
220
345
  switch (rc) {
221
0
    case EAI_ADDRFAMILY: s = "EAI_ADDRFAMILY"; break;
222
0
    case EAI_AGAIN: s = "EAI_AGAIN"; break;
223
0
    case EAI_BADFLAGS: s = "EAI_BADFLAGS"; break;
224
0
    case EAI_FAIL: s = "EAI_FAIL"; break;
225
0
    case EAI_FAMILY: s = "EAI_FAMILY"; break;
226
0
    case EAI_MEMORY: s = "EAI_MEMORY"; break;
227
0
    case EAI_NODATA: s = "EAI_NODATA"; break;
228
346
    case EAI_NONAME: s = "EAI_NONAME"; break;
229
0
    case EAI_SERVICE: s = "EAI_SERVICE"; break;
230
0
    case EAI_SOCKTYPE: s = "EAI_SOCKTYPE"; break;
231
0
    case EAI_SYSTEM: s = "EAI_SYSTEM"; break;
232
0
    default: s = "UNKNOWN";
233
345
  }
234
346
  return Substitute("$0 ($1)", rc, s);
235
345
}
236
237
30.9k
Result<std::unique_ptr<addrinfo, AddrinfoDeleter>> HostToInetAddrInfo(const std::string& host) {
238
30.9k
  struct addrinfo hints;
239
30.9k
  memset(&hints, 0, sizeof(hints));
240
30.9k
  hints.ai_family = AF_UNSPEC;
241
30.9k
  hints.ai_socktype = SOCK_STREAM;
242
30.9k
  struct addrinfo* res = nullptr;
243
30.9k
  int rc = 0;
244
30.9k
  LOG_SLOW_EXECUTION(WARNING, 200,
245
31.1k
                     Substitute("resolving address for $0", host)) {
246
31.1k
    rc = getaddrinfo(host.c_str(), nullptr, &hints, &res);
247
31.1k
  }
248
30.9k
  if (rc != 0) {
249
68
    return STATUS_FORMAT(NetworkError, "Unable to resolve address $0, getaddrinfo returned $1: $2",
250
68
                         host.c_str(), getaddrinfo_rc_to_string(rc).c_str(), gai_strerror(rc));
251
30.9k
  } else {
252
30.9k
    return std::unique_ptr<addrinfo, AddrinfoDeleter>(res);
253
30.9k
  }
254
30.9k
}
255
256
template <typename F>
257
205k
CHECKED_STATUS ResolveInetAddresses(const std::string& host, F func) {
258
205k
  boost::optional<IpAddress> fast_resolve = TryFastResolve(host);
259
205k
  if (fast_resolve) {
260
174k
    func(*fast_resolve);
261
18.4E
    VLOG(4) << "Fast resolved " << host << " to " << fast_resolve->to_string();
262
174k
    return Status::OK();
263
174k
  }
264
265
31.0k
  auto addrinfo_holder = 
VERIFY_RESULT30.9k
(HostToInetAddrInfo(host));30.9k
266
0
  struct addrinfo* addrinfo = addrinfo_holder.get();
267
93.0k
  for (; addrinfo != nullptr; 
addrinfo = addrinfo->ai_next62.0k
) {
268
62.0k
    if (addrinfo->ai_family == AF_INET) {
269
61.4k
      auto* addr = reinterpret_cast<struct sockaddr_in*>(addrinfo->ai_addr);
270
61.4k
      Endpoint endpoint;
271
61.4k
      memcpy(endpoint.data(), addr, sizeof(*addr));
272
61.4k
      func(endpoint.address());
273
61.4k
    } else 
if (675
addrinfo->ai_family == AF_INET6675
) {
274
676
      auto* addr = reinterpret_cast<struct sockaddr_in6*>(addrinfo->ai_addr);
275
676
      Endpoint endpoint;
276
676
      memcpy(endpoint.data(), addr, sizeof(*addr));
277
676
      func(endpoint.address());
278
18.4E
    } else {
279
18.4E
      return STATUS_FORMAT(NetworkError, "Unexpected address family: $0", addrinfo->ai_family);
280
18.4E
    }
281
62.0k
  }
282
30.9k
  return Status::OK();
283
30.9k
}
net_util.cc:yb::Status yb::(anonymous namespace)::ResolveInetAddresses<yb::HostPort::ResolveAddresses(std::__1::vector<boost::asio::ip::basic_endpoint<boost::asio::ip::tcp>, std::__1::allocator<boost::asio::ip::basic_endpoint<boost::asio::ip::tcp> > >*) const::$_0>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, yb::HostPort::ResolveAddresses(std::__1::vector<boost::asio::ip::basic_endpoint<boost::asio::ip::tcp>, std::__1::allocator<boost::asio::ip::basic_endpoint<boost::asio::ip::tcp> > >*) const::$_0)
Line
Count
Source
257
131k
CHECKED_STATUS ResolveInetAddresses(const std::string& host, F func) {
258
131k
  boost::optional<IpAddress> fast_resolve = TryFastResolve(host);
259
131k
  if (fast_resolve) {
260
100k
    func(*fast_resolve);
261
100k
    VLOG
(4) << "Fast resolved " << host << " to " << fast_resolve->to_string()0
;
262
100k
    return Status::OK();
263
100k
  }
264
265
31.0k
  auto addrinfo_holder = 
VERIFY_RESULT30.9k
(HostToInetAddrInfo(host));30.9k
266
0
  struct addrinfo* addrinfo = addrinfo_holder.get();
267
93.0k
  for (; addrinfo != nullptr; 
addrinfo = addrinfo->ai_next62.0k
) {
268
62.0k
    if (addrinfo->ai_family == AF_INET) {
269
61.4k
      auto* addr = reinterpret_cast<struct sockaddr_in*>(addrinfo->ai_addr);
270
61.4k
      Endpoint endpoint;
271
61.4k
      memcpy(endpoint.data(), addr, sizeof(*addr));
272
61.4k
      func(endpoint.address());
273
61.4k
    } else 
if (675
addrinfo->ai_family == AF_INET6675
) {
274
676
      auto* addr = reinterpret_cast<struct sockaddr_in6*>(addrinfo->ai_addr);
275
676
      Endpoint endpoint;
276
676
      memcpy(endpoint.data(), addr, sizeof(*addr));
277
676
      func(endpoint.address());
278
18.4E
    } else {
279
18.4E
      return STATUS_FORMAT(NetworkError, "Unexpected address family: $0", addrinfo->ai_family);
280
18.4E
    }
281
62.0k
  }
282
30.9k
  return Status::OK();
283
30.9k
}
net_util.cc:yb::Status yb::(anonymous namespace)::ResolveInetAddresses<yb::HostToAddresses(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, boost::container::small_vector_base<boost::asio::ip::address, void, void>*)::$_2>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, yb::HostToAddresses(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, boost::container::small_vector_base<boost::asio::ip::address, void, void>*)::$_2)
Line
Count
Source
257
74.1k
CHECKED_STATUS ResolveInetAddresses(const std::string& host, F func) {
258
74.1k
  boost::optional<IpAddress> fast_resolve = TryFastResolve(host);
259
74.1k
  if (fast_resolve) {
260
74.0k
    func(*fast_resolve);
261
18.4E
    VLOG(4) << "Fast resolved " << host << " to " << fast_resolve->to_string();
262
74.0k
    return Status::OK();
263
74.0k
  }
264
265
21
  auto addrinfo_holder = 
VERIFY_RESULT19
(HostToInetAddrInfo(host));19
266
0
  struct addrinfo* addrinfo = addrinfo_holder.get();
267
24
  for (; addrinfo != nullptr; 
addrinfo = addrinfo->ai_next5
) {
268
5
    if (addrinfo->ai_family == AF_INET) {
269
5
      auto* addr = reinterpret_cast<struct sockaddr_in*>(addrinfo->ai_addr);
270
5
      Endpoint endpoint;
271
5
      memcpy(endpoint.data(), addr, sizeof(*addr));
272
5
      func(endpoint.address());
273
5
    } else 
if (0
addrinfo->ai_family == AF_INET60
) {
274
0
      auto* addr = reinterpret_cast<struct sockaddr_in6*>(addrinfo->ai_addr);
275
0
      Endpoint endpoint;
276
0
      memcpy(endpoint.data(), addr, sizeof(*addr));
277
0
      func(endpoint.address());
278
0
    } else {
279
0
      return STATUS_FORMAT(NetworkError, "Unexpected address family: $0", addrinfo->ai_family);
280
0
    }
281
5
  }
282
19
  return Status::OK();
283
19
}
284
285
}  // namespace
286
287
131k
Status HostPort::ResolveAddresses(std::vector<Endpoint>* addresses) const {
288
131k
  TRACE_EVENT1("net", "HostPort::ResolveAddresses",
289
131k
               "host", host_);
290
131k
  if (!addresses) {
291
1
    return Status::OK();
292
1
  }
293
131k
  vector<IpAddress> ip_addresses;
294
131k
  RETURN_NOT_OK(ResolveInetAddresses(
295
131k
      host_, [this, &ip_addresses](const IpAddress &ip_address) {
296
131k
        ip_addresses.push_back(ip_address);
297
131k
        VLOG(3) << "Resolved address " << ip_address.to_string() << " for host "
298
131k
                << host_;
299
131k
      }));
300
301
131k
  FilterAddresses(FLAGS_net_address_filter, &ip_addresses);
302
303
131k
  VLOG(2) << "Returned " << ip_addresses.size() << " addresses for host "
304
16
          << host_;
305
162k
  for (const auto &ip_addr : ip_addresses) {
306
162k
    VLOG(2) << "Returned address " << ip_addr.to_string() << " for host "
307
13
            << host_;
308
162k
    addresses->push_back(Endpoint(ip_addr, port_));
309
162k
  }
310
131k
  return Status::OK();
311
131k
}
312
313
Status HostPort::ParseStrings(const string& comma_sep_addrs,
314
                              uint16_t default_port,
315
                              std::vector<HostPort>* res,
316
211k
                              const char* separator) {
317
211k
  std::vector<string> addr_strings = strings::Split(
318
211k
      comma_sep_addrs, separator, strings::SkipEmpty());
319
211k
  std::vector<HostPort> host_ports;
320
288k
  for (string& addr_string : addr_strings) {
321
288k
    HostPort host_port;
322
288k
    RETURN_NOT_OK(host_port.ParseString(addr_string, default_port));
323
288k
    host_ports.push_back(host_port);
324
288k
  }
325
211k
  *res = host_ports;
326
211k
  return Status::OK();
327
211k
}
328
329
97.2M
string HostPort::ToString() const { return HostPortToString(host_, port_); }
330
331
6.04k
string HostPort::ToCommaSeparatedString(const std::vector<HostPort>& hostports) {
332
6.04k
  vector<string> hostport_strs;
333
6.54k
  for (const HostPort& hostport : hostports) {
334
6.54k
    hostport_strs.push_back(hostport.ToString());
335
6.54k
  }
336
6.04k
  return JoinStrings(hostport_strs, ",");
337
6.04k
}
338
339
25.8k
bool IsPrivilegedPort(uint16_t port) { return port < 1024 && 
port != 054
; }
340
341
Status ParseAddressList(const std::string& addr_list,
342
                        uint16_t default_port,
343
53.6k
                        std::vector<Endpoint>* addresses) {
344
53.6k
  std::vector<HostPort> host_ports;
345
53.6k
  RETURN_NOT_OK(HostPort::ParseStrings(addr_list, default_port, &host_ports));
346
53.6k
  std::unordered_set<Endpoint, EndpointHash> uniqued;
347
348
53.6k
  for (const HostPort& host_port : host_ports) {
349
53.6k
    std::vector<Endpoint> this_addresses;
350
53.6k
    RETURN_NOT_OK(host_port.ResolveAddresses(&this_addresses));
351
352
    // Only add the unique ones -- the user may have specified
353
    // some IP addresses in multiple ways
354
54.3k
    
for (const auto& addr : this_addresses)53.6k
{
355
54.3k
      if (InsertIfNotPresent(&uniqued, addr)) {
356
54.3k
        addresses->push_back(addr);
357
54.3k
      } else {
358
0
        LOG(INFO) << "Address " << addr << " for " << host_port.ToString()
359
0
                  << " duplicates an earlier resolved entry.";
360
0
      }
361
54.3k
    }
362
53.6k
  }
363
53.6k
  return Status::OK();
364
53.6k
}
365
366
77.2k
Status GetHostname(string* hostname) {
367
77.2k
  TRACE_EVENT0("net", "GetHostname");
368
77.2k
  char name[HOST_NAME_MAX];
369
77.2k
  int ret = gethostname(name, HOST_NAME_MAX);
370
77.2k
  if (ret != 0) {
371
0
    return STATUS(NetworkError, "Unable to determine local hostname", Errno(errno));
372
0
  }
373
77.2k
  *hostname = name;
374
77.2k
  return Status::OK();
375
77.2k
}
376
377
11.9k
Result<string> GetHostname() {
378
11.9k
  std::string result;
379
11.9k
  RETURN_NOT_OK(GetHostname(&result));
380
11.9k
  return result;
381
11.9k
}
382
383
Status GetLocalAddresses(const string &filter_spec,
384
0
                         std::vector<IpAddress> *result) {
385
0
  RETURN_NOT_OK(GetLocalAddresses(result, AddressFilter::ANY));
386
0
  FilterAddresses(filter_spec, result);
387
0
  return Status::OK();
388
0
}
389
390
30.7k
Status GetLocalAddresses(std::vector<IpAddress>* result, AddressFilter filter) {
391
30.7k
  ifaddrs* addresses;
392
30.7k
  if (getifaddrs(&addresses)) {
393
0
    return STATUS(NetworkError, "Failed to list network interfaces", Errno(errno));
394
0
  }
395
396
30.7k
  auto se = ScopeExit([addresses] {
397
30.7k
    freeifaddrs(addresses);
398
30.7k
  });
399
400
32.2M
  for (auto address = addresses; address; 
address = address->ifa_next32.2M
) {
401
32.2M
    if (
address->ifa_addr != nullptr32.2M
) {
402
32.2M
      Endpoint temp;
403
32.2M
      auto family = address->ifa_addr->sa_family;
404
32.2M
      size_t size;
405
32.2M
      if (family == AF_INET) {
406
31.1M
        size = sizeof(sockaddr_in);
407
31.1M
      } else 
if (1.00M
family == AF_INET61.00M
) {
408
269k
        size = sizeof(sockaddr_in6);
409
735k
      } else {
410
735k
        continue;
411
735k
      }
412
31.4M
      memcpy(temp.data(), address->ifa_addr, size);
413
31.4M
      switch (filter) {
414
2.05k
        case AddressFilter::ANY:
415
2.05k
          result->push_back(temp.address());
416
2.05k
          break;
417
31.4M
        case AddressFilter::EXTERNAL:
418
31.4M
          if (
!temp.address().is_unspecified()31.4M
&& !temp.address().is_loopback()) {
419
361k
            result->push_back(temp.address());
420
361k
          }
421
31.4M
          break;
422
31.4M
      }
423
31.4M
    }
424
32.2M
  }
425
37.1k
  return Status::OK();
426
30.7k
}
427
428
32.7k
Status GetFQDN(string* hostname) {
429
32.7k
  TRACE_EVENT0("net", "GetFQDN");
430
  // Start with the non-qualified hostname
431
32.7k
  RETURN_NOT_OK(GetHostname(hostname));
432
433
32.7k
  struct addrinfo hints;
434
32.7k
  memset(&hints, 0, sizeof(hints));
435
32.7k
  hints.ai_socktype = SOCK_DGRAM;
436
32.7k
  hints.ai_flags = AI_CANONNAME;
437
438
32.7k
  struct addrinfo* result;
439
32.7k
  LOG_SLOW_EXECUTION(WARNING, 200,
440
32.7k
                     Substitute("looking up canonical hostname for localhost $0", *hostname)) {
441
32.7k
    TRACE_EVENT0("net", "getaddrinfo");
442
32.7k
    const int rc = getaddrinfo(hostname->c_str(), nullptr, &hints, &result);
443
32.7k
    if (rc != 0) {
444
277
      return STATUS(NetworkError,
445
277
                    Substitute("Unable to lookup FQDN ($0), getaddrinfo returned $1",
446
277
                               *hostname, getaddrinfo_rc_to_string(rc)),
447
277
                    Errno(errno));
448
277
    }
449
32.7k
  }
450
451
32.4k
  if (!result->ai_canonname) {
452
0
    return STATUS(NetworkError, "Canonical name not specified");
453
0
  }
454
455
32.4k
  *hostname = result->ai_canonname;
456
32.4k
  freeaddrinfo(result);
457
32.4k
  return Status::OK();
458
32.4k
}
459
460
0
Status EndpointFromHostPort(const HostPort& host_port, Endpoint* endpoint) {
461
0
  vector<Endpoint> addrs;
462
0
  RETURN_NOT_OK(host_port.ResolveAddresses(&addrs));
463
0
  if (addrs.empty()) {
464
0
    return STATUS(NetworkError, "Unable to resolve address", host_port.ToString());
465
0
  }
466
0
  *endpoint = addrs[0];
467
0
  if (addrs.size() > 1) {
468
0
    VLOG(1) << "Hostname " << host_port.host() << " resolved to more than one address. "
469
0
            << "Using address: " << *endpoint;
470
0
  }
471
0
  return Status::OK();
472
0
}
473
474
2
Status HostPortFromEndpointReplaceWildcard(const Endpoint& addr, HostPort* hp) {
475
2
  string host;
476
2
  if (addr.address().is_unspecified()) {
477
1
    auto status = GetFQDN(&host);
478
1
    if (!status.ok()) {
479
0
      std::vector<IpAddress> locals;
480
0
      if (GetLocalAddresses(&locals, AddressFilter::EXTERNAL).ok() && !locals.empty()) {
481
0
        hp->set_host(locals.front().to_string());
482
0
        hp->set_port(addr.port());
483
0
        return Status::OK();
484
0
      }
485
0
      return status;
486
0
    }
487
1
  } else {
488
1
    host = addr.address().to_string();
489
1
  }
490
2
  hp->set_host(host);
491
2
  hp->set_port(addr.port());
492
2
  return Status::OK();
493
2
}
494
495
96
void TryRunLsof(const Endpoint& addr, vector<string>* log) {
496
96
#if defined(__APPLE__)
497
96
  string cmd = strings::Substitute(
498
96
      "lsof -n -i 'TCP:$0' -sTCP:LISTEN ; "
499
96
      "for pid in $$(lsof -F p -n -i 'TCP:$0' -sTCP:LISTEN | cut -f 2 -dp) ; do"
500
96
      "  pstree $$pid || ps h -p $$pid;"
501
96
      "done",
502
96
      addr.port());
503
#else
504
  // Little inline bash script prints the full ancestry of any pid listening
505
  // on the same port as 'addr'. We could use 'pstree -s', but that option
506
  // doesn't exist on el6.
507
  //
508
  // Note the sed command to check for the process name wrapped in ().
509
  // Example prefix of /proc/$pid/stat output, with a process with spaces in the name:
510
  // 3917 (tmux: server) S 1
511
  string cmd = strings::Substitute(
512
      "export PATH=$$PATH:/usr/sbin ; "
513
      "lsof -n -i 'TCP:$0' -sTCP:LISTEN ; "
514
      "for pid in $$(lsof -F p -n -i 'TCP:$0' -sTCP:LISTEN | cut -f 2 -dp) ; do"
515
      "  while [ $$pid -gt 1 ] ; do"
516
      "    ps h -fp $$pid ;"
517
      "    pid=$$(sed 's/.* (.*) [^ ] \\([0-9]*\\).*/\\1/g' /proc/$$pid/stat);"
518
      "  done ; "
519
      "done",
520
      addr.port());
521
#endif // defined(__APPLE__)
522
523
96
  LOG_STRING(WARNING, log) << "Failed to bind to " << addr << ". "
524
96
                           << "Trying to use lsof to find any processes listening "
525
96
                           << "on the same port:";
526
96
  LOG_STRING(INFO, log) << "$ " << cmd;
527
96
  vector<string> argv = { "bash", "-c", cmd };
528
96
  string results;
529
96
  Status s = Subprocess::Call(argv, &results);
530
96
  if (PREDICT_FALSE(!s.ok())) {
531
94
    LOG_STRING(WARNING, log) << s.ToString();
532
94
  }
533
96
  LOG_STRING(WARNING, log) << results;
534
96
}
535
536
17.5k
uint16_t GetFreePort(std::unique_ptr<FileLock>* file_lock) {
537
  // To avoid a race condition where the free port returned to the caller gets used by another
538
  // process before this caller can use it, we will lock the port using a file level lock.
539
  // First create the directory, if it doesn't already exist, where these lock files will live.
540
17.5k
  Env* env = Env::Default();
541
17.5k
  bool created = false;
542
17.5k
  const string lock_file_dir = "/tmp/yb-port-locks";
543
17.5k
  Status status = env_util::CreateDirIfMissing(env, lock_file_dir, &created);
544
17.5k
  if (!status.ok()) {
545
0
    LOG(FATAL) << "Could not create " << lock_file_dir << " directory: "
546
0
               << status.ToString();
547
0
  }
548
549
  // Now, find a unused port in the [kMinPort..kMaxPort] range.
550
17.5k
  constexpr uint16_t kMinPort = 15000;
551
17.5k
  constexpr uint16_t kMaxPort = 30000;
552
17.5k
  Status s;
553
33.0k
  for (int i = 0; i < 1000; 
++i15.5k
) {
554
33.0k
    const uint16_t random_port = RandomUniformInt(kMinPort, kMaxPort);
555
33.0k
    VLOG
(1) << "Trying to bind to port " << random_port0
;
556
557
33.0k
    Endpoint sock_addr(boost::asio::ip::address_v4::loopback(), random_port);
558
33.0k
    Socket sock;
559
33.0k
    s = sock.Init(0);
560
33.0k
    if (!s.ok()) {
561
465
      VLOG
(1) << "Failed to call Init() on socket ith address " << sock_addr0
;
562
465
      continue;
563
465
    }
564
565
32.5k
    s = sock.Bind(sock_addr, /* explain_addr_in_use */ false);
566
32.5k
    if (s.ok()) {
567
      // We found an unused port.
568
569
      // Now, lock this "port" for use by the current process before 'sock' goes out of scope.
570
      // This will ensure that no other process can get this port while this process is still
571
      // running. LockFile() returns immediately if we can't get the lock. That's the behavior
572
      // we want. In that case, we'll just try another port.
573
29.5k
      const string lock_file = lock_file_dir + "/" + std::to_string(random_port) + ".lck";
574
29.5k
      FileLock *lock = nullptr;
575
29.5k
      s = env->LockFile(lock_file, &lock, false /* recursive_lock_ok */);
576
29.5k
      if (s.ok()) {
577
17.4k
        CHECK
(lock) << "Lock should not be NULL"0
;
578
17.4k
        file_lock->reset(lock);
579
17.4k
        LOG(INFO) << "Selected random free RPC port " << random_port;
580
17.4k
        return random_port;
581
17.4k
      } else {
582
12.0k
        VLOG
(1) << "Could not lock file " << lock_file << ": " << s.ToString()0
;
583
12.0k
      }
584
29.5k
    } else {
585
3.00k
      VLOG
(1) << "Failed to bind to port " << random_port << ": " << s.ToString()0
;
586
3.00k
    }
587
32.5k
  }
588
589
14
  LOG(FATAL) << "Could not find a free random port between " <<  kMinPort << " and "
590
14
             << kMaxPort << " inclusively" << ": " << s.ToString();
591
14
  return 0;  // never reached
592
17.5k
}
593
594
0
bool HostPort::equals(const Endpoint& endpoint) const {
595
0
  return endpoint.address().to_string() == host() && endpoint.port() == port();
596
0
}
597
598
2.02k
HostPort HostPort::FromBoundEndpoint(const Endpoint& endpoint) {
599
2.02k
  if (endpoint.address().is_unspecified()) {
600
84
    return HostPort(endpoint.address().is_v4() ? "127.0.0.1" : 
"::1"0
, endpoint.port());
601
1.94k
  } else {
602
1.94k
    return HostPort(endpoint);
603
1.94k
  }
604
2.02k
}
605
606
97.2M
std::string HostPortToString(const std::string& host, int port) {
607
97.2M
  DCHECK_GE(port, 0);
608
97.2M
  DCHECK_LE(port, 65535);
609
97.2M
  if (host.find(':') != string::npos) {
610
0
    return Format("[$0]:$1", host, port);
611
97.2M
  } else {
612
97.2M
    return Format("$0:$1", host, port);
613
97.2M
  }
614
97.2M
}
615
616
Status HostToAddresses(
617
    const std::string& host,
618
74.1k
    boost::container::small_vector_base<IpAddress>* addresses) {
619
74.1k
  return ResolveInetAddresses(host, [&addresses](const IpAddress& address) {
620
74.1k
    addresses->push_back(address);
621
74.1k
  });
622
74.1k
}
623
624
74.1k
Result<IpAddress> HostToAddress(const std::string& host) {
625
74.1k
  boost::container::small_vector<IpAddress, 1> addrs;
626
74.1k
  RETURN_NOT_OK(HostToAddresses(host, &addrs));
627
74.1k
  if (addrs.empty()) {
628
0
    return STATUS(NetworkError, "Unable to resolve address", host);
629
0
  }
630
74.1k
  auto addr = addrs.front();
631
74.1k
  if (addrs.size() > 1) {
632
0
    VLOG(1) << "Hostname " << host << " resolved to more than one address. "
633
0
            << "Using address: " << addr;
634
0
  }
635
74.1k
  return addr;
636
74.1k
}
637
638
89.3k
bool IsWildcardAddress(const std::string& host_str) {
639
89.3k
  boost::system::error_code ec;
640
89.3k
  auto addr = IpAddress::from_string(host_str, ec);
641
89.3k
  return !ec && 
addr.is_unspecified()87.1k
;
642
89.3k
}
643
644
2.47M
Result<IpAddress> ParseIpAddress(const std::string& host) {
645
2.47M
  boost::system::error_code ec;
646
2.47M
  auto addr = IpAddress::from_string(host, ec);
647
2.47M
  if (ec) {
648
78.5k
    return STATUS_FORMAT(InvalidArgument, "Failed to parse $0: $1", host, ec.message());
649
78.5k
  }
650
651
2.40M
  VLOG
(4) << "Resolving ip address to itself for input: " << host973
;
652
2.40M
  return addr;
653
2.47M
}
654
655
simple_spinlock fail_to_fast_resolve_address_mutex;
656
std::string fail_to_fast_resolve_address;
657
658
0
void TEST_SetFailToFastResolveAddress(const std::string& address) {
659
0
  {
660
0
    std::lock_guard<simple_spinlock> lock(fail_to_fast_resolve_address_mutex);
661
0
    fail_to_fast_resolve_address = address;
662
0
  }
663
0
  LOG(INFO) << "Setting fail_to_fast_resolve_address to: " << address;
664
0
}
665
666
2.48M
boost::optional<IpAddress> TryFastResolve(const std::string& host) {
667
2.48M
  auto result = ParseIpAddress(host);
668
2.48M
  if (result.ok()) {
669
2.39M
    return *result;
670
2.39M
  }
671
672
  // For testing purpose we resolve A.B.C.D.ip.yugabyte to A.B.C.D.
673
81.1k
  static const std::string kYbIpSuffix = ".ip.yugabyte";
674
81.1k
  if (boost::ends_with(host, kYbIpSuffix)) {
675
47.6k
    {
676
47.6k
      std::lock_guard<simple_spinlock> lock(fail_to_fast_resolve_address_mutex);
677
47.6k
      if (PREDICT_FALSE(host == fail_to_fast_resolve_address)) {
678
0
        return boost::none;
679
0
      }
680
47.6k
    }
681
47.6k
    boost::system::error_code ec;
682
47.6k
    auto address = IpAddress::from_string(
683
47.6k
        host.substr(0, host.length() - kYbIpSuffix.length()), ec);
684
47.6k
    if (
!ec47.6k
) {
685
47.6k
      return address;
686
47.6k
    }
687
47.6k
  }
688
689
33.4k
  return boost::none;
690
81.1k
}
691
692
} // namespace yb