• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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