1 // Copyright (c) 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "quiche/common/quiche_ip_address.h"
6
7 #include <algorithm>
8 #include <cstdint>
9 #include <cstring>
10 #include <string>
11
12 #include "absl/strings/str_cat.h"
13 #include "quiche/common/platform/api/quiche_bug_tracker.h"
14 #include "quiche/common/platform/api/quiche_logging.h"
15 #include "quiche/common/quiche_ip_address_family.h"
16
17 namespace quiche {
18
Loopback4()19 QuicheIpAddress QuicheIpAddress::Loopback4() {
20 QuicheIpAddress result;
21 result.family_ = IpAddressFamily::IP_V4;
22 result.address_.bytes[0] = 127;
23 result.address_.bytes[1] = 0;
24 result.address_.bytes[2] = 0;
25 result.address_.bytes[3] = 1;
26 return result;
27 }
28
Loopback6()29 QuicheIpAddress QuicheIpAddress::Loopback6() {
30 QuicheIpAddress result;
31 result.family_ = IpAddressFamily::IP_V6;
32 uint8_t* bytes = result.address_.bytes;
33 memset(bytes, 0, 15);
34 bytes[15] = 1;
35 return result;
36 }
37
Any4()38 QuicheIpAddress QuicheIpAddress::Any4() {
39 in_addr address;
40 memset(&address, 0, sizeof(address));
41 return QuicheIpAddress(address);
42 }
43
Any6()44 QuicheIpAddress QuicheIpAddress::Any6() {
45 in6_addr address;
46 memset(&address, 0, sizeof(address));
47 return QuicheIpAddress(address);
48 }
49
QuicheIpAddress()50 QuicheIpAddress::QuicheIpAddress() : family_(IpAddressFamily::IP_UNSPEC) {}
51
QuicheIpAddress(const in_addr & ipv4_address)52 QuicheIpAddress::QuicheIpAddress(const in_addr& ipv4_address)
53 : family_(IpAddressFamily::IP_V4) {
54 address_.v4 = ipv4_address;
55 }
QuicheIpAddress(const in6_addr & ipv6_address)56 QuicheIpAddress::QuicheIpAddress(const in6_addr& ipv6_address)
57 : family_(IpAddressFamily::IP_V6) {
58 address_.v6 = ipv6_address;
59 }
60
operator ==(QuicheIpAddress lhs,QuicheIpAddress rhs)61 bool operator==(QuicheIpAddress lhs, QuicheIpAddress rhs) {
62 if (lhs.family_ != rhs.family_) {
63 return false;
64 }
65 switch (lhs.family_) {
66 case IpAddressFamily::IP_V4:
67 return std::equal(lhs.address_.bytes,
68 lhs.address_.bytes + QuicheIpAddress::kIPv4AddressSize,
69 rhs.address_.bytes);
70 case IpAddressFamily::IP_V6:
71 return std::equal(lhs.address_.bytes,
72 lhs.address_.bytes + QuicheIpAddress::kIPv6AddressSize,
73 rhs.address_.bytes);
74 case IpAddressFamily::IP_UNSPEC:
75 return true;
76 }
77 QUICHE_BUG(quiche_bug_10126_2)
78 << "Invalid IpAddressFamily " << static_cast<int32_t>(lhs.family_);
79 return false;
80 }
81
operator !=(QuicheIpAddress lhs,QuicheIpAddress rhs)82 bool operator!=(QuicheIpAddress lhs, QuicheIpAddress rhs) {
83 return !(lhs == rhs);
84 }
85
IsInitialized() const86 bool QuicheIpAddress::IsInitialized() const {
87 return family_ != IpAddressFamily::IP_UNSPEC;
88 }
89
address_family() const90 IpAddressFamily QuicheIpAddress::address_family() const { return family_; }
91
AddressFamilyToInt() const92 int QuicheIpAddress::AddressFamilyToInt() const {
93 return ToPlatformAddressFamily(family_);
94 }
95
ToPackedString() const96 std::string QuicheIpAddress::ToPackedString() const {
97 switch (family_) {
98 case IpAddressFamily::IP_V4:
99 return std::string(address_.chars, sizeof(address_.v4));
100 case IpAddressFamily::IP_V6:
101 return std::string(address_.chars, sizeof(address_.v6));
102 case IpAddressFamily::IP_UNSPEC:
103 return "";
104 }
105 QUICHE_BUG(quiche_bug_10126_3)
106 << "Invalid IpAddressFamily " << static_cast<int32_t>(family_);
107 return "";
108 }
109
ToString() const110 std::string QuicheIpAddress::ToString() const {
111 if (!IsInitialized()) {
112 return "";
113 }
114
115 char buffer[INET6_ADDRSTRLEN] = {0};
116 const char* result =
117 inet_ntop(AddressFamilyToInt(), address_.bytes, buffer, sizeof(buffer));
118 QUICHE_BUG_IF(quiche_bug_10126_4, result == nullptr)
119 << "Failed to convert an IP address to string";
120 return buffer;
121 }
122
123 static const uint8_t kMappedAddressPrefix[] = {
124 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
125 };
126
Normalized() const127 QuicheIpAddress QuicheIpAddress::Normalized() const {
128 if (!IsIPv6()) {
129 return *this;
130 }
131 if (!std::equal(std::begin(kMappedAddressPrefix),
132 std::end(kMappedAddressPrefix), address_.bytes)) {
133 return *this;
134 }
135
136 in_addr result;
137 memcpy(&result, &address_.bytes[12], sizeof(result));
138 return QuicheIpAddress(result);
139 }
140
DualStacked() const141 QuicheIpAddress QuicheIpAddress::DualStacked() const {
142 if (!IsIPv4()) {
143 return *this;
144 }
145
146 QuicheIpAddress result;
147 result.family_ = IpAddressFamily::IP_V6;
148 memcpy(result.address_.bytes, kMappedAddressPrefix,
149 sizeof(kMappedAddressPrefix));
150 memcpy(result.address_.bytes + 12, address_.bytes, kIPv4AddressSize);
151 return result;
152 }
153
FromPackedString(const char * data,size_t length)154 bool QuicheIpAddress::FromPackedString(const char* data, size_t length) {
155 switch (length) {
156 case kIPv4AddressSize:
157 family_ = IpAddressFamily::IP_V4;
158 break;
159 case kIPv6AddressSize:
160 family_ = IpAddressFamily::IP_V6;
161 break;
162 default:
163 return false;
164 }
165 memcpy(address_.chars, data, length);
166 return true;
167 }
168
FromString(std::string str)169 bool QuicheIpAddress::FromString(std::string str) {
170 for (IpAddressFamily family :
171 {IpAddressFamily::IP_V6, IpAddressFamily::IP_V4}) {
172 int result =
173 inet_pton(ToPlatformAddressFamily(family), str.c_str(), address_.bytes);
174 if (result > 0) {
175 family_ = family;
176 return true;
177 }
178 }
179 return false;
180 }
181
IsIPv4() const182 bool QuicheIpAddress::IsIPv4() const {
183 return family_ == IpAddressFamily::IP_V4;
184 }
185
IsIPv6() const186 bool QuicheIpAddress::IsIPv6() const {
187 return family_ == IpAddressFamily::IP_V6;
188 }
189
InSameSubnet(const QuicheIpAddress & other,int subnet_length)190 bool QuicheIpAddress::InSameSubnet(const QuicheIpAddress& other,
191 int subnet_length) {
192 if (!IsInitialized()) {
193 QUICHE_BUG(quiche_bug_10126_5)
194 << "Attempting to do subnet matching on undefined address";
195 return false;
196 }
197 if ((IsIPv4() && subnet_length > 32) || (IsIPv6() && subnet_length > 128)) {
198 QUICHE_BUG(quiche_bug_10126_6) << "Subnet mask is out of bounds";
199 return false;
200 }
201
202 int bytes_to_check = subnet_length / 8;
203 int bits_to_check = subnet_length % 8;
204 const uint8_t* const lhs = address_.bytes;
205 const uint8_t* const rhs = other.address_.bytes;
206 if (!std::equal(lhs, lhs + bytes_to_check, rhs)) {
207 return false;
208 }
209 if (bits_to_check == 0) {
210 return true;
211 }
212 QUICHE_DCHECK_LT(static_cast<size_t>(bytes_to_check), sizeof(address_.bytes));
213 int mask = (~0u) << (8u - bits_to_check);
214 return (lhs[bytes_to_check] & mask) == (rhs[bytes_to_check] & mask);
215 }
216
GetIPv4() const217 in_addr QuicheIpAddress::GetIPv4() const {
218 QUICHE_DCHECK(IsIPv4());
219 return address_.v4;
220 }
221
GetIPv6() const222 in6_addr QuicheIpAddress::GetIPv6() const {
223 QUICHE_DCHECK(IsIPv6());
224 return address_.v6;
225 }
226
QuicheIpPrefix()227 QuicheIpPrefix::QuicheIpPrefix() : prefix_length_(0) {}
QuicheIpPrefix(const QuicheIpAddress & address)228 QuicheIpPrefix::QuicheIpPrefix(const QuicheIpAddress& address)
229 : address_(address) {
230 if (address_.IsIPv6()) {
231 prefix_length_ = QuicheIpAddress::kIPv6AddressSize * 8;
232 } else if (address_.IsIPv4()) {
233 prefix_length_ = QuicheIpAddress::kIPv4AddressSize * 8;
234 } else {
235 prefix_length_ = 0;
236 }
237 }
QuicheIpPrefix(const QuicheIpAddress & address,uint8_t prefix_length)238 QuicheIpPrefix::QuicheIpPrefix(const QuicheIpAddress& address,
239 uint8_t prefix_length)
240 : address_(address), prefix_length_(prefix_length) {
241 QUICHE_DCHECK(prefix_length <= QuicheIpPrefix(address).prefix_length())
242 << "prefix_length cannot be longer than the size of the IP address";
243 }
244
ToString() const245 std::string QuicheIpPrefix::ToString() const {
246 return absl::StrCat(address_.ToString(), "/", prefix_length_);
247 }
248
operator ==(const QuicheIpPrefix & lhs,const QuicheIpPrefix & rhs)249 bool operator==(const QuicheIpPrefix& lhs, const QuicheIpPrefix& rhs) {
250 return lhs.address_ == rhs.address_ &&
251 lhs.prefix_length_ == rhs.prefix_length_;
252 }
253
operator !=(const QuicheIpPrefix & lhs,const QuicheIpPrefix & rhs)254 bool operator!=(const QuicheIpPrefix& lhs, const QuicheIpPrefix& rhs) {
255 return !(lhs == rhs);
256 }
257
258 } // namespace quiche
259