blob: 7947b5899ebc5dbc07e0a41db2729a6f45900d40 [file] [log] [blame]
Avi Drissman64595482022-09-14 20:52:291// Copyright 2012 The Chromium Authors
[email protected]76ff86a2011-03-04 03:21:312// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/base/ip_endpoint.h"
6
Hans Wennborge93e9b22021-07-12 16:58:297#include <ostream>
8
Erik Chenc073e802020-04-22 21:21:549#include <string.h>
tfarina0dc490e2015-12-22 20:51:4610#include <tuple>
Eric Orthba55dfd2022-10-24 17:54:0911#include <utility>
tfarina0dc490e2015-12-22 20:51:4612
Hans Wennborg0924470b2020-04-27 21:08:0513#include "base/check.h"
Dan McArdle66c90982021-07-27 19:00:0214#include "base/check_op.h"
Hans Wennborg0924470b2020-04-27 21:08:0515#include "base/notreached.h"
Eric Orthba55dfd2022-10-24 17:54:0916#include "base/numerics/safe_conversions.h"
tfarina0dc490e2015-12-22 20:51:4617#include "base/strings/string_number_conversions.h"
18#include "base/sys_byteorder.h"
Eric Orthba55dfd2022-10-24 17:54:0919#include "base/values.h"
Dan McArdle66c90982021-07-27 19:00:0220#include "build/build_config.h"
tfarina0dc490e2015-12-22 20:51:4621#include "net/base/ip_address.h"
Matt Menke7290a6152021-06-30 10:33:2722#include "net/base/sys_addrinfo.h"
Eric Orthba55dfd2022-10-24 17:54:0923#include "third_party/abseil-cpp/absl/types/optional.h"
tfarinac5336ca2016-01-11 20:49:3624
Xiaohan Wang2a6845b2022-01-08 04:40:5725#if BUILDFLAG(IS_WIN)
Dan McArdle66c90982021-07-27 19:00:0226#include <winsock2.h>
27#include <ws2bth.h>
28
29#include "net/base/winsock_util.h" // For kBluetoothAddressSize
tfarinac5336ca2016-01-11 20:49:3630#endif
[email protected]76ff86a2011-03-04 03:21:3131
32namespace net {
33
Eric Orthba55dfd2022-10-24 17:54:0934namespace {
35
36// Value dictionary keys
37constexpr base::StringPiece kValueAddressKey = "address";
38constexpr base::StringPiece kValuePortKey = "port";
39
40} // namespace
41
42// static
43absl::optional<IPEndPoint> IPEndPoint::FromValue(const base::Value& value) {
44 const base::Value::Dict* dict = value.GetIfDict();
45 if (!dict)
46 return absl::nullopt;
47
48 const base::Value* address_value = dict->Find(kValueAddressKey);
49 if (!address_value)
50 return absl::nullopt;
51 absl::optional<IPAddress> address = IPAddress::FromValue(*address_value);
52 if (!address.has_value())
53 return absl::nullopt;
54 // Expect IPAddress to only allow deserializing valid addresses.
55 DCHECK(address.value().IsValid());
56
57 absl::optional<int> port = dict->FindInt(kValuePortKey);
58 if (!port.has_value() ||
59 !base::IsValueInRangeForNumericType<uint16_t>(port.value())) {
60 return absl::nullopt;
61 }
62
63 return IPEndPoint(address.value(),
64 base::checked_cast<uint16_t>(port.value()));
65}
66
Dan McArdle66c90982021-07-27 19:00:0267IPEndPoint::IPEndPoint() = default;
[email protected]76ff86a2011-03-04 03:21:3168
Chris Watkins68b15032017-12-01 03:07:1369IPEndPoint::~IPEndPoint() = default;
[email protected]034714b2011-03-04 04:09:1470
tfarina0dc490e2015-12-22 20:51:4671IPEndPoint::IPEndPoint(const IPAddress& address, uint16_t port)
martijn98acb9b2016-01-27 07:14:0772 : address_(address), port_(port) {}
tfarina0dc490e2015-12-22 20:51:4673
Dan McArdle66c90982021-07-27 19:00:0274IPEndPoint::IPEndPoint(const IPEndPoint& endpoint) = default;
75
76uint16_t IPEndPoint::port() const {
Xiaohan Wang2a6845b2022-01-08 04:40:5777#if BUILDFLAG(IS_WIN)
Dan McArdle66c90982021-07-27 19:00:0278 DCHECK_NE(address_.size(), kBluetoothAddressSize);
79#endif
80 return port_;
[email protected]76ff86a2011-03-04 03:21:3181}
82
[email protected]e466aaf2012-12-13 01:46:4483AddressFamily IPEndPoint::GetFamily() const {
martijn46f5edc2016-04-12 13:54:2184 return GetAddressFamily(address_);
[email protected]e466aaf2012-12-13 01:46:4485}
86
87int IPEndPoint::GetSockAddrFamily() const {
[email protected]43d4a0262011-03-09 19:26:0488 switch (address_.size()) {
martijn56506d02016-05-03 18:44:0089 case IPAddress::kIPv4AddressSize:
[email protected]43d4a0262011-03-09 19:26:0490 return AF_INET;
martijn56506d02016-05-03 18:44:0091 case IPAddress::kIPv6AddressSize:
[email protected]43d4a0262011-03-09 19:26:0492 return AF_INET6;
Xiaohan Wang2a6845b2022-01-08 04:40:5793#if BUILDFLAG(IS_WIN)
Dan McArdle66c90982021-07-27 19:00:0294 case kBluetoothAddressSize:
95 return AF_BTH;
96#endif
[email protected]7054e78f2012-05-07 21:44:5697 default:
[email protected]43d4a0262011-03-09 19:26:0498 NOTREACHED() << "Bad IP address";
[email protected]48e410fb2011-04-07 17:10:4699 return AF_UNSPEC;
[email protected]43d4a0262011-03-09 19:26:04100 }
101}
102
103bool IPEndPoint::ToSockAddr(struct sockaddr* address,
[email protected]7054e78f2012-05-07 21:44:56104 socklen_t* address_length) const {
Dan McArdle66c90982021-07-27 19:00:02105 // By definition, socklen_t is large enough to hold both sizes.
106 constexpr socklen_t kSockaddrInSize =
107 static_cast<socklen_t>(sizeof(struct sockaddr_in));
108 constexpr socklen_t kSockaddrIn6Size =
109 static_cast<socklen_t>(sizeof(struct sockaddr_in6));
110
[email protected]76ff86a2011-03-04 03:21:31111 DCHECK(address);
112 DCHECK(address_length);
Xiaohan Wang2a6845b2022-01-08 04:40:57113#if BUILDFLAG(IS_WIN)
Dan McArdle66c90982021-07-27 19:00:02114 DCHECK_NE(address_.size(), kBluetoothAddressSize);
115#endif
[email protected]76ff86a2011-03-04 03:21:31116 switch (address_.size()) {
martijn56506d02016-05-03 18:44:00117 case IPAddress::kIPv4AddressSize: {
[email protected]7054e78f2012-05-07 21:44:56118 if (*address_length < kSockaddrInSize)
[email protected]76ff86a2011-03-04 03:21:31119 return false;
[email protected]7054e78f2012-05-07 21:44:56120 *address_length = kSockaddrInSize;
[email protected]76ff86a2011-03-04 03:21:31121 struct sockaddr_in* addr = reinterpret_cast<struct sockaddr_in*>(address);
122 memset(addr, 0, sizeof(struct sockaddr_in));
123 addr->sin_family = AF_INET;
[email protected]9eb7b11b2012-03-28 20:19:31124 addr->sin_port = base::HostToNet16(port_);
martijn56506d02016-05-03 18:44:00125 memcpy(&addr->sin_addr, address_.bytes().data(),
126 IPAddress::kIPv4AddressSize);
[email protected]76ff86a2011-03-04 03:21:31127 break;
128 }
martijn56506d02016-05-03 18:44:00129 case IPAddress::kIPv6AddressSize: {
[email protected]7054e78f2012-05-07 21:44:56130 if (*address_length < kSockaddrIn6Size)
[email protected]76ff86a2011-03-04 03:21:31131 return false;
[email protected]7054e78f2012-05-07 21:44:56132 *address_length = kSockaddrIn6Size;
[email protected]76ff86a2011-03-04 03:21:31133 struct sockaddr_in6* addr6 =
134 reinterpret_cast<struct sockaddr_in6*>(address);
135 memset(addr6, 0, sizeof(struct sockaddr_in6));
136 addr6->sin6_family = AF_INET6;
[email protected]9eb7b11b2012-03-28 20:19:31137 addr6->sin6_port = base::HostToNet16(port_);
martijn56506d02016-05-03 18:44:00138 memcpy(&addr6->sin6_addr, address_.bytes().data(),
139 IPAddress::kIPv6AddressSize);
[email protected]76ff86a2011-03-04 03:21:31140 break;
141 }
[email protected]7054e78f2012-05-07 21:44:56142 default:
143 return false;
[email protected]76ff86a2011-03-04 03:21:31144 }
145 return true;
146}
147
[email protected]0c365402012-09-08 09:44:22148bool IPEndPoint::FromSockAddr(const struct sockaddr* sock_addr,
149 socklen_t sock_addr_len) {
150 DCHECK(sock_addr);
Dan McArdle66c90982021-07-27 19:00:02151 switch (sock_addr->sa_family) {
152 case AF_INET: {
153 if (sock_addr_len < static_cast<socklen_t>(sizeof(struct sockaddr_in)))
154 return false;
155 const struct sockaddr_in* addr =
156 reinterpret_cast<const struct sockaddr_in*>(sock_addr);
157 *this = IPEndPoint(
158 IPAddress(reinterpret_cast<const uint8_t*>(&addr->sin_addr),
159 IPAddress::kIPv4AddressSize),
160 base::NetToHost16(addr->sin_port));
161 return true;
162 }
163 case AF_INET6: {
164 if (sock_addr_len < static_cast<socklen_t>(sizeof(struct sockaddr_in6)))
165 return false;
166 const struct sockaddr_in6* addr =
167 reinterpret_cast<const struct sockaddr_in6*>(sock_addr);
168 *this = IPEndPoint(
169 IPAddress(reinterpret_cast<const uint8_t*>(&addr->sin6_addr),
170 IPAddress::kIPv6AddressSize),
171 base::NetToHost16(addr->sin6_port));
172 return true;
173 }
Xiaohan Wang2a6845b2022-01-08 04:40:57174#if BUILDFLAG(IS_WIN)
Dan McArdle66c90982021-07-27 19:00:02175 case AF_BTH: {
176 if (sock_addr_len < static_cast<socklen_t>(sizeof(SOCKADDR_BTH)))
177 return false;
178 const SOCKADDR_BTH* addr =
179 reinterpret_cast<const SOCKADDR_BTH*>(sock_addr);
180 *this = IPEndPoint();
181 address_ = IPAddress(reinterpret_cast<const uint8_t*>(&addr->btAddr),
182 kBluetoothAddressSize);
183 // Intentionally ignoring Bluetooth port. It is a ULONG, but
184 // `IPEndPoint::port_` is a uint16_t. See https://crbug.com/1231273.
185 return true;
186 }
187#endif
[email protected]76ff86a2011-03-04 03:21:31188 }
Dan McArdle66c90982021-07-27 19:00:02189 return false; // Unrecognized |sa_family|.
[email protected]76ff86a2011-03-04 03:21:31190}
191
[email protected]1a2123c62011-03-12 04:42:39192std::string IPEndPoint::ToString() const {
Xiaohan Wang2a6845b2022-01-08 04:40:57193#if BUILDFLAG(IS_WIN)
Dan McArdle66c90982021-07-27 19:00:02194 DCHECK_NE(address_.size(), kBluetoothAddressSize);
195#endif
martijn884d81a2016-04-30 13:52:18196 return IPAddressToStringWithPort(address_, port_);
[email protected]7054e78f2012-05-07 21:44:56197}
198
199std::string IPEndPoint::ToStringWithoutPort() const {
Xiaohan Wang2a6845b2022-01-08 04:40:57200#if BUILDFLAG(IS_WIN)
Dan McArdle66c90982021-07-27 19:00:02201 DCHECK_NE(address_.size(), kBluetoothAddressSize);
202#endif
martijn98acb9b2016-01-27 07:14:07203 return address_.ToString();
[email protected]1a2123c62011-03-12 04:42:39204}
205
jsbellcea42a52015-11-30 23:50:25206bool IPEndPoint::operator<(const IPEndPoint& other) const {
[email protected]17e06f12011-04-05 23:10:10207 // Sort IPv4 before IPv6.
jsbellcea42a52015-11-30 23:50:25208 if (address_.size() != other.address_.size()) {
209 return address_.size() < other.address_.size();
[email protected]17e06f12011-04-05 23:10:10210 }
jsbellcea42a52015-11-30 23:50:25211 return std::tie(address_, port_) < std::tie(other.address_, other.port_);
[email protected]76ff86a2011-03-04 03:21:31212}
213
jsbellcea42a52015-11-30 23:50:25214bool IPEndPoint::operator==(const IPEndPoint& other) const {
215 return address_ == other.address_ && port_ == other.port_;
[email protected]76ff86a2011-03-04 03:21:31216}
217
Victor Vasilievbee79ea2019-05-15 01:25:48218bool IPEndPoint::operator!=(const IPEndPoint& that) const {
219 return !(*this == that);
220}
221
Eric Orthba55dfd2022-10-24 17:54:09222base::Value IPEndPoint::ToValue() const {
223 base::Value::Dict dict;
224
225 DCHECK(address_.IsValid());
226 dict.Set(kValueAddressKey, address_.ToValue());
227 dict.Set(kValuePortKey, port_);
228
229 return base::Value(std::move(dict));
230}
231
Eric Orthd39d0672021-11-16 21:17:58232std::ostream& operator<<(std::ostream& os, const IPEndPoint& ip_endpoint) {
233 return os << ip_endpoint.ToString();
234}
235
[email protected]76ff86a2011-03-04 03:21:31236} // namespace net