blob: 1a99c4f199ab2832117b50fa2ca7d4715368971d [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "rtc_base/win32.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000012
13#include <winsock2.h>
14#include <ws2tcpip.h>
Jonas Olssona4d87372019-07-05 19:08:33 +020015
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000016#include <algorithm>
17
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "rtc_base/arraysize.h"
Steve Anton10542f22019-01-11 09:11:00 -080019#include "rtc_base/byte_order.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "rtc_base/checks.h"
21#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080022#include "rtc_base/string_utils.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000023
24namespace rtc {
25
26// Helper function declarations for inet_ntop/inet_pton.
27static const char* inet_ntop_v4(const void* src, char* dst, socklen_t size);
28static const char* inet_ntop_v6(const void* src, char* dst, socklen_t size);
29static int inet_pton_v4(const char* src, void* dst);
30static int inet_pton_v6(const char* src, void* dst);
31
32// Implementation of inet_ntop (create a printable representation of an
33// ip address). XP doesn't have its own inet_ntop, and
34// WSAAddressToString requires both IPv6 to be installed and for Winsock
35// to be initialized.
Yves Gerey665174f2018-06-19 15:03:05 +020036const char* win32_inet_ntop(int af,
37 const void* src,
38 char* dst,
39 socklen_t size) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000040 if (!src || !dst) {
deadbeef37f5ecf2017-02-27 14:06:41 -080041 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000042 }
43 switch (af) {
44 case AF_INET: {
45 return inet_ntop_v4(src, dst, size);
46 }
47 case AF_INET6: {
48 return inet_ntop_v6(src, dst, size);
49 }
50 }
deadbeef37f5ecf2017-02-27 14:06:41 -080051 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000052}
53
54// As above, but for inet_pton. Implements inet_pton for v4 and v6.
55// Note that our inet_ntop will output normal 'dotted' v4 addresses only.
56int win32_inet_pton(int af, const char* src, void* dst) {
57 if (!src || !dst) {
58 return 0;
59 }
60 if (af == AF_INET) {
61 return inet_pton_v4(src, dst);
62 } else if (af == AF_INET6) {
63 return inet_pton_v6(src, dst);
64 }
65 return -1;
66}
67
68// Helper function for inet_ntop for IPv4 addresses.
69// Outputs "dotted-quad" decimal notation.
70const char* inet_ntop_v4(const void* src, char* dst, socklen_t size) {
71 if (size < INET_ADDRSTRLEN) {
deadbeef37f5ecf2017-02-27 14:06:41 -080072 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000073 }
74 const struct in_addr* as_in_addr =
75 reinterpret_cast<const struct in_addr*>(src);
Niels Mölleraba06332018-10-16 15:14:15 +020076 snprintf(dst, size, "%d.%d.%d.%d", as_in_addr->S_un.S_un_b.s_b1,
77 as_in_addr->S_un.S_un_b.s_b2, as_in_addr->S_un.S_un_b.s_b3,
78 as_in_addr->S_un.S_un_b.s_b4);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000079 return dst;
80}
81
82// Helper function for inet_ntop for IPv6 addresses.
83const char* inet_ntop_v6(const void* src, char* dst, socklen_t size) {
84 if (size < INET6_ADDRSTRLEN) {
deadbeef37f5ecf2017-02-27 14:06:41 -080085 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000086 }
Peter Boström0c4e06b2015-10-07 12:23:21 +020087 const uint16_t* as_shorts = reinterpret_cast<const uint16_t*>(src);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000088 int runpos[8];
89 int current = 1;
guoweis@webrtc.orgb08f4042015-02-17 19:00:42 +000090 int max = 0;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000091 int maxpos = -1;
tfarina5237aaf2015-11-10 23:44:30 -080092 int run_array_size = arraysize(runpos);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000093 // Run over the address marking runs of 0s.
94 for (int i = 0; i < run_array_size; ++i) {
95 if (as_shorts[i] == 0) {
96 runpos[i] = current;
97 if (current > max) {
98 maxpos = i;
99 max = current;
100 }
101 ++current;
102 } else {
103 runpos[i] = -1;
guoweis@webrtc.orgb08f4042015-02-17 19:00:42 +0000104 current = 1;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000105 }
106 }
107
guoweis@webrtc.orgb08f4042015-02-17 19:00:42 +0000108 if (max > 0) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000109 int tmpmax = maxpos;
110 // Run back through, setting -1 for all but the longest run.
111 for (int i = run_array_size - 1; i >= 0; i--) {
112 if (i > tmpmax) {
113 runpos[i] = -1;
114 } else if (runpos[i] == -1) {
115 // We're less than maxpos, we hit a -1, so the 'good' run is done.
116 // Setting tmpmax -1 means all remaining positions get set to -1.
117 tmpmax = -1;
118 }
119 }
120 }
121
122 char* cursor = dst;
123 // Print IPv4 compatible and IPv4 mapped addresses using the IPv4 helper.
124 // These addresses have an initial run of either eight zero-bytes followed
125 // by 0xFFFF, or an initial run of ten zero-bytes.
Yves Gerey665174f2018-06-19 15:03:05 +0200126 if (runpos[0] == 1 &&
127 (maxpos == 5 || (maxpos == 4 && as_shorts[5] == 0xFFFF))) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000128 *cursor++ = ':';
129 *cursor++ = ':';
130 if (maxpos == 4) {
Niels Mölleraba06332018-10-16 15:14:15 +0200131 cursor += snprintf(cursor, INET6_ADDRSTRLEN - 2, "ffff:");
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000132 }
133 const struct in_addr* as_v4 =
134 reinterpret_cast<const struct in_addr*>(&(as_shorts[6]));
135 inet_ntop_v4(as_v4, cursor,
136 static_cast<socklen_t>(INET6_ADDRSTRLEN - (cursor - dst)));
137 } else {
138 for (int i = 0; i < run_array_size; ++i) {
139 if (runpos[i] == -1) {
Niels Mölleraba06332018-10-16 15:14:15 +0200140 cursor += snprintf(cursor, INET6_ADDRSTRLEN - (cursor - dst), "%x",
141 NetworkToHost16(as_shorts[i]));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000142 if (i != 7 && runpos[i + 1] != 1) {
143 *cursor++ = ':';
144 }
145 } else if (runpos[i] == 1) {
146 // Entered the run; print the colons and skip the run.
147 *cursor++ = ':';
148 *cursor++ = ':';
149 i += (max - 1);
150 }
151 }
152 }
153 return dst;
154}
155
156// Helper function for inet_pton for IPv4 addresses.
157// |src| points to a character string containing an IPv4 network address in
158// dotted-decimal format, "ddd.ddd.ddd.ddd", where ddd is a decimal number
159// of up to three digits in the range 0 to 255.
160// The address is converted and copied to dst,
161// which must be sizeof(struct in_addr) (4) bytes (32 bits) long.
162int inet_pton_v4(const char* src, void* dst) {
163 const int kIpv4AddressSize = 4;
164 int found = 0;
165 const char* src_pos = src;
166 unsigned char result[kIpv4AddressSize] = {0};
167
168 while (*src_pos != '\0') {
169 // strtol won't treat whitespace characters in the begining as an error,
170 // so check to ensure this is started with digit before passing to strtol.
171 if (!isdigit(*src_pos)) {
172 return 0;
173 }
174 char* end_pos;
175 long value = strtol(src_pos, &end_pos, 10);
176 if (value < 0 || value > 255 || src_pos == end_pos) {
177 return 0;
178 }
179 ++found;
180 if (found > kIpv4AddressSize) {
181 return 0;
182 }
183 result[found - 1] = static_cast<unsigned char>(value);
184 src_pos = end_pos;
185 if (*src_pos == '.') {
186 // There's more.
187 ++src_pos;
188 } else if (*src_pos != '\0') {
189 // If it's neither '.' nor '\0' then return fail.
190 return 0;
191 }
192 }
193 if (found != kIpv4AddressSize) {
194 return 0;
195 }
196 memcpy(dst, result, sizeof(result));
197 return 1;
198}
199
200// Helper function for inet_pton for IPv6 addresses.
201int inet_pton_v6(const char* src, void* dst) {
202 // sscanf will pick any other invalid chars up, but it parses 0xnnnn as hex.
203 // Check for literal x in the input string.
204 const char* readcursor = src;
205 char c = *readcursor++;
206 while (c) {
207 if (c == 'x') {
208 return 0;
209 }
210 c = *readcursor++;
211 }
212 readcursor = src;
213
214 struct in6_addr an_addr;
215 memset(&an_addr, 0, sizeof(an_addr));
216
Peter Boström0c4e06b2015-10-07 12:23:21 +0200217 uint16_t* addr_cursor = reinterpret_cast<uint16_t*>(&an_addr.s6_addr[0]);
218 uint16_t* addr_end = reinterpret_cast<uint16_t*>(&an_addr.s6_addr[16]);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000219 bool seencompressed = false;
220
221 // Addresses that start with "::" (i.e., a run of initial zeros) or
222 // "::ffff:" can potentially be IPv4 mapped or compatibility addresses.
223 // These have dotted-style IPv4 addresses on the end (e.g. "::192.168.7.1").
Yves Gerey665174f2018-06-19 15:03:05 +0200224 if (*readcursor == ':' && *(readcursor + 1) == ':' &&
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000225 *(readcursor + 2) != 0) {
226 // Check for periods, which we'll take as a sign of v4 addresses.
227 const char* addrstart = readcursor + 2;
Niels Möllerd1892522018-10-17 13:39:01 +0200228 if (strchr(addrstart, '.')) {
229 const char* colon = strchr(addrstart, ':');
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000230 if (colon) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200231 uint16_t a_short;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000232 int bytesread = 0;
233 if (sscanf(addrstart, "%hx%n", &a_short, &bytesread) != 1 ||
234 a_short != 0xFFFF || bytesread != 4) {
235 // Colons + periods means has to be ::ffff:a.b.c.d. But it wasn't.
236 return 0;
237 } else {
238 an_addr.s6_addr[10] = 0xFF;
239 an_addr.s6_addr[11] = 0xFF;
240 addrstart = colon + 1;
241 }
242 }
243 struct in_addr v4;
244 if (inet_pton_v4(addrstart, &v4.s_addr)) {
245 memcpy(&an_addr.s6_addr[12], &v4, sizeof(v4));
246 memcpy(dst, &an_addr, sizeof(an_addr));
247 return 1;
248 } else {
249 // Invalid v4 address.
250 return 0;
251 }
252 }
253 }
254
255 // For addresses without a trailing IPv4 component ('normal' IPv6 addresses).
256 while (*readcursor != 0 && addr_cursor < addr_end) {
257 if (*readcursor == ':') {
258 if (*(readcursor + 1) == ':') {
259 if (seencompressed) {
260 // Can only have one compressed run of zeroes ("::") per address.
261 return 0;
262 }
263 // Hit a compressed run. Count colons to figure out how much of the
264 // address is skipped.
265 readcursor += 2;
266 const char* coloncounter = readcursor;
267 int coloncount = 0;
268 if (*coloncounter == 0) {
269 // Special case - trailing ::.
270 addr_cursor = addr_end;
271 } else {
272 while (*coloncounter) {
273 if (*coloncounter == ':') {
274 ++coloncount;
275 }
276 ++coloncounter;
277 }
278 // (coloncount + 1) is the number of shorts left in the address.
deadbeef966963a2017-05-08 11:35:56 -0700279 // If this number is greater than the number of available shorts, the
280 // address is malformed.
281 if (coloncount + 1 > addr_end - addr_cursor) {
282 return 0;
283 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000284 addr_cursor = addr_end - (coloncount + 1);
285 seencompressed = true;
286 }
287 } else {
288 ++readcursor;
289 }
290 } else {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200291 uint16_t word;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000292 int bytesread = 0;
deadbeef966963a2017-05-08 11:35:56 -0700293 if (sscanf(readcursor, "%4hx%n", &word, &bytesread) != 1) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000294 return 0;
295 } else {
296 *addr_cursor = HostToNetwork16(word);
297 ++addr_cursor;
298 readcursor += bytesread;
299 if (*readcursor != ':' && *readcursor != '\0') {
300 return 0;
301 }
302 }
303 }
304 }
305
306 if (*readcursor != '\0' || addr_cursor < addr_end) {
307 // Catches addresses too short or too long.
308 return 0;
309 }
310 memcpy(dst, &an_addr, sizeof(an_addr));
311 return 1;
312}
313
Robin Raymondce1b1402018-11-22 20:10:11 -0500314// Windows UWP applications cannot obtain versioning information from
315// the sandbox with intention (as behehaviour based on OS versioning rather
316// than feature discovery / compilation flags is discoraged and Windows
317// 10 is living continously updated version unlike previous versions
318// of Windows).
319#if !defined(WINUWP)
320
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000321bool GetOsVersion(int* major, int* minor, int* build) {
322 OSVERSIONINFO info = {0};
323 info.dwOSVersionInfoSize = sizeof(info);
324 if (GetVersionEx(&info)) {
Yves Gerey665174f2018-06-19 15:03:05 +0200325 if (major)
326 *major = info.dwMajorVersion;
327 if (minor)
328 *minor = info.dwMinorVersion;
329 if (build)
330 *build = info.dwBuildNumber;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000331 return true;
332 }
333 return false;
334}
335
Robin Raymondce1b1402018-11-22 20:10:11 -0500336#endif // !defined(WINUWP)
337
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000338} // namespace rtc